Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/copyright-check.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ $global:copyright_results = @{

$ignored_files = @('.clang-format', '.gitattributes', '.gitignore', '.gitkeep', '.patch', 'Cargo.lock', 'LICENSE', 'uv.lock', 'rust-toolchain.toml', 'codespell.txt', 'exclusions.txt')
write-debug "<copyright-check> ignored_files = ['$($ignored_files -join "','")']."
$ignored_paths = @('.github', '.mypy_cache', '.pytest_cache', 'lib/llm/tests/data/sample-models')
$ignored_paths = @('.github', '.mypy_cache', '.pytest_cache', 'lib/llm/tests/data/sample-models', 'lib/llm/tests/data/deepseek-v3.2')
write-debug "<copyright-check> ignored_paths = ['$($ignored_paths -join "','")']."
$ignored_types = @('.bat', '.gif', '.ico', '.ipynb', '.jpg', '.jpeg', '.patch', '.png', '.pyc', '.pyi', '.rst', '.zip', '.md', '.json')
write-debug "<copyright-check> ignored_types = ['$($ignored_types -join "', '")']."
Expand Down
1 change: 1 addition & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ repos:
- id: mixed-line-ending
- id: requirements-txt-fixer
- id: trailing-whitespace
exclude: lib/llm/tests/data/deepseek-v3.2/.*\.txt$

# NOTE: removing from pre commit
# will move to gitlab ci to run in proper
Expand Down
112 changes: 112 additions & 0 deletions lib/llm/tests/data/deepseek-v3.2/test_output.txt
Comment thread
vladnosiv marked this conversation as resolved.
Outdated
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
<|begin▁of▁sentence|>You are a helpful Assistant.

## Tools

You have access to a set of tools you can use to answer the user's question.
You can invoke functions by writing a "<|DSML|function_calls>" block like the following as part of your reply to the user:
<|DSML|function_calls>
<|DSML|invoke name="$FUNCTION_NAME">
<|DSML|parameter name="$PARAMETER_NAME" string="true|false">$PARAMETER_VALUE</|DSML|parameter>
...
</|DSML|invoke>
<|DSML|invoke name="$FUNCTION_NAME2">
...
</|DSML|invoke>
</|DSML|function_calls>

String and scalar parameters should be specified as is without any escaping or quotes, while lists and objects should use JSON format. The "string" attribute should be set to "true" for string type parameters and "false" for other types (numbers, booleans, arrays, objects).

If the thinking_mode is enabled, then after function results you should strongly consider outputting a thinking block. Here is an example:

<|DSML|function_calls>
...
</|DSML|function_calls>

<function_results>
...
</function_results>

<think>...thinking about results</think>

Here are the functions available in JSONSchema format:
<functions>
{"name": "get_datetime", "description": "Get the current date and time", "parameters": {"type": "object", "properties": {"timezone": {"type": "string", "description": "The timezone, e.g. Asia/Shanghai, UTC"}}, "required": ["timezone"]}}
{"name": "get_weather", "description": "Get the weather for a specific date and location", "parameters": {"type": "object", "properties": {"location": {"type": "string", "description": "The city name, e.g. Beijing, Hangzhou"}, "date": {"type": "string", "description": "The date in YYYY-MM-DD format"}}, "required": ["location", "date"]}}
</functions>
<|User|>明天杭州和北京的天气怎么样?<|Assistant|></think>

<|DSML|function_calls>
<|DSML|invoke name="get_datetime">
<|DSML|parameter name="timezone" string="true">Asia/Shanghai</|DSML|parameter>
</|DSML|invoke>
</|DSML|function_calls><|end▁of▁sentence|>

<function_results>
<result>{"current_date": "2024-01-15", "current_time": "14:30:00", "timezone": "Asia/Shanghai"}</result>
</function_results>

</think>

<|DSML|function_calls>
<|DSML|invoke name="get_weather">
<|DSML|parameter name="location" string="true">Hangzhou</|DSML|parameter>
<|DSML|parameter name="date" string="true">2024-01-16</|DSML|parameter>
</|DSML|invoke>
<|DSML|invoke name="get_weather">
<|DSML|parameter name="location" string="true">Beijing</|DSML|parameter>
<|DSML|parameter name="date" string="true">2024-01-16</|DSML|parameter>
</|DSML|invoke>
</|DSML|function_calls><|end▁of▁sentence|>

<function_results>
<result>{"location": "Hangzhou", "date": "2024-01-16", "temperature_high": "12", "temperature_low": "5", "weather": "多云", "humidity": "65%"}</result>
<result>{"location": "Beijing", "date": "2024-01-16", "temperature_high": "-2", "temperature_low": "-8", "weather": "晴", "humidity": "30%"}</result>
</function_results>

</think>根据查询结果,明天(2024年1月16日)的天气情况如下:

**杭州**:
- 天气:多云
- 最高温度:12°C
- 最低温度:5°C
- 湿度:65%

**北京**:
- 天气:晴
- 最高温度:-2°C
- 最低温度:-8°C
- 湿度:30%

杭州明天会比较温暖但有些多云,而北京会很冷但是晴天。建议在北京的朋友要注意保暖!<|end▁of▁sentence|><|User|>谢谢!那后天呢?<|Assistant|><think>用户现在问后天的天气,后天是2024-01-17,我可以直接查询(因为已知今天日期)🗓️</think>

<|DSML|function_calls>
<|DSML|invoke name="get_weather">
<|DSML|parameter name="location" string="true">Hangzhou</|DSML|parameter>
<|DSML|parameter name="date" string="true">2024-01-17</|DSML|parameter>
</|DSML|invoke>
<|DSML|invoke name="get_weather">
<|DSML|parameter name="location" string="true">Beijing</|DSML|parameter>
<|DSML|parameter name="date" string="true">2024-01-17</|DSML|parameter>
</|DSML|invoke>
</|DSML|function_calls><|end▁of▁sentence|>

<function_results>
<result>{"location": "Hangzhou", "date": "2024-01-17", "temperature_high": "15", "temperature_low": "8", "weather": "小雨", "humidity": "80%"}</result>
<result>{"location": "Beijing", "date": "2024-01-17", "temperature_high": "0", "temperature_low": "-6", "weather": "多云", "humidity": "45%"}</result>
</function_results>

<think>获取到后天的天气数据,整理回复给用户📝</think>后天(2024年1月17日)的天气情况:

**杭州**:
- 天气:小雨
- 最高温度:15°C
- 最低温度:8°C
- 湿度:80%

**北京**:
- 天气:多云
- 最高温度:0°C
- 最低温度:-6°C
- 湿度:45%

杭州后天会有小雨,温度略有回升,记得带伞。北京会稍微暖和一点,但依然很冷,请继续做好保暖措施。<|end▁of▁sentence|>
45 changes: 45 additions & 0 deletions lib/parsers/src/tool_calling/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,36 @@ impl Default for XmlParserConfig {
}
}

/// Configuration for DSML-style tool call parser (DeepSeek V3.2+)
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
pub struct DsmlParserConfig {
/// Start token for function_calls block (e.g., "<|DSML|function_calls>")
pub function_calls_start: String,
/// End token for function_calls block (e.g., "</|DSML|function_calls>")
pub function_calls_end: String,
/// Start prefix for invoke (e.g., "<|DSML|invoke name=")
pub invoke_start_prefix: String,
/// End token for invoke (e.g., "</|DSML|invoke>")
pub invoke_end: String,
/// Start prefix for parameter (e.g., "<|DSML|parameter name=")
pub parameter_prefix: String,
/// End token for parameter (e.g., "</|DSML|parameter>")
pub parameter_end: String,
}

impl Default for DsmlParserConfig {
fn default() -> Self {
Self {
function_calls_start: "<|DSML|function_calls>".to_string(),
function_calls_end: "</|DSML|function_calls>".to_string(),
invoke_start_prefix: "<|DSML|invoke name=".to_string(),
invoke_end: "</|DSML|invoke>".to_string(),
parameter_prefix: "<|DSML|parameter name=".to_string(),
parameter_end: "</|DSML|parameter>".to_string(),
}
}
}

/// Parser-specific configuration
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
Expand All @@ -78,6 +108,7 @@ pub enum ParserConfig {
Pythonic,
Harmony(JsonParserConfig),
Typescript,
Dsml(DsmlParserConfig),
}

impl ParserConfig {
Expand All @@ -90,6 +121,7 @@ impl ParserConfig {
ParserConfig::Xml(config) => vec![config.tool_call_start_token.clone()],
ParserConfig::Pythonic => vec![],
ParserConfig::Typescript => vec![],
ParserConfig::Dsml(config) => vec![config.function_calls_start.clone()],
}
}

Expand All @@ -102,6 +134,7 @@ impl ParserConfig {
ParserConfig::Xml(config) => vec![config.tool_call_end_token.clone()],
ParserConfig::Pythonic => vec![],
ParserConfig::Typescript => vec![],
ParserConfig::Dsml(config) => vec![config.function_calls_end.clone()],
}
}
}
Expand Down Expand Up @@ -249,4 +282,16 @@ impl ToolCallConfig {
}),
}
}

pub fn deepseek_v3_2() -> Self {
// DeepSeek V3.2 format (DSML):
// <|DSML|function_calls>
// <|DSML|invoke name="function_name">
// <|DSML|parameter name="param_name" string="true|false">value</|DSML|parameter>
// </|DSML|invoke>
// </|DSML|function_calls>
Self {
parser_config: ParserConfig::Dsml(DsmlParserConfig::default()),
}
}
}
9 changes: 9 additions & 0 deletions lib/parsers/src/tool_calling/dsml/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

mod parser;

pub use super::response;
pub use parser::{
detect_tool_call_start_dsml, find_tool_call_end_position_dsml, try_tool_call_parse_dsml,
};
Loading
Loading