Packages@downcity/cityCity

Service Call Model

How @downcity/city unifies AI service, custom service, and service calls.

The easiest mistake with City is to notice only client.ai.* and assume the access layer is just "an AI SDK."

The more accurate model is:

  • client.ai.*: AI service calls
  • client.service(...).action(...).invoke(): generic Action calls
  • client.service(...).get(...): read-oriented GET Action calls

AI service

Use this for:

  • text()
  • stream()
  • image()
  • video()

These should usually go through AIService first because AIService already unifies the model catalog, default model selection, and AI SDK UIMessage contracts.

Custom service

This is a business service you registered into City yourself.

For example:

const result = await client.service("rewrite").action("formal").invoke({
  prompt: "Rewrite this in a more professional tone",
});

This is a better fit for:

  • workflow actions
  • city business actions
  • capabilities where you do not want to expose raw model details directly

Official service

A service is not a separate API family. It is still just a service mounted inside City.

For example:

  • accounts
  • usage
  • payment
  • payment

So the calling pattern stays the same:

await client.service("accounts").action("login").invoke(...)
await client.service("usage").get("me")
await client.service("payment").get("methods")

Why this unified model matters

Because a city frontend should not need to learn three separate systems:

  • one for AI
  • one for business services
  • one for services

Downcity is designed to compress all of them back into one call mental model.