fix: make presentation problem scene read as tool loop
This commit is contained in:
@@ -8,15 +8,16 @@ const problemScene = findScene("problem")!;
|
||||
afterEach(() => cleanup());
|
||||
|
||||
describe("ProblemLoopScene", () => {
|
||||
it("renders the action sequence as useful but insufficient", () => {
|
||||
it("shows direct action as a vertical chat and tool transcript", () => {
|
||||
render(<ProblemLoopScene scene={problemScene} beat={findBeat("problem", "direct-actions")!} />);
|
||||
|
||||
const action = screen.getByRole("group", { name: "Action sequence" });
|
||||
expect(within(action).getByText("think")).toBeInTheDocument();
|
||||
expect(within(action).getAllByText("tool")).toHaveLength(2);
|
||||
expect(within(action).getByText("observe")).toBeInTheDocument();
|
||||
expect(within(action).getByText("done")).toBeInTheDocument();
|
||||
expect(screen.getByText(/useful once/i)).toBeInTheDocument();
|
||||
const transcript = screen.getByRole("list", { name: /one-off tool loop transcript/i });
|
||||
expect(within(transcript).getByText("User prompt")).toBeInTheDocument();
|
||||
expect(within(transcript).getByText("Agent reasoning")).toBeInTheDocument();
|
||||
expect(within(transcript).getByText("Tool call")).toBeInTheDocument();
|
||||
expect(within(transcript).getByText("Observation")).toBeInTheDocument();
|
||||
expect(within(transcript).getByText("Final answer")).toBeInTheDocument();
|
||||
expect(screen.queryByRole("group", { name: /^Action sequence$/i })).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders reusable automation with simple verbs only", () => {
|
||||
@@ -30,4 +31,19 @@ describe("ProblemLoopScene", () => {
|
||||
expect(screen.queryByText(formalName)).not.toBeInTheDocument();
|
||||
}
|
||||
});
|
||||
|
||||
it("keeps reusable automation as the durable counterpart without formal lifecycle words", () => {
|
||||
render(<ProblemLoopScene scene={problemScene} beat={findBeat("problem", "missing-contracts")!} />);
|
||||
|
||||
expect(screen.getByRole("group", { name: /reusable automation/i })).toBeInTheDocument();
|
||||
expect(screen.getByText("design")).toBeInTheDocument();
|
||||
expect(screen.getByText("save")).toBeInTheDocument();
|
||||
expect(screen.getByText("connect")).toBeInTheDocument();
|
||||
expect(screen.getByText("run")).toBeInTheDocument();
|
||||
expect(screen.getByText("inspect")).toBeInTheDocument();
|
||||
expect(screen.queryByText("Draft")).not.toBeInTheDocument();
|
||||
expect(screen.queryByText("Artifact")).not.toBeInTheDocument();
|
||||
expect(screen.queryByText("Deployment")).not.toBeInTheDocument();
|
||||
expect(screen.queryByText("Trace")).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,6 +2,14 @@ import { StageCaption } from "../StageCaption.js";
|
||||
import type { SceneBeatDefinition, SceneDefinition } from "../storyboard.js";
|
||||
import { ConceptNode, ConceptRail } from "./ConceptPrimitives.js";
|
||||
|
||||
const toolLoopTurns = [
|
||||
{ role: "User prompt", detail: "Do this workspace task once." },
|
||||
{ role: "Agent reasoning", detail: "Decides the next action." },
|
||||
{ role: "Tool call", detail: "Runs an operation directly." },
|
||||
{ role: "Observation", detail: "Reads the result." },
|
||||
{ role: "Final answer", detail: "Reports success, but keeps no reusable lifecycle." },
|
||||
] as const;
|
||||
|
||||
type ProblemLoopSceneProps = {
|
||||
readonly scene: SceneDefinition;
|
||||
readonly beat: SceneBeatDefinition;
|
||||
@@ -15,15 +23,19 @@ export const ProblemLoopScene = ({ scene, beat }: ProblemLoopSceneProps) => {
|
||||
<p>{beat.caption}</p>
|
||||
</StageCaption>
|
||||
<section className="problem-loop-scene" aria-label="action sequence versus reusable automation">
|
||||
<div className="problem-loop-scene__side" data-problem-active={automationBeat ? "false" : "true"}>
|
||||
<h2>Action sequence</h2>
|
||||
<ConceptRail label="Action sequence">
|
||||
<ConceptNode title="think" icon="think" emphasis={automationBeat ? "muted" : "normal"} />
|
||||
<ConceptNode title="tool" icon="toolCall" emphasis={automationBeat ? "muted" : "normal"} />
|
||||
<ConceptNode title="observe" icon="observe" emphasis={automationBeat ? "muted" : "normal"} />
|
||||
<ConceptNode title="tool" icon="toolCall" emphasis={automationBeat ? "muted" : "normal"} />
|
||||
<ConceptNode title="done" icon="done" emphasis={automationBeat ? "muted" : "normal"} />
|
||||
</ConceptRail>
|
||||
<div
|
||||
className="problem-loop-scene__side problem-loop-scene__side--transcript"
|
||||
data-problem-active={automationBeat ? "false" : "true"}
|
||||
>
|
||||
<h2>One-off tool loop</h2>
|
||||
<ol className="problem-loop-transcript" aria-label="one-off tool loop transcript">
|
||||
{toolLoopTurns.map((turn) => (
|
||||
<li key={turn.role} className="problem-loop-transcript__turn">
|
||||
<span>{turn.role}</span>
|
||||
<p>{turn.detail}</p>
|
||||
</li>
|
||||
))}
|
||||
</ol>
|
||||
<p>Useful once. Hard to reuse.</p>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1437,6 +1437,39 @@
|
||||
font: 0.95rem/1.35 var(--font-interface);
|
||||
}
|
||||
|
||||
.problem-loop-scene__side--transcript {
|
||||
align-self: stretch;
|
||||
}
|
||||
|
||||
.problem-loop-transcript {
|
||||
display: grid;
|
||||
gap: 0.45rem;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.problem-loop-transcript__turn {
|
||||
display: grid;
|
||||
grid-template-columns: 7.5rem minmax(0, 1fr);
|
||||
gap: 0.65rem;
|
||||
align-items: start;
|
||||
border: 1px solid color-mix(in oklch, var(--stage-line) 66%, transparent);
|
||||
border-radius: 0.65rem;
|
||||
background: color-mix(in oklch, var(--stage-surface) 88%, transparent);
|
||||
padding: 0.5rem 0.6rem;
|
||||
}
|
||||
|
||||
.problem-loop-transcript__turn span {
|
||||
color: var(--accent-cyan);
|
||||
font: 700 0.72rem/1.15 var(--font-evidence);
|
||||
}
|
||||
|
||||
.problem-loop-transcript__turn p {
|
||||
color: var(--text-primary);
|
||||
font: 0.8rem/1.25 var(--font-interface);
|
||||
}
|
||||
|
||||
.problem-loop-scene .concept-rail {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(5, minmax(0, 1fr));
|
||||
|
||||
Reference in New Issue
Block a user