Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
OpenDAS
ollama
Commits
fd8aa947
Unverified
Commit
fd8aa947
authored
Oct 14, 2025
by
Devon Rifkin
Committed by
GitHub
Oct 14, 2025
Browse files
Merge pull request #12562 from ollama/drifkin/registries
add registries for parsers/renderers
parents
05982a95
ddaca643
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
222 additions
and
4 deletions
+222
-4
model/parsers/parsers.go
model/parsers/parsers.go
+21
-0
model/parsers/parsers_test.go
model/parsers/parsers_test.go
+97
-0
model/renderers/renderer.go
model/renderers/renderer.go
+36
-2
model/renderers/renderer_test.go
model/renderers/renderer_test.go
+67
-0
server/prompt.go
server/prompt.go
+1
-2
No files found.
model/parsers/parsers.go
View file @
fd8aa947
...
...
@@ -16,7 +16,28 @@ type Parser interface {
HasThinkingSupport
()
bool
}
type
ParserConstructor
func
()
Parser
type
ParserRegistry
struct
{
constructors
map
[
string
]
ParserConstructor
}
func
(
r
*
ParserRegistry
)
Register
(
name
string
,
constructor
ParserConstructor
)
{
r
.
constructors
[
name
]
=
constructor
}
var
registry
=
ParserRegistry
{
constructors
:
make
(
map
[
string
]
ParserConstructor
),
}
func
Register
(
name
string
,
constructor
ParserConstructor
)
{
registry
.
Register
(
name
,
constructor
)
}
func
ParserForName
(
name
string
)
Parser
{
if
parser
,
ok
:=
registry
.
constructors
[
name
];
ok
{
return
parser
()
}
switch
name
{
case
"qwen3-coder"
:
parser
:=
&
Qwen3CoderParser
{}
...
...
model/parsers/parsers_test.go
0 → 100644
View file @
fd8aa947
package
parsers
import
(
"testing"
"github.com/ollama/ollama/api"
)
type
mockParser
struct
{
name
string
}
func
(
m
*
mockParser
)
Init
(
tools
[]
api
.
Tool
,
lastMessage
*
api
.
Message
)
[]
api
.
Tool
{
return
tools
}
func
(
m
*
mockParser
)
Add
(
s
string
,
done
bool
)
(
content
string
,
thinking
string
,
calls
[]
api
.
ToolCall
,
err
error
)
{
return
"mock:"
+
s
,
""
,
nil
,
nil
}
func
(
m
*
mockParser
)
HasToolSupport
()
bool
{
return
false
}
func
(
m
*
mockParser
)
HasThinkingSupport
()
bool
{
return
false
}
func
TestRegisterCustomParser
(
t
*
testing
.
T
)
{
// Register a custom parser
Register
(
"custom-parser"
,
func
()
Parser
{
return
&
mockParser
{
name
:
"custom"
}
})
// Retrieve it
parser
:=
ParserForName
(
"custom-parser"
)
if
parser
==
nil
{
t
.
Fatal
(
"expected parser to be registered"
)
}
// Test it works
content
,
_
,
_
,
err
:=
parser
.
Add
(
"test"
,
false
)
if
err
!=
nil
{
t
.
Fatalf
(
"unexpected error: %v"
,
err
)
}
if
content
!=
"mock:test"
{
t
.
Errorf
(
"expected 'mock:test', got %q"
,
content
)
}
}
func
TestBuiltInParsersStillWork
(
t
*
testing
.
T
)
{
tests
:=
[]
struct
{
name
string
}{
{
"passthrough"
},
{
"qwen3-coder"
},
{
"harmony"
},
}
for
_
,
tt
:=
range
tests
{
t
.
Run
(
tt
.
name
,
func
(
t
*
testing
.
T
)
{
parser
:=
ParserForName
(
tt
.
name
)
if
parser
==
nil
{
t
.
Fatalf
(
"expected built-in parser %q to exist"
,
tt
.
name
)
}
})
}
}
func
TestOverrideBuiltInParser
(
t
*
testing
.
T
)
{
// Override a built-in parser
Register
(
"passthrough"
,
func
()
Parser
{
return
&
mockParser
{
name
:
"override"
}
})
// Should get the override
parser
:=
ParserForName
(
"passthrough"
)
if
parser
==
nil
{
t
.
Fatal
(
"expected parser to exist"
)
}
// Test it's the override
content
,
_
,
_
,
err
:=
parser
.
Add
(
"test"
,
false
)
if
err
!=
nil
{
t
.
Fatalf
(
"unexpected error: %v"
,
err
)
}
if
content
!=
"mock:test"
{
t
.
Errorf
(
"expected 'mock:test' from override, got %q"
,
content
)
}
}
func
TestUnknownParserReturnsNil
(
t
*
testing
.
T
)
{
parser
:=
ParserForName
(
"nonexistent-parser"
)
if
parser
!=
nil
{
t
.
Error
(
"expected nil for unknown parser"
)
}
}
model/renderers/renderer.go
View file @
fd8aa947
package
renderers
import
"github.com/ollama/ollama/api"
import
(
"fmt"
"github.com/ollama/ollama/api"
)
type
Renderer
interface
{
Render
(
messages
[]
api
.
Message
,
tools
[]
api
.
Tool
,
think
*
api
.
ThinkValue
)
(
string
,
error
)
}
func
RendererForName
(
name
string
)
Renderer
{
type
(
RendererConstructor
func
()
Renderer
RendererRegistry
struct
{
renderers
map
[
string
]
RendererConstructor
}
)
func
(
r
*
RendererRegistry
)
Register
(
name
string
,
renderer
RendererConstructor
)
{
r
.
renderers
[
name
]
=
renderer
}
var
registry
=
RendererRegistry
{
renderers
:
make
(
map
[
string
]
RendererConstructor
),
}
func
Register
(
name
string
,
renderer
RendererConstructor
)
{
registry
.
Register
(
name
,
renderer
)
}
func
RenderWithRenderer
(
name
string
,
msgs
[]
api
.
Message
,
tools
[]
api
.
Tool
,
think
*
api
.
ThinkValue
)
(
string
,
error
)
{
renderer
:=
rendererForName
(
name
)
if
renderer
==
nil
{
return
""
,
fmt
.
Errorf
(
"unknown renderer %q"
,
name
)
}
return
renderer
.
Render
(
msgs
,
tools
,
think
)
}
func
rendererForName
(
name
string
)
Renderer
{
if
constructor
,
ok
:=
registry
.
renderers
[
name
];
ok
{
return
constructor
()
}
switch
name
{
case
"qwen3-coder"
:
renderer
:=
&
Qwen3CoderRenderer
{}
...
...
model/renderers/renderer_test.go
0 → 100644
View file @
fd8aa947
package
renderers
import
(
"testing"
"github.com/ollama/ollama/api"
)
type
mockRenderer
struct
{}
func
(
m
*
mockRenderer
)
Render
(
msgs
[]
api
.
Message
,
tools
[]
api
.
Tool
,
think
*
api
.
ThinkValue
)
(
string
,
error
)
{
return
"mock-output"
,
nil
}
func
TestRegisterCustomRenderer
(
t
*
testing
.
T
)
{
// Register a custom renderer
Register
(
"custom-renderer"
,
func
()
Renderer
{
return
&
mockRenderer
{}
})
// Retrieve and use it
result
,
err
:=
RenderWithRenderer
(
"custom-renderer"
,
nil
,
nil
,
nil
)
if
err
!=
nil
{
t
.
Fatalf
(
"unexpected error: %v"
,
err
)
}
if
result
!=
"mock-output"
{
t
.
Errorf
(
"expected 'mock-output', got %q"
,
result
)
}
}
func
TestBuiltInRendererStillWorks
(
t
*
testing
.
T
)
{
// Test that qwen3-coder still works
messages
:=
[]
api
.
Message
{
{
Role
:
"user"
,
Content
:
"Hello"
},
}
result
,
err
:=
RenderWithRenderer
(
"qwen3-coder"
,
messages
,
nil
,
nil
)
if
err
!=
nil
{
t
.
Fatalf
(
"unexpected error: %v"
,
err
)
}
if
result
==
""
{
t
.
Error
(
"expected non-empty result from qwen3-coder renderer"
)
}
}
func
TestOverrideBuiltInRenderer
(
t
*
testing
.
T
)
{
// Override the built-in renderer
Register
(
"qwen3-coder"
,
func
()
Renderer
{
return
&
mockRenderer
{}
})
// Should get the override
result
,
err
:=
RenderWithRenderer
(
"qwen3-coder"
,
nil
,
nil
,
nil
)
if
err
!=
nil
{
t
.
Fatalf
(
"unexpected error: %v"
,
err
)
}
if
result
!=
"mock-output"
{
t
.
Errorf
(
"expected 'mock-output' from override, got %q"
,
result
)
}
}
func
TestUnknownRendererReturnsError
(
t
*
testing
.
T
)
{
_
,
err
:=
RenderWithRenderer
(
"nonexistent-renderer"
,
nil
,
nil
,
nil
)
if
err
==
nil
{
t
.
Error
(
"expected error for unknown renderer"
)
}
}
server/prompt.go
View file @
fd8aa947
...
...
@@ -106,8 +106,7 @@ func chatPrompt(ctx context.Context, m *Model, tokenize tokenizeFunc, opts *api.
func
renderPrompt
(
m
*
Model
,
msgs
[]
api
.
Message
,
tools
[]
api
.
Tool
,
think
*
api
.
ThinkValue
)
(
string
,
error
)
{
if
m
.
Config
.
Renderer
!=
""
{
renderer
:=
renderers
.
RendererForName
(
m
.
Config
.
Renderer
)
rendered
,
err
:=
renderer
.
Render
(
msgs
,
tools
,
think
)
rendered
,
err
:=
renderers
.
RenderWithRenderer
(
m
.
Config
.
Renderer
,
msgs
,
tools
,
think
)
if
err
!=
nil
{
return
""
,
err
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment