fix(ui): stream phase progress without gates

This commit is contained in:
2026-08-24 12:10:56 +02:00
parent 36a7a0ab33
commit fa2298653b
10 changed files with 186 additions and 5 deletions
+1 -1
View File
@@ -98,7 +98,7 @@ export type StreamEvent =
}
| { type: "usage"; usage: TokenUsage }
| { type: "info"; level?: "info" | "warning" | "error"; text: string }
| { type: "system_event"; event: string };
| { type: "system_event"; event: string; phase?: string };
export interface SessionSummary {
id: string;
+12
View File
@@ -29,6 +29,18 @@ test("dots carry done / running / pending states around the active phase", () =>
expect(screen.getByTestId("phase-F5")).toHaveAttribute("data-state", "pending");
});
test("phase_started colors a phase even when no human gate was rendered", () => {
const store = useSessionStore.getState();
store.setPhase("F1");
store.applyEvent({ type: "system_event", event: "phase_started", phase: "F2" });
render(<WorkflowBar />);
expect(screen.getByTestId("phase-F1")).toHaveAttribute("data-state", "done");
expect(screen.getByTestId("phase-F2")).toHaveAttribute("data-state", "running");
expect(screen.getByTestId("phase-F3")).toHaveAttribute("data-state", "pending");
});
test("the active dot turns to the error state when phaseError flags it", () => {
const st = useSessionStore.getState();
st.applyEvent({ type: "ui_request", ui_request: { id: "u", widget: "select", phase: "F3_x" } });
+13
View File
@@ -184,6 +184,19 @@ test("ui_request without a phase keeps the existing currentPhase", () => {
expect(useSessionStore.getState().currentPhase).toBe("F2");
});
test("phase_started advances progress even when the phase has no human gate", () => {
const store = useSessionStore.getState();
store.setPhase("F1");
store.applyEvent({
type: "system_event",
event: "phase_started",
phase: "F2_memory",
});
expect(useSessionStore.getState().currentPhase).toBe("F2");
});
test("agentActive lifecycle: off by default, on with activity, off on agent_end", () => {
const st = useSessionStore.getState();
expect(useSessionStore.getState().agentActive).toBe(false);
+13 -1
View File
@@ -176,14 +176,26 @@ export const useSessionStore = create<SessionState>((set) => ({
: { stepMessages, activityLog };
}
if (e.type === "system_event") {
const currentPhase = e.event === "phase_started"
? phaseOf(e.phase, st.currentPhase)
: st.currentPhase;
const activityLog = [
...st.activityLog,
{
kind: "lifecycle" as const,
phase: st.currentPhase,
phase: currentPhase,
text: lifecycleText(e.event),
},
];
if (e.event === "phase_started") {
return {
lastSystemEvent: e,
activityLog,
currentPhase,
phaseError: null,
agentActive: true,
};
}
return e.event === "agent_end"
? { lastSystemEvent: e, activityLog, agentActive: false }
: { lastSystemEvent: e, activityLog };