mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 17:30:23 +08:00
fix(provider): serialize Claude tool results as JSON strings
This commit is contained in:
@@ -538,6 +538,15 @@ mod tests {
|
|||||||
converted["messages"][2]["content"][0]["tool_use_id"],
|
converted["messages"][2]["content"][0]["tool_use_id"],
|
||||||
"call_1"
|
"call_1"
|
||||||
);
|
);
|
||||||
|
assert_eq!(
|
||||||
|
serde_json::from_str::<Value>(
|
||||||
|
converted["messages"][2]["content"][0]["content"]
|
||||||
|
.as_str()
|
||||||
|
.expect("object tool result content should be serialized for Claude")
|
||||||
|
)
|
||||||
|
.expect("serialized tool result content should remain JSON"),
|
||||||
|
json!({"rows": 1})
|
||||||
|
);
|
||||||
assert_eq!(converted["tool_choice"]["type"], "auto");
|
assert_eq!(converted["tool_choice"]["type"], "auto");
|
||||||
assert_eq!(converted["stream"], true);
|
assert_eq!(converted["stream"], true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -835,6 +835,15 @@ mod tests {
|
|||||||
provider_request_body["messages"][2]["content"][0]["type"],
|
provider_request_body["messages"][2]["content"][0]["type"],
|
||||||
"tool_result"
|
"tool_result"
|
||||||
);
|
);
|
||||||
|
assert_eq!(
|
||||||
|
serde_json::from_str::<Value>(
|
||||||
|
provider_request_body["messages"][2]["content"][0]["content"]
|
||||||
|
.as_str()
|
||||||
|
.expect("object tool result content should be serialized for Claude")
|
||||||
|
)
|
||||||
|
.expect("serialized tool result content should remain JSON"),
|
||||||
|
json!({"rows": 1})
|
||||||
|
);
|
||||||
assert_eq!(provider_request_body["tool_choice"]["type"], "auto");
|
assert_eq!(provider_request_body["tool_choice"]["type"], "auto");
|
||||||
assert_eq!(provider_request_body["stream"], true);
|
assert_eq!(provider_request_body["stream"], true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3820,9 +3820,11 @@ pub(crate) fn canonical_block_to_claude(
|
|||||||
);
|
);
|
||||||
out.insert(
|
out.insert(
|
||||||
"content".to_string(),
|
"content".to_string(),
|
||||||
output
|
canonical_tool_result_content_to_claude(
|
||||||
.clone()
|
output.as_ref(),
|
||||||
.unwrap_or_else(|| Value::String(content_text.clone().unwrap_or_default())),
|
content_text.as_deref(),
|
||||||
|
role,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
out.insert("is_error".to_string(), Value::Bool(*is_error));
|
out.insert("is_error".to_string(), Value::Bool(*is_error));
|
||||||
out.extend(namespace_extension_object(extensions, "claude", &out));
|
out.extend(namespace_extension_object(extensions, "claude", &out));
|
||||||
@@ -3832,6 +3834,41 @@ pub(crate) fn canonical_block_to_claude(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn canonical_tool_result_content_to_claude(
|
||||||
|
output: Option<&Value>,
|
||||||
|
content_text: Option<&str>,
|
||||||
|
role: &CanonicalRole,
|
||||||
|
) -> Value {
|
||||||
|
if matches!(role, CanonicalRole::Assistant) {
|
||||||
|
return output
|
||||||
|
.cloned()
|
||||||
|
.unwrap_or_else(|| Value::String(content_text.unwrap_or_default().to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
match output {
|
||||||
|
Some(Value::String(text)) => Value::String(text.clone()),
|
||||||
|
Some(Value::Array(parts)) if claude_tool_result_content_blocks_are_wire_safe(parts) => {
|
||||||
|
Value::Array(parts.clone())
|
||||||
|
}
|
||||||
|
Some(value) => serde_json::to_string(value)
|
||||||
|
.map(Value::String)
|
||||||
|
.unwrap_or_else(|_| Value::String(content_text.unwrap_or_default().to_string())),
|
||||||
|
None => Value::String(content_text.unwrap_or_default().to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn claude_tool_result_content_blocks_are_wire_safe(parts: &[Value]) -> bool {
|
||||||
|
!parts.is_empty()
|
||||||
|
&& parts.iter().all(|part| {
|
||||||
|
part.as_object()
|
||||||
|
.and_then(|object| object.get("type"))
|
||||||
|
.and_then(Value::as_str)
|
||||||
|
.is_some_and(|block_type| {
|
||||||
|
matches!(block_type, "text" | "image" | "document" | "file")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn claude_source_value(
|
pub(crate) fn claude_source_value(
|
||||||
media_type: Option<&str>,
|
media_type: Option<&str>,
|
||||||
data: Option<&str>,
|
data: Option<&str>,
|
||||||
|
|||||||
Reference in New Issue
Block a user