fix(google): omit request config with cached content#84958
Conversation
Co-authored-by: Cursor <cursoragent@cursor.com>
|
Codex review: needs maintainer review before merge. Workflow note: Future ClawSweeper reviews update this same comment in place. How this review workflow works
Summary Reproducibility: yes. at source level: current main can build a Gemini GenerateContent payload that combines PR rating Rank-up moves:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. Real behavior proof Risk before merge
Maintainer options:
Next step before merge Security Review detailsBest possible solution: Land this focused Google provider payload fix after normal checks, then close #84919 as implemented. Do we have a high-confidence way to reproduce the issue? Yes at source level: current main can build a Gemini GenerateContent payload that combines Is this the best way to solve the issue? Yes. The patch fixes both explicit Label justifications:
What I checked:
Likely related people:
Codex review notes: model gpt-5.5, reasoning high; reviewed against 8961eae3f022. |
|
ClawSweeper PR egg ✨ Hatched: 🥚 common Clockwork Clawlet Hatch commandComment Hatchability rules:
Rarity: 🥚 common. What is this egg doing here?
|
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
|
Landed in
Thanks @neeravmakwana! |
Summary
systemInstruction,tools, andtoolConfigfrom Gemini GenerateContent requests whencachedContentis used.params.cachedContentand managed GeminicacheRetentionprompt caching.Root Cause
OpenClaw had two ways to put
cachedContenton direct Gemini GenerateContent requests:params.cachedContent, serialized by the Google transport itselfcacheRetention, where the embedded-runner Google prompt-cache wrapper creates a GeminicachedContentsresource and patchescachedContentinto the transport payloadThe explicit path sent
cachedContentwhile still serializing request-levelsystemInstruction,tools, andtoolConfig. The managed path stripped the request system prompt, but it still let request tools serialize before patchingcachedContentinto the payload. Google requires system instructions and tools/tool config to be set on the cached content resource whencachedContentis used; sending them again on GenerateContent can return HTTP 400.Fix
options.cachedContentas a cached-content request and skips request-levelsystemInstruction,tools, andtoolConfig.cachedContents.createrequest when tools are present.systemPromptandtoolsfrom the downstream GenerateContent context after it has created or reused the matching cached content.Why This Is Safe
Uncached Gemini requests are unchanged: they still send system prompts and tools directly on GenerateContent. Cached Gemini requests still include
contentsand generation settings such as temperature, max tokens, and thinking config.Security and runtime controls are unchanged for auth resolution, guarded model fetch, request URL/header construction, tool execution policy, and Slack/channel policy. This fix changes provider payload construction and managed cache contents only; it does not rely on prompt text to enforce the policy.
Real Behavior Proof
Behavior addressed: Gemini GenerateContent requests using managed
cacheRetention: "long"with tools no longer send request-levelsystemInstruction,tools, ortoolConfigtogether withcachedContent, avoiding Google 400INVALID_ARGUMENT.Real environment tested: Local macOS checkout, PR head
198a42bbc6, real Google Gemini API,google/gemini-2.5-flash, Gemini API key read from 1Password/Molty service account without logging the secret.Exact steps or command run after this patch: Created a large managed prompt-cache request through
prepareGooglePromptCacheStreamFnwithextraParams: { cacheRetention: "long" }, one tool declaration,toolChoice: "auto", andcreateGoogleGenerativeAiTransportStreamFn; captured the downstream GenerateContent payload viaonPayload; waited forstream.result(); deleted the createdcachedContents/...resource. Also ran the same current-main managed path againstgoogle/gemini-3.5-flashto confirm the pre-fix 400.Evidence after fix:
Current-main repro before fix:
Observed result after fix: The real managed
cacheRetention: "long"request created and used Gemini cached content, omitted all three conflicting request-level keys, returned text with the marker, reportedcacheRead=11886, and cleaned up the cached content with HTTP 200.What was not tested: Slack two-bot delivery was not retested as the passing proof exercises the failing Google provider payload path directly; broad CI remains the merge gate for unrelated channels and platform coverage.
Tests
pnpm check:changedpnpm test src/agents/pi-embedded-runner/google-prompt-cache.test.ts extensions/google/transport-stream.test.ts -- -t "google prompt cache|cachedContent|guarded fetch transport"git diff --checkOut Of Scope
cachedContent.Transparency
AI-assisted change; locally reviewed and validated with focused tests plus live managed Gemini provider proof.