From 2c639431b1c460135005116be4ddc81205281133 Mon Sep 17 00:00:00 2001 From: Grace <88872231+gr4ceG@users.noreply.github.com> Date: Mon, 15 Dec 2025 14:50:52 -0800 Subject: [PATCH] DeepseekV3 family renderer (#13180) --- model/renderers/deepseek3.go | 121 ++++++++ model/renderers/deepseek3_test.go | 492 ++++++++++++++++++++++++++++++ model/renderers/renderer.go | 3 + 3 files changed, 616 insertions(+) create mode 100644 model/renderers/deepseek3.go create mode 100644 model/renderers/deepseek3_test.go diff --git a/model/renderers/deepseek3.go b/model/renderers/deepseek3.go new file mode 100644 index 000000000..ec98574ed --- /dev/null +++ b/model/renderers/deepseek3.go @@ -0,0 +1,121 @@ +package renderers + +import ( + "encoding/json" + "strings" + + "github.com/ollama/ollama/api" +) + +type DeepSeek3Variant int + +const ( + Deepseek31 DeepSeek3Variant = iota +) + +type DeepSeek3Renderer struct { + IsThinking bool + Variant DeepSeek3Variant +} + +func (r *DeepSeek3Renderer) Render(messages []api.Message, tools []api.Tool, thinkValue *api.ThinkValue) (string, error) { + var sb strings.Builder + + // thinking is enabled: model must support it AND user must request it + thinking := r.IsThinking && (thinkValue != nil && thinkValue.Bool()) + + // extract system messages first + var systemPrompt strings.Builder + isFirstSystemPrompt := true + + for _, message := range messages { + if message.Role == "system" { + if isFirstSystemPrompt { + systemPrompt.WriteString(message.Content) + isFirstSystemPrompt = false + } else { + systemPrompt.WriteString("\n\n" + message.Content) + } + } + } + + sb.WriteString("<|begin▁of▁sentence|>" + systemPrompt.String()) + + // state tracking + isTool := false + isLastUser := false + + for _, message := range messages { + switch message.Role { + case "user": + isTool = false + isLastUser = true + sb.WriteString("<|User|>" + message.Content) + + case "assistant": + if len(message.ToolCalls) > 0 { + if isLastUser { + sb.WriteString("<|Assistant|>") + } + isLastUser = false + isTool = false + + if message.Content != "" { + sb.WriteString(message.Content) + } + + sb.WriteString("<|tool▁calls▁begin|>") + for _, toolCall := range message.ToolCalls { + sb.WriteString("<|tool▁call▁begin|>" + toolCall.Function.Name + "<|tool▁sep|>") + + argsJSON, _ := json.Marshal(toolCall.Function.Arguments) + sb.WriteString(string(argsJSON)) + sb.WriteString("<|tool▁call▁end|>") + } + sb.WriteString("<|tool▁calls▁end|><|end▁of▁sentence|>") + } else { + if isLastUser { + sb.WriteString("<|Assistant|>") + // message["prefix"] is defined and message["prefix"] and thinking + // message.Thinking != "" represents message["prefix"] being defined + if message.Thinking != "" && thinking { + sb.WriteString("") + } else { + sb.WriteString("") + } + } + isLastUser = false + + content := message.Content + if isTool { + sb.WriteString(content + "<|end▁of▁sentence|>") + isTool = false + } else { + if strings.Contains(content, "") { + parts := strings.SplitN(content, "", 2) + if len(parts) > 1 { + content = parts[1] + } + } + sb.WriteString(content + "<|end▁of▁sentence|>") + } + } + + case "tool": + isLastUser = false + isTool = true + sb.WriteString("<|tool▁output▁begin|>" + message.Content + "<|tool▁output▁end|>") + } + } + + if isLastUser && !isTool { + sb.WriteString("<|Assistant|>") + if thinking { + sb.WriteString("") + } else { + sb.WriteString("") + } + } + + return sb.String(), nil +} diff --git a/model/renderers/deepseek3_test.go b/model/renderers/deepseek3_test.go new file mode 100644 index 000000000..e25bf624a --- /dev/null +++ b/model/renderers/deepseek3_test.go @@ -0,0 +1,492 @@ +package renderers + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + + "github.com/ollama/ollama/api" +) + +func TestDeepSeekRenderer(t *testing.T) { + tests := []struct { + name string + messages []api.Message + tools []api.Tool + thinkValue *api.ThinkValue + expected string + }{ + { + name: "basic user message", + messages: []api.Message{ + {Role: "user", Content: "Hello, how are you?"}, + }, + thinkValue: &api.ThinkValue{Value: false}, + expected: `<|begin▁of▁sentence|><|User|>Hello, how are you?<|Assistant|>`, + }, + { + name: "basic with system message", + messages: []api.Message{ + {Role: "system", Content: "You are a helpful assistant."}, + {Role: "user", Content: "Hello, how are you?"}, + }, + thinkValue: &api.ThinkValue{Value: false}, + expected: `<|begin▁of▁sentence|>You are a helpful assistant.<|User|>Hello, how are you?<|Assistant|>`, + }, + { + name: "multiple system messages", + messages: []api.Message{ + {Role: "system", Content: "First instruction"}, + {Role: "system", Content: "Second instruction"}, + {Role: "user", Content: "Hello"}, + }, + thinkValue: &api.ThinkValue{Value: false}, + expected: `<|begin▁of▁sentence|>First instruction + +Second instruction<|User|>Hello<|Assistant|>`, + }, + { + name: "thinking enabled", + messages: []api.Message{ + {Role: "user", Content: "Hello, how are you?"}, + }, + thinkValue: &api.ThinkValue{Value: true}, + expected: `<|begin▁of▁sentence|><|User|>Hello, how are you?<|Assistant|>`, + }, + { + name: "thinking enabled with system", + messages: []api.Message{ + {Role: "system", Content: "You are a helpful assistant."}, + {Role: "user", Content: "Hello, how are you?"}, + }, + thinkValue: &api.ThinkValue{Value: true}, + expected: `<|begin▁of▁sentence|>You are a helpful assistant.<|User|>Hello, how are you?<|Assistant|>`, + }, + { + name: "conversation with assistant response", + messages: []api.Message{ + {Role: "user", Content: "What is the capital of France?"}, + {Role: "assistant", Content: "The capital of France is Paris."}, + {Role: "user", Content: "Fantastic!"}, + }, + thinkValue: &api.ThinkValue{Value: false}, + expected: `<|begin▁of▁sentence|><|User|>What is the capital of France?<|Assistant|>The capital of France is Paris.<|end▁of▁sentence|><|User|>Fantastic!<|Assistant|>`, + }, + { + name: "assistant with tool calls", + messages: []api.Message{ + {Role: "user", Content: "What's the weather?"}, + { + Role: "assistant", + ToolCalls: []api.ToolCall{ + { + Function: api.ToolCallFunction{ + Name: "get_weather", + Arguments: api.ToolCallFunctionArguments{ + "location": "Paris", + }, + }, + }, + }, + }, + }, + thinkValue: &api.ThinkValue{Value: false}, + expected: `<|begin▁of▁sentence|><|User|>What's the weather?<|Assistant|><|tool▁calls▁begin|><|tool▁call▁begin|>get_weather<|tool▁sep|>{"location":"Paris"}<|tool▁call▁end|><|tool▁calls▁end|><|end▁of▁sentence|>`, + }, + { + name: "assistant with content and tool calls", + messages: []api.Message{ + {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", + }, + }, + }, + }, + }, + }, + thinkValue: &api.ThinkValue{Value: false}, + expected: `<|begin▁of▁sentence|><|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|>`, + }, + { + name: "tool response", + messages: []api.Message{ + {Role: "user", Content: "What's the weather?"}, + { + Role: "assistant", + ToolCalls: []api.ToolCall{ + { + Function: api.ToolCallFunction{ + Name: "get_weather", + Arguments: api.ToolCallFunctionArguments{ + "location": "Paris", + }, + }, + }, + }, + }, + {Role: "tool", Content: "Temperature: 22°C, Sunny"}, + }, + thinkValue: &api.ThinkValue{Value: false}, + expected: `<|begin▁of▁sentence|><|User|>What's the weather?<|Assistant|><|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|>`, + }, + { + name: "multiple tool calls", + messages: []api.Message{ + {Role: "user", Content: "Get weather for Paris and London"}, + { + Role: "assistant", + ToolCalls: []api.ToolCall{ + { + Function: api.ToolCallFunction{ + Name: "get_weather", + Arguments: api.ToolCallFunctionArguments{ + "location": "Paris", + }, + }, + }, + { + Function: api.ToolCallFunction{ + Name: "get_weather", + Arguments: api.ToolCallFunctionArguments{ + "location": "London", + }, + }, + }, + }, + }, + {Role: "tool", Content: "Paris: 22°C, Sunny"}, + {Role: "tool", Content: "London: 18°C, Cloudy"}, + }, + thinkValue: &api.ThinkValue{Value: false}, + expected: `<|begin▁of▁sentence|><|User|>Get weather for Paris and London<|Assistant|><|tool▁calls▁begin|><|tool▁call▁begin|>get_weather<|tool▁sep|>{"location":"Paris"}<|tool▁call▁end|><|tool▁call▁begin|>get_weather<|tool▁sep|>{"location":"London"}<|tool▁call▁end|><|tool▁calls▁end|><|end▁of▁sentence|><|tool▁output▁begin|>Paris: 22°C, Sunny<|tool▁output▁end|><|tool▁output▁begin|>London: 18°C, Cloudy<|tool▁output▁end|>`, + }, + { + name: "content with tag removal", + messages: []api.Message{ + {Role: "user", Content: "Think about this"}, + {Role: "assistant", Content: "I'm thinking about this.The answer is 42."}, + }, + thinkValue: &api.ThinkValue{Value: false}, + expected: `<|begin▁of▁sentence|><|User|>Think about this<|Assistant|>The answer is 42.<|end▁of▁sentence|>`, + }, + { + name: "empty system message", + messages: []api.Message{ + {Role: "system", Content: ""}, + {Role: "user", Content: "Hello"}, + }, + thinkValue: &api.ThinkValue{Value: false}, + expected: `<|begin▁of▁sentence|><|User|>Hello<|Assistant|>`, + }, + { + name: "empty assistant content", + messages: []api.Message{ + {Role: "user", Content: "Hello"}, + {Role: "assistant", Content: ""}, + }, + thinkValue: &api.ThinkValue{Value: false}, + expected: `<|begin▁of▁sentence|><|User|>Hello<|Assistant|><|end▁of▁sentence|>`, + }, + { + name: "special characters", + messages: []api.Message{ + {Role: "user", Content: "What about <|special|> tokens and \"quotes\"?"}, + {Role: "assistant", Content: "They're handled normally."}, + }, + thinkValue: &api.ThinkValue{Value: false}, + expected: `<|begin▁of▁sentence|><|User|>What about <|special|> tokens and "quotes"?<|Assistant|>They're handled normally.<|end▁of▁sentence|>`, + }, + { + name: "tool calls with null content", + messages: []api.Message{ + {Role: "user", Content: "Get weather"}, + { + Role: "assistant", + ToolCalls: []api.ToolCall{ + { + Function: api.ToolCallFunction{ + Name: "get_weather", + Arguments: api.ToolCallFunctionArguments{ + "location": "Paris", + }, + }, + }, + }, + }, + }, + thinkValue: &api.ThinkValue{Value: false}, + expected: `<|begin▁of▁sentence|><|User|>Get weather<|Assistant|><|tool▁calls▁begin|><|tool▁call▁begin|>get_weather<|tool▁sep|>{"location":"Paris"}<|tool▁call▁end|><|tool▁calls▁end|><|end▁of▁sentence|>`, + }, + { + name: "assistant after tool context", + messages: []api.Message{ + {Role: "user", Content: "Process data"}, + { + Role: "assistant", + ToolCalls: []api.ToolCall{ + { + Function: api.ToolCallFunction{ + Name: "process", + Arguments: api.ToolCallFunctionArguments{ + "data": "test", + }, + }, + }, + }, + }, + {Role: "tool", Content: "Success"}, + {Role: "assistant", Content: "Done"}, + }, + thinkValue: &api.ThinkValue{Value: false}, + expected: `<|begin▁of▁sentence|><|User|>Process data<|Assistant|><|tool▁calls▁begin|><|tool▁call▁begin|>process<|tool▁sep|>{"data":"test"}<|tool▁call▁end|><|tool▁calls▁end|><|end▁of▁sentence|><|tool▁output▁begin|>Success<|tool▁output▁end|>Done<|end▁of▁sentence|>`, + }, + { + name: "no messages", + messages: []api.Message{}, + thinkValue: &api.ThinkValue{Value: false}, + expected: `<|begin▁of▁sentence|>`, + }, + { + name: "only system messages", + messages: []api.Message{ + {Role: "system", Content: "System instruction"}, + }, + thinkValue: &api.ThinkValue{Value: false}, + expected: `<|begin▁of▁sentence|>System instruction`, + }, + { + name: "multiple think tags in content", + messages: []api.Message{ + {Role: "user", Content: "Complex question"}, + {Role: "assistant", Content: "First thoughtSecond thoughtFinal answer"}, + }, + thinkValue: &api.ThinkValue{Value: false}, + expected: `<|begin▁of▁sentence|><|User|>Complex question<|Assistant|>Second thoughtFinal answer<|end▁of▁sentence|>`, + }, + { + name: "thinking enabled after tool call - should render thinking", + messages: []api.Message{ + {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", + }, + }, + }, + }, + }, + {Role: "tool", Content: "Temperature: 22°C, Sunny"}, + {Role: "assistant", Content: "Based on the weather data, it's sunny in Paris."}, + {Role: "user", Content: "Now tell me about London weather too."}, + }, + thinkValue: &api.ThinkValue{Value: true}, + expected: `<|begin▁of▁sentence|><|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|><|tool▁output▁begin|>Temperature: 22°C, Sunny<|tool▁output▁end|>Based on the weather data, it's sunny in Paris.<|end▁of▁sentence|><|User|>Now tell me about London weather too.<|Assistant|>`, + }, + { + name: "thinking disabled after tool call - should not render thinking", + messages: []api.Message{ + {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", + }, + }, + }, + }, + }, + {Role: "tool", Content: "Temperature: 22°C, Sunny"}, + {Role: "assistant", Content: "Based on the weather data, it's sunny in Paris."}, + {Role: "user", Content: "Now tell me about London weather too."}, + }, + thinkValue: &api.ThinkValue{Value: false}, + expected: `<|begin▁of▁sentence|><|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|><|tool▁output▁begin|>Temperature: 22°C, Sunny<|tool▁output▁end|>Based on the weather data, it's sunny in Paris.<|end▁of▁sentence|><|User|>Now tell me about London weather too.<|Assistant|>`, + }, + { + name: "thinking enabled but messages without thinking content", + messages: []api.Message{ + {Role: "user", Content: "First question about cats"}, + {Role: "assistant", Content: "Cats are wonderful pets."}, + {Role: "user", Content: "What about dogs?"}, + {Role: "assistant", Content: "Dogs are loyal companions."}, + {Role: "user", Content: "Final question about birds"}, + }, + thinkValue: &api.ThinkValue{Value: true}, + expected: `<|begin▁of▁sentence|><|User|>First question about cats<|Assistant|>Cats are wonderful pets.<|end▁of▁sentence|><|User|>What about dogs?<|Assistant|>Dogs are loyal companions.<|end▁of▁sentence|><|User|>Final question about birds<|Assistant|>`, + }, + { + name: "thinking disabled for all assistant responses", + messages: []api.Message{ + {Role: "user", Content: "First question about cats"}, + {Role: "assistant", Content: "Cats are wonderful pets."}, + {Role: "user", Content: "What about dogs?"}, + {Role: "assistant", Content: "Dogs are loyal companions."}, + {Role: "user", Content: "Final question about birds"}, + }, + thinkValue: &api.ThinkValue{Value: false}, + expected: `<|begin▁of▁sentence|><|User|>First question about cats<|Assistant|>Cats are wonderful pets.<|end▁of▁sentence|><|User|>What about dogs?<|Assistant|>Dogs are loyal companions.<|end▁of▁sentence|><|User|>Final question about birds<|Assistant|>`, + }, + { + name: "complex conversation with tool calls and thinking enabled", + messages: []api.Message{ + {Role: "user", Content: "Tell me about the weather"}, + {Role: "assistant", Content: "I'll check the weather for you."}, + {Role: "user", Content: "Actually, get Paris weather specifically"}, + { + Role: "assistant", + ToolCalls: []api.ToolCall{ + { + Function: api.ToolCallFunction{ + Name: "get_weather", + Arguments: api.ToolCallFunctionArguments{ + "location": "Paris", + }, + }, + }, + }, + }, + {Role: "tool", Content: "Paris: 22°C, Sunny"}, + {Role: "assistant", Content: "The weather in Paris is great!"}, + {Role: "user", Content: "What about the forecast for tomorrow?"}, + }, + thinkValue: &api.ThinkValue{Value: true}, + expected: `<|begin▁of▁sentence|><|User|>Tell me about the weather<|Assistant|>I'll check the weather for you.<|end▁of▁sentence|><|User|>Actually, get Paris weather specifically<|Assistant|><|tool▁calls▁begin|><|tool▁call▁begin|>get_weather<|tool▁sep|>{"location":"Paris"}<|tool▁call▁end|><|tool▁calls▁end|><|end▁of▁sentence|><|tool▁output▁begin|>Paris: 22°C, Sunny<|tool▁output▁end|>The weather in Paris is great!<|end▁of▁sentence|><|User|>What about the forecast for tomorrow?<|Assistant|>`, + }, + { + name: "tool call without subsequent user message - no thinking", + messages: []api.Message{ + {Role: "user", Content: "Get the weather"}, + { + Role: "assistant", + ToolCalls: []api.ToolCall{ + { + Function: api.ToolCallFunction{ + Name: "get_weather", + Arguments: api.ToolCallFunctionArguments{ + "location": "Paris", + }, + }, + }, + }, + }, + {Role: "tool", Content: "22°C, Sunny"}, + }, + thinkValue: &api.ThinkValue{Value: true}, + expected: `<|begin▁of▁sentence|><|User|>Get the weather<|Assistant|><|tool▁calls▁begin|><|tool▁call▁begin|>get_weather<|tool▁sep|>{"location":"Paris"}<|tool▁call▁end|><|tool▁calls▁end|><|end▁of▁sentence|><|tool▁output▁begin|>22°C, Sunny<|tool▁output▁end|>`, + }, + { + name: "messages with thinking content, no thinking in render", + messages: []api.Message{ + {Role: "user", Content: "Solve this math problem: 15 * 23"}, + { + Role: "assistant", + Content: "The answer is 345.", + Thinking: "Let me calculate 15 * 23. I can break this down: 15 * 20 = 300, and 15 * 3 = 45, so 300 + 45 = 345.", + }, + {Role: "user", Content: "What about 12 * 34?"}, + }, + thinkValue: &api.ThinkValue{Value: false}, + expected: `<|begin▁of▁sentence|><|User|>Solve this math problem: 15 * 23<|Assistant|>The answer is 345.<|end▁of▁sentence|><|User|>What about 12 * 34?<|Assistant|>`, + }, + { + name: "conversation with mix of thinking and no thinking", + messages: []api.Message{ + {Role: "user", Content: "Explain quantum physics"}, + { + Role: "assistant", + Content: "Quantum physics is the study of matter and energy at the smallest scales.", + Thinking: "This is a complex topic. I should start with basic concepts and avoid overwhelming technical details.", + }, + {Role: "user", Content: "What about photons?"}, + { + Role: "assistant", + Content: "Photons are particles of light with no mass.", + }, + {Role: "user", Content: "How do they interact with matter?"}, + }, + thinkValue: &api.ThinkValue{Value: true}, + expected: `<|begin▁of▁sentence|><|User|>Explain quantum physics<|Assistant|>Quantum physics is the study of matter and energy at the smallest scales.<|end▁of▁sentence|><|User|>What about photons?<|Assistant|>Photons are particles of light with no mass.<|end▁of▁sentence|><|User|>How do they interact with matter?<|Assistant|>`, + }, + { + name: "tool call with thinking content in response", + messages: []api.Message{ + {Role: "user", Content: "What's the weather in Tokyo and New York?"}, + { + Role: "assistant", + Content: "I'll check the weather for both cities.", + Thinking: "I need to call the weather API for two different cities. Let me make parallel calls.", + ToolCalls: []api.ToolCall{ + { + Function: api.ToolCallFunction{ + Name: "get_weather", + Arguments: api.ToolCallFunctionArguments{ + "location": "Tokyo", + }, + }, + }, + { + Function: api.ToolCallFunction{ + Name: "get_weather", + Arguments: api.ToolCallFunctionArguments{ + "location": "New York", + }, + }, + }, + }, + }, + {Role: "tool", Content: "Tokyo: 18°C, Cloudy"}, + {Role: "tool", Content: "New York: 22°C, Sunny"}, + { + Role: "assistant", + Content: "Based on the weather data: Tokyo is cloudy at 18°C, while New York is sunny at 22°C.", + Thinking: "The data shows a nice contrast between the two cities. Tokyo is cooler and overcast while NYC has better weather.", + }, + }, + thinkValue: &api.ThinkValue{Value: true}, + expected: `<|begin▁of▁sentence|><|User|>What's the weather in Tokyo and New York?<|Assistant|>I'll check the weather for both cities.<|tool▁calls▁begin|><|tool▁call▁begin|>get_weather<|tool▁sep|>{"location":"Tokyo"}<|tool▁call▁end|><|tool▁call▁begin|>get_weather<|tool▁sep|>{"location":"New York"}<|tool▁call▁end|><|tool▁calls▁end|><|end▁of▁sentence|><|tool▁output▁begin|>Tokyo: 18°C, Cloudy<|tool▁output▁end|><|tool▁output▁begin|>New York: 22°C, Sunny<|tool▁output▁end|>Based on the weather data: Tokyo is cloudy at 18°C, while New York is sunny at 22°C.<|end▁of▁sentence|>`, + }, + { + name: "empty thinking field", + messages: []api.Message{ + {Role: "user", Content: "Simple question"}, + { + Role: "assistant", + Content: "Simple answer.", + Thinking: "", // Empty thinking content + }, + }, + thinkValue: &api.ThinkValue{Value: true}, + expected: `<|begin▁of▁sentence|><|User|>Simple question<|Assistant|>Simple answer.<|end▁of▁sentence|>`, + }, + } + + renderer := &DeepSeek3Renderer{IsThinking: true, Variant: Deepseek31} + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + rendered, err := renderer.Render(tt.messages, tt.tools, tt.thinkValue) + if err != nil { + t.Fatalf("Render() error = %v", err) + } + if diff := cmp.Diff(tt.expected, rendered); diff != "" { + t.Errorf("Render() mismatch (-want +got):\n%s", diff) + } + }) + } +} diff --git a/model/renderers/renderer.go b/model/renderers/renderer.go index e3d797a62..d05182d94 100644 --- a/model/renderers/renderer.go +++ b/model/renderers/renderer.go @@ -59,6 +59,9 @@ func rendererForName(name string) Renderer { case "cogito": renderer := &CogitoRenderer{isThinking: true} return renderer + case "deepseek-v3.1": + renderer := &DeepSeek3Renderer{IsThinking: true, Variant: Deepseek31} + return renderer case "olmo3": renderer := &Olmo3Renderer{UseExtendedSystemMessage: false} return renderer