From 7b95087b9d26f371f78cd8af3144d9f5575e890c Mon Sep 17 00:00:00 2001 From: Grace <88872231+gr4ceG@users.noreply.github.com> Date: Mon, 15 Dec 2025 17:57:06 -0800 Subject: [PATCH] Adding tool definitions to DeepseekV3 renderer (#13491) --- model/renderers/deepseek3.go | 27 +- model/renderers/deepseek3_test.go | 484 ++++++++++++++++++++++++++++++ 2 files changed, 510 insertions(+), 1 deletion(-) diff --git a/model/renderers/deepseek3.go b/model/renderers/deepseek3.go index ec98574e..be7709b9 100644 --- a/model/renderers/deepseek3.go +++ b/model/renderers/deepseek3.go @@ -39,7 +39,32 @@ func (r *DeepSeek3Renderer) Render(messages []api.Message, tools []api.Tool, thi } } - sb.WriteString("<|begin▁of▁sentence|>" + systemPrompt.String()) + sb.WriteString("<|begin▁of▁sentence|>") + sb.WriteString(systemPrompt.String()) + + // tool definitions + if len(tools) > 0 { + sb.WriteString("\n\n## Tools\nYou have access to the following tools:\n") + + for _, tool := range tools { + sb.WriteString("\n### " + tool.Function.Name) + sb.WriteString("\nDescription: " + tool.Function.Description) + + // parameters as JSON + parametersJSON, err := json.Marshal(tool.Function.Parameters) + if err == nil { + sb.WriteString("\n\nParameters: " + string(parametersJSON) + "\n") + } + } + + // usage instructions + sb.WriteString("\nIMPORTANT: ALWAYS adhere to this exact format for tool use:\n") + sb.WriteString("<|tool▁calls▁begin|><|tool▁call▁begin|>tool_call_name<|tool▁sep|>tool_call_arguments<|tool▁call▁end|>{{additional_tool_calls}}<|tool▁calls▁end|>\n\n") + sb.WriteString("Where:\n\n") + sb.WriteString("- `tool_call_name` must be an exact match to one of the available tools\n") + sb.WriteString("- `tool_call_arguments` must be valid JSON that strictly follows the tool's Parameters Schema\n") + sb.WriteString("- For multiple tool calls, chain them directly without separators or spaces\n") + } // state tracking isTool := false diff --git a/model/renderers/deepseek3_test.go b/model/renderers/deepseek3_test.go index e25bf624..eb997550 100644 --- a/model/renderers/deepseek3_test.go +++ b/model/renderers/deepseek3_test.go @@ -475,6 +475,490 @@ Second instruction<|User|>Hello<|Assistant|>`, thinkValue: &api.ThinkValue{Value: true}, expected: `<|begin▁of▁sentence|><|User|>Simple question<|Assistant|>Simple answer.<|end▁of▁sentence|>`, }, + { + name: "with tools definitions", + messages: []api.Message{ + {Role: "system", Content: "You are a helpful assistant."}, + {Role: "user", Content: "What's the weather like?"}, + }, + tools: []api.Tool{ + { + Type: "function", + Function: api.ToolFunction{ + Name: "get_weather", + Description: "Get current weather information", + Parameters: api.ToolFunctionParameters{ + Type: "object", + Properties: map[string]api.ToolProperty{ + "location": { + Type: api.PropertyType{"string"}, + Description: "City name", + }, + }, + Required: []string{"location"}, + }, + }, + }, + }, + thinkValue: &api.ThinkValue{Value: false}, + expected: `<|begin▁of▁sentence|>You are a helpful assistant. + +## Tools +You have access to the following tools: + +### get_weather +Description: Get current weather information + +Parameters: {"type":"object","required":["location"],"properties":{"location":{"type":"string","description":"City name"}}} + +IMPORTANT: ALWAYS adhere to this exact format for tool use: +<|tool▁calls▁begin|><|tool▁call▁begin|>tool_call_name<|tool▁sep|>tool_call_arguments<|tool▁call▁end|>{{additional_tool_calls}}<|tool▁calls▁end|> + +Where: + +- ` + "`tool_call_name`" + ` must be an exact match to one of the available tools +- ` + "`tool_call_arguments`" + ` must be valid JSON that strictly follows the tool's Parameters Schema +- For multiple tool calls, chain them directly without separators or spaces +<|User|>What's the weather like?<|Assistant|>`, + }, + { + name: "tools definitions with thinking enabled", + messages: []api.Message{ + {Role: "system", Content: "You are a helpful assistant."}, + {Role: "user", Content: "What's the weather in Paris?"}, + }, + tools: []api.Tool{ + { + Type: "function", + Function: api.ToolFunction{ + Name: "get_weather", + Description: "Get current weather information", + Parameters: api.ToolFunctionParameters{ + Type: "object", + Properties: map[string]api.ToolProperty{ + "location": { + Type: api.PropertyType{"string"}, + Description: "City name", + }, + }, + Required: []string{"location"}, + }, + }, + }, + }, + thinkValue: &api.ThinkValue{Value: true}, + expected: `<|begin▁of▁sentence|>You are a helpful assistant. + +## Tools +You have access to the following tools: + +### get_weather +Description: Get current weather information + +Parameters: {"type":"object","required":["location"],"properties":{"location":{"type":"string","description":"City name"}}} + +IMPORTANT: ALWAYS adhere to this exact format for tool use: +<|tool▁calls▁begin|><|tool▁call▁begin|>tool_call_name<|tool▁sep|>tool_call_arguments<|tool▁call▁end|>{{additional_tool_calls}}<|tool▁calls▁end|> + +Where: + +- ` + "`tool_call_name`" + ` must be an exact match to one of the available tools +- ` + "`tool_call_arguments`" + ` must be valid JSON that strictly follows the tool's Parameters Schema +- For multiple tool calls, chain them directly without separators or spaces +<|User|>What's the weather in Paris?<|Assistant|>`, + }, + { + name: "tools definitions with actual tool call", + messages: []api.Message{ + {Role: "system", Content: "You are a helpful assistant."}, + {Role: "user", Content: "What's the weather in Paris?"}, + { + Role: "assistant", + ToolCalls: []api.ToolCall{ + { + Function: api.ToolCallFunction{ + Name: "get_weather", + Arguments: api.ToolCallFunctionArguments{ + "location": "Paris", + }, + }, + }, + }, + }, + }, + tools: []api.Tool{ + { + Type: "function", + Function: api.ToolFunction{ + Name: "get_weather", + Description: "Get current weather information", + Parameters: api.ToolFunctionParameters{ + Type: "object", + Properties: map[string]api.ToolProperty{ + "location": { + Type: api.PropertyType{"string"}, + Description: "City name", + }, + }, + Required: []string{"location"}, + }, + }, + }, + }, + thinkValue: &api.ThinkValue{Value: false}, + expected: `<|begin▁of▁sentence|>You are a helpful assistant. + +## Tools +You have access to the following tools: + +### get_weather +Description: Get current weather information + +Parameters: {"type":"object","required":["location"],"properties":{"location":{"type":"string","description":"City name"}}} + +IMPORTANT: ALWAYS adhere to this exact format for tool use: +<|tool▁calls▁begin|><|tool▁call▁begin|>tool_call_name<|tool▁sep|>tool_call_arguments<|tool▁call▁end|>{{additional_tool_calls}}<|tool▁calls▁end|> + +Where: + +- ` + "`tool_call_name`" + ` must be an exact match to one of the available tools +- ` + "`tool_call_arguments`" + ` must be valid JSON that strictly follows the tool's Parameters Schema +- For multiple tool calls, chain them directly without separators or spaces +<|User|>What's the weather in Paris?<|Assistant|><|tool▁calls▁begin|><|tool▁call▁begin|>get_weather<|tool▁sep|>{"location":"Paris"}<|tool▁call▁end|><|tool▁calls▁end|><|end▁of▁sentence|>`, + }, + { + name: "tools definitions with full conversation cycle", + messages: []api.Message{ + {Role: "system", Content: "You are a helpful assistant."}, + {Role: "user", Content: "What's the weather in Paris?"}, + { + Role: "assistant", + Content: "I'll check the weather for you.", + ToolCalls: []api.ToolCall{ + { + Function: api.ToolCallFunction{ + Name: "get_weather", + Arguments: api.ToolCallFunctionArguments{ + "location": "Paris", + }, + }, + }, + }, + }, + {Role: "tool", Content: "Temperature: 22°C, Sunny"}, + {Role: "assistant", Content: "The weather in Paris is 22°C and sunny!"}, + }, + tools: []api.Tool{ + { + Type: "function", + Function: api.ToolFunction{ + Name: "get_weather", + Description: "Get current weather information", + Parameters: api.ToolFunctionParameters{ + Type: "object", + Properties: map[string]api.ToolProperty{ + "location": { + Type: api.PropertyType{"string"}, + Description: "City name", + }, + }, + Required: []string{"location"}, + }, + }, + }, + }, + thinkValue: &api.ThinkValue{Value: false}, + expected: `<|begin▁of▁sentence|>You are a helpful assistant. + +## Tools +You have access to the following tools: + +### get_weather +Description: Get current weather information + +Parameters: {"type":"object","required":["location"],"properties":{"location":{"type":"string","description":"City name"}}} + +IMPORTANT: ALWAYS adhere to this exact format for tool use: +<|tool▁calls▁begin|><|tool▁call▁begin|>tool_call_name<|tool▁sep|>tool_call_arguments<|tool▁call▁end|>{{additional_tool_calls}}<|tool▁calls▁end|> + +Where: + +- ` + "`tool_call_name`" + ` must be an exact match to one of the available tools +- ` + "`tool_call_arguments`" + ` must be valid JSON that strictly follows the tool's Parameters Schema +- For multiple tool calls, chain them directly without separators or spaces +<|User|>What's the weather in Paris?<|Assistant|>I'll check the weather for you.<|tool▁calls▁begin|><|tool▁call▁begin|>get_weather<|tool▁sep|>{"location":"Paris"}<|tool▁call▁end|><|tool▁calls▁end|><|end▁of▁sentence|><|tool▁output▁begin|>Temperature: 22°C, Sunny<|tool▁output▁end|>The weather in Paris is 22°C and sunny!<|end▁of▁sentence|>`, + }, + { + name: "tools with thinking and full conversation", + messages: []api.Message{ + {Role: "system", Content: "You are a helpful assistant."}, + {Role: "user", Content: "Check the weather in Tokyo"}, + { + Role: "assistant", + Thinking: "The user wants weather info for Tokyo. I should use the get_weather tool.", + Content: "Let me check that for you.", + ToolCalls: []api.ToolCall{ + { + Function: api.ToolCallFunction{ + Name: "get_weather", + Arguments: api.ToolCallFunctionArguments{ + "location": "Tokyo", + }, + }, + }, + }, + }, + {Role: "tool", Content: "Temperature: 18°C, Cloudy"}, + { + Role: "assistant", + Thinking: "The weather data shows it's cloudy and cool. I should present this clearly.", + Content: "In Tokyo, it's currently 18°C and cloudy.", + }, + {Role: "user", Content: "What about London?"}, + }, + tools: []api.Tool{ + { + Type: "function", + Function: api.ToolFunction{ + Name: "get_weather", + Description: "Get current weather information", + Parameters: api.ToolFunctionParameters{ + Type: "object", + Properties: map[string]api.ToolProperty{ + "location": { + Type: api.PropertyType{"string"}, + Description: "City name", + }, + }, + Required: []string{"location"}, + }, + }, + }, + }, + thinkValue: &api.ThinkValue{Value: true}, + expected: `<|begin▁of▁sentence|>You are a helpful assistant. + +## Tools +You have access to the following tools: + +### get_weather +Description: Get current weather information + +Parameters: {"type":"object","required":["location"],"properties":{"location":{"type":"string","description":"City name"}}} + +IMPORTANT: ALWAYS adhere to this exact format for tool use: +<|tool▁calls▁begin|><|tool▁call▁begin|>tool_call_name<|tool▁sep|>tool_call_arguments<|tool▁call▁end|>{{additional_tool_calls}}<|tool▁calls▁end|> + +Where: + +- ` + "`tool_call_name`" + ` must be an exact match to one of the available tools +- ` + "`tool_call_arguments`" + ` must be valid JSON that strictly follows the tool's Parameters Schema +- For multiple tool calls, chain them directly without separators or spaces +<|User|>Check the weather in Tokyo<|Assistant|>Let me check that for you.<|tool▁calls▁begin|><|tool▁call▁begin|>get_weather<|tool▁sep|>{"location":"Tokyo"}<|tool▁call▁end|><|tool▁calls▁end|><|end▁of▁sentence|><|tool▁output▁begin|>Temperature: 18°C, Cloudy<|tool▁output▁end|>In Tokyo, it's currently 18°C and cloudy.<|end▁of▁sentence|><|User|>What about London?<|Assistant|>`, + }, + { + name: "multiple tools definitions", + messages: []api.Message{ + {Role: "system", Content: "You are a helpful assistant with access to multiple tools."}, + {Role: "user", Content: "What can you help me with?"}, + }, + tools: []api.Tool{ + { + Type: "function", + Function: api.ToolFunction{ + Name: "get_weather", + Description: "Get current weather information", + Parameters: api.ToolFunctionParameters{ + Type: "object", + Properties: map[string]api.ToolProperty{ + "location": { + Type: api.PropertyType{"string"}, + Description: "City name", + }, + }, + Required: []string{"location"}, + }, + }, + }, + { + Type: "function", + Function: api.ToolFunction{ + Name: "calculate", + Description: "Perform mathematical calculations", + Parameters: api.ToolFunctionParameters{ + Type: "object", + Properties: map[string]api.ToolProperty{ + "expression": { + Type: api.PropertyType{"string"}, + Description: "Mathematical expression to evaluate", + }, + }, + Required: []string{"expression"}, + }, + }, + }, + }, + thinkValue: &api.ThinkValue{Value: false}, + expected: `<|begin▁of▁sentence|>You are a helpful assistant with access to multiple tools. + +## Tools +You have access to the following tools: + +### get_weather +Description: Get current weather information + +Parameters: {"type":"object","required":["location"],"properties":{"location":{"type":"string","description":"City name"}}} + +### calculate +Description: Perform mathematical calculations + +Parameters: {"type":"object","required":["expression"],"properties":{"expression":{"type":"string","description":"Mathematical expression to evaluate"}}} + +IMPORTANT: ALWAYS adhere to this exact format for tool use: +<|tool▁calls▁begin|><|tool▁call▁begin|>tool_call_name<|tool▁sep|>tool_call_arguments<|tool▁call▁end|>{{additional_tool_calls}}<|tool▁calls▁end|> + +Where: + +- ` + "`tool_call_name`" + ` must be an exact match to one of the available tools +- ` + "`tool_call_arguments`" + ` must be valid JSON that strictly follows the tool's Parameters Schema +- For multiple tool calls, chain them directly without separators or spaces +<|User|>What can you help me with?<|Assistant|>`, + }, + { + name: "multiple tools with multiple tool calls", + messages: []api.Message{ + {Role: "user", Content: "Get weather for Paris and calculate 25 * 4"}, + { + Role: "assistant", + ToolCalls: []api.ToolCall{ + { + Function: api.ToolCallFunction{ + Name: "get_weather", + Arguments: api.ToolCallFunctionArguments{ + "location": "Paris", + }, + }, + }, + { + Function: api.ToolCallFunction{ + Name: "calculate", + Arguments: api.ToolCallFunctionArguments{ + "expression": "25 * 4", + }, + }, + }, + }, + }, + {Role: "tool", Content: "Temperature: 22°C, Sunny"}, + {Role: "tool", Content: "Result: 100"}, + }, + tools: []api.Tool{ + { + Type: "function", + Function: api.ToolFunction{ + Name: "get_weather", + Description: "Get current weather information", + Parameters: api.ToolFunctionParameters{ + Type: "object", + Properties: map[string]api.ToolProperty{ + "location": { + Type: api.PropertyType{"string"}, + Description: "City name", + }, + }, + Required: []string{"location"}, + }, + }, + }, + { + Type: "function", + Function: api.ToolFunction{ + Name: "calculate", + Description: "Perform mathematical calculations", + Parameters: api.ToolFunctionParameters{ + Type: "object", + Properties: map[string]api.ToolProperty{ + "expression": { + Type: api.PropertyType{"string"}, + Description: "Mathematical expression to evaluate", + }, + }, + Required: []string{"expression"}, + }, + }, + }, + }, + thinkValue: &api.ThinkValue{Value: false}, + expected: `<|begin▁of▁sentence|> + +## Tools +You have access to the following tools: + +### get_weather +Description: Get current weather information + +Parameters: {"type":"object","required":["location"],"properties":{"location":{"type":"string","description":"City name"}}} + +### calculate +Description: Perform mathematical calculations + +Parameters: {"type":"object","required":["expression"],"properties":{"expression":{"type":"string","description":"Mathematical expression to evaluate"}}} + +IMPORTANT: ALWAYS adhere to this exact format for tool use: +<|tool▁calls▁begin|><|tool▁call▁begin|>tool_call_name<|tool▁sep|>tool_call_arguments<|tool▁call▁end|>{{additional_tool_calls}}<|tool▁calls▁end|> + +Where: + +- ` + "`tool_call_name`" + ` must be an exact match to one of the available tools +- ` + "`tool_call_arguments`" + ` must be valid JSON that strictly follows the tool's Parameters Schema +- For multiple tool calls, chain them directly without separators or spaces +<|User|>Get weather for Paris and calculate 25 * 4<|Assistant|><|tool▁calls▁begin|><|tool▁call▁begin|>get_weather<|tool▁sep|>{"location":"Paris"}<|tool▁call▁end|><|tool▁call▁begin|>calculate<|tool▁sep|>{"expression":"25 * 4"}<|tool▁call▁end|><|tool▁calls▁end|><|end▁of▁sentence|><|tool▁output▁begin|>Temperature: 22°C, Sunny<|tool▁output▁end|><|tool▁output▁begin|>Result: 100<|tool▁output▁end|>`, + }, + { + name: "tools without system message", + messages: []api.Message{ + {Role: "user", Content: "What's the weather?"}, + }, + tools: []api.Tool{ + { + Type: "function", + Function: api.ToolFunction{ + Name: "get_weather", + Description: "Get current weather information", + Parameters: api.ToolFunctionParameters{ + Type: "object", + Properties: map[string]api.ToolProperty{ + "location": { + Type: api.PropertyType{"string"}, + Description: "City name", + }, + }, + Required: []string{"location"}, + }, + }, + }, + }, + thinkValue: &api.ThinkValue{Value: false}, + expected: `<|begin▁of▁sentence|> + +## Tools +You have access to the following tools: + +### get_weather +Description: Get current weather information + +Parameters: {"type":"object","required":["location"],"properties":{"location":{"type":"string","description":"City name"}}} + +IMPORTANT: ALWAYS adhere to this exact format for tool use: +<|tool▁calls▁begin|><|tool▁call▁begin|>tool_call_name<|tool▁sep|>tool_call_arguments<|tool▁call▁end|>{{additional_tool_calls}}<|tool▁calls▁end|> + +Where: + +- ` + "`tool_call_name`" + ` must be an exact match to one of the available tools +- ` + "`tool_call_arguments`" + ` must be valid JSON that strictly follows the tool's Parameters Schema +- For multiple tool calls, chain them directly without separators or spaces +<|User|>What's the weather?<|Assistant|>`, + }, } renderer := &DeepSeek3Renderer{IsThinking: true, Variant: Deepseek31}