hank9999 commited on
Commit ·
9014673
1
Parent(s): 66bdb5a
Revert "feat(converter): 支持基于 conversation_id 为 Claude Code Agent 生成确定性 agentContinuationId"
Browse filesThis reverts commit 66bdb5a9cc67f8a3e2c203051200f5205bfdd380.
- src/anthropic/converter.rs +1 -262
src/anthropic/converter.rs
CHANGED
|
@@ -59,66 +59,6 @@ impl std::fmt::Display for ConversionError {
|
|
| 59 |
|
| 60 |
impl std::error::Error for ConversionError {}
|
| 61 |
|
| 62 |
-
/// Claude Code Agent 标识字符串
|
| 63 |
-
const CLAUDE_CODE_AGENT_MARKER: &str = "You are an agent for Claude Code, Anthropic's official CLI for Claude.";
|
| 64 |
-
|
| 65 |
-
/// 检查请求是否来自 Claude Code Agent
|
| 66 |
-
///
|
| 67 |
-
/// 在 system 消息中搜索 agent 标识字符串
|
| 68 |
-
fn is_claude_code_agent(req: &MessagesRequest) -> bool {
|
| 69 |
-
// 检查 system 消息
|
| 70 |
-
if let Some(ref system) = req.system {
|
| 71 |
-
for sys_msg in system {
|
| 72 |
-
if sys_msg.text.contains(CLAUDE_CODE_AGENT_MARKER) {
|
| 73 |
-
return true;
|
| 74 |
-
}
|
| 75 |
-
}
|
| 76 |
-
}
|
| 77 |
-
|
| 78 |
-
false
|
| 79 |
-
}
|
| 80 |
-
|
| 81 |
-
/// 使用 conversation_id 作为种子生成确定性 UUID
|
| 82 |
-
///
|
| 83 |
-
/// 同一个 conversation_id 总是生成相同的 UUID,确保同一会话中的 agentContinuationId 保持一致
|
| 84 |
-
fn generate_deterministic_uuid(seed: &str) -> String {
|
| 85 |
-
use sha2::{Digest, Sha256};
|
| 86 |
-
|
| 87 |
-
// 使用 SHA-256 哈希种子
|
| 88 |
-
let mut hasher = Sha256::new();
|
| 89 |
-
hasher.update(seed.as_bytes());
|
| 90 |
-
let hash = hasher.finalize();
|
| 91 |
-
|
| 92 |
-
// 取前 16 字节构造 UUID
|
| 93 |
-
let mut bytes = [0u8; 16];
|
| 94 |
-
bytes.copy_from_slice(&hash[..16]);
|
| 95 |
-
|
| 96 |
-
// 设置 UUID 版本为 4 (随机) 和变体
|
| 97 |
-
bytes[6] = (bytes[6] & 0x0f) | 0x40; // 版本 4
|
| 98 |
-
bytes[8] = (bytes[8] & 0x3f) | 0x80; // 变体 1
|
| 99 |
-
|
| 100 |
-
// 格式化为 UUID 字符串
|
| 101 |
-
format!(
|
| 102 |
-
"{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
|
| 103 |
-
bytes[0],
|
| 104 |
-
bytes[1],
|
| 105 |
-
bytes[2],
|
| 106 |
-
bytes[3],
|
| 107 |
-
bytes[4],
|
| 108 |
-
bytes[5],
|
| 109 |
-
bytes[6],
|
| 110 |
-
bytes[7],
|
| 111 |
-
bytes[8],
|
| 112 |
-
bytes[9],
|
| 113 |
-
bytes[10],
|
| 114 |
-
bytes[11],
|
| 115 |
-
bytes[12],
|
| 116 |
-
bytes[13],
|
| 117 |
-
bytes[14],
|
| 118 |
-
bytes[15]
|
| 119 |
-
)
|
| 120 |
-
}
|
| 121 |
-
|
| 122 |
/// 从 metadata.user_id 中提取 session UUID
|
| 123 |
///
|
| 124 |
/// user_id 格式: user_xxx_account__session_0b4445e1-f5be-49e1-87ce-62bbc28ad705
|
|
@@ -196,14 +136,7 @@ pub fn convert_request(req: &MessagesRequest) -> Result<ConversionResult, Conver
|
|
| 196 |
.and_then(|m| m.user_id.as_ref())
|
| 197 |
.and_then(|user_id| extract_session_id(user_id))
|
| 198 |
.unwrap_or_else(|| Uuid::new_v4().to_string());
|
| 199 |
-
|
| 200 |
-
// 如果是 Claude Code Agent,使用 conversation_id 作为种子生成确定性的 agentContinuationId
|
| 201 |
-
// 确保同一会话中的 agentContinuationId 保持一致
|
| 202 |
-
let agent_continuation_id = if is_claude_code_agent(req) {
|
| 203 |
-
generate_deterministic_uuid(&conversation_id)
|
| 204 |
-
} else {
|
| 205 |
-
Uuid::new_v4().to_string()
|
| 206 |
-
};
|
| 207 |
|
| 208 |
// 4. 确定触发类型
|
| 209 |
let chat_trigger_type = determine_chat_trigger_type(req);
|
|
@@ -873,198 +806,4 @@ mod tests {
|
|
| 873 |
4
|
| 874 |
);
|
| 875 |
}
|
| 876 |
-
|
| 877 |
-
#[test]
|
| 878 |
-
fn test_is_claude_code_agent_in_system() {
|
| 879 |
-
use super::super::types::{Message as AnthropicMessage, SystemMessage};
|
| 880 |
-
|
| 881 |
-
// 测试 system 消息中包含 agent 标识
|
| 882 |
-
let req = MessagesRequest {
|
| 883 |
-
model: "claude-sonnet-4".to_string(),
|
| 884 |
-
max_tokens: 1024,
|
| 885 |
-
messages: vec![AnthropicMessage {
|
| 886 |
-
role: "user".to_string(),
|
| 887 |
-
content: serde_json::json!("Hello"),
|
| 888 |
-
}],
|
| 889 |
-
stream: false,
|
| 890 |
-
system: Some(vec![SystemMessage {
|
| 891 |
-
text: "You are an agent for Claude Code, Anthropic's official CLI for Claude."
|
| 892 |
-
.to_string(),
|
| 893 |
-
}]),
|
| 894 |
-
tools: None,
|
| 895 |
-
tool_choice: None,
|
| 896 |
-
thinking: None,
|
| 897 |
-
metadata: None,
|
| 898 |
-
};
|
| 899 |
-
|
| 900 |
-
assert!(is_claude_code_agent(&req));
|
| 901 |
-
}
|
| 902 |
-
|
| 903 |
-
#[test]
|
| 904 |
-
fn test_is_claude_code_agent_in_messages() {
|
| 905 |
-
use super::super::types::Message as AnthropicMessage;
|
| 906 |
-
|
| 907 |
-
// 测试 messages 中包含 agent 标识
|
| 908 |
-
let req = MessagesRequest {
|
| 909 |
-
model: "claude-sonnet-4".to_string(),
|
| 910 |
-
max_tokens: 1024,
|
| 911 |
-
messages: vec![AnthropicMessage {
|
| 912 |
-
role: "user".to_string(),
|
| 913 |
-
content: serde_json::json!(
|
| 914 |
-
"You are an agent for Claude Code, the best coding assistant."
|
| 915 |
-
),
|
| 916 |
-
}],
|
| 917 |
-
stream: false,
|
| 918 |
-
system: None,
|
| 919 |
-
tools: None,
|
| 920 |
-
tool_choice: None,
|
| 921 |
-
thinking: None,
|
| 922 |
-
metadata: None,
|
| 923 |
-
};
|
| 924 |
-
|
| 925 |
-
assert!(is_claude_code_agent(&req));
|
| 926 |
-
}
|
| 927 |
-
|
| 928 |
-
#[test]
|
| 929 |
-
fn test_is_claude_code_agent_in_content_block() {
|
| 930 |
-
use super::super::types::Message as AnthropicMessage;
|
| 931 |
-
|
| 932 |
-
// 测试 content block 数组中包含 agent 标识
|
| 933 |
-
let req = MessagesRequest {
|
| 934 |
-
model: "claude-sonnet-4".to_string(),
|
| 935 |
-
max_tokens: 1024,
|
| 936 |
-
messages: vec![AnthropicMessage {
|
| 937 |
-
role: "user".to_string(),
|
| 938 |
-
content: serde_json::json!([
|
| 939 |
-
{"type": "text", "text": "You are an agent for Claude Code, Anthropic's official CLI for Claude."}
|
| 940 |
-
]),
|
| 941 |
-
}],
|
| 942 |
-
stream: false,
|
| 943 |
-
system: None,
|
| 944 |
-
tools: None,
|
| 945 |
-
tool_choice: None,
|
| 946 |
-
thinking: None,
|
| 947 |
-
metadata: None,
|
| 948 |
-
};
|
| 949 |
-
|
| 950 |
-
assert!(is_claude_code_agent(&req));
|
| 951 |
-
}
|
| 952 |
-
|
| 953 |
-
#[test]
|
| 954 |
-
fn test_is_not_claude_code_agent() {
|
| 955 |
-
use super::super::types::Message as AnthropicMessage;
|
| 956 |
-
|
| 957 |
-
// 测试普通请求不是 agent
|
| 958 |
-
let req = MessagesRequest {
|
| 959 |
-
model: "claude-sonnet-4".to_string(),
|
| 960 |
-
max_tokens: 1024,
|
| 961 |
-
messages: vec![AnthropicMessage {
|
| 962 |
-
role: "user".to_string(),
|
| 963 |
-
content: serde_json::json!("Hello, how are you?"),
|
| 964 |
-
}],
|
| 965 |
-
stream: false,
|
| 966 |
-
system: None,
|
| 967 |
-
tools: None,
|
| 968 |
-
tool_choice: None,
|
| 969 |
-
thinking: None,
|
| 970 |
-
metadata: None,
|
| 971 |
-
};
|
| 972 |
-
|
| 973 |
-
assert!(!is_claude_code_agent(&req));
|
| 974 |
-
}
|
| 975 |
-
|
| 976 |
-
#[test]
|
| 977 |
-
fn test_generate_deterministic_uuid() {
|
| 978 |
-
// 测试相同种子生成相同的 UUID
|
| 979 |
-
let seed = "a0662283-7fd3-4399-a7eb-52b9a717ae88";
|
| 980 |
-
let uuid1 = generate_deterministic_uuid(seed);
|
| 981 |
-
let uuid2 = generate_deterministic_uuid(seed);
|
| 982 |
-
|
| 983 |
-
assert_eq!(uuid1, uuid2);
|
| 984 |
-
assert_eq!(uuid1.len(), 36);
|
| 985 |
-
assert_eq!(uuid1.chars().filter(|c| *c == '-').count(), 4);
|
| 986 |
-
}
|
| 987 |
-
|
| 988 |
-
#[test]
|
| 989 |
-
fn test_generate_deterministic_uuid_different_seeds() {
|
| 990 |
-
// 测试不同种子生成不同的 UUID
|
| 991 |
-
let uuid1 = generate_deterministic_uuid("seed1");
|
| 992 |
-
let uuid2 = generate_deterministic_uuid("seed2");
|
| 993 |
-
|
| 994 |
-
assert_ne!(uuid1, uuid2);
|
| 995 |
-
}
|
| 996 |
-
|
| 997 |
-
#[test]
|
| 998 |
-
fn test_agent_continuation_id_deterministic_for_agent() {
|
| 999 |
-
use super::super::types::{Message as AnthropicMessage, Metadata, SystemMessage};
|
| 1000 |
-
|
| 1001 |
-
// 测试 agent 请求的 agentContinuationId 是确定性的
|
| 1002 |
-
let req = MessagesRequest {
|
| 1003 |
-
model: "claude-sonnet-4".to_string(),
|
| 1004 |
-
max_tokens: 1024,
|
| 1005 |
-
messages: vec![AnthropicMessage {
|
| 1006 |
-
role: "user".to_string(),
|
| 1007 |
-
content: serde_json::json!("Hello"),
|
| 1008 |
-
}],
|
| 1009 |
-
stream: false,
|
| 1010 |
-
system: Some(vec![SystemMessage {
|
| 1011 |
-
text: "You are an agent for Claude Code, Anthropic's official CLI for Claude."
|
| 1012 |
-
.to_string(),
|
| 1013 |
-
}]),
|
| 1014 |
-
tools: None,
|
| 1015 |
-
tool_choice: None,
|
| 1016 |
-
thinking: None,
|
| 1017 |
-
metadata: Some(Metadata {
|
| 1018 |
-
user_id: Some(
|
| 1019 |
-
"user_xxx_account__session_a0662283-7fd3-4399-a7eb-52b9a717ae88".to_string(),
|
| 1020 |
-
),
|
| 1021 |
-
}),
|
| 1022 |
-
};
|
| 1023 |
-
|
| 1024 |
-
let result1 = convert_request(&req).unwrap();
|
| 1025 |
-
let result2 = convert_request(&req).unwrap();
|
| 1026 |
-
|
| 1027 |
-
// 同一个 conversation_id 应该生成相同的 agentContinuationId
|
| 1028 |
-
assert_eq!(
|
| 1029 |
-
result1.conversation_state.agent_continuation_id,
|
| 1030 |
-
result2.conversation_state.agent_continuation_id
|
| 1031 |
-
);
|
| 1032 |
-
|
| 1033 |
-
// 验证 agentContinuationId 是基于 conversation_id 生成的
|
| 1034 |
-
let expected_agent_id = generate_deterministic_uuid("a0662283-7fd3-4399-a7eb-52b9a717ae88");
|
| 1035 |
-
assert_eq!(
|
| 1036 |
-
result1.conversation_state.agent_continuation_id,
|
| 1037 |
-
Some(expected_agent_id)
|
| 1038 |
-
);
|
| 1039 |
-
}
|
| 1040 |
-
|
| 1041 |
-
#[test]
|
| 1042 |
-
fn test_agent_continuation_id_random_for_non_agent() {
|
| 1043 |
-
use super::super::types::Message as AnthropicMessage;
|
| 1044 |
-
|
| 1045 |
-
// 测试非 agent 请求的 agentContinuationId 是随机的
|
| 1046 |
-
let req = MessagesRequest {
|
| 1047 |
-
model: "claude-sonnet-4".to_string(),
|
| 1048 |
-
max_tokens: 1024,
|
| 1049 |
-
messages: vec![AnthropicMessage {
|
| 1050 |
-
role: "user".to_string(),
|
| 1051 |
-
content: serde_json::json!("Hello"),
|
| 1052 |
-
}],
|
| 1053 |
-
stream: false,
|
| 1054 |
-
system: None,
|
| 1055 |
-
tools: None,
|
| 1056 |
-
tool_choice: None,
|
| 1057 |
-
thinking: None,
|
| 1058 |
-
metadata: None,
|
| 1059 |
-
};
|
| 1060 |
-
|
| 1061 |
-
let result1 = convert_request(&req).unwrap();
|
| 1062 |
-
let result2 = convert_request(&req).unwrap();
|
| 1063 |
-
|
| 1064 |
-
// 非 agent 请求每次生成不同的 agentContinuationId
|
| 1065 |
-
assert_ne!(
|
| 1066 |
-
result1.conversation_state.agent_continuation_id,
|
| 1067 |
-
result2.conversation_state.agent_continuation_id
|
| 1068 |
-
);
|
| 1069 |
-
}
|
| 1070 |
}
|
|
|
|
| 59 |
|
| 60 |
impl std::error::Error for ConversionError {}
|
| 61 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 62 |
/// 从 metadata.user_id 中提取 session UUID
|
| 63 |
///
|
| 64 |
/// user_id 格式: user_xxx_account__session_0b4445e1-f5be-49e1-87ce-62bbc28ad705
|
|
|
|
| 136 |
.and_then(|m| m.user_id.as_ref())
|
| 137 |
.and_then(|user_id| extract_session_id(user_id))
|
| 138 |
.unwrap_or_else(|| Uuid::new_v4().to_string());
|
| 139 |
+
let agent_continuation_id = Uuid::new_v4().to_string();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 140 |
|
| 141 |
// 4. 确定触发类型
|
| 142 |
let chat_trigger_type = determine_chat_trigger_type(req);
|
|
|
|
| 806 |
4
|
| 807 |
);
|
| 808 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 809 |
}
|