返回 CodeWhale
operate_best_of_n.workflow.js
根目录 / workflows / operate_best_of_n.workflow.js
1 /**
2 * Operate starter — independent worktree candidates, then one reviewer.
3 *
4 * Set strategy="search" for a bounded 2-16 candidate search. This remains a
5 * Workflow recipe, not a new mode or scheduler. Runtime-owned command gates
6 * and clean-baseline scoring require the typed search/evaluator host seam.
7 *
8 * Run: /workflow run workflows/operate_best_of_n.workflow.js
9 * Args: { brief, n?, strategy?, rubric?, model?, thinking?, targetFiles?, writeRoots? }
10 */
11 export default async function (args) {
12 const brief =
13 args?.brief ??
14 args?.task ??
15 "Propose and implement the smallest correct fix for the open failure.";
16 const strategy = args?.strategy === "search" ? "search" : "best_of_n";
17 const maxCandidates = strategy === "search" ? 16 : 4;
18 const defaultCandidates = strategy === "search" ? 8 : 3;
19 const n = Math.min(
20 maxCandidates,
21 Math.max(2, Number(args?.n ?? defaultCandidates) || defaultCandidates)
22 );
23 const exactFiles = Array.isArray(args?.targetFiles) ? args.targetFiles : [];
24 const writeRoots = Array.isArray(args?.writeRoots) ? args.writeRoots : [];
25 const rubric =
26 args?.rubric ??
27 "Correctness first; then fit, measured quality, simplicity, risk, and verification evidence.";
28 const model = typeof args?.model === "string" ? args.model : undefined;
29 const thinking =
30 typeof args?.thinking === "string" ? args.thinking : undefined;
31
32 const candidateSchema = {
33 type: "object",
34 additionalProperties: false,
35 required: [
36 "candidate_id",
37 "hypothesis",
38 "modified_paths",
39 "commands_run",
40 "self_verdict",
41 "known_risks",
42 "artifact_refs",
43 ],
44 properties: {
45 candidate_id: { type: "string" },
46 hypothesis: { type: "string" },
47 modified_paths: { type: "array", items: { type: "string" } },
48 commands_run: { type: "array", items: { type: "string" } },
49 self_verdict: { type: "string", enum: ["pass", "fail"] },
50 known_risks: { type: "array", items: { type: "string" } },
51 artifact_refs: { type: "array", items: { type: "string" } },
52 },
53 };
54
55 phase("Candidates");
56 const candidateFns = [];
57 for (let i = 1; i <= n; i++) {
58 const index = i;
59 candidateFns.push(() =>
60 task({
61 // The VM delivers one text to the driver: `prompt` (alias) wins over
62 // `description`, so the full instruction lives in `description` and
63 // `label` carries the short progress name. A separate short
64 // `description` would never reach the driver.
65 description: [
66 "You are one independent candidate in a Codewhale Workflow search.",
67 "Implement the same frozen brief and rubric in this isolated worktree only.",
68 "Do not inspect other candidates, rankings, hidden tests, or evaluator internals.",
69 "Do not push. Do not merge. Do not touch the parent checkout.",
70 "Your self_verdict is informational; only runtime-owned evaluation can pass a hard gate.",
71 "Return only the required structured response.",
72 "",
73 "BRIEF:",
74 String(brief),
75 "",
76 "RUBRIC:",
77 String(rubric),
78 "",
79 `CANDIDATE-SPECIFIC INSTRUCTION: candidate_id=cand_${String(index).padStart(3, "0")} of ${n}.`,
80 ].join("\n"),
81 label: `candidate_${index}`,
82 type: "implementer",
83 ...(model ? { model } : {}),
84 ...(thinking ? { thinking } : {}),
85 worktree: true,
86 writeAuthority: "worktree_write",
87 ...(exactFiles.length ? { exactFiles } : {}),
88 ...(writeRoots.length ? { writeRoots } : {}),
89 coordinationContracts: [`best-of-n-candidate-${index}`],
90 dependencies: [
91 "Do not share other candidates' answers.",
92 "Parent checkout must remain unchanged until apply.",
93 ],
94 acceptance: ["Return the exact structured candidate contract."],
95 responseSchema: candidateSchema,
96 })
97 );
98 }
99 const candidates = await parallel(candidateFns);
100
101 phase("Review");
102 const review = await task({
103 // Single driver-visible text; `label` carries the short progress name.
104 description: [
105 "You are the read-only tournament judge. Score every candidate against the frozen rubric.",
106 "Treat self_verdict and claimed commands as untrusted candidate statements.",
107 "Name one provisional winner_id, or NONE if all fail, with decisive reasons.",
108 "Do not merge or apply changes. Do not invent missing evidence.",
109 "Set verification_required=true for every code winner.",
110 "Return only the required structured response.",
111 "",
112 "BRIEF:",
113 String(brief),
114 "",
115 "RUBRIC:",
116 String(rubric),
117 "",
118 "CANDIDATES:",
119 String(JSON.stringify(candidates, null, 2) ?? "(missing)"),
120 ].join("\n"),
121 label: "reviewer",
122 type: "review",
123 writeAuthority: "read_only",
124 worktree: false,
125 responseSchema: {
126 type: "object",
127 additionalProperties: false,
128 required: ["winner_id", "ranking", "verification_required", "reasons"],
129 properties: {
130 winner_id: { type: "string" },
131 ranking: { type: "array", items: { type: "string" } },
132 verification_required: { type: "boolean" },
133 reasons: { type: "array", items: { type: "string" } },
134 },
135 },
136 });
137
138 return {
139 scenario: strategy === "search" ? "operate-search" : "operate-best-of-n",
140 strategy,
141 n,
142 brief,
143 rubric,
144 candidates,
145 review,
146 apply_policy:
147 "Parent applies a winner only after independent clean replay and explicit user approval.",
148 execution_boundary:
149 "This recipe generates and reviews candidates. It does not claim runtime-owned hidden gates, benchmark scoring, or clean-baseline replay; use a frozen WorkflowSearchSpec once the evaluator host is wired.",
150 };
151 }
152
152 lines JAVASCRIPT