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
65f10c28
Unverified
Commit
65f10c28
authored
May 30, 2025
by
Parth Sareen
Committed by
GitHub
May 30, 2025
Browse files
tools: resiliency upgrade to name and arg extraction from template (#10917)
parent
aaa78180
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
97 additions
and
69 deletions
+97
-69
tools/tools_utils.go
tools/tools_utils.go
+15
-20
tools/tools_utils_test.go
tools/tools_utils_test.go
+82
-49
No files found.
tools/tools_utils.go
View file @
65f10c28
...
@@ -166,31 +166,26 @@ func extractToolArgs(tmpl *gotmpl.Template) (name, arguments string, err error)
...
@@ -166,31 +166,26 @@ func extractToolArgs(tmpl *gotmpl.Template) (name, arguments string, err error)
return
""
,
""
,
err
return
""
,
""
,
err
}
}
var
obj
any
// Extract JSON object between curly braces
err
=
json
.
Unmarshal
(
b
.
Bytes
(),
&
obj
)
// JSON arrays are also valid as they will not be repeated in the template
if
err
!=
nil
{
output
:=
b
.
String
()
return
""
,
""
,
err
start
:=
strings
.
Index
(
output
,
"{"
)
end
:=
strings
.
LastIndex
(
output
,
"}"
)
if
start
==
-
1
||
end
==
-
1
||
start
>
end
{
return
""
,
""
,
errors
.
New
(
"no valid JSON object found in template output"
)
}
}
jsonStr
:=
output
[
start
:
end
+
1
]
var
objs
[]
map
[
string
]
any
var
obj
map
[
string
]
any
switch
v
:=
obj
.
(
type
)
{
if
err
:=
json
.
Unmarshal
([]
byte
(
jsonStr
),
&
obj
);
err
!=
nil
{
case
map
[
string
]
any
:
return
""
,
""
,
err
objs
=
[]
map
[
string
]
any
{
v
}
case
[]
map
[
string
]
any
:
objs
=
v
case
[]
any
:
objs
=
collect
(
v
)
}
if
len
(
objs
)
==
0
{
return
""
,
""
,
errors
.
New
(
"no template objects found"
)
}
}
// find the keys that correspond to the name and arguments fields
// Find name and arguments fields
for
k
,
v
:=
range
objs
[
0
]
{
for
k
,
v
:=
range
obj
{
switch
v
.
(
type
)
{
if
str
,
ok
:=
v
.
(
string
);
ok
&&
str
==
"@@name@@"
{
case
string
:
name
=
k
name
=
k
case
map
[
string
]
any
:
}
else
if
_
,
ok
:=
v
.
(
map
[
string
]
any
);
ok
{
arguments
=
k
arguments
=
k
}
}
}
}
...
...
tools/tools_utils_test.go
View file @
65f10c28
...
@@ -271,74 +271,99 @@ func TestExtractToolArgs(t *testing.T) {
...
@@ -271,74 +271,99 @@ func TestExtractToolArgs(t *testing.T) {
cases
:=
[]
struct
{
cases
:=
[]
struct
{
name
string
name
string
template
string
template
string
want
string
wantName
string
ok
bool
wantArgs
string
wantErr
bool
}{
}{
{
{
name
:
"basic tool call with text after"
,
name
:
"basic tool call"
,
template
:
`{{if .ToolCalls}}tool response{{end}}`
,
template
:
`{{ range .ToolCalls }}
want
:
"tool response"
,
{"name": "{{ .Function.Name }}", "parameters": {{ .Function.Arguments }}}{{ end }}`
,
ok
:
true
,
wantName
:
"name"
,
wantArgs
:
"parameters"
,
wantErr
:
false
,
},
},
{
{
name
:
"tool call with mixed content after"
,
name
:
"tool call with whitespace"
,
template
:
`{{if .ToolCalls}}<tool_call>{{.Something}}{{end}}`
,
template
:
`{{range .ToolCalls}}
want
:
"<tool_call>"
,
{"name": "{{.Function.Name}}", "parameters": {{.Function.Arguments}}}
ok
:
true
,
{{end}}`
,
},
wantName
:
"name"
,
{
wantArgs
:
"parameters"
,
name
:
"tool call with no text after"
,
wantErr
:
false
,
template
:
`{{if .ToolCalls}}{{.Something}}{{end}}`
,
want
:
""
,
ok
:
true
,
},
},
{
{
name
:
"nested tool call"
,
name
:
"tool call with extra content"
,
template
:
`{{if .Something}}{{if .ToolCalls}}[TOOL_CALL]{{end}}{{end}}`
,
template
:
`Before {{range .ToolCalls}}
want
:
"[TOOL_CALL]"
,
{"name": "{{.Function.Name}}", "arguments": {{.Function.Arguments}}}{{end}} After`
,
ok
:
true
,
wantName
:
"name"
,
wantArgs
:
"arguments"
,
wantErr
:
false
,
},
},
{
{
name
:
"no tool calls"
,
name
:
"no tool calls"
,
template
:
`{{if .Something}}no tools here{{end}}`
,
template
:
`{{if .Something}}no tools here{{end}}`
,
want
:
""
,
wantName
:
""
,
ok
:
false
,
wantArgs
:
""
,
wantErr
:
true
,
},
},
{
{
name
:
"empty template"
,
name
:
"empty template"
,
template
:
``
,
template
:
``
,
want
:
""
,
wantName
:
""
,
ok
:
false
,
wantArgs
:
""
,
wantErr
:
true
,
},
},
{
{
name
:
"multiple tool calls sections"
,
name
:
"prefix within tool call"
,
template
:
`{{if .ToolCalls}}first{{end}}{{if .ToolCalls}}second{{end}}`
,
template
:
`{{- if .ToolCalls }}
want
:
"first"
,
{{ range .ToolCalls }}
ok
:
true
,
<tool_call>
{"name": "{{ .Function.Name }}", "arguments": {{ .Function.Arguments }}}
</tool_call>{{ end }}{{- end }}`
,
wantName
:
"name"
,
wantArgs
:
"arguments"
,
wantErr
:
false
,
},
},
{
{
name
:
"range over tool calls"
,
name
:
"JSON array"
,
template
:
`{{if .ToolCalls}}{{range .ToolCalls}}tool{{end}}{{end}}`
,
template
:
`{{ range .ToolCalls }}
want
:
""
,
[{"name": "{{ .Function.Name }}", "arguments": {{ .Function.Arguments }}}]{{ end }}`
,
ok
:
true
,
wantName
:
"name"
,
wantArgs
:
"arguments"
,
wantErr
:
false
,
},
},
{
{
name
:
"tool calls with pipe delimiters"
,
name
:
"invalid JSON"
,
template
:
`{{if .ToolCalls}}<|tool|>{{end}}`
,
template
:
`{{ range .ToolCalls }}
want
:
"<|tool|>"
,
{"name": "{{ .Function.Name }}", "arguments": {{ .Function.Arguments }}, invalid}{{ end }}`
,
ok
:
true
,
wantName
:
""
,
wantArgs
:
""
,
wantErr
:
true
,
},
},
{
{
name
:
"tool calls with nested template"
,
name
:
"missing name field"
,
template
:
`{{if .ToolCalls}}{{template "tool" .}}{{end}}`
,
template
:
`{{ range .ToolCalls }}
want
:
""
,
{"parameters": {{ .Function.Arguments }}}{{ end }}`
,
ok
:
true
,
wantName
:
""
,
wantArgs
:
""
,
wantErr
:
true
,
},
},
{
{
name
:
"tool calls with whitespace variations"
,
name
:
"missing arguments field"
,
template
:
`{{if .ToolCalls}} tool {{end}}`
,
template
:
`{{ range .ToolCalls }}
want
:
" tool "
,
{"name": "{{ .Function.Name }}"}{{ end }}`
,
ok
:
true
,
wantName
:
""
,
wantArgs
:
""
,
wantErr
:
true
,
},
{
name
:
"malformed JSON"
,
template
:
`{{ range .ToolCalls }}
{"name": {{ .Function.Name }}, "arguments": {{ .Function.Arguments }}{{ end }}`
,
wantName
:
""
,
wantArgs
:
""
,
wantErr
:
true
,
},
},
}
}
...
@@ -349,12 +374,20 @@ func TestExtractToolArgs(t *testing.T) {
...
@@ -349,12 +374,20 @@ func TestExtractToolArgs(t *testing.T) {
t
.
Fatalf
(
"failed to parse template: %v"
,
err
)
t
.
Fatalf
(
"failed to parse template: %v"
,
err
)
}
}
got
,
ok
:=
extractToolCallsFormat
(
tmpl
)
gotName
,
gotArgs
,
err
:=
extractToolArgs
(
tmpl
)
if
got
!=
tt
.
want
{
if
(
err
!=
nil
)
!=
tt
.
wantErr
{
t
.
Errorf
(
"TextAfterToolCalls() got = %q, want %q"
,
got
,
tt
.
want
)
t
.
Errorf
(
"extractToolArgs() error = %v, wantErr %v"
,
err
,
tt
.
wantErr
)
return
}
if
err
!=
nil
{
return
}
if
gotName
!=
tt
.
wantName
{
t
.
Errorf
(
"extractToolArgs() gotName = %q, want %q"
,
gotName
,
tt
.
wantName
)
}
}
if
ok
!=
tt
.
ok
{
if
gotArgs
!=
tt
.
wantArgs
{
t
.
Errorf
(
"
T
ext
AfterToolCalls() ok
= %
v
, want %
v
"
,
ok
,
tt
.
ok
)
t
.
Errorf
(
"ext
ractToolArgs() gotArgs
= %
q
, want %
q
"
,
gotArgs
,
tt
.
wantArgs
)
}
}
})
})
}
}
...
...
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