[Bugfix][Rust Frontend][Renderer] Align DeepSeek tool-call arguments with deepseek-recipe (#56260)
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> Co-authored-by: Bugen Zhao <i@bugenzhao.com> Co-authored-by: Codex <noreply@openai.com> Signed-off-by: JinYan Su <751080330@qq.com> Signed-off-by: Bugen Zhao <i@bugenzhao.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
Bugen Zhao
Codex
parent
8c1d1c2974
commit
79c137c6ad
@@ -11,7 +11,7 @@ use std::collections::HashMap;
|
||||
use std::fmt::Write as _;
|
||||
|
||||
use serde::Serialize;
|
||||
use serde_json::Value;
|
||||
use serde_json::{Map, Value};
|
||||
use serde_json_fmt::JsonFormat;
|
||||
|
||||
use llm_multimodal::DEEPSEEK_V41_IMAGE_PLACEHOLDER;
|
||||
@@ -685,19 +685,18 @@ fn encode_arguments_to_dsml(
|
||||
dialect: DsDialect,
|
||||
) -> Result<()> {
|
||||
let parameter_tag = dialect.parameter_tag();
|
||||
let arguments: Value = serde_json::from_str(&tool_call.arguments).map_err(|error| {
|
||||
Error::ChatTemplate(format!(
|
||||
"assistant tool call has invalid JSON arguments for DeepSeek: {error}"
|
||||
))
|
||||
})?;
|
||||
let Some(arguments) = arguments.as_object() else {
|
||||
return Err(Error::ChatTemplate(
|
||||
"assistant tool call arguments for DeepSeek must be a JSON object".to_string(),
|
||||
));
|
||||
};
|
||||
// Match deepseek-recipe's render_tool_arguments for both V4 and V4.1:
|
||||
// https://github.com/deepseek-ai/deepseek-recipe/blob/8cadfede7063c896b944e7bae05daa3549ae97ea/deepseek-recipe-encoding/src/v4/mod.rs#L48-L58
|
||||
let arguments = serde_json::from_str::<Map<String, Value>>(&tool_call.arguments)
|
||||
.unwrap_or_else(|_| {
|
||||
Map::from_iter([(
|
||||
"arguments".to_owned(),
|
||||
Value::String(tool_call.arguments.clone()),
|
||||
)])
|
||||
});
|
||||
|
||||
let mut wrote_parameter = false;
|
||||
for (key, value) in arguments {
|
||||
for (key, value) in &arguments {
|
||||
if wrote_parameter {
|
||||
out.push('\n');
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ use serde_json::Value;
|
||||
use super::DeepSeekV4ChatRenderer;
|
||||
use crate::ChatRenderer;
|
||||
use crate::event::{AssistantContentBlock, AssistantToolCall};
|
||||
use crate::renderer::deepseek_v41::DeepSeekV41ChatRenderer;
|
||||
use crate::renderer::test_utils::{FixtureRequestOptions, fixture_chat_request};
|
||||
use crate::request::{ChatMessage, ChatRequest, ChatTool, GenerationPromptMode, ReasoningEffort};
|
||||
|
||||
@@ -399,6 +400,51 @@ fn reasoning_effort_template_kwarg_is_ignored() {
|
||||
assert!(rendered.ends_with("<|Assistant|><think>"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tool_call_arguments_preserve_non_objects_like_recipe() {
|
||||
let renderers: [(&dyn ChatRenderer, &str); 2] = [
|
||||
(&DeepSeekV4ChatRenderer::new(), "parameter"),
|
||||
(&DeepSeekV41ChatRenderer::new(), " parameter"),
|
||||
];
|
||||
for arguments in [
|
||||
"not json",
|
||||
"[1, 2]",
|
||||
"null",
|
||||
"42",
|
||||
"true",
|
||||
"",
|
||||
r#""text""#,
|
||||
r#""{\"query\":\"double\"}""#,
|
||||
] {
|
||||
let request = ChatRequest {
|
||||
messages: vec![
|
||||
ChatMessage::assistant_blocks(vec![AssistantContentBlock::ToolCall(
|
||||
AssistantToolCall {
|
||||
id: "call".to_string(),
|
||||
name: "search".to_string(),
|
||||
arguments: arguments.to_string(),
|
||||
},
|
||||
)]),
|
||||
ChatMessage::tool_response("result", "call"),
|
||||
],
|
||||
..ChatRequest::for_test()
|
||||
};
|
||||
|
||||
for (renderer, tag) in renderers {
|
||||
let prompt = renderer.render(&request).unwrap().prompt.into_text().unwrap();
|
||||
let parameters: Vec<_> =
|
||||
prompt.lines().filter(|line| line.contains("parameter name=")).collect();
|
||||
assert_eq!(
|
||||
parameters,
|
||||
[format!(
|
||||
"<|DSML|{tag} name=\"arguments\" string=\"true\">{arguments}</|DSML|{tag}>"
|
||||
)],
|
||||
"arguments: {arguments:?}, tag: {tag:?}",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tool_results_are_sorted_by_previous_assistant_tool_call_order() {
|
||||
let mut request = ChatRequest {
|
||||
|
||||
Reference in New Issue
Block a user