feat(xai): 支持 Claude Messages 兼容转发#5626
Conversation
WalkthroughThe xAI channel adaptor gains functional Claude support: ChangesxAI Claude Format Integration
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
relay/channel/xai/adaptor_test.go (1)
84-111: ⚡ Quick winAdd a regression case for responses without
usage.Please add a non-stream Claude-format test where upstream omits
usage, and assert the handler preserves the intended downstream usage contract (no synthetic zero-token usage).As per coding guidelines, backend tests must protect billing/accounting invariants and regression paths.
🤖 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 `@relay/channel/xai/adaptor_test.go` around lines 84 - 111, Add a new regression test function (similar to TestXAIHandlerConvertsClaudeFormatResponse) that tests the xAIHandler function with a Claude-format response that omits the usage field entirely. In this test, create a responseBody without the usage object, call xAIHandler with the same setup, and verify that the handler does not create synthetic zero-token usage values. Assert that the returned usage is nil or that zero values are not populated to protect the billing/accounting invariants.Source: Coding guidelines
🤖 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.
Inline comments:
In `@relay/channel/xai/text.go`:
- Around line 126-128: The issue is that when xaiResponse.Usage is nil, the
condition at the if statement is not entered, but then at line 142 the code
returns a pointer to openAIResponse.Usage which creates a non-nil pointer to a
zero-valued struct instead of preserving the nil semantics. To fix this, modify
the code to only return the Usage pointer when it was actually populated from
the upstream response. Make the return at line 142 conditional so that it
returns nil for Usage when xaiResponse.Usage was nil (i.e., the if block was not
entered), thereby preserving the nullable semantics and preventing synthetic
zero-token usage from being created when usage data is absent from upstream.
---
Nitpick comments:
In `@relay/channel/xai/adaptor_test.go`:
- Around line 84-111: Add a new regression test function (similar to
TestXAIHandlerConvertsClaudeFormatResponse) that tests the xAIHandler function
with a Claude-format response that omits the usage field entirely. In this test,
create a responseBody without the usage object, call xAIHandler with the same
setup, and verify that the handler does not create synthetic zero-token usage
values. Assert that the returned usage is nil or that zero values are not
populated to protect the billing/accounting invariants.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 5e3119ea-54e0-437d-a1f8-d33d02b5e4f3
📒 Files selected for processing (3)
relay/channel/xai/adaptor.gorelay/channel/xai/adaptor_test.gorelay/channel/xai/text.go
| if xaiResponse.Usage != nil { | ||
| openAIResponse.Usage = *xaiResponse.Usage | ||
| } |
There was a problem hiding this comment.
Preserve nullable usage semantics when upstream omits usage.
At Line 142, returning &openAIResponse.Usage makes usage non-nil even when Line 126 is not entered (xaiResponse.Usage == nil). That turns “usage absent” into synthetic zero-token usage, which can break downstream usage/billing fallback logic.
Suggested fix
openAIResponse := dto.OpenAITextResponse{
Id: xaiResponse.Id,
Object: xaiResponse.Object,
Created: xaiResponse.Created,
Model: xaiResponse.Model,
Choices: xaiResponse.Choices,
}
+ var usagePtr *dto.Usage
if xaiResponse.Usage != nil {
openAIResponse.Usage = *xaiResponse.Usage
+ usagePtr = &openAIResponse.Usage
}
@@
- return &openAIResponse.Usage, nil
+ return usagePtr, nil
}Also applies to: 142-142
🤖 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 `@relay/channel/xai/text.go` around lines 126 - 128, The issue is that when
xaiResponse.Usage is nil, the condition at the if statement is not entered, but
then at line 142 the code returns a pointer to openAIResponse.Usage which
creates a non-nil pointer to a zero-valued struct instead of preserving the nil
semantics. To fix this, modify the code to only return the Usage pointer when it
was actually populated from the upstream response. Make the return at line 142
conditional so that it returns nil for Usage when xaiResponse.Usage was nil
(i.e., the if block was not entered), thereby preserving the nullable semantics
and preventing synthetic zero-token usage from being created when usage data is
absent from upstream.
Important
📝 变更描述 / Description
为 xAI 渠道补齐 Claude Messages 兼容转发,使 Claude Code / Anthropic Messages 格式请求可以落到 xAI 的 OpenAI-compatible chat completions 接口,并把响应转换回 Claude 格式。
具体改动:
ConvertClaudeRequest,复用已有ClaudeToOpenAIRequest转换逻辑,并在流式请求中补充stream_options.include_usage。RelayFormatClaude走 xAI 渠道时,将上游 URL 改为/v1/chat/completions,避免把/v1/messages直接发给 xAI。[DONE]后判定为 malformed response。查重时发现
/v1/messages/count_tokens已有独立打开的 PR(如 #5596、#4441)。为避免重复提交和扩大影响范围,本 PR 不重复实现 count_tokens,仅聚焦 xAI 渠道的 Claude Messages relay 兼容。🚀 变更类型 / Type of change
🔗 关联任务 / Related Issue
✅ 提交前检查项 / Checklist
Bug fix,我已提交或关联对应 Issue,且不会将设计取舍、预期不一致或理解偏差直接归类为 bug。📸 运行证明 / Proof of Work
git diff --check go test ./relay/channel/xai ./relay/... ./controller ./router验证结果:
git diff --check无输出。go test ./relay/channel/xai ./relay/... ./controller ./router通过。Summary by CodeRabbit
New Features
Tests