Call a model
Call Federation models with ModelCall, CityModel, and ModelStreamEvent.
Call a Federation model
const catalog = await city.ai.catalog();
const model = catalog.require("deepseek-v4-flash");
const stream = await model.stream({
messages: [{
role: "user",
content: [{ type: "text", text: "Explain this repository" }],
}],
});
for await (const event of stream) {
if (event.type === "text_delta") process.stdout.write(event.delta);
}model.stream() returns a ReadableStream<ModelStreamEvent>. A successful stream begins with model_start and provides final model_usage before model_finish. Invalid event ordering fails as a protocol error.
Use a model with Agent
Objects returned by the catalog implement ModelClient and can be passed directly to Agent:
const catalog = await city.ai.catalog();
const model = catalog.require("deepseek-v4-flash");
const agent = new Agent({ id: "reviewer", model });Agent owns Session context, tool loops, and approvals. Federation owns final model selection and billing.
Multimodal fallback
Fallback checks file content only in the latest role: "user" message in ModelCall.messages. A new text-only user message does not trigger fallback again. When the final model's fallback rules reject a historical file, the execution view replaces that file with its filename, original URL, or MIME type as plain text. The original Session file remains unchanged. Trailing assistant or tool messages do not change which user message is inspected.
OpenAI-compatible clients
Use /v1/ai/chat/completions for the OpenAI SDK, curl, or an existing gateway. The boundary adapter converts that request into the same ModelCall, so routing, fallback, reasoning, usage, and billing stay consistent.