| name | add-opencode-model |
| description | Fetch OpenCode Zen model details and provide guidance for adding models to acai-ts provider configuration. |
Add OpenCode Zen Model
Fetches model details from both OpenCode and OpenRouter APIs to provide structured information for the agent to add the model to source/models/opencode-zen-provider.ts.
Usage
# Get details for a specific OpenCode model
{baseDir}/add-model.js google/gemini-3-flash-preview
How It Works
- Confirms model exists in OpenCode API (
https://opencode.ai/zen/v1/models) - Searches OpenRouter API (
https://openrouter.ai/api/v1/models) for matching model to get:- Context window length
- Max output tokens
- Pricing information
- Supported features (reasoning/tool calling)
- Determines client type based on model provider:
openai→ uses@ai-sdk/openai(Responses API)google→ uses@ai-sdk/google(custom base URL)anthropic→ uses@ai-sdk/anthropicopenai-compatible→ usescreateOpenAICompatible
- Outputs JSON with all details needed to add the model
JSON Output Format
The script outputs a JSON object wrapped in markers:
--- MODEL_DETAILS_JSON_START ---
{...}
--- MODEL_DETAILS_JSON_END ---
JSON Structure
{
"modelKey": "gemini-3-flash-preview",
"opencodeId": "google/gemini-3-flash-preview",
"openrouterId": "google/gemini-3-flash-preview",
"providerFile": "./source/models/opencode-zen-provider.ts",
"registryId": "opencode:gemini-3-flash-preview",
"clientType": "google",
"registryEntry": {
"id": "opencode:gemini-3-flash-preview",
"provider": "OpenCode",
"contextWindow": 1048576,
"maxOutputTokens": 65535,
"defaultTemperature": 0.5,
"promptFormat": "markdown",
"supportsReasoning": true,
"supportsToolCalling": true,
"costPerInputToken": 0.0000005,
"costPerOutputToken": 0.000003
},
"clientConfig": {
"key": "gemini-3-flash-preview",
"opencodeId": "google/gemini-3-flash-preview",
"clientType": "google",
"openrouterId": "google/gemini-3-flash-preview"
},
"modelInfo": {
"opencodeId": "google/gemini-3-flash-preview",
"opencodeName": "Gemini 3 Flash Preview",
"openrouterId": "google/gemini-3-flash-preview",
"openrouterName": "Google: Gemini 3 Flash Preview",
"contextLength": 1048576,
"maxCompletionTokens": 65535,
"pricing": {...},
"supportedParameters": [...]
}
}
Client Type Reference
| Client Type | Library | Base URL | Example Models |
|---|---|---|---|
openai |
@ai-sdk/openai |
Responses API | openai/gpt-4o |
google |
@ai-sdk/google |
https://opencode.ai/zen/v1/models/<model-id> |
google/gemini-3-flash-preview |
anthropic |
@ai-sdk/anthropic |
Messages API | anthropic/claude-3-5-sonnet |
openai-compatible |
@ai-sdk/openai-compatible |
https://opencode.ai/zen/v1 |
All other models |
How to Add Model to Provider File
Step 1: Add client if needed
In source/models/opencode-zen-provider.ts, check if you need to add a new client based on clientType:
// For OpenAI models (Responses API)
import { createOpenAI } from "@ai-sdk/openai";
const openaiClient = createOpenAI({
apiKey: process.env["OPENCODE_ZEN_API_TOKEN"] ?? "",
baseURL: "https://opencode.ai/zen/v1",
});
// For Google models
import { createGoogle } from "@ai-sdk/google";
const googleClient = createGoogle({
apiKey: process.env["OPENCODE_ZEN_API_TOKEN"] ?? "",
baseURL: "https://opencode.ai/zen/v1/models/<model-id>",
});
Step 2: Add to opencodeZenModels object
Find the opencodeZenModels const object and add the new model entry in alphabetical order by key, using the appropriate client:
const opencodeZenModels = {
"glm-4-7": completionsClient("glm-4.7-free"),
"minimax-m2-1": messagesClient("minimax-m2.1-free"),
// For OpenAI-compatible models:
"new-model": completionsClient("provider/new-model"),
// For Anthropic models:
"claude-model": messagesClient("anthropic/claude-model"),
// For Google models:
"gemini-flash": googleClient("google/gemini-3-flash-preview"),
} as const;
Step 3: Add to opencodeZenModelRegistry object
Find the opencodeZenModelRegistry object and add the registry entry in alphabetical order by registryId:
export const opencodeZenModelRegistry: {
[K in ModelName]: ModelMetadata<ModelName>;
} = {
"opencode:glm-4-7": {
id: "opencode:glm-4-7",
provider: "opencode",
// ... existing entry ...
},
// ... existing entries ...
"opencode:new-model": {
id: "opencode:new-model",
provider: "opencode",
contextWindow: 1048576,
maxOutputTokens: 65535,
defaultTemperature: 0.5,
promptFormat: "markdown",
supportsReasoning: true,
supportsToolCalling: true,
costPerInputToken: 0.0000005,
costPerOutputToken: 0.000003,
},
// ...
};
Step 4: Validate changes
Run the project's validation commands:
npm run typecheck
npm run lint
npm run format
Field Mapping Reference
| JSON Field | Registry Field | Notes |
|---|---|---|
registryEntry.id |
id |
Full registry ID |
registryEntry.provider |
provider |
Always "opencode" |
registryEntry.contextWindow |
contextWindow |
From OpenRouter API |
registryEntry.maxOutputTokens |
maxOutputTokens |
From OpenRouter API |
registryEntry.defaultTemperature |
defaultTemperature |
Inferred from model ID |
registryEntry.promptFormat |
promptFormat |
Inferred from model family |
registryEntry.supportsReasoning |
supportsReasoning |
From OpenRouter API |
registryEntry.supportsToolCalling |
supportsToolCalling |
From OpenRouter API |
registryEntry.costPerInputToken |
costPerInputToken |
From OpenRouter API |
registryEntry.costPerOutputToken |
costPerOutputToken |
From OpenRouter API |
Matching Strategy
The script uses multiple strategies to find a matching OpenRouter model:
- Direct key match: Match by model key (e.g.,
glm-4.7matchesglm-4.7) - Provider + name match: Match by provider prefix and model name (e.g.,
google/gemini-3-flashmatchesgoogle/gemini-3-flash-preview) - Partial name match: Match by partial model name (fallback)
If no match is found, defaults are used for pricing and capability fields.
Default Value Inferences
| Field | Logic |
|---|---|
defaultTemperature |
Returns -1 if model ID contains "codex", "coder", or "code"; otherwise 0.5 |
promptFormat |
Maps model family to format: gemini/claude/qwen/mistral/moonshotai → "markdown", gpt/openai → "xml", deepseek → "bracket", defaults to "markdown" |
maxOutputTokens |
Falls back to context_length if not available from OpenRouter |
costPerInputToken |
Defaults to 0 if no OpenRouter match |
costPerOutputToken |
Defaults to 0 if no OpenRouter match |
Error Handling
- Validates model ID exists in OpenCode API
- Shows first 10 available OpenCode models if ID not found
- Warns if no matching OpenRouter model found
- Provides clear error messages with suggestions
Examples
# Add Google Gemini Flash
{baseDir}/add-model.js google/gemini-3-flash-preview
# Add OpenAI GPT model
{baseDir}/add-model.js openai/gpt-4o
# Add Anthropic Claude model
{baseDir}/add-model.js anthropic/claude-3-5-sonnet
# Add other provider model
{baseDir}/add-model.js deepseek/deepseek-v3