diff --git a/internal/cloud/server-workbench-http.test.ts b/internal/cloud/server-workbench-http.test.ts index 3418602d..af350403 100644 --- a/internal/cloud/server-workbench-http.test.ts +++ b/internal/cloud/server-workbench-http.test.ts @@ -250,6 +250,45 @@ test("workbench read model treats active session state as running", async () => } }); +test("workbench read model lets running trace override idle session summary", async () => { + const traceStore = createCodeAgentTraceStore(); + const traceId = "trc_workbench_idle_with_running_trace"; + const session = { + id: "ses_workbench_idle_with_running_trace", + projectId: "prj_hwpod_workbench", + agentId: "hwlab-code-agent", + status: "idle", + ownerUserId: ACTOR.id, + conversationId: "cnv_workbench_idle_with_running_trace", + threadId: "thread-workbench-idle-with-running-trace", + lastTraceId: traceId, + updatedAt: "2026-06-17T00:02:00.000Z", + session: { sessionStatus: "idle", lastTraceId: traceId, messages: [{ role: "user", text: "still running despite idle row", traceId, status: "sent" }] } + }; + traceStore.append(traceId, { type: "backend", status: "running", label: "runner:created", terminal: false }); + const accessController = { + store: { + async listAgentSessionsForUser() { return [session]; } + }, + async ensureBootstrap() {}, + async authenticate() { return { ok: true, actor: ACTOR, session: { id: "uss_workbench_reader" } }; } + }; + const server = createCloudApiServer({ accessController, traceStore, codeAgentChatResults: createCodeAgentChatResultStore() }); + await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve)); + + try { + const { port } = server.address(); + const sessions = await getJson(port, `/v1/workbench/sessions?includeSessionId=${encodeURIComponent(session.id)}`); + assert.equal(sessions.status, 200); + assert.equal(sessions.body.sessions[0].status, "running"); + assert.equal(sessions.body.sessions[0].running, true); + assert.equal(sessions.body.sessions[0].terminal, false); + assert.equal(sessions.body.sessions[0].turnSummary.status, "running"); + } finally { + await new Promise((resolve, reject) => server.close((error) => error ? reject(error) : resolve())); + } +}); + test("workbench realtime stream accepts session authority without project or workspace", async () => { const traceStore = createCodeAgentTraceStore(); const results = createCodeAgentChatResultStore(); diff --git a/internal/cloud/server-workbench-http.ts b/internal/cloud/server-workbench-http.ts index afccfd74..11c7fb3d 100644 --- a/internal/cloud/server-workbench-http.ts +++ b/internal/cloud/server-workbench-http.ts @@ -643,6 +643,7 @@ function turnStatus(result, session, trace) { function canonicalWorkbenchStatus(primary, traceStatus) { const primaryStatus = normalizeStatus(primary); const trace = normalizeStatus(traceStatus); + if (RUNNING_STATUSES.has(trace) && (primaryStatus === "idle" || primaryStatus === "unknown" || !TERMINAL_STATUSES.has(primaryStatus))) return trace; if (TERMINAL_STATUSES.has(trace) && (!TERMINAL_STATUSES.has(primaryStatus) || RUNNING_STATUSES.has(primaryStatus))) return trace; return primaryStatus || trace || "unknown"; }