From 4258e92c506642f97bee4dfd2ecbee8e74493978 Mon Sep 17 00:00:00 2001 From: Cameron Date: Wed, 4 Feb 2026 15:27:25 -0800 Subject: [PATCH] fix: auto-reset conversation when stream receives no data (#142) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a conversation has a stuck tool approval from a previous session, the stream receives NO data at all (not even init). This leaves users stuck with "(No response from agent)" and no clear path to recovery. Changes: - Track if stream received ANY data (not just assistant messages) - If stream times out with zero data, assume stuck approval state - Auto-reset conversation and notify user to try again - Add message type counts to "no response" logs for debugging - Fix 'system' -> 'init' type comparison (was causing TS error) This addresses the issue reported by Signo on Discord where responses were going to ADE instead of the channel due to stuck approvals. Related issues: #125, #127, #132 Written by Cameron ◯ Letta Code "When the stream runs dry, dig a new well." - Infrastructure proverb --- package-lock.json | 1 + src/core/bot.ts | 34 +++++++++++++++++++++++++++------- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8f5d5e1..6ceedb4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,6 +33,7 @@ }, "bin": { "lettabot": "dist/cli.js", + "lettabot-channels": "dist/cli/channels.js", "lettabot-message": "dist/cli/message.js", "lettabot-react": "dist/cli/react.js", "lettabot-schedule": "dist/cron/cli.js" diff --git a/src/core/bot.ts b/src/core/bot.ts index cdb4e8d..0a80e97 100644 --- a/src/core/bot.ts +++ b/src/core/bot.ts @@ -287,6 +287,7 @@ export class LettaBot { let lastMsgType: string | null = null; let lastAssistantUuid: string | null = null; let sentAnyMessage = false; + let receivedAnyData = false; // Track if stream received ANY data at all const msgTypeCounts: Record = {}; // Stream watchdog - abort if idle for too long @@ -335,6 +336,7 @@ export class LettaBot { for await (const streamMsg of session.stream()) { const msgUuid = (streamMsg as any).uuid; watchdog.ping(); + receivedAnyData = true; msgTypeCounts[streamMsg.type] = (msgTypeCounts[streamMsg.type] || 0) + 1; // Verbose logging: show every stream message type @@ -361,9 +363,8 @@ export class LettaBot { console.log(`[Bot] Generating response...`); } else if (streamMsg.type === 'reasoning' && lastMsgType !== 'reasoning') { console.log(`[Bot] Reasoning...`); - } else if (streamMsg.type === 'system' && lastMsgType !== 'system') { - const subtype = (streamMsg as any).subtype || 'unknown'; - console.log(`[Bot] System message: ${subtype}`); + } else if (streamMsg.type === 'init' && lastMsgType !== 'init') { + console.log(`[Bot] Session initialized`); } lastMsgType = streamMsg.type; @@ -461,10 +462,29 @@ export class LettaBot { // Only show "no response" if we never sent anything if (!sentAnyMessage) { - console.warn('[Bot] No message sent during stream - sending "(No response from agent)"'); - console.warn('[Bot] This may indicate: tool approval hang, stream error, or ADE session conflict'); - console.warn('[Bot] Check if ADE web interface is open - simultaneous access can cause this issue'); - await adapter.sendMessage({ chatId: msg.chatId, text: '(No response from agent)', threadId: msg.threadId }); + if (!receivedAnyData) { + // Stream received NOTHING - likely stuck approval or connection issue + console.error('[Bot] Stream received NO DATA at all - conversation may be stuck'); + console.error('[Bot] This usually means a pending tool approval from a previous session'); + console.error('[Bot] Auto-resetting conversation to recover...'); + + // Clear conversation ID to force new conversation on next message + const oldConvoId = this.store.conversationId; + this.store.conversationId = null; // Auto-saves via setter + + await adapter.sendMessage({ + chatId: msg.chatId, + text: '(Connection issue detected - conversation reset. Please try again.)', + threadId: msg.threadId + }); + console.log(`[Bot] Conversation reset: ${oldConvoId} -> (new conversation on next message)`); + } else { + console.warn('[Bot] No message sent during stream - sending "(No response from agent)"'); + console.warn('[Bot] Stream DID receive data but no assistant response'); + console.warn('[Bot] Message type counts:', msgTypeCounts); + console.warn('[Bot] Check if ADE web interface is open - simultaneous access can cause this issue'); + await adapter.sendMessage({ chatId: msg.chatId, text: '(No response from agent)', threadId: msg.threadId }); + } } } catch (error) {