Skip to content

Commit 01e6503

Browse files
committed
Read custom provider model context limits from OpenCode config
Custom models defined in opencode.json(c) via provider.<id>.models.<name>.limit.context were not being picked up for context limit resolution. Only models.dev cache was checked, so proxy/custom models like google/antigravity-claude-opus-4-6-thinking fell back to the 128k default even when the user had explicitly set limit.context: 200000 in their OpenCode config. Now reads and overlays OpenCode config provider definitions on top of models.dev cache, with 5-minute in-memory caching.
1 parent b06876c commit 01e6503

1 file changed

Lines changed: 67 additions & 16 deletions

File tree

packages/plugin/src/shared/models-dev-cache.ts

Lines changed: 67 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -34,27 +34,42 @@ function getModelsJsonPath(): string {
3434
return join(cacheBase, "opencode", "models.json");
3535
}
3636

37+
function getOpencodeConfigPath(): string | null {
38+
const envDir = process.env.OPENCODE_CONFIG_DIR?.trim();
39+
const configDir = envDir
40+
? envDir
41+
: platform() === "win32"
42+
? join(homedir(), ".config", "opencode")
43+
: join(process.env.XDG_CONFIG_HOME || join(homedir(), ".config"), "opencode");
44+
45+
// Check jsonc first, then json (matches OpenCode's own lookup order)
46+
const jsonc = join(configDir, "opencode.jsonc");
47+
if (existsSync(jsonc)) return jsonc;
48+
const json = join(configDir, "opencode.json");
49+
if (existsSync(json)) return json;
50+
return null;
51+
}
52+
3753
function loadModelsDevLimits(): Map<string, number> {
3854
const limits = new Map<string, number>();
39-
const filePath = getModelsJsonPath();
4055

56+
// 1. Load from OpenCode's models.dev cache (base layer — all known public models)
57+
const modelsJsonPath = getModelsJsonPath();
4158
try {
42-
if (!existsSync(filePath)) {
43-
return limits;
44-
}
59+
if (existsSync(modelsJsonPath)) {
60+
const raw = readFileSync(modelsJsonPath, "utf-8");
61+
const data = JSON.parse(raw) as Record<
62+
string,
63+
{ models?: Record<string, { limit?: { context?: number } }> }
64+
>;
4565

46-
const raw = readFileSync(filePath, "utf-8");
47-
const data = JSON.parse(raw) as Record<
48-
string,
49-
{ models?: Record<string, { limit?: { context?: number } }> }
50-
>;
51-
52-
for (const [providerId, provider] of Object.entries(data)) {
53-
if (!provider?.models || typeof provider.models !== "object") continue;
54-
for (const [modelId, model] of Object.entries(provider.models)) {
55-
const context = model?.limit?.context;
56-
if (typeof context === "number" && context > 0) {
57-
limits.set(`${providerId}/${modelId}`, context);
66+
for (const [providerId, provider] of Object.entries(data)) {
67+
if (!provider?.models || typeof provider.models !== "object") continue;
68+
for (const [modelId, model] of Object.entries(provider.models)) {
69+
const context = model?.limit?.context;
70+
if (typeof context === "number" && context > 0) {
71+
limits.set(`${providerId}/${modelId}`, context);
72+
}
5873
}
5974
}
6075
}
@@ -66,6 +81,42 @@ function loadModelsDevLimits(): Map<string, number> {
6681
);
6782
}
6883

84+
// 2. Overlay custom provider models from OpenCode config (higher priority).
85+
// Users define custom/proxy models via provider.<id>.models.<name>.limit.context
86+
// in opencode.json(c). These override models.dev entries for the same key.
87+
try {
88+
const configPath = getOpencodeConfigPath();
89+
if (configPath && existsSync(configPath)) {
90+
let raw = readFileSync(configPath, "utf-8");
91+
// Strip JSONC comments (single-line only — sufficient for OpenCode configs)
92+
raw = raw.replace(/\/\/.*$/gm, "");
93+
const config = JSON.parse(raw) as {
94+
provider?: Record<
95+
string,
96+
{ models?: Record<string, { limit?: { context?: number } }> }
97+
>;
98+
};
99+
100+
if (config.provider && typeof config.provider === "object") {
101+
for (const [providerId, provider] of Object.entries(config.provider)) {
102+
if (!provider?.models || typeof provider.models !== "object") continue;
103+
for (const [modelId, model] of Object.entries(provider.models)) {
104+
const context = model?.limit?.context;
105+
if (typeof context === "number" && context > 0) {
106+
limits.set(`${providerId}/${modelId}`, context);
107+
}
108+
}
109+
}
110+
}
111+
}
112+
} catch (error) {
113+
sessionLog(
114+
"global",
115+
"models-dev-cache: failed to read opencode config for custom models:",
116+
error instanceof Error ? error.message : String(error),
117+
);
118+
}
119+
69120
return limits;
70121
}
71122

0 commit comments

Comments
 (0)