From 2e5199a40d8791e99dc304ad722bf6baa707f09c Mon Sep 17 00:00:00 2001 From: chrarnoldus <12196001+chrarnoldus@users.noreply.github.com> Date: Mon, 10 Aug 2026 12:49:48 +0000 Subject: [PATCH 1/2] feat(cli): exclude ChatGPT subscriptions from explicit prompt cache breakpoints --- ...de-chatgpt-from-prompt-cache-breakpoint.md | 5 ++ packages/opencode/src/provider/transform.ts | 19 ++++-- .../opencode/test/provider/transform.test.ts | 64 +++++++++++++++++++ 3 files changed, 82 insertions(+), 6 deletions(-) create mode 100644 .changeset/exclude-chatgpt-from-prompt-cache-breakpoint.md diff --git a/.changeset/exclude-chatgpt-from-prompt-cache-breakpoint.md b/.changeset/exclude-chatgpt-from-prompt-cache-breakpoint.md new file mode 100644 index 00000000000..6362bdd7ff1 --- /dev/null +++ b/.changeset/exclude-chatgpt-from-prompt-cache-breakpoint.md @@ -0,0 +1,5 @@ +--- +"@kilocode/cli": patch +--- + +Exclude ChatGPT subscriptions from explicit prompt cache breakpoints. diff --git a/packages/opencode/src/provider/transform.ts b/packages/opencode/src/provider/transform.ts index ff534bf107f..7a9659b25d2 100644 --- a/packages/opencode/src/provider/transform.ts +++ b/packages/opencode/src/provider/transform.ts @@ -328,15 +328,22 @@ function normalizeMessages( return msgs } -// kilocode_change start - explicit prompt cache breakpoints for GPT-5.6+ -function supportsPromptCacheBreakpoint(modelId: string): boolean { - const match = modelId.match(/gpt-(\d+)\.(\d+)/) +// kilocode_change start - explicit prompt cache breakpoints for GPT-5.6+ (excluding ChatGPT subscriptions) +function isChatGPTSubscription(model: Provider.Model): boolean { + if (model.providerID === "openai" && model.cost?.input === 0 && model.cost?.output === 0) return true + if (typeof model.api.url === "string" && model.api.url.includes("chatgpt.com")) return true + return false +} + +function supportsPromptCacheBreakpoint(model: Provider.Model): boolean { + if (isChatGPTSubscription(model)) return false + const match = model.api.id.match(/gpt-(\d+)\.(\d+)/) if (match) { const major = Number(match[1]) const minor = Number(match[2]) if (major > 5 || (major === 5 && minor >= 6)) return true } - const majorMatch = modelId.match(/gpt-(\d+)/) + const majorMatch = model.api.id.match(/gpt-(\d+)/) if (majorMatch && Number(majorMatch[1]) >= 6) return true return false } @@ -366,7 +373,7 @@ function applyCaching(msgs: ModelMessage[], model: Provider.Model): ModelMessage cacheControl: { type: "ephemeral" }, }, // kilocode_change start - ...(supportsPromptCacheBreakpoint(model.api.id) + ...(supportsPromptCacheBreakpoint(model) ? { openai: { promptCacheBreakpoint: { mode: "explicit" }, @@ -494,7 +501,7 @@ export function message(msgs: ModelMessage[], model: Provider.Model, options: Re ((model.api.npm === "@ai-sdk/openai" || model.api.npm === "@ai-sdk/azure" || model.api.npm === "@kilocode/kilo-gateway") && - supportsPromptCacheBreakpoint(model.api.id))) && + supportsPromptCacheBreakpoint(model))) && model.api.npm !== "@ai-sdk/gateway" ) { msgs = applyCaching(msgs, model) diff --git a/packages/opencode/test/provider/transform.test.ts b/packages/opencode/test/provider/transform.test.ts index 74ef174ade8..508f6a8cd0b 100644 --- a/packages/opencode/test/provider/transform.test.ts +++ b/packages/opencode/test/provider/transform.test.ts @@ -3162,6 +3162,70 @@ describe("ProviderTransform.message - cache control on gateway", () => { }, }) }) + + test("openai gpt-5.6 with ChatGPT subscription (zero cost) does not apply promptCacheBreakpoint", () => { + const model = createModel({ + providerID: "openai", + api: { + id: "gpt-5.6", + url: "https://api.openai.com/v1", + npm: "@ai-sdk/openai", + }, + id: "gpt-5.6", + cost: { + input: 0, + output: 0, + cache: { read: 0, write: 0 }, + }, + }) + const msgs = [ + { + role: "system", + content: "You are a helpful assistant", + }, + { + role: "user", + content: "Hello", + }, + ] as any[] + + const result = ProviderTransform.message(msgs, model, {}) as any[] + + expect(result[0].providerOptions?.openai?.promptCacheBreakpoint).toBeUndefined() + expect(result[1].providerOptions?.openai?.promptCacheBreakpoint).toBeUndefined() + }) + + test("openai gpt-5.6 with ChatGPT backend endpoint does not apply promptCacheBreakpoint", () => { + const model = createModel({ + providerID: "openai", + api: { + id: "gpt-5.6", + url: "https://chatgpt.com/backend-api/codex/responses", + npm: "@ai-sdk/openai", + }, + id: "gpt-5.6", + cost: { + input: 0.002, + output: 0.008, + cache: { read: 0.0005, write: 0.002 }, + }, + }) + const msgs = [ + { + role: "system", + content: "You are a helpful assistant", + }, + { + role: "user", + content: "Hello", + }, + ] as any[] + + const result = ProviderTransform.message(msgs, model, {}) as any[] + + expect(result[0].providerOptions?.openai?.promptCacheBreakpoint).toBeUndefined() + expect(result[1].providerOptions?.openai?.promptCacheBreakpoint).toBeUndefined() + }) // kilocode_change end }) From 9b820d2f9d153baf0c8e8840d83c9de98b93ab58 Mon Sep 17 00:00:00 2001 From: chrarnoldus <12196001+chrarnoldus@users.noreply.github.com> Date: Mon, 10 Aug 2026 13:04:02 +0000 Subject: [PATCH 2/2] refactor(cli): simplify ChatGPT subscription detection to zero-cost heuristic Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com> --- packages/opencode/src/provider/transform.ts | 8 ++--- .../opencode/test/provider/transform.test.ts | 34 +------------------ 2 files changed, 4 insertions(+), 38 deletions(-) diff --git a/packages/opencode/src/provider/transform.ts b/packages/opencode/src/provider/transform.ts index 7a9659b25d2..310c9d0c83c 100644 --- a/packages/opencode/src/provider/transform.ts +++ b/packages/opencode/src/provider/transform.ts @@ -329,14 +329,12 @@ function normalizeMessages( } // kilocode_change start - explicit prompt cache breakpoints for GPT-5.6+ (excluding ChatGPT subscriptions) -function isChatGPTSubscription(model: Provider.Model): boolean { - if (model.providerID === "openai" && model.cost?.input === 0 && model.cost?.output === 0) return true - if (typeof model.api.url === "string" && model.api.url.includes("chatgpt.com")) return true - return false +function isLikelyChatGPTSubscription(model: Provider.Model): boolean { + return model.providerID === "openai" && model.cost?.input === 0 && model.cost?.output === 0 } function supportsPromptCacheBreakpoint(model: Provider.Model): boolean { - if (isChatGPTSubscription(model)) return false + if (isLikelyChatGPTSubscription(model)) return false const match = model.api.id.match(/gpt-(\d+)\.(\d+)/) if (match) { const major = Number(match[1]) diff --git a/packages/opencode/test/provider/transform.test.ts b/packages/opencode/test/provider/transform.test.ts index 508f6a8cd0b..e834ec326eb 100644 --- a/packages/opencode/test/provider/transform.test.ts +++ b/packages/opencode/test/provider/transform.test.ts @@ -3163,7 +3163,7 @@ describe("ProviderTransform.message - cache control on gateway", () => { }) }) - test("openai gpt-5.6 with ChatGPT subscription (zero cost) does not apply promptCacheBreakpoint", () => { + test("openai gpt-5.6 with ChatGPT subscription (zero cost heuristic) does not apply promptCacheBreakpoint", () => { const model = createModel({ providerID: "openai", api: { @@ -3194,38 +3194,6 @@ describe("ProviderTransform.message - cache control on gateway", () => { expect(result[0].providerOptions?.openai?.promptCacheBreakpoint).toBeUndefined() expect(result[1].providerOptions?.openai?.promptCacheBreakpoint).toBeUndefined() }) - - test("openai gpt-5.6 with ChatGPT backend endpoint does not apply promptCacheBreakpoint", () => { - const model = createModel({ - providerID: "openai", - api: { - id: "gpt-5.6", - url: "https://chatgpt.com/backend-api/codex/responses", - npm: "@ai-sdk/openai", - }, - id: "gpt-5.6", - cost: { - input: 0.002, - output: 0.008, - cache: { read: 0.0005, write: 0.002 }, - }, - }) - const msgs = [ - { - role: "system", - content: "You are a helpful assistant", - }, - { - role: "user", - content: "Hello", - }, - ] as any[] - - const result = ProviderTransform.message(msgs, model, {}) as any[] - - expect(result[0].providerOptions?.openai?.promptCacheBreakpoint).toBeUndefined() - expect(result[1].providerOptions?.openai?.promptCacheBreakpoint).toBeUndefined() - }) // kilocode_change end })