diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts index 6b4242a225a..681cbed7196 100644 --- a/packages/opencode/src/config/config.ts +++ b/packages/opencode/src/config/config.ts @@ -937,6 +937,7 @@ export namespace Config { .record( z.string(), ModelsDev.Model.partial().extend({ + limit: ModelsDev.Model.shape.limit.partial().optional(), variants: z .record( z.string(), diff --git a/packages/opencode/src/provider/provider.ts b/packages/opencode/src/provider/provider.ts index b4836ae047d..473b1d08bb8 100644 --- a/packages/opencode/src/provider/provider.ts +++ b/packages/opencode/src/provider/provider.ts @@ -895,6 +895,7 @@ export namespace Provider { options: mergeDeep(existingModel?.options ?? {}, model.options ?? {}), limit: { context: model.limit?.context ?? existingModel?.limit?.context ?? 0, + input: model.limit?.input ?? existingModel?.limit?.input, output: model.limit?.output ?? existingModel?.limit?.output ?? 0, }, headers: mergeDeep(existingModel?.headers ?? {}, model.headers ?? {}), diff --git a/packages/opencode/test/provider/provider.test.ts b/packages/opencode/test/provider/provider.test.ts index 11c943db6f8..a84dd7d10ed 100644 --- a/packages/opencode/test/provider/provider.test.ts +++ b/packages/opencode/test/provider/provider.test.ts @@ -750,6 +750,85 @@ test("model inherits properties from existing database model", async () => { }) }) +test("existing model supports partial limit.input override", async () => { + await using tmp = await tmpdir({ + init: async (dir) => { + await Bun.write( + path.join(dir, "opencode.json"), + JSON.stringify({ + $schema: "https://opencode.ai/config.json", + provider: { + anthropic: { + models: { + "claude-sonnet-4-20250514": { + limit: { + input: 123456, + }, + }, + }, + }, + }, + }), + ) + }, + }) + await Instance.provide({ + directory: tmp.path, + init: async () => { + Env.set("ANTHROPIC_API_KEY", "test-api-key") + }, + fn: async () => { + const providers = await Provider.list() + const model = providers["anthropic"].models["claude-sonnet-4-20250514"] + expect(model.limit.input).toBe(123456) + expect(model.limit.context).toBeGreaterThan(0) + expect(model.limit.output).toBeGreaterThan(0) + }, + }) +}) + +test("custom model preserves configured limit.input", async () => { + await using tmp = await tmpdir({ + init: async (dir) => { + await Bun.write( + path.join(dir, "opencode.json"), + JSON.stringify({ + $schema: "https://opencode.ai/config.json", + provider: { + "custom-input-limit": { + name: "Custom Input Limit", + npm: "@ai-sdk/openai-compatible", + env: [], + models: { + model: { + name: "Model", + tool_call: true, + limit: { + context: 128000, + input: 64000, + output: 4096, + }, + }, + }, + options: { apiKey: "test" }, + }, + }, + }), + ) + }, + }) + await Instance.provide({ + directory: tmp.path, + fn: async () => { + const providers = await Provider.list() + const model = providers["custom-input-limit"].models["model"] + expect(model.limit.context).toBe(128000) + expect(model.limit.input).toBe(64000) + expect(model.limit.output).toBe(4096) + }, + }) +}) + test("disabled_providers prevents loading even with env var", async () => { await using tmp = await tmpdir({ init: async (dir) => {