use otherone_ai::types::{ChatResponse, ParsedResponse, ToolCallsWrapper};
pub fn parse_ai_response(
response: &ChatResponse,
provider: &otherone_ai::types::ProviderType,
) -> Result<ParsedResponse, String> {
match provider {
otherone_ai::types::ProviderType::OpenAI
| otherone_ai::types::ProviderType::OpenRouter
| otherone_ai::types::ProviderType::Local => parse_openai_response(response),
otherone_ai::types::ProviderType::Fetch => parse_fetch_response(response),
otherone_ai::types::ProviderType::Anthropic => parse_anthropic_response(response),
}
}
fn parse_openai_response(response: &ChatResponse) -> Result<ParsedResponse, String> {
if response.choices.is_empty() {
return Err("Invalid OpenAI response format: missing choices".to_string());
}
let choice = &response.choices[0];
let message = choice.message.as_ref().unwrap();
let content = message.content.as_deref().unwrap_or("");
let role = message.role.as_deref().unwrap_or("assistant");
let token_consumption = response
.usage
.as_ref()
.map(|u| u.total_tokens.unwrap_or(0))
.unwrap_or(0);
let tools = message.tool_calls.as_ref().map(|tc| ToolCallsWrapper {
tool_calls: tc.clone(),
});
Ok(ParsedResponse {
content: content.to_string(),
role: role.to_string(),
token_consumption,
tools,
thinking: None,
raw_response: None,
})
}
fn parse_anthropic_response(response: &ChatResponse) -> Result<ParsedResponse, String> {
if response.choices.is_empty() {
return Err("Invalid Anthropic response format: missing choices".to_string());
}
let choice = &response.choices[0];
let message = choice.message.as_ref().unwrap();
let content = message.content.as_deref().unwrap_or("");
let role = message.role.as_deref().unwrap_or("assistant");
let token_consumption = response
.usage
.as_ref()
.map(|u| u.total_tokens.unwrap_or(0))
.unwrap_or(0);
Ok(ParsedResponse {
content: content.to_string(),
role: role.to_string(),
token_consumption,
tools: None,
thinking: None,
raw_response: None,
})
}
fn parse_fetch_response(response: &ChatResponse) -> Result<ParsedResponse, String> {
parse_openai_response(response)
}
#[cfg(test)]
mod tests {
use super::*;
use otherone_ai::types::{ChatResponse, Choice, ResponseMessage, Usage};
#[test]
fn test_parse_openai_response() {
let response = ChatResponse {
id: Some("chat-123".to_string()),
object: Some("chat.completion".to_string()),
created: Some(1234567890),
model: Some("gpt-4".to_string()),
choices: vec![Choice {
index: 0,
message: Some(ResponseMessage {
role: Some("assistant".to_string()),
content: Some("Hello!".to_string()),
tool_calls: None,
}),
delta: None,
finish_reason: Some("stop".to_string()),
}],
usage: Some(Usage {
prompt_tokens: Some(10),
completion_tokens: Some(5),
total_tokens: Some(15),
}),
};
let parsed = parse_openai_response(&response).unwrap();
assert_eq!(parsed.content, "Hello!");
assert_eq!(parsed.role, "assistant");
assert_eq!(parsed.token_consumption, 15);
assert!(parsed.tools.is_none());
}
}