mirror of
https://github.com/fawney19/Aether.git
synced 2026-10-04 00:17:45 +08:00
fix(claude-code): 让 openai:responses/chat 转 claude 的路径也应用请求体伪装
openai:responses 与 openai:chat 的决策构建器各自构建上游 body,不经过 apply_transport_request_body_semantics,导致跨格式请求转发到 claude_code provider 时请求体伪装没有生效,上游仍返回 429。 - responses/decision/request.rs:finalize 之后应用伪装 - chat/decision/request.rs:finalize 成功后应用伪装 - 同格式路径改为经 ai_serving::transport 门面引用,满足架构守卫 (ai_serving 不得直接依赖 crate::provider_transport) - 更新 chat -> claude_code 用例断言为新的请求体形态
This commit is contained in:
@@ -316,7 +316,7 @@ pub(crate) async fn resolve_local_same_format_provider_candidate_payload_parts(
|
||||
|
||||
// Same-format requests skip `apply_transport_request_body_semantics`, so the opt-in
|
||||
// Claude Code body mimicry has to be applied here as well.
|
||||
if crate::provider_transport::claude_code::apply_claude_code_body_mimicry_for_transport(
|
||||
if crate::ai_serving::transport::claude_code::apply_claude_code_body_mimicry_for_transport(
|
||||
&mut base_provider_request_body,
|
||||
&transport,
|
||||
prepared.provider_api_format.as_str(),
|
||||
|
||||
+12
-2
@@ -140,7 +140,7 @@ fn finalize_openai_chat_provider_request_body(
|
||||
mapped_model,
|
||||
source_model,
|
||||
);
|
||||
crate::ai_serving::finalize_openai_provider_request_with_codex_model_capabilities_and_reasoning_replay_policy(
|
||||
let finalization_failure = crate::ai_serving::finalize_openai_provider_request_with_codex_model_capabilities_and_reasoning_replay_policy(
|
||||
provider_request_body,
|
||||
crate::ai_serving::OpenAiProviderRequestFinalization {
|
||||
source_api_format: "openai:chat",
|
||||
@@ -170,7 +170,17 @@ fn finalize_openai_chat_provider_request_body(
|
||||
provider_api_format,
|
||||
"openai_chat_request_finalization",
|
||||
)
|
||||
})
|
||||
});
|
||||
if finalization_failure.is_none() {
|
||||
// This builder does not go through `apply_transport_request_body_semantics`, so the
|
||||
// Claude Code body mimicry must be applied here for Chat -> claude_code requests.
|
||||
crate::ai_serving::transport::claude_code::apply_claude_code_body_mimicry_for_transport(
|
||||
provider_request_body,
|
||||
transport,
|
||||
provider_api_format,
|
||||
);
|
||||
}
|
||||
finalization_failure
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
|
||||
+7
@@ -635,6 +635,13 @@ pub(crate) async fn resolve_local_openai_responses_candidate_payload_parts_with_
|
||||
{
|
||||
log_responses_to_chat_tool_conversion(trace_id, body_json, &base_provider_request_body);
|
||||
}
|
||||
// This builder does not go through `apply_transport_request_body_semantics`, so the
|
||||
// Claude Code body mimicry must be applied here for Responses -> claude_code requests.
|
||||
crate::ai_serving::transport::claude_code::apply_claude_code_body_mimicry_for_transport(
|
||||
&mut base_provider_request_body,
|
||||
&transport,
|
||||
provider_api_format,
|
||||
);
|
||||
let provider_request_body = base_provider_request_body;
|
||||
|
||||
if let Some(kiro_auth) = kiro_auth.as_ref() {
|
||||
|
||||
@@ -2028,14 +2028,30 @@ async fn gateway_returns_openai_chat_error_for_local_cross_format_claude_cli_syn
|
||||
"claude-code-upstream"
|
||||
);
|
||||
assert_eq!(seen_execution_runtime_request.body["max_tokens"], 64);
|
||||
// claude_code providers get the Claude Code body shape: billing header + identity +
|
||||
// generic prompt, with the client's own system moved into the message history.
|
||||
let system = seen_execution_runtime_request.body["system"]
|
||||
.as_array()
|
||||
.expect("claude_code system should be rewritten into blocks");
|
||||
assert_eq!(system.len(), 3);
|
||||
assert!(system[0]["text"]
|
||||
.as_str()
|
||||
.is_some_and(|text| text.starts_with("x-anthropic-billing-header: cc_version=")));
|
||||
assert_eq!(
|
||||
seen_execution_runtime_request.body["system"],
|
||||
"You are terse."
|
||||
system[1]["text"],
|
||||
"You are Claude Code, Anthropic's official CLI for Claude."
|
||||
);
|
||||
assert_eq!(
|
||||
seen_execution_runtime_request.body["messages"],
|
||||
json!([{"role":"user","content":"Say hello"}])
|
||||
json!([
|
||||
{"role":"user","content":[{"type":"text","text":"[System Instructions]\nYou are terse."}]},
|
||||
{"role":"assistant","content":[{"type":"text","text":"Understood. I will follow these instructions."}]},
|
||||
{"role":"user","content":"Say hello"}
|
||||
])
|
||||
);
|
||||
assert!(seen_execution_runtime_request.body["metadata"]["user_id"]
|
||||
.as_str()
|
||||
.is_some_and(|user_id| user_id.contains("\"session_id\"")));
|
||||
assert_eq!(
|
||||
seen_execution_runtime_request.client_api_format,
|
||||
"openai:chat"
|
||||
|
||||
Reference in New Issue
Block a user