fix(ui): stream phase progress without gates
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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" } });
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 };
|
||||
|
||||
Reference in New Issue
Block a user