Fix OpenAI empty choices panic (#5248)
Signed-off-by: Arya Pratap Singh <notaryasingh@gmail.com>
This commit is contained in:
committed by
GitHub
parent
c662039674
commit
3b04b2ebf4
@@ -7,6 +7,7 @@ use crate::providers::utils::{
|
|||||||
};
|
};
|
||||||
use anyhow::{anyhow, Error};
|
use anyhow::{anyhow, Error};
|
||||||
use async_stream::try_stream;
|
use async_stream::try_stream;
|
||||||
|
use chrono;
|
||||||
use futures::Stream;
|
use futures::Stream;
|
||||||
use rmcp::model::{
|
use rmcp::model::{
|
||||||
object, AnnotateAble, CallToolRequestParam, Content, ErrorCode, ErrorData, RawContent,
|
object, AnnotateAble, CallToolRequestParam, Content, ErrorCode, ErrorData, RawContent,
|
||||||
@@ -281,7 +282,18 @@ pub fn format_tools(tools: &[Tool]) -> anyhow::Result<Vec<Value>> {
|
|||||||
|
|
||||||
/// Convert OpenAI's API response to internal Message format
|
/// Convert OpenAI's API response to internal Message format
|
||||||
pub fn response_to_message(response: &Value) -> anyhow::Result<Message> {
|
pub fn response_to_message(response: &Value) -> anyhow::Result<Message> {
|
||||||
let original = &response["choices"][0]["message"];
|
let Some(original) = response
|
||||||
|
.get("choices")
|
||||||
|
.and_then(|c| c.get(0))
|
||||||
|
.and_then(|m| m.get("message"))
|
||||||
|
else {
|
||||||
|
return Ok(Message::new(
|
||||||
|
Role::Assistant,
|
||||||
|
chrono::Utc::now().timestamp(),
|
||||||
|
Vec::new(),
|
||||||
|
));
|
||||||
|
};
|
||||||
|
|
||||||
let mut content = Vec::new();
|
let mut content = Vec::new();
|
||||||
|
|
||||||
if let Some(text) = original.get("content") {
|
if let Some(text) = original.get("content") {
|
||||||
@@ -465,12 +477,14 @@ where
|
|||||||
|
|
||||||
if chunk.choices.is_empty() {
|
if chunk.choices.is_empty() {
|
||||||
yield (None, usage)
|
yield (None, usage)
|
||||||
} else if let Some(tool_calls) = &chunk.choices[0].delta.tool_calls {
|
} else if chunk.choices[0].delta.tool_calls.as_ref().is_some_and(|tc| !tc.is_empty()) {
|
||||||
let mut tool_call_data: std::collections::HashMap<i32, (String, String, String)> = std::collections::HashMap::new();
|
let mut tool_call_data: std::collections::HashMap<i32, (String, String, String)> = std::collections::HashMap::new();
|
||||||
|
|
||||||
for tool_call in tool_calls {
|
if let Some(tool_calls) = &chunk.choices[0].delta.tool_calls {
|
||||||
if let (Some(index), Some(id), Some(name)) = (tool_call.index, &tool_call.id, &tool_call.function.name) {
|
for tool_call in tool_calls {
|
||||||
tool_call_data.insert(index, (id.clone(), name.clone(), tool_call.function.arguments.clone()));
|
if let (Some(index), Some(id), Some(name)) = (tool_call.index, &tool_call.id, &tool_call.function.name) {
|
||||||
|
tool_call_data.insert(index, (id.clone(), name.clone(), tool_call.function.arguments.clone()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -489,23 +503,27 @@ where
|
|||||||
let tool_chunk: StreamingChunk = serde_json::from_str(line)
|
let tool_chunk: StreamingChunk = serde_json::from_str(line)
|
||||||
.map_err(|e| anyhow!("Failed to parse streaming chunk: {}: {:?}", e, &line))?;
|
.map_err(|e| anyhow!("Failed to parse streaming chunk: {}: {:?}", e, &line))?;
|
||||||
|
|
||||||
if let Some(delta_tool_calls) = &tool_chunk.choices[0].delta.tool_calls {
|
if !tool_chunk.choices.is_empty() {
|
||||||
for delta_call in delta_tool_calls {
|
if let Some(delta_tool_calls) = &tool_chunk.choices[0].delta.tool_calls {
|
||||||
if let Some(index) = delta_call.index {
|
for delta_call in delta_tool_calls {
|
||||||
if let Some((_, _, ref mut args)) = tool_call_data.get_mut(&index) {
|
if let Some(index) = delta_call.index {
|
||||||
args.push_str(&delta_call.function.arguments);
|
if let Some((_, _, ref mut args)) = tool_call_data.get_mut(&index) {
|
||||||
} else if let (Some(id), Some(name)) = (&delta_call.id, &delta_call.function.name) {
|
args.push_str(&delta_call.function.arguments);
|
||||||
tool_call_data.insert(index, (id.clone(), name.clone(), delta_call.function.arguments.clone()));
|
} else if let (Some(id), Some(name)) = (&delta_call.id, &delta_call.function.name) {
|
||||||
|
tool_call_data.insert(index, (id.clone(), name.clone(), delta_call.function.arguments.clone()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
done = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if tool_chunk.choices[0].finish_reason == Some("tool_calls".to_string()) {
|
||||||
|
done = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
done = true;
|
done = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if tool_chunk.choices[0].finish_reason == Some("tool_calls".to_string()) {
|
|
||||||
done = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
@@ -563,7 +581,8 @@ where
|
|||||||
Some(msg),
|
Some(msg),
|
||||||
usage,
|
usage,
|
||||||
)
|
)
|
||||||
} else if let Some(text) = &chunk.choices[0].delta.content {
|
} else if chunk.choices[0].delta.content.is_some() {
|
||||||
|
let text = chunk.choices[0].delta.content.as_ref().unwrap();
|
||||||
let mut msg = Message::new(
|
let mut msg = Message::new(
|
||||||
Role::Assistant,
|
Role::Assistant,
|
||||||
chrono::Utc::now().timestamp(),
|
chrono::Utc::now().timestamp(),
|
||||||
|
|||||||
Reference in New Issue
Block a user