From 8643e0f57cf517d8443b7f8ee686efaff74b232f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rouzbeh=E2=80=A0?= <78313022+rqzbeh@users.noreply.github.com> Date: Sat, 22 Aug 2026 03:36:21 +0330 Subject: [PATCH] fix(cli): default limit.context to 128k when unknown in OpenCode configs (#11035, #11032) (#11054) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ⭐5 — OpenCode config: limit.context default 128k quando metadata de catálogo desconhecida (#11035/#11032); limit emitido por model entry. TDD, suíte aberta limpa. --- .../cli-helper/config-generator/opencode.ts | 21 +++++++++++-------- src/shared/services/opencodeConfig.ts | 13 ++++++++++-- .../unit/opencode-limit-output-10940.test.ts | 4 ++-- ...t40-opencode-cli-tools-integration.test.ts | 8 ++++++- 4 files changed, 32 insertions(+), 14 deletions(-) diff --git a/src/lib/cli-helper/config-generator/opencode.ts b/src/lib/cli-helper/config-generator/opencode.ts index e3d3f0e950..a2329968ab 100644 --- a/src/lib/cli-helper/config-generator/opencode.ts +++ b/src/lib/cli-helper/config-generator/opencode.ts @@ -303,15 +303,18 @@ function buildModelEntry( const output = typeof userOutput === "number" && userOutput > 0 ? userOutput : (catalogOutput ?? 8_192); - // `limit.output` is REQUIRED by OpenCode's v1 provider schema regardless of - // whether the catalog (or the user's existing config) knows the model's - // context window — a model with no catalog metadata at all must still get - // a `limit` block, or OpenCode rejects the whole config with "Missing key - // provider.omniroute.models.{model}.limit.output" (#10940). `output` above - // already resolves to a safe fallback (8K) when nothing else is known, so - // we always emit it; `context`/`input` are added only when actually known. - const limit: { context?: number; input?: number; output?: number } = { output }; - if (typeof context === "number") limit.context = context; + // Both `limit.context` and `limit.output` are REQUIRED by OpenCode's v1 provider schema + // regardless of whether the catalog (or the user's existing config) knows the model's + // context window — a model with no catalog metadata at all must still get both + // `limit.context` and `limit.output`, or OpenCode rejects the whole config with "Missing key + // provider.omniroute.models.{model}.limit.context" (#11035) or ".limit.output" (#10940, #11032). + // `output` above resolves to a safe fallback (8K) and `context` resolves to a safe fallback (128K) + // when nothing else is known, so we always emit both fields. + const resolvedContext = typeof context === "number" && context > 0 ? context : 128_000; + const limit: { context: number; input?: number; output: number } = { + context: resolvedContext, + output, + }; const userInput = existing?.limit?.input; if (typeof userInput === "number" && userInput > 0) { limit.input = userInput; diff --git a/src/shared/services/opencodeConfig.ts b/src/shared/services/opencodeConfig.ts index a398585dba..a4bbd65591 100644 --- a/src/shared/services/opencodeConfig.ts +++ b/src/shared/services/opencodeConfig.ts @@ -57,10 +57,19 @@ export const buildOpenCodeProviderConfig = ({ ? normalizedModels : [...new Set([normalizedModel, ...OPENCODE_DEFAULT_MODELS].filter(Boolean))]; - const modelsRecord: Record = {}; + const modelsRecord: Record< + string, + { name: string; limit: { context: number; output: number } } + > = {}; for (const m of uniqueModels) { if (m) { - modelsRecord[m] = { name: getModelEntryName(m, normalizedLabels) }; + modelsRecord[m] = { + name: getModelEntryName(m, normalizedLabels), + limit: { + context: 128_000, + output: 8_192, + }, + }; } } diff --git a/tests/unit/opencode-limit-output-10940.test.ts b/tests/unit/opencode-limit-output-10940.test.ts index 653002ebe8..317ae1f5a9 100644 --- a/tests/unit/opencode-limit-output-10940.test.ts +++ b/tests/unit/opencode-limit-output-10940.test.ts @@ -54,8 +54,8 @@ describe("opencode config generator — limit.output always emitted (#10940)", ( `entry.limit.output must be a number, got ${JSON.stringify(entry.limit?.output)}` ); assert.ok(entry.limit.output > 0, "entry.limit.output must be a positive number"); - // context stays unknown — we must NOT fabricate it. - assert.strictEqual(entry.limit.context, undefined); + // context defaults to 128k when unknown to satisfy OpenCode's required limit.context schema (#11035). + assert.strictEqual(entry.limit.context, 128_000); } finally { stub.restore(); } diff --git a/tests/unit/t40-opencode-cli-tools-integration.test.ts b/tests/unit/t40-opencode-cli-tools-integration.test.ts index 7a7c305bac..c1da020ff9 100644 --- a/tests/unit/t40-opencode-cli-tools-integration.test.ts +++ b/tests/unit/t40-opencode-cli-tools-integration.test.ts @@ -158,7 +158,13 @@ test("T40: OpenCode merge preserves unrelated config and updates only provider.o github: { command: "npx", args: ["-y", "@modelcontextprotocol/server-github"] }, }); assert.deepEqual(mergedConfig.provider.omniroute.models, { - "cx/gpt-5.6-sol": { name: "GPT-5.6 Sol" }, + "cx/gpt-5.6-sol": { + name: "GPT-5.6 Sol", + limit: { + context: 128_000, + output: 8_192, + }, + }, }); });