Fix tool loop handling and count tokens endpoint
This commit is contained in:
@@ -283,10 +283,11 @@ func ActionOutputPrompt(toolCallID string, output string) string {
|
||||
if output == "" {
|
||||
return ""
|
||||
}
|
||||
next := "Based on the tool result above, answer the user's request directly if you have enough information. Only use another structured action block if a specific missing fact still requires another tool call."
|
||||
if id := strings.TrimSpace(toolCallID); id != "" {
|
||||
return "Tool result for " + id + ":\n" + output + "\n\nBased on the tool result above, continue with the next appropriate action using the structured format."
|
||||
return "Tool result for " + id + ":\n" + output + "\n\n" + next
|
||||
}
|
||||
return "Tool result:\n" + output + "\n\nBased on the tool result above, continue with the next appropriate action using the structured format."
|
||||
return "Tool result:\n" + output + "\n\n" + next
|
||||
}
|
||||
|
||||
func ActionBlockExample(tools []ToolDef) string {
|
||||
@@ -629,6 +630,9 @@ func ParseActionBlocks(text string, tools []ToolDef, cfg Config) ([]ToolCall, st
|
||||
// Filter arguments against the tool's input schema to strip unknown params
|
||||
if schema, ok := toolSchemaMap[call.Name]; ok && len(schema) > 0 {
|
||||
call.Arguments = filterArgsBySchema(call.Arguments, schema)
|
||||
if !hasRequiredArgs(call.Arguments, schema) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
calls = append(calls, call)
|
||||
spans = append(spans, span{start: start, end: end + 3})
|
||||
@@ -1011,6 +1015,19 @@ func filterArgsBySchema(args map[string]any, schema map[string]any) map[string]a
|
||||
return out
|
||||
}
|
||||
|
||||
func hasRequiredArgs(args map[string]any, schema map[string]any) bool {
|
||||
for _, key := range requiredKeys(schema) {
|
||||
value, ok := args[key]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if s, ok := value.(string); ok && strings.TrimSpace(s) == "" {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func cloneMap(src map[string]any) map[string]any {
|
||||
if src == nil {
|
||||
return nil
|
||||
|
||||
@@ -154,3 +154,25 @@ func TestParseActionBlocksMapsReadAlias(t *testing.T) {
|
||||
t.Fatalf("calls = %+v", calls)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseActionBlocksDropsCallsMissingRequiredArgs(t *testing.T) {
|
||||
text := "```json action\n{\"tool\":\"Read\",\"parameters\":{\"path\":\"/tmp/a.txt\"}}\n```"
|
||||
calls, clean, err := ParseActionBlocks(text, []ToolDef{{
|
||||
Name: "Read",
|
||||
InputSchema: map[string]any{
|
||||
"properties": map[string]any{
|
||||
"file_path": map[string]any{"type": "string"},
|
||||
},
|
||||
"required": []any{"file_path"},
|
||||
},
|
||||
}}, Config{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(calls) != 0 {
|
||||
t.Fatalf("expected no calls, got %+v", calls)
|
||||
}
|
||||
if !strings.Contains(clean, "\"path\"") {
|
||||
t.Fatalf("clean should preserve unparseable action block, got %q", clean)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user