From cf47522bf69f0c76a1aa267b236cb4984b20c7d6 Mon Sep 17 00:00:00 2001 From: Cameron Date: Mon, 9 Mar 2026 13:10:40 -0700 Subject: [PATCH] fix: skip non-targeted directives when no source adapter context MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When sendToAgent() has no valid sourceChannel (e.g. webhook/feed triggers), filter directives to only those that carry explicit channel/chat targets. Prevents non-targeted directives (react, voice, untargeted send-file) from executing against an arbitrary first-registered adapter. Written by Cameron ◯ Letta Code "Simplicity is prerequisite for reliability." -- Edsger Dijkstra --- src/core/bot.ts | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/core/bot.ts b/src/core/bot.ts index bca4f07..5d0a9d5 100644 --- a/src/core/bot.ts +++ b/src/core/bot.ts @@ -1922,12 +1922,27 @@ export class LettaBot implements AgentSession { if (response.trim()) { const parsed = parseDirectives(response); if (parsed.directives.length > 0) { - const sourceAdapter = (context?.sourceChannel ? this.channels.get(context.sourceChannel) : undefined) - ?? this.channels.values().next().value; - if (sourceAdapter) { - executedDirectives = await this.executeDirectives( - parsed.directives, sourceAdapter, context?.sourceChatId ?? '', - ); + const sourceAdapter = context?.sourceChannel ? this.channels.get(context.sourceChannel) : undefined; + const sourceChatId = context?.sourceChatId ?? ''; + + // Without a valid source adapter, only explicitly targeted directives can run. + // Non-targeted directives (react, voice, untargeted send-file) need a source + // chat context and must be filtered out to avoid executing against a wrong channel. + const directives = sourceAdapter + ? parsed.directives + : parsed.directives.filter(d => + d.type === 'send-message' || (d.type === 'send-file' && d.channel && d.chat) + ); + + if (directives.length > 0) { + // Targeted directives resolve their own adapter; the fallback here is only + // used by non-targeted directives (which are filtered out when no source). + const adapter = sourceAdapter ?? this.channels.values().next().value; + if (adapter) { + executedDirectives = await this.executeDirectives( + directives, adapter, sourceChatId, + ); + } } response = parsed.cleanText; }