fix(cli): default limit.context to 128k when unknown in OpenCode configs (#11035, #11032) (#11054)

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.
This commit is contained in:
Rouzbeh†
2026-08-22 03:36:21 +03:30
committed by GitHub
parent 7e48be8061
commit 8643e0f57c
4 changed files with 32 additions and 14 deletions

View File

@@ -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;

View File

@@ -57,10 +57,19 @@ export const buildOpenCodeProviderConfig = ({
? normalizedModels
: [...new Set([normalizedModel, ...OPENCODE_DEFAULT_MODELS].filter(Boolean))];
const modelsRecord: Record<string, { name: string }> = {};
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,
},
};
}
}

View File

@@ -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();
}

View File

@@ -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,
},
},
});
});