fix: strip prompt_cache_key for non-OpenAI openai-responses endpoints#49877
Conversation
Greptile SummaryThis PR fixes a real user-facing bug where third-party providers (e.g. Volcano Engine DeepSeek) using the What changed:
Assessment:
Confidence Score: 4/5
Prompt To Fix All With AIThis is a comment left during a code review.
Path: src/agents/pi-embedded-runner/openai-stream-wrappers.ts
Line: 309-312
Comment:
**No test coverage for stripPromptCache**
The new `stripPromptCache` behavior has no test coverage. Given that:
1. A regression here would silently break prompt caching for all direct OpenAI users without any observable error.
2. The existing `createOpenAIResponsesContextManagementWrapper` has no dedicated test file (confirmed by the absence of `openai-stream-wrappers.test.ts`).
It would be valuable to add unit tests covering at least:
- Volcano Engine (or any non-`isDirectOpenAIBaseUrl` provider) — `prompt_cache_key` and `prompt_cache_retention` are stripped from the payload.
- Native OpenAI (`baseUrl: "https://api.openai.com/v1"`) — fields are **not** stripped.
- Azure OpenAI (`baseUrl: "https://myinstance.openai.azure.com/..."`) — fields are **not** stripped.
- Model with `api !== "openai-responses"` — `stripPromptCache` is `false` (no unnecessary wrapper overhead).
How can I resolve this? If you propose a fix, please make it concise.Last reviewed commit: "fix: strip prompt_ca..." |
| const stripPromptCache = | ||
| typeof model.api === "string" && | ||
| OPENAI_RESPONSES_APIS.has(model.api) && | ||
| !isDirectOpenAIBaseUrl(model.baseUrl); |
There was a problem hiding this comment.
No test coverage for stripPromptCache
The new stripPromptCache behavior has no test coverage. Given that:
- A regression here would silently break prompt caching for all direct OpenAI users without any observable error.
- The existing
createOpenAIResponsesContextManagementWrapperhas no dedicated test file (confirmed by the absence ofopenai-stream-wrappers.test.ts).
It would be valuable to add unit tests covering at least:
- Volcano Engine (or any non-
isDirectOpenAIBaseUrlprovider) —prompt_cache_keyandprompt_cache_retentionare stripped from the payload. - Native OpenAI (
baseUrl: "https://api.openai.com/v1") — fields are not stripped. - Azure OpenAI (
baseUrl: "https://myinstance.openai.azure.com/...") — fields are not stripped. - Model with
api !== "openai-responses"—stripPromptCacheisfalse(no unnecessary wrapper overhead).
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/pi-embedded-runner/openai-stream-wrappers.ts
Line: 309-312
Comment:
**No test coverage for stripPromptCache**
The new `stripPromptCache` behavior has no test coverage. Given that:
1. A regression here would silently break prompt caching for all direct OpenAI users without any observable error.
2. The existing `createOpenAIResponsesContextManagementWrapper` has no dedicated test file (confirmed by the absence of `openai-stream-wrappers.test.ts`).
It would be valuable to add unit tests covering at least:
- Volcano Engine (or any non-`isDirectOpenAIBaseUrl` provider) — `prompt_cache_key` and `prompt_cache_retention` are stripped from the payload.
- Native OpenAI (`baseUrl: "https://api.openai.com/v1"`) — fields are **not** stripped.
- Azure OpenAI (`baseUrl: "https://myinstance.openai.azure.com/..."`) — fields are **not** stripped.
- Model with `api !== "openai-responses"` — `stripPromptCache` is `false` (no unnecessary wrapper overhead).
How can I resolve this? If you propose a fix, please make it concise.|
@codex review |
|
Codex Review: Didn't find any major issues. Another round soon, please! ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
pi-ai unconditionally injects prompt_cache_key and prompt_cache_retention into openai-responses request bodies. Third-party providers using the openai-responses API (e.g. Volcano Engine DeepSeek) reject these unknown fields with HTTP 400. Instead of maintaining a separate provider allowlist, fold the stripping logic into the existing createOpenAIResponsesContextManagementWrapper which already handles openai-responses payload overrides. Use the existing isDirectOpenAIBaseUrl() check to determine whether the endpoint actually supports these fields. Fixes openclaw#48155
834cd1c to
7185eb5
Compare
|
Thanks @ShaunTsai. Landed in bcc725f from source head ShaunTsai@7185eb5 . |
…penclaw#49877) thanks @ShaunTsai Fixes openclaw#48155 Co-authored-by: Shaun Tsai <13811075+ShaunTsai@users.noreply.github.com> Co-authored-by: frankekn <4488090+frankekn@users.noreply.github.com>
…penclaw#49877) thanks @ShaunTsai Fixes openclaw#48155 Co-authored-by: Shaun Tsai <13811075+ShaunTsai@users.noreply.github.com> Co-authored-by: frankekn <4488090+frankekn@users.noreply.github.com>
…enAI proxies PR openclaw#49877 introduced shouldStripResponsesPromptCache() which strips prompt_cache_key and prompt_cache_retention from requests to non-direct OpenAI endpoints. While this prevents 400 errors from endpoints that do not support these fields, it also disables prompt caching for third-party proxies that forward to real OpenAI APIs. Add a compat.supportsPromptCache boolean opt-in that lets users declare their proxy backend supports OpenAI prompt caching, preserving the cache fields in the request payload. Refs openclaw#48155
…penclaw#49877) thanks @ShaunTsai Fixes openclaw#48155 Co-authored-by: Shaun Tsai <13811075+ShaunTsai@users.noreply.github.com> Co-authored-by: frankekn <4488090+frankekn@users.noreply.github.com>
|
This is a rather “costly” fix. As noted in #52017, isn’t the real issue that Volcengine DeepSeek doesn’t fully support the OpenAI Responses API, and that OpenClaw was instead changed in a way that makes it no longer fully compatible? |
…ache_key strip The strip introduced in openclaw#49877 (fixes openclaw#48155 — Volcano Engine DeepSeek rejects prompt_cache_key with HTTP 400) applies to every non-native baseUrl via the usesExplicitProxyLikeEndpoint gate. This catches OpenAI- compatible proxies that DO forward prompt_cache_key correctly — CLIProxy, LiteLLM, vLLM, etc. — and disables prompt caching for agents routed through them. Empirical impact on a CLIProxy-routed agent with a ~40K-token prefix: cached_tokens stays at 0 across consecutive turns on the same session, despite a stable prefix and a stable session-derived prompt_cache_key being constructed upstream in buildOpenAIResponsesParams. Add compat.supportsPromptCacheKey to let operators override the default: - true -> never strip (endpoint is known-compatible, e.g. CLIProxy) - false -> always strip for openai-responses APIs, even on native endpoints (endpoint is known-incompatible) - undefined (default) -> existing behavior preserved: strip only on proxy-like endpoints, so the Volcano Engine fix from openclaw#48155 continues to work without configuration. Validated end-to-end on the maintainer fleet via A/B test on a running agent: before the opt-out, cacheRead=0 across 3 consecutive turns (input_tokens 39856 / 39896 / 39937). After setting compat.supportsPromptCacheKey=true, cacheRead=32256 / 39808 / 39936 and visible input_tokens drops to 7723 / 213 / 127 (99.7% prefix cache hit by turn 3). Adds 3 unit tests to provider-attribution.test.ts covering the override, the forced-strip path, and the preserved default.
…penclaw#49877) thanks @ShaunTsai Fixes openclaw#48155 Co-authored-by: Shaun Tsai <13811075+ShaunTsai@users.noreply.github.com> Co-authored-by: frankekn <4488090+frankekn@users.noreply.github.com>
…penclaw#49877) thanks @ShaunTsai Fixes openclaw#48155 Co-authored-by: Shaun Tsai <13811075+ShaunTsai@users.noreply.github.com> Co-authored-by: frankekn <4488090+frankekn@users.noreply.github.com>
…penclaw#49877) thanks @ShaunTsai Fixes openclaw#48155 Co-authored-by: Shaun Tsai <13811075+ShaunTsai@users.noreply.github.com> Co-authored-by: frankekn <4488090+frankekn@users.noreply.github.com>
…penclaw#49877) thanks @ShaunTsai Fixes openclaw#48155 Co-authored-by: Shaun Tsai <13811075+ShaunTsai@users.noreply.github.com> Co-authored-by: frankekn <4488090+frankekn@users.noreply.github.com>
Summary
openai-responsesAPI) returns HTTP 400unknown field "prompt_cache_key"because pi-ai unconditionally injectsprompt_cache_keyandprompt_cache_retentioninto OpenAI Responses request bodies.prompt_cache_key/prompt_cache_retentionstripping to the existingcreateOpenAIResponsesContextManagementWrapperinopenai-stream-wrappers.ts, using the existingisDirectOpenAIBaseUrl()check to determine whether the endpoint actually supports these fields.isDirectOpenAIBaseUrlcheck). Anthropic caching uses a different mechanism (cacheRetentionoption) and is unaffected. The existingcreateBedrockNoCacheWrapperfor non-Anthropic Bedrock models is also unchanged. No changes toextra-params.ts.Change Type (select all)
Scope (select all touched areas)
Linked Issue/PR
openai-stream-wrappers.tsand was missingazure-openai)User-visible / Behavior Changes
Volcano Engine DeepSeek (and other non-OpenAI providers using
openai-responsesAPI) will no longer fail with HTTP 400 on unknownprompt_cache_keyfield.Security Impact (required)
Repro + Verification
Environment
Steps
volcesprovider withdeepseek-v3-2-251201modelExpected
Actual
unknown field "prompt_cache_key"Evidence
prompt_cache_keyinjection from pi-aiopenai-responsesstream through to the HTTP request body; confirmed the field is only meaningful for OpenAI's own APIisDirectOpenAIBaseUrl()check correctly identifies OpenAI (api.openai.com), ChatGPT (chatgpt.com), and Azure OpenAI (*.openai.azure.com) endpoints — all other baseUrls (including Volcano Engine) return falseHuman Verification (required)
applyExtraParamsToAgent→createOpenAIResponsesContextManagementWrapper→applyOpenAIResponsesPayloadOverrides; confirmedstripPromptCacheis true for non-direct-OpenAI endpoints and false for direct OpenAIazure-openaiprovider with*.openai.azure.combaseUrl passesisDirectOpenAIBaseUrland keeps prompt cache fields; providers with no baseUrl (empty string) get fields stripped (safe — no-op since pi-ai only injects for openai-responses)pnpm checkcurrently has pre-existing typing debt failures onmainunrelated to this PRAI Disclosure
Review Conversations
Compatibility / Migration
Failure Recovery (if this breaks)
src/agents/pi-embedded-runner/openai-stream-wrappers.tsisDirectOpenAIBaseUrlfails to recognize a legitimate OpenAI endpoint, prompt caching would silently stop working for that endpointRisks and Mitigations
api.openai.com,chatgpt.com, or*.openai.azure.com) would needisDirectOpenAIBaseUrlupdated.storefield decisions — any such endpoint would already be broken forstore: trueforcing, so the fix would naturally cover both.