A React Native app for the ultimate thinking partner.

Centralize tool call formatting to Python-style in one place

Created formatToolCall utility used by both:
- lettaApi.ts (historical messages from server)
- useMessageStream.ts (streaming messages)

Now formats consistently as: web_search(query="poetry", num_results=10)
Instead of: web_search({"query":"poetry","num_results":10})

Simplified extractToolArgument - no more JSON extraction, just regex.

🐾 Generated with [Letta Code](https://letta.com)

Co-Authored-By: Letta <noreply@letta.com>

Changed files
+38 -34
src
+2 -1
src/api/lettaApi.ts
··· 617 618 // CONSTRUCT content for tool call messages (if content is empty) 619 if ((type === 'tool_call_message' || type === 'tool_call') && !content && toolCall) { 620 const name = toolCall.name || 'tool'; 621 const args = toolCall.arguments || '{}'; 622 - content = `${name}(${args})`; 623 } 624 625 // EXTRACT content for tool return messages (if content is empty)
··· 617 618 // CONSTRUCT content for tool call messages (if content is empty) 619 if ((type === 'tool_call_message' || type === 'tool_call') && !content && toolCall) { 620 + const { formatToolCall } = require('../utils/formatToolCall'); 621 const name = toolCall.name || 'tool'; 622 const args = toolCall.arguments || '{}'; 623 + content = formatToolCall(name, args); 624 } 625 626 // EXTRACT content for tool return messages (if content is empty)
+2 -10
src/hooks/useMessageStream.ts
··· 200 // Format tool call content as Python-style string (like server does) 201 let content = msg.content; 202 if (msg.type === 'tool_call' && msg.toolCallName) { 203 - try { 204 - const argsObj = JSON.parse(msg.content); 205 - const formattedArgs = Object.entries(argsObj) 206 - .map(([k, v]) => `${k}=${typeof v === 'string' ? `"${v}"` : JSON.stringify(v)}`) 207 - .join(', '); 208 - content = `${msg.toolCallName}(${formattedArgs})`; 209 - } catch (e) { 210 - // If parse fails, keep original content 211 - content = msg.content; 212 - } 213 } 214 215 return {
··· 200 // Format tool call content as Python-style string (like server does) 201 let content = msg.content; 202 if (msg.type === 'tool_call' && msg.toolCallName) { 203 + const { formatToolCall } = require('../utils/formatToolCall'); 204 + content = formatToolCall(msg.toolCallName, msg.content); 205 } 206 207 return {
+32
src/utils/formatToolCall.ts
···
··· 1 + /** 2 + * Format tool call arguments as Python-style string 3 + * 4 + * Input: { query: "poetry", num_results: 10 } 5 + * Output: query="poetry", num_results=10 6 + */ 7 + export function formatToolArgs(args: any): string { 8 + if (!args || typeof args !== 'object') { 9 + return ''; 10 + } 11 + 12 + return Object.entries(args) 13 + .map(([k, v]) => `${k}=${typeof v === 'string' ? `"${v}"` : JSON.stringify(v)}`) 14 + .join(', '); 15 + } 16 + 17 + /** 18 + * Format tool call as Python-style function call 19 + * 20 + * Input: name="web_search", arguments='{"query":"poetry","num_results":10}' 21 + * Output: web_search(query="poetry", num_results=10) 22 + */ 23 + export function formatToolCall(name: string, argumentsJson: string): string { 24 + try { 25 + const argsObj = JSON.parse(argumentsJson); 26 + const formattedArgs = formatToolArgs(argsObj); 27 + return `${name}(${formattedArgs})`; 28 + } catch (e) { 29 + // If JSON parse fails, wrap the raw string in parens 30 + return `${name}(${argumentsJson})`; 31 + } 32 + }
+2 -23
src/utils/messageLabels.ts
··· 14 15 /** 16 * Extract a specific argument from tool call arguments 17 - * Handles multiple formats: Python string, JSON string, JSON-in-parens 18 */ 19 function extractToolArgument(group: MessageGroup, argName: string): string | null { 20 const argsStr = group.toolCall?.args || group.content || ''; 21 22 - // Try to parse as JSON first (pure JSON string) 23 - if (argsStr.startsWith('{')) { 24 - try { 25 - const argsObj = JSON.parse(argsStr); 26 - return argsObj[argName] || null; 27 - } catch (e) { 28 - // Not valid JSON, continue 29 - } 30 - } 31 - 32 - // Try to extract JSON from inside parens: tool_name({"key": "value"}) 33 - const jsonMatch = argsStr.match(/\((\{.+\})\)/); 34 - if (jsonMatch) { 35 - try { 36 - const argsObj = JSON.parse(jsonMatch[1]); 37 - return argsObj[argName] || null; 38 - } catch (e) { 39 - // Not valid JSON, continue 40 - } 41 - } 42 - 43 - // Try to extract from Python-style string: tool(arg="value", ...) 44 const regex = new RegExp(`${argName}=["']([^"']+)["']`); 45 const match = argsStr.match(regex); 46 if (match) {
··· 14 15 /** 16 * Extract a specific argument from tool call arguments 17 + * Expects Python-style format: tool(query="value", num=10) 18 */ 19 function extractToolArgument(group: MessageGroup, argName: string): string | null { 20 const argsStr = group.toolCall?.args || group.content || ''; 21 22 + // Extract from Python-style string: tool(arg="value", ...) 23 const regex = new RegExp(`${argName}=["']([^"']+)["']`); 24 const match = argsStr.match(regex); 25 if (match) {