diff --git a/client/src/hooks/Letta/useLettaMessageHandler.ts b/client/src/hooks/Letta/useLettaMessageHandler.ts index f8d84f18..3d08e67e 100644 --- a/client/src/hooks/Letta/useLettaMessageHandler.ts +++ b/client/src/hooks/Letta/useLettaMessageHandler.ts @@ -291,30 +291,48 @@ export default function useLettaMessageHandler({ setLatestMessage?.(streamingAssistantMessage); } else if (isToolCallMessage(chunk)) { // Handle tool call messages - convert to ToolCallContent format - const toolCall = chunk.tool_call; - if (toolCall && 'name' in toolCall && 'arguments' in toolCall) { - // Parse arguments if they're a string - let input: Record = {}; - try { - input = typeof toolCall.arguments === 'string' - ? JSON.parse(toolCall.arguments) - : toolCall.arguments as Record; - } catch (e) { - logger.error('letta', 'Failed to parse tool call arguments:', e); - input = { raw: toolCall.arguments }; + logger.log('letta', 'ToolCallMessage received:', { + hasToolCalls: !!chunk.tool_calls, + hasToolCall: !!chunk.tool_call, + toolCallsType: Array.isArray(chunk.tool_calls) ? 'array' : typeof chunk.tool_calls, + chunk, + }); + + // Check tool_calls (array) first, then fall back to deprecated tool_call + const toolCallsArray = Array.isArray(chunk.tool_calls) ? chunk.tool_calls : []; + const toolCallSingle = chunk.tool_call && 'name' in chunk.tool_call ? chunk.tool_call : null; + + const toolCallsToProcess = toolCallsArray.length > 0 + ? toolCallsArray + : (toolCallSingle ? [toolCallSingle] : []); + + for (const toolCall of toolCallsToProcess) { + if ('name' in toolCall && 'arguments' in toolCall && 'tool_call_id' in toolCall) { + // Parse arguments if they're a string + let input: Record = {}; + try { + input = typeof toolCall.arguments === 'string' + ? JSON.parse(toolCall.arguments) + : toolCall.arguments as Record; + } catch (e) { + logger.error('letta', 'Failed to parse tool call arguments:', e); + input = { raw: toolCall.arguments }; + } + + const toolCallContent: ToolCallContent = { + id: toolCall.tool_call_id, + name: toolCall.name, + input, + type: 'tool_call', + }; + toolCallsMap.set(toolCallContent.id, toolCallContent); + + logger.log('letta', 'Tool call received:', toolCallContent.name); } + } - const toolCallContent: ToolCallContent = { - id: toolCall.tool_call_id, - name: toolCall.name, - input, - type: 'tool_call', - }; - toolCallsMap.set(toolCallContent.id, toolCallContent); - - logger.log('letta', 'Tool call received:', toolCallContent.name); - - // Update UI with the new tool call + // Update UI if we processed any tool calls + if (toolCallsToProcess.length > 0) { const streamingAssistantMessage: TMessage = { ...assistantMessage, text: responseText,