feat(irc): work-aware peer roster with role and activity

Add a display-only `activity` field to AgentRef plus `setActivity`, fed
from the subagent progress chokepoint with a short gist of the agent's
latest intent (or current tool). Render it in the `irc list` output, the
subagent peer roster, and the TUI peer card, beside the role-derived
display name. setActivity emits no event — the roster reads on demand —
so the per-tool-call rate stays off the registry listener path. Peers
with no activity render without a dangling clause.

Refs #2470

Op: extend
This commit is contained in:
metaphorics
2026-06-14 08:47:01 +09:00
parent a6cce473ac
commit aeebcbb6c2
6 changed files with 197 additions and 3 deletions
+7 -1
View File
@@ -125,7 +125,10 @@ function renderIrcPeerRoster(selfId: string): string {
.list()
.filter(ref => ref.id !== selfId && ref.status !== "aborted");
if (peers.length === 0) return "- (no other agents)";
const lines = peers.map(peer => `- \`${peer.id}\` — ${peer.displayName} (${peer.kind}, ${peer.status})`);
const lines = peers.map(
peer =>
`- \`${peer.id}\` — ${peer.displayName} (${peer.kind}, ${peer.status})${peer.activity ? `: ${peer.activity}` : ""}`,
);
if (peers.some(peer => peer.status === "idle" || peer.status === "parked")) {
lines.push("Idle/parked peers are not gone: messaging them wakes (or revives) them.");
}
@@ -841,6 +844,9 @@ function createSubagentRunMonitor(args: RunMonitorArgs): SubagentRunMonitor {
const emitProgressNow = () => {
progress.durationMs = Date.now() - startTime;
onProgress?.({ ...progress });
const activityGist =
progress.lastIntent ?? (progress.currentTool ? `running ${progress.currentTool}` : undefined);
if (activityGist) AgentRegistry.global().setActivity(id, activityGist);
if (args.eventBus) {
args.eventBus.emit(TASK_SUBAGENT_PROGRESS_CHANNEL, {
index,