test(cli): cover provider-reported context output cap

Add regression coverage for capOutputTokens preferring the provider-reported
context size (image/vision input priced by the provider) and falling back to
the media-normalized floor when reported usage is smaller or absent.
This commit is contained in:
marius-kilocode
2026-07-03 12:02:06 +02:00
parent 9066bac142
commit a909efe246
3 changed files with 39 additions and 2 deletions
+1 -1
View File
@@ -2,4 +2,4 @@
"@kilocode/cli": patch
---
Preserve model output capacity when requests contain encoded images.
Preserve model output capacity when requests contain encoded images. The output token cap now uses the provider-reported context size from the previous turn, so image and vision input is measured by the provider instead of by encoded payload size.
+2 -1
View File
@@ -1685,10 +1685,11 @@ export const layer = Layer.effect(
tools,
model,
toolChoice: format.type === "json_schema" ? "required" : undefined,
// kilocode_change - feed the provider-reported context size from the last finished
// kilocode_change start - feed the provider-reported context size from the last finished
// turn into the output-token cap, so image/vision input is measured by the provider
// rather than by encoded payload bytes (see KiloLLM.capOutputTokens)
reportedContextTokens: lastFinished ? KiloSessionOverflow.count(lastFinished.tokens) : undefined,
// kilocode_change end
})
if (structured !== undefined) {
@@ -157,6 +157,42 @@ describe("Kilo request estimation", () => {
expect(cap).toBeGreaterThanOrEqual(1_024)
expect(cap).toBeLessThan(32_000)
})
test("prefers provider-reported context over the client estimate for images", () => {
// The client cannot price encoded image bytes, but the provider reported a
// large vision-token cost for the last turn.
const mdl = model({ context: 300_000, output: 32_000 })
const messages = [
{
role: "user",
content: [{ type: "image", image: `data:image/png;base64,${"x".repeat(600_000)}` }],
},
] satisfies ModelMessage[]
// Without reported usage the media-normalized estimate leaves output untouched.
expect(KiloLLM.capOutputTokens({ model: mdl, messages, tools: {}, configured: 32_000 })).toBe(32_000)
// With the provider-reported context size, output is capped to fit real usage.
expect(KiloLLM.capOutputTokens({ model: mdl, messages, tools: {}, configured: 32_000, reported: 280_000 })).toBe(
17_952,
)
})
test("uses the media-normalized floor when reported usage is smaller", () => {
const mdl = model({ context: 200_000, output: 32_000 })
const messages = [{ role: "user" as const, content: "x".repeat(600_000) }]
const withoutReported = KiloLLM.capOutputTokens({ model: mdl, messages, tools: {}, configured: 32_000 })
const withStaleReported = KiloLLM.capOutputTokens({
model: mdl,
messages,
tools: {},
configured: 32_000,
reported: 1_000,
})
expect(withStaleReported).toBe(withoutReported)
expect(withStaleReported).toBeLessThan(32_000)
})
})
describe("Kilo preflight compaction", () => {