diff options
| author | sigoden <sigoden@gmail.com> | 2025-02-26 08:08:34 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-02-26 08:08:34 +0800 |
| commit | 6b28b1c4fcf57edc4375703bca34eeafa597c905 (patch) | |
| tree | d6f6e6d1ac51f46ba258d46128a5f31d3c874645 /src/client/claude.rs | |
| parent | d8b1aef97d00e2f66d5af32ad075d990c7dfdba1 (diff) | |
| download | aichat-6b28b1c4fcf57edc4375703bca34eeafa597c905.tar.gz | |
feat: support claude-3-7-sonnet (#1201)
Diffstat (limited to 'src/client/claude.rs')
| -rw-r--r-- | src/client/claude.rs | 74 |
1 files changed, 48 insertions, 26 deletions
diff --git a/src/client/claude.rs b/src/client/claude.rs index 7167e80..202d2f7 100644 --- a/src/client/claude.rs +++ b/src/client/claude.rs @@ -80,6 +80,7 @@ pub async fn claude_chat_completions_streaming( let mut function_name = String::new(); let mut function_arguments = String::new(); let mut function_id = String::new(); + let mut reasoning_state = 0; let handle = |message: SseMmessage| -> Result<bool> { let data: Value = serde_json::from_str(&message.data)?; debug!("stream-data: {data}"); @@ -110,6 +111,12 @@ pub async fn claude_chat_completions_streaming( "content_block_delta" => { if let Some(text) = data["delta"]["text"].as_str() { handler.text(text)?; + } else if let Some(text) = data["delta"]["thinking"].as_str() { + if reasoning_state == 0 { + handler.text("<think>\n")?; + reasoning_state = 1; + } + handler.text(text)?; } else if let (true, Some(partial_json)) = ( !function_name.is_empty(), data["delta"]["partial_json"].as_str(), @@ -118,6 +125,10 @@ pub async fn claude_chat_completions_streaming( } } "content_block_stop" => { + if reasoning_state == 1 { + handler.text("\n</think>\n\n")?; + reasoning_state = 0; + } if !function_name.is_empty() { let arguments: Value = if function_arguments.is_empty() { json!({}) @@ -282,34 +293,45 @@ pub fn claude_build_chat_completions_body( } pub fn claude_extract_chat_completions(data: &Value) -> Result<ChatCompletionsOutput> { - let text = data["content"][0]["text"].as_str().unwrap_or_default(); - + let mut text = String::new(); + let mut reasoning = None; let mut tool_calls = vec![]; - if let Some(calls) = data["content"].as_array().map(|content| { - content - .iter() - .filter(|content| matches!(content["type"].as_str(), Some("tool_use"))) - .collect::<Vec<&Value>>() - }) { - tool_calls = calls - .into_iter() - .filter_map(|call| { - if let (Some(name), Some(input), Some(id)) = ( - call["name"].as_str(), - call.get("input"), - call["id"].as_str(), - ) { - Some(ToolCall::new( - name.to_string(), - input.clone(), - Some(id.to_string()), - )) - } else { - None + if let Some(list) = data["content"].as_array() { + for item in list { + match item["type"].as_str() { + Some("thinking") => { + if let Some(v) = item["thinking"].as_str() { + reasoning = Some(v.to_string()); + } } - }) - .collect(); - }; + Some("text") => { + if let Some(v) = item["text"].as_str() { + if !text.is_empty() { + text.push_str("\n\n"); + } + text.push_str(v); + } + } + Some("tool_use") => { + if let (Some(name), Some(input), Some(id)) = ( + item["name"].as_str(), + item.get("input"), + item["id"].as_str(), + ) { + tool_calls.push(ToolCall::new( + name.to_string(), + input.clone(), + Some(id.to_string()), + )); + } + } + _ => {} + } + } + } + if let Some(reasoning) = reasoning { + text = format!("<think>\n{reasoning}\n</think>\n\n{text}") + } if text.is_empty() && tool_calls.is_empty() { bail!("Invalid response data: {data}"); |
