Skip to content

(subagents): attribute subagent activity to its parent from every source - #270

Merged
devsuitup merged 1 commit into
mainfrom
feat/247-subagent-attribution
Sep 11, 2026
Merged

devsuitup merged 1 commit into
mainfrom
feat/247-subagent-attribution

Conversation

@devsuitup

Copy link
Copy Markdown
Owner

Closes #247. Step 5 of #246, after #269.

What

  • subagent-attribution.js: pure subagentParentFromParts(parts){ parentSessionId, agentId } | null for <parent>/subagents/agent-<id>.jsonl and the legacy <parent>/agent-<id>.jsonl; null for a top-level transcript or anything else.
  • local-transcript-activity.js and remote-activity.js use it instead of dropping subagent legs: the existing channels (session-transcript-activity, remote-activity) carry either the previous { sessionId, at } or { parentSessionId, agentId, at, kind:'subagent' } (+ alias for remote). Local attribution is gated on the parent having no PTY in the app, so detectSubagentTransitions() keeps owning PTY parents — nothing is fed twice.
  • public/local-transcript-adapter.js, public/remote-activity-ui.js: subagentSpawned on the parent's persistent state plus a separate 20 s decay → subagentCompleted({ stillActive:false }). session-activity-dom.js applyStateClasses projects has-busy-agents off snapshot.agentsBusy (that rung never wins the icon while busy is active, but the row tint must still show).
  • sidebar.js parentHasActiveSubagent() also consults the adapter states, so a periodic renderProjects() (remote refresh 15–60 s) no longer wipes the tint before the decay.
  • Remote subagent label: buildSubagentItem() already reads session.subagentType, populated for mirrored rows by readSubagentMeta() like local ones (checked in code, DOM parity test added). The "SUB" seen on the VPS is therefore most likely the sidecar arriving a mirror cycle after its transcript — not verified live; if it persists after this, the next step is on the mirror ordering, not the renderer.
  • Docs: session-state.md (all three kinds wired for subagent ports, status "steps 1-5 done"), subagent-observability.md, ipc-bridge.md.

Proof

  • test/subagent-attribution.test.js (both layouts, top-level → null; mutation reporting the wrong segment as parent turns two tests red, reverted).
  • Tracker tests: subagent leg without PTY → event; with PTY → none. Adapter tests: subagent write → parent has-busy-agents + session-icon--agents-busy; decay clears it. test/dom-sidebar-remote-subagent-attribution.test.js: remote subagent row shows the agent type like a local one; parent tint survives a re-render.
  • task check: two stages green, 0 fail, pre-existing skips.

Not done: seeding agentsBusy at first paint (no persisted "active-at" signal for subagents exists to seed from) — live events only, as #247's acceptance requires.

Closes #247, step 5 of #246. A pure subagentParentFromParts() resolves a
subagent transcript path to its parent for both layouts; the local-transcript
and remote trackers emit a kind:'subagent' event on their existing channels,
and the renderer adapters apply subagentSpawned to the parent's state with a
separate decay. has-busy-agents is projected off the snapshot and survives a
sidebar re-render for adapter-owned parents. Parents with a PTY keep the IPC
path, so nothing is fed twice.
@devsuitup
devsuitup merged commit e0549c3 into main Sep 11, 2026
10 checks passed
@devsuitup
devsuitup deleted the feat/247-subagent-attribution branch September 11, 2026 21:51
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.

(activity): light has-busy-agents for remote parents and local parents without a PTY

1 participant