4.0 KiB
4.0 KiB
title, description
| title | description |
|---|---|
| Outbound Session Mirroring Refactor (Issue | Track outbound session mirroring refactor notes, decisions, tests, and open items. |
Outbound Session Mirroring Refactor (Issue #1520)
Status
- In progress.
- Core + plugin channel routing updated for outbound mirroring.
- Gateway send now derives target session when sessionKey is omitted.
Context
Outbound sends were mirrored into the current agent session (tool session key) rather than the target channel session. Inbound routing uses channel/peer session keys, so outbound responses landed in the wrong session and first-contact targets often lacked session entries.
Goals
- Mirror outbound messages into the target channel session key.
- Create session entries on outbound when missing.
- Keep thread/topic scoping aligned with inbound session keys.
- Cover core channels plus bundled extensions.
Implementation Summary
- New outbound session routing helper:
src/infra/outbound/outbound-session.tsresolveOutboundSessionRoutebuilds target sessionKey usingbuildAgentSessionKey(dmScope + identityLinks).ensureOutboundSessionEntrywrites minimalMsgContextviarecordSessionMetaFromInbound.
runMessageAction(send) derives target sessionKey and passes it toexecuteSendActionfor mirroring.message-toolno longer mirrors directly; it only resolves agentId from the current session key.- Plugin send path mirrors via
appendAssistantMessageToSessionTranscriptusing the derived sessionKey. - Gateway send derives a target session key when none is provided (default agent), and ensures a session entry.
Thread/Topic Handling
- Slack: replyTo/threadId ->
resolveThreadSessionKeys(suffix). - Discord: threadId/replyTo ->
resolveThreadSessionKeyswithuseSuffix=falseto match inbound (thread channel id already scopes session). - Telegram: topic IDs map to
chatId:topic:<id>viabuildTelegramGroupPeerId.
Extensions Covered
- Matrix, MS Teams, Mattermost, BlueBubbles, Nextcloud Talk, Zalo, Zalo Personal, Nostr, Tlon.
- Notes:
- Mattermost targets now strip
@for DM session key routing. - Zalo Personal uses DM peer kind for 1:1 targets (group only when
group:is present). - BlueBubbles group targets strip
chat_*prefixes to match inbound session keys. - Slack auto-thread mirroring matches channel ids case-insensitively.
- Gateway send lowercases provided session keys before mirroring.
- Mattermost targets now strip
Decisions
- Gateway send session derivation: if
sessionKeyis provided, use it. If omitted, derive a sessionKey from target + default agent and mirror there. - Session entry creation: always use
recordSessionMetaFromInboundwithProvider/From/To/ChatType/AccountId/Originating*aligned to inbound formats. - Target normalization: outbound routing uses resolved targets (post
resolveChannelTarget) when available. - Session key casing: canonicalize session keys to lowercase on write and during migrations.
Tests Added/Updated
src/infra/outbound/outbound-session.test.ts- Slack thread session key.
- Telegram topic session key.
- dmScope identityLinks with Discord.
src/agents/tools/message-tool.test.ts- Derives agentId from session key (no sessionKey passed through).
src/gateway/server-methods/send.test.ts- Derives session key when omitted and creates session entry.
Open Items / Follow-ups
- Voice-call plugin uses custom
voice:<phone>session keys. Outbound mapping is not standardized here; if message-tool should support voice-call sends, add explicit mapping. - Confirm if any external plugin uses non-standard
From/Toformats beyond the bundled set.
Files Touched
src/infra/outbound/outbound-session.tssrc/infra/outbound/outbound-send-service.tssrc/infra/outbound/message-action-runner.tssrc/agents/tools/message-tool.tssrc/gateway/server-methods/send.ts- Tests in:
src/infra/outbound/outbound-session.test.tssrc/agents/tools/message-tool.test.tssrc/gateway/server-methods/send.test.ts