From 95a59b0e9fc96ae6da273c0d9ac76a1d6d972670 Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 13 Jun 2026 06:10:30 +0200 Subject: [PATCH] feat(agents): wire AgentArtifactIndex into server, broadcast agent:artifact SSE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Starts agentArtifactIndex alongside the existing subagentWatcher listeners (sourced from its subagent:tool_call stream) and rebroadcasts artifact:added/updated as a single agent:artifact SSE event. Registers the event in sse-events.ts + constants.js (parity test passes). Listeners detached and the index stopped in cleanupSubagentWatcherListeners. Purely additive — no existing behavior changes. Server boots clean on an isolated beta instance and discovers subagents as before. Backend half of the Agent Gallery; the serve route and frontend are still to come. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/web/public/constants.js | 1 + src/web/server.ts | 25 +++++++++++++++++++++++++ src/web/sse-events.ts | 3 +++ 3 files changed, 29 insertions(+) diff --git a/src/web/public/constants.js b/src/web/public/constants.js index 1dc86bc1..5aa4dece 100644 --- a/src/web/public/constants.js +++ b/src/web/public/constants.js @@ -333,6 +333,7 @@ const SSE_EVENTS = { SUBAGENT_MESSAGE: 'subagent:message', SUBAGENT_TOOL_RESULT: 'subagent:tool_result', SUBAGENT_COMPLETED: 'subagent:completed', + AGENT_ARTIFACT: 'agent:artifact', // Images IMAGE_DETECTED: 'image:detected', diff --git a/src/web/server.ts b/src/web/server.ts index b5678534..e9d0eba5 100644 --- a/src/web/server.ts +++ b/src/web/server.ts @@ -59,6 +59,7 @@ import { type SubagentMessage, type SubagentToolResult, } from '../subagent-watcher.js'; +import { agentArtifactIndex, type AgentArtifact } from '../agent-artifact-index.js'; import { imageWatcher } from '../image-watcher.js'; import { attachmentRegistry, registerExternalAttachment } from '../attachment-registry.js'; import { TranscriptWatcher } from '../transcript-watcher.js'; @@ -248,6 +249,11 @@ export class WebServer extends EventEmitter { completed: (info: SubagentInfo) => void; error: (error: Error, agentId?: string) => void; } | null = null; + private artifactIndexHandlers: { + added: (artifact: AgentArtifact) => void; + updated: (artifact: AgentArtifact) => void; + error: (error: Error) => void; + } | null = null; private imageWatcherHandlers: { detected: (event: ImageDetectedEvent) => void; attachmentDetected: (event: AttachmentDetectedEvent) => void; @@ -412,6 +418,18 @@ export class WebServer extends EventEmitter { subagentWatcher.on('subagent:message', this.subagentWatcherHandlers.message); subagentWatcher.on('subagent:completed', this.subagentWatcherHandlers.completed); subagentWatcher.on('subagent:error', this.subagentWatcherHandlers.error); + + // Agent artifact index: attribute the files each subagent writes (from subagentWatcher's + // tool-call stream) and broadcast them as `agent:artifact` for the Agent Gallery view. + agentArtifactIndex.start(subagentWatcher); + this.artifactIndexHandlers = { + added: (artifact: AgentArtifact) => this.broadcast(SseEvent.AgentArtifact, artifact), + updated: (artifact: AgentArtifact) => this.broadcast(SseEvent.AgentArtifact, artifact), + error: (error: Error) => console.error('[AgentArtifactIndex] Error:', error.message), + }; + agentArtifactIndex.on('artifact:added', this.artifactIndexHandlers.added); + agentArtifactIndex.on('artifact:updated', this.artifactIndexHandlers.updated); + agentArtifactIndex.on('artifact:error', this.artifactIndexHandlers.error); } /** @@ -429,6 +447,13 @@ export class WebServer extends EventEmitter { subagentWatcher.off('subagent:error', this.subagentWatcherHandlers.error); this.subagentWatcherHandlers = null; } + if (this.artifactIndexHandlers) { + agentArtifactIndex.off('artifact:added', this.artifactIndexHandlers.added); + agentArtifactIndex.off('artifact:updated', this.artifactIndexHandlers.updated); + agentArtifactIndex.off('artifact:error', this.artifactIndexHandlers.error); + this.artifactIndexHandlers = null; + } + agentArtifactIndex.stop(); } /** diff --git a/src/web/sse-events.ts b/src/web/sse-events.ts index e851dfd6..edce5da2 100644 --- a/src/web/sse-events.ts +++ b/src/web/sse-events.ts @@ -212,6 +212,8 @@ export const SubagentProgress = 'subagent:progress' as const; export const SubagentMessage = 'subagent:message' as const; /** Subagent finished. */ export const SubagentCompleted = 'subagent:completed' as const; +/** A file artifact was attributed to a subagent (newly added or re-written). Powers the Agent Gallery. */ +export const AgentArtifact = 'agent:artifact' as const; // ─── Scheduled Runs ────────────────────────────────────────────────────────── @@ -442,6 +444,7 @@ export const SseEvent = { SubagentProgress, SubagentMessage, SubagentCompleted, + AgentArtifact, // Scheduled runs ScheduledCreated,