feat(relay,mcpl): markdown-preserving split sends + opt-in inline audio (RFC-006) - #2
Open
wolframs wants to merge 3 commits into
Open
feat(relay,mcpl): markdown-preserving split sends + opt-in inline audio (RFC-006)#2wolframs wants to merge 3 commits into
wolframs wants to merge 3 commits into
Conversation
…io (RFC-006) Ports chapterx PR #13 (markdown across message splits) and PR #12 (audio input; membrane PR #29 context) onto portal's relay architecture. Split sends (relay): - discord-markdown.ts: splitter engine ported from chapterx — closes/reopens fences & emphasis at chunk boundaries, records synthetic bridge strings - sendMessage splits >2000-char content; WebhookPool.sendMany keeps parts contiguous on the persona's webhook queue (send() now delegates to it); partial failures record the posted parts and name them in the error - MessageStore persists bridgeOpen/bridgeClose/parts/partOf per part; buildPortalMessage strips bridges so agents see their original markdown (history, live events, pins), with PortalMessage.partOf for grouping - edit_message re-splits across existing parts (surplus deleted, growth refused with INVALID_PARAMS); delete_message fans out over all parts and surfaces failures instead of silently succeeding - SendMessageResult.messageIds lists all parts (additive, no version bump) Inline audio (mcpl + protocol): - PortalAttachment.duration/waveform captured from Discord voice messages - set_audio_visibility tool: durable per-channel opt-in (default OFF), mirroring the reactions pattern; content-shaping only, never wakes - buildContent inlines audio as MCPL audio blocks (12MB cap, max 2/message, MIME normalized: mpeg/mpeg3/x-mpeg-3 → mp3, extension fallback when Discord omits contentType); attachment fetches now run concurrently - oversized clips flagged with a native 🐘 reaction (idempotent shared-bot) Tests: 140 splitter tests ported from chapterx + new split-send integration tests (contiguity, partial failure, store round-trip, strip/reassemble) and audio tests (opt-in persistence, MIME normalization/detection). 257 total. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ication Live-tested RFC-006 on a real guild (scripts/rfc6-live.mjs, new): 3 of 21 checks failed, all in the live-event path — - Split-send parts were recorded only after the whole batch resolved, but each part's gateway create echo arrives while later parts are still posting: live events went out with bridge markers unstripped and no partOf. sendMany now fires an onSent callback per posted part and the relay records attribution/bridge metadata immediately. - Even per-part, the gateway echo can beat the REST response, so onDiscordMessage now holds an own-webhook echo that has no store ref until the send path records and flushes it (5s timer as safety net). This also fixes the pre-existing single-send attribution race. - editMessage removed surplus-part store refs itself, so the gateway's delete echo emitted raw Discord ids instead of relay ids. Cleanup is now left to the echo, exactly like delete_message. Re-run: 21/21 live checks green; 227 relay unit tests (2 new for onSent). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…a persona scripts/mimo-audio-live.mjs: one persona posts a spoken .wav, a second persona driven by xiaomi/mimo-v2.5 (OpenRouter, provider order pinned like chapterx's mimo.yaml) consumes it through portal-mcpl's real buildContent (now exported for live verification) mapped to an input_audio part exactly as membrane's adapter does. The model quoted the spoken sentence verbatim. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Author
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.

Ports two capabilities from chapterx (PRs #12, #13, with membrane #29 context) onto portal's relay architecture. Full design + verification notes in PORTAL-RFC-006.
1. Markdown-preserving split sends (relay)
Previously a >2000-char
send_messagebubbled a raw discord.js error asINTERNAL. Now:discord-markdown.ts(ported verbatim from chapterx, with its 140-test suite): splits content closing every markdown construct open at a chunk boundary and reopening it in the next chunk, recording the synthetic bridge strings per chunk.WebhookPool.sendManyas one queue item — no same-webhook send can interleave. Files ride on the last part. Partial failure records the posted parts and names their relay ids in the error.buildPortalMessage(live events, history, pins) — agents always see their original unbroken markdown, across restarts.SendMessageResult.messageIds+PortalMessage.partOflet clients group parts (additive; no protocol version bump).edit_messagere-splits across existing parts (surplus deleted; growth refused withINVALID_PARAMS);delete_messagefans out over all parts.2. Inline audio for agents (mcpl) + protocol audio metadata
set_audio_visibilitytool: per-channel, durable, default-OFF opt-in (mirrors the reactions pattern). Content-shaping only — never wakes.audioblocks: MIME normalization (MP3 aliases →audio/mp3), extension fallback for Discord's optional content-type, 12 MiB cap, max 2 clips/message, notes explaining anything not inlined.reactRPC (shared-bot, idempotent across agents).PortalAttachmentgainsduration/waveform(Discord voice-message fields).Verification
scripts/rfc6-live.mjs, 21/21): 4-part split send, stripped live events/history, reassembly equality,partOflinks, shrink/collapse/grow-refusal edits, delete fan-out, audio CDN round-trip, native 🐘.scripts/mimo-audio-live.mjs): a spoken .wav posted by one persona reached a MiMo v2.5-driven persona as an mcpl audio block and the model quoted the spoken sentence verbatim.store.record) — fixed via per-part recording (sendManyonSentcallback) plus holding unrecorded own-webhook echoes until the send path flushes them; this also fixed a pre-existing single-send attribution race.Version bumps left out on purpose (repo does
chore(release)commits separately).🤖 Generated with Claude Code