@miller-tech/uap 1.26.6 → 1.28.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.
Files changed (41) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/bin/cli.js +20 -0
  3. package/dist/bin/cli.js.map +1 -1
  4. package/dist/cli/deliver.d.ts +21 -0
  5. package/dist/cli/deliver.d.ts.map +1 -0
  6. package/dist/cli/deliver.js +197 -0
  7. package/dist/cli/deliver.js.map +1 -0
  8. package/dist/delivery/applier.d.ts +50 -0
  9. package/dist/delivery/applier.d.ts.map +1 -0
  10. package/dist/delivery/applier.js +258 -0
  11. package/dist/delivery/applier.js.map +1 -0
  12. package/dist/delivery/convergence-loop.d.ts +143 -0
  13. package/dist/delivery/convergence-loop.d.ts.map +1 -0
  14. package/dist/delivery/convergence-loop.js +301 -0
  15. package/dist/delivery/convergence-loop.js.map +1 -0
  16. package/dist/delivery/critic.d.ts +35 -0
  17. package/dist/delivery/critic.d.ts.map +1 -0
  18. package/dist/delivery/critic.js +77 -0
  19. package/dist/delivery/critic.js.map +1 -0
  20. package/dist/delivery/explorer.d.ts +77 -0
  21. package/dist/delivery/explorer.d.ts.map +1 -0
  22. package/dist/delivery/explorer.js +166 -0
  23. package/dist/delivery/explorer.js.map +1 -0
  24. package/dist/delivery/index.d.ts +15 -0
  25. package/dist/delivery/index.d.ts.map +1 -0
  26. package/dist/delivery/index.js +15 -0
  27. package/dist/delivery/index.js.map +1 -0
  28. package/dist/delivery/judge.d.ts +33 -0
  29. package/dist/delivery/judge.d.ts.map +1 -0
  30. package/dist/delivery/judge.js +70 -0
  31. package/dist/delivery/judge.js.map +1 -0
  32. package/dist/delivery/verifier-ladder.d.ts +78 -0
  33. package/dist/delivery/verifier-ladder.d.ts.map +1 -0
  34. package/dist/delivery/verifier-ladder.js +213 -0
  35. package/dist/delivery/verifier-ladder.js.map +1 -0
  36. package/dist/models/openai-compat-client.d.ts +34 -0
  37. package/dist/models/openai-compat-client.d.ts.map +1 -0
  38. package/dist/models/openai-compat-client.js +82 -0
  39. package/dist/models/openai-compat-client.js.map +1 -0
  40. package/package.json +1 -1
  41. package/tools/agents/docker-compose.qdrant.yml +7 -1
@@ -0,0 +1,301 @@
1
+ /**
2
+ * Convergence Loop
3
+ *
4
+ * Drives an underlying model through execute → apply → verify → feedback
5
+ * iterations until the project's completion gates (verifier ladder) pass or
6
+ * the turn budget is exhausted.
7
+ *
8
+ * The loop owns pluggable seams so phases extend without breaking changes:
9
+ * - executor: how a prompt becomes model output
10
+ * - applier: how model output is materialized into the project tree
11
+ * - promptBuilder: how instruction/feedback/critique compose a prompt
12
+ * - ladderRunner: how gates are verified
13
+ * - explorer (Phase 2): best-of-N candidate exploration with judge tie-break
14
+ * - critic (Phase 3): structured repair plans replacing raw gate dumps
15
+ * - onIteration: per-turn control hook (Phase 5 escalation controllers)
16
+ */
17
+ import { detectRungs, runLadder } from './verifier-ladder.js';
18
+ import { applyFileBlocks } from './applier.js';
19
+ import { exploreAndCommit } from './explorer.js';
20
+ const DEFAULT_MAX_TURNS = 5;
21
+ const DEFAULT_PREVIOUS_OUTPUT_CHARS = 3_000;
22
+ const OUTPUT_CONTRACT = [
23
+ 'You are an autonomous software delivery agent. Complete the task by emitting complete file contents.',
24
+ '',
25
+ 'OUTPUT FORMAT — emit every file you create or modify as a fenced block:',
26
+ '```file:relative/path/from/project/root',
27
+ '<entire file content>',
28
+ '```',
29
+ 'Use a longer fence (````file:path) when the file itself contains ``` sequences.',
30
+ 'Files are written to disk verbatim, then real gates (build, type-check, tests) run.',
31
+ 'Emit only file blocks plus brief reasoning.',
32
+ ].join('\n');
33
+ function truncateHead(text, maxChars) {
34
+ if (text.length <= maxChars)
35
+ return text;
36
+ return `${text.slice(0, maxChars)}\n…(truncated)…`;
37
+ }
38
+ /** Default prompt strategy: lean contract + structured retry context. */
39
+ export const defaultPromptBuilder = (ctx) => {
40
+ if (ctx.turn === 1) {
41
+ return [OUTPUT_CONTRACT, '', `TASK: ${ctx.instruction}`].join('\n');
42
+ }
43
+ const sections = [OUTPUT_CONTRACT, '', `TASK: ${ctx.instruction}`, ''];
44
+ sections.push(`PREVIOUS ATTEMPT (turn ${ctx.turn - 1}):`);
45
+ if (ctx.previousFiles && ctx.previousFiles.length > 0) {
46
+ sections.push(`Files you emitted: ${ctx.previousFiles.join(', ')}`);
47
+ }
48
+ if (ctx.applyError) {
49
+ sections.push(`Your output could not be applied: ${ctx.applyError}`);
50
+ }
51
+ // A structured repair plan outranks the raw gate dump: one concrete action
52
+ // per line is what small models can actually execute.
53
+ if (ctx.critique && ctx.critique.length > 0) {
54
+ sections.push('');
55
+ sections.push('REPAIR PLAN — apply these fixes exactly:');
56
+ ctx.critique.forEach((step, i) => sections.push(`${i + 1}. ${step}`));
57
+ }
58
+ if (ctx.feedback) {
59
+ sections.push('');
60
+ sections.push(ctx.feedback);
61
+ }
62
+ if (ctx.previousOutput) {
63
+ sections.push('');
64
+ sections.push('Your previous output (truncated):');
65
+ sections.push(truncateHead(ctx.previousOutput, DEFAULT_PREVIOUS_OUTPUT_CHARS));
66
+ }
67
+ sections.push('');
68
+ sections.push('Fix the issues and emit corrected file blocks.');
69
+ return sections.join('\n');
70
+ };
71
+ export class ConvergenceLoop {
72
+ config;
73
+ executor;
74
+ ladderRunner;
75
+ applier;
76
+ promptBuilder;
77
+ constructor(config, executor, seams = {}) {
78
+ this.config = config;
79
+ this.executor = executor;
80
+ this.ladderRunner = seams.ladderRunner ?? runLadder;
81
+ this.applier = seams.applier ?? applyFileBlocks;
82
+ this.promptBuilder = seams.promptBuilder ?? defaultPromptBuilder;
83
+ }
84
+ /** Single-candidate turn: execute → apply → verify. */
85
+ async runSingleTurn(prompt, rungs) {
86
+ let output = '';
87
+ let executorError;
88
+ try {
89
+ output = await this.executor(prompt);
90
+ }
91
+ catch (err) {
92
+ executorError = err instanceof Error ? err.message : String(err);
93
+ }
94
+ let applyResult = null;
95
+ let applyError;
96
+ if (!executorError) {
97
+ applyResult = await this.applier(output, this.config.projectRoot);
98
+ if (applyResult.error) {
99
+ applyError = applyResult.error;
100
+ }
101
+ else if (applyResult.rejected.length > 0) {
102
+ applyError = `Rejected blocks: ${applyResult.rejected
103
+ .map((r) => `${r.path} (${r.reason})`)
104
+ .join('; ')}`;
105
+ }
106
+ }
107
+ // Verify — only when something was applied; otherwise the tree is
108
+ // unchanged and re-running gates would waste minutes for no signal.
109
+ const filesApplied = applyResult?.filesWritten ?? [];
110
+ let ladder = null;
111
+ if (!executorError && filesApplied.length > 0) {
112
+ ladder = await this.ladderRunner(rungs, this.config.projectRoot, this.config.ladderOptions);
113
+ }
114
+ return { output, filesApplied, ladder, executorError, applyError };
115
+ }
116
+ /** Explorer turn: best-of-N candidates, commit the winner (Phase 2). */
117
+ async runExplorerTurn(instruction, prompt, rungs, settings) {
118
+ const exploration = await exploreAndCommit(instruction, prompt, this.executor, {
119
+ candidates: settings.candidates,
120
+ seeds: settings.seeds,
121
+ judge: settings.judge,
122
+ projectRoot: this.config.projectRoot,
123
+ rungs,
124
+ ladderOptions: this.config.ladderOptions,
125
+ ladderRunner: this.ladderRunner,
126
+ });
127
+ const summaries = exploration.candidates.map((c) => ({
128
+ id: c.id,
129
+ strategy: c.strategy,
130
+ passed: c.passed,
131
+ score: c.score,
132
+ error: c.error,
133
+ }));
134
+ const winner = exploration.winner;
135
+ if (!winner) {
136
+ // Distinguish executor failure (no usable model output) from apply
137
+ // failure (output produced but no file blocks) so the retry prompt
138
+ // carries the right guidance — matching single-turn feedback quality.
139
+ const execErrors = exploration.candidates.map((c) => c.error).filter(Boolean);
140
+ if (execErrors.length === exploration.candidates.length && execErrors.length > 0) {
141
+ return {
142
+ output: '',
143
+ filesApplied: [],
144
+ ladder: null,
145
+ executorError: execErrors.join('; '),
146
+ candidates: summaries,
147
+ };
148
+ }
149
+ const applyErr = exploration.candidates.map((c) => c.applyResult?.error).find(Boolean) ??
150
+ 'No candidate produced applicable file blocks.';
151
+ return {
152
+ output: '',
153
+ filesApplied: [],
154
+ ladder: null,
155
+ applyError: applyErr,
156
+ candidates: summaries,
157
+ };
158
+ }
159
+ let applyError;
160
+ if (winner.applyResult?.error) {
161
+ applyError = winner.applyResult.error;
162
+ }
163
+ else if (winner.applyResult && winner.applyResult.rejected.length > 0) {
164
+ applyError = `Rejected blocks: ${winner.applyResult.rejected
165
+ .map((r) => `${r.path} (${r.reason})`)
166
+ .join('; ')}`;
167
+ }
168
+ return {
169
+ output: winner.output,
170
+ filesApplied: winner.applyResult?.filesWritten ?? [],
171
+ ladder: exploration.ladder,
172
+ applyError,
173
+ strategy: winner.strategy,
174
+ candidates: summaries,
175
+ judgeRationale: exploration.judgeRationale,
176
+ };
177
+ }
178
+ /**
179
+ * Run the loop for an instruction until all required gates pass or the
180
+ * turn budget is exhausted. Returns the full iteration history so callers
181
+ * can record outcomes and inspect convergence behavior.
182
+ */
183
+ async deliver(instruction) {
184
+ const start = Date.now();
185
+ const maxTurns = this.config.maxTurns ?? DEFAULT_MAX_TURNS;
186
+ const rungs = this.config.rungs && this.config.rungs.length > 0
187
+ ? this.config.rungs
188
+ : detectRungs(this.config.projectRoot);
189
+ if (rungs.length === 0) {
190
+ throw new Error(`No verifiable gates for ${this.config.projectRoot} — pass explicit rungs or add package.json scripts.`);
191
+ }
192
+ if (!Number.isInteger(maxTurns) || maxTurns < 1) {
193
+ throw new Error(`maxTurns must be a positive integer, got ${String(this.config.maxTurns)}`);
194
+ }
195
+ const history = [];
196
+ const previousOutputChars = this.config.previousOutputChars ?? DEFAULT_PREVIOUS_OUTPUT_CHARS;
197
+ // Baseline: a green tree means there is nothing for the loop to deliver.
198
+ if (this.config.baselineCheck ?? true) {
199
+ const baseline = await this.ladderRunner(rungs, this.config.projectRoot, this.config.ladderOptions);
200
+ if (baseline.passed) {
201
+ return {
202
+ success: true,
203
+ alreadyDelivered: true,
204
+ turns: 0,
205
+ bestScore: baseline.score,
206
+ bestTurn: 0,
207
+ history,
208
+ finalFeedback: baseline.feedback,
209
+ finalOutput: '',
210
+ totalDurationMs: Date.now() - start,
211
+ };
212
+ }
213
+ }
214
+ let success = false;
215
+ let finalOutput = '';
216
+ let finalFeedback = '';
217
+ let prevContext = {};
218
+ for (let turn = 1; turn <= maxTurns; turn++) {
219
+ const turnStart = Date.now();
220
+ const prompt = this.promptBuilder({ instruction, turn, ...prevContext });
221
+ const outcome = this.config.explorer
222
+ ? await this.runExplorerTurn(instruction, prompt, rungs, this.config.explorer)
223
+ : await this.runSingleTurn(prompt, rungs);
224
+ finalOutput = outcome.output || finalOutput;
225
+ if (outcome.ladder) {
226
+ finalFeedback = outcome.ladder.feedback;
227
+ }
228
+ const record = {
229
+ turn,
230
+ passed: outcome.ladder?.passed ?? false,
231
+ score: outcome.ladder?.score ?? 0,
232
+ gateResults: outcome.ladder?.results ?? [],
233
+ filesApplied: outcome.filesApplied,
234
+ executorError: outcome.executorError,
235
+ applyError: outcome.applyError,
236
+ strategy: outcome.strategy,
237
+ candidates: outcome.candidates,
238
+ judgeRationale: outcome.judgeRationale,
239
+ durationMs: Date.now() - turnStart,
240
+ };
241
+ history.push(record);
242
+ const directive = this.config.onIteration?.(record);
243
+ if (outcome.ladder?.passed) {
244
+ success = true;
245
+ break;
246
+ }
247
+ if (directive === 'stop') {
248
+ break;
249
+ }
250
+ // Phase 3: structured critique of the failed turn (fail-soft). Skipped
251
+ // on the last turn — prevContext is never consumed, so it would waste
252
+ // a model call.
253
+ let critique;
254
+ if (this.config.critic && !outcome.executorError && turn < maxTurns) {
255
+ try {
256
+ const result = await this.config.critic({
257
+ instruction,
258
+ record,
259
+ feedback: outcome.ladder?.feedback ?? outcome.applyError ?? '',
260
+ attemptOutput: truncateHead(outcome.output, previousOutputChars),
261
+ });
262
+ critique = result.fixList.length > 0 ? result.fixList : undefined;
263
+ }
264
+ catch {
265
+ critique = undefined;
266
+ }
267
+ }
268
+ prevContext = {
269
+ previousOutput: outcome.executorError
270
+ ? undefined
271
+ : truncateHead(outcome.output, previousOutputChars),
272
+ feedback: outcome.executorError
273
+ ? `Model call failed: ${outcome.executorError}`
274
+ : outcome.ladder?.feedback,
275
+ applyError: outcome.applyError,
276
+ previousFiles: outcome.filesApplied.length > 0 ? outcome.filesApplied : undefined,
277
+ critique,
278
+ };
279
+ }
280
+ let bestScore = 0;
281
+ let bestTurn = 0;
282
+ for (const record of history) {
283
+ if (record.score > bestScore) {
284
+ bestScore = record.score;
285
+ bestTurn = record.turn;
286
+ }
287
+ }
288
+ return {
289
+ success,
290
+ alreadyDelivered: false,
291
+ turns: history.length,
292
+ bestScore,
293
+ bestTurn,
294
+ history,
295
+ finalFeedback,
296
+ finalOutput,
297
+ totalDurationMs: Date.now() - start,
298
+ };
299
+ }
300
+ }
301
+ //# sourceMappingURL=convergence-loop.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"convergence-loop.js","sourceRoot":"","sources":["../../src/delivery/convergence-loop.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Structured Critic (Phase 3)
3
+ *
4
+ * Replaces raw gate-output dumps with a decomposed repair plan. After a
5
+ * failed iteration, the critic analyzes the gate feedback through a
6
+ * gate-specific lens and emits a numbered, file-scoped fix list sized for
7
+ * small-model context budgets — one concrete action per line beats a wall
8
+ * of compiler output.
9
+ */
10
+ import type { LoopExecutor } from './convergence-loop.js';
11
+ import type { IterationRecord } from './convergence-loop.js';
12
+ export interface CritiqueInput {
13
+ instruction: string;
14
+ /** The failed iteration being critiqued */
15
+ record: IterationRecord;
16
+ /** Gate feedback from the ladder (already truncated) */
17
+ feedback: string;
18
+ /** Model output from the failed attempt (already truncated) */
19
+ attemptOutput: string;
20
+ }
21
+ export interface Critique {
22
+ /** Numbered, file-scoped repair steps */
23
+ fixList: string[];
24
+ /** Gate the critique focuses on (first failing required gate) */
25
+ focusGate?: string;
26
+ }
27
+ export type Critic = (input: CritiqueInput) => Promise<Critique>;
28
+ /** Parse numbered lines ("1. ...", "2) ...") out of model output. */
29
+ export declare function parseFixList(text: string): string[];
30
+ /**
31
+ * Model-backed critic. Fail-soft: on executor error or unparseable output
32
+ * it returns an empty fix list, and the loop falls back to raw feedback.
33
+ */
34
+ export declare function createModelCritic(executor: LoopExecutor): Critic;
35
+ //# sourceMappingURL=critic.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"critic.d.ts","sourceRoot":"","sources":["../../src/delivery/critic.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE7D,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,2CAA2C;IAC3C,MAAM,EAAE,eAAe,CAAC;IACxB,wDAAwD;IACxD,QAAQ,EAAE,MAAM,CAAC;IACjB,+DAA+D;IAC/D,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,QAAQ;IACvB,yCAAyC;IACzC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,iEAAiE;IACjE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,MAAM,GAAG,CAAC,KAAK,EAAE,aAAa,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AAmDjE,qEAAqE;AACrE,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CASnD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,YAAY,GAAG,MAAM,CAUhE"}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Structured Critic (Phase 3)
3
+ *
4
+ * Replaces raw gate-output dumps with a decomposed repair plan. After a
5
+ * failed iteration, the critic analyzes the gate feedback through a
6
+ * gate-specific lens and emits a numbered, file-scoped fix list sized for
7
+ * small-model context budgets — one concrete action per line beats a wall
8
+ * of compiler output.
9
+ */
10
+ /** Gate-specific analyst personas — the lens shapes what the critic looks for. */
11
+ const GATE_PERSONAS = {
12
+ build: 'You are a compiler-error analyst. Map each error to its file and the exact change that resolves it.',
13
+ typecheck: 'You are a TypeScript type-system expert. For each type error, state the file, the conflicting types, and the precise fix.',
14
+ test: 'You are a test-failure analyst. For each failing test, state what behavior it expects, which source file implements that behavior, and what must change.',
15
+ lint: 'You are a code-style reviewer. List the mechanical fixes per file.',
16
+ };
17
+ const DEFAULT_PERSONA = 'You are a senior engineer diagnosing why a change failed verification.';
18
+ const MAX_FIX_STEPS = 8;
19
+ function firstFailingGate(record) {
20
+ return record.gateResults.find((g) => !g.passed && !g.skipped)?.id;
21
+ }
22
+ function buildCriticPrompt(input) {
23
+ const gate = firstFailingGate(input.record);
24
+ const persona = (gate && GATE_PERSONAS[gate]) ?? DEFAULT_PERSONA;
25
+ return [
26
+ persona,
27
+ '',
28
+ `TASK BEING ATTEMPTED: ${input.instruction}`,
29
+ '',
30
+ input.record.filesApplied.length > 0
31
+ ? `FILES CHANGED BY THE ATTEMPT: ${input.record.filesApplied.join(', ')}`
32
+ : 'THE ATTEMPT CHANGED NO FILES.',
33
+ '',
34
+ 'VERIFICATION FEEDBACK:',
35
+ input.feedback,
36
+ '',
37
+ 'THE ATTEMPT (truncated):',
38
+ input.attemptOutput,
39
+ '',
40
+ `Produce a repair plan: at most ${MAX_FIX_STEPS} numbered steps, each naming a specific file and a specific change.`,
41
+ 'Format strictly as numbered lines ("1. <file>: <change>"). No prose before or after.',
42
+ ].join('\n');
43
+ }
44
+ /** Max characters of critic output parsed (bounds work on untrusted text). */
45
+ const MAX_CRITIC_CHARS = 20_000;
46
+ /** Linear, anchored matcher — no overlapping quantifiers (avoids ReDoS). */
47
+ const FIX_LINE_RE = /^\s{0,8}(\d{1,3})[.)]\s+(\S[^\n]*?)\s*$/;
48
+ /** Parse numbered lines ("1. ...", "2) ...") out of model output. */
49
+ export function parseFixList(text) {
50
+ const steps = [];
51
+ const bounded = text.length > MAX_CRITIC_CHARS ? text.slice(0, MAX_CRITIC_CHARS) : text;
52
+ for (const line of bounded.split('\n')) {
53
+ const match = FIX_LINE_RE.exec(line);
54
+ if (match)
55
+ steps.push(match[2]);
56
+ if (steps.length >= MAX_FIX_STEPS)
57
+ break;
58
+ }
59
+ return steps;
60
+ }
61
+ /**
62
+ * Model-backed critic. Fail-soft: on executor error or unparseable output
63
+ * it returns an empty fix list, and the loop falls back to raw feedback.
64
+ */
65
+ export function createModelCritic(executor) {
66
+ return async (input) => {
67
+ const focusGate = firstFailingGate(input.record);
68
+ try {
69
+ const raw = await executor(buildCriticPrompt(input));
70
+ return { fixList: parseFixList(raw), focusGate };
71
+ }
72
+ catch {
73
+ return { fixList: [], focusGate };
74
+ }
75
+ };
76
+ }
77
+ //# sourceMappingURL=critic.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"critic.js","sourceRoot":"","sources":["../../src/delivery/critic.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAwBH,kFAAkF;AAClF,MAAM,aAAa,GAA2B;IAC5C,KAAK,EACH,qGAAqG;IACvG,SAAS,EACP,2HAA2H;IAC7H,IAAI,EACF,0JAA0J;IAC5J,IAAI,EAAE,oEAAoE;CAC3E,CAAC;AAEF,MAAM,eAAe,GACnB,wEAAwE,CAAC;AAE3E,MAAM,aAAa,GAAG,CAAC,CAAC;AAExB,SAAS,gBAAgB,CAAC,MAAuB;IAC/C,OAAO,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC;AACrE,CAAC;AAED,SAAS,iBAAiB,CAAC,KAAoB;IAC7C,MAAM,IAAI,GAAG,gBAAgB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC5C,MAAM,OAAO,GAAG,CAAC,IAAI,IAAI,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,eAAe,CAAC;IAEjE,OAAO;QACL,OAAO;QACP,EAAE;QACF,yBAAyB,KAAK,CAAC,WAAW,EAAE;QAC5C,EAAE;QACF,KAAK,CAAC,MAAM,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC;YAClC,CAAC,CAAC,iCAAiC,KAAK,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;YACzE,CAAC,CAAC,+BAA+B;QACnC,EAAE;QACF,wBAAwB;QACxB,KAAK,CAAC,QAAQ;QACd,EAAE;QACF,0BAA0B;QAC1B,KAAK,CAAC,aAAa;QACnB,EAAE;QACF,kCAAkC,aAAa,qEAAqE;QACpH,sFAAsF;KACvF,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED,8EAA8E;AAC9E,MAAM,gBAAgB,GAAG,MAAM,CAAC;AAChC,4EAA4E;AAC5E,MAAM,WAAW,GAAG,yCAAyC,CAAC;AAE9D,qEAAqE;AACrE,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,GAAG,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACxF,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACvC,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrC,IAAI,KAAK;YAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAChC,IAAI,KAAK,CAAC,MAAM,IAAI,aAAa;YAAE,MAAM;IAC3C,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAAsB;IACtD,OAAO,KAAK,EAAE,KAAK,EAAE,EAAE;QACrB,MAAM,SAAS,GAAG,gBAAgB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACjD,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,CAAC;YACrD,OAAO,EAAE,OAAO,EAAE,YAAY,CAAC,GAAG,CAAC,EAAE,SAAS,EAAE,CAAC;QACnD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC;QACpC,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Explorer — best-of-N candidate exploration (Phase 2)
3
+ *
4
+ * Instead of committing to a single attempt per turn, the explorer:
5
+ * 1. generates N candidates concurrently, each steered by a distinct
6
+ * strategy seed (diversity by prompt, not temperature — small-model
7
+ * profiles pin temperature low for stability)
8
+ * 2. evaluates each candidate against the real gates on the same baseline
9
+ * tree via apply → verify → rollback
10
+ * 3. ranks objectively (gates passed, then score); a judge tie-breaks
11
+ * candidates tied at the top
12
+ * 4. commits only the winner to the tree
13
+ *
14
+ * Candidate verification is sequential by design: gates (npm test, builds)
15
+ * cannot safely run concurrently in one tree. Worktree-isolated parallel
16
+ * verification is a planned optimization (inject via `revertibleApplier` +
17
+ * a per-candidate workspace), not a Phase 2 requirement.
18
+ *
19
+ * Fairness caveat: rollback reverts files the model wrote, but gate commands
20
+ * also mutate the tree (dist/ output, snapshots, caches). Candidate N+1 may
21
+ * therefore see candidate N's gate side effects. The committed winner is
22
+ * re-verified after commit so its reported ladder reflects real on-disk
23
+ * state. Full per-candidate isolation requires the workspace seam above.
24
+ */
25
+ import type { GateRung, LadderResult, LadderOptions } from './verifier-ladder.js';
26
+ import type { LadderRunner, LoopExecutor } from './convergence-loop.js';
27
+ import type { Applier, ApplyResult, RevertibleApply } from './applier.js';
28
+ import type { Judge } from './judge.js';
29
+ /** Hard ceiling on candidates per turn — guards direct library callers
30
+ * (the CLI caps lower); each candidate costs a model call + a full gate run. */
31
+ export declare const MAX_CANDIDATES = 8;
32
+ export interface StrategySeed {
33
+ id: string;
34
+ hint: string;
35
+ }
36
+ export declare const DEFAULT_STRATEGY_SEEDS: StrategySeed[];
37
+ export interface CandidateResult {
38
+ id: string;
39
+ strategy: string;
40
+ output: string;
41
+ applyResult: ApplyResult | null;
42
+ ladder: LadderResult | null;
43
+ /** Executor failure for this candidate, if any */
44
+ error?: string;
45
+ passed: boolean;
46
+ score: number;
47
+ }
48
+ export interface ExplorationResult {
49
+ winner: CandidateResult | null;
50
+ candidates: CandidateResult[];
51
+ /** Judge rationale when a tie-break occurred */
52
+ judgeRationale?: string;
53
+ /** Ladder result of the committed winner (from its evaluation run) */
54
+ ladder: LadderResult | null;
55
+ }
56
+ export interface ExplorerConfig {
57
+ /** Number of candidates per turn (default 3) */
58
+ candidates?: number;
59
+ seeds?: StrategySeed[];
60
+ judge?: Judge;
61
+ projectRoot: string;
62
+ rungs: GateRung[];
63
+ ladderOptions?: LadderOptions;
64
+ ladderRunner?: LadderRunner;
65
+ /** Override the commit applier (defaults to applyFileBlocks) */
66
+ applier?: Applier;
67
+ /** Override the per-candidate revertible applier (defaults to applyFileBlocksWithRollback) */
68
+ revertibleApplier?: (output: string, projectRoot: string) => RevertibleApply;
69
+ onCandidate?: (candidate: CandidateResult) => void;
70
+ }
71
+ /**
72
+ * Generate, evaluate, and commit the best candidate for one loop turn.
73
+ * The base prompt comes from the loop's prompt builder; each candidate
74
+ * appends its strategy seed.
75
+ */
76
+ export declare function exploreAndCommit(task: string, basePrompt: string, executor: LoopExecutor, config: ExplorerConfig): Promise<ExplorationResult>;
77
+ //# sourceMappingURL=explorer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"explorer.d.ts","sourceRoot":"","sources":["../../src/delivery/explorer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAElF,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAExE,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC1E,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAExC;gFACgF;AAChF,eAAO,MAAM,cAAc,IAAI,CAAC;AAEhC,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;CACd;AAED,eAAO,MAAM,sBAAsB,EAAE,YAAY,EAiBhD,CAAC;AAEF,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,WAAW,GAAG,IAAI,CAAC;IAChC,MAAM,EAAE,YAAY,GAAG,IAAI,CAAC;IAC5B,kDAAkD;IAClD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,eAAe,GAAG,IAAI,CAAC;IAC/B,UAAU,EAAE,eAAe,EAAE,CAAC;IAC9B,gDAAgD;IAChD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,sEAAsE;IACtE,MAAM,EAAE,YAAY,GAAG,IAAI,CAAC;CAC7B;AAED,MAAM,WAAW,cAAc;IAC7B,gDAAgD;IAChD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,YAAY,EAAE,CAAC;IACvB,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,gEAAgE;IAChE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,8FAA8F;IAC9F,iBAAiB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,eAAe,CAAC;IAC7E,WAAW,CAAC,EAAE,CAAC,SAAS,EAAE,eAAe,KAAK,IAAI,CAAC;CACpD;AAID;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,YAAY,EACtB,MAAM,EAAE,cAAc,GACrB,OAAO,CAAC,iBAAiB,CAAC,CA6H5B"}