Skip to content

feat: cross-studio self-messaging support (by Wren)#267

Merged
conoremclaughlin merged 5 commits intomainfrom
wren/feat/self-studio-messaging
Mar 26, 2026
Merged

feat: cross-studio self-messaging support (by Wren)#267
conoremclaughlin merged 5 commits intomainfrom
wren/feat/self-studio-messaging

Conversation

@conoremclaughlin
Copy link
Copy Markdown
Owner

Summary

  • Allow agents to message themselves in a different studio (e.g., wren-omega → wren-review for review requests)
  • resolveTriggeredAgents gains selfStudioTarget flag — keeps sender in trigger lists when targeting a different studio
  • handleSendToInbox detects cross-studio self-messages when sender is in recipients AND recipientStudioId/recipientStudioHint is set
  • Trigger payload passes studioId/studioHint for routing; skips thread history auto-resolve for self (would find own session)
  • Channel plugin self-filter now checks studioId — accepts messages from self when sent from a different studio
  • Replaced duplicated resolveTriggeredAgents in test file with direct import

Test plan

  • 65 tests pass across 3 files (thread-handlers, inbox-handlers, channel-plugin)
  • 5 new selfStudioTarget unit tests
  • Live test: send_to_inbox from wren-omega to wren with recipientStudioHint targeting wren-review

🤖 Generated with Claude Code

conoremclaughlin and others added 5 commits March 25, 2026 18:36
Allow an agent to message themselves in a different studio (e.g., wren-omega
sends a review request to wren-review).

Changes:
- resolveTriggeredAgents: add selfStudioTarget flag that keeps sender in
  trigger lists instead of excluding them
- handleSendToInbox: detect cross-studio self-message when sender is in
  recipients AND recipientStudioId/recipientStudioHint is set
- Skip auto-resolve from thread history for self-messages (would find
  sender's own session); pass studioId/studioHint through trigger payload
- Channel plugin: self-filter now checks studioId, not just agentId —
  accepts messages from self when they came from a different studio
- thread-handlers.test.ts: import resolveTriggeredAgents directly instead
  of duplicating the function; add 5 selfStudioTarget tests
- 65 tests pass across 3 test files

Co-Authored-By: Wren <noreply@anthropic.com>
Lumen's review: channelPoll filter rejected cross-studio self-threads
because isThreadOwnedByStudio only checked sender.studioId. The target
studio's channel plugin never saw the thread.

Fix:
- Stamp metadata.pcp.recipient.studioId on thread messages for cross-
  studio self-messages (when sender is in recipients + recipientStudioId set)
- isThreadOwnedByStudio now also checks recipient.studioId — accepts
  threads where this studio is an explicit recipient
- 2 regression tests: accept via recipient match, reject third-party

Co-Authored-By: Wren <noreply@anthropic.com>
Lumen's review: the hint-only path (recipientStudioHint without
recipientStudioId) left metadata.pcp.recipient.studioId empty, so the
channelPoll filter couldn't match.

Now resolves hints to studioIds via DB lookup (slug match or 'main'
fallback) before stamping thread message metadata and trigger payload.
Both explicit recipientStudioId and recipientStudioHint paths are
now covered end-to-end.

Co-Authored-By: Wren <noreply@anthropic.com>
Lumen's review: the hint-only path (recipientStudioHint without
recipientStudioId) left metadata.pcp.recipient.studioId empty, so the
channelPoll filter couldn't match.

Now resolves 'main' hint using branch='main' match (same semantics as
SessionService.resolveMainStudioId) instead of naive 'most recently
updated studio'. Named hints resolve by slug match.

Co-Authored-By: Wren <noreply@anthropic.com>
Lumen's review: the 'main' hint resolution was naive (branch match only)
instead of matching SessionService.resolveMainStudioId semantics
(worktree path → branch fallback).

Extract resolveStudioHint() as a standalone exported function in
session-service.ts — handles both 'main' (worktree path then branch)
and named hints (slug match). Inbox handler now uses this shared
function instead of inline resolution.

Co-Authored-By: Wren <noreply@anthropic.com>
@conoremclaughlin conoremclaughlin merged commit 2561bdd into main Mar 26, 2026
3 of 4 checks passed
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