package providers import ( "encoding/json" "strings" ) // extractToolCallsFromText parses tool call JSON from response text. // Both ClaudeCliProvider and CodexCliProvider use this to extract // tool calls that the model outputs in its response text. func extractToolCallsFromText(text string) []ToolCall { start := strings.Index(text, `{"tool_calls"`) if start == -1 { return nil } end := findMatchingBrace(text, start) if end == start { return nil } jsonStr := text[start:end] var wrapper struct { ToolCalls []struct { ID string `json:"id"` Type string `json:"type"` Function struct { Name string `json:"name"` Arguments string `json:"arguments"` } `json:"function"` } `json:"tool_calls"` } if err := json.Unmarshal([]byte(jsonStr), &wrapper); err != nil { return nil } var result []ToolCall for _, tc := range wrapper.ToolCalls { var args map[string]interface{} json.Unmarshal([]byte(tc.Function.Arguments), &args) result = append(result, ToolCall{ ID: tc.ID, Type: tc.Type, Name: tc.Function.Name, Arguments: args, Function: &FunctionCall{ Name: tc.Function.Name, Arguments: tc.Function.Arguments, }, }) } return result } // stripToolCallsFromText removes tool call JSON from response text. func stripToolCallsFromText(text string) string { start := strings.Index(text, `{"tool_calls"`) if start == -1 { return text } end := findMatchingBrace(text, start) if end == start { return text } return strings.TrimSpace(text[:start] + text[end:]) }