hank9999 commited on
Commit
8ca3e6d
·
1 Parent(s): 7439977

feat: 新增会话ID保持

Browse files
src/anthropic/converter.rs CHANGED
@@ -59,6 +59,26 @@ impl std::fmt::Display for ConversionError {
59
 
60
  impl std::error::Error for ConversionError {}
61
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
 
63
  /// 收集历史消息中使用的所有工具名称
64
  fn collect_history_tool_names(history: &[Message]) -> Vec<String> {
@@ -97,7 +117,6 @@ fn create_placeholder_tool(name: &str) -> Tool {
97
  }
98
  }
99
 
100
-
101
  /// 将 Anthropic 请求转换为 Kiro 请求
102
  pub fn convert_request(req: &MessagesRequest) -> Result<ConversionResult, ConversionError> {
103
  // 1. 映射模型
@@ -110,7 +129,13 @@ pub fn convert_request(req: &MessagesRequest) -> Result<ConversionResult, Conver
110
  }
111
 
112
  // 3. 生成会话 ID 和代理 ID
113
- let conversation_id = Uuid::new_v4().to_string();
 
 
 
 
 
 
114
  let agent_continuation_id = Uuid::new_v4().to_string();
115
 
116
  // 4. 确定触发类型
@@ -584,6 +609,7 @@ mod tests {
584
  tools: None,
585
  tool_choice: None,
586
  thinking: None,
 
587
  };
588
  assert_eq!(determine_chat_trigger_type(&req), "MANUAL");
589
  }
@@ -669,6 +695,7 @@ mod tests {
669
  tools: None, // 没有提供工具定义
670
  tool_choice: None,
671
  thinking: None,
 
672
  };
673
 
674
  let result = convert_request(&req).unwrap();
@@ -687,4 +714,96 @@ mod tests {
687
  "tools 列表应包含 'read' 工具的占位符定义"
688
  );
689
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
690
  }
 
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
65
+ /// 提取 session_ 后面的 UUID 作为 conversationId
66
+ fn extract_session_id(user_id: &str) -> Option<String> {
67
+ // 查找 "session_" 后面的内容
68
+ if let Some(pos) = user_id.find("session_") {
69
+ let session_part = &user_id[pos + 8..]; // "session_" 长度为 8
70
+ // session_part 应该是 UUID 格式: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
71
+ // 验证是否是有效的 UUID 格式(36 字符,包含 4 个连字符)
72
+ if session_part.len() >= 36 {
73
+ let uuid_str = &session_part[..36];
74
+ // 简单验证 UUID 格式
75
+ if uuid_str.chars().filter(|c| *c == '-').count() == 4 {
76
+ return Some(uuid_str.to_string());
77
+ }
78
+ }
79
+ }
80
+ None
81
+ }
82
 
83
  /// 收集历史消息中使用的所有工具名称
84
  fn collect_history_tool_names(history: &[Message]) -> Vec<String> {
 
117
  }
118
  }
119
 
 
120
  /// 将 Anthropic 请求转换为 Kiro 请求
121
  pub fn convert_request(req: &MessagesRequest) -> Result<ConversionResult, ConversionError> {
122
  // 1. 映射模型
 
129
  }
130
 
131
  // 3. 生成会话 ID 和代理 ID
132
+ // 优先从 metadata.user_id 中提取 session UUID 作为 conversationId
133
+ let conversation_id = req
134
+ .metadata
135
+ .as_ref()
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. 确定触发类型
 
609
  tools: None,
610
  tool_choice: None,
611
  thinking: None,
612
+ metadata: None,
613
  };
614
  assert_eq!(determine_chat_trigger_type(&req), "MANUAL");
615
  }
 
695
  tools: None, // 没有提供工具定义
696
  tool_choice: None,
697
  thinking: None,
698
+ metadata: None,
699
  };
700
 
701
  let result = convert_request(&req).unwrap();
 
714
  "tools 列表应包含 'read' 工具的占位符定义"
715
  );
716
  }
717
+
718
+ #[test]
719
+ fn test_extract_session_id_valid() {
720
+ // 测试有效的 user_id 格式
721
+ let user_id = "user_0dede55c6dcc4a11a30bbb5e7f22e6fdf86cdeba3820019cc27612af4e1243cd_account__session_8bb5523b-ec7c-4540-a9ca-beb6d79f1552";
722
+ let session_id = extract_session_id(user_id);
723
+ assert_eq!(
724
+ session_id,
725
+ Some("8bb5523b-ec7c-4540-a9ca-beb6d79f1552".to_string())
726
+ );
727
+ }
728
+
729
+ #[test]
730
+ fn test_extract_session_id_no_session() {
731
+ // 测试没有 session 的 user_id
732
+ let user_id = "user_0dede55c6dcc4a11a30bbb5e7f22e6fdf86cdeba3820019cc27612af4e1243cd";
733
+ let session_id = extract_session_id(user_id);
734
+ assert_eq!(session_id, None);
735
+ }
736
+
737
+ #[test]
738
+ fn test_extract_session_id_invalid_uuid() {
739
+ // 测试无效的 UUID 格式
740
+ let user_id = "user_xxx_session_invalid-uuid";
741
+ let session_id = extract_session_id(user_id);
742
+ assert_eq!(session_id, None);
743
+ }
744
+
745
+ #[test]
746
+ fn test_convert_request_with_session_metadata() {
747
+ use super::super::types::{Message as AnthropicMessage, Metadata};
748
+
749
+ // 测试带有 metadata 的请求,应该使用 session UUID 作为 conversationId
750
+ let req = MessagesRequest {
751
+ model: "claude-sonnet-4".to_string(),
752
+ max_tokens: 1024,
753
+ messages: vec![AnthropicMessage {
754
+ role: "user".to_string(),
755
+ content: serde_json::json!("Hello"),
756
+ }],
757
+ stream: false,
758
+ system: None,
759
+ tools: None,
760
+ tool_choice: None,
761
+ thinking: None,
762
+ metadata: Some(Metadata {
763
+ user_id: Some(
764
+ "user_0dede55c6dcc4a11a30bbb5e7f22e6fdf86cdeba3820019cc27612af4e1243cd_account__session_a0662283-7fd3-4399-a7eb-52b9a717ae88".to_string(),
765
+ ),
766
+ }),
767
+ };
768
+
769
+ let result = convert_request(&req).unwrap();
770
+ assert_eq!(
771
+ result.conversation_state.conversation_id,
772
+ "a0662283-7fd3-4399-a7eb-52b9a717ae88"
773
+ );
774
+ }
775
+
776
+ #[test]
777
+ fn test_convert_request_without_metadata() {
778
+ use super::super::types::Message as AnthropicMessage;
779
+
780
+ // 测试没有 metadata 的请求,应该生成新的 UUID
781
+ let req = MessagesRequest {
782
+ model: "claude-sonnet-4".to_string(),
783
+ max_tokens: 1024,
784
+ messages: vec![AnthropicMessage {
785
+ role: "user".to_string(),
786
+ content: serde_json::json!("Hello"),
787
+ }],
788
+ stream: false,
789
+ system: None,
790
+ tools: None,
791
+ tool_choice: None,
792
+ thinking: None,
793
+ metadata: None,
794
+ };
795
+
796
+ let result = convert_request(&req).unwrap();
797
+ // 验证生成的是有效的 UUID 格式
798
+ assert_eq!(result.conversation_state.conversation_id.len(), 36);
799
+ assert_eq!(
800
+ result
801
+ .conversation_state
802
+ .conversation_id
803
+ .chars()
804
+ .filter(|c| *c == '-')
805
+ .count(),
806
+ 4
807
+ );
808
+ }
809
  }
src/anthropic/types.rs CHANGED
@@ -86,6 +86,13 @@ where
86
  Ok(value.min(MAX_BUDGET_TOKENS))
87
  }
88
 
 
 
 
 
 
 
 
89
  /// Messages 请求体
90
  #[derive(Debug, Deserialize)]
91
  pub struct MessagesRequest {
@@ -98,6 +105,8 @@ pub struct MessagesRequest {
98
  pub tools: Option<Vec<Tool>>,
99
  pub tool_choice: Option<serde_json::Value>,
100
  pub thinking: Option<Thinking>,
 
 
101
  }
102
 
103
  /// 消息
 
86
  Ok(value.min(MAX_BUDGET_TOKENS))
87
  }
88
 
89
+ /// Claude Code 请求中的 metadata
90
+ #[derive(Debug, Clone, Deserialize)]
91
+ pub struct Metadata {
92
+ /// 用户 ID,格式如: user_xxx_account__session_0b4445e1-f5be-49e1-87ce-62bbc28ad705
93
+ pub user_id: Option<String>,
94
+ }
95
+
96
  /// Messages 请求体
97
  #[derive(Debug, Deserialize)]
98
  pub struct MessagesRequest {
 
105
  pub tools: Option<Vec<Tool>>,
106
  pub tool_choice: Option<serde_json::Value>,
107
  pub thinking: Option<Thinking>,
108
+ /// Claude Code 请求中的 metadata,包含 session 信息
109
+ pub metadata: Option<Metadata>,
110
  }
111
 
112
  /// 消息