mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-09 03:18:44 +00:00
fix(rust): count explicit null tool call arguments as the string None like python
This commit is contained in:
parent
e06685c3e4
commit
be79444f9c
2 changed files with 29 additions and 2 deletions
|
|
@ -147,15 +147,28 @@ pub(crate) struct ToolCall {
|
|||
pub(crate) function: ToolCallFunction,
|
||||
}
|
||||
|
||||
/// Python runs `str(function.get("arguments", ""))`: a missing key counts as
|
||||
/// empty, but an explicit null counts as the string "None". `serde(default)`
|
||||
/// keeps a missing key at `None`, and the deserializer turns an explicit null
|
||||
/// into "None" so the counter sees what Python counts.
|
||||
fn explicit_null_arguments_as_none<'de, D: Deserializer<'de>>(
|
||||
deserializer: D,
|
||||
) -> Result<Option<String>, D::Error> {
|
||||
match Option::<String>::deserialize(deserializer)? {
|
||||
Some(arguments) => Ok(Some(arguments)),
|
||||
None => Ok(Some(String::from("None"))),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq)]
|
||||
pub(crate) struct ToolCallFunction {
|
||||
#[serde(default)]
|
||||
#[serde(default, deserialize_with = "explicit_null_arguments_as_none")]
|
||||
pub(crate) arguments: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq)]
|
||||
pub(crate) struct LegacyFunctionCall {
|
||||
#[serde(default)]
|
||||
#[serde(default, deserialize_with = "explicit_null_arguments_as_none")]
|
||||
pub(crate) arguments: Option<String>,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -80,6 +80,17 @@ mod json {
|
|||
const ASSISTANT_CONTENT_WITH_TOOL_CALL: &str = r#"{"model":"claude-sonnet-4-5","messages":[
|
||||
{"role":"assistant","content":"calling","tool_calls":[{"id":"1","type":"function","function":{"name":"get_weather","arguments":"{\"city\": \"Paris, France\"}"}}]}]}"#;
|
||||
|
||||
const NULL_TOOL_CALL_ARGUMENTS: &str = r#"{"model":"claude-sonnet-4-5","messages":[
|
||||
{"role":"assistant","tool_calls":[{"id":"1","type":"function","function":{"name":"f","arguments":null}}]},
|
||||
{"role":"tool","tool_call_id":"1","content":"x"}]}"#;
|
||||
|
||||
const MISSING_TOOL_CALL_ARGUMENTS: &str = r#"{"model":"claude-sonnet-4-5","messages":[
|
||||
{"role":"assistant","tool_calls":[{"id":"1","type":"function","function":{"name":"f"}}]},
|
||||
{"role":"tool","tool_call_id":"1","content":"x"}]}"#;
|
||||
|
||||
const LEGACY_NULL_FUNCTION_CALL_ARGUMENTS: &str = r#"{"model":"claude-sonnet-4-5","messages":[
|
||||
{"role":"assistant","function_call":{"name":"f","arguments":null}}]}"#;
|
||||
|
||||
fn assert_count_request_matches_python_token_counter(
|
||||
load: JsonLoader,
|
||||
body: &str,
|
||||
|
|
@ -167,6 +178,9 @@ mod json {
|
|||
#[case::tool_calls_and_tool_result(super::TOOL_CALLS_AND_TOOL_RESULT, 24)]
|
||||
#[case::legacy_function_call(super::LEGACY_FUNCTION_CALL, 14)]
|
||||
#[case::assistant_content_with_tool_call(super::ASSISTANT_CONTENT_WITH_TOOL_CALL, 16)]
|
||||
#[case::null_tool_call_arguments_count_as_none(super::NULL_TOOL_CALL_ARGUMENTS, 14)]
|
||||
#[case::missing_tool_call_arguments_count_as_empty(super::MISSING_TOOL_CALL_ARGUMENTS, 13)]
|
||||
#[case::legacy_null_function_call_arguments_count_as_none(super::LEGACY_NULL_FUNCTION_CALL_ARGUMENTS, 8)]
|
||||
fn count_request_matches_python_token_counter(
|
||||
#[case] body: &str,
|
||||
#[case] expected: usize,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue