feat: support explicit live demo launch
This commit is contained in:
@@ -109,6 +109,37 @@ describe("useTimelineAgent", () => {
|
||||
expect(start).toHaveBeenCalledWith("replay");
|
||||
});
|
||||
|
||||
it("starts live explicitly from a direct replay view when the target is ready", async () => {
|
||||
const start = vi.fn();
|
||||
const demo = demoController({
|
||||
state: { ...initialDemoTimelineState, mode: "replay" },
|
||||
start,
|
||||
});
|
||||
|
||||
const { result } = renderHook(() => useTimelineAgent(demo, {
|
||||
mode: "live",
|
||||
status: replayStatus,
|
||||
liveTargetReady: true,
|
||||
}));
|
||||
|
||||
expect(result.current.canRunLive).toBe(true);
|
||||
await act(async () => result.current.runPreparedWorkflow("live"));
|
||||
|
||||
expect(start).toHaveBeenCalledWith("live");
|
||||
});
|
||||
|
||||
it("does not offer an explicit live launch when health has failed", () => {
|
||||
const start = vi.fn();
|
||||
const demo = demoController({ start });
|
||||
const { result } = renderHook(() => useTimelineAgent(demo, {
|
||||
mode: "live",
|
||||
status: failedStatus,
|
||||
liveTargetReady: false,
|
||||
}));
|
||||
|
||||
expect(result.current.canRunLive).toBe(false);
|
||||
});
|
||||
|
||||
it("submits selected issues from the current interrupt payload", async () => {
|
||||
const submitSelectedIssues = vi.fn(async () => {});
|
||||
const demo = demoController({
|
||||
|
||||
@@ -14,13 +14,15 @@ export type TimelineAgentMode = "live" | "replay";
|
||||
export type TimelineAgentOptions = {
|
||||
readonly mode: TimelineAgentMode;
|
||||
readonly status: PresentationTargetHealth;
|
||||
readonly liveTargetReady?: boolean | undefined;
|
||||
};
|
||||
|
||||
export type TimelineAgentController = {
|
||||
readonly messages: ReadonlyArray<AgentMessage>;
|
||||
readonly canRun: boolean;
|
||||
readonly canRunLive: boolean;
|
||||
readonly runLabel: string;
|
||||
readonly runPreparedWorkflow: () => Promise<void>;
|
||||
readonly runPreparedWorkflow: (mode?: TimelineAgentMode) => Promise<void>;
|
||||
readonly submitSelectedIssues: () => Promise<void>;
|
||||
readonly requestRevision: () => Promise<void>;
|
||||
};
|
||||
@@ -89,18 +91,23 @@ export const useTimelineAgent = (
|
||||
|
||||
const runLabel = modeLabel === "live" ? "Run prepared workflow" : "Run replay walkthrough";
|
||||
const canRun = demo.canStart && !demo.inFlight && demo.state.phase !== "running";
|
||||
const canRunLive = (options.liveTargetReady ?? (options.mode === "live" && (
|
||||
options.status.kind === "ready" || options.status.kind === "active"
|
||||
))) && !demo.inFlight && demo.state.phase !== "running";
|
||||
|
||||
const runPreparedWorkflow = useCallback(async () => {
|
||||
const runPreparedWorkflow = useCallback(async (requestedMode?: TimelineAgentMode) => {
|
||||
const mode = requestedMode ?? modeLabel;
|
||||
if (mode === "live" && !canRunLive) return;
|
||||
if (!demo.canStart || demo.inFlight || demo.state.phase === "running") return;
|
||||
demo.start(modeLabel);
|
||||
demo.start(mode);
|
||||
setMessages((current) => appendToolMessage(
|
||||
current,
|
||||
"timeline-agent-start",
|
||||
"startRun",
|
||||
{ mode: modeLabel },
|
||||
{ mode },
|
||||
{ phase: "started" },
|
||||
));
|
||||
}, [demo, modeLabel]);
|
||||
}, [canRunLive, demo, modeLabel]);
|
||||
|
||||
const selectedIssueIds = useMemo(
|
||||
() => demo.interruptPayload?.proposed_issues.map((issue) => issue.id) ?? [],
|
||||
@@ -135,6 +142,7 @@ export const useTimelineAgent = (
|
||||
return {
|
||||
messages,
|
||||
canRun,
|
||||
canRunLive,
|
||||
runLabel,
|
||||
runPreparedWorkflow,
|
||||
submitSelectedIssues,
|
||||
|
||||
@@ -191,6 +191,7 @@ describe("OperatorChat", () => {
|
||||
timelineAgent={{
|
||||
messages: [],
|
||||
canRun: true,
|
||||
canRunLive: true,
|
||||
runLabel: "Run prepared workflow",
|
||||
runPreparedWorkflow,
|
||||
submitSelectedIssues: vi.fn(async () => {}),
|
||||
@@ -236,6 +237,7 @@ describe("OperatorChat", () => {
|
||||
timelineAgent={{
|
||||
messages: [],
|
||||
canRun: false,
|
||||
canRunLive: false,
|
||||
runLabel: "Run prepared workflow",
|
||||
runPreparedWorkflow: vi.fn(async () => {}),
|
||||
submitSelectedIssues,
|
||||
|
||||
@@ -59,6 +59,7 @@ export const PresentationRoute = () => {
|
||||
const timelineAgent = useTimelineAgent(demo, {
|
||||
mode: presentationTarget.mode === "live" ? "live" : "replay",
|
||||
status: targetStatus,
|
||||
liveTargetReady: targetStatusController.liveTargetReady,
|
||||
});
|
||||
const requiredDemoStage = state.location.kind === "main"
|
||||
? requirementForDemoBeat(state.location.sceneId, state.location.beatId).requiredStage
|
||||
|
||||
Reference in New Issue
Block a user