A React Native app for the ultimate thinking partner.
at main 187 lines 7.3 kB view raw
1const { LettaClient } = require('@letta-ai/letta-client'); 2 3// Get token and optional agent ID from command line or environment 4const token = process.env.LETTA_API_KEY; 5const agentId = process.argv[2]; 6 7if (!token) { 8 console.error('ERROR: No LETTA_API_KEY environment variable set'); 9 console.error('Usage: LETTA_API_KEY=<token> node analyze_message_grouping.js [agent-id]'); 10 process.exit(1); 11} 12 13const client = new LettaClient({ token }); 14 15(async () => { 16 try { 17 // If no agent ID provided, list available agents 18 if (!agentId) { 19 console.log('No agent ID provided. Listing available agents...\n'); 20 const agents = await client.agents.list(); 21 console.log(`Found ${agents.length} agents:\n`); 22 agents.forEach((agent, idx) => { 23 console.log(`[${idx + 1}] ${agent.name || 'Unnamed'}`); 24 console.log(` ID: ${agent.id}`); 25 console.log(` Created: ${agent.created_at}`); 26 console.log(''); 27 }); 28 console.log('Usage: node analyze_message_grouping.js <agent-id>'); 29 process.exit(0); 30 } 31 32 console.log(`Fetching messages from agent ${agentId}...\n`); 33 34 const messages = await client.agents.messages.list(agentId, { 35 limit: 200, 36 use_assistant_message: true, 37 }); 38 39 console.log(`\n========================================`); 40 console.log(`LOADED ${messages.length} MESSAGES`); 41 console.log(`========================================\n`); 42 43 // Sort chronologically 44 const sorted = [...messages].sort((a, b) => { 45 const timeA = new Date(a.date || 0).getTime(); 46 const timeB = new Date(b.date || 0).getTime(); 47 return timeA - timeB; 48 }); 49 50 // Print all messages with grouping info 51 console.log('ALL MESSAGES (CHRONOLOGICAL):\n'); 52 sorted.forEach((msg, idx) => { 53 console.log(`[${idx}]`); 54 console.log(` ID: ${msg.id}`); 55 console.log(` Type: ${msg.messageType}`); 56 console.log(` Step ID: ${msg.stepId || 'none'}`); 57 console.log(` Created: ${msg.date}`); 58 59 if (msg.messageType === 'reasoning_message') { 60 console.log(` Reasoning: ${msg.reasoning?.substring(0, 80) || 'none'}...`); 61 } else if (msg.messageType === 'assistant_message') { 62 console.log(` Content: ${msg.content?.substring(0, 80) || 'none'}...`); 63 } else if (msg.messageType === 'tool_call_message') { 64 console.log(` Tool: ${msg.content?.substring(0, 80) || 'none'}...`); 65 } else if (msg.messageType === 'tool_return_message') { 66 console.log(` Return: ${msg.content?.substring(0, 80) || 'none'}...`); 67 } else if (msg.messageType === 'user_message') { 68 const contentStr = typeof msg.content === 'string' 69 ? msg.content 70 : JSON.stringify(msg.content).substring(0, 80); 71 console.log(` Content: ${contentStr}...`); 72 } 73 console.log(''); 74 }); 75 76 // Group by ID and analyze 77 console.log('\n========================================'); 78 console.log('GROUPING ANALYSIS (by message ID)'); 79 console.log('========================================\n'); 80 81 const groupedById = new Map(); 82 for (const msg of sorted) { 83 if (!groupedById.has(msg.id)) { 84 groupedById.set(msg.id, []); 85 } 86 groupedById.get(msg.id).push(msg); 87 } 88 89 // Find groups with multiple messages 90 const multiMessageGroups = Array.from(groupedById.entries()) 91 .filter(([id, msgs]) => msgs.length > 1); 92 93 console.log(`Found ${multiMessageGroups.length} groups with multiple messages sharing same ID:\n`); 94 95 multiMessageGroups.forEach(([id, msgs], idx) => { 96 console.log(`\nGROUP ${idx + 1}: ID=${id}`); 97 console.log(` Contains ${msgs.length} messages:`); 98 msgs.forEach((msg, i) => { 99 console.log(` [${i}] ${msg.messageType} (step: ${msg.stepId?.substring(0, 16) || 'none'}...)`); 100 if (msg.messageType === 'reasoning_message') { 101 console.log(` Reasoning: "${msg.reasoning?.substring(0, 60)}..."`); 102 } 103 }); 104 }); 105 106 // Group by step_id and analyze 107 console.log('\n\n========================================'); 108 console.log('GROUPING ANALYSIS (by step_id)'); 109 console.log('========================================\n'); 110 111 const groupedByStep = new Map(); 112 for (const msg of sorted) { 113 if (msg.stepId) { 114 if (!groupedByStep.has(msg.stepId)) { 115 groupedByStep.set(msg.stepId, []); 116 } 117 groupedByStep.get(msg.stepId).push(msg); 118 } 119 } 120 121 console.log(`Found ${groupedByStep.size} unique step IDs:\n`); 122 123 // Show a few examples of step groupings 124 let stepCount = 0; 125 for (const [stepId, msgs] of groupedByStep.entries()) { 126 if (stepCount++ > 10) break; // Only show first 10 127 128 console.log(`\nSTEP: ${stepId}`); 129 console.log(` Contains ${msgs.length} messages with ${new Set(msgs.map(m => m.id)).size} unique IDs:`); 130 msgs.forEach((msg, i) => { 131 console.log(` [${i}] ${msg.messageType} (id: ${msg.id.substring(0, 16)}...)`); 132 if (msg.messageType === 'reasoning_message') { 133 console.log(` Reasoning: "${msg.reasoning?.substring(0, 60)}..."`); 134 } 135 }); 136 } 137 138 // Analyze reasoning accumulation pattern 139 console.log('\n\n========================================'); 140 console.log('REASONING ACCUMULATION PATTERNS'); 141 console.log('========================================\n'); 142 143 // Find messages where reasoning appears multiple times with same ID 144 const reasoningGroups = multiMessageGroups.filter(([id, msgs]) => 145 msgs.filter(m => m.messageType === 'reasoning_message').length > 1 146 ); 147 148 console.log(`Found ${reasoningGroups.length} groups with MULTIPLE reasoning messages:\n`); 149 150 reasoningGroups.forEach(([id, msgs], idx) => { 151 const reasoningMsgs = msgs.filter(m => m.messageType === 'reasoning_message'); 152 const assistantMsg = msgs.find(m => m.messageType === 'assistant_message'); 153 const toolCallMsg = msgs.find(m => m.messageType === 'tool_call_message'); 154 155 console.log(`\nMULTI-REASONING GROUP ${idx + 1}: ID=${id.substring(0, 16)}...`); 156 console.log(` Message composition:`); 157 msgs.forEach((msg, i) => { 158 console.log(` [${i}] ${msg.messageType}`); 159 }); 160 161 console.log(`\n Reasoning messages (${reasoningMsgs.length} total):`); 162 reasoningMsgs.forEach((msg, i) => { 163 console.log(` [${i}] "${msg.reasoning?.substring(0, 100)}..."`); 164 }); 165 166 if (assistantMsg) { 167 console.log(`\n Assistant message: "${assistantMsg.content?.substring(0, 100)}..."`); 168 } 169 if (toolCallMsg) { 170 console.log(`\n Tool call: "${toolCallMsg.content?.substring(0, 100)}..."`); 171 } 172 173 console.log(`\n RECOMMENDATION:`); 174 if (toolCallMsg && reasoningMsgs.length > 1) { 175 console.log(` → Use LAST reasoning for tool call`); 176 console.log(` → Reasoning [${reasoningMsgs.length - 1}]: "${reasoningMsgs[reasoningMsgs.length - 1].reasoning?.substring(0, 60)}..."`); 177 } else if (assistantMsg) { 178 console.log(` → Use FIRST reasoning for assistant`); 179 console.log(` → Reasoning [0]: "${reasoningMsgs[0].reasoning?.substring(0, 60)}..."`); 180 } 181 }); 182 183 } catch (e) { 184 console.error('Error:', e.message); 185 console.error('Full error:', e); 186 } 187})();