diff --git a/packages/opencode/src/provider/models.ts b/packages/opencode/src/provider/models.ts index 796dcb7c238..5e182a47096 100644 --- a/packages/opencode/src/provider/models.ts +++ b/packages/opencode/src/provider/models.ts @@ -48,6 +48,7 @@ export namespace ModelsDev { limit: z.object({ context: z.number(), output: z.number(), + input: z.number().optional(), }), modalities: z .object({ diff --git a/packages/opencode/src/provider/provider.ts b/packages/opencode/src/provider/provider.ts index 9967edec5dd..5c301f915a3 100644 --- a/packages/opencode/src/provider/provider.ts +++ b/packages/opencode/src/provider/provider.ts @@ -465,6 +465,7 @@ export namespace Provider { limit: z.object({ context: z.number(), output: z.number(), + input: z.number().optional(), }), status: z.enum(["alpha", "beta", "deprecated", "active"]), options: z.record(z.string(), z.any()), @@ -527,6 +528,7 @@ export namespace Provider { limit: { context: model.limit.context, output: model.limit.output, + input: model.limit.input, }, capabilities: { temperature: model.temperature, diff --git a/packages/opencode/src/session/compaction.ts b/packages/opencode/src/session/compaction.ts index 42bab2eb975..47bd3d1eb77 100644 --- a/packages/opencode/src/session/compaction.ts +++ b/packages/opencode/src/session/compaction.ts @@ -27,6 +27,8 @@ export namespace SessionCompaction { ), } + const NEXT_INPUT_TOKEN_MAX = 20_000 + export async function isOverflow(input: { tokens: MessageV2.Assistant["tokens"]; model: Provider.Model }) { const config = await Config.get() if (config.compaction?.auto === false) return false @@ -34,7 +36,7 @@ export namespace SessionCompaction { if (context === 0) return false const count = input.tokens.input + input.tokens.cache.read + input.tokens.output const output = Math.min(input.model.limit.output, SessionPrompt.OUTPUT_TOKEN_MAX) || SessionPrompt.OUTPUT_TOKEN_MAX - const usable = context - output + const usable = input.model.limit.input ? input.model.limit.input - NEXT_INPUT_TOKEN_MAX : context - output return count > usable } diff --git a/packages/opencode/test/session/compaction.test.ts b/packages/opencode/test/session/compaction.test.ts index 9070428ea54..b36134d9555 100644 --- a/packages/opencode/test/session/compaction.test.ts +++ b/packages/opencode/test/session/compaction.test.ts @@ -10,7 +10,7 @@ import type { Provider } from "../../src/provider/provider" Log.init({ print: false }) -function createModel(opts: { context: number; output: number; cost?: Provider.Model["cost"] }): Provider.Model { +function createModel(opts: { context: number; output: number; inputLimit?: number; cost?: Provider.Model["cost"] }): Provider.Model { return { id: "test-model", providerID: "test", @@ -18,6 +18,7 @@ function createModel(opts: { context: number; output: number; cost?: Provider.Mo limit: { context: opts.context, output: opts.output, + input: opts.inputLimit, }, cost: opts.cost ?? { input: 0, output: 0, cache: { read: 0, write: 0 } }, capabilities: { @@ -102,6 +103,18 @@ describe("session.compaction.isOverflow", () => { }, }) }) + + test("returns true when input limit is reached", async () => { + await using tmp = await tmpdir() + await Instance.provide({ + directory: tmp.path, + fn: async () => { + const model = createModel({ context: 100_000, output: 32_000, inputLimit: 50_000 }) + const tokens = { input: 40_000, output: 5_000, reasoning: 0, cache: { read: 0, write: 0 } } + expect(await SessionCompaction.isOverflow({ tokens, model })).toBe(true) + }, + }) + }) }) describe("util.token.estimate", () => {