alith_interface/llms/api/anthropic/completion/
res.rs1use crate::requests::completion::*;
2use serde::{Deserialize, Serialize};
3use tool::{Function, ToolCall};
4
5impl CompletionResponse {
6 pub fn new_from_anthropic(
7 req: &CompletionRequest,
8 res: AnthropicCompletionResponse,
9 ) -> Result<Self, CompletionError> {
10 let finish_reason = match res.stop_reason {
11 StopReason::EndTurn => CompletionFinishReason::Eos,
12 StopReason::StopSequence => {
13 if let Some(stopping_string) = &res.stop_sequence {
14 if let Some(stop_sequence) =
15 req.stop_sequences.parse_string_response(stopping_string)
16 {
17 CompletionFinishReason::MatchingStoppingSequence(stop_sequence)
18 } else {
19 CompletionFinishReason::NonMatchingStoppingSequence(Some(
20 stopping_string.clone(),
21 ))
22 }
23 } else {
24 CompletionFinishReason::NonMatchingStoppingSequence(None)
25 }
26 }
27 StopReason::MaxTokens => CompletionFinishReason::StopLimit,
28 StopReason::ToolUse => {
29 return Err(CompletionError::StopReasonUnsupported(
30 "StopReason::ToolUse is not supported".to_owned(),
31 ));
32 }
33 };
34
35 if res.content.is_empty() {
36 return Err(CompletionError::ResponseContentEmpty);
37 }
38
39 if res.content.len() > 1 {
40 return Err(CompletionError::ResponseContentEmpty);
41 }
42 let content = res
43 .content
44 .first()
45 .ok_or_else(|| CompletionError::ResponseContentEmpty)?
46 .text()
47 .to_owned();
48
49 Ok(Self {
50 id: res.id.to_owned(),
51 index: None,
52 content,
53 finish_reason,
54 completion_probabilities: None,
55 truncated: false,
56 generation_settings: GenerationSettings::new_from_anthropic(req, &res),
57 timing_usage: TimingUsage::new_from_generic(req.start_time),
58 token_usage: TokenUsage::new_from_anthropic(&res),
59 tool_calls: match res.content.as_slice() {
60 [
61 CompletionContent::ToolUse {
62 name,
63 input,
64 id,
65 r#type,
66 },
67 ..,
68 ] => Some(vec![ToolCall {
69 id: id.to_owned(),
70 r#type: r#type.to_owned(),
71 function: Function {
72 name: name.to_owned(),
73 arguments: serde_json::to_string(input)?,
74 },
75 }]),
76 _ => None,
77 },
78 })
79 }
80}
81
82#[derive(Debug, Deserialize, Clone, PartialEq, Serialize)]
84pub struct AnthropicCompletionResponse {
85 pub id: String,
89 pub content: Vec<CompletionContent>,
93 pub model: String,
95 pub stop_reason: StopReason,
103 pub stop_sequence: Option<String>,
107 pub usage: CompletionUsage,
115}
116
117#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
118#[serde(untagged)]
119pub enum CompletionContent {
120 String(String),
122 Text {
123 r#type: String,
124 text: String,
125 },
126 ToolUse {
127 r#type: String,
128 id: String,
129 name: String,
130 input: serde_json::Value,
131 },
132}
133
134impl CompletionContent {
135 pub fn text(&self) -> String {
136 match self {
137 CompletionContent::String(text) => text.to_string(),
138 CompletionContent::Text {
139 r#type: _, text, ..
140 } => text.to_string(),
141 CompletionContent::ToolUse { .. } => "".to_string(),
142 }
143 }
144}
145
146#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
148pub struct CompletionUsage {
149 pub input_tokens: u32,
151 pub output_tokens: u32,
153}
154
155#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq)]
156#[serde(rename_all = "snake_case")]
157pub enum StopReason {
158 EndTurn,
160 MaxTokens,
162 StopSequence,
164 ToolUse,
166}