Quickstart
Add a Model
Register models with Provider + AIService. OpenAI-compatible providers auto-passthrough.
Scenario 1: OpenAI-Compatible Provider (Auto Passthrough)
For DeepSeek and other OpenAI-compatible providers:
import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
import { Provider, AIService, type OpenAICompatibleClientConfig } from "@downcity/city";
class DeepSeekProvider extends Provider {
constructor() {
super({
id: "deepseek",
env: { DEEPSEEK_API_KEY: "DeepSeek API Key" },
baseURL: "https://api.deepseek.com",
envKey: "DEEPSEEK_API_KEY", // auto-passthrough uses this
});
}
protected createClient({ apiKey, baseURL }: OpenAICompatibleClientConfig) {
return createOpenAICompatible({ apiKey, baseURL, name: "deepseek" });
}
}
const deepseek = new DeepSeekProvider();
const ai = new AIService();
ai.use(deepseek.model({
id: "deepseek-v4-flash",
name: "DeepSeek V4 Flash",
description: "DeepSeek text model",
default: true,
}));
base.use(ai);Scenario 2: Custom OpenAI-Compatible Handler
Use an openai method when an OpenAI-compatible upstream needs request or response customization:
import { Provider, type Context, type AIProviderChargedResponse } from "@downcity/city";
class OpenAICustomProvider extends Provider {
constructor() {
super({
id: "openai-custom",
env: { OPENAI_API_KEY: "OpenAI API Key" },
});
}
async openai(ctx: Context): Promise<AIProviderChargedResponse> {
// Downstream: customize OpenAI body
// Upstream: normalize response
// (streaming: SSE event-by-event conversion)
}
}
const openaiCustom = new OpenAICustomProvider();Method Signatures
| Pathway | ctx.input | Return |
|---|---|---|
text | { prompt } | { output: UIMessage; charge? } |
stream | { prompt } | { response: Response; charge? } |
openai | { model, messages, stream, ... } | { response: Response; charge? } |