Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export interface Config {
* server actively blocks requests whose version looks stale or absent.
*/
export const DEFAULT_CC_VERSION = "0.40.3";
export const DEFAULT_CC_API_BASE = "https://api.commandcode.ai";
const CC_VERSION_REFRESH_MS = 24 * 60 * 60 * 1000;

let cachedVersion: string | null = null;
Expand Down Expand Up @@ -83,7 +84,7 @@ export function loadConfig(): Config {
const host = cli.host || process.env.HOST || "127.0.0.1";
const port = parseInt(cli.port || process.env.PORT || "8787", 10);
const apiKey = cli["api-key"] || process.env.CC_API_KEY || readAuthKey();
const ccApiBase = process.env.CC_API_BASE || "https://api.commandcode.ai";
const ccApiBase = process.env.CC_API_BASE || DEFAULT_CC_API_BASE;
const ccVersion = process.env.CC_CLI_VERSION || cachedVersion || DEFAULT_CC_VERSION;
const logLevel = process.env.LOG_LEVEL || "info";
// `*` is fine for a localhost proxy; restrict (e.g. to an origin or leave
Expand Down
99 changes: 93 additions & 6 deletions src/models.json
Original file line number Diff line number Diff line change
@@ -1,38 +1,63 @@
{
"closedModelOrgs": ["anthropic", "openai", "google", "gemini"],
"builtin": [
"deepseek/deepseek-v4-pro",
"deepseek/deepseek-v4-flash",
"deepseek/deepseek-v4-flash-vision-exp",
"zai-org/GLM-5.3",
"z-ai/glm-5.3-flash",
"zai-org/GLM-5.2",
"zai-org/GLM-5.2-Fast",
"zai-org/GLM-5.1",
"zai-org/GLM-5",
"MiniMaxAI/MiniMax-M3",
"MiniMaxAI/MiniMax-M2.7",
"minimax/minimax-m3-free",
"minimax/minimax-m2.7-free",
"MiniMaxAI/MiniMax-M2.5",
"moonshotai/Kimi-K3",
"moonshotai/Kimi-K2.7-Code",
"moonshotai/Kimi-K2.7-Code-Highspeed",
"moonshotai/Kimi-K2.6",
"moonshotai/Kimi-K2.5",
"Qwen/Qwen3.8-Max",
"Qwen/Qwen3.8-Flash",
"Qwen/Qwen3.8-27B",
"Qwen/Qwen3.7-Max",
"Qwen/Qwen3.7-Plus",
"Qwen/Qwen3.7-Flash",
"Qwen/Qwen3.6-Max-Preview",
"Qwen/Qwen3.6-Plus",
"stepfun/Step-3.7-Flash",
"stepfun/Step-3.5-Flash",
"xiaomi/mimo-v2.5-pro",
"xiaomi/mimo-v2.5",
"xai/grok-4.6",
"xai/grok-4.5",
"nvidia/nemotron-3-ultra-550b-a55b",
"thinkingmachines/inkling",
"tencent/Hy3"
"thinkingmachines/inkling-small",
"tencent/hy4-preview",
"tencent/hy3-paid",
"tencent/Hy3",
"meta/muse-spark-1.2",
"meta/muse-spark-1.2-contributor",
"meta/muse-spark-1.1",
"sakana/fugu-ultra",
"poolside/laguna-s-2.1-free"
],
"shortAliases": {
"deepseek-v4-pro": "deepseek/deepseek-v4-pro",
"deepseek-v4": "deepseek/deepseek-v4-pro",
"deepseek-pro": "deepseek/deepseek-v4-pro",
"deepseek-v4-flash": "deepseek/deepseek-v4-flash",
"deepseek-flash": "deepseek/deepseek-v4-flash",
"deepseek-v4-flash-vision": "deepseek/deepseek-v4-flash-vision-exp",
"deepseek-vision": "deepseek/deepseek-v4-flash-vision-exp",
"glm-5.3": "zai-org/GLM-5.3",
"glm5.3": "zai-org/GLM-5.3",
"glm-5.3-flash": "z-ai/glm-5.3-flash",
"glm5.3-flash": "z-ai/glm-5.3-flash",
"glm-5.2": "zai-org/GLM-5.2",
"glm5.2": "zai-org/GLM-5.2",
"glm-5.2-fast": "zai-org/GLM-5.2-Fast",
Expand All @@ -41,8 +66,10 @@
"glm-5": "zai-org/GLM-5",
"minimax-m3": "MiniMaxAI/MiniMax-M3",
"minimax3": "MiniMaxAI/MiniMax-M3",
"minimax-m3-free": "minimax/minimax-m3-free",
"minimax-m2.7": "MiniMaxAI/MiniMax-M2.7",
"minimax2.7": "MiniMaxAI/MiniMax-M2.7",
"minimax-m2.7-free": "minimax/minimax-m2.7-free",
"minimax-m2.5": "MiniMaxAI/MiniMax-M2.5",
"minimax2.5": "MiniMaxAI/MiniMax-M2.5",
"kimi-k3": "moonshotai/Kimi-K3",
Expand All @@ -56,14 +83,22 @@
"kimi2.6": "moonshotai/Kimi-K2.6",
"kimi-k2.5": "moonshotai/Kimi-K2.5",
"kimi2.5": "moonshotai/Kimi-K2.5",
"qwen3.8-max": "Qwen/Qwen3.8-Max",
"qwen-3.8-max": "Qwen/Qwen3.8-Max",
"qwen3.8-flash": "Qwen/Qwen3.8-Flash",
"qwen-3.8-flash": "Qwen/Qwen3.8-Flash",
"qwen3.8-27b": "Qwen/Qwen3.8-27B",
"qwen-3.8-27b": "Qwen/Qwen3.8-27B",
"qwen3.7-max": "Qwen/Qwen3.7-Max",
"qwen-3.7-max": "Qwen/Qwen3.7-Max",
"qwen3.7-plus": "Qwen/Qwen3.7-Plus",
"qwen-3.7-plus": "Qwen/Qwen3.7-Plus",
"qwen-3.6-max": "Qwen/Qwen3.6-Max-Preview",
"qwen3.7-flash": "Qwen/Qwen3.7-Flash",
"qwen-3.7-flash": "Qwen/Qwen3.7-Flash",
"qwen3.6-max": "Qwen/Qwen3.6-Max-Preview",
"qwen-3.6-plus": "Qwen/Qwen3.6-Plus",
"qwen-3.6-max": "Qwen/Qwen3.6-Max-Preview",
"qwen3.6-plus": "Qwen/Qwen3.6-Plus",
"qwen-3.6-plus": "Qwen/Qwen3.6-Plus",
"step-3.7-flash": "stepfun/Step-3.7-Flash",
"step3.7": "stepfun/Step-3.7-Flash",
"step-3.5-flash": "stepfun/Step-3.5-Flash",
Expand All @@ -72,73 +107,125 @@
"mimo-pro": "xiaomi/mimo-v2.5-pro",
"mimo-v2.5": "xiaomi/mimo-v2.5",
"mimo2.5": "xiaomi/mimo-v2.5",
"grok-4.6": "xai/grok-4.6",
"grok4.6": "xai/grok-4.6",
"grok-4.5": "xai/grok-4.5",
"grok4.5": "xai/grok-4.5",
"nemotron": "nvidia/nemotron-3-ultra-550b-a55b",
"nemotron-3-ultra": "nvidia/nemotron-3-ultra-550b-a55b",
"inkling": "thinkingmachines/inkling",
"hy3": "tencent/Hy3"
"inkling-small": "thinkingmachines/inkling-small",
"hy4": "tencent/hy4-preview",
"hy4-preview": "tencent/hy4-preview",
"hy3": "tencent/Hy3",
"muse-spark": "meta/muse-spark-1.2",
"muse-spark-1.2": "meta/muse-spark-1.2",
"muse-spark-contributor": "meta/muse-spark-1.2-contributor",
"muse-spark-1.1": "meta/muse-spark-1.1",
"fugu": "sakana/fugu-ultra",
"fugu-ultra": "sakana/fugu-ultra",
"laguna": "poolside/laguna-s-2.1-free"
},
"contextWindows": {
"deepseek/deepseek-v4-pro": 1048576,
"deepseek/deepseek-v4-flash": 1048576,
"deepseek/deepseek-v4-flash-vision-exp": 1048576,
"zai-org/GLM-5.3": 1000000,
"z-ai/glm-5.3-flash": 1048576,
"zai-org/GLM-5.2": 1048576,
"zai-org/GLM-5.2-Fast": 1048576,
"zai-org/GLM-5.1": 200000,
"zai-org/GLM-5": 200000,
"MiniMaxAI/MiniMax-M3": 1048576,
"MiniMaxAI/MiniMax-M2.7": 204800,
"minimax/minimax-m3-free": 1048576,
"minimax/minimax-m2.7-free": 197000,
"MiniMaxAI/MiniMax-M2.5": 200000,
"moonshotai/Kimi-K3": 1048576,
"moonshotai/Kimi-K2.7-Code": 256000,
"moonshotai/Kimi-K2.7-Code-Highspeed": 262000,
"moonshotai/Kimi-K2.6": 256000,
"moonshotai/Kimi-K2.5": 256000,
"Qwen/Qwen3.8-Max": 1000000,
"Qwen/Qwen3.8-Flash": 1000000,
"Qwen/Qwen3.8-27B": 262144,
"Qwen/Qwen3.7-Max": 1048576,
"Qwen/Qwen3.7-Plus": 1048576,
"Qwen/Qwen3.7-Flash": 1048576,
"Qwen/Qwen3.6-Max-Preview": 262144,
"Qwen/Qwen3.6-Plus": 1048576,
"stepfun/Step-3.7-Flash": 256000,
"stepfun/Step-3.5-Flash": 1048576,
"xiaomi/mimo-v2.5-pro": 1048576,
"xiaomi/mimo-v2.5": 1048576,
"xai/grok-4.6": 500000,
"xai/grok-4.5": 500000,
"nvidia/nemotron-3-ultra-550b-a55b": 1048576,
"thinkingmachines/inkling": 256000,
"tencent/Hy3": 262144
"thinkingmachines/inkling-small": 1000000,
"tencent/hy4-preview": 1048576,
"tencent/hy3-paid": 262144,
"tencent/Hy3": 262144,
"meta/muse-spark-1.2": 1048576,
"meta/muse-spark-1.2-contributor": 1048576,
"meta/muse-spark-1.1": 1048576,
"sakana/fugu-ultra": 1000000,
"poolside/laguna-s-2.1-free": 256000
},
"modelNames": {
"deepseek/deepseek-v4-pro": "DeepSeek V4 Pro",
"deepseek/deepseek-v4-flash": "DeepSeek V4 Flash",
"deepseek/deepseek-v4-flash-vision-exp": "DeepSeek V4 Flash Vision (exp)",
"zai-org/GLM-5.3": "GLM-5.3",
"z-ai/glm-5.3-flash": "GLM-5.3 Flash",
"zai-org/GLM-5.2": "GLM-5.2",
"zai-org/GLM-5.2-Fast": "GLM-5.2 Fast",
"zai-org/GLM-5.1": "GLM-5.1",
"zai-org/GLM-5": "GLM-5",
"MiniMaxAI/MiniMax-M3": "MiniMax M3",
"MiniMaxAI/MiniMax-M2.7": "MiniMax M2.7",
"minimax/minimax-m3-free": "MiniMax M3 (Free)",
"minimax/minimax-m2.7-free": "MiniMax M2.7 (Free)",
"MiniMaxAI/MiniMax-M2.5": "MiniMax M2.5",
"moonshotai/Kimi-K3": "Kimi K3",
"moonshotai/Kimi-K2.7-Code": "Kimi K2.7 Code",
"moonshotai/Kimi-K2.7-Code-Highspeed": "Kimi K2.7 Code Highspeed",
"moonshotai/Kimi-K2.6": "Kimi K2.6",
"moonshotai/Kimi-K2.5": "Kimi K2.5",
"Qwen/Qwen3.8-Max": "Qwen 3.8 Max",
"Qwen/Qwen3.8-Flash": "Qwen 3.8 Flash",
"Qwen/Qwen3.8-27B": "Qwen 3.8 27B",
"Qwen/Qwen3.7-Max": "Qwen 3.7 Max",
"Qwen/Qwen3.7-Plus": "Qwen 3.7 Plus",
"Qwen/Qwen3.7-Flash": "Qwen 3.7 Flash",
"Qwen/Qwen3.6-Max-Preview": "Qwen 3.6 Max Preview",
"Qwen/Qwen3.6-Plus": "Qwen 3.6 Plus",
"stepfun/Step-3.7-Flash": "Step 3.7 Flash",
"stepfun/Step-3.5-Flash": "Step 3.5 Flash",
"xiaomi/mimo-v2.5-pro": "MiMo V2.5 Pro",
"xiaomi/mimo-v2.5": "MiMo V2.5",
"xai/grok-4.6": "Grok 4.6",
"xai/grok-4.5": "Grok 4.5",
"nvidia/nemotron-3-ultra-550b-a55b": "Nemotron 3 Ultra",
"thinkingmachines/inkling": "Inkling",
"tencent/Hy3": "Hy3"
"thinkingmachines/inkling-small": "Inkling Small",
"tencent/hy4-preview": "Tencent Hy4 Preview",
"tencent/hy3-paid": "Tencent Hy3",
"tencent/Hy3": "Hy3",
"meta/muse-spark-1.2": "Muse Spark 1.2",
"meta/muse-spark-1.2-contributor": "Muse Spark 1.2 Contributor",
"meta/muse-spark-1.1": "Muse Spark 1.1",
"sakana/fugu-ultra": "Fugu Ultra",
"poolside/laguna-s-2.1-free": "Laguna S 2.1 (Free)"
},
"reasoningEfforts": {
"deepseek/deepseek-v4-pro": ["high", "max"],
"deepseek/deepseek-v4-flash": ["high", "max"],
"deepseek/deepseek-v4-flash-vision-exp": ["high", "max"],
"zai-org/GLM-5.3": ["high", "max"],
"z-ai/glm-5.3-flash": ["high", "max"],
"zai-org/GLM-5.2": ["high", "max"],
"xai/grok-4.6": ["low", "medium", "high"],
"xai/grok-4.5": ["low", "medium", "high"]
},
"maxOutputTokens": {
Expand Down
35 changes: 14 additions & 21 deletions src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
AnthropicStreamEncoder,
buildAnthropicResponse,
} from "@/translate/anthropic.js";
import { getDefaultModels, fetchModelList } from "@/translate/models.js";
import { refreshCatalog, getCatalog } from "@/translate/catalog.js";
import type { CCEvent } from "@/translate/types.js";
import { formatSSE, formatSSEDone, formatAnthropicSSE } from "@/stream.js";
import { sendToCC, collectEvents, UpstreamError } from "@/upstream.js";
Expand All @@ -26,13 +26,8 @@ import type { AnthropicRequest, AnthropicSSERecord } from "@/translate/anthropic
// ──────────────────────────────────────────

let config: Config;
let modelList: string[] = getDefaultModels();
let corsOrigin = "*";

function updateModelList(models: string[]): void {
if (models.length > 0) modelList = models;
}

// ──────────────────────────────────────────
// Request body parser
// ──────────────────────────────────────────
Expand Down Expand Up @@ -251,28 +246,29 @@ function handleModels(req: http.IncomingMessage, res: http.ServerResponse): void
const isAnthropic = req.headers["anthropic-version"] !== undefined;

if (isAnthropic) {
const items = modelList;
const catalog = getCatalog();
const items = catalog.models;
const data = {
data: items.map((id: string) => ({
id,
data: items.map((m) => ({
id: m.id,
type: "model" as const,
display_name: id,
display_name: m.displayName,
created_at: new Date().toISOString(),
max_input_tokens: null as number | null,
max_tokens: null as number | null,
capabilities: null,
})),
has_more: false,
first_id: items.length > 0 ? items[0] : null,
last_id: items.length > 0 ? items[items.length - 1] : null,
first_id: items.length > 0 ? items[0].id : null,
last_id: items.length > 0 ? items[items.length - 1].id : null,
};
sendJson(res, 200, data);
return;
}

const data = {
object: "list",
data: modelList.map((id: string) => ({
data: getCatalog().ids.map((id: string) => ({
id,
object: "model",
created: Math.floor(Date.now() / 1000),
Expand Down Expand Up @@ -586,15 +582,12 @@ export function createServer(cfg: Config): http.Server {
config = cfg;
corsOrigin = cfg.corsOrigin;

// Start fetching model list in background (only if we have a key to use).
// Refresh the model catalog from the CC provider API in background (only if
// we have a key to use). On failure the static fallback stays in place.
if (cfg.apiKey) {
fetchModelList(cfg.ccApiBase, cfg.apiKey)
.then((models) => {
if (models.length > 0) updateModelList(models);
})
.catch(() => {
/* keep defaults */
});
refreshCatalog(cfg.ccApiBase, cfg.apiKey).catch(() => {
/* keep defaults */
});
}

const routes: RouteEntry[] = [
Expand Down
Loading
Loading