// The run page's live island: what it shows from the server's seed before the first event, and // from the run's AG-UI events (the projection `agent.run.events` serves, folded by the TanStack AI // client's reducer) after it — step states, a parked approval, the completed run's answer with its // Art. 50 disclosure, and a lost stream. Server-rendered, the island is exactly the seed. import type { AgentRunRecord, AgentStepRecord } from "@conusai-kit/agent" import { runEventsOf } from "@conusai-kit/agent/agui" import { type AgUiChunk, initialAgentRunView, reduceAgentRunEvent } from "@conusai-kit/agent/client" import { buildRegistry } from "@conusai-kit/core" import { createI18n } from "@conusai-kit/i18n" import { createDataClient, DataProvider } from "@conusai-kit/ui/data" import { renderToStaticMarkup } from "react-dom/server" import { describe, expect, it } from "vitest" import { appModules } from "../../index.js" import type { RunView } from "../contract/index.js" import { LiveRun } from "../ui/live-run.js" import { liveRunState } from "../ui/live-run-state.js" const RUN = "01a19940-0000-7000-0000-000000000001" const PLAN = [ { key: "read", label: "Read", tool: "documents.read", args: {} }, { key: "order", label: "Order", tool: "orders.create", args: { total: 4200 }, needsApproval: true }, ] const seed: RunView = { runId: RUN, goal: "Order the parts", status: "queued", failureCode: null, failureDetail: null, plan: PLAN.map((step) => ({ ...step, needsApproval: step.needsApproval === true, status: "pending" as const, attempts: 0, error: null, })), usageCostMicrocents: 0, usageSteps: 0, percent: 0, cancelRequested: false, answer: null, answerProvenance: null, actorId: "user-1", createdAt: "2026-11-02T10:00:00.000Z", startedAt: null, finishedAt: null, } const record = (status: AgentRunRecord["status"]): AgentRunRecord => ({ id: RUN, version: 1, status, failureCode: null, failureDetail: null, goal: seed.goal, plan: PLAN, actorId: "user-1", budget: { maxCostMicrocents: 1_000_000, maxSteps: 10, maxDurationSeconds: 600 }, usageCostMicrocents: 0, usageSteps: 0, cancelRequestedAt: null, startedAt: "2026-11-02T10:00:01.000Z", finishedAt: null, createdAt: seed.createdAt, answerProvenance: null, }) const step = ( index: number, status: AgentStepRecord["status"], approval: AgentStepRecord["approval"] = null, ): AgentStepRecord => ({ id: `s-${index}`, runId: RUN, key: PLAN[index]?.key ?? "missing", index, label: PLAN[index]?.label ?? "missing", status, attempts: 1, usageCostMicrocents: 0, usageTokens: 0, error: null, externalEffect: false, artifacts: [], result: null, approval, startedAt: null, finishedAt: null, }) const parked = { actionId: null, tool: "orders.create", arguments: { total: 4200 }, reviewUrl: null, interrupt: { id: "approval_c-1", runId: `${RUN}.chat` }, decision: null, } const fold = (events: readonly unknown[]) => (events as AgUiChunk[]).reduce(reduceAgentRunEvent, initialAgentRunView(RUN)) describe("the live run state", () => { it("is the seed until the first event", () => { const state = liveRunState(seed, initialAgentRunView(RUN)) expect(state.status).toBe("queued") expect(state.steps.map((s) => s.status)).toEqual(["pending", "pending"]) expect(state.answer).toBeNull() }) it("follows the run's events: a committed step, then a parked approval", () => { const view = fold(runEventsOf(record("awaiting_approval"), [step(0, "committed"), step(1, "pending", parked)])) const state = liveRunState(seed, view) expect(state.status).toBe("awaiting_approval") expect(state.steps.map((s) => s.status)).toEqual(["committed", "pending"]) expect(state.percent).toBe(0.5) }) it("shows a completed run's answer and a failed run's code", () => { const done = fold( runEventsOf( record("completed"), [step(0, "committed"), step(1, "committed", { ...parked, decision: "approved" })], "Ordered.", ), ) expect(liveRunState(seed, done)).toMatchObject({ status: "completed", percent: 1, answer: "Ordered." }) const failed = fold( runEventsOf( { ...record("failed"), failureCode: "budget_exhausted", failureDetail: "the run reached its budget" }, [step(0, "committed")], ), ) expect(liveRunState(seed, failed)).toMatchObject({ status: "failed", failureCode: "budget_exhausted", answer: null, }) }) it("names a lost stream and keeps the last state it knew", () => { const view = { ...fold(runEventsOf(record("running"), [step(0, "committed")])), error: { source: "transport" as const, code: "reconnect_limit", message: "gone", status: null }, } const state = liveRunState(seed, view) expect(state.streamError).toBe("reconnect_limit") expect(state.steps[0]?.status).toBe("committed") }) }) describe("the live run island", () => { const catalogues = buildRegistry([...appModules]).catalogues const i18n = createI18n("en", { en: { agent: catalogues.en?.agent ?? {} } }) const t = (key: string) => i18n.message(`agent.${key}`) const labels = { status: t("runs.status"), progress: t("runs.progress"), plan: t("runs.plan"), step: t("runs.step"), tool: t("runs.tool"), needsApproval: t("runs.needsApproval"), answer: t("runs.answer"), answerDisclosure: t("runs.answerDisclosure"), streamLost: t("runs.streamLost"), statuses: { queued: t("runs.statusQueued"), running: t("runs.statusRunning"), awaiting_approval: t("runs.statusAwaitingApproval"), completed: t("runs.statusCompleted"), failed: t("runs.statusFailed"), cancelled: t("runs.statusCancelled"), uncertain: t("runs.statusUncertain"), }, stepStatuses: { pending: t("runs.stepPending"), committed: t("runs.stepCommitted"), failed: t("runs.stepFailed"), cancelled: t("runs.stepCancelled"), uncertain: t("runs.stepUncertain"), }, controls: { cancel: t("runs.cancel"), cancelling: t("runs.cancelling"), failedHint: t("recovery.failedHint"), cancelledHint: t("recovery.cancelledHint"), uncertainHint: t("recovery.uncertainHint"), budgetExhausted: t("recovery.budgetExhausted"), approvalUnavailable: t("recovery.approvalUnavailable"), toolError: t("recovery.toolError"), planRefused: t("recovery.planRefused"), internal: t("recovery.internal"), }, } const render = (run: RunView) => renderToStaticMarkup( new Response(null, { status: 501 }) })}> , ) it("renders the seed on the server, the approval mark on a gated step, and no answer yet", () => { const html = render(seed) expect(html).toContain(labels.statuses.queued) expect(html).toContain(labels.needsApproval) expect(html).not.toContain(labels.answer) }) it("renders a completed run's answer with the AI disclosure", () => { const html = render({ ...seed, status: "completed", answer: "Ordered the parts." }) expect(html).toContain("Ordered the parts.") expect(html).toContain(labels.answerDisclosure.replaceAll("'", "'")) }) })