mirror of
https://github.com/ollama/ollama.git
synced 2026-01-29 07:12:03 +03:00
* preserve tool definition and call JSON ordering This is another iteration of <https://github.com/ollama/ollama/pull/12518>, but this time we've simplified things by relaxing the competing requirements of being compatible AND order-preserving with templates (vs. renderers). We maintain backwards compatibility at the cost of not guaranteeing order for templates. We plan on moving more and more models to renderers, which have been updated to use these new data types, and additionally we could add an opt-in way of templates getting an order-preserved list (e.g., via sibling template vars) * orderedmap_test: remove testify
99 lines
2.5 KiB
Go
99 lines
2.5 KiB
Go
package parsers
|
|
|
|
import (
|
|
"encoding/json"
|
|
|
|
"github.com/google/go-cmp/cmp"
|
|
"github.com/ollama/ollama/api"
|
|
)
|
|
|
|
// argsComparer provides cmp options for comparing ToolCallFunctionArguments
|
|
// It compares by logical equality (same keys with same values) not by order
|
|
var argsComparer = cmp.Comparer(func(a, b api.ToolCallFunctionArguments) bool {
|
|
// Convert both to maps and compare
|
|
aMap := a.ToMap()
|
|
bMap := b.ToMap()
|
|
if len(aMap) != len(bMap) {
|
|
return false
|
|
}
|
|
for k, av := range aMap {
|
|
bv, ok := bMap[k]
|
|
if !ok {
|
|
return false
|
|
}
|
|
// Use JSON encoding for deep comparison of values
|
|
aJSON, _ := json.Marshal(av)
|
|
bJSON, _ := json.Marshal(bv)
|
|
if string(aJSON) != string(bJSON) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
})
|
|
|
|
// propsComparer provides cmp options for comparing ToolPropertiesMap
|
|
var propsComparer = cmp.Comparer(func(a, b *api.ToolPropertiesMap) bool {
|
|
if a == nil && b == nil {
|
|
return true
|
|
}
|
|
if a == nil || b == nil {
|
|
return false
|
|
}
|
|
aJSON, _ := json.Marshal(a)
|
|
bJSON, _ := json.Marshal(b)
|
|
return string(aJSON) == string(bJSON)
|
|
})
|
|
|
|
// toolsComparer combines argsComparer and propsComparer for comparing tools
|
|
var toolsComparer = cmp.Options{argsComparer, propsComparer}
|
|
|
|
// toolCallEqual compares two tool calls by comparing their components
|
|
// It compares arguments by logical equality (same keys with same values) not by order
|
|
func toolCallEqual(a, b api.ToolCall) bool {
|
|
if a.ID != b.ID {
|
|
return false
|
|
}
|
|
if a.Function.Index != b.Function.Index {
|
|
return false
|
|
}
|
|
if a.Function.Name != b.Function.Name {
|
|
return false
|
|
}
|
|
// Compare arguments by logical equality using argsComparer logic
|
|
aMap := a.Function.Arguments.ToMap()
|
|
bMap := b.Function.Arguments.ToMap()
|
|
if len(aMap) != len(bMap) {
|
|
return false
|
|
}
|
|
for k, av := range aMap {
|
|
bv, ok := bMap[k]
|
|
if !ok {
|
|
return false
|
|
}
|
|
aJSON, _ := json.Marshal(av)
|
|
bJSON, _ := json.Marshal(bv)
|
|
if string(aJSON) != string(bJSON) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
// testPropsMap creates a ToolPropertiesMap from a map (convenience function for tests, order not preserved)
|
|
func testPropsMap(m map[string]api.ToolProperty) *api.ToolPropertiesMap {
|
|
props := api.NewToolPropertiesMap()
|
|
for k, v := range m {
|
|
props.Set(k, v)
|
|
}
|
|
return props
|
|
}
|
|
|
|
// testArgs creates ToolCallFunctionArguments from a map (convenience function for tests, order not preserved)
|
|
func testArgs(m map[string]any) api.ToolCallFunctionArguments {
|
|
args := api.NewToolCallFunctionArguments()
|
|
for k, v := range m {
|
|
args.Set(k, v)
|
|
}
|
|
return args
|
|
}
|