Skip to content

fix(gate): keep notices out of a batch's route; name its channels - #948

Open
nissa-seru wants to merge 1 commit into
anima-research:mainfrom
nissa-seru:effie/debounce-notices
Open

nissa-seru wants to merge 1 commit into
anima-research:mainfrom
nissa-seru:effie/debounce-notices

Conversation

@nissa-seru

Copy link
Copy Markdown
Contributor

In a debounced gate batch, a chat:system notice no longer decides the batch's route, its addressed flag or the channel its wake names. When no message of a batch addressed the agent, the notice the agent gets for a reply that had no channel now names the channels the batch came from and says to send explicitly, where it said the turn came from no channel.

At a64cfc010f, a batch of a mention in one channel and a newer pin in a DM took the pin's DM as its route, not the mention's channel. 0.28.0's changelog says no notice decides where an agent's plain speech goes, even one addressed by its place. And a reply to a batch that addressed no one was told it "came from no channel" and to ask whoever runs the host, though the batch's messages came from channels and nothing is misconfigured. The six test files this change touches pass at this head, 281 tests, and with a64cfc010f's versions of the four source files it touches, 19 of them fail (see Tests). This change doesn't route such a batch: #945 proposes that separately, since it would change a rule agent-framework publishes.

@antra-tess, we're asking you to review this before it's merged, since it changes what an agent reads: the [send-undeliverable] notice it gets when its reply to a debounced batch that didn't address it went nowhere, and which message of a batch decides where its reply goes.

Problem

At a64cfc010f, in this change's tests run with a64cfc010f's versions of the four source files it touches (see Tests):

  • A notice deciding a batch's route. wakeProvenance takes the batch's newest addressed event as its route, counting chat:system notices. In test/event-gate.test.ts, a batch of a mention in discord:g:room and a newer pin in discord:dm:5, which is tagged as addressing the agent, got the route discord:dm:5, not the mention's channel. In test/chat-system-notices.test.ts, a notice the gate batched stamped its turn's wakeChannelId as world:commons, where the same notice woken directly stamps none. 0.28.0's changelog says a chat:system notice "no longer decides where an agent's plain speech goes … This holds when the notice is also addressed by its place (a pin in a DM)" (CHANGELOG.md:2072–2083).

  • A notice that's false for a batch. A batch in which no message addressed the agent sets no route, and under the default speech.locus: 'delivery' its turn had no channel in these tests. In test/batched-wake-locus.test.ts, a reply to such a batch from one channel, and from two, got:

    [send-undeliverable] Your previous reply (10 chars) had no channel to go to — this turn came from no channel, and it had no home or recent channel to reply in; if it should have had one, ask whoever runs this host. This is a routing/configuration situation, not a channel failure. This route delivered it nowhere; if another surface showed it (a reply thread, the console), that copy stands. It is saved in your archive.

    The batch's messages did come from channels.

Changes

  • Notices take no part in a batch's choice (wakeProvenance, src/gate/event-gate.ts). A chat:system notice decides neither the batch's route, nor its addressed flag, nor the channel its wake names, even when it's addressed by its place. A batch of notices alone carries only the author of its newest notice that has one, as the same notice woken directly does. wakeProvenance's doc names the exception.
  • A batch that addressed no one names its channels. When no message of a batch addressed the agent, the new WakeProvenance.batchChannels lists the registered channels its messages came from, those the host resolved, keyed on server and id, each once in the order they first appear. A push the host can't place is passed over, and a notice names no channel. The framework carries them on the wake as the new InferenceRequest.wakeChannels, and a turn merged from several such wakes names each channel once, unless a request in the merge names a channel.
  • The notice (src/mcpl/channel-registry.ts, src/framework.ts). When such a turn routes its plain speech, or a sleep's announcement, with no channel to go to, the reason names those channels as the agent is shown them, says what came from them didn't address the agent and that no channel was chosen, and says to send its reply to that channel, or one of them, explicitly. The notice calls it "a routing situation", where every other no-channel notice keeps "routing/configuration". It holds under prose routing by locus and by hybrid. The reason lists every channel it's given, with no limit on how many. For three or more, src/mcpl/channel-registry.ts:6177 at this head joins them as "#a, #b and #c". Only one channel and two ran here. The logged line keeps "no locus", which connectome-host's scripts/connectome-doctor looks for (:311 at anima-research/connectome-host@82cbab99).
  • Unchanged: a batch with an addressed message routes as before. A batch that addressed no one still sets no route and keeps the shared fallback, and the notice is written only when that gives no channel.
  • Also: wakeProvenance's fallback time is a reduce rather than a spread into Math.max, so a very large batch can't overflow the call.
  • Types. WakeProvenance.batchChannels and InferenceRequest.wakeChannels are new optional fields of exported types.
  • Tests: in test/batched-wake-locus.test.ts, test/event-gate.test.ts, test/chat-system-notices.test.ts, test/turn-trigger-provenance.test.ts, test/channel-registry-routing.test.ts and test/route-failure-targeting.test.ts, as the Tests section lists.

With other open pull requests

At 21:42 UTC on October 30, this change merges with main at a64cfc010f without conflicts, by git merge-tree. Of the 50 open pull requests, 40 change a file that this change changes, each by its diff from its merge base with main. Each was merged by git merge-tree with main, and with this change merged into it, and the conflict blocks in each file were counted.

Tests

Each run below was part of one invocation on Linux, in a clean checkout of 1e86b9ab1b, this head, with Node 24.22.2 and npm 11.19.1. npm install gave TypeScript 7.0.2, @animalabs/context-manager 0.24.2, @animalabs/mcpl-core 0.4.0, @animalabs/membrane 0.8.0, @animalabs/chronicle 0.5.1, @modelcontextprotocol/client and @modelcontextprotocol/server 2.4.0, discord.js 14.27.0, ws 8.22.0, chokidar 4.0.3 and @babel/parser 7.29.12.

  • At this head. tsc --noEmit and the build succeed, and the six test files pass: 281 tests, none failing or cancelled, run with --test-force-exit, the flag npm test uses.

  • Red first, with a64cfc010f's src/framework.ts, src/gate/event-gate.ts, src/mcpl/channel-registry.ts and src/types/agent.ts in place of this change's. The build reported 8 type errors, each where a test uses batchChannels, wakeChannels or routeSpeech's new argument, and still wrote the output the tests ran from. 19 tests fail:

    • batched-wake-locus: 6 of 12, each a test of the notice: batches of one, two and three messages from one channel or two, under prose routing by locus and by hybrid, and a sleep's announcement. Each failure shows the old "came from no channel" notice.
    • event-gate: 8 of 71: the pin in a DM beside a mention; a notice's channel; the channels of a batch that addressed no one, of pushes that name only their registered channel, and of one channel id on two servers; a push the host can't place, passed over; a newer ambient push that names only its route, not hiding an earlier event's channel and author; and a batch too large to spread into one call.
    • turn-trigger-provenance: 3 of 11: a turn merged from several such wakes, one merged with a wake that names a channel, and a gate wake naming a channel another conversation fork calls home.
    • chat-system-notices: 1 of 9, the batched notice's stamp.
    • channel-registry-routing: 1 of 78, the reason's words and the log line.
    • route-failure-targeting: none of its 100 fail, since a turn with no channel at all keeps "routing/configuration".
  • The notice. At this head, a copy of test/batched-wake-locus.test.ts with one console.log added printed the notice its tests get. For one channel, from batches of one message and of two:

    [send-undeliverable] Your previous reply (10 chars) had no channel to go to — this turn came from #room (discord:g1:room), and what came from there didn't address you, and no channel was chosen for its reply; to reply there, send your reply to that channel explicitly. This is a routing situation, not a channel failure. This route delivered it nowhere; if another surface showed it (a reply thread, the console), that copy stands. It is saved in your archive.

    For two channels, from batches of two messages and of three: "… this turn came from #room (discord:g1:room) and #general (discord:g1:general), and what came from those didn't address you, and no channel was chosen for its reply; to reply in one of them, send your reply to that channel explicitly. This is a routing situation, not a channel failure. …"

Not verified

  • The whole suite. The runs above cover the six test files this change touches. CI runs the rest.
  • A batch none of whose channels the host resolved. By changelog.d/gate-batch-channels.changed.md, it keeps the old notice. No test runs it: the one test of a push the host can't place batches it beside a message whose channel resolves.
  • A real chat server. The tests use the framework's stand-in MCPL server and a stand-in provider (MockMembrane). Nothing ran against Discord.
  • Two merges the notice's words don't fit, which no test covers:
    • a turn merged from such a batch's wake and an addressed batch's wake from a channel another conversation fork calls home, whose route this agent couldn't take, where "what came from there didn't address you" would be false;
    • a turn merged with an addressed push the host couldn't place, where "a routing situation" could hide a misconfiguration.

  • Changelog fragments added: changelog.d/gate-batch-notices.fixed.md, changelog.d/gate-batch-channels.changed.md and changelog.d/gate-batch-channels.added.md.

Effie-2289 made the change, and Ada-1017 made its design calls. Internal reviews read its rounds. Humphrey-2407 wrote this description.

A debounced gate batch let a chat:system notice decide its route, its
addressed flag and the channel its wake names. A pin in a DM is
addressed by its place, so as the newest addressed event it took the
reply meant for a mention elsewhere in the same batch, though 0.28.0
says no notice decides where an agent's speech goes, even one addressed
by its place. The direct path already skips notices.

A batch in which no message addressed the agent sets no route, so
under the default speech.locus its turn has no channel. The agent was
then told its reply "came from no channel", and to ask whoever runs
the host, though the batch's messages came from channels and nothing
is misconfigured.

- wakeProvenance sets notices aside before choosing the batch's event.
  A batch of notices alone names only the author of its newest notice
  that has one, as the same notice woken directly does. Its doc names
  the exception.
- A batch in which no message addressed the agent lists the channels
  its messages came from, those the host resolved, keyed on server and
  id, in the new WakeProvenance.batchChannels. A push the host can't
  place is passed over. The framework carries the channels it names on
  the wake as the new InferenceRequest.wakeChannels; a merge keeps them
  unless a request in it names a channel.
- With no locus, deliverSpeech's reason names those channels, says what
  came from them didn't address the agent and that no channel was
  chosen, and says to send explicitly, under prose routing by locus and
  hybrid and for a sleep's announcement. The notice calls this a
  routing situation (byDesign), where every other no-channel notice
  keeps "routing/configuration". The logged line keeps "no locus".
- wakeProvenance's fallback time is a reduce, not a spread, so a very
  large batch can't overflow the call.
- Tests: notices beside a message, addressed in a DM beside a mention,
  and alone; a batched notice's stamp against the same notice woken
  directly; the channels of one-channel, two-channel, push-only,
  unplaceable-push and two-server batches, and none for an addressed
  batch; the whole reason for one and two channels from batches of one
  to three messages, under locus and hybrid, and a sleep's; merges with
  a channel-naming wake, an addressed wake and an addressed notice; a
  fork's home kept; no notice when the fallback gives a channel; the
  log line and trace keeping "no locus"; a 200,000-event batch.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant