Skip to content

feat(providers): Codex 缓存提示协议可选,Responses 对齐 CLI - #436

Merged
su-fen merged 2 commits into
mainfrom
feat/codex-prompt-cache-hint-mode
Aug 12, 2026
Merged

feat(providers): Codex 缓存提示协议可选,Responses 对齐 CLI#436
su-fen merged 2 commits into
mainfrom
feat/codex-prompt-cache-hint-mode

Conversation

@su-fen

@su-fen su-fen commented Aug 12, 2026

Copy link
Copy Markdown
Member

Linked issue

Closes #435

Summary

Codex(OpenAI 兼容)供应商此前只用一个布尔开关控制 Prompt 缓存,无法区分 Responses API、Chat Completions,以及不同端点支持的缓存提示协议。本 PR 将它拆成四选一的 promptCacheHintMode,并让 auto 同时依据请求格式端点能力决定 wire 行为。

模式 wire 行为
auto(默认,推荐) Responses API:所有 Codex 端点都发送会话级 prompt_cache_key,与 Codex CLI 对齐;Chat Completionsapi.openai.com 发送 prompt_cache_keyopenrouter.ai 发送 x-session-id,其他端点不发送缓存提示
openai-key 发送 prompt_cache_key(按会话 id,64 字符上限)
openrouter-session 发送 x-session-id 请求头(256 字符上限)
none 不发送任何缓存提示

设计要点:

  1. Responses API 与 Codex CLI 对齐。Codex CLI 的 Responses 请求使用稳定的会话 ID 作为 prompt_cache_key,不按 Base URL 主机名关闭该字段;LiveAgent 的 auto 现在采用相同行为,第三方 Responses 端点也会收到该键。
  2. Chat Completions 保持保守兼容。严格校验未知参数的中转站 / NVIDIA NIM / DeepSeek / Groq / Moonshot 等端点在 auto 下不会收到 prompt_cache_key,避免 调用模型报错 #307 的 400;OpenRouter 改用 x-session-id 会话粘性头。
  3. 显式设置仍具有最高优先级。用户可以用 openai-key / openrouter-session 覆盖自动判定,或用 none 完全禁用。标题、压缩等请求级 cacheRetention: none 仍会压过 auto,不会发送缓存字段。
  4. 模型级覆盖ProviderModelConfig.promptCacheHintMode 可选,缺省继承供应商设置,适合同一供应商下混用不同协议或能力的模型。
  5. 旧配置无损迁移promptCachingEnabled: falsenone,未设置 → auto。布尔字段仅用于读取旧设置;非 Codex 供应商不受影响,Anthropic 的 ephemeral 缓存断点与 retention 档位保持原行为。
  6. none 从源头禁用缓存提示。该模式会把 cacheRetention 一并压成 none,阻止 pi-ai 在 Responses 或兼容链路生成缓存字段;最终 payload 中间件还会剥离既有的 prompt_cache_keyprompt_cache_retentionprompt_cache_options

Change scope

  • Modules: agent-gui(前端 + src-tauri)/ agent-ui(共享设置 UI)/ agent-gateway/web(WebUI 镜像)
  • Key paths:
路径 变更
crates/agent-gui/src/lib/providers/runtime/codexPromptCache.ts 核心:auto 先按 Responses/Completions 分流,再按端点选择注入或剥离策略
crates/agent-gui/src/lib/providers/runtime/payloadPipeline.ts 将当前模型 API 格式传给缓存提示中间件
crates/agent-gui/src/lib/providers/runtime/requestOptions.ts Codex 的 retention 解析交给 hint mode,请求级禁用仍优先
crates/agent-gui/src/lib/providers/runtime/types.ts / providerRuntimeConfig.ts / textOnlyRuntime.ts mode 参数贯通到聊天与 text-only 请求链路
crates/agent-gui/src/lib/chat/runner/agentRunner.ts 模型级覆盖优先于供应商级
crates/agent-gui/src/lib/settings/index.ts + crates/agent-gateway/web/src/lib/settings/index.ts 类型、常量、归一化与旧配置迁移(两端镜像)
crates/agent-ui/src/pages/settings/ProvidersSection.tsx 供应商级 + 模型级缓存提示协议下拉
crates/agent-gui/src-tauri/src/services/gateway_bridge.rs provider summary 白名单放行新字段
crates/agent-gui/src-tauri/src/services/proxy.rs x-session-id 转发回归测试
两端 i18n/config.ts 中英文案

Screenshots / preview

UI 变更:Codex 供应商弹窗的 Prompt 缓存卡片,开关替换为“缓存提示协议”下拉(4 项);模型编辑区新增“缓存提示协议”下拉(5 项,含“继承供应商设置”)。Anthropic 供应商仍保持开关 + 保留档位。

截图待补:下方 wire 行为与自动化测试可以先用于行为审核;合入前仍需补真实 before/after 截图或录屏以满足 UI 治理要求。

wire 行为

// auto + Responses API:无论是否为第三方域名,都与 Codex CLI 一样发送会话级 key
POST https://relay.example/v1/responses
{
  "model": "gpt-5",
  "input": [...],
  "prompt_cache_key": "conv-1234"
}

// auto + OpenAI Chat Completions:发送 prompt_cache_key
POST https://api.openai.com/v1/chat/completions
{
  "messages": [...],
  "prompt_cache_key": "conv-1234"
}

// auto + 第三方 Chat Completions:严格兼容端点不发送 OpenAI 私有缓存字段
POST https://relay.example/v1/chat/completions
{
  "messages": [...]
}

// auto + OpenRouter Chat Completions:改用会话粘性头
POST https://openrouter.ai/api/v1/chat/completions
x-session-id: conv-1234
{
  "messages": [...]
}

边界行为也有测试覆盖:pi-ai 已写入的字符串 prompt_cache_key 不被覆盖;用户自带的 X-Session-ID 不被顶掉;会话 ID 按 64 / 256 字符分别截断;显式模式覆盖 auto;请求级 cacheRetention: none 在 Responses 下仍禁止发送;prompt_cache_key: undefined 不触发无意义 payload 拷贝。

Verification

pnpm test:gui                                      # 1552 passed / 0 failed
pnpm test:webui                                    #  555 passed / 0 failed
pnpm check:ui-boundaries                           # passed
pnpm exec tsc --noEmit                             # agent-gui passed
pnpm exec tsc --noEmit                             # agent-gateway/web passed
node --test test/providers/request-options.test.mjs # 49 passed / 0 failed
biome check changed files                          # 0 errors; 1 pre-existing noExplicitAny warning
git diff --check                                   # passed

新增/更新的测试:

  • test/providers/request-options.test.mjs:请求格式优先级、第三方 Responses 的 prompt_cache_key 矩阵、第三方 Completions 字段剥离、OpenRouter 头注入、显式覆盖、长度上限、请求级禁用。
  • 同一测试文件通过真实 pi-ai Responses stream() 截获最终 wire payload,确认第三方 Base URL 在 auto 下实际发送稳定的会话 key,而不仅是中间件结构断言。
  • test/settings/normalization.test.mjs + crates/agent-gateway/test/webui/web-settings.test.mjs:双端归一化、旧配置迁移、非法值回落、模型级覆盖、非 Codex 供应商隔离。
  • services/proxy.rsx-session-id 转发。

Pre-submit checklist

  • A requirement issue is linked.
  • Synced with the PR source branch; no concurrent head update was overwritten.
  • The change is focused, with no unrelated modifications.
  • No secrets, tokens, or personal data included.
  • Runtime behavior and bilingual setting copy are updated consistently.
  • Add real before/after screenshots or a recording before merge.

Codex 供应商此前只要开启 Prompt 缓存就无条件补 prompt_cache_key,
第三方中转 / NIM / DeepSeek / Groq 等严格校验未知参数的 OpenAI 兼容端点
因此直接 400(#307)。根因是把"要不要缓存"与"端点认哪种缓存提示协议"
混成一个布尔开关——协议是端点能力,不该由 on/off 决定。

改为四选一的 promptCacheHintMode:
- auto(默认)按 base URL 主机名判定,仅 api.openai.com 发 prompt_cache_key、
  openrouter.ai 发 x-session-id,其余一律不发,退回服务端自动前缀缓存;
- openai-key / openrouter-session 供自建端点手动指定;
- none 完全不发。

模型级可选覆盖,缺省继承供应商设置,解决同一供应商下官方与中转模型混用。
旧配置无损迁移:promptCachingEnabled:false → none,未设置 → auto。

mode=none 时把 cacheRetention 一并压成 none:缓存提示由 pi-ai 在源头按
retention 生成(如 OpenRouter 上 anthropic/* 的 cache_control 断点),
事后剥 payload 已知字段拦不住。

Closes #435
@StackCairn
StackCairn marked this pull request as draft August 12, 2026 11:30
@github-actions

Copy link
Copy Markdown
Contributor

PR governance checks failed — this PR has been converted to draft.

  • UI change without screenshots: this PR modifies frontend code. Please add before/after screenshots or a recording under "Screenshots / preview" in the PR body.

Fix the items above, then click Ready for review to re-run the checks.

@su-fen su-fen added the governance-exempt Skip PR governance checks label Aug 12, 2026
@su-fen
su-fen marked this pull request as ready for review August 12, 2026 11:34
@su-fen su-fen changed the title feat(providers): Codex 缓存提示协议可选,中转端点默认不发 prompt_cache_key feat(providers): Codex 缓存提示协议可选,Responses 对齐 CLI Aug 12, 2026
@su-fen
su-fen merged commit 5a368b6 into main Aug 12, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

governance-exempt Skip PR governance checks

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] Codex 缓存提示协议可选(修中转端点 prompt_cache_key 报 400)

1 participant