File size: 4,714 Bytes
3f76ff4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
837e3ac
 
3f76ff4
 
 
837e3ac
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
import { describe, expect, it } from "vitest";
import seedWorkPackages from "../agentic_pm_demo_codex_plans/data/work-packages.seed.json";
import { runMockAgent } from "./mock-agent";
import { hydrateWorkPackages } from "./work-package-specs";
import type { ChatMessage, WorkPackage } from "./work-package-types";
import { SIMULATED_EXECUTION_DISCLAIMER } from "./work-package-types";

const productIdea =
  "I want to build an IoT product for production-line tightening quality monitoring.";

const hydrated = hydrateWorkPackages(
  seedWorkPackages as WorkPackage[],
  productIdea,
);

function userMessage(content: string): ChatMessage {
  return {
    id: "m-1",
    role: "user",
    content,
    createdAt: new Date().toISOString(),
  };
}

describe("runMockAgent", () => {
  it("hydrates the board from a free-form product idea", () => {
    const response = runMockAgent({
      messages: [userMessage(productIdea)],
      workPackages: seedWorkPackages as WorkPackage[],
      parsedCommand: { instruction: productIdea },
    });

    expect(response.boardAction?.type).toBe("replace_all");
    const replacement = response.boardAction?.fields?.replacementWorkPackages as
      | WorkPackage[]
      | undefined;
    expect(replacement?.length).toBe(hydrated.length);
    expect(replacement?.[0]?.inputFiles[0]).toContain("Product brief:");
  });

  it("creates spec-driven execute outputs for every work package", () => {
    for (const wp of hydrated) {
      const response = runMockAgent({
        messages: [userMessage(productIdea)],
        workPackages: hydrated,
        selectedWorkPackageId: wp.id,
        parsedCommand: {
          referencedPackageName: wp.title,
          mode: "execute",
          instruction: `Generate the expected outputs for ${wp.shortName}.`,
        },
      });

      expect(response.boardAction?.type).toBe("update");
      const fields = response.boardAction?.fields;
      const outputs = (fields?.outputs as WorkPackage["outputs"] | undefined) ?? [];
      expect(outputs.length).toBeGreaterThan(0);
      const latest = outputs[outputs.length - 1];
      expect(latest.disclaimer).toBe(SIMULATED_EXECUTION_DISCLAIMER);
      for (const expectedOutput of wp.outputFiles) {
        expect(latest.content).toContain(expectedOutput);
      }
    }
  });

  it("returns package-aware guidance for ask", () => {
    const wp = hydrated.find((item) => item.id === "wp-test-management");
    expect(wp).toBeTruthy();

    const response = runMockAgent({
      messages: [userMessage(productIdea)],
      workPackages: hydrated,
      selectedWorkPackageId: wp?.id,
      parsedCommand: {
        referencedPackageName: wp?.title,
        mode: "ask",
        instruction: "How should we verify reliability?",
      },
    });

    expect(response.assistantMessage).toContain("traceability");
    expect(response.assistantMessage).toContain("reliability");
    expect(response.assistantMessage).not.toContain("Package:");
    expect(response.assistantMessage).not.toContain("Phase:");
    expect(response.boardAction?.type).toBe("none");
  });

  it("preserves the existing product brief when asking about a package detail", () => {
    const wp = hydrated.find((item) => item.id === "wp-srs");
    expect(wp).toBeTruthy();

    const response = runMockAgent({
      messages: [userMessage("What does verification method mean in this package?")],
      workPackages: hydrated,
      selectedWorkPackageId: wp?.id,
      parsedCommand: {
        referencedPackageName: wp?.title,
        mode: "ask",
        instruction: "What does verification method mean in this package?",
      },
    });

    expect(response.assistantMessage).toContain(productIdea);
    expect(response.assistantMessage).not.toContain(
      "Product brief: What does verification method mean in this package?",
    );
  });

  it("does not turn a package question into the product brief when no product brief exists yet", () => {
    const unhydrated = seedWorkPackages as WorkPackage[];
    const wp = unhydrated.find((item) => item.id === "wp-srs");
    expect(wp).toBeTruthy();

    const response = runMockAgent({
      messages: [userMessage("Explain this objective in simpler words.")],
      workPackages: unhydrated,
      selectedWorkPackageId: wp?.id,
      parsedCommand: {
        referencedPackageName: wp?.title,
        mode: "ask",
        instruction: "Explain this objective in simpler words.",
      },
    });

    expect(response.assistantMessage).not.toContain(
      "Product brief: Explain this objective in simpler words.",
    );
    expect(response.assistantMessage).not.toContain(
      "Product context: Explain this objective in simpler words.",
    );
  });
});