fix(context-window-monitor): use model-specific context limits

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
YeonGyu-Kim
2026-03-08 02:10:40 +09:00
parent f3be710a73
commit 17707ee835
2 changed files with 103 additions and 3 deletions
@@ -0,0 +1,90 @@
/// <reference types="bun-types" />
import { describe, expect, it } from "bun:test"
import { createContextWindowMonitorHook } from "./context-window-monitor"
function createOutput() {
return { title: "", output: "original", metadata: null }
}
describe("context-window-monitor modelContextLimitsCache", () => {
it("does not append reminder below cached non-anthropic threshold", async () => {
// given
const modelContextLimitsCache = new Map<string, number>()
modelContextLimitsCache.set("opencode/kimi-k2.5-free", 262144)
const hook = createContextWindowMonitorHook({} as never, {
anthropicContext1MEnabled: false,
modelContextLimitsCache,
})
const sessionID = "ses_non_anthropic_below_threshold"
await hook.event({
event: {
type: "message.updated",
properties: {
info: {
role: "assistant",
sessionID,
providerID: "opencode",
modelID: "kimi-k2.5-free",
finish: true,
tokens: {
input: 150000,
output: 0,
reasoning: 0,
cache: { read: 10000, write: 0 },
},
},
},
},
})
// when
const output = createOutput()
await hook["tool.execute.after"]({ tool: "bash", sessionID, callID: "call_1" }, output)
// then
expect(output.output).toBe("original")
})
it("appends reminder above cached non-anthropic threshold", async () => {
// given
const modelContextLimitsCache = new Map<string, number>()
modelContextLimitsCache.set("opencode/kimi-k2.5-free", 262144)
const hook = createContextWindowMonitorHook({} as never, {
anthropicContext1MEnabled: false,
modelContextLimitsCache,
})
const sessionID = "ses_non_anthropic_above_threshold"
await hook.event({
event: {
type: "message.updated",
properties: {
info: {
role: "assistant",
sessionID,
providerID: "opencode",
modelID: "kimi-k2.5-free",
finish: true,
tokens: {
input: 180000,
output: 0,
reasoning: 0,
cache: { read: 10000, write: 0 },
},
},
},
},
})
// when
const output = createOutput()
await hook["tool.execute.after"]({ tool: "bash", sessionID, callID: "call_1" }, output)
// then
expect(output.output).toContain("context remaining")
})
})
+13 -3
View File
@@ -7,6 +7,7 @@ const CONTEXT_WARNING_THRESHOLD = 0.70
type ModelCacheStateLike = {
anthropicContext1MEnabled: boolean
modelContextLimitsCache?: Map<string, number>
}
function getAnthropicActualLimit(modelCacheState?: ModelCacheStateLike): number {
@@ -32,6 +33,7 @@ interface TokenInfo {
interface CachedTokenState {
providerID: string
modelID: string
tokens: TokenInfo
}
@@ -57,13 +59,19 @@ export function createContextWindowMonitorHook(
const cached = tokenCache.get(sessionID)
if (!cached) return
if (!isAnthropicProvider(cached.providerID)) return
const cachedLimit = modelCacheState?.modelContextLimitsCache?.get(
`${cached.providerID}/${cached.modelID}`
)
const actualLimit =
cachedLimit ??
(isAnthropicProvider(cached.providerID) ? getAnthropicActualLimit(modelCacheState) : null)
if (!actualLimit) return
const lastTokens = cached.tokens
const totalInputTokens = (lastTokens?.input ?? 0) + (lastTokens?.cache?.read ?? 0)
const actualUsagePercentage =
totalInputTokens / getAnthropicActualLimit(modelCacheState)
const actualUsagePercentage = totalInputTokens / actualLimit
if (actualUsagePercentage < CONTEXT_WARNING_THRESHOLD) return
@@ -95,6 +103,7 @@ export function createContextWindowMonitorHook(
role?: string
sessionID?: string
providerID?: string
modelID?: string
finish?: boolean
tokens?: TokenInfo
} | undefined
@@ -104,6 +113,7 @@ export function createContextWindowMonitorHook(
tokenCache.set(info.sessionID, {
providerID: info.providerID,
modelID: info.modelID ?? "",
tokens: info.tokens,
})
}