Skip to content

fix(claude-code-proxy): 合并多条 system 消息为单条前置消息 / merge multiple system messages into one leading message - #2714

Merged
EKKOLearnAI merged 1 commit into
EKKOLearnAI:mainfrom
WenhuaXia:fix/claude-code-merged-system-messages
Aug 24, 2026
Merged

fix(claude-code-proxy): 合并多条 system 消息为单条前置消息 / merge multiple system messages into one leading message#2714
EKKOLearnAI merged 1 commit into
EKKOLearnAI:mainfrom
WenhuaXia:fix/claude-code-merged-system-messages

Conversation

@WenhuaXia

Copy link
Copy Markdown
Contributor

摘要 / Summary

Claude Code 2.1.x 把主 prompt 放在顶层 system 字段,同时会把额外的 role: 'system' 消息(如 ToolSearch 延迟工具提示)注入到 messages 中间。anthropicToOpenAiChat 原样保留该消息,产生 [system, user, system] 顺序,vLLM 等强制 system 在首位的 provider 返回 400:System message must be at the beginning。

Claude Code 2.1.x places its primary prompt in the top-level system field but also injects additional role: 'system' messages mid-conversation (e.g. the ToolSearch deferred-tools notice). anthropicToOpenAiChat kept that message in place, producing [system, user, system] order — rejected by vLLM-backed providers with 400 System message must be at the beginning.

修复 / Fix

新增 consolidateAnthropicChatSystemMessages():合并所有 system 消息为单条前置消息(顶层 system 字段优先,其余按原顺序合并)。镜像 PR #2688 对 codex-proxy 的同类修复。

Adds consolidateAnthropicChatSystemMessages(), keeping exactly one leading system message (top-level field first, additional in-message systems merged in original order). Mirrors the earlier codex-proxy fix in PR #2688.

验证 / Verification

  • 端到端复现:用 mock 抓包捕获真实 Claude Code 2.1.240 的 /v1/messages 请求,跑已部署的转换函数,确认产生 [system, user, system] 且 vLLM 返回 400
  • 修复后同一 payload 转换出 [system, user],vLLM 返回 200
  • 新增 2 个回归测试(多 system 合并 + 单 system 保持原位)
  • 43 个 adapter 测试全部通过
  • End-to-end repro with a captured real Claude Code 2.1.240 payload: pre-fix 400, post-fix 200 from the vLLM endpoint
  • 2 new regression tests; all 43 adapter tests pass

测试计划 / Test Plan

  • npm run build(type-check 通过)
  • vitest run tests/server/agent-runner-adapters.test.ts(43 passed)

…ng message

Claude Code 2.1.x sends its primary prompt as the top-level 'system' field
and injects additional role:'system' messages mid-conversation (e.g. the
ToolSearch deferred-tools notice). anthropicToOpenAiChat kept that second
system message in place, which vLLM-backed OpenAI-compatible providers
reject with 400 'System message must be at the beginning.'

Consolidate to exactly one leading system message, mirroring the earlier
codex-proxy fix (responses.ts consolidateChatSystemMessages).

Verified end-to-end: captured a real Claude Code 2.1.240 /v1/messages
payload, ran it through the fixed adapter, and the resulting
chat/completions body now returns 200 from the vLLM Qwen3.8-27B endpoint
(previously 400).
@EKKOLearnAI
EKKOLearnAI merged commit 068791d into EKKOLearnAI:main Aug 24, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants