Skip to content

feat: show subagent activity on every chat platform - #369

Open
raullopez-sandbox wants to merge 3 commits into
mainfrom
feat/agent-list-all-references
Open

feat: show subagent activity on every chat platform#369
raullopez-sandbox wants to merge 3 commits into
mainfrom
feat/agent-list-all-references

Conversation

@raullopez-sandbox

@raullopez-sandbox raullopez-sandbox commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator

Implements subagent activity visibility on every bridged chat platform. When an agent delegates to subagents, the room's working indicator now lists them.

What changes

Backend (core/)

  • POST /agents/{id}/runtime-state accepts active_subagents: a list of {agent_id, agent_name, state, detail}, max 50 entries. null means "unchanged".
  • The list is stored on agent_runtime_states.active_subagents (JSONB, migration f8a1b2c3d4e5) with the same preserve-on-omit rule as control_capabilities, and carried on AgentRuntimeStateEvent.
  • Every collaboration adapter renders the list under the working indicator as - <emoji> <name>[: detail]. Names and details are escaped for the platform (mrkdwn for Slack, markdown for Discord, Mattermost and Teams, HTML for Telegram). Limits: Slack 10 entries and 100-char detail, Teams 4 entries, Telegram 120-char detail, others 20 entries.
  • The agent's own activity line is not escaped. It is rendered as before.

Console (console/)

  • Claude Code fires SubagentStart / SubagentStop hooks. The Claude plugin already maps them to the subagent / subagent-done hook events. The event enricher now returns a subagent event for them, and both the desktop hook service and the sidecar runtime dispatch it.
  • RoomConnection keeps the live subagents of the running turn and posts them with runtime state at once on each spawn and finish. The list is cleared when the turn ends, when the state leaves working, and when a new turn starts.

Housekeeping

  • internal/ and .claude/worktrees/ are no longer tracked and are ignored.

Result

Mattermost, from a stack built on this branch:

⚙️ _Delegating to_ `Explore`
• ⚙️ Explore

The same message is edited in place when the subagent finishes and the line is removed.

Tests

  • Backend: adapter rendering through the real Mattermost, Slack, Teams, Telegram and Discord adapters; bridge → adapter pass-through; store round trip and preserve-on-omit against PostgreSQL; schema contract. just check, just typecheck, just test (2284 passed).
  • Console: enricher maps subagent / subagent-done; RoomConnection posts one runtime state per event with the list, keys by id, clears at turn end, and does not push outside a working turn. Typecheck, lint and vitest are green (one pre-existing failure in session-spawner.test.ts is identical on main).
  • Migration chain has one head.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Tq1pDDfir5c96Lzzc3txk1

raullopez-sandbox added a commit that referenced this pull request Sep 4, 2026
…te reporting

Completes CHOO-2555 agent-side implementation. Detects Agent tool calls via
hooks, tracks subagent lifecycle (spawn/working/complete), and reports
active_subagents in runtime state POSTs to /agents/{id}/runtime-state.

**Implementation:**
- Created SubagentTracker service managing per-session subagent state
- Added hook detection in event-enricher for Agent/SendMessage MCP tools
- Wired tracker through SwitchNotificationPoller to all RoomConnections
- Extended RoomConnection.postRuntimeState() to include active_subagents
- Added session lifecycle cleanup (session:deleted, session:remote-terminated)
- Fixed unsafe type casts in extractTargetAgent() with proper validation

**Files created:**
- src/shared/core/switch-rooms/subagent-activity.ts - shared types
- src/main/core/switch-rooms/subagent-tracker.ts - tracking service

**Files modified:**
- src/main/core/agent-hooks/event-enricher.ts - detect Agent tool calls
- src/main/core/agent-hooks/agent-hook-service.ts - route to tracker
- src/main/core/switch-rooms/switch-notification-poller.ts - own tracker
- src/main/core/switch-rooms/room-connection.ts - accept & use tracker
- src/main/core/switch-rooms/room-connection.test.ts - mock tracker
- src/sidecar/sidecar-runtime.ts - own tracker for remote sessions

The backend implementation (PR #369) is already merged and ready to receive
this data. Once this lands, subagent activity will flow through the full
stack: console → API → DB → Matrix → bridge → Teams/Slack/Mattermost/etc.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
raullopez-sandbox and others added 2 commits September 4, 2026 12:38
Parent agents can now report their active subagents with runtime state
(POST /agents/{id}/runtime-state, active_subagents, max 50). The list is
stored on agent_runtime_states with the same preserve-on-omit rule as
control_capabilities, carried on AgentRuntimeStateEvent, and rendered
under the working indicator by every collaboration adapter with
platform-specific escaping and limits.

Also stop tracking internal/ and .claude/worktrees.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Tq1pDDfir5c96Lzzc3txk1
The Claude plugin already maps SubagentStart/SubagentStop to the
subagent/subagent-done hook events. The room connection now keeps the
live subagents of the running turn from those events and posts them with
runtime state at once on each spawn and finish, so the room's working
indicator lists them.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Tq1pDDfir5c96Lzzc3txk1
@raullopez-sandbox
raullopez-sandbox force-pushed the feat/agent-list-all-references branch from 7716f25 to 174e340 Compare September 4, 2026 10:39
@raullopez-sandbox raullopez-sandbox changed the title feat: implement subagent activity tracking (CHOO-2555) feat: show subagent activity on every chat platform Sep 4, 2026
Claude Code does not report the same agent_id on a named subagent's
SubagentStart and its matching SubagentStop — observed against a real
session: Stop carried a different id than Start, and no agent_type at
all. Matching the finish event by id silently never cleared the
started entry, so the indicator never showed anything.

Track subagents in an ordered list and clear the oldest live one on
finish instead. Verified against a real Claude Code session driven by
the console: Mattermost's working indicator gains the subagent line on
spawn and loses it on finish.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Tq1pDDfir5c96Lzzc3txk1
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