Skip to content

fix: [#1009] activate Snowflake Cortex prompt caching for Claude models#1020

Merged
anandgupta42 merged 7 commits into
mainfrom
fix/cortex-prompt-caching
Jul 21, 2026
Merged

fix: [#1009] activate Snowflake Cortex prompt caching for Claude models#1020
anandgupta42 merged 7 commits into
mainfrom
fix/cortex-prompt-caching

Conversation

@anandgupta42

@anandgupta42 anandgupta42 commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

PINEAPPLE

Summary

Fixes #1009 — Snowflake Cortex users on Claude models were getting zero prompt caching (cache_read_input/cache_write_input NULL in TOKENS_GRANULAR), billing every request's full ~300K-token input at the undiscounted rate.

Root cause: Cortex's Chat Completions API only honors caching for Claude models via block-level markers — messages[].content[].cache_control: {"type":"ephemeral"} (max 4 breakpoints; docs). Our pipeline sets the markers as providerOptions.openaiCompatible.cache_control, but @ai-sdk/openai-compatible@2.0.41 serializes them as message-level fields — on system messages, on single-text-part user messages (collapsed to string content), on tool messages — and into assistant tool_calls entries. Cortex silently ignores all of those. This has been the case since the provider shipped (#349); the cost explosion in the issue coincides with Opus 4.7's 1M context making uncached prefixes much larger.

Fix (in the registered plugin packages/opencode/src/altimate/plugin/snowflake.ts, alongside the existing max_tokens body rewrite):

  • relocateCacheControl moves message-level markers into content blocks (string content wrapped in a text block, array content attaches to the last non-empty block), strips stray markers from tool_calls entries, and enforces the 4-breakpoint limit keeping the trailing markers.
  • Live-verified role behavior: Cortex honors block markers on system/user/assistant messages but silently ignores them on role:"tool" (accepted, zero cache activity). A marker destined for a tool message therefore walks back to the nearest earlier cacheable message — in agent loops the trailing breakpoint lands on the last assistant/user message, caching the whole conversation prefix except the newest tool result. Useless markers on tool-message blocks are stripped so they can't burn the breakpoint budget.
  • Safety net: if Cortex ever 400s a cache-marked request, the plugin retries once with markers stripped; if the stripped retry succeeds, caching is disabled for the rest of the session. Worst case degrades to today's behavior (no caching), never breaks requests.
  • Non-Claude models untouched (OpenAI models auto-cache on Cortex; others ignore the field). No other provider goes through this transform.

Test Plan

Live verification (account EJJKBKO-FUB20041, key-pair JWT, claude-sonnet-4-5):

  • System-block marker: cached_tokens: 12466 on both write and read requests ✅
  • User-block marker: cached_tokens: 7563 ✅ · Assistant-block marker: cached_tokens: 8273
  • Tool-block marker: accepted (200) but cached_tokens: 0 → drove the walk-back design
  • Agent-loop shape (assistant text blocks + tool_calls + marker): cached_tokens: 18474
  • Full live e2e suite: 40 pass / 0 fail (2 skip = PAT-only tests)

Automated:

  • Contract test drives ProviderTransform.applyCaching through the real @ai-sdk/openai-compatible serialization (captured fetch) and then transformSnowflakeBody, asserting final block placement — guards against SDK upgrades moving the serialization.
  • 15 new unit tests: relocation per role/shape, walk-back past empty assistant messages, marker dropped with no cacheable predecessor, tool-block stripping, breakpoint cap, non-Claude passthrough, disabled-mode stripping, interceptor 400-retry + sticky disable.
  • bun test test/provider/snowflake.test.ts → 75 pass / 0 fail; typecheck clean; upstream marker check clean.
  • E2E maintenance: live tests moved off claude-3-5-sonnet (now unknown model on current Cortex accounts) to claude-sonnet-4-5.
  • Pre-existing failure note: test/plugin/snowflake-cortex.test.ts ("single-flight refresh") fails on main too — it tests the unregistered OAuth plugin variant, untouched here.

Model catalog refresh + per-family caching verification (follow-up commits)

Probed every candidate model ID live against the Cortex account (2026-07-20):

Added to the picker: claude-sonnet-5 (1M/64K — tools + caching verified live), claude-opus-4-8 (1M/128K — caching verified: 10,369 cached; agent-loop shape 20,385), openai-gpt-5.4, openai-gpt-5.4-mini, openai-gpt-5.4-nano.

Removed: Snowflake-deprecated on 2026-07-08 (deepseek-r1, mistral-large, llama3.1-405b, snowflake-llama-3.3-70b) and delisted/"unknown model" (claude-3-7-sonnet, claude-3-5-sonnet, openai-gpt-5-chat, llama4-scout, snowflake-llama-3.1-405b, mixtral-8x7b, gemini-3.1-pro). Requests to all of these hard-fail on Cortex today. (claude-fable-5 is recognized but gated — noted in the map.)

Caching verified per family (live):

Family Mechanism Result
Claude — all 9 picker models (sonnet-5, opus-4-8/4-7/4-6/4-5, sonnet-4-6/4-5, haiku-4-5, claude-4-sonnet) explicit block markers (this PR's fix) cached on every model (11-14K tokens/probe)
OpenAI gpt-4.1 / gpt-5 / gpt-5.4 / gpt-5.4-mini automatic (Cortex-side) 2nd request shows 11-13K cached
OpenAI gpt-5.2 automatic no cache activity observed on this account
Llama / Mistral n/a markers tolerated (no 400), no caching — as documented

Catalog tests now lock in the verified list and assert removed models are gone. Final runs: 117 unit / 0 fail, live e2e 37 / 0 fail, typecheck clean.

Checklist

  • Tests added/updated
  • Documentation updated
  • CHANGELOG updated

Summary by CodeRabbit

  • New Features
    • Added newly available Claude/Snowflake Cortex and OpenAI GPT-5.4 variants to the model picker (live-verified), including prompt caching and tool calling where supported.
  • Bug Fixes
    • Fixed Snowflake Cortex Claude prompt caching by placing cache markers in the required request locations.
    • Improved resilience: on rejected cache-marked requests, a one-time retry strips markers, then temporarily pauses further marker injection for the session.
  • Documentation
    • Updated Snowflake Cortex docs with caching behavior (discount/TTL) and refreshed available-models guidance.
  • Tests
    • Expanded E2E/unit coverage for prompt caching (issue #1009) and refreshed Snowflake model availability expectations.

Cortex's Chat Completions API only honors prompt caching for Claude models
via block-level markers (`messages[].content[].cache_control`, `ephemeral`,
max 4 breakpoints). `@ai-sdk/openai-compatible` serializes our cache
providerOptions as message-level fields — on `system` messages, on
single-text-part `user` messages (collapsed to string content), on `tool`
messages, and into assistant `tool_calls` entries — all silently ignored by
Cortex, so every request billed the full input rate
(`cache_read_input`/`cache_write_input` stayed NULL in `TOKENS_GRANULAR`).

- `relocateCacheControl`: move message-level markers into content blocks
  (string content is wrapped in a text block; array content attaches to the
  last non-empty block), strip stray markers from `tool_calls` entries,
  leave pre-existing block-level markers untouched, and enforce the
  4-breakpoint limit keeping the trailing markers (longest prefixes).
- Fallback: if Cortex rejects a cache-marked request with a 400, retry once
  with markers stripped via `stripCacheControl`; when the stripped retry
  succeeds, disable caching for the rest of the session (`cacheControl`
  param on `transformSnowflakeBody` strips all markers when disabled).
- Contract test drives `ProviderTransform.applyCaching` through the real
  `@ai-sdk/openai-compatible` serialization and the plugin transform.
- Env-gated live e2e tests: cache activity via
  `usage.prompt_tokens_details.cached_tokens`, and acceptance of
  `role:"tool"` messages with array content carrying markers.
- Docs + CHANGELOG entries.

Closes #1009

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review for a one-time review, or @claude review always to subscribe this PR to a review on every future push.

Tip: disable this comment in your organization's Code Review settings.

@github-actions

Copy link
Copy Markdown

This PR doesn't fully meet our contributing guidelines and PR template.

What needs to be fixed:

  • PR description is missing required template sections. Please use the PR template.

Please edit this PR description to address the above within 2 hours, or it will be automatically closed.

If you believe this was flagged incorrectly, please let a maintainer know.

@github-actions

github-actions Bot commented Jul 20, 2026

Copy link
Copy Markdown
- - - - - - - - - - - - - - - - - - - - - - - - -
                    AIRECEIPTS                    
            2 sessions behind this PR             

claude-fable-5.........................≥ $146.0492
  session slice: turns 1–255 of 267
  SUBAGENTS (9).........................≥ $18.1693
  CODEX HELPERS (1) — no commits
  gpt-5.6-sol · 12m......................≥ $2.6576
--------------------------------------------------
TOTAL priced...........................≥ $166.8761
  standard API-equivalent floor; not an invoice
  counted: 2 sessions + 9 subagents
  cache served 96% of input tokens

1 GPT-5.6 Codex session omitted cache-write tokens
(floor excludes any write premium — see docs/cost-model.md)
  full receipts + session ids: section below
- - - - - - - - - - - - - - - - - - - - - - - - -
                npx aireceipts-cli                
         github.com/anandgupta42/receipts         
- - - - - - - - - - - - - - - - - - - - - - - - -
full receipts (2 sessions)
session id scope turns time tokens in / out cached
orchestrator 82664c08 turns 1–255 of 267 255 6h 12m 78k / 227k 98%
codex a7762cee no commits 1 12m 155k / 28k 93%

orchestrator · 82664c08

- - - - - - - - - - - - - - - - - - - - - - - - -
                    AIRECEIPTS                    
       “Fix GitHub issue in altimate-code”        
   Claude Code · Jul 20 2026 18:07 UTC · 6h 12m   
               claude-fable-5 100%                
         cache served 98% of input tokens         

pre-edit: 11% of priced floor (40/255 turns)
  (share before the first named edit tool)

Bash.......................≥ $86.9594  (162 calls)
(thinking/reply)............≥ $17.9176  (31 turns)
Edit........................≥ $17.2555  (42 calls)
Skill..........................≥ $9.0206  (1 call)
Write.........................≥ $3.1680  (5 calls)
SendMessage..................≥ $2.2740  (26 calls)
Read..........................≥ $2.0530  (8 calls)
TaskUpdate....................≥ $1.6835  (4 calls)
WebFetch......................≥ $1.5097  (4 calls)
TaskCreate...................≥ $1.1850  (11 calls)
WebSearch.....................≥ $0.9172  (2 calls)
Agent.........................≥ $0.9143  (9 calls)
TaskOutput....................≥ $0.6917  (2 calls)
mcp__codebase-memory-mcp__…...≥ $0.4990  (2 calls)

≈ re-priced eligible trivial spans.......≈ $0.4945
  (9 tiny turns, priced at claude-haiku-4-5)
--------------------------------------------------
TOTAL..................................≥ $146.0485
standard API-equivalent floor; not an invoice
same tokens on claude-haiku-4-5.........≥ $14.6049
  (90% lower observable floor)
  (arithmetic, not a prediction)
- - - - - - - - - - - - - - - - - - - - - - - - -
                npx aireceipts-cli                
         github.com/anandgupta42/receipts         
- - - - - - - - - - - - - - - - - - - - - - - - -
subagents (9)
subagent cost
agent-aglm5-reviewer-81e1a2d9cfc161f3 · claude-sonnet-5 ≥ $3.0816
agent-aminimax-reviewer-af3ab9c88cd88d75 · claude-sonnet-5 ≥ $2.6444
agent-adeepseek-reviewer-7f791f93b26cccb3 · claude-sonnet-5 ≥ $2.3129
agent-agemini-reviewer-1f1f416419a90b2e · claude-sonnet-5 ≥ $1.9977
agent-amimo-reviewer-c05561467a6dfb7f · claude-sonnet-5 ≥ $1.8187
agent-agrok-reviewer-3684d935dddf1a29 · claude-sonnet-5 ≥ $1.7811
agent-aqwen-reviewer-680478472935ab7a · claude-sonnet-5 ≥ $1.7811
agent-agpt-reviewer-0517b09cc8290db1 · claude-sonnet-5 ≥ $1.7437
agent-akimi-reviewer-a21643382d43872f · claude-sonnet-5 ≥ $1.0077

codex · a7762cee

- - - - - - - - - - - - - - - - - - - - - - - - -
                    AIRECEIPTS                    
 “Review this git diff for the fix to GitHub is…” 
    Codex · Jul 20 2026 18:34:20 UTC · 12m 54s    
                 gpt-5.6-sol 100%                 
         cache served 93% of input tokens         

pre-edit: no named edit tool observed
  (share before the first named edit tool)

exec.........................≥ $2.6576  (25 calls)

caveat: Codex trace omits GPT-5.6 cache-write tokens — floor excludes any write premium
--------------------------------------------------
KNOWN PRICED SUBTOTAL....................≥ $2.6576
standard API-equivalent floor; not an invoice
partial pricing coverage; invoice total unknown
same tokens on gpt-5.4-mini..............≥ $0.3986
  (85% lower observable floor)
  (arithmetic, not a prediction)
- - - - - - - - - - - - - - - - - - - - - - - - -
                npx aireceipts-cli                
         github.com/anandgupta42/receipts         
- - - - - - - - - - - - - - - - - - - - - - - - -
handoff — flagged pattern cost ≈ 4,788,862 tok
FLAGGED PATTERN COST...............≈ 4,788,862 tok
  heuristic pattern subtotal · not proven savings

≈ re-priced eligible trivial spans.......≈ $0.4945
  (9 tiny turns, priced at claude-haiku-4-5)
  → route short replies to a cheaper model

covers: 2 sessions · 256 turns · 1 flagged-pattern line

Generated by aireceipts

@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Snowflake Cortex now supports Claude prompt-cache marker relocation with retry fallback, and its model catalog and documentation are refreshed. Tests cover cache transformations, session behavior, current model availability, and updated Claude model identifiers.

Changes

Snowflake Cortex Claude prompt caching

Layer / File(s) Summary
Cache marker transformation
packages/opencode/src/altimate/plugin/snowflake.ts, packages/opencode/test/provider/snowflake.test.ts
Cache markers move into eligible content blocks, are capped or stripped as needed, and are exposed through cacheApplied; unit and serialization tests cover the behavior.
Session retry fallback
packages/opencode/src/altimate/plugin/snowflake.ts, packages/opencode/test/provider/snowflake.test.ts
HTTP 400 responses trigger one unmarked retry, with successful retries disabling cache injection for the session.
Cortex model catalog
packages/opencode/src/provider/provider.ts, packages/opencode/test/provider/snowflake.test.ts
Claude, OpenAI, and Llama entries are refreshed, capability and limit expectations are updated, and delisted models are removed.
Validation and documentation
packages/opencode/test/altimate/cortex-snowflake-e2e.test.ts, CHANGELOG.md, docs/docs/configure/providers.md
E2E coverage verifies caching and updated Claude flows, while release notes and provider documentation describe the current behavior.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant SnowflakeCortexAuthPlugin
  participant transformSnowflakeBody
  participant Cortex
  Client->>SnowflakeCortexAuthPlugin: Send request
  SnowflakeCortexAuthPlugin->>transformSnowflakeBody: Transform with cache control
  transformSnowflakeBody-->>SnowflakeCortexAuthPlugin: Return body and cacheApplied
  SnowflakeCortexAuthPlugin->>Cortex: Submit marked request
  Cortex-->>SnowflakeCortexAuthPlugin: Return HTTP 400
  SnowflakeCortexAuthPlugin->>Cortex: Retry without cache markers
  Cortex-->>SnowflakeCortexAuthPlugin: Return retry response
Loading

Possibly related PRs

Poem

A rabbit watched the markers hop,
Into content blocks they’d neatly stop.
When Cortex rejected the marked debut,
One unmarked retry came hopping through.
Then Claude cached softly, as rabbits do!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the core change: enabling Snowflake Cortex prompt caching for Claude models.
Description check ✅ Passed The description covers the issue, root cause, fix, verification, and checklist, though it doesn't follow the template headings exactly.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/cortex-prompt-caching

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
packages/opencode/test/altimate/cortex-snowflake-e2e.test.ts (2)

401-402: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consume the first response body.

It is a good practice to consume the response body of the first fetch to ensure the underlying connection can be returned to the pool or gracefully closed before the second request is dispatched.

♻️ Proposed refactor
       const first = await request()
       expect(first.status).toBe(200)
+      await first.text()
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/opencode/test/altimate/cortex-snowflake-e2e.test.ts` around lines
401 - 402, Consume the body of the first response returned by request() before
dispatching the second request, while preserving the existing status assertion
in the test flow.

378-379: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Update the token estimate.

The comment estimates ~1,400 tokens, but 700 iterations of this filler string actually produce around 7,000 tokens (which still safely exceeds the 4,096 minimum for Opus/Haiku).

📝 Proposed update
-    // ~1,400 tokens of deterministic filler — above the 1,024-token minimum
+    // ~7,000 tokens of deterministic filler — above the 1,024-token minimum
     // for claude-3-5-sonnet cache entries (Opus/Haiku models need 4,096).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/opencode/test/altimate/cortex-snowflake-e2e.test.ts` around lines
378 - 379, Update the filler-token estimate comment near the deterministic
filler generation to state approximately 7,000 tokens, while preserving the note
that this exceeds the 4,096-token minimum required by Opus/Haiku models.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/opencode/test/altimate/cortex-snowflake-e2e.test.ts`:
- Around line 401-402: Consume the body of the first response returned by
request() before dispatching the second request, while preserving the existing
status assertion in the test flow.
- Around line 378-379: Update the filler-token estimate comment near the
deterministic filler generation to state approximately 7,000 tokens, while
preserving the note that this exceeds the 4,096-token minimum required by
Opus/Haiku models.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: dcb98848-160e-4283-b6c6-37aa7107b073

📥 Commits

Reviewing files that changed from the base of the PR and between 8a50ec7 and 40234c7.

📒 Files selected for processing (5)
  • CHANGELOG.md
  • docs/docs/configure/providers.md
  • packages/opencode/src/altimate/plugin/snowflake.ts
  • packages/opencode/test/altimate/cortex-snowflake-e2e.test.ts
  • packages/opencode/test/provider/snowflake.test.ts

if (stripped !== body) {
const retry = await fetch(requestInput, { ...init, headers, body: stripped })
if (retry.ok) {
cacheControlSupported = false

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: cacheControlSupported race under concurrent fetches multiplies retries.

The flag is read at transform time (line 290) but only written here after the stripped retry succeeds. Between those points, concurrent in-flight requests all observe the stale true value, so each independently fires with cache markers, 400s, and retries stripped before the session-wide disable propagates. On parallel-agent workloads against an account that rejects markers, this multiplies Cortex request load N-fold during the window (each retry is billable on Snowflake credits) and can compound rate-limit backpressure. An in-flight retry guard or setting the flag before the retry would bound the fan-out.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 84bc9fa0cf (after the sticky flag became a 5-minute cooldown in 1912781896): the cooldown is now set eagerly when the cache-marked 400 is detected — before the probe retry runs — so concurrent in-flight requests stop sending the rejected shape immediately. It rolls back if the probe shows the markers weren't the cause.

@kilo-code-bot

kilo-code-bot Bot commented Jul 20, 2026

Copy link
Copy Markdown

Code Review Summary

Status: 1 Issue Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
packages/opencode/src/altimate/plugin/snowflake.ts 345 cacheControlSupported race under concurrent fetches multiplies retries
Files Reviewed (3 files)
  • packages/opencode/src/altimate/plugin/snowflake.ts - 1 unresolved issue (carried forward)
  • packages/opencode/test/provider/snowflake.test.ts - no issues (previous SUGGESTION resolved: fixture synced with catalog)
  • packages/opencode/test/altimate/cortex-snowflake-e2e.test.ts - no issues

Fix these issues in Kilo Cloud

Previous Review Summaries (4 snapshots, latest commit 10c67e5)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 10c67e5)

Status: 1 Issue Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
packages/opencode/src/altimate/plugin/snowflake.ts 345 cacheControlSupported race under concurrent fetches multiplies retries
Files Reviewed (3 files)
  • packages/opencode/src/altimate/plugin/snowflake.ts - 1 unresolved issue (carried forward)
  • packages/opencode/test/provider/snowflake.test.ts - no issues (previous SUGGESTION resolved: fixture synced with catalog)
  • packages/opencode/test/altimate/cortex-snowflake-e2e.test.ts - no issues

Fix these issues in Kilo Cloud

Previous review (commit 39597d7)

Status: 2 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 1
Issue Details (click to expand)

WARNING

File Line Issue
packages/opencode/src/altimate/plugin/snowflake.ts 340 cacheControlSupported race under concurrent fetches multiplies retries

SUGGESTION

File Line Issue
packages/opencode/test/provider/snowflake.test.ts 54 TOOLCAPABLE_FIXTURE retains models removed by this PR's catalog refresh
Files Reviewed (6 files)
  • packages/opencode/src/provider/provider.ts - no issues
  • packages/opencode/test/provider/snowflake.test.ts - 1 issue
  • packages/opencode/test/altimate/cortex-snowflake-e2e.test.ts - no issues
  • CHANGELOG.md - no issues
  • docs/docs/configure/providers.md - no issues
  • packages/opencode/src/altimate/plugin/snowflake.ts - 1 issue (carried forward, unchanged lines)

Fix these issues in Kilo Cloud

Previous review (commit 04b0faf)

Status: 1 Issue Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
packages/opencode/src/altimate/plugin/snowflake.ts 340 cacheControlSupported race under concurrent fetches multiplies retries
Files Reviewed (3 files)
  • packages/opencode/src/altimate/plugin/snowflake.ts - 1 issue (carried forward, unchanged lines)
  • packages/opencode/test/altimate/cortex-snowflake-e2e.test.ts - no issues
  • packages/opencode/test/provider/snowflake.test.ts - no issues

Fix these issues in Kilo Cloud

Previous review (commit 40234c7)

Status: 1 Issue Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
packages/opencode/src/altimate/plugin/snowflake.ts 311 cacheControlSupported race under concurrent fetches multiplies retries
Files Reviewed (5 files)
  • packages/opencode/src/altimate/plugin/snowflake.ts - 1 issue
  • CHANGELOG.md - no issues
  • docs/docs/configure/providers.md - no issues
  • packages/opencode/test/altimate/cortex-snowflake-e2e.test.ts - no issues
  • packages/opencode/test/provider/snowflake.test.ts - no issues

Fix these issues in Kilo Cloud


Reviewed by glm-5.2 · Input: 23.4K · Output: 2.4K · Cached: 195.6K

Review guidance: REVIEW.md from base branch main

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 5 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread packages/opencode/src/altimate/plugin/snowflake.ts Outdated
Comment thread packages/opencode/src/altimate/plugin/snowflake.ts Outdated
Live verification against a real Cortex account (claude-sonnet-4-5) showed
Cortex honors block-level `cache_control` on system/user/assistant messages
(cache activity confirmed via `usage.prompt_tokens_details.cached_tokens`),
but **silently ignores** markers on `role:"tool"` messages (accepted, zero
cache). Relocation now walks a tool-message marker back to the nearest
earlier cacheable message — in agent loops the trailing breakpoint lands on
the last assistant/user message, which caches the full conversation prefix
except the newest tool result. Markers already sitting on tool-message
blocks are stripped so they don't burn the 4-breakpoint budget.

Also verified live: assistant messages with text blocks + `tool_calls` +
marker cache correctly (the exact mid-loop shape the plugin now emits), and
array content on `role:"tool"` never 400s (the fallback retry stays as
insurance only).

E2E suite updates: swap `claude-3-5-sonnet` (now "unknown model" on current
Cortex accounts) for `claude-sonnet-4-5` in live-network tests, and add an
agent-loop caching test. Full live run: 40 pass / 0 fail via key-pair JWT.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

1 similar comment
@github-actions

Copy link
Copy Markdown

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/opencode/test/altimate/cortex-snowflake-e2e.test.ts (1)

35-38: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Add claude-sonnet-4-5 to TOOLCAPABLE_E2E_FIXTURE.

transformSnowflakeBody() keeps tools only for allowlisted models, and this file now exercises claude-sonnet-4-5 in the tool-calling paths. Leaving the fixture on claude-3-5-sonnet/claude-sonnet-4-6 makes the new model look non-tool-capable in these checks.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/opencode/test/altimate/cortex-snowflake-e2e.test.ts` around lines 35
- 38, Add "claude-sonnet-4-5" to the TOOLCAPABLE_E2E_FIXTURE allowlist so
tool-calling checks preserve tools for this model.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@packages/opencode/test/altimate/cortex-snowflake-e2e.test.ts`:
- Around line 35-38: Add "claude-sonnet-4-5" to the TOOLCAPABLE_E2E_FIXTURE
allowlist so tool-calling checks preserve tools for this model.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: eb22836c-2995-4173-95d1-336e2e4c0048

📥 Commits

Reviewing files that changed from the base of the PR and between 40234c7 and 04b0faf.

📒 Files selected for processing (3)
  • packages/opencode/src/altimate/plugin/snowflake.ts
  • packages/opencode/test/altimate/cortex-snowflake-e2e.test.ts
  • packages/opencode/test/provider/snowflake.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/opencode/src/altimate/plugin/snowflake.ts

…per family

Catalog probed live against a Cortex account (2026-07-20, every ID via
/chat/completions):

Added:
- `claude-sonnet-5` (1M ctx / 64K out) — tool calling and prompt caching
  verified live (cache markers honored, 8,965 cached tokens)
- `claude-opus-4-8` (1M / 128K, public preview) — caching verified
  (10,369 cached; agent-loop shape 20,385)
- `openai-gpt-5.4` (gpt-5 family defaults), `openai-gpt-5.4-mini` and
  `openai-gpt-5.4-nano` (400K / 128K per Snowflake's restrictions table)

Removed (requests hard-fail on Cortex now):
- Deprecated by Snowflake on 2026-07-08: `deepseek-r1`, `mistral-large`,
  `llama3.1-405b`, `snowflake-llama-3.3-70b`
- Delisted ("unknown model"): `claude-3-7-sonnet`, `claude-3-5-sonnet`,
  `openai-gpt-5-chat`, `llama4-scout`, `snowflake-llama-3.1-405b`,
  `mixtral-8x7b`, `gemini-3.1-pro`

Caching verified per family on the live account:
- Claude (all 9 picker models): explicit block markers cache on every model
- OpenAI: automatic caching confirmed on gpt-4.1 / gpt-5 / gpt-5.4 /
  gpt-5.4-mini (second request shows 11-13K cached tokens); gpt-5.2 showed
  no cache activity in this account/region
- Llama/Mistral: markers tolerated (no 400), no caching, as documented

`claude-fable-5` is recognized by Cortex (maps to claude-fable-5-global)
but unavailable on tested accounts — noted in the map for later.

Catalog tests updated to lock in the verified list, including assertions
that removed models are gone from the picker. Live e2e: 37 pass / 0 fail.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

2 similar comments
@github-actions

Copy link
Copy Markdown

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

@github-actions

Copy link
Copy Markdown

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

const TOOLCAPABLE_FIXTURE: ReadonlySet<string> = new Set([
"claude-opus-4-7", "claude-sonnet-4-6", "claude-opus-4-6", "claude-sonnet-4-5",
"claude-opus-4-8", "claude-opus-4-7", "claude-sonnet-4-6", "claude-opus-4-6", "claude-sonnet-4-5",
"claude-opus-4-5", "claude-haiku-4-5", "claude-4-sonnet", "claude-3-7-sonnet",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SUGGESTION: Fixture retains models this PR removed from the catalog.

TOOLCAPABLE_FIXTURE still lists claude-3-7-sonnet, claude-3-5-sonnet (lines 54-55), and openai-gpt-5-chat (line 57) — all removed from provider.ts in this same PR — and is missing the newly added claude-sonnet-5 and openai-gpt-5.4 / -mini / -nano. The fixture header (lines 48-49) states it "reflects what Snowflake Cortex actually accepts tools for today," which is no longer accurate. The e2e counterpart TOOLCAPABLE_E2E_FIXTURE was fully synced with the new catalog; this unit-test fixture only had claude-opus-4-8 added. Syncing it keeps both fixtures consistent and avoids misleading future maintainers.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 10c67e5918: TOOLCAPABLE_FIXTURE is synced with the refreshed catalog — removed claude-3-7-sonnet/claude-3-5-sonnet/openai-gpt-5-chat, added claude-sonnet-5 and the openai-gpt-5.4 family.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 39597d74de

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

if (response.status === 400 && cacheApplied && typeof body === "string") {
const stripped = stripCacheControl(body)
if (stripped !== body) {
const retry = await fetch(requestInput, { ...init, headers, body: stripped })

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve the original 400 when the fallback fetch rejects

When a cache-marked Cortex request returns 400 but the marker-free retry encounters a transport failure or an already-aborted signal, this unguarded await fetch(...) rejects and discards the valid original response. The Snowflake fetch interceptor then surfaces a network exception instead of the original Cortex diagnostic, contradicting the fallback's intended fail-safe behavior; catch retry failures and return response in that case.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 84bc9fa0cf: the probe retry is wrapped in try/catch — on a transport failure the eager cooldown is rolled back and the original Cortex 400 (with its diagnostic body) is returned. Covered by a new unit test ("returns the original 400 and keeps caching enabled when the retry fetch throws").

// Cortex documents block-level cache_control for Claude models, but not
// for every message role. If an account rejects a cache-marked request,
// fall back once and stop injecting markers for the rest of the session.
let cacheControlSupported = true

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Scope the sticky cache disable to the affected session

When any request-specific cache marker shape receives a 400 and succeeds after stripping, this flag is set to false in the auth-loader closure. The loader output is retained by the instance-scoped Provider state, so the disable applies to every later Snowflake conversation and Claude model in that workspace—not merely the affected session as documented—and remains until provider state is rebuilt. A single unsupported block shape can therefore silently restore full uncached billing for unrelated sessions.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 1912781896: the disable is no longer sticky at any scope — it's a 5-minute cooldown (matching Cortex's ephemeral cache TTL), so a trip affects at most one cold-cache window across the provider instance and self-heals. Comments/docs updated to say "pause" rather than "session".

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 5 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread packages/opencode/test/provider/snowflake.test.ts Outdated

@dev-punia-altimate dev-punia-altimate left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Code Review — OpenCodeReview (Gemini) — 3 finding(s)

  • 3 anchored to a line (posted inline when the comment stream is on)
  • 0 without a line anchor
All findings (full text)

1. packages/opencode/src/altimate/plugin/snowflake.ts (L337-L346)

[🟠 MEDIUM] High Severity Issue: Missing Cleanup on Fetch Exception
If the retry fetch call throws an exception (e.g., a network error or DNS failure), the original response.body stream is never cancelled. This can cause the original connection to stay open, leading to memory leaks and socket exhaustion.
Consider wrapping the retry logic in a try...catch block to ensure cleanup on error.

Suggested change:

              if (stripped !== body) {
                try {
                  const retry = await fetch(requestInput, { ...init, headers, body: stripped })
                  if (retry.ok) {
                    cacheControlSupported = false
                    void response.body?.cancel().catch(() => {})
                    return retry
                  }
                  void retry.body?.cancel().catch(() => {})
                  return response
                } catch (error) {
                  void response.body?.cancel().catch(() => {})
                  throw error
                }
              }

2. packages/opencode/src/altimate/plugin/snowflake.ts (L205-L207)

[🔴 HIGH] High Severity Issue: Bypassed Cache Stripping for Non-Claude Models
When cacheControl is true but the model does not include "claude" (e.g., Llama or Mistral), relocateCacheControl returns false early and leaves the original payload untouched. This causes stripParsedCacheControl to be bypassed, leaving cache_control markers intact on non-Claude requests, which Snowflake Cortex rejects with a 400 Bad Request error.
If relocation fails or isn't applicable, we should strip the markers to ensure compatibility.

Suggested change:

  let cacheApplied = false
  if (cacheControl) {
    cacheApplied = relocateCacheControl(parsed)
    if (!cacheApplied) stripParsedCacheControl(parsed)
  } else {
    stripParsedCacheControl(parsed)
  }

3. packages/opencode/src/altimate/plugin/snowflake.ts (L46-L48)

[🔵 LOW] Code Quality Issue: Missing Comment for any Type
According to the TypeScript type standards, any type should be avoided. If its use is strictly necessary, an explanatory comment should be provided to clarify why Record<string, any> is needed here (e.g., to easily read and mutate arbitrary JSON properties like content or cache_control later).

Suggested change:

// Using `any` is necessary here to allow flexible reading and modification of
// arbitrary JSON properties (e.g., `content`, `cache_control`, `tool_calls`).
function isRecord(value: unknown): value is Record<string, any> {
  return typeof value === "object" && value !== null && !Array.isArray(value)
}

Comment on lines +337 to +346
if (stripped !== body) {
const retry = await fetch(requestInput, { ...init, headers, body: stripped })
if (retry.ok) {
cacheControlSupported = false
void response.body?.cancel().catch(() => {})
return retry
}
void retry.body?.cancel().catch(() => {})
return response
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[🟠 MEDIUM] High Severity Issue: Missing Cleanup on Fetch Exception
If the retry fetch call throws an exception (e.g., a network error or DNS failure), the original response.body stream is never cancelled. This can cause the original connection to stay open, leading to memory leaks and socket exhaustion.
Consider wrapping the retry logic in a try...catch block to ensure cleanup on error.

Suggested change:

Suggested change
if (stripped !== body) {
const retry = await fetch(requestInput, { ...init, headers, body: stripped })
if (retry.ok) {
cacheControlSupported = false
void response.body?.cancel().catch(() => {})
return retry
}
void retry.body?.cancel().catch(() => {})
return response
}
if (stripped !== body) {
try {
const retry = await fetch(requestInput, { ...init, headers, body: stripped })
if (retry.ok) {
cacheControlSupported = false
void response.body?.cancel().catch(() => {})
return retry
}
void retry.body?.cancel().catch(() => {})
return response
} catch (error) {
void response.body?.cancel().catch(() => {})
throw error
}
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 84bc9fa0cf: the retry fetch is wrapped in try/catch and the original response is returned on failure, so the original connection is handed back to the caller rather than abandoned. (When the retry succeeds, the original body was already being cancelled.)

Comment on lines +205 to +207
let cacheApplied = false
if (cacheControl) cacheApplied = relocateCacheControl(parsed)
else stripParsedCacheControl(parsed)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[🔴 HIGH] High Severity Issue: Bypassed Cache Stripping for Non-Claude Models
When cacheControl is true but the model does not include "claude" (e.g., Llama or Mistral), relocateCacheControl returns false early and leaves the original payload untouched. This causes stripParsedCacheControl to be bypassed, leaving cache_control markers intact on non-Claude requests, which Snowflake Cortex rejects with a 400 Bad Request error.
If relocation fails or isn't applicable, we should strip the markers to ensure compatibility.

Suggested change:

Suggested change
let cacheApplied = false
if (cacheControl) cacheApplied = relocateCacheControl(parsed)
else stripParsedCacheControl(parsed)
let cacheApplied = false
if (cacheControl) {
cacheApplied = relocateCacheControl(parsed)
if (!cacheApplied) stripParsedCacheControl(parsed)
} else {
stripParsedCacheControl(parsed)
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This finding is factually incorrect: Snowflake Cortex does NOT 400 on cache markers for non-Claude models — it silently ignores them, per Snowflake's compatibility chart ("ignored for OpenAI and others") and live verification on a real account (llama4-maverick / llama3.1-8b / mistral-large2 / mistral-7b all returned 200 with block-level markers present, cached_tokens 0). Leaving non-Claude payloads untouched is deliberate; stripping them would alter requests for no benefit. No change made — though 84bc9fa0cf does tighten the opposite direction (disabled-mode stripping is now Claude-scoped).

Comment on lines +46 to +48
function isRecord(value: unknown): value is Record<string, any> {
return typeof value === "object" && value !== null && !Array.isArray(value)
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[🔵 LOW] Code Quality Issue: Missing Comment for any Type
According to the TypeScript type standards, any type should be avoided. If its use is strictly necessary, an explanatory comment should be provided to clarify why Record<string, any> is needed here (e.g., to easily read and mutate arbitrary JSON properties like content or cache_control later).

Suggested change:

Suggested change
function isRecord(value: unknown): value is Record<string, any> {
return typeof value === "object" && value !== null && !Array.isArray(value)
}
// Using `any` is necessary here to allow flexible reading and modification of
// arbitrary JSON properties (e.g., `content`, `cache_control`, `tool_calls`).
function isRecord(value: unknown): value is Record<string, any> {
return typeof value === "object" && value !== null && !Array.isArray(value)
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 84bc9fa0cf: added a comment on isRecord explaining the deliberate Record<string, any> (arbitrary request-body JSON navigated and mutated without a fixed schema).

Addresses the converged 10-reviewer consensus review (2 majors, 6 minors):

- Sync `TOOLCAPABLE_FIXTURE` with the live catalog (drop `claude-3-7-sonnet`,
  `claude-3-5-sonnet`, `openai-gpt-5-chat`; add `claude-sonnet-5` and the
  `openai-gpt-5.4` family).
- Replace the dead `DeepSeek R1 Reasoning` e2e block (passed vacuously via a
  status guard against the removed model) with a negative test asserting
  Cortex rejects the deprecated `deepseek-r1`.
- Tighten the caching gate from `includes("claude")` to
  `startsWith("claude-")` — no false positives on user aliases.
- Narrow the interceptor's catch to `SyntaxError`: non-JSON bodies still pass
  through, but transform bugs now surface instead of silently disabling both
  caching and the `max_tokens` rename.
- Build the 400-retry body via `transformSnowflakeBody(text, toolCapable,
  false)` so the fallback request matches the clean disabled-mode shape;
  remove the now-unused `stripCacheControl` export.
- Log a warning when caching is sticky-disabled (previously silent loss of
  the cache discount). The retry remains unscoped by design — Cortex's
  marker-rejection error text is undocumented, and a deterministic
  non-marker 400 recurs identically on the retry, never flipping the flag.
- Add `openai-gpt-5.4-mini`/`-nano` to the e2e availability list; retarget
  the removed-model tool-strip unit test to `mistral-7b`.
- Document `cacheApplied` in the `transformSnowflakeBody` JSDoc; add tests
  for the prefix gate and for a marker attaching to a trailing non-text
  block (previously untested path).

Verified: 76 unit tests, live e2e 39 pass / 0 fail (key-pair JWT), typecheck
and upstream marker check clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

@anandgupta42

Copy link
Copy Markdown
Contributor Author

Multi-model consensus code review completed (Claude + GPT 5.4, Gemini 3.1 Pro, Kimi K2.6, Grok 4.20, MiniMax M2.7, GLM-5.1, Qwen 3.6 Plus, MiMo V2.5 Pro, DeepSeek V4 Pro; 1 convergence round).

Verdict was REQUEST CHANGES — 0 critical, 2 majors (both test hygiene), 6 minors, all now addressed in 10c67e5918:

  • Synced TOOLCAPABLE_FIXTURE with the live catalog (7/10 reviewers)
  • Replaced the vacuous deepseek-r1 e2e block with a negative rejection test (4 reviewers)
  • includes("claude")startsWith("claude-") (7 reviewers)
  • Interceptor catch narrowed to SyntaxError so transform bugs surface (DeepSeek)
  • 400-retry body now built via the clean disabled-mode transform; stripCacheControl export removed (GLM-5.1)
  • Warn log when caching is sticky-disabled (6 reviewers); retry stays unscoped by design (no documented Cortex error signal; deterministic 400s recur on retry and never flip the flag — per Grok's re-verification)
  • e2e allModels + unit-test model IDs refreshed; cacheApplied documented; 2 new unit tests (prefix gate, non-text-block attach)

The core caching implementation passed all ten reviewers. Follow-up notes (non-blocking, tracked in the review artifacts): attachMarker dedupe could continue the walk-back for an extra fallback breakpoint; live-probe whether Cortex honors markers on image blocks; dormant src/plugin/snowflake-cortex.ts + packages/core PluginV2 port lack the caching fix if ever revived; new Claude entries follow the existing reasoning: false catalog pattern.

Post-fix verification: 76 unit / 0 fail · live e2e 39 / 0 fail (key-pair JWT against a real account) · typecheck + marker check clean.

@github-actions

Copy link
Copy Markdown

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

@dev-punia-altimate

Copy link
Copy Markdown
Contributor

🤖 Code Review — OpenCodeReview (Gemini) — No Issues Found

No supported files changed.

The 400-fallback previously disabled marker injection for the REST of the
session — a false trip (transient 400 whose stripped retry happened to
succeed) would silently bill every subsequent request at the uncached rate,
reintroducing the exact cost blowout this fix exists to prevent.

Replace the session-permanent flag with `cacheDisabledUntil`, a cooldown
deadline set to `CACHE_DISABLE_COOLDOWN_MS` (5 minutes — Cortex's ephemeral
cache TTL, so by expiry the cache would be cold anyway). This bounds both
failure modes:

- False trip: caching self-heals after <= 5 minutes instead of never.
- Account that genuinely rejects markers (hypothetical — every live probe
  accepted them): one wasted marked-attempt + retry per cooldown period.

Cooldown test uses `setSystemTime` to verify markers resume after expiry.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@anandgupta42

Copy link
Copy Markdown
Contributor Author

Follow-up to the review batch: the 400-fallback is no longer session-permanent. 1912781896 replaces the sticky disable with a 5-minute cooldown (matching Cortex's ephemeral cache TTL) — a false trip now self-heals in ≤5 minutes instead of silently billing the rest of the session at the uncached rate, while a genuinely marker-rejecting account costs only one wasted retry per cooldown period. Cooldown expiry is covered by a setSystemTime unit test. Re-verified: 76 unit / 0 fail, live e2e 39 / 0 fail, typecheck + marker check clean.

@github-actions

Copy link
Copy Markdown

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

1 similar comment
@github-actions

Copy link
Copy Markdown

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/opencode/src/altimate/plugin/snowflake.ts (1)

351-365: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Ensure cleanup of original response on retry fetch exception.

If the retry fetch throws an exception (e.g., a network error or DNS failure), the original response.body stream is never cancelled. This leaves the original connection open, which can lead to memory leaks and socket exhaustion. Wrap the retry fetch in a try...catch block to guarantee cleanup on error.

🐛 Proposed fix
-              const stripped = transformSnowflakeBody(text, toolCapable, false).body
-              if (stripped !== body) {
-                const retry = await fetch(requestInput, { ...init, headers, body: stripped })
-                if (retry.ok) {
-                  cacheDisabledUntil = Date.now() + CACHE_DISABLE_COOLDOWN_MS
-                  log.warn("Cortex rejected cache-marked request; pausing prompt caching", {
-                    status: response.status,
-                    cooldownMs: CACHE_DISABLE_COOLDOWN_MS,
-                  })
-                  void response.body?.cancel().catch(() => {})
-                  return retry
-                }
-                void retry.body?.cancel().catch(() => {})
-                return response
-              }
+              const stripped = transformSnowflakeBody(text, toolCapable, false).body
+              if (stripped !== body) {
+                let retry: Response
+                try {
+                  retry = await fetch(requestInput, { ...init, headers, body: stripped })
+                } catch (error) {
+                  void response.body?.cancel().catch(() => {})
+                  throw error
+                }
+
+                if (retry.ok) {
+                  cacheDisabledUntil = Date.now() + CACHE_DISABLE_COOLDOWN_MS
+                  log.warn("Cortex rejected cache-marked request; pausing prompt caching", {
+                    status: response.status,
+                    cooldownMs: CACHE_DISABLE_COOLDOWN_MS,
+                  })
+                  void response.body?.cancel().catch(() => {})
+                  return retry
+                }
+                void retry.body?.cancel().catch(() => {})
+                return response
+              }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/opencode/src/altimate/plugin/snowflake.ts` around lines 351 - 365,
Update the retry fetch flow in the transformSnowflakeBody handling block to wrap
fetch(requestInput, { ...init, headers, body: stripped }) in try/catch. If the
retry throws, cancel the original response.body stream before propagating the
exception, while preserving the existing successful retry and failed retry
response behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@packages/opencode/src/altimate/plugin/snowflake.ts`:
- Around line 351-365: Update the retry fetch flow in the transformSnowflakeBody
handling block to wrap fetch(requestInput, { ...init, headers, body: stripped })
in try/catch. If the retry throws, cancel the original response.body stream
before propagating the exception, while preserving the existing successful retry
and failed retry response behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 34058fae-52a0-4845-84a5-d5cdd7fb75df

📥 Commits

Reviewing files that changed from the base of the PR and between 10c67e5 and 96280da.

📒 Files selected for processing (3)
  • CHANGELOG.md
  • packages/opencode/src/altimate/plugin/snowflake.ts
  • packages/opencode/test/provider/snowflake.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • CHANGELOG.md
  • packages/opencode/test/provider/snowflake.test.ts

- Close the concurrency window (kilo-code-bot, cubic): the cooldown is now
  set eagerly when a cache-marked 400 is detected, before the probe retry
  runs, so concurrent in-flight requests stop sending the rejected shape
  immediately; it is rolled back if the retry shows markers weren't the
  cause (retry also fails) or the probe hits a transport error.
- Preserve the original 400 when the probe retry fetch throws (Codex,
  OpenCodeReview): the unguarded `await fetch` could replace Cortex's
  diagnostic with a network exception; the retry is now wrapped and the
  original response returned on transport failure.
- Scope disabled-mode stripping to Claude models (cubic): non-Claude
  payloads pass through untouched during a cooldown instead of having
  their (Cortex-ignored) markers removed.
- Consume the first response body in the caching e2e test (CodeRabbit);
  document the deliberate `any` in `isRecord` (OpenCodeReview).

New tests: disabled-mode non-Claude passthrough; retry-fetch-throws returns
the original 400 and rolls back the cooldown. 78 unit / 0 fail; live e2e
39 / 0 fail; typecheck + marker check clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

@anandgupta42

Copy link
Copy Markdown
Contributor Author

Review-bot findings addressed in 84bc9fa0cf (each thread has an inline reply):

  • Concurrency window (kilo-code-bot, cubic): cooldown now set eagerly on 400 detection, rolled back if the probe retry shows markers weren't the cause.
  • Unguarded retry fetch (Codex, OpenCodeReview): wrapped — transport failure returns the original Cortex 400 instead of a network exception.
  • Disabled-mode stripping (cubic): Claude-scoped; non-Claude payloads pass through untouched.
  • Nits (CodeRabbit, OpenCodeReview): first e2e response body consumed; isRecord's any documented.
  • Rebutted: the HIGH claiming Cortex 400s on non-Claude cache markers — live probes show Cortex silently ignores them (llama/mistral returned 200 with markers present); details in the thread.
  • Fixture-drift and session-scope comments were against 39597d74de and were already resolved by 10c67e5918/1912781896.

Verified after changes: 78 unit / 0 fail · live e2e 39 / 0 fail (two runs, key-pair JWT) · typecheck + marker check clean.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 3 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/opencode/src/altimate/plugin/snowflake.ts">

<violation number="1" location="packages/opencode/src/altimate/plugin/snowflake.ts:364">
P2: Concurrent 400 probes can clear the cooldown after another probe succeeds, so subsequent requests resume sending the rejected cache-marker shape. Associate restoration with this probe's deadline (or serialize probes) so a stale failed retry cannot overwrite a newer in-flight pause.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

// sending the rejected shape while this probe retry runs;
// restored below if the retry shows markers weren't the cause.
const previousDisabledUntil = cacheDisabledUntil
cacheDisabledUntil = Date.now() + CACHE_DISABLE_COOLDOWN_MS

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Concurrent 400 probes can clear the cooldown after another probe succeeds, so subsequent requests resume sending the rejected cache-marker shape. Associate restoration with this probe's deadline (or serialize probes) so a stale failed retry cannot overwrite a newer in-flight pause.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/opencode/src/altimate/plugin/snowflake.ts, line 364:

<comment>Concurrent 400 probes can clear the cooldown after another probe succeeds, so subsequent requests resume sending the rejected cache-marker shape. Associate restoration with this probe's deadline (or serialize probes) so a stale failed retry cannot overwrite a newer in-flight pause.</comment>

<file context>
@@ -350,16 +357,29 @@ export async function SnowflakeCortexAuthPlugin(_input: PluginInput): Promise<Ho
+                // sending the rejected shape while this probe retry runs;
+                // restored below if the retry shows markers weren't the cause.
+                const previousDisabledUntil = cacheDisabledUntil
+                cacheDisabledUntil = Date.now() + CACHE_DISABLE_COOLDOWN_MS
+                let retry: Response
+                try {
</file context>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 84bc9fa0cf

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

retry = await fetch(requestInput, { ...init, headers, body: stripped })
} catch {
// Transport failure on the probe — surface the original 400.
cacheDisabledUntil = previousDisabledUntil

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve concurrent successful cache cooldowns

When two cache-marked requests probe concurrently, one stripped retry can succeed and establish a confirmed cooldown after the other request captured previousDisabledUntil; if the latter retry then throws—or reaches the equivalent restoration after a non-OK response—this unconditional assignment restores the stale timestamp and erases the successful request's cooldown. Subsequent requests resume the rejected marker shape and incur another 400 plus retry, so only roll back if cacheDisabledUntil still equals the value installed by this probe.

Useful? React with 👍 / 👎.

@anandgupta42
anandgupta42 merged commit 9761436 into main Jul 21, 2026
26 of 28 checks passed
@anandgupta42
anandgupta42 deleted the fix/cortex-prompt-caching branch July 21, 2026 02:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

AI spent going through the roof because requests are not cached

2 participants