diff --git a/pkg/agent/loop.go b/pkg/agent/loop.go index b36f4a0c4..9a66c6cd1 100644 --- a/pkg/agent/loop.go +++ b/pkg/agent/loop.go @@ -635,9 +635,10 @@ func (al *AgentLoop) runLLMIteration( } assistantMsg.ToolCalls = append(assistantMsg.ToolCalls, providers.ToolCall{ - ID: tc.ID, - Type: "function", - Name: tc.Name, + ID: tc.ID, + Type: "function", + Name: tc.Name, + Arguments: tc.Arguments, Function: &providers.FunctionCall{ Name: tc.Name, Arguments: string(argumentsJSON), diff --git a/pkg/providers/anthropic/provider.go b/pkg/providers/anthropic/provider.go index b23236869..39e523ba4 100644 --- a/pkg/providers/anthropic/provider.go +++ b/pkg/providers/anthropic/provider.go @@ -146,7 +146,20 @@ func buildParams( blocks = append(blocks, anthropic.NewTextBlock(msg.Content)) } for _, tc := range msg.ToolCalls { - blocks = append(blocks, anthropic.NewToolUseBlock(tc.ID, tc.Arguments, tc.Name)) + input := tc.Arguments + if input == nil { + // Recover from nil Arguments (e.g. loaded from older sessions) + if tc.Function != nil && tc.Function.Arguments != "" { + var parsed map[string]interface{} + if err := json.Unmarshal([]byte(tc.Function.Arguments), &parsed); err == nil { + input = parsed + } + } + if input == nil { + input = map[string]interface{}{} + } + } + blocks = append(blocks, anthropic.NewToolUseBlock(tc.ID, input, tc.Name)) } anthropicMessages = append(anthropicMessages, anthropic.NewAssistantMessage(blocks...)) } else { diff --git a/pkg/session/manager.go b/pkg/session/manager.go index 08f0b0ad2..09e494bfd 100644 --- a/pkg/session/manager.go +++ b/pkg/session/manager.go @@ -259,6 +259,14 @@ func (sm *SessionManager) loadSessions() error { continue } + // Normalize tool calls to ensure Arguments map is populated + // from Function.Arguments for sessions saved before this fix. + for i, msg := range session.Messages { + for j, tc := range msg.ToolCalls { + session.Messages[i].ToolCalls[j] = providers.NormalizeToolCall(tc) + } + } + sm.sessions[session.Key] = &session }