mirror of
https://github.com/fawney19/Aether.git
synced 2026-10-04 16:37:46 +08:00
fix(ai-formats): omit request tool call ids in OpenAI Responses input
This commit is contained in:
@@ -9,7 +9,7 @@ use crate::{
|
||||
},
|
||||
protocol::canonical::{
|
||||
canonical_response_format_to_openai_responses, canonical_tool_is_openai_custom,
|
||||
canonical_tool_use_to_openai_responses_item, is_claude_messages_request,
|
||||
canonical_tool_use_to_openai_responses_input_item, is_claude_messages_request,
|
||||
is_claude_system_instruction, is_claude_thinking_block, is_claude_tool_result,
|
||||
is_openai_responses_input_message, is_openai_thinking_block, media_data_or_url,
|
||||
namespace_extension_object, openai_content_text, openai_extensions,
|
||||
@@ -331,7 +331,7 @@ fn canonical_messages_to_responses_input(canonical: &CanonicalRequest) -> Option
|
||||
let call_id = responses_tool_call_id(id, &mut next_generated_tool_call_index);
|
||||
let tool_name = responses_tool_name(name);
|
||||
pending_tool_call_ids.push_back(call_id.clone());
|
||||
input.push(canonical_tool_use_to_openai_responses_item(
|
||||
input.push(canonical_tool_use_to_openai_responses_input_item(
|
||||
&call_id, &tool_name, arguments, extensions,
|
||||
));
|
||||
}
|
||||
@@ -1430,7 +1430,7 @@ mod tests {
|
||||
|
||||
assert_eq!(body["input"].as_array().expect("input").len(), 2);
|
||||
assert_eq!(body["input"][0]["type"], "function_call");
|
||||
assert_eq!(body["input"][0]["id"], "call_auto_0");
|
||||
assert!(body["input"][0].get("id").is_none());
|
||||
assert_eq!(body["input"][0]["call_id"], "call_auto_0");
|
||||
assert_eq!(body["input"][0]["name"], "unknown");
|
||||
assert_eq!(body["input"][0]["arguments"], "{\"q\":\"rust\"}");
|
||||
|
||||
@@ -2609,7 +2609,7 @@ mod tests {
|
||||
.value;
|
||||
|
||||
assert_eq!(converted["input"][0]["type"], "function_call");
|
||||
assert_eq!(converted["input"][0]["id"], "call_lookup_1");
|
||||
assert!(converted["input"][0].get("id").is_none());
|
||||
assert_eq!(converted["input"][0]["call_id"], "call_lookup_1");
|
||||
assert_eq!(converted["input"][1]["type"], "function_call_output");
|
||||
assert_eq!(converted["input"][1]["call_id"], "call_lookup_1");
|
||||
|
||||
@@ -808,6 +808,66 @@ pub(crate) fn canonical_tool_use_to_openai_responses_item(
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn canonical_tool_use_to_openai_responses_input_item(
|
||||
id: &str,
|
||||
name: &str,
|
||||
input: &Value,
|
||||
extensions: &BTreeMap<String, Value>,
|
||||
) -> Value {
|
||||
if let Some(item_type) = openai_responses_hosted_tool_call_item_type(extensions) {
|
||||
let mut item = Map::new();
|
||||
item.insert("type".to_string(), Value::String(item_type.to_string()));
|
||||
item.insert("id".to_string(), Value::String(id.to_string()));
|
||||
item.insert("call_id".to_string(), Value::String(id.to_string()));
|
||||
item.insert("status".to_string(), Value::String("completed".to_string()));
|
||||
if let Some(input_object) = input.as_object() {
|
||||
for field in openai_responses_hosted_tool_input_fields(item_type) {
|
||||
if let Some(value) = input_object.get(*field) {
|
||||
item.insert((*field).to_string(), value.clone());
|
||||
}
|
||||
}
|
||||
} else if item_type == "apply_patch_call" {
|
||||
item.insert("operation".to_string(), input.clone());
|
||||
} else if !name.trim().is_empty() {
|
||||
item.insert("name".to_string(), Value::String(name.to_string()));
|
||||
}
|
||||
return Value::Object(item);
|
||||
}
|
||||
if is_openai_custom_tool_call(extensions) {
|
||||
let mut item = Map::new();
|
||||
item.insert(
|
||||
"type".to_string(),
|
||||
Value::String("custom_tool_call".to_string()),
|
||||
);
|
||||
if let Some(item_id) = openai_responses_request_tool_call_item_id(extensions, "ctc") {
|
||||
item.insert("id".to_string(), Value::String(item_id));
|
||||
}
|
||||
item.insert("call_id".to_string(), Value::String(id.to_string()));
|
||||
item.insert("status".to_string(), Value::String("completed".to_string()));
|
||||
item.insert("name".to_string(), Value::String(name.to_string()));
|
||||
item.insert(
|
||||
"input".to_string(),
|
||||
Value::String(openai_custom_tool_input_text(input)),
|
||||
);
|
||||
return Value::Object(item);
|
||||
}
|
||||
let mut item = Map::new();
|
||||
item.insert(
|
||||
"type".to_string(),
|
||||
Value::String("function_call".to_string()),
|
||||
);
|
||||
if let Some(item_id) = openai_responses_request_tool_call_item_id(extensions, "fc") {
|
||||
item.insert("id".to_string(), Value::String(item_id));
|
||||
}
|
||||
item.insert("call_id".to_string(), Value::String(id.to_string()));
|
||||
item.insert("name".to_string(), Value::String(name.to_string()));
|
||||
item.insert(
|
||||
"arguments".to_string(),
|
||||
Value::String(canonicalize_tool_arguments(input)),
|
||||
);
|
||||
Value::Object(item)
|
||||
}
|
||||
|
||||
fn openai_responses_tool_call_item_id(
|
||||
call_id: &str,
|
||||
extensions: &BTreeMap<String, Value>,
|
||||
@@ -828,6 +888,18 @@ fn openai_responses_tool_call_item_id(
|
||||
}
|
||||
}
|
||||
|
||||
fn openai_responses_request_tool_call_item_id(
|
||||
extensions: &BTreeMap<String, Value>,
|
||||
prefix: &str,
|
||||
) -> Option<String> {
|
||||
openai_responses_extension(extensions)
|
||||
.and_then(|value| value.get("item_id").or_else(|| value.get("id")))
|
||||
.and_then(Value::as_str)
|
||||
.map(str::trim)
|
||||
.filter(|value| value.starts_with(prefix))
|
||||
.map(ToString::to_string)
|
||||
}
|
||||
|
||||
fn openai_responses_hosted_tool_call_item_type(
|
||||
extensions: &BTreeMap<String, Value>,
|
||||
) -> Option<&str> {
|
||||
|
||||
Reference in New Issue
Block a user