feat(mcpl): transport-declared context-only messages (suppressWake) - #180
ian-de-marcellus wants to merge 3 commits into
Conversation
A transport can mark an incoming message or push event as context-only with metadata/origin suppressWake: true. It is checked before the optional inference gate, so a permissive gate cannot turn it into a wake. discord-mcpl uses it for continuation chunks and for non-tail messages of a batched room. Ported from local uncommitted work onto current main. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…e gate Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
| let triggerInference = message.metadata?.suppressWake !== true; | ||
| if (triggerInference && this.shouldTriggerInference) { |
There was a problem hiding this comment.
Module wakes bypass suppression When a module requests inference for a context-only channel message, this check sets
triggerInference to false, but the framework still dispatches the event to the module and queues its wake request without checking that flag. The same applies to suppressed push events. The agent can therefore wake despite the transport's context-only hint.
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/mcpl/channel-registry.ts
Line: 888-889
Comment:
**Module wakes bypass suppression** When a module requests inference for a context-only channel message, this check sets `triggerInference` to false, but the framework still dispatches the event to the module and queues its wake request without checking that flag. The same applies to suppressed push events. The agent can therefore wake despite the transport's context-only hint.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.| if (this.shouldTriggerInference) { | ||
| // Same context-only contract as channels/incoming: a transport may mark | ||
| // an event (e.g. a continuation chunk) as context-only. | ||
| let triggerInference = params.origin?.suppressWake !== true; |
There was a problem hiding this comment.
Suppressed events receive inference IDs When
origin.suppressWake is true, this code disables inference, but the push handler still returns an inferenceId in its success response. The response contract says that field is present only when inference was triggered, so the transport receives an identifier for a turn that will not occur.
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/mcpl/push-handler.ts
Line: 239
Comment:
**Suppressed events receive inference IDs** When `origin.suppressWake` is true, this code disables inference, but the push handler still returns an `inferenceId` in its success response. The response contract says that field is present only when inference was triggered, so the transport receives an identifier for a turn that will not occur.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.
Problem
In a large setup the EventGate is the right place to decide what wakes a resident. Residents see many channels, get woken by DMs and pings, and read the rest at their leisure.
Small setups work differently. A resident that lives in a handful of channels naturally runs a gate that wakes on essentially every message (or on custom rules for one busy room). There, the transport often knows something the gate can't: a message isn't a turn. For example:
Upstream's answer today is a gate rule on a tag. That needs every small setup to write matching rules, and because policies are first-match-wins, a permissive rule placed earlier ("wake on anything addressed") silently wins over the "don't wake on continuations" rule.
Fix
A transport can declare a message context-only:
channels/incoming:metadata.suppressWake: trueorigin.suppressWake: trueIt is stored and routed exactly as before but never triggers inference. The check runs before the optional gate, so gate rule order can't undo it. It only ever removes a wake: transports that never set it, and large setups whose gates already skip ambient traffic, are unaffected.
Tests
test/mcpl-gate-roundtrip.test.ts:suppressWakeis stored withtriggerInference: false, and the flag stays in its metadata.Full suite: 957 pass, 0 fail (4 skipped). Changelog fragment included.
In production on a small five-resident setup for continuation chunks and batched rooms; discord-mcpl #38 emits the hint for replays.
🤖 Generated with Claude Code