mirror of
https://github.com/ollama/ollama.git
synced 2026-07-03 03:38:52 +00:00
parser/renderer: add Ornith 9B renderer/parser support (#16920)
This commit is contained in:
parent
2cb2c5381f
commit
2e474c98f9
6 changed files with 101 additions and 4 deletions
|
|
@ -54,6 +54,8 @@ func ParserForName(name string) Parser {
|
|||
p = &Qwen3Parser{hasThinkingSupport: true, defaultThinking: true}
|
||||
case "qwen3.5":
|
||||
p = &Qwen35Parser{}
|
||||
case "ornith":
|
||||
p = &Qwen35Parser{}
|
||||
case "qwen3-coder":
|
||||
p = &Qwen3CoderParser{}
|
||||
case "qwen3-vl-instruct":
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ func TestBuiltInParsersStillWork(t *testing.T) {
|
|||
{"lfm2"},
|
||||
{"lfm2-thinking"},
|
||||
{"qwen3.5"},
|
||||
{"ornith"},
|
||||
{"harmony"},
|
||||
}
|
||||
|
||||
|
|
|
|||
16
model/renderers/ornith.go
Normal file
16
model/renderers/ornith.go
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
package renderers
|
||||
|
||||
type OrnithRenderer struct {
|
||||
Qwen35Renderer
|
||||
}
|
||||
|
||||
func newOrnithRenderer() Renderer {
|
||||
return &OrnithRenderer{
|
||||
Qwen35Renderer: Qwen35Renderer{
|
||||
isThinking: true,
|
||||
alwaysRenderAssistantThinkBlock: true,
|
||||
emitEmptyThinkOnNoThink: true,
|
||||
useImgTags: RenderImgTags,
|
||||
},
|
||||
}
|
||||
}
|
||||
74
model/renderers/ornith_test.go
Normal file
74
model/renderers/ornith_test.go
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
package renderers
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/ollama/ollama/api"
|
||||
)
|
||||
|
||||
func TestOrnithRendererMatchesAssistantHistoryThinkBlocks(t *testing.T) {
|
||||
msgs := []api.Message{
|
||||
{Role: "user", Content: "Say hello."},
|
||||
{Role: "assistant", Content: "Hello."},
|
||||
{Role: "user", Content: "Now say bye."},
|
||||
}
|
||||
|
||||
got, err := RenderWithRenderer("ornith", msgs, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("render failed: %v", err)
|
||||
}
|
||||
|
||||
want := `<|im_start|>user
|
||||
Say hello.<|im_end|>
|
||||
<|im_start|>assistant
|
||||
<think>
|
||||
|
||||
</think>
|
||||
|
||||
Hello.<|im_end|>
|
||||
<|im_start|>user
|
||||
Now say bye.<|im_end|>
|
||||
<|im_start|>assistant
|
||||
<think>
|
||||
`
|
||||
if got != want {
|
||||
t.Fatalf("unexpected Ornith render\n--- got ---\n%q\n--- want ---\n%q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOrnithRendererKeepsAssistantThinkBlocksWhenThinkingDisabled(t *testing.T) {
|
||||
msgs := []api.Message{
|
||||
{Role: "user", Content: "Say hello."},
|
||||
{
|
||||
Role: "assistant",
|
||||
Thinking: "Keep it short.",
|
||||
Content: "Hello.",
|
||||
},
|
||||
{Role: "user", Content: "Now say bye."},
|
||||
}
|
||||
|
||||
got, err := RenderWithRenderer("ornith", msgs, nil, &api.ThinkValue{Value: false})
|
||||
if err != nil {
|
||||
t.Fatalf("render failed: %v", err)
|
||||
}
|
||||
|
||||
want := `<|im_start|>user
|
||||
Say hello.<|im_end|>
|
||||
<|im_start|>assistant
|
||||
<think>
|
||||
Keep it short.
|
||||
</think>
|
||||
|
||||
Hello.<|im_end|>
|
||||
<|im_start|>user
|
||||
Now say bye.<|im_end|>
|
||||
<|im_start|>assistant
|
||||
<think>
|
||||
|
||||
</think>
|
||||
|
||||
`
|
||||
if got != want {
|
||||
t.Fatalf("unexpected Ornith render with thinking disabled\n--- got ---\n%q\n--- want ---\n%q", got, want)
|
||||
}
|
||||
}
|
||||
|
|
@ -39,8 +39,9 @@ Reminder:
|
|||
type Qwen35Renderer struct {
|
||||
isThinking bool
|
||||
|
||||
emitEmptyThinkOnNoThink bool
|
||||
useImgTags bool
|
||||
alwaysRenderAssistantThinkBlock bool
|
||||
emitEmptyThinkOnNoThink bool
|
||||
useImgTags bool
|
||||
}
|
||||
|
||||
func (r *Qwen35Renderer) LeadingBOS() string {
|
||||
|
|
@ -140,9 +141,10 @@ func (r *Qwen35Renderer) Render(messages []api.Message, tools []api.Tool, think
|
|||
if message.Role == "user" || (message.Role == "system" && i != 0) {
|
||||
sb.WriteString(imStartTag + message.Role + "\n" + content + imEndTag + "\n")
|
||||
} else if message.Role == "assistant" {
|
||||
contentReasoning, content := splitQwen35ReasoningContent(content, message.Thinking, isThinking)
|
||||
renderAssistantThinkBlock := r.alwaysRenderAssistantThinkBlock || (isThinking && i > lastQueryIndex)
|
||||
contentReasoning, content := splitQwen35ReasoningContent(content, message.Thinking, renderAssistantThinkBlock)
|
||||
|
||||
if isThinking && i > lastQueryIndex {
|
||||
if renderAssistantThinkBlock {
|
||||
sb.WriteString(imStartTag + message.Role + "\n<think>\n" + contentReasoning + "\n</think>\n\n" + content)
|
||||
} else {
|
||||
sb.WriteString(imStartTag + message.Role + "\n" + content)
|
||||
|
|
|
|||
|
|
@ -69,6 +69,8 @@ func rendererForName(name string) Renderer {
|
|||
case "qwen3.5":
|
||||
renderer := &Qwen35Renderer{isThinking: true, emitEmptyThinkOnNoThink: true, useImgTags: RenderImgTags}
|
||||
return renderer
|
||||
case "ornith":
|
||||
return newOrnithRenderer()
|
||||
case "cogito":
|
||||
renderer := &CogitoRenderer{isThinking: true}
|
||||
return renderer
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue