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
2d06977a
Unverified
Commit
2d06977a
authored
Aug 05, 2025
by
Devon Rifkin
Committed by
GitHub
Aug 05, 2025
Browse files
Merge pull request #11705 from ollama/drifkin/fn-schema
tools: support anyOf types
parents
e378e334
30f8a68c
Changes
7
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
264 additions
and
154 deletions
+264
-154
api/types.go
api/types.go
+58
-10
api/types_typescript_test.go
api/types_typescript_test.go
+142
-0
openai/openai_test.go
openai/openai_test.go
+6
-16
server/routes_generate_test.go
server/routes_generate_test.go
+12
-32
server/routes_harmony_streaming_test.go
server/routes_harmony_streaming_test.go
+12
-32
template/template.go
template/template.go
+10
-0
tools/tools_test.go
tools/tools_test.go
+24
-64
No files found.
api/types.go
View file @
2d06977a
...
...
@@ -225,6 +225,59 @@ func (pt PropertyType) String() string {
return
fmt
.
Sprintf
(
"%v"
,
[]
string
(
pt
))
}
type
ToolProperty
struct
{
AnyOf
[]
ToolProperty
`json:"anyOf,omitempty"`
Type
PropertyType
`json:"type"`
Items
any
`json:"items,omitempty"`
Description
string
`json:"description"`
Enum
[]
any
`json:"enum,omitempty"`
}
// ToTypeScriptType converts a ToolProperty to a TypeScript type string
func
(
tp
ToolProperty
)
ToTypeScriptType
()
string
{
if
len
(
tp
.
AnyOf
)
>
0
{
var
types
[]
string
for
_
,
anyOf
:=
range
tp
.
AnyOf
{
types
=
append
(
types
,
anyOf
.
ToTypeScriptType
())
}
return
strings
.
Join
(
types
,
" | "
)
}
if
len
(
tp
.
Type
)
==
0
{
return
"any"
}
if
len
(
tp
.
Type
)
==
1
{
return
mapToTypeScriptType
(
tp
.
Type
[
0
])
}
var
types
[]
string
for
_
,
t
:=
range
tp
.
Type
{
types
=
append
(
types
,
mapToTypeScriptType
(
t
))
}
return
strings
.
Join
(
types
,
" | "
)
}
// mapToTypeScriptType maps JSON Schema types to TypeScript types
func
mapToTypeScriptType
(
jsonType
string
)
string
{
switch
jsonType
{
case
"string"
:
return
"string"
case
"number"
,
"integer"
:
return
"number"
case
"boolean"
:
return
"boolean"
case
"array"
:
return
"any[]"
case
"object"
:
return
"Record<string, any>"
case
"null"
:
return
"null"
default
:
return
"any"
}
}
type
ToolFunction
struct
{
Name
string
`json:"name"`
Description
string
`json:"description"`
...
...
@@ -233,12 +286,7 @@ type ToolFunction struct {
Defs
any
`json:"$defs,omitempty"`
Items
any
`json:"items,omitempty"`
Required
[]
string
`json:"required"`
Properties
map
[
string
]
struct
{
Type
PropertyType
`json:"type"`
Items
any
`json:"items,omitempty"`
Description
string
`json:"description"`
Enum
[]
any
`json:"enum,omitempty"`
}
`json:"properties"`
Properties
map
[
string
]
ToolProperty
`json:"properties"`
}
`json:"parameters"`
}
...
...
api/types_typescript_test.go
0 → 100644
View file @
2d06977a
package
api
import
(
"testing"
)
func
TestToolParameterToTypeScriptType
(
t
*
testing
.
T
)
{
tests
:=
[]
struct
{
name
string
param
ToolProperty
expected
string
}{
{
name
:
"single string type"
,
param
:
ToolProperty
{
Type
:
PropertyType
{
"string"
},
},
expected
:
"string"
,
},
{
name
:
"single number type"
,
param
:
ToolProperty
{
Type
:
PropertyType
{
"number"
},
},
expected
:
"number"
,
},
{
name
:
"integer maps to number"
,
param
:
ToolProperty
{
Type
:
PropertyType
{
"integer"
},
},
expected
:
"number"
,
},
{
name
:
"boolean type"
,
param
:
ToolProperty
{
Type
:
PropertyType
{
"boolean"
},
},
expected
:
"boolean"
,
},
{
name
:
"array type"
,
param
:
ToolProperty
{
Type
:
PropertyType
{
"array"
},
},
expected
:
"any[]"
,
},
{
name
:
"object type"
,
param
:
ToolProperty
{
Type
:
PropertyType
{
"object"
},
},
expected
:
"Record<string, any>"
,
},
{
name
:
"null type"
,
param
:
ToolProperty
{
Type
:
PropertyType
{
"null"
},
},
expected
:
"null"
,
},
{
name
:
"multiple types as union"
,
param
:
ToolProperty
{
Type
:
PropertyType
{
"string"
,
"number"
},
},
expected
:
"string | number"
,
},
{
name
:
"string or null union"
,
param
:
ToolProperty
{
Type
:
PropertyType
{
"string"
,
"null"
},
},
expected
:
"string | null"
,
},
{
name
:
"anyOf with single types"
,
param
:
ToolProperty
{
AnyOf
:
[]
ToolProperty
{
{
Type
:
PropertyType
{
"string"
}},
{
Type
:
PropertyType
{
"number"
}},
},
},
expected
:
"string | number"
,
},
{
name
:
"anyOf with multiple types in each branch"
,
param
:
ToolProperty
{
AnyOf
:
[]
ToolProperty
{
{
Type
:
PropertyType
{
"string"
,
"null"
}},
{
Type
:
PropertyType
{
"number"
}},
},
},
expected
:
"string | null | number"
,
},
{
name
:
"nested anyOf"
,
param
:
ToolProperty
{
AnyOf
:
[]
ToolProperty
{
{
Type
:
PropertyType
{
"boolean"
}},
{
AnyOf
:
[]
ToolProperty
{
{
Type
:
PropertyType
{
"string"
}},
{
Type
:
PropertyType
{
"number"
}},
},
},
},
},
expected
:
"boolean | string | number"
,
},
{
name
:
"empty type returns any"
,
param
:
ToolProperty
{
Type
:
PropertyType
{},
},
expected
:
"any"
,
},
{
name
:
"unknown type maps to any"
,
param
:
ToolProperty
{
Type
:
PropertyType
{
"unknown_type"
},
},
expected
:
"any"
,
},
{
name
:
"multiple types including array"
,
param
:
ToolProperty
{
Type
:
PropertyType
{
"string"
,
"array"
,
"null"
},
},
expected
:
"string | any[] | null"
,
},
}
for
_
,
tt
:=
range
tests
{
t
.
Run
(
tt
.
name
,
func
(
t
*
testing
.
T
)
{
result
:=
tt
.
param
.
ToTypeScriptType
()
if
result
!=
tt
.
expected
{
t
.
Errorf
(
"ToTypeScriptType() = %q, want %q"
,
result
,
tt
.
expected
)
}
})
}
}
openai/openai_test.go
View file @
2d06977a
...
...
@@ -284,21 +284,11 @@ func TestChatMiddleware(t *testing.T) {
Defs
any
`json:"$defs,omitempty"`
Items
any
`json:"items,omitempty"`
Required
[]
string
`json:"required"`
Properties
map
[
string
]
struct
{
Type
api
.
PropertyType
`json:"type"`
Items
any
`json:"items,omitempty"`
Description
string
`json:"description"`
Enum
[]
any
`json:"enum,omitempty"`
}
`json:"properties"`
Properties
map
[
string
]
api
.
ToolProperty
`json:"properties"`
}{
Type
:
"object"
,
Required
:
[]
string
{
"location"
},
Properties
:
map
[
string
]
struct
{
Type
api
.
PropertyType
`json:"type"`
Items
any
`json:"items,omitempty"`
Description
string
`json:"description"`
Enum
[]
any
`json:"enum,omitempty"`
}{
Properties
:
map
[
string
]
api
.
ToolProperty
{
"location"
:
{
Type
:
api
.
PropertyType
{
"string"
},
Description
:
"The city and state"
,
...
...
server/routes_generate_test.go
View file @
2d06977a
...
...
@@ -392,21 +392,11 @@ func TestGenerateChat(t *testing.T) {
Defs
any
`json:"$defs,omitempty"`
Items
any
`json:"items,omitempty"`
Required
[]
string
`json:"required"`
Properties
map
[
string
]
struct
{
Type
api
.
PropertyType
`json:"type"`
Items
any
`json:"items,omitempty"`
Description
string
`json:"description"`
Enum
[]
any
`json:"enum,omitempty"`
}
`json:"properties"`
Properties
map
[
string
]
api
.
ToolProperty
`json:"properties"`
}{
Type
:
"object"
,
Required
:
[]
string
{
"location"
},
Properties
:
map
[
string
]
struct
{
Type
api
.
PropertyType
`json:"type"`
Items
any
`json:"items,omitempty"`
Description
string
`json:"description"`
Enum
[]
any
`json:"enum,omitempty"`
}{
Properties
:
map
[
string
]
api
.
ToolProperty
{
"location"
:
{
Type
:
api
.
PropertyType
{
"string"
},
Description
:
"The city and state"
,
...
...
@@ -493,21 +483,11 @@ func TestGenerateChat(t *testing.T) {
Defs
any
`json:"$defs,omitempty"`
Items
any
`json:"items,omitempty"`
Required
[]
string
`json:"required"`
Properties
map
[
string
]
struct
{
Type
api
.
PropertyType
`json:"type"`
Items
any
`json:"items,omitempty"`
Description
string
`json:"description"`
Enum
[]
any
`json:"enum,omitempty"`
}
`json:"properties"`
Properties
map
[
string
]
api
.
ToolProperty
`json:"properties"`
}{
Type
:
"object"
,
Required
:
[]
string
{
"location"
},
Properties
:
map
[
string
]
struct
{
Type
api
.
PropertyType
`json:"type"`
Items
any
`json:"items,omitempty"`
Description
string
`json:"description"`
Enum
[]
any
`json:"enum,omitempty"`
}{
Properties
:
map
[
string
]
api
.
ToolProperty
{
"location"
:
{
Type
:
api
.
PropertyType
{
"string"
},
Description
:
"The city and state"
,
...
...
server/routes_harmony_streaming_test.go
View file @
2d06977a
...
...
@@ -31,21 +31,11 @@ func getTestTools() []api.Tool {
Defs
any
`json:"$defs,omitempty"`
Items
any
`json:"items,omitempty"`
Required
[]
string
`json:"required"`
Properties
map
[
string
]
struct
{
Type
api
.
PropertyType
`json:"type"`
Items
any
`json:"items,omitempty"`
Description
string
`json:"description"`
Enum
[]
any
`json:"enum,omitempty"`
}
`json:"properties"`
Properties
map
[
string
]
api
.
ToolProperty
`json:"properties"`
}{
Type
:
"object"
,
Required
:
[]
string
{
"location"
},
Properties
:
map
[
string
]
struct
{
Type
api
.
PropertyType
`json:"type"`
Items
any
`json:"items,omitempty"`
Description
string
`json:"description"`
Enum
[]
any
`json:"enum,omitempty"`
}{
Properties
:
map
[
string
]
api
.
ToolProperty
{
"location"
:
{
Type
:
api
.
PropertyType
{
"string"
},
Description
:
"The city and state, e.g. San Francisco, CA"
,
...
...
@@ -64,21 +54,11 @@ func getTestTools() []api.Tool {
Defs
any
`json:"$defs,omitempty"`
Items
any
`json:"items,omitempty"`
Required
[]
string
`json:"required"`
Properties
map
[
string
]
struct
{
Type
api
.
PropertyType
`json:"type"`
Items
any
`json:"items,omitempty"`
Description
string
`json:"description"`
Enum
[]
any
`json:"enum,omitempty"`
}
`json:"properties"`
Properties
map
[
string
]
api
.
ToolProperty
`json:"properties"`
}{
Type
:
"object"
,
Required
:
[]
string
{
"expression"
},
Properties
:
map
[
string
]
struct
{
Type
api
.
PropertyType
`json:"type"`
Items
any
`json:"items,omitempty"`
Description
string
`json:"description"`
Enum
[]
any
`json:"enum,omitempty"`
}{
Properties
:
map
[
string
]
api
.
ToolProperty
{
"expression"
:
{
Type
:
api
.
PropertyType
{
"string"
},
Description
:
"The mathematical expression to calculate"
,
...
...
template/template.go
View file @
2d06977a
...
...
@@ -127,6 +127,16 @@ var funcs = template.FuncMap{
// Default format is YYYY-MM-DD
return
time
.
Now
()
.
Format
(
"2006-01-02"
)
},
"toTypeScriptType"
:
func
(
v
any
)
string
{
if
param
,
ok
:=
v
.
(
api
.
ToolProperty
);
ok
{
return
param
.
ToTypeScriptType
()
}
// Handle pointer case
if
param
,
ok
:=
v
.
(
*
api
.
ToolProperty
);
ok
&&
param
!=
nil
{
return
param
.
ToTypeScriptType
()
}
return
"any"
},
}
func
Parse
(
s
string
)
(
*
Template
,
error
)
{
...
...
tools/tools_test.go
View file @
2d06977a
...
...
@@ -45,21 +45,11 @@ func TestParser(t *testing.T) {
Defs
any
`json:"$defs,omitempty"`
Items
any
`json:"items,omitempty"`
Required
[]
string
`json:"required"`
Properties
map
[
string
]
struct
{
Type
api
.
PropertyType
`json:"type"`
Items
any
`json:"items,omitempty"`
Description
string
`json:"description"`
Enum
[]
any
`json:"enum,omitempty"`
}
`json:"properties"`
Properties
map
[
string
]
api
.
ToolProperty
`json:"properties"`
}{
Type
:
"object"
,
Required
:
[]
string
{
"city"
},
Properties
:
map
[
string
]
struct
{
Type
api
.
PropertyType
`json:"type"`
Items
any
`json:"items,omitempty"`
Description
string
`json:"description"`
Enum
[]
any
`json:"enum,omitempty"`
}{
Properties
:
map
[
string
]
api
.
ToolProperty
{
"format"
:
{
Type
:
api
.
PropertyType
{
"string"
},
Description
:
"The format to return the temperature in"
,
...
...
@@ -83,20 +73,10 @@ func TestParser(t *testing.T) {
Defs
any
`json:"$defs,omitempty"`
Items
any
`json:"items,omitempty"`
Required
[]
string
`json:"required"`
Properties
map
[
string
]
struct
{
Type
api
.
PropertyType
`json:"type"`
Items
any
`json:"items,omitempty"`
Description
string
`json:"description"`
Enum
[]
any
`json:"enum,omitempty"`
}
`json:"properties"`
Properties
map
[
string
]
api
.
ToolProperty
`json:"properties"`
}{
Type
:
"object"
,
Properties
:
map
[
string
]
struct
{
Type
api
.
PropertyType
`json:"type"`
Items
any
`json:"items,omitempty"`
Description
string
`json:"description"`
Enum
[]
any
`json:"enum,omitempty"`
}{
Properties
:
map
[
string
]
api
.
ToolProperty
{
"location"
:
{
Type
:
api
.
PropertyType
{
"string"
},
Description
:
"The location to get the weather conditions for"
,
...
...
@@ -129,20 +109,10 @@ func TestParser(t *testing.T) {
Defs
any
`json:"$defs,omitempty"`
Items
any
`json:"items,omitempty"`
Required
[]
string
`json:"required"`
Properties
map
[
string
]
struct
{
Type
api
.
PropertyType
`json:"type"`
Items
any
`json:"items,omitempty"`
Description
string
`json:"description"`
Enum
[]
any
`json:"enum,omitempty"`
}
`json:"properties"`
Properties
map
[
string
]
api
.
ToolProperty
`json:"properties"`
}{
Type
:
"object"
,
Properties
:
map
[
string
]
struct
{
Type
api
.
PropertyType
`json:"type"`
Items
any
`json:"items,omitempty"`
Description
string
`json:"description"`
Enum
[]
any
`json:"enum,omitempty"`
}{
Properties
:
map
[
string
]
api
.
ToolProperty
{
"location"
:
{
Type
:
api
.
PropertyType
{
"string"
},
Description
:
"The location to get the address for"
,
...
...
@@ -161,20 +131,10 @@ func TestParser(t *testing.T) {
Defs
any
`json:"$defs,omitempty"`
Items
any
`json:"items,omitempty"`
Required
[]
string
`json:"required"`
Properties
map
[
string
]
struct
{
Type
api
.
PropertyType
`json:"type"`
Items
any
`json:"items,omitempty"`
Description
string
`json:"description"`
Enum
[]
any
`json:"enum,omitempty"`
}
`json:"properties"`
Properties
map
[
string
]
api
.
ToolProperty
`json:"properties"`
}{
Type
:
"object"
,
Properties
:
map
[
string
]
struct
{
Type
api
.
PropertyType
`json:"type"`
Items
any
`json:"items,omitempty"`
Description
string
`json:"description"`
Enum
[]
any
`json:"enum,omitempty"`
}{
Properties
:
map
[
string
]
api
.
ToolProperty
{
"a"
:
{
Type
:
api
.
PropertyType
{
"string"
},
Description
:
"The first number to add"
,
...
...
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