refactor: make scene 8 a single chat entry beat
This commit is contained in:
@@ -22,12 +22,12 @@
|
|||||||
|
|
||||||
## Task 1: Remove The Redundant Scene 8 Handoff Beat
|
## Task 1: Remove The Redundant Scene 8 Handoff Beat
|
||||||
|
|
||||||
- [ ] Write failing storyboard/navigation and Scene 8 tests before changing the catalog. Cover the single-beat count, valid request hash, invalid/removed handoff hash fallback, and footer progress.
|
- [x] Write failing storyboard/navigation and Scene 8 tests before changing the catalog. Cover the single-beat count, valid request hash, invalid/removed handoff hash fallback, and footer progress.
|
||||||
- [ ] Modify `web/apps/console/src/presentation/storyboard.ts` so `agent-handoff` contains only the `request` beat. Update its caption/title wording if needed so it describes the request-to-first-turn interaction rather than a separate durable-work handoff.
|
- [x] Modify `web/apps/console/src/presentation/storyboard.ts` so `agent-handoff` contains only the `request` beat. Update its caption/title wording if needed so it describes the request-to-first-turn interaction rather than a separate durable-work handoff.
|
||||||
- [ ] Simplify `AgentHandoffScene.tsx` and its tests: remove the `handoff` branch, deployment projection, and any comments claiming Scene 8 renders the full authoring transcript. Keep the local empty/submitted reducer and `Scene8ChatEntry` behavior.
|
- [x] Simplify `AgentHandoffScene.tsx` and its tests: remove the `handoff` branch, deployment projection, and any comments claiming Scene 8 renders the full authoring transcript. Keep the local empty/submitted reducer and `Scene8ChatEntry` behavior.
|
||||||
- [ ] Remove stale `/handoff` references from `PresentationRoute.test.tsx`, `SceneBody.test.tsx`, `web/README.md`, and nearby docs. Do not add a compatibility alias for a route that has no real persisted/external contract; invalid hashes should use the existing fail-closed default.
|
- [x] Remove stale `/handoff` references from `PresentationRoute.test.tsx`, `SceneBody.test.tsx`, `web/README.md`, and nearby docs. Do not add a compatibility alias for a route that has no real persisted/external contract; invalid hashes should use the existing fail-closed default.
|
||||||
- [ ] Confirm the full authoring conversation remains available through Scene 9 and is not deleted with the route cleanup.
|
- [x] Confirm the full authoring conversation remains available through Scene 9 and is not deleted with the route cleanup.
|
||||||
- [ ] Run focused storyboard, route, and Scene 8 tests plus typecheck. Commit as `refactor: make scene 8 a single chat entry beat`.
|
- [x] Run focused storyboard, route, and Scene 8 tests plus typecheck. Commit as `refactor: make scene 8 a single chat entry beat`.
|
||||||
|
|
||||||
## Task 2: Vendor And Validate The Assistant Thread Surface
|
## Task 2: Vendor And Validate The Assistant Thread Surface
|
||||||
|
|
||||||
|
|||||||
@@ -97,8 +97,8 @@ When Send is activated with non-empty text:
|
|||||||
The send action must not call `workflow.runs.start`, `workflow.runs.resume`, or
|
The send action must not call `workflow.runs.start`, `workflow.runs.resume`, or
|
||||||
any other workflow RPC. It is a scripted presentation entry event.
|
any other workflow RPC. It is a scripted presentation entry event.
|
||||||
|
|
||||||
If the presenter advances with `ArrowRight`, the existing storyboard location
|
Scene 8 has no second handoff beat. Advancing with `ArrowRight` moves directly
|
||||||
changes to `#scene/agent-handoff/handoff`, and the full prepared authoring
|
to Scene 9's first lifecycle beat, where the full prepared authoring
|
||||||
conversation becomes visible through the existing phase projection.
|
conversation becomes visible through the existing phase projection.
|
||||||
|
|
||||||
If the composer is empty or contains only whitespace, Send is disabled and no
|
If the composer is empty or contains only whitespace, Send is disabled and no
|
||||||
@@ -176,8 +176,6 @@ encoded in the URL hash.
|
|||||||
- Whitespace-only draft: treated as blank.
|
- Whitespace-only draft: treated as blank.
|
||||||
- Send while already submitted: disabled or ignored; it must not duplicate the
|
- Send while already submitted: disabled or ignored; it must not duplicate the
|
||||||
prepared conversation.
|
prepared conversation.
|
||||||
- Direct navigation to the handoff beat: render the full prepared conversation
|
|
||||||
without requiring the request-beat send transition.
|
|
||||||
- Missing recording data: preserve the existing bounded presentation fallback
|
- Missing recording data: preserve the existing bounded presentation fallback
|
||||||
and render an explicit unavailable state rather than inventing a live result.
|
and render an explicit unavailable state rather than inventing a live result.
|
||||||
|
|
||||||
@@ -191,13 +189,11 @@ Add or update tests for:
|
|||||||
3. sending reveals the prepared request/assistant/Discover content and does not
|
3. sending reveals the prepared request/assistant/Discover content and does not
|
||||||
call workflow RPC operations;
|
call workflow RPC operations;
|
||||||
4. sending twice does not duplicate the first conversation;
|
4. sending twice does not duplicate the first conversation;
|
||||||
5. direct navigation to the handoff beat still renders the full prepared
|
5. Scene 8 no longer renders the standalone `Run prepared workflow` button or
|
||||||
conversation;
|
|
||||||
6. Scene 8 no longer renders the standalone `Run prepared workflow` button or
|
|
||||||
the old phase rail;
|
the old phase rail;
|
||||||
7. 1280x720 and 1024x768 browser smoke captures show the composer without
|
6. 1280x720 and 1024x768 browser smoke captures show the composer without
|
||||||
clipping or horizontal overflow;
|
clipping or horizontal overflow;
|
||||||
8. reduced-motion mode does not hide the submitted conversation.
|
7. reduced-motion mode does not hide the submitted conversation.
|
||||||
|
|
||||||
## Out Of Scope
|
## Out Of Scope
|
||||||
|
|
||||||
@@ -214,6 +210,6 @@ Add or update tests for:
|
|||||||
|
|
||||||
The slice is complete when the presenter can open
|
The slice is complete when the presenter can open
|
||||||
`#scene/agent-handoff/request`, see a credible full-screen chat entry, press
|
`#scene/agent-handoff/request`, see a credible full-screen chat entry, press
|
||||||
Send, see the first prepared authoring turn, advance to the handoff beat, and
|
Send, see the first prepared authoring turn, and continue directly into Scene 9
|
||||||
continue into Scene 9 without a standalone run button or a second chat state
|
without a standalone run button or a second chat state runtime. The behavior is
|
||||||
runtime. The behavior is covered by focused tests and 16:9/4:3 browser smoke.
|
covered by focused tests and 16:9/4:3 browser smoke.
|
||||||
|
|||||||
+10
-12
@@ -180,12 +180,12 @@ claim boundaries and future work explicit, and end on the canonical defense
|
|||||||
discussion index rather than a benchmark or generic conclusion.
|
discussion index rather than a benchmark or generic conclusion.
|
||||||
|
|
||||||
Scenes 8 and 9 use the canonical prepared-authoring recording as their only
|
Scenes 8 and 9 use the canonical prepared-authoring recording as their only
|
||||||
execution evidence. Scene 8 is a full-screen chat entry: its prefilled request
|
execution evidence. Scene 8 is a single full-screen chat-entry beat: its
|
||||||
is submitted locally, then reveals the first deterministic user, assistant, and
|
prefilled request is submitted locally, then reveals the first deterministic
|
||||||
Discover tool group. It is deterministic replay, not a live LLM chat, and does
|
user, assistant, and Discover tool group. It is deterministic replay, not a live
|
||||||
not start a workflow run. The handoff beat reveals the full prepared conversation;
|
LLM chat, and does not start a workflow run. Scene 9 breaks the prepared
|
||||||
Scene 9 breaks the prepared authoring into five phases
|
authoring into five phases with the same conversation contracted into a
|
||||||
with the same conversation contracted into a synchronized bottom dock. Each
|
synchronized bottom dock. Each
|
||||||
phase opens its matching prepared tool group beneath a factual source, graph,
|
phase opens its matching prepared tool group beneath a factual source, graph,
|
||||||
repair, artifact, or deployment view. Neither scene calls workflow authoring
|
repair, artifact, or deployment view. Neither scene calls workflow authoring
|
||||||
RPC operations — they consume deterministic prepared data. Scenes 10 through
|
RPC operations — they consume deterministic prepared data. Scenes 10 through
|
||||||
@@ -203,8 +203,7 @@ presentation timeline.
|
|||||||
|
|
||||||
The key deep-link-addressable defense states include:
|
The key deep-link-addressable defense states include:
|
||||||
|
|
||||||
- `/present#scene/agent-handoff/request` — Scene 8, prepared handoff request
|
- `/present#scene/agent-handoff/request` — Scene 8, prepared authoring request
|
||||||
- `/present#scene/agent-handoff/handoff` — Scene 8, agent accepts
|
|
||||||
- `/present#scene/prepared-lifecycle/discover` — Scene 9, discover phase
|
- `/present#scene/prepared-lifecycle/discover` — Scene 9, discover phase
|
||||||
- `/present#scene/prepared-lifecycle/draft` — Scene 9, draft phase
|
- `/present#scene/prepared-lifecycle/draft` — Scene 9, draft phase
|
||||||
- `/present#scene/prepared-lifecycle/deployment` — Scene 9, deployment phase
|
- `/present#scene/prepared-lifecycle/deployment` — Scene 9, deployment phase
|
||||||
@@ -333,11 +332,10 @@ Scenes 8 and 9 are the prepared authoring story. They use deterministic data
|
|||||||
from the committed `projectPreparedAuthoring()` recording and never call
|
from the committed `projectPreparedAuthoring()` recording and never call
|
||||||
workflow authoring RPC operations.
|
workflow authoring RPC operations.
|
||||||
|
|
||||||
- **Scene 8 (Agent Handoff)**: a full-screen deterministic chat entry that
|
- **Scene 8 (Agent Request)**: a single full-screen deterministic chat entry that
|
||||||
pre-fills the report-authoring request. Send is local presentation state and
|
pre-fills the report-authoring request. Send is local presentation state and
|
||||||
reveals the first prepared Discover tool group; the `handoff` beat reveals
|
reveals the first prepared Discover tool group. This is not a live LLM chat
|
||||||
the full completed conversation with prepared `wf` tool groups across all
|
or workflow run.
|
||||||
authoring phases. This is not a live LLM chat or workflow run.
|
|
||||||
- **Scene 9 (Prepared Workflow Lifecycle)**: a five-phase lifecycle
|
- **Scene 9 (Prepared Workflow Lifecycle)**: a five-phase lifecycle
|
||||||
(discover, draft, validate, artifact, deployment) with a compact phase rail
|
(discover, draft, validate, artifact, deployment) with a compact phase rail
|
||||||
and one dominant factual product projection per beat. The Scene 8 thread
|
and one dominant factual product projection per beat. The Scene 8 thread
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ describe("PresentationRoute", () => {
|
|||||||
render(<PresentationRoute />);
|
render(<PresentationRoute />);
|
||||||
expect(screen.getByRole("textbox", { name: /authoring request/i })).toBeInTheDocument();
|
expect(screen.getByRole("textbox", { name: /authoring request/i })).toBeInTheDocument();
|
||||||
await userEvent.keyboard("{ArrowRight}");
|
await userEvent.keyboard("{ArrowRight}");
|
||||||
expect(await screen.findByRole("button", { name: /deployment.*2 tool calls/i })).toBeInTheDocument();
|
expect(await screen.findByLabelText("authoring phase rail")).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("renders audience progress chrome without rail or mode label", async () => {
|
it("renders audience progress chrome without rail or mode label", async () => {
|
||||||
@@ -467,15 +467,6 @@ describe("PresentationRoute", () => {
|
|||||||
expect(screen.getByRole("button", { name: /discover.*4 tool calls/i })).toBeInTheDocument();
|
expect(screen.getByRole("button", { name: /discover.*4 tool calls/i })).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("navigates to Scene 8 handoff beat via hash", async () => {
|
|
||||||
window.location.hash = "#scene/agent-handoff/handoff";
|
|
||||||
const { PresentationRoute } = await import("./PresentationRoute.js");
|
|
||||||
render(<PresentationRoute />);
|
|
||||||
|
|
||||||
expect(await screen.findByRole("log", { name: "prepared authoring conversation" })).toBeInTheDocument();
|
|
||||||
expect(screen.getByRole("button", { name: /deployment.*2 tool calls/i })).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
|
|
||||||
it.each([
|
it.each([
|
||||||
"#scene/prepared-lifecycle/discover",
|
"#scene/prepared-lifecycle/discover",
|
||||||
"#scene/prepared-lifecycle/draft",
|
"#scene/prepared-lifecycle/draft",
|
||||||
|
|||||||
@@ -439,11 +439,11 @@ describe("SceneBody", () => {
|
|||||||
expect(screen.getAllByText(/lda_report_case_study/i).length).toBeGreaterThanOrEqual(1);
|
expect(screen.getAllByText(/lda_report_case_study/i).length).toBeGreaterThanOrEqual(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("routes Scene 8 through the prepared authoring conversation", () => {
|
it("renders Scene 8 as the request entry beat", () => {
|
||||||
renderSceneBodyAtMainLocation("agent-handoff", "handoff");
|
renderSceneBodyAtMainLocation("agent-handoff", "request");
|
||||||
|
|
||||||
expect(screen.getByRole("log", { name: "prepared authoring conversation" })).toBeInTheDocument();
|
expect(screen.getByRole("textbox", { name: /authoring request/i })).toBeInTheDocument();
|
||||||
expect(screen.getByRole("button", { name: /deployment.*2 tool calls/i })).toBeInTheDocument();
|
expect(screen.queryByRole("button", { name: /deployment.*2 tool calls/i })).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("renders evidence before discussion links so the chip lane cannot cover evidence text", () => {
|
it("renders evidence before discussion links so the chip lane cannot cover evidence text", () => {
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ import { findBeat, findScene } from "../storyboard.js";
|
|||||||
import { AgentHandoffScene } from "./AgentHandoffScene.js";
|
import { AgentHandoffScene } from "./AgentHandoffScene.js";
|
||||||
import { SCENE8_REQUEST } from "./scene8-entry-state.js";
|
import { SCENE8_REQUEST } from "./scene8-entry-state.js";
|
||||||
|
|
||||||
const renderBeat = (beatId: "request" | "handoff") => {
|
const renderRequestBeat = () => {
|
||||||
const scene = findScene("agent-handoff");
|
const scene = findScene("agent-handoff");
|
||||||
const beat = findBeat("agent-handoff", beatId);
|
const beat = findBeat("agent-handoff", "request");
|
||||||
if (!scene || !beat) throw new Error(`missing agent-handoff/${beatId}`);
|
if (!scene || !beat) throw new Error("missing agent-handoff/request");
|
||||||
return render(<AgentHandoffScene scene={scene} beat={beat} />);
|
return render(<AgentHandoffScene scene={scene} beat={beat} />);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -23,11 +23,11 @@ describe("AgentHandoffScene", () => {
|
|||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(screen.getByRole("region", { name: "prepared agent handoff" })).toHaveAttribute(
|
expect(screen.getByRole("region", { name: "prepared agent request" })).toHaveAttribute(
|
||||||
"data-handoff-phase",
|
"data-handoff-phase",
|
||||||
"discover",
|
"discover",
|
||||||
);
|
);
|
||||||
expect(screen.getByRole("region", { name: "prepared agent handoff" })).toHaveAttribute(
|
expect(screen.getByRole("region", { name: "prepared agent request" })).toHaveAttribute(
|
||||||
"data-presentation-surface",
|
"data-presentation-surface",
|
||||||
"editorial",
|
"editorial",
|
||||||
);
|
);
|
||||||
@@ -37,46 +37,17 @@ describe("AgentHandoffScene", () => {
|
|||||||
expect(screen.queryByRole("button", { name: /run prepared workflow/i })).not.toBeInTheDocument();
|
expect(screen.queryByRole("button", { name: /run prepared workflow/i })).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("advances the same conversation to deployment evidence", () => {
|
|
||||||
render(
|
|
||||||
<AgentHandoffScene
|
|
||||||
scene={findScene("agent-handoff")!}
|
|
||||||
beat={findBeat("agent-handoff", "handoff")!}
|
|
||||||
/>,
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(screen.getByRole("region", { name: "prepared agent handoff" })).toHaveAttribute(
|
|
||||||
"data-handoff-phase",
|
|
||||||
"deployment",
|
|
||||||
);
|
|
||||||
expect(screen.getAllByText(/workflow\.deployments\.save/i).length).toBeGreaterThan(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("reveals separated user and assistant turns after local submission", async () => {
|
it("reveals separated user and assistant turns after local submission", async () => {
|
||||||
renderBeat("request");
|
renderRequestBeat();
|
||||||
await userEvent.click(screen.getByRole("button", { name: "Send" }));
|
await userEvent.click(screen.getByRole("button", { name: "Send" }));
|
||||||
expect(screen.getAllByText(/report|workflow|prepare/i).length).toBeGreaterThanOrEqual(1);
|
expect(screen.getAllByText(/report|workflow|prepare/i).length).toBeGreaterThanOrEqual(1);
|
||||||
expect(screen.getAllByText(/inspect|capabilities|sources|schemas|let me/i).length).toBeGreaterThanOrEqual(1);
|
expect(screen.getAllByText(/inspect|capabilities|sources|schemas|let me/i).length).toBeGreaterThanOrEqual(1);
|
||||||
expect(screen.getByRole("button", { name: /discover.*4 tool calls/i })).toBeInTheDocument();
|
expect(screen.getByRole("button", { name: /discover.*4 tool calls/i })).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("interleaves prepared workflow tool groups with the handoff conversation", () => {
|
|
||||||
renderBeat("handoff");
|
|
||||||
expect(screen.getAllByText(/workflow\.deployments\.save/i).length).toBeGreaterThan(0);
|
|
||||||
expect(screen.getByRole("button", { name: /deployment.*2 tool calls/i }))
|
|
||||||
.toHaveAttribute("aria-expanded", "true");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("does not render prepared workflow lifecycle content", () => {
|
it("does not render prepared workflow lifecycle content", () => {
|
||||||
renderBeat("request");
|
renderRequestBeat();
|
||||||
expect(screen.queryByText("prepared workflow lifecycle")).not.toBeInTheDocument();
|
expect(screen.queryByText("prepared workflow lifecycle")).not.toBeInTheDocument();
|
||||||
cleanup();
|
|
||||||
renderBeat("handoff");
|
|
||||||
expect(screen.queryByText("prepared workflow lifecycle")).not.toBeInTheDocument();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("does not expose a workflow run action", () => {
|
|
||||||
renderBeat("handoff");
|
|
||||||
expect(screen.queryByRole("button", { name: /run prepared workflow/i })).not.toBeInTheDocument();
|
expect(screen.queryByRole("button", { name: /run prepared workflow/i })).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { useReducer } from "react";
|
import { useReducer } from "react";
|
||||||
import { AuthoringConversation } from "./AuthoringConversation.js";
|
|
||||||
import { Scene8ChatEntry } from "./Scene8ChatEntry.js";
|
import { Scene8ChatEntry } from "./Scene8ChatEntry.js";
|
||||||
import {
|
import {
|
||||||
initialScene8EntryState,
|
initialScene8EntryState,
|
||||||
@@ -12,32 +11,17 @@ type AgentHandoffSceneProps = {
|
|||||||
readonly beat: SceneBeatDefinition;
|
readonly beat: SceneBeatDefinition;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Scene 8 request and handoff beats share one local deterministic entry state.
|
|
||||||
*/
|
|
||||||
export const AgentHandoffScene = ({ beat }: AgentHandoffSceneProps) => {
|
export const AgentHandoffScene = ({ beat }: AgentHandoffSceneProps) => {
|
||||||
const [entryState, dispatch] = useReducer(scene8EntryReducer, initialScene8EntryState);
|
const [entryState, dispatch] = useReducer(scene8EntryReducer, initialScene8EntryState);
|
||||||
const phase = beat.id === "handoff" ? "deployment" : "discover";
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section
|
<section
|
||||||
className="agent-handoff-scene"
|
className="agent-handoff-scene"
|
||||||
aria-label="prepared agent handoff"
|
aria-label="prepared agent request"
|
||||||
data-handoff-phase={phase}
|
data-handoff-phase="discover"
|
||||||
data-presentation-surface="editorial"
|
data-presentation-surface="editorial"
|
||||||
>
|
>
|
||||||
{beat.id === "request" ? (
|
{beat.id === "request" && <Scene8ChatEntry state={entryState} dispatch={dispatch} />}
|
||||||
<Scene8ChatEntry state={entryState} dispatch={dispatch} />
|
|
||||||
) : (
|
|
||||||
<div className="agent-handoff-scene__handoff">
|
|
||||||
<AuthoringConversation
|
|
||||||
throughPhase="deployment"
|
|
||||||
activePhase="deployment"
|
|
||||||
surface="stage"
|
|
||||||
{...(entryState.phase === "submitted" ? { requestOverride: entryState.request } : {})}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -157,7 +157,6 @@ const beatContracts = {
|
|||||||
"authoring/diagnose": { mode: "evidence", primarySurface: "authoring-diagnostic", supportSurface: "authoring-loop" },
|
"authoring/diagnose": { mode: "evidence", primarySurface: "authoring-diagnostic", supportSurface: "authoring-loop" },
|
||||||
"authoring/repair": { mode: "evidence", primarySurface: "authoring-repair", supportSurface: "authoring-loop" },
|
"authoring/repair": { mode: "evidence", primarySurface: "authoring-repair", supportSurface: "authoring-loop" },
|
||||||
"agent-handoff/request": { mode: "conversation", primarySurface: "prepared-conversation", supportSurface: "none" },
|
"agent-handoff/request": { mode: "conversation", primarySurface: "prepared-conversation", supportSurface: "none" },
|
||||||
"agent-handoff/handoff": { mode: "conversation", primarySurface: "prepared-conversation", supportSurface: "none" },
|
|
||||||
"evaluation/cohort": { mode: "evidence", primarySurface: "evaluation-cohort", supportSurface: "none" },
|
"evaluation/cohort": { mode: "evidence", primarySurface: "evaluation-cohort", supportSurface: "none" },
|
||||||
"evaluation/validity": { mode: "evidence", primarySurface: "evaluation-validity", supportSurface: "audit-reconciliation" },
|
"evaluation/validity": { mode: "evidence", primarySurface: "evaluation-validity", supportSurface: "audit-reconciliation" },
|
||||||
"evaluation/findings": { mode: "evidence", primarySurface: "evaluation-findings", supportSurface: "validity-boundary" },
|
"evaluation/findings": { mode: "evidence", primarySurface: "evaluation-findings", supportSurface: "validity-boundary" },
|
||||||
|
|||||||
@@ -3006,22 +3006,6 @@
|
|||||||
color: var(--authoring-ink, var(--text-primary));
|
color: var(--authoring-ink, var(--text-primary));
|
||||||
}
|
}
|
||||||
|
|
||||||
.agent-handoff-scene__handoff {
|
|
||||||
min-height: 0;
|
|
||||||
height: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.agent-handoff-scene__handoff .assistant-operator-thread {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
max-height: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.agent-handoff-scene__handoff .assistant-thread__viewport {
|
|
||||||
padding: 1rem 1.2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.agent-handoff-scene__composer {
|
.agent-handoff-scene__composer {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 0.75rem;
|
gap: 0.75rem;
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ describe("storyboard navigation", () => {
|
|||||||
it("falls back for unknown scene, beat, and branch hashes", () => {
|
it("falls back for unknown scene, beat, and branch hashes", () => {
|
||||||
expect(locationFromHash("#scene/missing/nope")).toEqual(defaultMainLocation);
|
expect(locationFromHash("#scene/missing/nope")).toEqual(defaultMainLocation);
|
||||||
expect(locationFromHash("#scene/lifecycle/nope")).toEqual(defaultMainLocation);
|
expect(locationFromHash("#scene/lifecycle/nope")).toEqual(defaultMainLocation);
|
||||||
|
expect(locationFromHash("#scene/agent-handoff/handoff")).toEqual(defaultMainLocation);
|
||||||
expect(locationFromHash("#discuss/nope")).toEqual(defaultMainLocation);
|
expect(locationFromHash("#discuss/nope")).toEqual(defaultMainLocation);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ describe("defense storyboard catalog", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("uses one editorial canvas theme and independent chat composition", () => {
|
it("uses one editorial canvas theme and independent chat composition", () => {
|
||||||
|
expect(findScene("agent-handoff")?.beats).toHaveLength(1);
|
||||||
expect(findBeat("agent-handoff", "request")?.chatMode).toBe("hidden");
|
expect(findBeat("agent-handoff", "request")?.chatMode).toBe("hidden");
|
||||||
expect(findBeat("resume-output-evidence", "trace")?.chatMode).toBe("hidden");
|
expect(findBeat("resume-output-evidence", "trace")?.chatMode).toBe("hidden");
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -154,15 +154,12 @@ export const mainScenes = defineScenes([
|
|||||||
{
|
{
|
||||||
id: "agent-handoff",
|
id: "agent-handoff",
|
||||||
number: 8,
|
number: 8,
|
||||||
title: "Agent Handoff",
|
title: "Agent Request",
|
||||||
claimClass: "implemented",
|
claimClass: "implemented",
|
||||||
evidencePointer: "Constrained demo agent and prepared replay recipe",
|
evidencePointer: "Constrained demo agent and prepared replay recipe",
|
||||||
view: "agent",
|
view: "agent",
|
||||||
beats: [
|
beats: [
|
||||||
// Scene 8 renders its own full-screen prepared transcript in the primary
|
|
||||||
// region, so the persistent stage chat rail must stay out of the way.
|
|
||||||
sceneBeat("request", "Operator request", "A thin agent interface receives the report request.", { chatMode: "hidden", chatTheme: "light" }),
|
sceneBeat("request", "Operator request", "A thin agent interface receives the report request.", { chatMode: "hidden", chatTheme: "light" }),
|
||||||
sceneBeat("handoff", "Prepared operation", "The interface delegates durable work to lda.chat.", { chatMode: "hidden", chatTheme: "light" }),
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user