ultimate-pi 0.14.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/skills/harness-debate-plan/SKILL.md +41 -61
- package/.agents/skills/harness-governor/SKILL.md +11 -0
- package/.agents/skills/harness-orchestration/SKILL.md +5 -3
- package/.agents/skills/harness-plan/SKILL.md +11 -9
- package/.pi/agents/harness/adversary.md +1 -1
- package/.pi/agents/harness/evaluator.md +1 -1
- package/.pi/agents/harness/executor.md +1 -1
- package/.pi/agents/harness/incident-recorder.md +1 -1
- package/.pi/agents/harness/meta-optimizer.md +1 -1
- package/.pi/agents/harness/planning/decompose.md +8 -35
- package/.pi/agents/harness/planning/execution-plan-author.md +27 -15
- package/.pi/agents/harness/planning/hypothesis-validator.md +23 -6
- package/.pi/agents/harness/planning/hypothesis.md +4 -27
- package/.pi/agents/harness/planning/implementation-researcher.md +43 -0
- package/.pi/agents/harness/planning/plan-adversary.md +20 -5
- package/.pi/agents/harness/planning/plan-evaluator.md +28 -6
- package/.pi/agents/harness/planning/review-integrator.md +23 -10
- package/.pi/agents/harness/planning/scout-graphify.md +4 -23
- package/.pi/agents/harness/planning/scout-semantic.md +3 -18
- package/.pi/agents/harness/planning/scout-structure.md +3 -18
- package/.pi/agents/harness/planning/sprint-contract-auditor.md +22 -6
- package/.pi/agents/harness/planning/stack-researcher.md +21 -11
- package/.pi/agents/harness/tie-breaker.md +1 -1
- package/.pi/agents/harness/trace-librarian.md +1 -1
- package/.pi/extensions/budget-guard.ts +33 -19
- package/.pi/extensions/harness-debate-tools.ts +280 -19
- package/.pi/extensions/harness-live-widget.ts +39 -159
- package/.pi/extensions/harness-plan-approval.ts +47 -5
- package/.pi/extensions/harness-run-context.ts +96 -2
- package/.pi/extensions/harness-subagent-submit.ts +195 -0
- package/.pi/extensions/lib/debate-bus-core.ts +108 -17
- package/.pi/extensions/lib/debate-bus-state.ts +6 -0
- package/.pi/extensions/lib/harness-subagent-policy.ts +45 -0
- package/.pi/extensions/lib/harness-subagent-submit-pipeline.ts +82 -0
- package/.pi/extensions/lib/harness-subagent-submit-registry.ts +172 -0
- package/.pi/extensions/lib/harness-subagents-bridge.ts +42 -0
- package/.pi/extensions/lib/plan-approval/plan-review.ts +56 -0
- package/.pi/extensions/lib/plan-approval/types.ts +1 -0
- package/.pi/extensions/lib/plan-debate-eligibility.ts +214 -0
- package/.pi/extensions/lib/plan-debate-focus.ts +151 -0
- package/.pi/extensions/lib/plan-debate-gate.ts +88 -34
- package/.pi/extensions/lib/plan-debate-lane.ts +15 -0
- package/.pi/extensions/lib/plan-debate-lanes.ts +44 -0
- package/.pi/extensions/lib/plan-debate-round-status.ts +63 -20
- package/.pi/extensions/lib/plan-messenger.ts +93 -17
- package/.pi/extensions/policy-gate.ts +1 -1
- package/.pi/harness/README.md +1 -1
- package/.pi/harness/agents.manifest.json +25 -21
- package/.pi/harness/docs/adrs/0034-darwin-plan-research-pipeline.md +1 -3
- package/.pi/harness/docs/adrs/0035-plan-phase-review-gate.md +13 -5
- package/.pi/harness/docs/adrs/0036-implementation-research-and-selective-debate.md +51 -0
- package/.pi/harness/docs/adrs/0037-subagent-submit-tools.md +31 -0
- package/.pi/harness/docs/adrs/0038-budget-telemetry-only.md +23 -0
- package/.pi/harness/docs/adrs/README.md +4 -0
- package/.pi/harness/evals/smoke/fixtures/plan-phase/minimal-low-light/artifacts/implementation-research.yaml +28 -0
- package/.pi/harness/evals/smoke/fixtures/plan-phase/minimal-low-light/artifacts/review-round-r1.yaml +24 -0
- package/.pi/harness/evals/smoke/fixtures/plan-phase/minimal-low-light/artifacts/review-round-r2.yaml +25 -0
- package/.pi/harness/evals/smoke/fixtures/plan-phase/minimal-low-light/plan-packet.yaml +196 -0
- package/.pi/harness/evals/smoke/fixtures/plan-phase/minimal-low-light/plan-review.md +14 -0
- package/.pi/harness/evals/smoke/fixtures/plan-phase/minimal-low-light/research-brief.yaml +62 -0
- package/.pi/harness/evals/smoke/fixtures/plan-phase/minimal-med/artifacts/implementation-research.yaml +28 -0
- package/.pi/harness/evals/smoke/fixtures/plan-phase/minimal-med/artifacts/review-round-r2.yaml +24 -0
- package/.pi/harness/evals/smoke/fixtures/plan-phase/minimal-med/artifacts/review-round-r3.yaml +24 -0
- package/.pi/harness/evals/smoke/fixtures/plan-phase/minimal-med/research-brief.yaml +29 -0
- package/.pi/harness/evals/smoke/smoke-harness-plan.mjs +97 -16
- package/.pi/harness/specs/harness-executor-handoff.schema.json +19 -0
- package/.pi/harness/specs/harness-human-required.schema.json +16 -0
- package/.pi/harness/specs/plan-implementation-research-brief.schema.json +128 -0
- package/.pi/harness/specs/plan-review-round-draft.schema.json +1 -1
- package/.pi/harness/specs/plan-scout-findings.schema.json +19 -0
- package/.pi/harness/specs/round-result.schema.json +15 -2
- package/.pi/lib/harness-agent-output.ts +45 -0
- package/.pi/lib/harness-budget-enforce.ts +18 -0
- package/.pi/lib/harness-schema-validate.ts +89 -0
- package/.pi/lib/harness-spawn-parse.ts +86 -0
- package/.pi/lib/harness-subagent-submit-path.ts +41 -0
- package/.pi/lib/harness-ui-state.ts +107 -2
- package/.pi/prompts/harness-auto.md +2 -2
- package/.pi/prompts/harness-plan.md +94 -42
- package/.pi/prompts/harness-run.md +2 -2
- package/.pi/prompts/planning-rubrics.md +31 -0
- package/.pi/scripts/harness-verify.mjs +2 -0
- package/.pi/scripts/harness_web/__pycache__/__init__.cpython-314.pyc +0 -0
- package/.pi/scripts/harness_web/__pycache__/config.cpython-314.pyc +0 -0
- package/.pi/scripts/harness_web/__pycache__/output.cpython-314.pyc +0 -0
- package/.pi/scripts/harness_web/__pycache__/scrape.cpython-314.pyc +0 -0
- package/.pi/scripts/harness_web/__pycache__/search.cpython-314.pyc +0 -0
- package/.pi/scripts/harness_web/__pycache__/search_ddg.cpython-314.pyc +0 -0
- package/.pi/scripts/harness_web/__pycache__/search_searxng.cpython-314.pyc +0 -0
- package/CHANGELOG.md +21 -0
- package/package.json +4 -2
- package/vendor/pi-subagents/src/subagents.ts +29 -3
|
@@ -2,11 +2,16 @@
|
|
|
2
2
|
* P0–P3 plan debate tools — bus + pi-messenger transport.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import { mkdir } from "node:fs/promises";
|
|
5
|
+
import { mkdir, readFile } from "node:fs/promises";
|
|
6
6
|
import { dirname, join } from "node:path";
|
|
7
7
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
8
8
|
import { Type } from "@sinclair/typebox";
|
|
9
|
+
import { parse as parseYaml } from "yaml";
|
|
9
10
|
import type { DebateParticipant } from "../lib/debate-orchestrator-types.js";
|
|
11
|
+
import {
|
|
12
|
+
extractLastSubmitCall,
|
|
13
|
+
type MessageLike,
|
|
14
|
+
} from "../lib/harness-agent-output.js";
|
|
10
15
|
import {
|
|
11
16
|
getLatestRunContext,
|
|
12
17
|
getRunIdFromSession,
|
|
@@ -14,22 +19,33 @@ import {
|
|
|
14
19
|
import { writeYamlFile } from "../lib/harness-yaml.js";
|
|
15
20
|
import {
|
|
16
21
|
acceptDebateRound,
|
|
22
|
+
capsForDebate,
|
|
17
23
|
finalizeDebateConsensus,
|
|
18
24
|
openDebateBus,
|
|
19
25
|
} from "./lib/debate-bus-core.js";
|
|
20
26
|
import { getDebateState } from "./lib/debate-bus-state.js";
|
|
21
27
|
import { claimExtensionLoad } from "./lib/extension-load-guard.js";
|
|
22
28
|
import { captureHarnessEvent } from "./lib/harness-posthog.js";
|
|
29
|
+
import { DEBATE_AGENT_SUBMIT_TOOL } from "./lib/harness-subagent-submit-registry.js";
|
|
30
|
+
import {
|
|
31
|
+
type DebateEligibilityInput,
|
|
32
|
+
harnessPlanDebateEligibility,
|
|
33
|
+
} from "./lib/plan-debate-eligibility.js";
|
|
23
34
|
import {
|
|
24
35
|
buildPlanReviewRoundEnvelope,
|
|
25
36
|
type PlanReviewRoundDraft,
|
|
26
37
|
} from "./lib/plan-debate-envelope.js";
|
|
38
|
+
import {
|
|
39
|
+
getPlanFocusCoverage,
|
|
40
|
+
planDebateOutcomeComplete,
|
|
41
|
+
} from "./lib/plan-debate-focus.js";
|
|
27
42
|
import {
|
|
28
43
|
normalizePlanDebateId,
|
|
29
44
|
planDebateIdForRun,
|
|
30
45
|
} from "./lib/plan-debate-id.js";
|
|
31
46
|
import {
|
|
32
47
|
applyDebateLane,
|
|
48
|
+
applyDebateLaneFromDoc,
|
|
33
49
|
type DebateLaneKind,
|
|
34
50
|
debateLaneForAgent,
|
|
35
51
|
formatApplyLaneMessage,
|
|
@@ -40,6 +56,7 @@ import {
|
|
|
40
56
|
formatTranscriptForSpawn,
|
|
41
57
|
getMessengerRoundState,
|
|
42
58
|
initPlanMessenger,
|
|
59
|
+
loadMessengerState,
|
|
43
60
|
messengerRoundDebateReady,
|
|
44
61
|
postMessengerMessage,
|
|
45
62
|
readRoundTranscript,
|
|
@@ -84,13 +101,19 @@ function telemetryRound(
|
|
|
84
101
|
|
|
85
102
|
function subagentResults(
|
|
86
103
|
details: unknown,
|
|
87
|
-
): Array<{ agent: string; finalOutput?: string }> {
|
|
104
|
+
): Array<{ agent: string; finalOutput?: string; messages?: MessageLike[] }> {
|
|
88
105
|
const d = details as {
|
|
89
|
-
results?: Array<{
|
|
106
|
+
results?: Array<{
|
|
107
|
+
agent: string;
|
|
108
|
+
finalOutput?: string;
|
|
109
|
+
messages?: MessageLike[];
|
|
110
|
+
}>;
|
|
90
111
|
};
|
|
91
112
|
return d?.results ?? [];
|
|
92
113
|
}
|
|
93
114
|
|
|
115
|
+
const USE_SUBMIT_TOOLS = process.env.HARNESS_SUBMIT_TOOLS !== "0";
|
|
116
|
+
|
|
94
117
|
export default function harnessDebateTools(pi: ExtensionAPI) {
|
|
95
118
|
if (!claimExtensionLoad("harness-debate-tools", MODULE_URL)) return;
|
|
96
119
|
|
|
@@ -107,7 +130,34 @@ export default function harnessDebateTools(pi: ExtensionAPI) {
|
|
|
107
130
|
let lastRound = 1;
|
|
108
131
|
for (const result of subagentResults(event.details)) {
|
|
109
132
|
const lane = debateLaneForAgent(result.agent ?? "");
|
|
110
|
-
if (!lane
|
|
133
|
+
if (!lane) continue;
|
|
134
|
+
|
|
135
|
+
const submitTool = DEBATE_AGENT_SUBMIT_TOOL[result.agent ?? ""];
|
|
136
|
+
const submitCall =
|
|
137
|
+
USE_SUBMIT_TOOLS && submitTool && result.messages
|
|
138
|
+
? extractLastSubmitCall(result.messages, submitTool)
|
|
139
|
+
: null;
|
|
140
|
+
|
|
141
|
+
if (submitCall) {
|
|
142
|
+
const out = await applyDebateLaneFromDoc({
|
|
143
|
+
runDir: rd,
|
|
144
|
+
lane,
|
|
145
|
+
doc: submitCall.document,
|
|
146
|
+
});
|
|
147
|
+
if (out.round_index) lastRound = out.round_index;
|
|
148
|
+
pi.appendEntry("harness-debate-lane-applied", {
|
|
149
|
+
agent: result.agent,
|
|
150
|
+
source: "submit_tool",
|
|
151
|
+
tool: submitCall.toolName,
|
|
152
|
+
...out,
|
|
153
|
+
});
|
|
154
|
+
applied.push(formatApplyLaneMessage(out));
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (!result.finalOutput?.trim()) continue;
|
|
159
|
+
if (USE_SUBMIT_TOOLS && submitTool) continue;
|
|
160
|
+
|
|
111
161
|
const out = await applyDebateLane({
|
|
112
162
|
runDir: rd,
|
|
113
163
|
lane,
|
|
@@ -122,7 +172,7 @@ export default function harnessDebateTools(pi: ExtensionAPI) {
|
|
|
122
172
|
}
|
|
123
173
|
if (applied.length === 0) return;
|
|
124
174
|
|
|
125
|
-
const status = await getPlanDebateRoundStatus(rd, lastRound);
|
|
175
|
+
const status = await getPlanDebateRoundStatus(rd, lastRound, runId);
|
|
126
176
|
pi.sendMessage({
|
|
127
177
|
customType: "harness-debate-next-step",
|
|
128
178
|
content: [
|
|
@@ -138,28 +188,131 @@ export default function harnessDebateTools(pi: ExtensionAPI) {
|
|
|
138
188
|
});
|
|
139
189
|
});
|
|
140
190
|
|
|
191
|
+
pi.registerTool({
|
|
192
|
+
name: "harness_plan_debate_eligibility",
|
|
193
|
+
label: "Plan Debate Eligibility",
|
|
194
|
+
description:
|
|
195
|
+
"Pre-debate profile selection (full|standard|light). Call after DAG pass, before harness_debate_open. Uses risk, fork, implementation/stack briefs — not R1 hypothesis output.",
|
|
196
|
+
parameters: Type.Object({
|
|
197
|
+
risk_level: Type.Optional(
|
|
198
|
+
Type.String({ description: "low | med | high" }),
|
|
199
|
+
),
|
|
200
|
+
material_fork: Type.Optional(Type.Boolean()),
|
|
201
|
+
dag_pass: Type.Optional(Type.Boolean()),
|
|
202
|
+
dag_manually_patched: Type.Optional(Type.Boolean()),
|
|
203
|
+
implementation_brief_path: Type.Optional(
|
|
204
|
+
Type.String({
|
|
205
|
+
description:
|
|
206
|
+
"Default: artifacts/implementation-research.yaml under run dir",
|
|
207
|
+
}),
|
|
208
|
+
),
|
|
209
|
+
stack_brief_path: Type.Optional(Type.String()),
|
|
210
|
+
decomposition_path: Type.Optional(Type.String()),
|
|
211
|
+
}),
|
|
212
|
+
async execute(_id, params, _signal, _onUpdate, ctx) {
|
|
213
|
+
const runId = getRunId(ctx);
|
|
214
|
+
const rd = runDir(process.cwd(), runId);
|
|
215
|
+
const p = params as {
|
|
216
|
+
risk_level?: string;
|
|
217
|
+
material_fork?: boolean;
|
|
218
|
+
dag_pass?: boolean;
|
|
219
|
+
dag_manually_patched?: boolean;
|
|
220
|
+
implementation_brief_path?: string;
|
|
221
|
+
stack_brief_path?: string;
|
|
222
|
+
decomposition_path?: string;
|
|
223
|
+
};
|
|
224
|
+
async function loadYaml(
|
|
225
|
+
rel: string,
|
|
226
|
+
): Promise<Record<string, unknown> | null> {
|
|
227
|
+
try {
|
|
228
|
+
const raw = await readFile(join(rd, rel), "utf-8");
|
|
229
|
+
return parseYaml(raw) as Record<string, unknown>;
|
|
230
|
+
} catch {
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
const input: DebateEligibilityInput = {
|
|
235
|
+
risk_level: p.risk_level,
|
|
236
|
+
material_fork: p.material_fork,
|
|
237
|
+
dag_pass: p.dag_pass,
|
|
238
|
+
dag_manually_patched: p.dag_manually_patched,
|
|
239
|
+
implementation_brief: await loadYaml(
|
|
240
|
+
p.implementation_brief_path ??
|
|
241
|
+
"artifacts/implementation-research.yaml",
|
|
242
|
+
),
|
|
243
|
+
stack_brief: await loadYaml(
|
|
244
|
+
p.stack_brief_path ?? "artifacts/stack.yaml",
|
|
245
|
+
),
|
|
246
|
+
decomposition: await loadYaml(
|
|
247
|
+
p.decomposition_path ?? "artifacts/decomposition.yaml",
|
|
248
|
+
),
|
|
249
|
+
};
|
|
250
|
+
const result = harnessPlanDebateEligibility(input);
|
|
251
|
+
const lines = [
|
|
252
|
+
`profile: ${result.profile}`,
|
|
253
|
+
`required_focuses: ${result.required_focuses.join(", ")}`,
|
|
254
|
+
`min_focus_rounds: ${result.min_focus_rounds}`,
|
|
255
|
+
`debate_global_cap: ${result.debate_global_cap}`,
|
|
256
|
+
`human_required: ${result.human_required}`,
|
|
257
|
+
...result.rationale.map((r) => `- ${r}`),
|
|
258
|
+
];
|
|
259
|
+
return {
|
|
260
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
261
|
+
details: result,
|
|
262
|
+
};
|
|
263
|
+
},
|
|
264
|
+
});
|
|
265
|
+
|
|
141
266
|
pi.registerTool({
|
|
142
267
|
name: "harness_debate_open",
|
|
143
268
|
label: "Open Plan Debate",
|
|
144
269
|
description:
|
|
145
|
-
"Open plan-phase debate bus (plan-<run_id>) and initialize pi-messenger inboxes/threads. Call once
|
|
270
|
+
"Open plan-phase debate bus (plan-<run_id>) and initialize pi-messenger inboxes/threads. Call once after harness_plan_debate_eligibility.",
|
|
146
271
|
parameters: Type.Object({
|
|
147
272
|
debate_id: Type.Optional(
|
|
148
273
|
Type.String({ description: "Optional; normalized to plan-<run_id>" }),
|
|
149
274
|
),
|
|
275
|
+
debate_profile: Type.Optional(
|
|
276
|
+
Type.String({ description: "full | standard | light" }),
|
|
277
|
+
),
|
|
278
|
+
required_focuses: Type.Optional(
|
|
279
|
+
Type.Array(
|
|
280
|
+
Type.String({ description: "spec | wbs | schedule | quality" }),
|
|
281
|
+
),
|
|
282
|
+
),
|
|
150
283
|
}),
|
|
151
284
|
async execute(_id, params, _signal, _onUpdate, ctx) {
|
|
152
285
|
const runId = getRunId(ctx);
|
|
153
286
|
const projectRoot = process.cwd();
|
|
154
|
-
const
|
|
287
|
+
const p = params as {
|
|
288
|
+
debate_id?: string;
|
|
289
|
+
debate_profile?: string;
|
|
290
|
+
required_focuses?: string[];
|
|
291
|
+
};
|
|
292
|
+
const raw = String(p.debate_id ?? "");
|
|
155
293
|
const { debateId, corrected, warning } = normalizePlanDebateId(
|
|
156
294
|
raw,
|
|
157
295
|
runId,
|
|
158
296
|
);
|
|
159
|
-
const
|
|
297
|
+
const profile =
|
|
298
|
+
p.debate_profile === "full" ||
|
|
299
|
+
p.debate_profile === "standard" ||
|
|
300
|
+
p.debate_profile === "light"
|
|
301
|
+
? p.debate_profile
|
|
302
|
+
: "standard";
|
|
303
|
+
const required_focuses = (p.required_focuses ?? []).filter((f) =>
|
|
304
|
+
["spec", "wbs", "schedule", "quality"].includes(f),
|
|
305
|
+
) as Array<"spec" | "wbs" | "schedule" | "quality">;
|
|
306
|
+
const opened = await openDebateBus(runId, debateId, debateHooks(pi), {
|
|
307
|
+
debate_profile: profile,
|
|
308
|
+
required_focuses:
|
|
309
|
+
required_focuses.length > 0 ? required_focuses : undefined,
|
|
310
|
+
});
|
|
160
311
|
await initPlanMessenger(runDir(projectRoot, runId), {
|
|
161
312
|
runId,
|
|
162
313
|
debateId,
|
|
314
|
+
debate_profile: profile,
|
|
315
|
+
required_focuses: opened.required_focuses,
|
|
163
316
|
});
|
|
164
317
|
const sessionId = ctx.sessionManager.getSessionId();
|
|
165
318
|
captureHarnessEvent(sessionId, "harness_debate_round", {
|
|
@@ -171,6 +324,12 @@ export default function harnessDebateTools(pi: ExtensionAPI) {
|
|
|
171
324
|
});
|
|
172
325
|
const lines = [
|
|
173
326
|
`Plan debate opened: ${debateId}`,
|
|
327
|
+
`Profile: ${profile}`,
|
|
328
|
+
required_focuses.length
|
|
329
|
+
? `Required focuses: ${required_focuses.join(", ")}`
|
|
330
|
+
: opened.required_focuses?.length
|
|
331
|
+
? `Required focuses: ${opened.required_focuses.join(", ")}`
|
|
332
|
+
: "Required focuses: (default all four)",
|
|
174
333
|
`Messenger: debate-messenger/ (inbox + threads/round-N/transcript.jsonl)`,
|
|
175
334
|
];
|
|
176
335
|
if (warning) lines.push(`Note: ${warning}`);
|
|
@@ -187,13 +346,14 @@ export default function harnessDebateTools(pi: ExtensionAPI) {
|
|
|
187
346
|
description:
|
|
188
347
|
"Post a claim/rebuttal/integrate message to the round thread and agent inbox (pi-messenger style). Evaluator posts claims first; adversary rebuts with in_reply_to claim ids.",
|
|
189
348
|
parameters: Type.Object({
|
|
190
|
-
round_index: Type.Number({ description: "1–
|
|
349
|
+
round_index: Type.Number({ description: "1–12 (monotonic per run)" }),
|
|
191
350
|
from: Type.String({
|
|
192
351
|
description:
|
|
193
352
|
"PlanEvaluatorAgent | PlanAdversaryAgent | ReviewIntegratorAgent | HypothesisValidatorAgent | SprintContractAuditorAgent",
|
|
194
353
|
}),
|
|
195
354
|
kind: Type.String({
|
|
196
|
-
description:
|
|
355
|
+
description:
|
|
356
|
+
"claim | rebuttal | clarification | counter | integrate | audit | system",
|
|
197
357
|
}),
|
|
198
358
|
body: Type.String(),
|
|
199
359
|
to: Type.Optional(Type.Array(Type.String())),
|
|
@@ -207,7 +367,14 @@ export default function harnessDebateTools(pi: ExtensionAPI) {
|
|
|
207
367
|
const p = params as {
|
|
208
368
|
round_index: number;
|
|
209
369
|
from: DebateParticipant;
|
|
210
|
-
kind:
|
|
370
|
+
kind:
|
|
371
|
+
| "claim"
|
|
372
|
+
| "rebuttal"
|
|
373
|
+
| "clarification"
|
|
374
|
+
| "counter"
|
|
375
|
+
| "integrate"
|
|
376
|
+
| "audit"
|
|
377
|
+
| "system";
|
|
211
378
|
body: string;
|
|
212
379
|
to?: Array<DebateParticipant | "broadcast">;
|
|
213
380
|
in_reply_to?: string[];
|
|
@@ -269,7 +436,7 @@ export default function harnessDebateTools(pi: ExtensionAPI) {
|
|
|
269
436
|
description:
|
|
270
437
|
"Validate lane YAML + messenger thread, write review-round-rN.yaml, emit bus round envelope. Parent must not write review-round files directly.",
|
|
271
438
|
parameters: Type.Object({
|
|
272
|
-
round_index: Type.Number({ description: "1–
|
|
439
|
+
round_index: Type.Number({ description: "1–12 (monotonic per run)" }),
|
|
273
440
|
integrator_draft: Type.Record(Type.String(), Type.Unknown(), {
|
|
274
441
|
description: "ReviewIntegrator YAML object (review-round-rN fields)",
|
|
275
442
|
}),
|
|
@@ -300,8 +467,11 @@ export default function harnessDebateTools(pi: ExtensionAPI) {
|
|
|
300
467
|
evidence_refs: [`artifacts/review-round-r${roundIndex}.yaml`],
|
|
301
468
|
});
|
|
302
469
|
|
|
470
|
+
const caps = capsForDebate(debateId);
|
|
303
471
|
const roundState = await getMessengerRoundState(rd, roundIndex);
|
|
304
|
-
const mCheck = messengerRoundDebateReady(roundState, roundIndex
|
|
472
|
+
const mCheck = messengerRoundDebateReady(roundState, roundIndex >= 4, {
|
|
473
|
+
max_exchanges_per_round: caps.max_exchanges_per_round,
|
|
474
|
+
});
|
|
305
475
|
if (!mCheck.ok) {
|
|
306
476
|
return {
|
|
307
477
|
content: [
|
|
@@ -393,7 +563,7 @@ export default function harnessDebateTools(pi: ExtensionAPI) {
|
|
|
393
563
|
name: "harness_debate_consensus",
|
|
394
564
|
label: "Finalize Plan Debate Consensus",
|
|
395
565
|
description:
|
|
396
|
-
"After
|
|
566
|
+
"After all focus areas covered (spec|wbs|schedule|quality) and last review_gate_ready true, emit consensus packet to .pi/harness/debates/plan-<run_id>.consensus.json",
|
|
397
567
|
parameters: Type.Object({
|
|
398
568
|
rationale: Type.Optional(Type.String()),
|
|
399
569
|
}),
|
|
@@ -401,7 +571,7 @@ export default function harnessDebateTools(pi: ExtensionAPI) {
|
|
|
401
571
|
const runId = getRunId(ctx);
|
|
402
572
|
const rationale =
|
|
403
573
|
String((params as { rationale?: string }).rationale ?? "").trim() ||
|
|
404
|
-
"Plan Review Gate consensus after
|
|
574
|
+
"Plan Review Gate consensus after focus coverage and messenger-backed rounds.";
|
|
405
575
|
const decision = await finalizeDebateConsensus(
|
|
406
576
|
rationale,
|
|
407
577
|
debateHooks(pi),
|
|
@@ -468,16 +638,30 @@ export default function harnessDebateTools(pi: ExtensionAPI) {
|
|
|
468
638
|
description:
|
|
469
639
|
"List missing lane artifacts and messenger steps for a Review Gate round. Call when resuming after a stop.",
|
|
470
640
|
parameters: Type.Object({
|
|
471
|
-
round_index: Type.Number({ description: "1–
|
|
641
|
+
round_index: Type.Number({ description: "1–12 (monotonic per run)" }),
|
|
642
|
+
debate_round_focus: Type.Optional(
|
|
643
|
+
Type.String({ description: "spec | wbs | schedule | quality" }),
|
|
644
|
+
),
|
|
472
645
|
}),
|
|
473
646
|
async execute(_id, params, _signal, _onUpdate, ctx) {
|
|
474
647
|
const runId = getRunId(ctx);
|
|
475
|
-
const
|
|
476
|
-
|
|
477
|
-
|
|
648
|
+
const p = params as {
|
|
649
|
+
round_index: number;
|
|
650
|
+
debate_round_focus?: string;
|
|
651
|
+
};
|
|
652
|
+
const roundIndex = Number(p.round_index);
|
|
653
|
+
const focus =
|
|
654
|
+
p.debate_round_focus === "spec" ||
|
|
655
|
+
p.debate_round_focus === "wbs" ||
|
|
656
|
+
p.debate_round_focus === "schedule" ||
|
|
657
|
+
p.debate_round_focus === "quality"
|
|
658
|
+
? p.debate_round_focus
|
|
659
|
+
: undefined;
|
|
478
660
|
const status = await getPlanDebateRoundStatus(
|
|
479
661
|
runDir(process.cwd(), runId),
|
|
480
662
|
roundIndex,
|
|
663
|
+
runId,
|
|
664
|
+
focus ? { debate_round_focus: focus } : undefined,
|
|
481
665
|
);
|
|
482
666
|
const lines = [
|
|
483
667
|
`Round ${roundIndex}: ready_for_integrator=${status.ready_for_integrator}`,
|
|
@@ -493,6 +677,83 @@ export default function harnessDebateTools(pi: ExtensionAPI) {
|
|
|
493
677
|
},
|
|
494
678
|
});
|
|
495
679
|
|
|
680
|
+
pi.registerTool({
|
|
681
|
+
name: "harness_debate_focus_coverage",
|
|
682
|
+
label: "Plan Debate Focus Coverage",
|
|
683
|
+
description:
|
|
684
|
+
"Return which Review Gate focuses (spec|wbs|schedule|quality) are covered by submitted review-round artifacts and whether debate outcome is complete.",
|
|
685
|
+
parameters: Type.Object({}),
|
|
686
|
+
async execute(_id, _params, _signal, _onUpdate, ctx) {
|
|
687
|
+
const runId = getRunId(ctx);
|
|
688
|
+
const rd = runDir(process.cwd(), runId);
|
|
689
|
+
const messenger = await loadMessengerState(rd);
|
|
690
|
+
const requiredFocuses = messenger?.required_focuses;
|
|
691
|
+
const coverage = await getPlanFocusCoverage(rd, { requiredFocuses });
|
|
692
|
+
const caps = capsForDebate(
|
|
693
|
+
planDebateIdForRun(runId),
|
|
694
|
+
messenger?.debate_profile,
|
|
695
|
+
);
|
|
696
|
+
const complete = planDebateOutcomeComplete(coverage, {
|
|
697
|
+
requiredFocuses,
|
|
698
|
+
minRoundIndex: caps.min_focus_rounds,
|
|
699
|
+
});
|
|
700
|
+
const lines = [
|
|
701
|
+
`Profile: ${messenger?.debate_profile ?? "standard"}`,
|
|
702
|
+
`Required: ${(requiredFocuses ?? ["spec", "wbs", "schedule", "quality"]).join(", ")}`,
|
|
703
|
+
`Covered: ${coverage.covered.join(", ") || "(none)"}`,
|
|
704
|
+
coverage.missing.length
|
|
705
|
+
? `Missing: ${coverage.missing.join(", ")}`
|
|
706
|
+
: "All required focuses covered.",
|
|
707
|
+
`Last round: ${coverage.last_round_index}, review_gate_ready=${coverage.last_review_gate_ready}`,
|
|
708
|
+
`Outcome complete: ${complete}`,
|
|
709
|
+
`Budget: min_focus_rounds=${caps.min_focus_rounds}, max_rounds=${caps.max_rounds}, max_exchanges_per_round=${caps.max_exchanges_per_round}`,
|
|
710
|
+
];
|
|
711
|
+
return {
|
|
712
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
713
|
+
details: {
|
|
714
|
+
coverage,
|
|
715
|
+
caps,
|
|
716
|
+
complete,
|
|
717
|
+
profile: messenger?.debate_profile,
|
|
718
|
+
},
|
|
719
|
+
};
|
|
720
|
+
},
|
|
721
|
+
});
|
|
722
|
+
|
|
723
|
+
pi.registerTool({
|
|
724
|
+
name: "harness_debate_advance_thread",
|
|
725
|
+
label: "Advance Plan Debate Thread",
|
|
726
|
+
description:
|
|
727
|
+
"Ping-pong helper: read round transcript and return next spawn (evaluator clarification vs adversary counter) based on unresolved claim_ids and exchange_count.",
|
|
728
|
+
parameters: Type.Object({
|
|
729
|
+
round_index: Type.Number(),
|
|
730
|
+
}),
|
|
731
|
+
async execute(_id, params, _signal, _onUpdate, ctx) {
|
|
732
|
+
const runId = getRunId(ctx);
|
|
733
|
+
const roundIndex = Number(
|
|
734
|
+
(params as { round_index: number }).round_index,
|
|
735
|
+
);
|
|
736
|
+
const status = await getPlanDebateRoundStatus(
|
|
737
|
+
runDir(process.cwd(), runId),
|
|
738
|
+
roundIndex,
|
|
739
|
+
runId,
|
|
740
|
+
);
|
|
741
|
+
const text = [
|
|
742
|
+
`Round ${roundIndex}: exchange_count=${status.exchange_count}`,
|
|
743
|
+
status.unresolved_claim_ids.length
|
|
744
|
+
? `Unresolved claims: ${status.unresolved_claim_ids.join(", ")}`
|
|
745
|
+
: "No unresolved claims.",
|
|
746
|
+
status.next_tool
|
|
747
|
+
? `Next: ${status.next_tool}`
|
|
748
|
+
: "Dialogue complete — spawn review-integrator.",
|
|
749
|
+
].join("\n");
|
|
750
|
+
return {
|
|
751
|
+
content: [{ type: "text", text }],
|
|
752
|
+
details: status,
|
|
753
|
+
};
|
|
754
|
+
},
|
|
755
|
+
});
|
|
756
|
+
|
|
496
757
|
pi.registerTool({
|
|
497
758
|
name: "harness_plan_scope_check",
|
|
498
759
|
label: "Plan Scope Drift Check",
|