Files
united-workforce/packages/workflow-util-agent/__tests__/build-continuation-prompt.test.ts
T
xiaoju ca223a19c6 refactor: rename workflow-agent-kit → workflow-util-agent, merge workflow-moderator into cli-workflow
- Rename packages/workflow-agent-kit → packages/workflow-util-agent
- Update all imports, tsconfig references, docs
- Delete dead file packages/workflow-util-agent/src/build-agent-prompt.ts
- Merge workflow-moderator (62 LOC) into cli-workflow/src/moderator/
- Move workflow-moderator to legacy-packages/
- Add mustache dependency to cli-workflow
- Update publish-all.mjs

Fixes #512
2026-05-25 10:51:16 +00:00

235 lines
7.2 KiB
TypeScript

import type { StepContext } from "@uncaged/workflow-protocol";
import { describe, expect, test } from "vitest";
import { buildContinuationPrompt } from "../src/build-continuation-prompt.js";
const reviewerStep: StepContext = {
role: "reviewer",
output: { approved: false, comments: "Missing tests" },
detail: "2MXBG6PN4A8JR",
agent: "uwf-hermes",
edgePrompt: "Review the developer's work.",
content: null,
};
const developerStep: StepContext = {
role: "developer",
output: { filesChanged: ["src/app.ts"], summary: "Initial fix" },
detail: "1VPBG9SM5E7WK",
agent: "uwf-hermes",
edgePrompt: "Implement the fix.",
content: null,
};
describe("buildContinuationPrompt", () => {
test("includes steps after the last matching role and the edge prompt", () => {
const steps: StepContext[] = [
developerStep,
reviewerStep,
{
role: "planner",
output: { plan: "revise approach" },
detail: "7BQST3VW9F2MA",
agent: "uwf-hermes",
edgePrompt: "Revise the plan.",
content: null,
},
];
const result = buildContinuationPrompt(
steps,
"developer",
"The reviewer rejected your implementation. Read their feedback and fix the issues.",
);
expect(result).toContain("## What Happened Since Your Last Turn");
expect(result).toContain("### Step 2: reviewer");
expect(result).toContain("Missing tests");
expect(result).toContain("### Step 3: planner");
expect(result).toContain("## Moderator Instruction");
expect(result).toContain("The reviewer rejected your implementation.");
expect(result).not.toContain("Initial fix");
});
test("uses all steps when the role has not run before", () => {
const result = buildContinuationPrompt(
[developerStep, reviewerStep],
"planner",
"Continue from the reviewer feedback.",
);
expect(result).toContain("### Step 1: developer");
expect(result).toContain("### Step 2: reviewer");
expect(result).toContain("Continue from the reviewer feedback.");
});
test("still includes moderator instruction when there are no intervening steps", () => {
const result = buildContinuationPrompt(
[developerStep],
"developer",
"Please revise your work.",
);
expect(result).not.toContain("## What Happened Since Your Last Turn");
expect(result).toContain("## Moderator Instruction");
expect(result).toContain("Please revise your work.");
});
test("includes step content when includeContent option is true", () => {
const stepsWithContent: StepContext[] = [
{
role: "planner",
output: { plan: "hash123" },
detail: "detail1",
agent: "uwf-hermes",
edgePrompt: "",
content: "# Plan\nDetailed plan markdown...",
},
{
role: "developer",
output: { filesChanged: ["app.ts"] },
detail: "detail2",
agent: "uwf-hermes",
edgePrompt: "",
content: "# Implementation\nCode changes...",
},
{
role: "reviewer",
output: { approved: false },
detail: "detail3",
agent: "uwf-hermes",
edgePrompt: "",
content: "# Review\nFeedback...",
},
];
const result = buildContinuationPrompt(stepsWithContent, "committer", "Commit the changes.", {
includeContent: true,
});
expect(result).toContain("## What Happened Since Your Last Turn");
expect(result).toContain("### Step 1: planner");
expect(result).toContain("#### Step Content");
expect(result).toContain("# Plan");
expect(result).toContain("Detailed plan markdown");
expect(result).toContain("### Step 2: developer");
expect(result).toContain("# Implementation");
expect(result).toContain("### Step 3: reviewer");
expect(result).toContain("# Review");
expect(result).toContain("## Moderator Instruction");
expect(result).toContain("Commit the changes.");
});
test("omits step content when includeContent is false (default)", () => {
const stepsWithContent: StepContext[] = [
{
role: "developer",
output: { filesChanged: ["app.ts"] },
detail: "detail1",
agent: "uwf-hermes",
edgePrompt: "",
content: "# Implementation\nCode changes...",
},
{
role: "reviewer",
output: { approved: false },
detail: "detail2",
agent: "uwf-hermes",
edgePrompt: "",
content: "# Review\nFeedback...",
},
];
const result = buildContinuationPrompt(stepsWithContent, "developer", "Fix the issues.");
expect(result).toContain("## What Happened Since Your Last Turn");
expect(result).toContain("### Step 2: reviewer");
expect(result).toContain(JSON.stringify(stepsWithContent[1]?.output));
expect(result).not.toContain("#### Step Content");
expect(result).not.toContain("# Review");
});
test("respects quota when includeContent is true", () => {
const largeContent = "x".repeat(5000);
const stepsWithContent: StepContext[] = [
{
role: "planner",
output: { plan: "hash1" },
detail: "detail1",
agent: "uwf-hermes",
edgePrompt: "",
content: largeContent,
},
{
role: "developer",
output: { files: ["app.ts"] },
detail: "detail2",
agent: "uwf-hermes",
edgePrompt: "",
content: largeContent,
},
{
role: "reviewer",
output: { approved: true },
detail: "detail3",
agent: "uwf-hermes",
edgePrompt: "",
content: "# Review\nLooks good!",
},
];
const result = buildContinuationPrompt(stepsWithContent, "committer", "Commit the changes.", {
includeContent: true,
quota: 1000,
});
// Should include most recent step(s) within quota
expect(result).toContain("### Step 1: reviewer"); // Showing 1 of 3, so step 3 becomes step 1
expect(result).toContain("#### Step Content");
expect(result).toContain("## Moderator Instruction");
expect(result).toContain("Showing 1 of 3 steps (2 omitted due to quota)");
});
test("handles null content gracefully when includeContent is true", () => {
const stepsWithMixedContent: StepContext[] = [
{
role: "planner",
output: { plan: "hash1" },
detail: "detail1",
agent: "uwf-hermes",
edgePrompt: "",
content: "# Plan\nDetails...",
},
{
role: "developer",
output: { files: ["app.ts"] },
detail: "detail2",
agent: "uwf-hermes",
edgePrompt: "",
content: null, // No content available
},
{
role: "reviewer",
output: { approved: true },
detail: "detail3",
agent: "uwf-hermes",
edgePrompt: "",
content: "# Review\nApproved!",
},
];
const result = buildContinuationPrompt(
stepsWithMixedContent,
"committer",
"Commit the changes.",
{ includeContent: true },
);
expect(result).toContain("### Step 1: planner");
expect(result).toContain("# Plan");
expect(result).toContain("### Step 2: developer");
// Step 2 should not have content section since content is null
expect(result).toContain("### Step 3: reviewer");
expect(result).toContain("# Review");
});
});