Skip to content

feat: enable direct messaging to subagents from TUI - #1876

Open
cetagostini wants to merge 2 commits into
XiaomiMiMo:mainfrom
cetagostini:feat/subagent-direct-messaging
Open

feat: enable direct messaging to subagents from TUI#1876
cetagostini wants to merge 2 commits into
XiaomiMiMo:mainfrom
cetagostini:feat/subagent-direct-messaging

Conversation

@cetagostini

@cetagostini cetagostini commented Jul 23, 2026

Copy link
Copy Markdown

Summary

  • Add POST /:sessionID/inbox/send server endpoint that wraps Inbox.send() for direct subagent messaging
  • Add onCustomSubmit prop to Prompt component allowing custom submit routing (skips model/workspace checks)
  • Show input bar when viewing a running, pending, or idle subagent — users can now type directly to subagents without relaying through the main agent

Motivation

When navigating to a subagent's conversation view in the TUI, the input bar was hidden. All communication had to go through the main agent via actor send, adding latency. This PR enables direct messaging by:

  1. Exposing the existing Inbox.send() infrastructure as an HTTP endpoint
  2. Routing the TUI prompt's submit to that endpoint when viewing a subagent

If a sub-agent goes away from the main goal, you can provide small notch to put it back on track. If main agent miss indications, user can provide without let the agent go crazy.

Changes

Server (packages/opencode/src/server/routes/instance/session.ts)

  • New POST /:sessionID/inbox/send endpoint accepting { actorID, content, type? } and returning { inboxID }
  • Reuses the same inboxServiceRef.current.send() that the actor send tool uses

TUI Prompt (packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx)

  • New onCustomSubmit prop on PromptProps: when provided, the submit function calls it instead of the default session.prompt path
  • The custom path skips model selection, workspace checks, and slash command handling — just sends the text and clears the input

TUI Session (packages/opencode/src/cli/cmd/tui/routes/session/index.tsx)

  • New subagentInputVisible memo: returns true when viewing a subagent with status running, pending, or unknown (idle-without-outcome)
  • Renders a second <Prompt> with onCustomSubmit that POSTs to the inbox send endpoint
  • SubagentFooter (navigation + status) remains visible above the input bar

Testing

  1. Spawn a persistent peer via session create --topic test
  2. Navigate to the child session in the TUI
  3. Verify the input bar appears alongside the subagent footer
  4. Type a message and submit — verify it arrives in the subagent's inbox and triggers a turn
  5. Verify the subagent's response appears in its conversation view
  6. Navigate back to main — verify the main agent's input bar works normally
  7. Test with ephemeral subagents — verify input is disabled after terminal

Out of Scope

Add the ability for users to type directly to running/persistent
subagents from the TUI, bypassing the main agent relay.

Changes:
- Server: Add POST /:sessionID/inbox/send endpoint that wraps
  Inbox.send() for direct subagent messaging
- TUI: Add onCustomSubmit prop to Prompt component for custom
  submit routing (skips model/workspace checks)
- TUI: Add subagentInputVisible memo and render Prompt with
  onCustomSubmit when viewing a running/pending/idle subagent

The SubagentFooter (navigation + status) remains visible above
the input bar when viewing a subagent.
- Fix double-submit race: wrap onCustomSubmit in submitLock
- Remove history.append from custom submit path (inbox messages
  shouldn't pollute the shared prompt history)
- Map InboxReceiverNotFound to 404 via Effect.catchTag instead
  of letting it fall through to 500
- Add 6 test cases for POST /:sessionID/inbox/send:
  happy path, default type, empty content, missing actorID,
  nonexistent actor, invalid sessionID format
@cetagostini

Copy link
Copy Markdown
Author

@wqymi and @MiMoHardFather what do you think?

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