feat: project prepared authoring conversation
This commit is contained in:
@@ -2,7 +2,8 @@ export type WorkflowToolName =
|
|||||||
| "inspectDeployment"
|
| "inspectDeployment"
|
||||||
| "startRun"
|
| "startRun"
|
||||||
| "resumeIssueReview"
|
| "resumeIssueReview"
|
||||||
| "readRunTrace";
|
| "readRunTrace"
|
||||||
|
| "runWorkflowCommand";
|
||||||
|
|
||||||
export type PresentationToolName =
|
export type PresentationToolName =
|
||||||
| "selectWorkflowNode"
|
| "selectWorkflowNode"
|
||||||
@@ -41,6 +42,11 @@ export const AGENT_TOOLS = {
|
|||||||
kind: "workflow",
|
kind: "workflow",
|
||||||
description: "Read trace frames for the completed report run.",
|
description: "Read trace frames for the completed report run.",
|
||||||
},
|
},
|
||||||
|
runWorkflowCommand: {
|
||||||
|
name: "runWorkflowCommand",
|
||||||
|
kind: "workflow",
|
||||||
|
description: "Run one public wf CLI operation in the prepared authoring trace.",
|
||||||
|
},
|
||||||
selectWorkflowNode: {
|
selectWorkflowNode: {
|
||||||
name: "selectWorkflowNode",
|
name: "selectWorkflowNode",
|
||||||
kind: "presentation",
|
kind: "presentation",
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
import {
|
import {
|
||||||
authoringPhaseForBeat,
|
authoringPhaseForBeat,
|
||||||
|
authoringToolGroupId,
|
||||||
projectPreparedAuthoring,
|
projectPreparedAuthoring,
|
||||||
|
projectPreparedAuthoringThread,
|
||||||
type AuthoringPhaseId,
|
type AuthoringPhaseId,
|
||||||
} from "./authoring-recording.js";
|
} from "./authoring-recording.js";
|
||||||
|
|
||||||
@@ -69,14 +71,57 @@ describe("projectPreparedAuthoring", () => {
|
|||||||
const phases = projectPreparedAuthoring();
|
const phases = projectPreparedAuthoring();
|
||||||
for (const phase of phases) {
|
for (const phase of phases) {
|
||||||
for (const cmd of phase.commands) {
|
for (const cmd of phase.commands) {
|
||||||
expect(cmd.command.startsWith("wf") || cmd.command.startsWith("uv run wf")).toBe(true);
|
expect(cmd.command).toMatch(/^(uv run )?wf(\s|$)/);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("uses the public CLI command families for each authoring phase", () => {
|
||||||
|
const commands = projectPreparedAuthoring()
|
||||||
|
.flatMap((phase) => phase.commands)
|
||||||
|
.map((command) => command.command);
|
||||||
|
|
||||||
|
expect(commands.some((command) => command === "wf source list")).toBe(true);
|
||||||
|
expect(commands.some((command) => command === "wf cap list --source local.lda_report --format ids")).toBe(true);
|
||||||
|
expect(commands.some((command) => command === "wf cap inspect local.lda_report.analyze_documents")).toBe(true);
|
||||||
|
expect(commands.some((command) => command === "wf schema")).toBe(true);
|
||||||
|
expect(commands.some((command) => command.startsWith("wf draft add-step lda_report_workflow"))).toBe(true);
|
||||||
|
expect(commands.some((command) => command === "wf draft validate lda_report_workflow")).toBe(true);
|
||||||
|
expect(commands.some((command) => command === "wf draft compile lda_report_workflow")).toBe(true);
|
||||||
|
expect(commands.some((command) => command === "wf artifact inspect lda_report_case_study --version 1")).toBe(true);
|
||||||
|
expect(commands.some((command) => command.startsWith("wf deploy save lda_report_case_study.default"))).toBe(true);
|
||||||
|
expect(commands.some((command) => command === "wf deploy validate lda_report_case_study.default")).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
it("has unique beat IDs for each phase", () => {
|
it("has unique beat IDs for each phase", () => {
|
||||||
const phases = projectPreparedAuthoring();
|
const phases = projectPreparedAuthoring();
|
||||||
const ids = phases.map((p) => p.beatId);
|
const ids = phases.map((p) => p.beatId);
|
||||||
expect(new Set(ids).size).toBe(ids.length);
|
expect(new Set(ids).size).toBe(ids.length);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("projectPreparedAuthoringThread", () => {
|
||||||
|
it("keeps stable message ids while revealing later phases", () => {
|
||||||
|
const draft = projectPreparedAuthoringThread("draft");
|
||||||
|
const deployment = projectPreparedAuthoringThread("deployment");
|
||||||
|
|
||||||
|
expect(draft.map(({ id }) => id)).toEqual(
|
||||||
|
deployment.slice(0, draft.length).map(({ id }) => id),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("projects literal commands as paired workflow tool calls and results", () => {
|
||||||
|
const messages = projectPreparedAuthoringThread("discover");
|
||||||
|
const parts = messages.flatMap(({ parts }) => parts);
|
||||||
|
const calls = parts.filter((part) => part.type === "tool-call");
|
||||||
|
const results = parts.filter((part) => part.type === "tool-result");
|
||||||
|
|
||||||
|
expect(calls).toHaveLength(projectPreparedAuthoring()[0]!.commands.length);
|
||||||
|
expect(results).toHaveLength(calls.length);
|
||||||
|
expect(calls.every((part) => part.call.name === "runWorkflowCommand")).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("uses a stable phase tool-group id", () => {
|
||||||
|
expect(authoringToolGroupId("validate")).toBe("authoring-validate");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -7,6 +7,13 @@
|
|||||||
* presentation evidence, not live RPC responses.
|
* presentation evidence, not live RPC responses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import {
|
||||||
|
agentTextMessage,
|
||||||
|
agentToolCallPart,
|
||||||
|
agentToolResultPart,
|
||||||
|
type AgentMessage,
|
||||||
|
} from "../../demo/agent/events.js";
|
||||||
|
|
||||||
export type AuthoringPhaseId =
|
export type AuthoringPhaseId =
|
||||||
| "discover"
|
| "discover"
|
||||||
| "draft"
|
| "draft"
|
||||||
@@ -34,6 +41,8 @@ export type PreparedAuthoringPhase = {
|
|||||||
readonly label: string;
|
readonly label: string;
|
||||||
readonly commands: readonly PreparedAuthoringCommand[];
|
readonly commands: readonly PreparedAuthoringCommand[];
|
||||||
readonly conversation: readonly AuthoringConversationTurn[];
|
readonly conversation: readonly AuthoringConversationTurn[];
|
||||||
|
/** Compact factual projection for Scene 9; command detail stays in the trace panel. */
|
||||||
|
readonly proof: readonly string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
const unknownPhase = (phase: never): never => {
|
const unknownPhase = (phase: never): never => {
|
||||||
@@ -64,19 +73,25 @@ const recording: readonly PreparedAuthoringPhase[] = [
|
|||||||
command: "wf source list",
|
command: "wf source list",
|
||||||
summary: "List available capability sources",
|
summary: "List available capability sources",
|
||||||
result: "success",
|
result: "success",
|
||||||
detail: "2 sources: local (file:///.providers), docs (file:///docs)",
|
detail: "6 sources: local.lda_docs, local.lda_report, local.issue_board, and platform helpers.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
command: "wf cap inspect",
|
command: "wf cap list --source local.lda_report --format ids",
|
||||||
summary: "Inspect declared capabilities",
|
summary: "List report workflow capabilities",
|
||||||
result: "success",
|
result: "success",
|
||||||
detail: "6 capabilities: read_source, create_draft, add_step, bind_source, validate_graph, compile_artifact",
|
detail: "5 capabilities: analyze_documents, build_report, create_issue_drafts, finalise_report, record_revision_request.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
command: "wf schema list",
|
command: "wf cap inspect local.lda_report.analyze_documents",
|
||||||
|
summary: "Inspect the report-analysis contract",
|
||||||
|
result: "success",
|
||||||
|
detail: "Input: documents. Output: analysis. Declared outcome: ok.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
command: "wf schema",
|
||||||
summary: "List registered workflow schemas",
|
summary: "List registered workflow schemas",
|
||||||
result: "success",
|
result: "success",
|
||||||
detail: "3 schemas: [email protected], [email protected], [email protected]",
|
detail: "WorkflowDraft, RawWorkflowPlan, and NodeUse are available public shapes.",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
conversation: [
|
conversation: [
|
||||||
@@ -89,6 +104,11 @@ const recording: readonly PreparedAuthoringPhase[] = [
|
|||||||
text: "Let me inspect the available sources, capabilities, and schemas to understand what we can work with.",
|
text: "Let me inspect the available sources, capabilities, and schemas to understand what we can work with.",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
proof: [
|
||||||
|
"local.lda_docs",
|
||||||
|
"local.lda_report",
|
||||||
|
"documents input → analysis output",
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
phase: "draft",
|
phase: "draft",
|
||||||
@@ -96,21 +116,21 @@ const recording: readonly PreparedAuthoringPhase[] = [
|
|||||||
label: "Draft",
|
label: "Draft",
|
||||||
commands: [
|
commands: [
|
||||||
{
|
{
|
||||||
command: "wf draft create lda_report_workflow",
|
command: "wf draft create lda_report_workflow --capability local.lda_docs.read_documents",
|
||||||
summary: "Create a new workflow draft",
|
summary: "Create a new workflow draft",
|
||||||
result: "success",
|
result: "success",
|
||||||
detail: "Draft 'lda_report_workflow' created with ID draft_a1b2c3",
|
detail: "Draft 'lda_report_workflow' created with ID draft_a1b2c3",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
command: "wf add-step --id report --action generate_report --source lda_docs",
|
command: "wf draft add-step lda_report_workflow --revision 1 --step analyze --capability local.lda_report.analyze_documents --from-step read_documents --from-outcome ok --route ok=__end__ --input state.documents=documents",
|
||||||
summary: "Add a report generation step",
|
summary: "Add the report-analysis step with a declared route",
|
||||||
result: "success",
|
result: "success",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
command: "wf route list",
|
command: "wf draft inspect lda_report_workflow --include-draft",
|
||||||
summary: "List routes in the draft graph",
|
summary: "Inspect the prepared draft graph",
|
||||||
result: "success",
|
result: "success",
|
||||||
detail: "2 routes: start->report, report->end",
|
detail: "Draft contains read_documents followed by analyze with declared ok routing.",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
conversation: [
|
conversation: [
|
||||||
@@ -119,6 +139,11 @@ const recording: readonly PreparedAuthoringPhase[] = [
|
|||||||
text: "I found the available capabilities. Now I'll create a workflow draft with the report generation step and configure its routes.",
|
text: "I found the available capabilities. Now I'll create a workflow draft with the report generation step and configure its routes.",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
proof: [
|
||||||
|
"read_documents → analyze",
|
||||||
|
"analyze.ok → __end__",
|
||||||
|
"state.documents → documents",
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
phase: "validate",
|
phase: "validate",
|
||||||
@@ -126,16 +151,16 @@ const recording: readonly PreparedAuthoringPhase[] = [
|
|||||||
label: "Validate",
|
label: "Validate",
|
||||||
commands: [
|
commands: [
|
||||||
{
|
{
|
||||||
command: "wf bind --source lda_docs --capability read_source",
|
command: "wf draft validate lda_report_workflow",
|
||||||
summary: "Bind source to capability",
|
|
||||||
result: "success",
|
|
||||||
detail: "Binding established: lda_docs->read_source",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
command: "wf validate draft_a1b2c3",
|
|
||||||
summary: "Validate the workflow draft",
|
summary: "Validate the workflow draft",
|
||||||
result: "diagnostic",
|
result: "diagnostic",
|
||||||
detail: "Diagnostic: Unbound step 'report' — missing output destination. Repair applied: connected report output to end. Status: repaired.",
|
detail: "Diagnostic: analyze output 'analysis' has no state projection.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
command: "wf draft set-output lda_report_workflow --revision 2 --step analyze --map analysis=state.analysis",
|
||||||
|
summary: "Repair the missing output binding",
|
||||||
|
result: "success",
|
||||||
|
detail: "Added analysis -> state.analysis. A follow-up draft validate reports a valid draft.",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
conversation: [
|
conversation: [
|
||||||
@@ -148,6 +173,11 @@ const recording: readonly PreparedAuthoringPhase[] = [
|
|||||||
text: "Running diagnosis now. I'll bind the source and repair any issues found in the draft graph.",
|
text: "Running diagnosis now. I'll bind the source and repair any issues found in the draft graph.",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
proof: [
|
||||||
|
"analysis → state.analysis",
|
||||||
|
"diagnostic resolved",
|
||||||
|
"validated draft",
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
phase: "artifact",
|
phase: "artifact",
|
||||||
@@ -155,24 +185,35 @@ const recording: readonly PreparedAuthoringPhase[] = [
|
|||||||
label: "Artifact",
|
label: "Artifact",
|
||||||
commands: [
|
commands: [
|
||||||
{
|
{
|
||||||
command: "wf compile draft_a1b2c3",
|
command: "wf draft compile lda_report_workflow",
|
||||||
summary: "Compile draft into an immutable artifact",
|
summary: "Compile the validated draft without mutating it",
|
||||||
result: "success",
|
result: "success",
|
||||||
detail: "Compiled artifact art_x9y8z7 (version 1). 3 nodes, 2 edges. Schema: [email protected]",
|
detail: "Compiled raw plan requires local.lda_docs, local.lda_report, and local.issue_board.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
command: "wf artifact inspect art_x9y8z7",
|
command: "wf draft save lda_report_workflow --artifact lda_report_case_study --version 1 --title \"lda.chat Report Case Study\" --outcome completed --outcome cancelled --binding local.lda_docs=local.lda_docs --binding local.lda_report=local.lda_report --binding local.issue_board=local.issue_board",
|
||||||
|
summary: "Save immutable artifact version 1",
|
||||||
|
result: "success",
|
||||||
|
detail: "Artifact lda_report_case_study v1 saved with report-workflow source requirements.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
command: "wf artifact inspect lda_report_case_study --version 1",
|
||||||
summary: "Inspect the compiled artifact",
|
summary: "Inspect the compiled artifact",
|
||||||
result: "success",
|
result: "success",
|
||||||
detail: "Artifact art_x9y8z7 v1 — immutable. Created: 2026-07-11. Nodes: 3. Routes: 2.",
|
detail: "Artifact lda_report_case_study v1 — immutable workflow definition.",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
conversation: [
|
conversation: [
|
||||||
{
|
{
|
||||||
role: "assistant",
|
role: "assistant",
|
||||||
text: "The draft is valid and repaired. Let me compile it into an immutable artifact and inspect the result.",
|
text: "The draft is valid and repaired. I compiled and saved immutable artifact lda_report_case_study version 1.",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
proof: [
|
||||||
|
"lda_report_case_study v1",
|
||||||
|
"immutable artifact",
|
||||||
|
"3 required local sources",
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
phase: "deployment",
|
phase: "deployment",
|
||||||
@@ -180,16 +221,16 @@ const recording: readonly PreparedAuthoringPhase[] = [
|
|||||||
label: "Deployment",
|
label: "Deployment",
|
||||||
commands: [
|
commands: [
|
||||||
{
|
{
|
||||||
command: "wf deployment save --artifact art_x9y8z7 --bind lda_docs:local.lda_docs",
|
command: "wf deploy save lda_report_case_study.default --artifact lda_report_case_study --version 1 --binding local.lda_docs=local.lda_docs --binding local.lda_report=local.lda_report --binding local.issue_board=local.issue_board",
|
||||||
summary: "Save deployment with source bindings",
|
summary: "Save deployment with source bindings",
|
||||||
result: "success",
|
result: "success",
|
||||||
detail: "Deployment dep_m4n5p6 saved. Binding: lda_docs -> local.lda_docs",
|
detail: "Deployment lda_report_case_study.default saved with all three local source bindings.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
command: "wf deployment validate dep_m4n5p6",
|
command: "wf deploy validate lda_report_case_study.default",
|
||||||
summary: "Validate deployment bindings",
|
summary: "Validate deployment bindings",
|
||||||
result: "success",
|
result: "success",
|
||||||
detail: "Deployment dep_m4n5p6 valid — all 1 bindings resolved. Ready for run.",
|
detail: "Deployment lda_report_case_study.default valid — ready for a persisted run.",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
conversation: [
|
conversation: [
|
||||||
@@ -202,8 +243,82 @@ const recording: readonly PreparedAuthoringPhase[] = [
|
|||||||
text: "Saving the deployment with the source bindings and validating that everything is correctly configured.",
|
text: "Saving the deployment with the source bindings and validating that everything is correctly configured.",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
proof: [
|
||||||
|
"lda_report_case_study.default",
|
||||||
|
"local.lda_docs=local.lda_docs",
|
||||||
|
"local.lda_report=local.lda_report",
|
||||||
|
"local.issue_board=local.issue_board",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const authoringToolGroupId = (phase: AuthoringPhaseId): string =>
|
||||||
|
`authoring-${phase}`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Projects the prepared recording into one stable assistant transcript.
|
||||||
|
*
|
||||||
|
* IDs depend only on phase and command position so the full Scene 8 thread and
|
||||||
|
* compact Scene 9 dock retain DOM/message identity while later phases appear.
|
||||||
|
*/
|
||||||
|
export const projectPreparedAuthoringThread = (
|
||||||
|
throughPhase: AuthoringPhaseId = "deployment",
|
||||||
|
): readonly AgentMessage[] => {
|
||||||
|
const finalPhaseIndex = recording.findIndex(({ phase }) => phase === throughPhase);
|
||||||
|
if (finalPhaseIndex < 0) throw new Error(`unknown phase: ${throughPhase}`);
|
||||||
|
|
||||||
|
return recording.slice(0, finalPhaseIndex + 1).flatMap((phase) => {
|
||||||
|
const conversation = phase.conversation.map((turn, index) =>
|
||||||
|
agentTextMessage(`authoring-${phase.phase}-message-${index}`, turn.role, turn.text),
|
||||||
|
);
|
||||||
|
const groupId = authoringToolGroupId(phase.phase);
|
||||||
|
const toolParts = phase.commands.flatMap((command, index) => {
|
||||||
|
const callId = `${groupId}-command-${index}`;
|
||||||
|
return [
|
||||||
|
agentToolCallPart(callId, "runWorkflowCommand", {
|
||||||
|
phase: phase.phase,
|
||||||
|
command: command.command,
|
||||||
|
summary: command.summary,
|
||||||
|
}),
|
||||||
|
agentToolResultPart(callId, "runWorkflowCommand", "success", {
|
||||||
|
status: command.result,
|
||||||
|
detail: command.detail ?? null,
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
return [
|
||||||
|
...conversation,
|
||||||
|
{
|
||||||
|
id: `${groupId}-tools`,
|
||||||
|
role: "assistant" as const,
|
||||||
|
parts: toolParts,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handoffConversation: readonly AuthoringConversationTurn[] = [
|
||||||
|
{
|
||||||
|
role: "user",
|
||||||
|
text: "We need to prepare a report workflow for the lda_report scenario. What sources and capabilities are available?",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
role: "assistant",
|
||||||
|
text: "I found the local document, report, and issue-board capabilities. I can author the reusable workflow through the public wf CLI.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
role: "user",
|
||||||
|
text: "Keep the workflow inspectable and validate the source bindings before it runs.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
role: "assistant",
|
||||||
|
text: "The prepared workflow is ready for deployment: I will create the draft, repair validation diagnostics, save artifact lda_report_case_study v1, then validate its deployment bindings.",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
/** Returns the full prepared authoring recording. */
|
/** Returns the full prepared authoring recording. */
|
||||||
export const projectPreparedAuthoring = (): readonly PreparedAuthoringPhase[] => recording;
|
export const projectPreparedAuthoring = (): readonly PreparedAuthoringPhase[] => recording;
|
||||||
|
|
||||||
|
/** Returns the compact Scene 8 handoff derived from the prepared authoring evidence. */
|
||||||
|
export const projectPreparedAuthoringHandoff = (): readonly AuthoringConversationTurn[] => handoffConversation;
|
||||||
|
|||||||
Reference in New Issue
Block a user