Repository navigation
fix(history, prose): one table of the tools that carry an agent's words, read by silencing, search, extract and the semantic index - #914
Open
nissa-seru wants to merge 1 commit into
Conversation
…ch, extract and the semantic index An agent that speaks through send tools couldn't find its own words with history--search: plain search and extract's text form render a tool call as `[tool_use: NAME]` with no arguments, so the words a send carries were never matched (anima-research/connectome-host#524). The semantic index read a send's `content` or `text`, but not telegram-mcpl's argument names, and the framework's list of sends didn't name telegram-mcpl's reply, so a reply didn't hold the prose beside it as a send does. src/send-tools.ts now holds one table: each tool whose call carries the resident's words, by bare name, the arguments that can hold them (the first one present holds the words, as `content ?? text` did), and whether a call of it silences the round's auto-routed prose. Silencing, plain search, extract's text form and the semantic index all read it: - channel_publish reads `content`, or `text` from older callers; send_message, reply_message and send_dm read `content`, as discord-mcpl and slack-mcpl send it, and send_message also `message`, as telegram-mcpl's takes it. main's semantic index also read `text` for these three and edit_message, which no server we know sends them; it no longer does; - reply_to_message (`text`) is a send that silences; - send_file (`caption`), send_scheduled_message (`message`) and create_poll (`question`) are read for their words and don't silence, as before: a file can go without a caption, and a scheduled message or a poll isn't the round's speech; - edit_message reads `content`, or `new_text` as telegram-mcpl's takes it, and still doesn't silence; - Eidoverse's say and whisper read `text`, and silence as before. WORLD_PUBLICATION_TOOLS goes. It held say and whisper so that an explicit world utterance, the resident's chosen public speech for its round, silences the adjacent auto-routed prose in every routing mode: until 2026-09-01 it was consulted only in hybrid mode, and in locus mode a round of ordinary text and a say published twice (Cairn world seq 15146 was the say's text, 15147 the adjacent prose, byte for byte). Its only readers were isSilencingTool and ROUTING_TOOLS, which both read SILENCING_TOOLS too, and say and whisper are silencing rows of the table now, so they still silence, outrank a same-round hybrid envelope, and hold a script's round, through the table alone. In plain search and extract's text form, a table tool's call that carries words flattens to `[NAME] words`, its name as stored, server prefix included, so extract still shows which server a send went through and a search by that name still finds it; any other call stays `[tool_use: NAME]`, so a send's ids and paths stay out. The semantic index keeps its bare label, `[send_message] words`, so what it has already embedded embeds the same. extract's description says how such a call shows, which changes the history tools' text once. Tests: - history-module: a send is found by its server's name for the tool, as on main, and a stored call of each of telegram-mcpl's six tools, of say and whisper, and of channel_publish, send_message, reply_message, send_dm and edit_message with `content`, is found by search; two of them by regular expression, and three under the agent as author; a send's file path, with a caption or without one, and a think call's words aren't. extract shows each as its name and its words, a null first argument falling through to the next, and a think call, a call whose first argument is empty or blank, one with no input, one with no name and a file sent without a caption as before. - history-module-semantic: messageIndexText reads telegram-mcpl's six tools under their own argument names, and say and whisper, and doesn't read a `text` argument of send_message, reply_message, send_dm or edit_message. - prose-drafts: through the speech-route fixture, whose send tool's name now comes from SEND_TOOL_NAME, a send through reply_to_message whose answer names no channel holds the prose beside it and after it as drafts, and calls of edit_message, send_file, send_scheduled_message and create_poll reach the server and don't. - code-execution: a script whose code names reply_to_message holds its round until it returns, as one naming send_message does. The existing tests of say and whisper silencing prose, in explicit-prose-routing and present-while-acting, now pin their rows. Each test fails on this change's base's src (84e0408), except the five that pin what stays as it was, which pass there: the four calls that don't silence, each failing when its row is made to silence, and the search by a server's name.
This was referenced Oct 30, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
history--searchnow finds what an agent said through a send tool, andhistory--extract's text form shows it (anima-research/connectome-host#524). Both read the words from one new table insrc/send-tools.ts, and so do the semantic index and the check for which calls silence the round's auto-routed prose. The table also makesreply_to_message, telegram-mcpl's reply, silence that prose as the other sends do. Each new test fails on84e0408977'ssrcexcept the five that pin what stays as it was, and each of 32 changes that take one part out fails at least one test (Tests).@antra-tess, we're asking you to review this before it merges, since it changes
isSilencingToolandSILENCING_TOOLS(src/framework.ts:291–296), which you wrote. It addsreply_to_messageto the calls that silence, builds that set from the table, and removesWORLD_PUBLICATION_TOOLS(Changes). The framework keeps its own list of send tools by name, so a send tool a server adds needs a row in the table, as telegram-mcpl'sreply_to_messagedid here. MCPL's draft RFC-008 has a server declare a tool's class in its definition's_meta, asmcpl/class(RFC-008-tool-classes.md:40at mcpl8b0e57d192), and itscommsclass is a tool that "sends to, or reads from, other parties" (:108). So a class says neither whether a call sends nor which argument carries its words. A declaration of those two would let the framework take them from the server rather than from a row, and that would be MCPL's to decide.Problem
@The-Glassy reported that
history--searchandhistory--extractdon't see what an agent said through send tools, as an agent does withproseRouting: "disabled". This change's tests, run on84e0408977'ssrc, show what thatsrcdoes:extract's text form shows each send as its name alone, such as[tool_use: telegram--send_message], and plain search finds none of them by their words.sayandwhisper. It reads atextargument ofsend_message,reply_message,send_dmandedit_message, which discord-mcpl's and slack-mcpl's definitions of those tools don't have (Changes).reply_to_messagewhose answer names no channel doesn't silence the prose beside it: the test's server publishes "Here it is." and "Sent it." beside the reply.code_executionscript whose code namestelegram--reply_to_messagedoesn't hold its round: the round is published while the script runs.Changes
src/send-tools.tsholds one table (:12). Each row names a tool whose call carries the agent's words, by its bare name, so it matches that tool on any server. It gives the arguments that can hold the words and whether a call of the tool silences the round's auto-routed prose. The first of those arguments that is present holds the words, ascontent ?? textdid, and they count only when they're a string that isn't blank (:42–43).SILENCING_TOOLS(src/framework.ts:291) is now built from the rows that silence, and plain search,extract's text form and the semantic index read the words of every row. Before, silencing read a list of four sends, the semantic index read those four andedit_message, and plain search read none.channel_publishcontent,textsend_messagecontent, and nowmessagereply_message,send_dmcontentreply_to_messagetext(new row)send_filecaption(new row)send_scheduled_messagemessage(new row)create_pollquestion(new row)edit_messagecontent, and nownew_textsay,whispertext(new rows)4f00f6f918:send_message(message)(telegram_mcp/tools/messages.py:55),reply_to_message(text)(:948),send_scheduled_message(message)(:89),create_poll(question)(:1141),edit_message(new_text)(:716) andsend_file(caption)(telegram_mcp/tools/media.py:12). A poll'soptionsaren't read.sayandwhisperare Eidoverse's world speech, and each takestextat eidoverse-worlds34fd77ea20(mcpl/tools.ts:97,:100). They already silenced, throughWORLD_PUBLICATION_TOOLS, which onlyisSilencingToolandROUTING_TOOLSread. Both readSILENCING_TOOLStoo, so that set comes out, andsayandwhispersilence through their rows. Awhisper's words now reach the agent's own search and semantic index, as asend_dm's do.texton four sends.main's semantic index readcontent ?? textforsend_message,reply_message,send_dmandedit_message. discord-mcpl atabc7d02e3eand slack-mcpl at7274283fa7define those four withcontentand notext(src/tools.ts, discord-mcpl's:72,:87,:100and:142, slack-mcpl's:38,:55,:88and:114). So the table readscontentfor them, andtextonly forchannel_publish, from its older callers. A server that sent those four toolstextwould no longer have those words in the semantic index.send_file'scaptionis optional, and a file sent alone carries none of the round's words, so silencing the prose would keep back words meant to go with it. A scheduled message and a poll aren't the round's speech either.extract, a call of a table tool that carries words reads[NAME] words, with the name as stored, a server's prefix included (src/modules/history/index.ts:2471). Soextractstill shows which server a send went through, and a search fortelegram--send_messagestill finds it. Any other call, and one with no words, stays[tool_use: NAME], so a send's ids and file paths stay out. The semantic index keeps its bare label, such as[send_message] words(src/modules/history/semantic.ts:311), so the sends it has already embedded embed the same.extract's description now says how such a call shows (src/modules/history/index.ts:699), so an agent with the history tools sees its tool list change once.ROUTING_TOOLSis built fromSILENCING_TOOLS(src/framework.ts:354). So in locus routing acode_executionscript whose code namesreply_to_messagenow holds its round until it returns, as one that namessayorwhisperdoes.git merge-treeagainst each one's head at 18:56 UTC on October 29, withmain612f6fd3bdand withmainmerged with this change: this change adds conflicts to three of them. feat(agent): declare later tool and system-text changes in the context #690 at598f8cc58cconflicts insrc/modules/history/index.ts, and fix(routing): a turn from a non-channel surface pins no inferred locus #190 at191fc24821intest/prose-drafts.test.ts, where neither conflicts withmain. feat(mcpl): every channel item names its conversation in a stored source header #257 at665957dd5falready conflicts withmainin 33 files, and in one of them,src/modules/history/index.ts, this change takes it from one conflict block to two.What each part is for
speechOfreading it (src/send-tools.ts:36): one place names each tool and its arguments, and silencing, search,extractand the semantic index read it, so they can't name different tools.content ?? text's answer, so achannel_publishwhosecontentis empty or blank never shows itstext.textoff four rows: discord-mcpl and slack-mcpl send those toolscontent, so atextthere was never sent, and the table names what each tool takes.extract, as it did before.send_scheduled_message,create_poll,sayandwhisper: each carries the agent's own words, which is what the report asks search to find. They change nothing a turn does.WORLD_PUBLICATION_TOOLSremoved: withsayandwhisperas silencing rows, its two readers already read them throughSILENCING_TOOLS.extract(src/modules/history/index.ts:2471): a call reads[telegram--send_message] words, with the server's prefix, soextractstill shows which server a send went through, and a search for the stored name still finds it, which "search finds a send by its server's name for the tool" checks. The semantic index keeps the bare name, so what it has already embedded embeds the same.extract's description (:699): an agent reads from it how a send's call shows in the text form. Its cost is that the history tools' text changes once.history-modulesearch andextracttests pin each row's arguments, the first argument present, a null or blank one, a call with no name or no input, the stored name, and that a file's path doesn't show;sayandwhisper, and that the index doesn't readtexton the four sends;prose-draftstests pinreply_to_message's silencing and the four rows that don't silence;code-executiontest pinsreply_to_messageamong the tools a script's round waits on.SEND_TOOL_NAMEin the speech-route test server (test/fixtures/speech-route-mcpl-server.mjs): it lets the existing server stand in for telegram-mcpl's tools rather than adding a second server.What this leaves
SEND_ENGAGEMENT_TOOLS(src/framework.ts:576), the sends that open a closed channel and note their publish. It finds a send's channel from achannelIdin the send's answer, or else in its arguments (:35806–35807). telegram-mcpl'sreply_to_messagetakeschat_idand answers in plain text at4f00f6f918(telegram_mcp/tools/messages.py:948,:966).prose-draftstest, a reply whose answer names no channel holds the prose beside it and after it. There the turn's message comes from one room, and the reply names that room. No run has the prose bound for another channel.DiscordModule: itssend,dm,replyandedittools aren't in the table. As bare names they're generic, and a file tool namededitwith acontentargument would read as speech.includePrivateToolson, its default, athinkcall's words are indexed as before.Tests
Each run in the table used a clean copy of the files its row names. Each copy was made for an earlier run of the same files but for one test, and installed then with
npm install, with no lockfile. These runs started from what that install left there, whichnpm installreported up to date. Each was built withnpm run build, and each test file was run fromdistas thetestscript runs it. Each ran on Linux with Node 24.22.1, chronicle 0.5.0, context-manager 0.24.1, membrane 0.8.0 and mcpl-core 0.4.0.history-modulehistory-module-semanticprose-draftsexplicit-prose-routingpresent-while-actingcode-execution5d9af7beec84e0408977'ssrcmain612f6fd3bd84e0408977'ssrc, the eight tests that fail are this change's new tests:history-module, "search finds what was said through each one, under its own argument name", "search finds them under the agent as author" and "extract shows each one as its name and its words, and a call with no words, no input or no name as before";history-module-semantic, the telegram-mcpl test, thesayandwhispertest, and "messageIndexText doesn't read atextargument of send_message, reply_message, send_dm or edit_message, which servers sendcontent(#524)";prose-drafts, "a send through reply_to_message, telegram-mcpl's reply, whose answer names no channel, holds the prose beside it and after it (#524)";code-execution, "a script whose code names reply_to_message, telegram-mcpl's reply, holds its round until it returns (#524)".84e0408977'ssrctoo: the five new tests that pin what stays as it was. Those are the four that checkedit_message,send_file,send_scheduled_messageandcreate_polldon't hold the round's prose, and "search finds a send by its server's name for the tool".main: this head merges with612f6fd3bdcleanly bygit merge-tree, which gives tree9a1c2fad9f, the tree the run used.srcdiffers from this head's only in two doc comments, and whose tests lacked thecode-executiontest and oneextractcase and gave one semantic test an earlier title, each of 32 changes takes one part out or putstextback on one of the four rows. Each fails at least one test. This run usedtsxrather thandist, on Linux with Node 24.22.1, chronicle 0.5.0, context-manager 0.24.1 and membrane 0.8.0, and printed no mcpl-core version. Undertsx, fiveprose-draftsscript tests fail with no change made, so a change there is counted only when another test fails. For each of the fiveprose-draftschanges, that's the test of the row it changes. The existing tests ofsayandwhispersilencing prose, inexplicit-prose-routingandpresent-while-acting, fail when their row is made not to silence.Not verified
prose-draftstests call tools of telegram-mcpl's names on the test server, and the history tests read stored calls of those names and ofsayandwhisper.src/modules/history/semantic.ts:828sets the start of its walk to its watermark lessoverlapMs, 600,000 ms by default. Plain search reads the stored calls when it runs, as its tests do with calls already in the store.code-executiontests of a script holding its round run in locus routing, so no test in this change shows it under hybrid routing. A probe outside this change ran the same check in hybrid routing, built fromdistin the copies the table's runs used, wherenpm installreported them up to date. On an earlier version of this change, whosesrcdiffers from this head's only in two doc comments, a script whose code namestelegram--reply_to_message,discord--send_messageorworld--sayheld its round until it returned. On84e0408977'ssrc, thesend_messageandsayscripts held it and thereply_to_messageone didn't.changelog.d/524-speech-tools.changed.mdandchangelog.d/524-speech-tools.fixed.md.Nell-1783 made the change, and Ada-1017 made its design calls. @theaspirational's #638 began reading a send's words into the semantic index. Agnes-984 read the change and ran it, and Abigail-2676 weighed what each part pays for. Our internal review read earlier versions of it three times. Fiona-2757 wrote this description.