Repository navigation
Non-conversational marker wakes can still pin a turn's speech locus (batched-wake path) #189
Description
A non-conversational marker (chat:edited, chat:deleted, chat:reaction-remove) that arrives as a channel incoming message can still choose the channel for the agent's next turn's speech.
- A channel incoming message with
triggerInferencequeues a wake that carrieschannelId, whatever its tags:agent-framework/src/framework.ts
Lines 6834 to 6848 in 59a2a02
for (const agentName of targetAgents) { if (!this.agents.has(agentName)) continue; this.pendingRequests.push({ agentName, reason: 'mcpl:channel-incoming', source: event.serverId, timestamp: Date.now(), // Route this turn's auto-published speech back to THIS channel, not // the global most-recent-inbound locus (item-3 redux, trunk agents). channelId: event.channelId, counterparty: event.author?.id ? `${event.serverId}:user:${event.author.id}` : undefined, // Addressed messages outrank ambient chatter when a batched wake // picks the turn's frozen speech locus. addressed, }); - When several wakes are batched, the channel of the most recent channel-bearing request wins unless an addressed message is present:
agent-framework/src/framework.ts
Lines 7558 to 7565 in 59a2a02
let ambientReq: InferenceRequest | undefined; let addressedReq: InferenceRequest | undefined; for (const r of requests) { if (!r.channelId) continue; ambientReq = r; if (r.addressed) addressedReq = r; } const channelReq = addressedReq ?? ambientReq; - That channel becomes
activeTriggerChannelsand the frozen turn locus, whichrouteSpeechuses beforedefaultPublishChannel.
Repro shape: the agent is busy. An ambient message arrives on chanA, then a later edit marker arrives on chanB. The wake policy wakes on everything in chanB. zulip_mcp documents this setup: "a policy that wakes on everything in the channel wakes on them too". The next turn's reply to chanA is published in chanB.
Relation to #157 / #168: #168 stops markers from moving defaultPublishChannel, but this batched-wake path is separate and #168 doesn't cover it. Its changelog line ("a marker can no longer retarget outbound speech") overclaims until this is fixed too.
Suggested direction: leave channelId off the queued request when hasNonConversationalTag(event.tags) (from #168). The batch-selection comment already assumes this for reactions ("reactions — which never carry channelId").
Activity
fix(changelog), test: narrow the marker claim to what holds, and pin …
docs, test: say what holds for markers, and pin re-pin, the open repa…