@topce/pizx 0.1.0 → 0.3.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/README.md +261 -20
- package/dist/cli.js +681 -722
- package/dist/cli.js.map +4 -4
- package/dist/index.js +673 -715
- package/dist/index.js.map +4 -4
- package/package.json +13 -7
package/dist/index.js
CHANGED
|
@@ -2,7 +2,15 @@
|
|
|
2
2
|
export * from "zx";
|
|
3
3
|
|
|
4
4
|
// src/patterns/types.ts
|
|
5
|
-
import {
|
|
5
|
+
import { createInterface } from "node:readline";
|
|
6
|
+
import { completeSimple } from "@earendil-works/pi-ai";
|
|
7
|
+
|
|
8
|
+
// src/model-picker.ts
|
|
9
|
+
import {
|
|
10
|
+
getEnvApiKey,
|
|
11
|
+
getModels,
|
|
12
|
+
getProviders
|
|
13
|
+
} from "@earendil-works/pi-ai";
|
|
6
14
|
|
|
7
15
|
// src/load-pi-settings.ts
|
|
8
16
|
import { existsSync, readFileSync } from "node:fs";
|
|
@@ -33,40 +41,7 @@ function loadPiSettings(agentDir) {
|
|
|
33
41
|
}
|
|
34
42
|
}
|
|
35
43
|
|
|
36
|
-
// src/
|
|
37
|
-
var PatternOutput = class {
|
|
38
|
-
constructor(text, startTime = Date.now(), endTime = Date.now()) {
|
|
39
|
-
this.text = text;
|
|
40
|
-
this.startTime = startTime;
|
|
41
|
-
this.endTime = endTime;
|
|
42
|
-
}
|
|
43
|
-
text;
|
|
44
|
-
startTime;
|
|
45
|
-
endTime;
|
|
46
|
-
/** Duration in milliseconds */
|
|
47
|
-
get duration() {
|
|
48
|
-
return this.endTime - this.startTime;
|
|
49
|
-
}
|
|
50
|
-
toString() {
|
|
51
|
-
return this.text;
|
|
52
|
-
}
|
|
53
|
-
valueOf() {
|
|
54
|
-
return this.text;
|
|
55
|
-
}
|
|
56
|
-
[Symbol.toPrimitive]() {
|
|
57
|
-
return this.text;
|
|
58
|
-
}
|
|
59
|
-
};
|
|
60
|
-
var PatternPromise = class extends Promise {
|
|
61
|
-
};
|
|
62
|
-
function build(pieces, args) {
|
|
63
|
-
let s = "";
|
|
64
|
-
for (let i = 0; i < pieces.length; i++) {
|
|
65
|
-
s += pieces[i];
|
|
66
|
-
if (i < args.length) s += String(args[i]);
|
|
67
|
-
}
|
|
68
|
-
return s.trim();
|
|
69
|
-
}
|
|
44
|
+
// src/model-picker.ts
|
|
70
45
|
var _piSettings;
|
|
71
46
|
function getPiDefaults() {
|
|
72
47
|
if (_piSettings === void 0) {
|
|
@@ -110,7 +85,8 @@ function pickModel(preferred) {
|
|
|
110
85
|
if (hit) return hit;
|
|
111
86
|
}
|
|
112
87
|
if (settings.defaultProvider) {
|
|
113
|
-
const
|
|
88
|
+
const provider = settings.defaultProvider;
|
|
89
|
+
const providerModels = getModels(provider);
|
|
114
90
|
if (providerModels && providerModels.length > 0) {
|
|
115
91
|
const configured = new Set(getConfiguredProviders());
|
|
116
92
|
if (configured.has(settings.defaultProvider)) {
|
|
@@ -136,9 +112,138 @@ function pickModel(preferred) {
|
|
|
136
112
|
}
|
|
137
113
|
return models[0];
|
|
138
114
|
}
|
|
115
|
+
|
|
116
|
+
// src/patterns/types.ts
|
|
117
|
+
var PatternOutput = class {
|
|
118
|
+
constructor(text, startTime = Date.now(), endTime = Date.now()) {
|
|
119
|
+
this.text = text;
|
|
120
|
+
this.startTime = startTime;
|
|
121
|
+
this.endTime = endTime;
|
|
122
|
+
}
|
|
123
|
+
text;
|
|
124
|
+
startTime;
|
|
125
|
+
endTime;
|
|
126
|
+
/** Execution trace: one entry per LLM call within this pattern run. Populated by createPatternTag. */
|
|
127
|
+
trace = [];
|
|
128
|
+
/** Structured phase log: key phases during execution, populated by each pattern. */
|
|
129
|
+
phaseLog = [];
|
|
130
|
+
/** Duration in milliseconds */
|
|
131
|
+
get duration() {
|
|
132
|
+
return this.endTime - this.startTime;
|
|
133
|
+
}
|
|
134
|
+
/** Total input tokens across all calls */
|
|
135
|
+
get inputTokens() {
|
|
136
|
+
return this.trace.reduce((s, t) => s + t.inputTokens, 0);
|
|
137
|
+
}
|
|
138
|
+
/** Total output tokens across all calls */
|
|
139
|
+
get outputTokens() {
|
|
140
|
+
return this.trace.reduce((s, t) => s + t.outputTokens, 0);
|
|
141
|
+
}
|
|
142
|
+
/** Total tokens (input + output) across all calls */
|
|
143
|
+
get totalTokens() {
|
|
144
|
+
return this.trace.reduce((s, t) => s + t.totalTokens, 0);
|
|
145
|
+
}
|
|
146
|
+
/** Total cost in USD across all calls */
|
|
147
|
+
get totalCost() {
|
|
148
|
+
return this.trace.reduce((s, t) => s + t.cost, 0);
|
|
149
|
+
}
|
|
150
|
+
/** Number of LLM calls made during this pattern execution */
|
|
151
|
+
get callCount() {
|
|
152
|
+
return this.trace.length;
|
|
153
|
+
}
|
|
154
|
+
toString() {
|
|
155
|
+
return this.text;
|
|
156
|
+
}
|
|
157
|
+
valueOf() {
|
|
158
|
+
return this.text;
|
|
159
|
+
}
|
|
160
|
+
[Symbol.toPrimitive]() {
|
|
161
|
+
return this.text;
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
var PatternPromise = class extends Promise {
|
|
165
|
+
};
|
|
166
|
+
var _trace = null;
|
|
167
|
+
function beginTrace() {
|
|
168
|
+
_trace = [];
|
|
169
|
+
}
|
|
170
|
+
function collectTrace() {
|
|
171
|
+
const t = _trace ?? [];
|
|
172
|
+
_trace = null;
|
|
173
|
+
return t;
|
|
174
|
+
}
|
|
175
|
+
function pushTrace(entry) {
|
|
176
|
+
if (_trace) _trace.push(entry);
|
|
177
|
+
}
|
|
178
|
+
function createPatternTag(defaults17, execute17) {
|
|
179
|
+
function make(opts = {}) {
|
|
180
|
+
const merged = { ...defaults17, ...opts };
|
|
181
|
+
const fn = ((pieces, ...args) => {
|
|
182
|
+
if (!Array.isArray(pieces)) {
|
|
183
|
+
return make({ ...merged, ...pieces });
|
|
184
|
+
}
|
|
185
|
+
beginTrace();
|
|
186
|
+
return new PatternPromise((resolve, reject) => {
|
|
187
|
+
execute17(pieces, args, merged).then(
|
|
188
|
+
(output) => {
|
|
189
|
+
output.trace = collectTrace();
|
|
190
|
+
resolve(output);
|
|
191
|
+
},
|
|
192
|
+
(err) => {
|
|
193
|
+
collectTrace();
|
|
194
|
+
reject(err);
|
|
195
|
+
}
|
|
196
|
+
);
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
let _quiet;
|
|
200
|
+
Object.defineProperty(fn, "quiet", {
|
|
201
|
+
get() {
|
|
202
|
+
if (!_quiet) _quiet = make({ ...merged, quiet: true });
|
|
203
|
+
return _quiet;
|
|
204
|
+
},
|
|
205
|
+
enumerable: true,
|
|
206
|
+
configurable: true
|
|
207
|
+
});
|
|
208
|
+
return fn;
|
|
209
|
+
}
|
|
210
|
+
return make();
|
|
211
|
+
}
|
|
212
|
+
function build(pieces, args) {
|
|
213
|
+
let s = "";
|
|
214
|
+
for (let i = 0; i < pieces.length; i++) {
|
|
215
|
+
s += pieces[i];
|
|
216
|
+
if (i < args.length) s += String(args[i]);
|
|
217
|
+
}
|
|
218
|
+
return s.trim();
|
|
219
|
+
}
|
|
220
|
+
function mergeSystem(userSystem, patternSystem) {
|
|
221
|
+
if (!userSystem) return patternSystem;
|
|
222
|
+
return `${userSystem}
|
|
223
|
+
|
|
224
|
+
${patternSystem}`;
|
|
225
|
+
}
|
|
226
|
+
async function confirmPhase(description, opts) {
|
|
227
|
+
if (!opts.confirm) return true;
|
|
228
|
+
if (!opts.quiet) {
|
|
229
|
+
process.stderr.write(`
|
|
230
|
+
\u2500\u2500 Confirm \u2500\u2500
|
|
231
|
+
${description}
|
|
232
|
+
Proceed? [Y/n] `);
|
|
233
|
+
}
|
|
234
|
+
const rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
235
|
+
const answer = await new Promise((resolve) => {
|
|
236
|
+
rl.question("", (ans) => resolve(ans));
|
|
237
|
+
});
|
|
238
|
+
rl.close();
|
|
239
|
+
const trimmed = answer.trim().toLowerCase();
|
|
240
|
+
if (trimmed === "" || trimmed === "y" || trimmed === "yes") return true;
|
|
241
|
+
return false;
|
|
242
|
+
}
|
|
139
243
|
async function ask(prompt, opts = {}) {
|
|
140
244
|
const model = pickModel(opts.model);
|
|
141
245
|
if (!model) throw new Error("pizx/patterns: No AI models configured. Run `pi auth login` first.");
|
|
246
|
+
const t0 = Date.now();
|
|
142
247
|
const result = await completeSimple(
|
|
143
248
|
model,
|
|
144
249
|
{
|
|
@@ -147,12 +252,74 @@ async function ask(prompt, opts = {}) {
|
|
|
147
252
|
},
|
|
148
253
|
{
|
|
149
254
|
maxTokens: opts.maxTokens ?? 4096,
|
|
150
|
-
reasoning: opts.thinkingLevel ?? "medium"
|
|
255
|
+
reasoning: opts.thinkingLevel ?? "medium",
|
|
256
|
+
timeoutMs: opts.timeoutMs,
|
|
257
|
+
maxRetries: opts.maxRetries
|
|
151
258
|
}
|
|
152
259
|
);
|
|
260
|
+
const durationMs = Date.now() - t0;
|
|
261
|
+
if (!result.content || !Array.isArray(result.content)) {
|
|
262
|
+
throw new Error("pizx/patterns: Unexpected response format from AI model.");
|
|
263
|
+
}
|
|
153
264
|
const text = result.content.filter((c) => c.type === "text").map((c) => c.text).join("");
|
|
265
|
+
if (_trace !== null) {
|
|
266
|
+
pushTrace({
|
|
267
|
+
call: _trace.length + 1,
|
|
268
|
+
modelId: result.model,
|
|
269
|
+
promptPreview: prompt.slice(0, 200),
|
|
270
|
+
outputPreview: text.slice(0, 200),
|
|
271
|
+
inputTokens: result.usage.input,
|
|
272
|
+
outputTokens: result.usage.output,
|
|
273
|
+
cacheReadTokens: result.usage.cacheRead,
|
|
274
|
+
cacheWriteTokens: result.usage.cacheWrite,
|
|
275
|
+
totalTokens: result.usage.totalTokens,
|
|
276
|
+
cost: result.usage.cost.total,
|
|
277
|
+
durationMs
|
|
278
|
+
});
|
|
279
|
+
}
|
|
154
280
|
return text.trim();
|
|
155
281
|
}
|
|
282
|
+
var QUALITY_REVIEW_SYSTEM = `You are a quality assurance reviewer. Evaluate the final deliverable against the original request.
|
|
283
|
+
|
|
284
|
+
Output format:
|
|
285
|
+
SCORE: 0.XX (quality score from 0.0 to 1.0)
|
|
286
|
+
ASSESSMENT: (1-2 sentences \u2014 is the output complete, consistent, and actionable?)
|
|
287
|
+
RECOMMENDATION: (1 sentence \u2014 what would improve this output?)`;
|
|
288
|
+
async function runQualityReview(originalRequest, finalOutput, opts) {
|
|
289
|
+
if (!opts.qualityCheck) return void 0;
|
|
290
|
+
const reviewText = await ask(
|
|
291
|
+
`Original request:
|
|
292
|
+
${originalRequest}
|
|
293
|
+
|
|
294
|
+
Final deliverable:
|
|
295
|
+
${finalOutput}
|
|
296
|
+
|
|
297
|
+
Evaluate the quality.`,
|
|
298
|
+
{
|
|
299
|
+
model: opts.plannerModel ?? opts.model,
|
|
300
|
+
maxTokens: 512,
|
|
301
|
+
thinkingLevel: "high",
|
|
302
|
+
timeoutMs: opts.timeoutMs,
|
|
303
|
+
maxRetries: opts.maxRetries,
|
|
304
|
+
system: QUALITY_REVIEW_SYSTEM
|
|
305
|
+
}
|
|
306
|
+
);
|
|
307
|
+
const scoreMatch = reviewText.match(/SCORE:\s*([\d.]+)/i);
|
|
308
|
+
const assessMatch = reviewText.match(/ASSESSMENT:\s*(.+)/i);
|
|
309
|
+
const recMatch = reviewText.match(/RECOMMENDATION:\s*(.+)/i);
|
|
310
|
+
const result = {
|
|
311
|
+
score: scoreMatch ? parseFloat(scoreMatch[1]) : 0.5,
|
|
312
|
+
assessment: assessMatch?.[1]?.trim() ?? "(no assessment)",
|
|
313
|
+
recommendation: recMatch?.[1]?.trim() ?? "(no recommendation)"
|
|
314
|
+
};
|
|
315
|
+
if (!opts.quiet) {
|
|
316
|
+
process.stderr.write(` Quality score: ${result.score.toFixed(2)}
|
|
317
|
+
`);
|
|
318
|
+
process.stderr.write(` ${result.assessment.slice(0, 80)}...
|
|
319
|
+
`);
|
|
320
|
+
}
|
|
321
|
+
return result;
|
|
322
|
+
}
|
|
156
323
|
|
|
157
324
|
// src/patterns/adaptive.ts
|
|
158
325
|
var defaults = {
|
|
@@ -216,10 +383,10 @@ async function execute(pieces, args, opts) {
|
|
|
216
383
|
}
|
|
217
384
|
if (!opts.quiet) process.stderr.write(" \u2192 Planning...\n");
|
|
218
385
|
const planText = await ask(goal, {
|
|
386
|
+
...opts,
|
|
219
387
|
model: plannerModel,
|
|
220
|
-
maxTokens: opts.maxTokens,
|
|
221
388
|
thinkingLevel: "high",
|
|
222
|
-
system: PLAN_SYSTEM
|
|
389
|
+
system: mergeSystem(opts.system, PLAN_SYSTEM)
|
|
223
390
|
});
|
|
224
391
|
const planLines = planText.split("\n");
|
|
225
392
|
const plannedSteps = [];
|
|
@@ -249,10 +416,9 @@ async function execute(pieces, args, opts) {
|
|
|
249
416
|
process.stderr.write(` \u2192 Step ${executionStep}: ${currentStep.slice(0, 60)}...
|
|
250
417
|
`);
|
|
251
418
|
const result = await ask(currentStep, {
|
|
419
|
+
...opts,
|
|
252
420
|
model: workerModel,
|
|
253
|
-
|
|
254
|
-
thinkingLevel: opts.thinkingLevel,
|
|
255
|
-
system: EXECUTE_SYSTEM
|
|
421
|
+
system: mergeSystem(opts.system, EXECUTE_SYSTEM)
|
|
256
422
|
});
|
|
257
423
|
const evaluation = await ask(
|
|
258
424
|
`Goal: ${goal}
|
|
@@ -261,10 +427,11 @@ Result: ${result}
|
|
|
261
427
|
|
|
262
428
|
Evaluate the result.`,
|
|
263
429
|
{
|
|
430
|
+
...opts,
|
|
264
431
|
model: plannerModel,
|
|
265
432
|
maxTokens: 512,
|
|
266
433
|
thinkingLevel: "high",
|
|
267
|
-
system: EVALUATE_SYSTEM
|
|
434
|
+
system: mergeSystem(opts.system, EVALUATE_SYSTEM)
|
|
268
435
|
}
|
|
269
436
|
);
|
|
270
437
|
const scoreMatch = evaluation.match(/SCORE:\s*([\d.]+)/i);
|
|
@@ -287,8 +454,7 @@ Evaluate the result.`,
|
|
|
287
454
|
break;
|
|
288
455
|
}
|
|
289
456
|
const adaptUpper = adaptation.toUpperCase();
|
|
290
|
-
if (adaptUpper.startsWith("
|
|
291
|
-
} else if (adaptUpper.startsWith("SKIP_NEXT")) {
|
|
457
|
+
if (adaptUpper.startsWith("SKIP_NEXT")) {
|
|
292
458
|
stepIndex += 2;
|
|
293
459
|
} else if (adaptUpper.startsWith("ADD")) {
|
|
294
460
|
const newStep = adaptation.replace(/^ADD\s*/i, "");
|
|
@@ -307,36 +473,76 @@ Evaluate the result.`,
|
|
|
307
473
|
).join("\n\n");
|
|
308
474
|
return new AdaptiveOutput(summary, finalResult, adaptiveSteps, executionStep, t0, t1);
|
|
309
475
|
}
|
|
310
|
-
|
|
311
|
-
const merged = { ...defaults, ...opts };
|
|
312
|
-
const fn = ((pieces, ...args) => {
|
|
313
|
-
if (!Array.isArray(pieces)) {
|
|
314
|
-
return makeAdaptive({ ...merged, ...pieces });
|
|
315
|
-
}
|
|
316
|
-
return new PatternPromise((resolve, reject) => {
|
|
317
|
-
execute(pieces, args, merged).then(resolve, reject);
|
|
318
|
-
});
|
|
319
|
-
});
|
|
320
|
-
let _quiet;
|
|
321
|
-
Object.defineProperty(fn, "quiet", {
|
|
322
|
-
get() {
|
|
323
|
-
if (!_quiet) _quiet = makeAdaptive({ ...merged, quiet: true });
|
|
324
|
-
return _quiet;
|
|
325
|
-
},
|
|
326
|
-
enumerable: true,
|
|
327
|
-
configurable: true
|
|
328
|
-
});
|
|
329
|
-
return fn;
|
|
330
|
-
}
|
|
331
|
-
var \u0391 = makeAdaptive();
|
|
476
|
+
var \u0391 = createPatternTag(defaults, execute);
|
|
332
477
|
|
|
333
|
-
// src/patterns/
|
|
334
|
-
var
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
478
|
+
// src/patterns/role-sets.ts
|
|
479
|
+
var DEBATE_ROLE_SETS = {
|
|
480
|
+
2: [
|
|
481
|
+
"Optimist \u2014 advocate for the most ambitious approach",
|
|
482
|
+
"Pessimist \u2014 identify risks and failure modes"
|
|
483
|
+
],
|
|
484
|
+
3: [
|
|
485
|
+
"Optimist \u2014 advocate the benefits and opportunities",
|
|
486
|
+
"Pessimist \u2014 identify risks, costs, and failure modes",
|
|
487
|
+
"Pragmatist \u2014 focus on practical trade-offs and implementation"
|
|
488
|
+
],
|
|
489
|
+
4: [
|
|
490
|
+
"Optimist \u2014 argue for the best-case potential",
|
|
491
|
+
"Pessimist \u2014 highlight worst-case risks and downsides",
|
|
492
|
+
"Pragmatist \u2014 balance pros/cons with practical constraints",
|
|
493
|
+
"Innovator \u2014 propose creative alternatives and novel approaches"
|
|
494
|
+
],
|
|
495
|
+
5: [
|
|
496
|
+
"Optimist",
|
|
497
|
+
"Pessimist",
|
|
498
|
+
"Pragmatist",
|
|
499
|
+
"Innovator",
|
|
500
|
+
"User Advocate \u2014 focus on end-user experience and accessibility"
|
|
501
|
+
]
|
|
502
|
+
};
|
|
503
|
+
var MEMORY_ROLE_SETS = {
|
|
504
|
+
2: ["Analyst \u2014 deep analysis of core aspects", "Reviewer \u2014 check for gaps and blind spots"],
|
|
505
|
+
3: [
|
|
506
|
+
"Analyst \u2014 deep analysis of core aspects",
|
|
507
|
+
"Reviewer \u2014 check for gaps, edge cases, and blind spots",
|
|
508
|
+
"Strategist \u2014 connect findings to actionable insights"
|
|
509
|
+
],
|
|
510
|
+
4: [
|
|
511
|
+
"Analyst",
|
|
512
|
+
"Reviewer",
|
|
513
|
+
"Strategist",
|
|
514
|
+
"Innovator \u2014 propose novel angles and creative solutions"
|
|
515
|
+
],
|
|
516
|
+
5: [
|
|
517
|
+
"Analyst",
|
|
518
|
+
"Reviewer",
|
|
519
|
+
"Strategist",
|
|
520
|
+
"Innovator",
|
|
521
|
+
"Skeptic \u2014 challenge assumptions and stress-test conclusions"
|
|
522
|
+
]
|
|
523
|
+
};
|
|
524
|
+
var THREAD_ROLE_SETS = {
|
|
525
|
+
2: ["Proposer \u2014 advocate the best approach", "Critic \u2014 identify weaknesses and gaps"],
|
|
526
|
+
3: [
|
|
527
|
+
"Proposer \u2014 suggest the best approach",
|
|
528
|
+
"Critic \u2014 identify weaknesses, risks, and missing pieces",
|
|
529
|
+
"Synthesizer \u2014 combine the best ideas into a practical plan"
|
|
530
|
+
],
|
|
531
|
+
4: [
|
|
532
|
+
"Proposer \u2014 advocate a bold solution",
|
|
533
|
+
"Critic \u2014 identify risks and weaknesses",
|
|
534
|
+
"Pragmatist \u2014 focus on practical implementation",
|
|
535
|
+
"Innovator \u2014 propose creative alternatives"
|
|
536
|
+
],
|
|
537
|
+
5: [
|
|
538
|
+
"Proposer",
|
|
539
|
+
"Critic",
|
|
540
|
+
"Pragmatist",
|
|
541
|
+
"Innovator",
|
|
542
|
+
"Devil's Advocate \u2014 challenge every assumption"
|
|
543
|
+
]
|
|
338
544
|
};
|
|
339
|
-
var
|
|
545
|
+
var BROADCAST_ROLE_SETS = {
|
|
340
546
|
2: [
|
|
341
547
|
"Technical Expert \u2014 evaluate technical feasibility",
|
|
342
548
|
"Business Expert \u2014 evaluate business viability"
|
|
@@ -360,6 +566,13 @@ var ROLE_SETS = {
|
|
|
360
566
|
"Innovation Expert \u2014 suggest novel approaches and alternatives"
|
|
361
567
|
]
|
|
362
568
|
};
|
|
569
|
+
|
|
570
|
+
// src/patterns/broadcast.ts
|
|
571
|
+
var defaults2 = {
|
|
572
|
+
maxTokens: 4096,
|
|
573
|
+
thinkingLevel: "medium",
|
|
574
|
+
workers: 4
|
|
575
|
+
};
|
|
363
576
|
var BroadcastResponse = class {
|
|
364
577
|
constructor(role, response, success, error) {
|
|
365
578
|
this.role = role;
|
|
@@ -373,13 +586,15 @@ var BroadcastResponse = class {
|
|
|
373
586
|
error;
|
|
374
587
|
};
|
|
375
588
|
var BroadcastOutput = class extends PatternOutput {
|
|
376
|
-
constructor(text, synthesis, responses, startTime, endTime) {
|
|
589
|
+
constructor(text, synthesis, responses, startTime, endTime, qualityReview) {
|
|
377
590
|
super(text, startTime, endTime);
|
|
378
591
|
this.synthesis = synthesis;
|
|
379
592
|
this.responses = responses;
|
|
593
|
+
this.qualityReview = qualityReview;
|
|
380
594
|
}
|
|
381
595
|
synthesis;
|
|
382
596
|
responses;
|
|
597
|
+
qualityReview;
|
|
383
598
|
};
|
|
384
599
|
var WORKER_PROMPT = `You are a {role}.
|
|
385
600
|
|
|
@@ -394,7 +609,7 @@ async function execute2(pieces, args, opts) {
|
|
|
394
609
|
const question = build(pieces, args);
|
|
395
610
|
const t0 = Date.now();
|
|
396
611
|
const workerCount = opts.workers ?? 4;
|
|
397
|
-
const roles = opts.roles ??
|
|
612
|
+
const roles = opts.roles ?? BROADCAST_ROLE_SETS[workerCount] ?? BROADCAST_ROLE_SETS[4] ?? [];
|
|
398
613
|
const plannerModel = opts.plannerModel ?? opts.model;
|
|
399
614
|
const workerModel = opts.workerModel ?? opts.model;
|
|
400
615
|
if (!opts.quiet) {
|
|
@@ -409,11 +624,7 @@ async function execute2(pieces, args, opts) {
|
|
|
409
624
|
const broadcastResults = await Promise.allSettled(
|
|
410
625
|
roles.map(async (role) => {
|
|
411
626
|
const prompt = WORKER_PROMPT.replace("{role}", role).replace("{question}", question);
|
|
412
|
-
const text = await ask(prompt, {
|
|
413
|
-
model: workerModel,
|
|
414
|
-
maxTokens: opts.maxTokens,
|
|
415
|
-
thinkingLevel: opts.thinkingLevel
|
|
416
|
-
});
|
|
627
|
+
const text = await ask(prompt, { ...opts, model: workerModel });
|
|
417
628
|
return new BroadcastResponse(role, text, true);
|
|
418
629
|
})
|
|
419
630
|
);
|
|
@@ -438,40 +649,21 @@ ${responsesText}
|
|
|
438
649
|
|
|
439
650
|
Synthesize a cohesive, actionable recommendation.`,
|
|
440
651
|
{
|
|
652
|
+
...opts,
|
|
441
653
|
model: plannerModel,
|
|
442
|
-
maxTokens: opts.maxTokens,
|
|
443
654
|
thinkingLevel: "high",
|
|
444
|
-
system: SYNTHESIS_SYSTEM
|
|
655
|
+
system: mergeSystem(opts.system, SYNTHESIS_SYSTEM)
|
|
445
656
|
}
|
|
446
657
|
);
|
|
658
|
+
if (!opts.quiet && opts.qualityCheck) process.stderr.write(" \u2192 Quality review...\n");
|
|
659
|
+
const qualityReview = await runQualityReview(question, synthesis, opts);
|
|
447
660
|
const t1 = Date.now();
|
|
448
661
|
const summary = responses.map(
|
|
449
662
|
(wr) => `[${wr.role}]: ${wr.response.slice(0, 150)}${wr.response.length > 150 ? "..." : ""}`
|
|
450
663
|
).join("\n");
|
|
451
|
-
return new BroadcastOutput(summary, synthesis, responses, t0, t1);
|
|
452
|
-
}
|
|
453
|
-
function makeBroadcast(opts = {}) {
|
|
454
|
-
const merged = { ...defaults2, ...opts };
|
|
455
|
-
const fn = ((pieces, ...args) => {
|
|
456
|
-
if (!Array.isArray(pieces)) {
|
|
457
|
-
return makeBroadcast({ ...merged, ...pieces });
|
|
458
|
-
}
|
|
459
|
-
return new PatternPromise((resolve, reject) => {
|
|
460
|
-
execute2(pieces, args, merged).then(resolve, reject);
|
|
461
|
-
});
|
|
462
|
-
});
|
|
463
|
-
let _quiet;
|
|
464
|
-
Object.defineProperty(fn, "quiet", {
|
|
465
|
-
get() {
|
|
466
|
-
if (!_quiet) _quiet = makeBroadcast({ ...merged, quiet: true });
|
|
467
|
-
return _quiet;
|
|
468
|
-
},
|
|
469
|
-
enumerable: true,
|
|
470
|
-
configurable: true
|
|
471
|
-
});
|
|
472
|
-
return fn;
|
|
664
|
+
return new BroadcastOutput(summary, synthesis, responses, t0, t1, qualityReview);
|
|
473
665
|
}
|
|
474
|
-
var \u0392 =
|
|
666
|
+
var \u0392 = createPatternTag(defaults2, execute2);
|
|
475
667
|
|
|
476
668
|
// src/patterns/chi.ts
|
|
477
669
|
var defaults3 = {
|
|
@@ -491,15 +683,17 @@ var LearningInsight = class {
|
|
|
491
683
|
confidence;
|
|
492
684
|
};
|
|
493
685
|
var ChiOutput = class extends PatternOutput {
|
|
494
|
-
constructor(text, insights, summary, suggestedChanges, startTime, endTime) {
|
|
686
|
+
constructor(text, insights, summary, suggestedChanges, startTime, endTime, qualityReview) {
|
|
495
687
|
super(text, startTime, endTime);
|
|
496
688
|
this.insights = insights;
|
|
497
689
|
this.summary = summary;
|
|
498
690
|
this.suggestedChanges = suggestedChanges;
|
|
691
|
+
this.qualityReview = qualityReview;
|
|
499
692
|
}
|
|
500
693
|
insights;
|
|
501
694
|
summary;
|
|
502
695
|
suggestedChanges;
|
|
696
|
+
qualityReview;
|
|
503
697
|
};
|
|
504
698
|
var ANALYSIS_SYSTEM = `You are an agent team performance analyst. Review a multi-agent execution and extract structured learnings.
|
|
505
699
|
|
|
@@ -568,12 +762,13 @@ async function execute3(pieces, args, opts) {
|
|
|
568
762
|
`);
|
|
569
763
|
}
|
|
570
764
|
const response = await ask(input, {
|
|
765
|
+
...opts,
|
|
571
766
|
model: plannerModel,
|
|
572
|
-
|
|
573
|
-
thinkingLevel: opts.thinkingLevel,
|
|
574
|
-
system: ANALYSIS_SYSTEM
|
|
767
|
+
system: mergeSystem(opts.system, ANALYSIS_SYSTEM)
|
|
575
768
|
});
|
|
576
769
|
const { insights, summary, suggestedChanges } = parseInsights(response);
|
|
770
|
+
if (!opts.quiet && opts.qualityCheck) process.stderr.write(" \u2192 Quality review...\n");
|
|
771
|
+
const qualityReview = await runQualityReview(input, response, opts);
|
|
577
772
|
const t1 = Date.now();
|
|
578
773
|
const text = [
|
|
579
774
|
`Insights: ${insights.length} extracted`,
|
|
@@ -585,30 +780,9 @@ Summary: ${summary}`,
|
|
|
585
780
|
`
|
|
586
781
|
Changes: ${suggestedChanges}`
|
|
587
782
|
].join("\n");
|
|
588
|
-
return new ChiOutput(text, insights, summary, suggestedChanges, t0, t1);
|
|
783
|
+
return new ChiOutput(text, insights, summary, suggestedChanges, t0, t1, qualityReview);
|
|
589
784
|
}
|
|
590
|
-
|
|
591
|
-
const merged = { ...defaults3, ...opts };
|
|
592
|
-
const fn = ((pieces, ...args) => {
|
|
593
|
-
if (!Array.isArray(pieces)) {
|
|
594
|
-
return makeChi({ ...merged, ...pieces });
|
|
595
|
-
}
|
|
596
|
-
return new PatternPromise((resolve, reject) => {
|
|
597
|
-
execute3(pieces, args, merged).then(resolve, reject);
|
|
598
|
-
});
|
|
599
|
-
});
|
|
600
|
-
let _quiet;
|
|
601
|
-
Object.defineProperty(fn, "quiet", {
|
|
602
|
-
get() {
|
|
603
|
-
if (!_quiet) _quiet = makeChi({ ...merged, quiet: true });
|
|
604
|
-
return _quiet;
|
|
605
|
-
},
|
|
606
|
-
enumerable: true,
|
|
607
|
-
configurable: true
|
|
608
|
-
});
|
|
609
|
-
return fn;
|
|
610
|
-
}
|
|
611
|
-
var \u03A7 = makeChi();
|
|
785
|
+
var \u03A7 = createPatternTag(defaults3, execute3);
|
|
612
786
|
|
|
613
787
|
// src/patterns/critique.ts
|
|
614
788
|
var defaults4 = {
|
|
@@ -663,12 +837,7 @@ async function execute4(pieces, args, opts) {
|
|
|
663
837
|
for (let r = 0; r < rounds; r++) {
|
|
664
838
|
if (r === 0) {
|
|
665
839
|
if (!opts.quiet) process.stderr.write(" \u2192 Generating initial content...\n");
|
|
666
|
-
currentContent = await ask(prompt, {
|
|
667
|
-
model: workerModel,
|
|
668
|
-
maxTokens: opts.maxTokens,
|
|
669
|
-
thinkingLevel: opts.thinkingLevel,
|
|
670
|
-
system: void 0
|
|
671
|
-
});
|
|
840
|
+
currentContent = await ask(prompt, { ...opts, model: workerModel, system: opts.system });
|
|
672
841
|
} else {
|
|
673
842
|
if (!opts.quiet) process.stderr.write(` \u2192 Improving (round ${r + 1})...
|
|
674
843
|
`);
|
|
@@ -683,21 +852,15 @@ Content to improve:
|
|
|
683
852
|
${currentContent}
|
|
684
853
|
|
|
685
854
|
Revise the content based on the critique.`,
|
|
686
|
-
{
|
|
687
|
-
model: workerModel,
|
|
688
|
-
maxTokens: opts.maxTokens,
|
|
689
|
-
thinkingLevel: opts.thinkingLevel,
|
|
690
|
-
system: IMPROVE_SYSTEM
|
|
691
|
-
}
|
|
855
|
+
{ ...opts, model: workerModel, system: mergeSystem(opts.system, IMPROVE_SYSTEM) }
|
|
692
856
|
);
|
|
693
857
|
}
|
|
694
858
|
if (!opts.quiet) process.stderr.write(` \u2192 Critiquing (round ${r + 1})...
|
|
695
859
|
`);
|
|
696
860
|
const critique = await ask(currentContent, {
|
|
861
|
+
...opts,
|
|
697
862
|
model: plannerModel,
|
|
698
|
-
|
|
699
|
-
thinkingLevel: opts.thinkingLevel,
|
|
700
|
-
system: CRITIQUE_SYSTEM
|
|
863
|
+
system: mergeSystem(opts.system, CRITIQUE_SYSTEM)
|
|
701
864
|
});
|
|
702
865
|
critiqueRounds.push(new CritiqueRound(currentContent, critique, r));
|
|
703
866
|
}
|
|
@@ -710,28 +873,7 @@ Critique: ${cr.critique.slice(0, 200)}${cr.critique.length > 200 ? "..." : ""}`
|
|
|
710
873
|
).join("\n\n");
|
|
711
874
|
return new CritiqueOutput(summary, finalContent, critiqueRounds, t0, t1);
|
|
712
875
|
}
|
|
713
|
-
|
|
714
|
-
const merged = { ...defaults4, ...opts };
|
|
715
|
-
const fn = ((pieces, ...args) => {
|
|
716
|
-
if (!Array.isArray(pieces)) {
|
|
717
|
-
return makeCritique({ ...merged, ...pieces });
|
|
718
|
-
}
|
|
719
|
-
return new PatternPromise((resolve, reject) => {
|
|
720
|
-
execute4(pieces, args, merged).then(resolve, reject);
|
|
721
|
-
});
|
|
722
|
-
});
|
|
723
|
-
let _quiet;
|
|
724
|
-
Object.defineProperty(fn, "quiet", {
|
|
725
|
-
get() {
|
|
726
|
-
if (!_quiet) _quiet = makeCritique({ ...merged, quiet: true });
|
|
727
|
-
return _quiet;
|
|
728
|
-
},
|
|
729
|
-
enumerable: true,
|
|
730
|
-
configurable: true
|
|
731
|
-
});
|
|
732
|
-
return fn;
|
|
733
|
-
}
|
|
734
|
-
var \u03A8 = makeCritique();
|
|
876
|
+
var \u03A8 = createPatternTag(defaults4, execute4);
|
|
735
877
|
|
|
736
878
|
// src/patterns/debate.ts
|
|
737
879
|
var defaults5 = {
|
|
@@ -740,30 +882,6 @@ var defaults5 = {
|
|
|
740
882
|
perspectives: 3,
|
|
741
883
|
rounds: 1
|
|
742
884
|
};
|
|
743
|
-
var ROLE_SETS2 = {
|
|
744
|
-
2: [
|
|
745
|
-
"Optimist \u2014 advocate for the most ambitious approach",
|
|
746
|
-
"Pessimist \u2014 identify risks and failure modes"
|
|
747
|
-
],
|
|
748
|
-
3: [
|
|
749
|
-
"Optimist \u2014 advocate the benefits and opportunities",
|
|
750
|
-
"Pessimist \u2014 identify risks, costs, and failure modes",
|
|
751
|
-
"Pragmatist \u2014 focus on practical trade-offs and implementation"
|
|
752
|
-
],
|
|
753
|
-
4: [
|
|
754
|
-
"Optimist \u2014 argue for the best-case potential",
|
|
755
|
-
"Pessimist \u2014 highlight worst-case risks and downsides",
|
|
756
|
-
"Pragmatist \u2014 balance pros/cons with practical constraints",
|
|
757
|
-
"Innovator \u2014 propose creative alternatives and novel approaches"
|
|
758
|
-
],
|
|
759
|
-
5: [
|
|
760
|
-
"Optimist",
|
|
761
|
-
"Pessimist",
|
|
762
|
-
"Pragmatist",
|
|
763
|
-
"Innovator",
|
|
764
|
-
"User Advocate \u2014 focus on end-user experience and accessibility"
|
|
765
|
-
]
|
|
766
|
-
};
|
|
767
885
|
var DebatePerspective = class {
|
|
768
886
|
constructor(role, argument, round = 1) {
|
|
769
887
|
this.role = role;
|
|
@@ -775,15 +893,17 @@ var DebatePerspective = class {
|
|
|
775
893
|
round;
|
|
776
894
|
};
|
|
777
895
|
var DebateOutput = class extends PatternOutput {
|
|
778
|
-
constructor(text, conclusion, perspectives, rounds, startTime, endTime) {
|
|
896
|
+
constructor(text, conclusion, perspectives, rounds, startTime, endTime, qualityReview) {
|
|
779
897
|
super(text, startTime, endTime);
|
|
780
898
|
this.conclusion = conclusion;
|
|
781
899
|
this.perspectives = perspectives;
|
|
782
900
|
this.rounds = rounds;
|
|
901
|
+
this.qualityReview = qualityReview;
|
|
783
902
|
}
|
|
784
903
|
conclusion;
|
|
785
904
|
perspectives;
|
|
786
905
|
rounds;
|
|
906
|
+
qualityReview;
|
|
787
907
|
};
|
|
788
908
|
var PERSPECTIVE_SYSTEM = (role) => `You are a debater with the role: ${role}. Analyze the question from your perspective. Be thorough and specific. Provide evidence and reasoning for your position.`;
|
|
789
909
|
var REBUTTAL_SYSTEM = (role) => `You are a debater with the role: ${role}. Review the debate so far \u2014 including arguments from all other perspectives \u2014 and refine your position. Address counter-arguments directly. Challenge weak points in opposing views. Strengthen your original position with rebuttals. Be specific and responsive.`;
|
|
@@ -793,7 +913,7 @@ async function execute5(pieces, args, opts) {
|
|
|
793
913
|
const t0 = Date.now();
|
|
794
914
|
const count = opts.perspectives ?? 3;
|
|
795
915
|
const totalRounds = opts.rounds ?? 1;
|
|
796
|
-
const roles = opts.roles ??
|
|
916
|
+
const roles = opts.roles ?? DEBATE_ROLE_SETS[count] ?? DEBATE_ROLE_SETS[3] ?? [];
|
|
797
917
|
const plannerModel = opts.plannerModel ?? opts.model;
|
|
798
918
|
const workerModel = opts.workerModel ?? opts.model;
|
|
799
919
|
if (!opts.quiet) {
|
|
@@ -811,10 +931,9 @@ async function execute5(pieces, args, opts) {
|
|
|
811
931
|
const round1Results = await Promise.allSettled(
|
|
812
932
|
roles.map(
|
|
813
933
|
(role) => ask(question, {
|
|
934
|
+
...opts,
|
|
814
935
|
model: workerModel,
|
|
815
|
-
|
|
816
|
-
thinkingLevel: opts.thinkingLevel,
|
|
817
|
-
system: PERSPECTIVE_SYSTEM(role)
|
|
936
|
+
system: mergeSystem(opts.system, PERSPECTIVE_SYSTEM(role))
|
|
818
937
|
}).then((text) => new DebatePerspective(role, text, 1))
|
|
819
938
|
)
|
|
820
939
|
);
|
|
@@ -848,10 +967,9 @@ ${othersText}
|
|
|
848
967
|
|
|
849
968
|
Refine your position. Address the counter-arguments directly. Strengthen your argument with rebuttals.`;
|
|
850
969
|
return ask(prompt, {
|
|
970
|
+
...opts,
|
|
851
971
|
model: workerModel,
|
|
852
|
-
|
|
853
|
-
thinkingLevel: opts.thinkingLevel,
|
|
854
|
-
system: REBUTTAL_SYSTEM(role)
|
|
972
|
+
system: mergeSystem(opts.system, REBUTTAL_SYSTEM(role))
|
|
855
973
|
}).then((text) => new DebatePerspective(role, text, round));
|
|
856
974
|
})
|
|
857
975
|
);
|
|
@@ -875,37 +993,31 @@ Refine your position. Address the counter-arguments directly. Strengthen your ar
|
|
|
875
993
|
|
|
876
994
|
Synthesize a balanced conclusion from the full debate above. Weigh the evidence from all rounds.`,
|
|
877
995
|
{
|
|
996
|
+
...opts,
|
|
878
997
|
model: plannerModel,
|
|
879
|
-
maxTokens: opts.maxTokens,
|
|
880
998
|
thinkingLevel: "high",
|
|
881
|
-
system: SYNTHESIS_SYSTEM2
|
|
999
|
+
system: mergeSystem(opts.system, SYNTHESIS_SYSTEM2)
|
|
882
1000
|
}
|
|
883
1001
|
);
|
|
1002
|
+
if (!opts.quiet && opts.qualityCheck) process.stderr.write(" \u2192 Quality review...\n");
|
|
1003
|
+
const qualityReview = await runQualityReview(question, conclusion, opts);
|
|
884
1004
|
const t1 = Date.now();
|
|
885
|
-
return new DebateOutput(
|
|
1005
|
+
return new DebateOutput(
|
|
1006
|
+
conclusion,
|
|
1007
|
+
conclusion,
|
|
1008
|
+
allPerspectives,
|
|
1009
|
+
totalRounds,
|
|
1010
|
+
t0,
|
|
1011
|
+
t1,
|
|
1012
|
+
qualityReview
|
|
1013
|
+
);
|
|
886
1014
|
}
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
}
|
|
893
|
-
return new PatternPromise((resolve, reject) => {
|
|
894
|
-
execute5(pieces, args, merged).then(resolve, reject);
|
|
895
|
-
});
|
|
896
|
-
});
|
|
897
|
-
let _quiet;
|
|
898
|
-
Object.defineProperty(fn, "quiet", {
|
|
899
|
-
get() {
|
|
900
|
-
if (!_quiet) _quiet = makeDebate({ ...merged, quiet: true });
|
|
901
|
-
return _quiet;
|
|
902
|
-
},
|
|
903
|
-
enumerable: true,
|
|
904
|
-
configurable: true
|
|
905
|
-
});
|
|
906
|
-
return fn;
|
|
1015
|
+
var \u0394 = createPatternTag(defaults5, execute5);
|
|
1016
|
+
|
|
1017
|
+
// src/utils.ts
|
|
1018
|
+
function getErrorMessage(err) {
|
|
1019
|
+
return err instanceof Error ? err.message : String(err);
|
|
907
1020
|
}
|
|
908
|
-
var \u0394 = makeDebate();
|
|
909
1021
|
|
|
910
1022
|
// src/patterns/fleet.ts
|
|
911
1023
|
var defaults6 = {
|
|
@@ -926,11 +1038,13 @@ var FleetMemberOutput = class {
|
|
|
926
1038
|
error;
|
|
927
1039
|
};
|
|
928
1040
|
var FleetOutput = class extends PatternOutput {
|
|
929
|
-
constructor(text, members, startTime, endTime) {
|
|
1041
|
+
constructor(text, members, startTime, endTime, qualityReview) {
|
|
930
1042
|
super(text, startTime, endTime);
|
|
931
1043
|
this.members = members;
|
|
1044
|
+
this.qualityReview = qualityReview;
|
|
932
1045
|
}
|
|
933
1046
|
members;
|
|
1047
|
+
qualityReview;
|
|
934
1048
|
/** Number of successful members */
|
|
935
1049
|
get successCount() {
|
|
936
1050
|
return this.members.filter((m) => m.success).length;
|
|
@@ -950,20 +1064,30 @@ function parseTasks(template, explicitTasks) {
|
|
|
950
1064
|
if (lines.length > 1) return lines;
|
|
951
1065
|
return [template];
|
|
952
1066
|
}
|
|
1067
|
+
function describeTask(task) {
|
|
1068
|
+
if (typeof task === "function") return "(composed pattern)";
|
|
1069
|
+
return task;
|
|
1070
|
+
}
|
|
953
1071
|
var FLEET_SYSTEM = `You are a focused task specialist. Complete the assigned task concisely and accurately. Output only the result \u2014 no commentary about being an AI.`;
|
|
954
1072
|
async function executeTask(task, opts, workerModel) {
|
|
1073
|
+
if (typeof task === "function") {
|
|
1074
|
+
try {
|
|
1075
|
+
const text = await task("");
|
|
1076
|
+
return new FleetMemberOutput("(composed pattern)", text, true);
|
|
1077
|
+
} catch (err) {
|
|
1078
|
+
return new FleetMemberOutput("(composed pattern)", "", false, getErrorMessage(err));
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
955
1081
|
const model = workerModel ?? opts.model;
|
|
956
1082
|
try {
|
|
957
1083
|
const text = await ask(task, {
|
|
1084
|
+
...opts,
|
|
958
1085
|
model,
|
|
959
|
-
|
|
960
|
-
thinkingLevel: opts.thinkingLevel,
|
|
961
|
-
system: opts.system ?? FLEET_SYSTEM
|
|
1086
|
+
system: mergeSystem(opts.system, FLEET_SYSTEM)
|
|
962
1087
|
});
|
|
963
1088
|
return new FleetMemberOutput(task, text, true);
|
|
964
1089
|
} catch (err) {
|
|
965
|
-
|
|
966
|
-
return new FleetMemberOutput(task, "", false, msg);
|
|
1090
|
+
return new FleetMemberOutput(task, "", false, getErrorMessage(err));
|
|
967
1091
|
}
|
|
968
1092
|
}
|
|
969
1093
|
async function execute6(pieces, args, opts) {
|
|
@@ -975,11 +1099,16 @@ async function execute6(pieces, args, opts) {
|
|
|
975
1099
|
process.stderr.write(`\u03A6: Fleet executing ${tasks.length} task(s) in parallel
|
|
976
1100
|
`);
|
|
977
1101
|
for (let i = 0; i < tasks.length; i++) {
|
|
978
|
-
const t = tasks[i];
|
|
1102
|
+
const t = describeTask(tasks[i]);
|
|
979
1103
|
process.stderr.write(` [${i + 1}] ${t.slice(0, 60)}${t.length > 60 ? "..." : ""}
|
|
980
1104
|
`);
|
|
981
1105
|
}
|
|
982
1106
|
}
|
|
1107
|
+
const taskSummary = `Execute ${tasks.length} fleet task(s)?
|
|
1108
|
+
${tasks.map((t, i) => `${i + 1}. ${describeTask(t).slice(0, 80)}`).join("\n ")}`;
|
|
1109
|
+
if (!await confirmPhase(taskSummary, opts)) {
|
|
1110
|
+
throw new Error("pizx/\u03A6: Execution cancelled by user.");
|
|
1111
|
+
}
|
|
983
1112
|
const results = [];
|
|
984
1113
|
const concurrency = opts.concurrency ?? 5;
|
|
985
1114
|
for (let i = 0; i < tasks.length; i += concurrency) {
|
|
@@ -991,7 +1120,9 @@ async function execute6(pieces, args, opts) {
|
|
|
991
1120
|
if (r.status === "fulfilled") {
|
|
992
1121
|
results.push(r.value);
|
|
993
1122
|
} else {
|
|
994
|
-
results.push(
|
|
1123
|
+
results.push(
|
|
1124
|
+
new FleetMemberOutput(describeTask(batch[idx]), "", false, r.reason?.toString())
|
|
1125
|
+
);
|
|
995
1126
|
}
|
|
996
1127
|
});
|
|
997
1128
|
}
|
|
@@ -1003,30 +1134,11 @@ async function execute6(pieces, args, opts) {
|
|
|
1003
1134
|
const header = `Fleet Results: ${results.filter((r) => r.success).length}/${results.length} succeeded
|
|
1004
1135
|
|
|
1005
1136
|
`;
|
|
1006
|
-
|
|
1137
|
+
if (!opts.quiet && opts.qualityCheck) process.stderr.write(" \u2192 Quality review...\n");
|
|
1138
|
+
const qualityReview = await runQualityReview(template, header + summary, opts);
|
|
1139
|
+
return new FleetOutput(header + summary, results, t0, t1, qualityReview);
|
|
1007
1140
|
}
|
|
1008
|
-
|
|
1009
|
-
const merged = { ...defaults6, ...opts };
|
|
1010
|
-
const fn = ((pieces, ...args) => {
|
|
1011
|
-
if (!Array.isArray(pieces)) {
|
|
1012
|
-
return makeFleet({ ...merged, ...pieces });
|
|
1013
|
-
}
|
|
1014
|
-
return new PatternPromise((resolve, reject) => {
|
|
1015
|
-
execute6(pieces, args, merged).then(resolve, reject);
|
|
1016
|
-
});
|
|
1017
|
-
});
|
|
1018
|
-
let _quiet;
|
|
1019
|
-
Object.defineProperty(fn, "quiet", {
|
|
1020
|
-
get() {
|
|
1021
|
-
if (!_quiet) _quiet = makeFleet({ ...merged, quiet: true });
|
|
1022
|
-
return _quiet;
|
|
1023
|
-
},
|
|
1024
|
-
enumerable: true,
|
|
1025
|
-
configurable: true
|
|
1026
|
-
});
|
|
1027
|
-
return fn;
|
|
1028
|
-
}
|
|
1029
|
-
var \u03A6 = makeFleet();
|
|
1141
|
+
var \u03A6 = createPatternTag(defaults6, execute6);
|
|
1030
1142
|
|
|
1031
1143
|
// src/patterns/graph.ts
|
|
1032
1144
|
var defaults7 = {
|
|
@@ -1046,13 +1158,15 @@ var GraphNodeResult = class {
|
|
|
1046
1158
|
success;
|
|
1047
1159
|
};
|
|
1048
1160
|
var GraphOutput = class extends PatternOutput {
|
|
1049
|
-
constructor(text, finalOutput, nodeResults, startTime, endTime) {
|
|
1161
|
+
constructor(text, finalOutput, nodeResults, startTime, endTime, qualityReview) {
|
|
1050
1162
|
super(text, startTime, endTime);
|
|
1051
1163
|
this.finalOutput = finalOutput;
|
|
1052
1164
|
this.nodeResults = nodeResults;
|
|
1165
|
+
this.qualityReview = qualityReview;
|
|
1053
1166
|
}
|
|
1054
1167
|
finalOutput;
|
|
1055
1168
|
nodeResults;
|
|
1169
|
+
qualityReview;
|
|
1056
1170
|
};
|
|
1057
1171
|
function parseGraph(template, separator) {
|
|
1058
1172
|
const sep = separator ?? "\u2192";
|
|
@@ -1148,10 +1262,9 @@ Your task: ${node.task}`;
|
|
|
1148
1262
|
}
|
|
1149
1263
|
}
|
|
1150
1264
|
const text = await ask(context, {
|
|
1265
|
+
...opts,
|
|
1151
1266
|
model: workerModel,
|
|
1152
|
-
|
|
1153
|
-
thinkingLevel: opts.thinkingLevel,
|
|
1154
|
-
system: NODE_SYSTEM
|
|
1267
|
+
system: mergeSystem(opts.system, NODE_SYSTEM)
|
|
1155
1268
|
});
|
|
1156
1269
|
return { nodeId, task: node.task, text, success: true };
|
|
1157
1270
|
})
|
|
@@ -1169,34 +1282,15 @@ Your task: ${node.task}`;
|
|
|
1169
1282
|
const lastBatch = batches[batches.length - 1] ?? [];
|
|
1170
1283
|
const finalNodeResults = lastBatch.map((id) => results.get(id)).filter(Boolean);
|
|
1171
1284
|
const finalOutput = finalNodeResults.length > 0 ? finalNodeResults.join("\n\n") : "";
|
|
1285
|
+
if (!opts.quiet && opts.qualityCheck) process.stderr.write(" \u2192 Quality review...\n");
|
|
1286
|
+
const qualityReview = await runQualityReview(template, finalOutput, opts);
|
|
1172
1287
|
const summary = nodeResults.map(
|
|
1173
1288
|
(nr) => `[${nr.nodeId}] ${nr.task.slice(0, 80)}...
|
|
1174
1289
|
${nr.output.slice(0, 200)}${nr.output.length > 200 ? "..." : ""}`
|
|
1175
1290
|
).join("\n\n");
|
|
1176
|
-
return new GraphOutput(summary, finalOutput, nodeResults, t0, t1);
|
|
1177
|
-
}
|
|
1178
|
-
function makeGraph(opts = {}) {
|
|
1179
|
-
const merged = { ...defaults7, ...opts };
|
|
1180
|
-
const fn = ((pieces, ...args) => {
|
|
1181
|
-
if (!Array.isArray(pieces)) {
|
|
1182
|
-
return makeGraph({ ...merged, ...pieces });
|
|
1183
|
-
}
|
|
1184
|
-
return new PatternPromise((resolve, reject) => {
|
|
1185
|
-
execute7(pieces, args, merged).then(resolve, reject);
|
|
1186
|
-
});
|
|
1187
|
-
});
|
|
1188
|
-
let _quiet;
|
|
1189
|
-
Object.defineProperty(fn, "quiet", {
|
|
1190
|
-
get() {
|
|
1191
|
-
if (!_quiet) _quiet = makeGraph({ ...merged, quiet: true });
|
|
1192
|
-
return _quiet;
|
|
1193
|
-
},
|
|
1194
|
-
enumerable: true,
|
|
1195
|
-
configurable: true
|
|
1196
|
-
});
|
|
1197
|
-
return fn;
|
|
1291
|
+
return new GraphOutput(summary, finalOutput, nodeResults, t0, t1, qualityReview);
|
|
1198
1292
|
}
|
|
1199
|
-
var \u0393 =
|
|
1293
|
+
var \u0393 = createPatternTag(defaults7, execute7);
|
|
1200
1294
|
|
|
1201
1295
|
// src/patterns/memory.ts
|
|
1202
1296
|
var defaults8 = {
|
|
@@ -1205,27 +1299,6 @@ var defaults8 = {
|
|
|
1205
1299
|
agents: 3,
|
|
1206
1300
|
rounds: 1
|
|
1207
1301
|
};
|
|
1208
|
-
var ROLE_SETS3 = {
|
|
1209
|
-
2: ["Analyst \u2014 deep analysis of core aspects", "Reviewer \u2014 check for gaps and blind spots"],
|
|
1210
|
-
3: [
|
|
1211
|
-
"Analyst \u2014 deep analysis of core aspects",
|
|
1212
|
-
"Reviewer \u2014 check for gaps, edge cases, and blind spots",
|
|
1213
|
-
"Strategist \u2014 connect findings to actionable insights"
|
|
1214
|
-
],
|
|
1215
|
-
4: [
|
|
1216
|
-
"Analyst",
|
|
1217
|
-
"Reviewer",
|
|
1218
|
-
"Strategist",
|
|
1219
|
-
"Innovator \u2014 propose novel angles and creative solutions"
|
|
1220
|
-
],
|
|
1221
|
-
5: [
|
|
1222
|
-
"Analyst",
|
|
1223
|
-
"Reviewer",
|
|
1224
|
-
"Strategist",
|
|
1225
|
-
"Innovator",
|
|
1226
|
-
"Skeptic \u2014 challenge assumptions and stress-test conclusions"
|
|
1227
|
-
]
|
|
1228
|
-
};
|
|
1229
1302
|
var MemoryEntry = class {
|
|
1230
1303
|
constructor(role, round, content) {
|
|
1231
1304
|
this.role = role;
|
|
@@ -1237,13 +1310,15 @@ var MemoryEntry = class {
|
|
|
1237
1310
|
content;
|
|
1238
1311
|
};
|
|
1239
1312
|
var MemoryOutput = class extends PatternOutput {
|
|
1240
|
-
constructor(text, synthesis, entries, startTime, endTime) {
|
|
1313
|
+
constructor(text, synthesis, entries, startTime, endTime, qualityReview) {
|
|
1241
1314
|
super(text, startTime, endTime);
|
|
1242
1315
|
this.synthesis = synthesis;
|
|
1243
1316
|
this.entries = entries;
|
|
1317
|
+
this.qualityReview = qualityReview;
|
|
1244
1318
|
}
|
|
1245
1319
|
synthesis;
|
|
1246
1320
|
entries;
|
|
1321
|
+
qualityReview;
|
|
1247
1322
|
};
|
|
1248
1323
|
var WRITER_PROMPT = `You are a specialist with role: {role}.
|
|
1249
1324
|
|
|
@@ -1264,7 +1339,7 @@ async function execute8(pieces, args, opts) {
|
|
|
1264
1339
|
const t0 = Date.now();
|
|
1265
1340
|
const agentCount = opts.agents ?? 3;
|
|
1266
1341
|
const totalRounds = opts.rounds ?? 1;
|
|
1267
|
-
const roles = opts.roles ??
|
|
1342
|
+
const roles = opts.roles ?? MEMORY_ROLE_SETS[agentCount] ?? MEMORY_ROLE_SETS[3] ?? [];
|
|
1268
1343
|
const plannerModel = opts.plannerModel ?? opts.model;
|
|
1269
1344
|
const workerModel = opts.workerModel ?? opts.model;
|
|
1270
1345
|
if (!opts.quiet) {
|
|
@@ -1281,11 +1356,7 @@ async function execute8(pieces, args, opts) {
|
|
|
1281
1356
|
const roundResults = await Promise.allSettled(
|
|
1282
1357
|
roles.map(async (role) => {
|
|
1283
1358
|
const prompt = buildWriterPrompt(role, topic, blackboard);
|
|
1284
|
-
const text = await ask(prompt, {
|
|
1285
|
-
model: workerModel,
|
|
1286
|
-
maxTokens: opts.maxTokens,
|
|
1287
|
-
thinkingLevel: opts.thinkingLevel
|
|
1288
|
-
});
|
|
1359
|
+
const text = await ask(prompt, { ...opts, model: workerModel });
|
|
1289
1360
|
return { role, text };
|
|
1290
1361
|
})
|
|
1291
1362
|
);
|
|
@@ -1307,40 +1378,21 @@ ${blackboard}
|
|
|
1307
1378
|
|
|
1308
1379
|
Consolidate into a comprehensive, structured synthesis.`,
|
|
1309
1380
|
{
|
|
1381
|
+
...opts,
|
|
1310
1382
|
model: plannerModel,
|
|
1311
|
-
maxTokens: opts.maxTokens,
|
|
1312
1383
|
thinkingLevel: "high",
|
|
1313
|
-
system: CONSOLIDATOR_SYSTEM
|
|
1384
|
+
system: mergeSystem(opts.system, CONSOLIDATOR_SYSTEM)
|
|
1314
1385
|
}
|
|
1315
1386
|
);
|
|
1387
|
+
if (!opts.quiet && opts.qualityCheck) process.stderr.write(" \u2192 Quality review...\n");
|
|
1388
|
+
const qualityReview = await runQualityReview(topic, synthesis, opts);
|
|
1316
1389
|
const t1 = Date.now();
|
|
1317
1390
|
const summary = entries.map(
|
|
1318
|
-
(e) => `[${e.role}] Round ${e.round}: ${e.content.slice(0, 150)}${e.content.length > 150 ? "..." : ""}`
|
|
1319
|
-
).join("\n");
|
|
1320
|
-
return new MemoryOutput(summary, synthesis, entries, t0, t1);
|
|
1321
|
-
}
|
|
1322
|
-
function makeMemory(opts = {}) {
|
|
1323
|
-
const merged = { ...defaults8, ...opts };
|
|
1324
|
-
const fn = ((pieces, ...args) => {
|
|
1325
|
-
if (!Array.isArray(pieces)) {
|
|
1326
|
-
return makeMemory({ ...merged, ...pieces });
|
|
1327
|
-
}
|
|
1328
|
-
return new PatternPromise((resolve, reject) => {
|
|
1329
|
-
execute8(pieces, args, merged).then(resolve, reject);
|
|
1330
|
-
});
|
|
1331
|
-
});
|
|
1332
|
-
let _quiet;
|
|
1333
|
-
Object.defineProperty(fn, "quiet", {
|
|
1334
|
-
get() {
|
|
1335
|
-
if (!_quiet) _quiet = makeMemory({ ...merged, quiet: true });
|
|
1336
|
-
return _quiet;
|
|
1337
|
-
},
|
|
1338
|
-
enumerable: true,
|
|
1339
|
-
configurable: true
|
|
1340
|
-
});
|
|
1341
|
-
return fn;
|
|
1391
|
+
(e) => `[${e.role}] Round ${e.round}: ${e.content.slice(0, 150)}${e.content.length > 150 ? "..." : ""}`
|
|
1392
|
+
).join("\n");
|
|
1393
|
+
return new MemoryOutput(summary, synthesis, entries, t0, t1, qualityReview);
|
|
1342
1394
|
}
|
|
1343
|
-
var \u039C =
|
|
1395
|
+
var \u039C = createPatternTag(defaults8, execute8);
|
|
1344
1396
|
|
|
1345
1397
|
// src/patterns/nu.ts
|
|
1346
1398
|
var defaults9 = {
|
|
@@ -1360,19 +1412,21 @@ var NuRole = class {
|
|
|
1360
1412
|
goal;
|
|
1361
1413
|
};
|
|
1362
1414
|
var NuOutput = class extends PatternOutput {
|
|
1363
|
-
constructor(text, negotiatedRoles, workflow, workflowReasoning, roleResults, synthesis, startTime, endTime) {
|
|
1415
|
+
constructor(text, negotiatedRoles, workflow, workflowReasoning, roleResults, synthesis, startTime, endTime, qualityReview) {
|
|
1364
1416
|
super(text, startTime, endTime);
|
|
1365
1417
|
this.negotiatedRoles = negotiatedRoles;
|
|
1366
1418
|
this.workflow = workflow;
|
|
1367
1419
|
this.workflowReasoning = workflowReasoning;
|
|
1368
1420
|
this.roleResults = roleResults;
|
|
1369
1421
|
this.synthesis = synthesis;
|
|
1422
|
+
this.qualityReview = qualityReview;
|
|
1370
1423
|
}
|
|
1371
1424
|
negotiatedRoles;
|
|
1372
1425
|
workflow;
|
|
1373
1426
|
workflowReasoning;
|
|
1374
1427
|
roleResults;
|
|
1375
1428
|
synthesis;
|
|
1429
|
+
qualityReview;
|
|
1376
1430
|
};
|
|
1377
1431
|
var NEGOTIATE_SYSTEM = `You are a team architect. Given a task, propose a team of specialized agents. Each role must have a distinct name, expertise, and goal.
|
|
1378
1432
|
|
|
@@ -1410,6 +1464,7 @@ async function negotiateRoles(task, opts) {
|
|
|
1410
1464
|
const response = await ask(`Task: ${task}
|
|
1411
1465
|
|
|
1412
1466
|
${prompt}`, {
|
|
1467
|
+
...opts,
|
|
1413
1468
|
model: opts.plannerModel ?? opts.model,
|
|
1414
1469
|
maxTokens: 2048,
|
|
1415
1470
|
thinkingLevel: "high"
|
|
@@ -1446,10 +1501,11 @@ ${rolesText}
|
|
|
1446
1501
|
|
|
1447
1502
|
Determine the best execution strategy.`,
|
|
1448
1503
|
{
|
|
1504
|
+
...opts,
|
|
1449
1505
|
model: opts.plannerModel ?? opts.model,
|
|
1450
1506
|
maxTokens: 512,
|
|
1451
1507
|
thinkingLevel: "high",
|
|
1452
|
-
system: WORKFLOW_SYSTEM
|
|
1508
|
+
system: mergeSystem(opts.system, WORKFLOW_SYSTEM)
|
|
1453
1509
|
}
|
|
1454
1510
|
);
|
|
1455
1511
|
const wfMatch = response.match(/WORKFLOW\s*:\s*(.+)/i);
|
|
@@ -1468,10 +1524,9 @@ async function executeRoles(roles, task, workflow, opts) {
|
|
|
1468
1524
|
let context = task;
|
|
1469
1525
|
for (const role of roles) {
|
|
1470
1526
|
const output = await ask(context, {
|
|
1527
|
+
...opts,
|
|
1471
1528
|
model: workerModel,
|
|
1472
|
-
|
|
1473
|
-
thinkingLevel: opts.thinkingLevel,
|
|
1474
|
-
system: EXECUTE_SYSTEM2(role)
|
|
1529
|
+
system: mergeSystem(opts.system, EXECUTE_SYSTEM2(role))
|
|
1475
1530
|
});
|
|
1476
1531
|
results.push({ role: role.name, output });
|
|
1477
1532
|
context = `Previous output from ${role.name}:
|
|
@@ -1483,10 +1538,9 @@ Continue with: ${task}`;
|
|
|
1483
1538
|
const parallelResults = await Promise.allSettled(
|
|
1484
1539
|
roles.map(
|
|
1485
1540
|
(role) => ask(task, {
|
|
1541
|
+
...opts,
|
|
1486
1542
|
model: workerModel,
|
|
1487
|
-
|
|
1488
|
-
thinkingLevel: opts.thinkingLevel,
|
|
1489
|
-
system: EXECUTE_SYSTEM2(role)
|
|
1543
|
+
system: mergeSystem(opts.system, EXECUTE_SYSTEM2(role))
|
|
1490
1544
|
}).then((text) => ({ role: role.name, output: text })).catch((err) => ({ role: role.name, output: `(failed: ${String(err)})` }))
|
|
1491
1545
|
)
|
|
1492
1546
|
);
|
|
@@ -1508,10 +1562,10 @@ ${resultsText}
|
|
|
1508
1562
|
|
|
1509
1563
|
Synthesize a comprehensive final answer.`,
|
|
1510
1564
|
{
|
|
1565
|
+
...opts,
|
|
1511
1566
|
model: opts.plannerModel ?? opts.model,
|
|
1512
|
-
maxTokens: opts.maxTokens,
|
|
1513
1567
|
thinkingLevel: "high",
|
|
1514
|
-
system: SYNTHESIS_SYSTEM3
|
|
1568
|
+
system: mergeSystem(opts.system, SYNTHESIS_SYSTEM3)
|
|
1515
1569
|
}
|
|
1516
1570
|
);
|
|
1517
1571
|
}
|
|
@@ -1552,6 +1606,8 @@ async function execute9(pieces, args, opts) {
|
|
|
1552
1606
|
const roleResults = await executeRoles(roles, task, workflow, opts);
|
|
1553
1607
|
if (!opts.quiet) process.stderr.write(" \u2192 Synthesizing...\n");
|
|
1554
1608
|
const synthesis = await synthesize(task, roleResults, { ...opts, plannerModel });
|
|
1609
|
+
if (!opts.quiet && opts.qualityCheck) process.stderr.write(" \u2192 Quality review...\n");
|
|
1610
|
+
const qualityReview = await runQualityReview(task, synthesis, opts);
|
|
1555
1611
|
const t1 = Date.now();
|
|
1556
1612
|
const summary = [
|
|
1557
1613
|
`Roles: ${roles.map((r) => r.name).join(", ")}`,
|
|
@@ -1559,30 +1615,19 @@ async function execute9(pieces, args, opts) {
|
|
|
1559
1615
|
`Results: ${roleResults.length}/${roles.length} succeeded`,
|
|
1560
1616
|
`Synthesis: ${synthesis}`
|
|
1561
1617
|
].join("\n\n");
|
|
1562
|
-
return new NuOutput(
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
});
|
|
1574
|
-
let _quiet;
|
|
1575
|
-
Object.defineProperty(fn, "quiet", {
|
|
1576
|
-
get() {
|
|
1577
|
-
if (!_quiet) _quiet = makeNu({ ...merged, quiet: true });
|
|
1578
|
-
return _quiet;
|
|
1579
|
-
},
|
|
1580
|
-
enumerable: true,
|
|
1581
|
-
configurable: true
|
|
1582
|
-
});
|
|
1583
|
-
return fn;
|
|
1618
|
+
return new NuOutput(
|
|
1619
|
+
summary,
|
|
1620
|
+
roles,
|
|
1621
|
+
workflow,
|
|
1622
|
+
reasoning,
|
|
1623
|
+
roleResults,
|
|
1624
|
+
synthesis,
|
|
1625
|
+
t0,
|
|
1626
|
+
t1,
|
|
1627
|
+
qualityReview
|
|
1628
|
+
);
|
|
1584
1629
|
}
|
|
1585
|
-
var \u039D =
|
|
1630
|
+
var \u039D = createPatternTag(defaults9, execute9);
|
|
1586
1631
|
|
|
1587
1632
|
// src/patterns/orchestrator.ts
|
|
1588
1633
|
var defaults10 = {
|
|
@@ -1602,15 +1647,17 @@ var OrchestratorWorkerResult = class {
|
|
|
1602
1647
|
success;
|
|
1603
1648
|
};
|
|
1604
1649
|
var OrchestratorOutput = class extends PatternOutput {
|
|
1605
|
-
constructor(text, plan, synthesis, workerResults, startTime, endTime) {
|
|
1650
|
+
constructor(text, plan, synthesis, workerResults, startTime, endTime, qualityReview) {
|
|
1606
1651
|
super(text, startTime, endTime);
|
|
1607
1652
|
this.plan = plan;
|
|
1608
1653
|
this.synthesis = synthesis;
|
|
1609
1654
|
this.workerResults = workerResults;
|
|
1655
|
+
this.qualityReview = qualityReview;
|
|
1610
1656
|
}
|
|
1611
1657
|
plan;
|
|
1612
1658
|
synthesis;
|
|
1613
1659
|
workerResults;
|
|
1660
|
+
qualityReview;
|
|
1614
1661
|
};
|
|
1615
1662
|
var PLANNER_SYSTEM = `You are a senior architect and project planner. Given a high-level request, create a detailed execution plan.
|
|
1616
1663
|
|
|
@@ -1633,6 +1680,7 @@ async function execute10(pieces, args, opts) {
|
|
|
1633
1680
|
const request = build(pieces, args);
|
|
1634
1681
|
const t0 = Date.now();
|
|
1635
1682
|
const workerCount = opts.workers ?? 3;
|
|
1683
|
+
const phases = [];
|
|
1636
1684
|
const plannerModel = opts.plannerModel ?? opts.model;
|
|
1637
1685
|
const workerModel = opts.workerModel ?? opts.model;
|
|
1638
1686
|
if (!opts.quiet) {
|
|
@@ -1642,11 +1690,18 @@ async function execute10(pieces, args, opts) {
|
|
|
1642
1690
|
);
|
|
1643
1691
|
}
|
|
1644
1692
|
if (!opts.quiet) process.stderr.write(" \u2192 Planning...\n");
|
|
1693
|
+
const planStart = Date.now();
|
|
1645
1694
|
const planText = await ask(request, {
|
|
1695
|
+
...opts,
|
|
1646
1696
|
model: plannerModel,
|
|
1647
|
-
maxTokens: opts.maxTokens,
|
|
1648
1697
|
thinkingLevel: "high",
|
|
1649
|
-
system: PLANNER_SYSTEM.replace("{$workerCount}", String(workerCount))
|
|
1698
|
+
system: mergeSystem(opts.system, PLANNER_SYSTEM.replace("{$workerCount}", String(workerCount)))
|
|
1699
|
+
});
|
|
1700
|
+
phases.push({
|
|
1701
|
+
phase: "plan",
|
|
1702
|
+
durationMs: Date.now() - planStart,
|
|
1703
|
+
description: `Generated plan with ${workerCount} workers`,
|
|
1704
|
+
modelUsed: plannerModel
|
|
1650
1705
|
});
|
|
1651
1706
|
const subTasks = [];
|
|
1652
1707
|
const taskLines = planText.split("\n");
|
|
@@ -1670,27 +1725,37 @@ async function execute10(pieces, args, opts) {
|
|
|
1670
1725
|
`);
|
|
1671
1726
|
}
|
|
1672
1727
|
}
|
|
1728
|
+
const planSummary = tasks.length > 0 ? `Execute ${tasks.length} sub-task(s) as planned?
|
|
1729
|
+
${tasks.map((t, i) => `${i + 1}. ${t.slice(0, 80)}`).join("\n ")}` : `Execute the plan?`;
|
|
1730
|
+
if (!await confirmPhase(planSummary, opts)) {
|
|
1731
|
+
throw new Error("pizx/\u03A9: Execution cancelled by user.");
|
|
1732
|
+
}
|
|
1673
1733
|
const workerResults = [];
|
|
1674
1734
|
const concurrency = opts.concurrency ?? 3;
|
|
1735
|
+
const dispatchStart = Date.now();
|
|
1675
1736
|
for (let i = 0; i < tasks.length; i += concurrency) {
|
|
1676
1737
|
const batch = tasks.slice(i, i + concurrency);
|
|
1677
1738
|
const batchResults = await Promise.allSettled(
|
|
1678
1739
|
batch.map(
|
|
1679
|
-
(task) => ask(task, {
|
|
1680
|
-
model: workerModel,
|
|
1681
|
-
maxTokens: opts.maxTokens,
|
|
1682
|
-
thinkingLevel: opts.thinkingLevel,
|
|
1683
|
-
system: WORKER_SYSTEM
|
|
1684
|
-
}).then((text) => new OrchestratorWorkerResult(task, text, true)).catch((err) => new OrchestratorWorkerResult(task, String(err), false))
|
|
1740
|
+
(task) => ask(task, { ...opts, model: workerModel, system: mergeSystem(opts.system, WORKER_SYSTEM) }).then((text) => new OrchestratorWorkerResult(task, text, true)).catch((err) => new OrchestratorWorkerResult(task, String(err), false))
|
|
1685
1741
|
)
|
|
1686
1742
|
);
|
|
1687
1743
|
batchResults.forEach((r) => {
|
|
1688
1744
|
if (r.status === "fulfilled") workerResults.push(r.value);
|
|
1689
1745
|
});
|
|
1690
1746
|
}
|
|
1747
|
+
const succeeded = workerResults.filter((w) => w.success).length;
|
|
1748
|
+
phases.push({
|
|
1749
|
+
phase: "dispatch",
|
|
1750
|
+
durationMs: Date.now() - dispatchStart,
|
|
1751
|
+
description: `Executed ${workerResults.length} worker(s), ${succeeded} succeeded`,
|
|
1752
|
+
modelUsed: workerModel,
|
|
1753
|
+
callCount: workerResults.length
|
|
1754
|
+
});
|
|
1691
1755
|
if (!opts.quiet) process.stderr.write(" \u2192 Synthesizing results...\n");
|
|
1692
1756
|
const workerTexts = workerResults.map((wr, i) => `Task ${i + 1}: ${wr.task}
|
|
1693
1757
|
Result: ${wr.output}`).join("\n\n");
|
|
1758
|
+
const synthStart = Date.now();
|
|
1694
1759
|
const synthesis = await ask(
|
|
1695
1760
|
`Original request:
|
|
1696
1761
|
${request}
|
|
@@ -1703,46 +1768,60 @@ ${workerTexts}
|
|
|
1703
1768
|
|
|
1704
1769
|
Synthesize a final deliverable.`,
|
|
1705
1770
|
{
|
|
1771
|
+
...opts,
|
|
1706
1772
|
model: plannerModel,
|
|
1707
|
-
maxTokens: opts.maxTokens,
|
|
1708
1773
|
thinkingLevel: "high",
|
|
1709
|
-
system: SYNTHESIS_SYSTEM4
|
|
1774
|
+
system: mergeSystem(opts.system, SYNTHESIS_SYSTEM4)
|
|
1710
1775
|
}
|
|
1711
1776
|
);
|
|
1777
|
+
phases.push({
|
|
1778
|
+
phase: "synthesize",
|
|
1779
|
+
durationMs: Date.now() - synthStart,
|
|
1780
|
+
description: "Synthesized worker results into final deliverable",
|
|
1781
|
+
modelUsed: plannerModel
|
|
1782
|
+
});
|
|
1783
|
+
if (!opts.quiet && opts.qualityCheck) process.stderr.write(" \u2192 Quality review...\n");
|
|
1784
|
+
const qualityStart = Date.now();
|
|
1785
|
+
const qualityReview = await runQualityReview(request, synthesis, opts);
|
|
1786
|
+
if (qualityReview) {
|
|
1787
|
+
phases.push({
|
|
1788
|
+
phase: "quality-review",
|
|
1789
|
+
durationMs: Date.now() - qualityStart,
|
|
1790
|
+
description: `Score: ${qualityReview.score.toFixed(2)} \u2014 ${qualityReview.assessment.slice(0, 60)}`,
|
|
1791
|
+
modelUsed: plannerModel
|
|
1792
|
+
});
|
|
1793
|
+
}
|
|
1712
1794
|
const t1 = Date.now();
|
|
1795
|
+
const reviewSection = qualityReview ? `
|
|
1796
|
+
|
|
1797
|
+
Quality Review: ${qualityReview.score.toFixed(2)} \u2014 ${qualityReview.assessment}
|
|
1798
|
+
Recommendation: ${qualityReview.recommendation}` : "";
|
|
1713
1799
|
const summary = `Plan:
|
|
1714
1800
|
${planText}
|
|
1715
1801
|
|
|
1716
1802
|
Workers: ${workerResults.filter((w) => w.success).length}/${workerResults.length} succeeded
|
|
1717
1803
|
|
|
1718
1804
|
Synthesis:
|
|
1719
|
-
${synthesis}`;
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
});
|
|
1732
|
-
let _quiet;
|
|
1733
|
-
Object.defineProperty(fn, "quiet", {
|
|
1734
|
-
get() {
|
|
1735
|
-
if (!_quiet) _quiet = makeOrchestrator({ ...merged, quiet: true });
|
|
1736
|
-
return _quiet;
|
|
1737
|
-
},
|
|
1738
|
-
enumerable: true,
|
|
1739
|
-
configurable: true
|
|
1740
|
-
});
|
|
1741
|
-
return fn;
|
|
1805
|
+
${synthesis}${reviewSection}`;
|
|
1806
|
+
const output = new OrchestratorOutput(
|
|
1807
|
+
summary,
|
|
1808
|
+
planText,
|
|
1809
|
+
synthesis,
|
|
1810
|
+
workerResults,
|
|
1811
|
+
t0,
|
|
1812
|
+
t1,
|
|
1813
|
+
qualityReview
|
|
1814
|
+
);
|
|
1815
|
+
output.phaseLog = phases;
|
|
1816
|
+
return output;
|
|
1742
1817
|
}
|
|
1743
|
-
var \u03A9 =
|
|
1818
|
+
var \u03A9 = createPatternTag(defaults10, execute10);
|
|
1744
1819
|
|
|
1745
1820
|
// src/patterns/pipeline.ts
|
|
1821
|
+
function describeStage(stage) {
|
|
1822
|
+
if (typeof stage === "function") return "(composed pattern)";
|
|
1823
|
+
return stage;
|
|
1824
|
+
}
|
|
1746
1825
|
var defaults11 = {
|
|
1747
1826
|
maxTokens: 4096,
|
|
1748
1827
|
thinkingLevel: "medium"
|
|
@@ -1758,13 +1837,15 @@ var PipelineStageResult = class {
|
|
|
1758
1837
|
index;
|
|
1759
1838
|
};
|
|
1760
1839
|
var PipelineOutput = class extends PatternOutput {
|
|
1761
|
-
constructor(text, finalOutput, stages, startTime, endTime) {
|
|
1840
|
+
constructor(text, finalOutput, stages, startTime, endTime, qualityReview) {
|
|
1762
1841
|
super(text, startTime, endTime);
|
|
1763
1842
|
this.finalOutput = finalOutput;
|
|
1764
1843
|
this.stages = stages;
|
|
1844
|
+
this.qualityReview = qualityReview;
|
|
1765
1845
|
}
|
|
1766
1846
|
finalOutput;
|
|
1767
1847
|
stages;
|
|
1848
|
+
qualityReview;
|
|
1768
1849
|
};
|
|
1769
1850
|
function parseStages(template, explicitStages, separator) {
|
|
1770
1851
|
if (explicitStages && explicitStages.length > 0) return explicitStages;
|
|
@@ -1806,55 +1887,46 @@ async function execute11(pieces, args, opts) {
|
|
|
1806
1887
|
`);
|
|
1807
1888
|
}
|
|
1808
1889
|
}
|
|
1890
|
+
const stageSummary = `Run ${stages.length} pipeline stage(s)?
|
|
1891
|
+
${stages.map((s, i) => `${i + 1}. ${describeStage(s)}`).join("\n ")}`;
|
|
1892
|
+
if (!await confirmPhase(stageSummary, opts)) {
|
|
1893
|
+
throw new Error("pizx/\u039B: Execution cancelled by user.");
|
|
1894
|
+
}
|
|
1809
1895
|
const stageResults = [];
|
|
1810
1896
|
let currentInput = "";
|
|
1811
1897
|
for (let i = 0; i < stages.length; i++) {
|
|
1812
1898
|
const stage = stages[i];
|
|
1899
|
+
const stageLabel = describeStage(stage);
|
|
1813
1900
|
const customPrompt = opts.stagePrompts?.[i];
|
|
1814
1901
|
if (!opts.quiet)
|
|
1815
|
-
process.stderr.write(` \u2192 Stage ${i + 1}/${stages.length}: ${
|
|
1902
|
+
process.stderr.write(` \u2192 Stage ${i + 1}/${stages.length}: ${stageLabel.slice(0, 50)}...
|
|
1816
1903
|
`);
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1904
|
+
let output;
|
|
1905
|
+
if (typeof stage === "function") {
|
|
1906
|
+
output = await stage(currentInput);
|
|
1907
|
+
} else {
|
|
1908
|
+
const prompt = customPrompt ?? generateStagePrompt(stage, currentInput, i === 0);
|
|
1909
|
+
const systemMessage = i === 0 ? `You are a specialist executing stage ${i + 1}: ${stage}. Focus only on this stage's output.` : `You are a specialist executing stage ${i + 1}: ${stage}. Process the previous stage's output according to your instructions. Maintain all important information from previous stages.`;
|
|
1910
|
+
output = await ask(prompt, {
|
|
1911
|
+
...opts,
|
|
1912
|
+
model: workerModel,
|
|
1913
|
+
system: mergeSystem(opts.system, systemMessage)
|
|
1914
|
+
});
|
|
1915
|
+
}
|
|
1916
|
+
stageResults.push(new PipelineStageResult(stageLabel, output, i));
|
|
1826
1917
|
currentInput = output;
|
|
1827
1918
|
}
|
|
1828
1919
|
const t1 = Date.now();
|
|
1829
1920
|
const finalOutput = currentInput;
|
|
1921
|
+
if (!opts.quiet && opts.qualityCheck) process.stderr.write(" \u2192 Quality review...\n");
|
|
1922
|
+
const qualityReview = await runQualityReview(template, finalOutput, opts);
|
|
1830
1923
|
const summary = stageResults.map(
|
|
1831
1924
|
(sr) => `Stage ${sr.index + 1} (${sr.stage}):
|
|
1832
1925
|
${sr.output.slice(0, 200)}${sr.output.length > 200 ? "..." : ""}`
|
|
1833
1926
|
).join("\n\n");
|
|
1834
|
-
return new PipelineOutput(summary, finalOutput, stageResults, t0, t1);
|
|
1835
|
-
}
|
|
1836
|
-
function makePipeline(opts = {}) {
|
|
1837
|
-
const merged = { ...defaults11, ...opts };
|
|
1838
|
-
const fn = ((pieces, ...args) => {
|
|
1839
|
-
if (!Array.isArray(pieces)) {
|
|
1840
|
-
return makePipeline({ ...merged, ...pieces });
|
|
1841
|
-
}
|
|
1842
|
-
return new PatternPromise((resolve, reject) => {
|
|
1843
|
-
execute11(pieces, args, merged).then(resolve, reject);
|
|
1844
|
-
});
|
|
1845
|
-
});
|
|
1846
|
-
let _quiet;
|
|
1847
|
-
Object.defineProperty(fn, "quiet", {
|
|
1848
|
-
get() {
|
|
1849
|
-
if (!_quiet) _quiet = makePipeline({ ...merged, quiet: true });
|
|
1850
|
-
return _quiet;
|
|
1851
|
-
},
|
|
1852
|
-
enumerable: true,
|
|
1853
|
-
configurable: true
|
|
1854
|
-
});
|
|
1855
|
-
return fn;
|
|
1927
|
+
return new PipelineOutput(summary, finalOutput, stageResults, t0, t1, qualityReview);
|
|
1856
1928
|
}
|
|
1857
|
-
var \u039B =
|
|
1929
|
+
var \u039B = createPatternTag(defaults11, execute11);
|
|
1858
1930
|
|
|
1859
1931
|
// src/patterns/ralph.ts
|
|
1860
1932
|
import { createAgentSession } from "@earendil-works/pi-coding-agent";
|
|
@@ -1889,17 +1961,17 @@ async function executeWithTools(goal, opts) {
|
|
|
1889
1961
|
});
|
|
1890
1962
|
try {
|
|
1891
1963
|
await session.sendUserMessage(goal);
|
|
1892
|
-
const
|
|
1893
|
-
for (let i =
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1964
|
+
const messages = session.messages;
|
|
1965
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
1966
|
+
const msg = messages[i];
|
|
1967
|
+
if (msg?.role !== "assistant") continue;
|
|
1968
|
+
const c = "content" in msg ? msg.content : void 0;
|
|
1969
|
+
if (typeof c === "string") return c.trim();
|
|
1970
|
+
if (Array.isArray(c)) {
|
|
1971
|
+
const texts = c.filter(
|
|
1972
|
+
(x) => x.type === "text" && typeof x.text === "string"
|
|
1973
|
+
).map((x) => x.text);
|
|
1974
|
+
if (texts.length > 0) return texts.join("").trim();
|
|
1903
1975
|
}
|
|
1904
1976
|
}
|
|
1905
1977
|
return "(no assistant response)";
|
|
@@ -1934,10 +2006,9 @@ async function execute12(pieces, args, opts) {
|
|
|
1934
2006
|
}
|
|
1935
2007
|
if (!opts.quiet) process.stderr.write(" \u2192 Analyzing...\n");
|
|
1936
2008
|
const analysis = await ask(currentGoal, {
|
|
2009
|
+
...opts,
|
|
1937
2010
|
model: plannerModel,
|
|
1938
|
-
|
|
1939
|
-
thinkingLevel: opts.thinkingLevel,
|
|
1940
|
-
system: ANALYSIS_SYSTEM2
|
|
2011
|
+
system: mergeSystem(opts.system, ANALYSIS_SYSTEM2)
|
|
1941
2012
|
});
|
|
1942
2013
|
if (!opts.quiet) process.stderr.write(" \u2192 Planning...\n");
|
|
1943
2014
|
const plan = await ask(
|
|
@@ -1946,12 +2017,7 @@ async function execute12(pieces, args, opts) {
|
|
|
1946
2017
|
Analysis: ${analysis}
|
|
1947
2018
|
|
|
1948
2019
|
Generate an implementation plan.`,
|
|
1949
|
-
{
|
|
1950
|
-
model: plannerModel,
|
|
1951
|
-
maxTokens: opts.maxTokens,
|
|
1952
|
-
thinkingLevel: opts.thinkingLevel,
|
|
1953
|
-
system: PLAN_SYSTEM2
|
|
1954
|
-
}
|
|
2020
|
+
{ ...opts, model: plannerModel, system: mergeSystem(opts.system, PLAN_SYSTEM2) }
|
|
1955
2021
|
);
|
|
1956
2022
|
if (!opts.quiet) process.stderr.write(" \u2192 Executing...\n");
|
|
1957
2023
|
const result = opts.useTools ? await executeWithTools(`Implement this plan:
|
|
@@ -1964,9 +2030,8 @@ Goal: ${currentGoal}`, {
|
|
|
1964
2030
|
${plan}
|
|
1965
2031
|
|
|
1966
2032
|
Goal: ${currentGoal}`, {
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
thinkingLevel: opts.thinkingLevel
|
|
2033
|
+
...opts,
|
|
2034
|
+
model: workerModel
|
|
1970
2035
|
});
|
|
1971
2036
|
if (!opts.quiet) process.stderr.write(" \u2192 Reviewing...\n");
|
|
1972
2037
|
const review = await ask(`Plan:
|
|
@@ -1976,10 +2041,11 @@ Result:
|
|
|
1976
2041
|
${result}
|
|
1977
2042
|
|
|
1978
2043
|
Review the implementation.`, {
|
|
2044
|
+
...opts,
|
|
1979
2045
|
model: plannerModel,
|
|
1980
2046
|
maxTokens: 1024,
|
|
1981
2047
|
thinkingLevel: "high",
|
|
1982
|
-
system: REVIEW_SYSTEM
|
|
2048
|
+
system: mergeSystem(opts.system, REVIEW_SYSTEM)
|
|
1983
2049
|
});
|
|
1984
2050
|
const shouldContinue = review.includes("ITERATE") && !review.includes("DONE");
|
|
1985
2051
|
iterations.push({
|
|
@@ -2015,28 +2081,7 @@ Original goal: ${goal}`;
|
|
|
2015
2081
|
t1
|
|
2016
2082
|
);
|
|
2017
2083
|
}
|
|
2018
|
-
|
|
2019
|
-
const merged = { ...defaults12, ...opts };
|
|
2020
|
-
const fn = ((pieces, ...args) => {
|
|
2021
|
-
if (!Array.isArray(pieces)) {
|
|
2022
|
-
return makeRalph({ ...merged, ...pieces });
|
|
2023
|
-
}
|
|
2024
|
-
return new PatternPromise((resolve, reject) => {
|
|
2025
|
-
execute12(pieces, args, merged).then(resolve, reject);
|
|
2026
|
-
});
|
|
2027
|
-
});
|
|
2028
|
-
let _quiet;
|
|
2029
|
-
Object.defineProperty(fn, "quiet", {
|
|
2030
|
-
get() {
|
|
2031
|
-
if (!_quiet) _quiet = makeRalph({ ...merged, quiet: true });
|
|
2032
|
-
return _quiet;
|
|
2033
|
-
},
|
|
2034
|
-
enumerable: true,
|
|
2035
|
-
configurable: true
|
|
2036
|
-
});
|
|
2037
|
-
return fn;
|
|
2038
|
-
}
|
|
2039
|
-
var \u03A1 = makeRalph();
|
|
2084
|
+
var \u03A1 = createPatternTag(defaults12, execute12);
|
|
2040
2085
|
|
|
2041
2086
|
// src/patterns/subagent.ts
|
|
2042
2087
|
var defaults13 = {
|
|
@@ -2056,13 +2101,15 @@ var SubagentResult = class {
|
|
|
2056
2101
|
success;
|
|
2057
2102
|
};
|
|
2058
2103
|
var SubagentOutput = class extends PatternOutput {
|
|
2059
|
-
constructor(text, synthesis, subResults, startTime, endTime) {
|
|
2104
|
+
constructor(text, synthesis, subResults, startTime, endTime, qualityReview) {
|
|
2060
2105
|
super(text, startTime, endTime);
|
|
2061
2106
|
this.synthesis = synthesis;
|
|
2062
2107
|
this.subResults = subResults;
|
|
2108
|
+
this.qualityReview = qualityReview;
|
|
2063
2109
|
}
|
|
2064
2110
|
synthesis;
|
|
2065
2111
|
subResults;
|
|
2112
|
+
qualityReview;
|
|
2066
2113
|
};
|
|
2067
2114
|
var DECOMPOSE_SYSTEM = `You are a task decomposition specialist. Break down complex tasks into independent sub-tasks that can be worked on in parallel. Output ONLY a JSON array of strings, each being a self-contained sub-task description. No markdown, no explanation.`;
|
|
2068
2115
|
var SYNTHESIS_SYSTEM5 = `You are a synthesis specialist. Combine the results from multiple sub-agent analyses into a coherent, comprehensive answer. Identify patterns, conflicts, and gaps.`;
|
|
@@ -2075,10 +2122,11 @@ ${task}
|
|
|
2075
2122
|
|
|
2076
2123
|
Output a JSON array of strings.`,
|
|
2077
2124
|
{
|
|
2125
|
+
...opts,
|
|
2078
2126
|
model: opts.model,
|
|
2079
2127
|
maxTokens: 1024,
|
|
2080
2128
|
thinkingLevel: "medium",
|
|
2081
|
-
system: DECOMPOSE_SYSTEM
|
|
2129
|
+
system: mergeSystem(opts.system, DECOMPOSE_SYSTEM)
|
|
2082
2130
|
}
|
|
2083
2131
|
);
|
|
2084
2132
|
try {
|
|
@@ -2099,6 +2147,7 @@ var SUBAGENT_SYSTEM = `You are a domain specialist. Complete your assigned sub-t
|
|
|
2099
2147
|
async function execute13(pieces, args, opts) {
|
|
2100
2148
|
const task = build(pieces, args);
|
|
2101
2149
|
const t0 = Date.now();
|
|
2150
|
+
const phases = [];
|
|
2102
2151
|
const plannerModel = opts.plannerModel ?? opts.model;
|
|
2103
2152
|
const workerModel = opts.workerModel ?? opts.model;
|
|
2104
2153
|
if (!opts.quiet) {
|
|
@@ -2108,7 +2157,14 @@ async function execute13(pieces, args, opts) {
|
|
|
2108
2157
|
);
|
|
2109
2158
|
}
|
|
2110
2159
|
if (!opts.quiet) process.stderr.write(" \u2192 Decomposing task into sub-tasks...\n");
|
|
2160
|
+
const decomposeStart = Date.now();
|
|
2111
2161
|
const subTasks = await decomposeTask(task, { ...opts, model: plannerModel });
|
|
2162
|
+
phases.push({
|
|
2163
|
+
phase: "decompose",
|
|
2164
|
+
durationMs: Date.now() - decomposeStart,
|
|
2165
|
+
description: `Decomposed into ${subTasks.length} sub-task(s)`,
|
|
2166
|
+
modelUsed: plannerModel
|
|
2167
|
+
});
|
|
2112
2168
|
if (!opts.quiet) {
|
|
2113
2169
|
process.stderr.write(` \u2192 ${subTasks.length} sub-task(s) identified:
|
|
2114
2170
|
`);
|
|
@@ -2118,27 +2174,37 @@ async function execute13(pieces, args, opts) {
|
|
|
2118
2174
|
`);
|
|
2119
2175
|
}
|
|
2120
2176
|
}
|
|
2177
|
+
const subTaskSummary = `Execute ${subTasks.length} sub-task(s)?
|
|
2178
|
+
${subTasks.map((st, i) => `${i + 1}. ${st.slice(0, 80)}`).join("\n ")}`;
|
|
2179
|
+
if (!await confirmPhase(subTaskSummary, opts)) {
|
|
2180
|
+
throw new Error("pizx/\u03A3: Execution cancelled by user.");
|
|
2181
|
+
}
|
|
2121
2182
|
const subResults = [];
|
|
2122
2183
|
const concurrency = opts.concurrency ?? 4;
|
|
2184
|
+
const execStart = Date.now();
|
|
2123
2185
|
for (let i = 0; i < subTasks.length; i += concurrency) {
|
|
2124
2186
|
const batch = subTasks.slice(i, i + concurrency);
|
|
2125
2187
|
const batchResults = await Promise.allSettled(
|
|
2126
2188
|
batch.map(
|
|
2127
|
-
(st) => ask(st, {
|
|
2128
|
-
model: workerModel,
|
|
2129
|
-
maxTokens: opts.maxTokens,
|
|
2130
|
-
thinkingLevel: opts.thinkingLevel,
|
|
2131
|
-
system: SUBAGENT_SYSTEM
|
|
2132
|
-
}).then((text) => new SubagentResult(st, text, true)).catch((err) => new SubagentResult(st, String(err), false))
|
|
2189
|
+
(st) => ask(st, { ...opts, model: workerModel, system: mergeSystem(opts.system, SUBAGENT_SYSTEM) }).then((text) => new SubagentResult(st, text, true)).catch((err) => new SubagentResult(st, String(err), false))
|
|
2133
2190
|
)
|
|
2134
2191
|
);
|
|
2135
2192
|
batchResults.forEach((r) => {
|
|
2136
2193
|
if (r.status === "fulfilled") subResults.push(r.value);
|
|
2137
2194
|
});
|
|
2138
2195
|
}
|
|
2196
|
+
const succeeded = subResults.filter((r) => r.success).length;
|
|
2197
|
+
phases.push({
|
|
2198
|
+
phase: "execute",
|
|
2199
|
+
durationMs: Date.now() - execStart,
|
|
2200
|
+
description: `Executed ${subResults.length} sub-task(s), ${succeeded} succeeded`,
|
|
2201
|
+
modelUsed: workerModel,
|
|
2202
|
+
callCount: subResults.length
|
|
2203
|
+
});
|
|
2139
2204
|
if (!opts.quiet) process.stderr.write(" \u2192 Synthesizing results...\n");
|
|
2140
2205
|
const subResultsText = subResults.map((sr, i) => `Sub-task ${i + 1}: ${sr.subTask}
|
|
2141
2206
|
Result: ${sr.text}`).join("\n\n");
|
|
2207
|
+
const synthStart = Date.now();
|
|
2142
2208
|
const synthesis = await ask(
|
|
2143
2209
|
`Original task:
|
|
2144
2210
|
${task}
|
|
@@ -2147,38 +2213,31 @@ Sub-task results:
|
|
|
2147
2213
|
${subResultsText}
|
|
2148
2214
|
|
|
2149
2215
|
Synthesize a comprehensive answer.`,
|
|
2150
|
-
{
|
|
2151
|
-
model: plannerModel,
|
|
2152
|
-
maxTokens: opts.maxTokens,
|
|
2153
|
-
thinkingLevel: opts.thinkingLevel,
|
|
2154
|
-
system: SYNTHESIS_SYSTEM5
|
|
2155
|
-
}
|
|
2216
|
+
{ ...opts, model: plannerModel, system: mergeSystem(opts.system, SYNTHESIS_SYSTEM5) }
|
|
2156
2217
|
);
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
const fn = ((pieces, ...args) => {
|
|
2163
|
-
if (!Array.isArray(pieces)) {
|
|
2164
|
-
return makeSubagent({ ...merged, ...pieces });
|
|
2165
|
-
}
|
|
2166
|
-
return new PatternPromise((resolve, reject) => {
|
|
2167
|
-
execute13(pieces, args, merged).then(resolve, reject);
|
|
2168
|
-
});
|
|
2169
|
-
});
|
|
2170
|
-
let _quiet;
|
|
2171
|
-
Object.defineProperty(fn, "quiet", {
|
|
2172
|
-
get() {
|
|
2173
|
-
if (!_quiet) _quiet = makeSubagent({ ...merged, quiet: true });
|
|
2174
|
-
return _quiet;
|
|
2175
|
-
},
|
|
2176
|
-
enumerable: true,
|
|
2177
|
-
configurable: true
|
|
2218
|
+
phases.push({
|
|
2219
|
+
phase: "synthesize",
|
|
2220
|
+
durationMs: Date.now() - synthStart,
|
|
2221
|
+
description: "Synthesized sub-agent results",
|
|
2222
|
+
modelUsed: plannerModel
|
|
2178
2223
|
});
|
|
2179
|
-
|
|
2224
|
+
if (!opts.quiet && opts.qualityCheck) process.stderr.write(" \u2192 Quality review...\n");
|
|
2225
|
+
const qStart = Date.now();
|
|
2226
|
+
const qualityReview = await runQualityReview(task, synthesis, opts);
|
|
2227
|
+
if (qualityReview) {
|
|
2228
|
+
phases.push({
|
|
2229
|
+
phase: "quality-review",
|
|
2230
|
+
durationMs: Date.now() - qStart,
|
|
2231
|
+
description: `Score: ${qualityReview.score.toFixed(2)}`,
|
|
2232
|
+
modelUsed: plannerModel
|
|
2233
|
+
});
|
|
2234
|
+
}
|
|
2235
|
+
const t1 = Date.now();
|
|
2236
|
+
const output = new SubagentOutput(synthesis, synthesis, subResults, t0, t1, qualityReview);
|
|
2237
|
+
output.phaseLog = phases;
|
|
2238
|
+
return output;
|
|
2180
2239
|
}
|
|
2181
|
-
var \u03A3 =
|
|
2240
|
+
var \u03A3 = createPatternTag(defaults13, execute13);
|
|
2182
2241
|
|
|
2183
2242
|
// src/patterns/tau.ts
|
|
2184
2243
|
var defaults14 = {
|
|
@@ -2202,15 +2261,17 @@ var ToolMediatedEntry = class {
|
|
|
2202
2261
|
content;
|
|
2203
2262
|
};
|
|
2204
2263
|
var TauOutput = class extends PatternOutput {
|
|
2205
|
-
constructor(text, entries, finalState, synthesis, startTime, endTime) {
|
|
2264
|
+
constructor(text, entries, finalState, synthesis, startTime, endTime, qualityReview) {
|
|
2206
2265
|
super(text, startTime, endTime);
|
|
2207
2266
|
this.entries = entries;
|
|
2208
2267
|
this.finalState = finalState;
|
|
2209
2268
|
this.synthesis = synthesis;
|
|
2269
|
+
this.qualityReview = qualityReview;
|
|
2210
2270
|
}
|
|
2211
2271
|
entries;
|
|
2212
2272
|
finalState;
|
|
2213
2273
|
synthesis;
|
|
2274
|
+
qualityReview;
|
|
2214
2275
|
};
|
|
2215
2276
|
var SCHEMA_SYSTEM = `You are a coordination architect. Given a task, design a shared structured context for agent collaboration.
|
|
2216
2277
|
|
|
@@ -2265,6 +2326,7 @@ async function defineSchema(task, opts) {
|
|
|
2265
2326
|
const response = await ask(`Task: ${task}
|
|
2266
2327
|
|
|
2267
2328
|
${prompt}`, {
|
|
2329
|
+
...opts,
|
|
2268
2330
|
model: opts.plannerModel ?? opts.model,
|
|
2269
2331
|
maxTokens: 1024,
|
|
2270
2332
|
thinkingLevel: "high"
|
|
@@ -2317,10 +2379,9 @@ async function executeRound(roles, assignments, store, round, opts) {
|
|
|
2317
2379
|
const systemPrompt = isWrite ? WRITE_SYSTEM(role, keysStr).replace("{store}", storeText) : UPDATE_SYSTEM(role, keysStr).replace("{store}", storeText);
|
|
2318
2380
|
const task = isWrite ? `Write your initial findings to your assigned keys: ${keysStr}` : `Review the shared context and update your entries for keys: ${keysStr}`;
|
|
2319
2381
|
const response = await ask(task, {
|
|
2382
|
+
...opts,
|
|
2320
2383
|
model: workerModel,
|
|
2321
|
-
|
|
2322
|
-
thinkingLevel: opts.thinkingLevel,
|
|
2323
|
-
system: systemPrompt
|
|
2384
|
+
system: mergeSystem(opts.system, systemPrompt)
|
|
2324
2385
|
});
|
|
2325
2386
|
return { role, response };
|
|
2326
2387
|
})
|
|
@@ -2360,10 +2421,10 @@ ${storeText}
|
|
|
2360
2421
|
|
|
2361
2422
|
Consolidate into a comprehensive, well-structured synthesis.`,
|
|
2362
2423
|
{
|
|
2424
|
+
...opts,
|
|
2363
2425
|
model: opts.plannerModel ?? opts.model,
|
|
2364
|
-
maxTokens: opts.maxTokens,
|
|
2365
2426
|
thinkingLevel: "high",
|
|
2366
|
-
system: CONSOLIDATE_SYSTEM
|
|
2427
|
+
system: mergeSystem(opts.system, CONSOLIDATE_SYSTEM)
|
|
2367
2428
|
}
|
|
2368
2429
|
);
|
|
2369
2430
|
}
|
|
@@ -2408,6 +2469,8 @@ async function execute14(pieces, args, opts) {
|
|
|
2408
2469
|
}
|
|
2409
2470
|
if (!opts.quiet) process.stderr.write(" \u2192 Consolidating store...\n");
|
|
2410
2471
|
const synthesis = await consolidateStore(task, store, { ...opts, plannerModel });
|
|
2472
|
+
if (!opts.quiet && opts.qualityCheck) process.stderr.write(" \u2192 Quality review...\n");
|
|
2473
|
+
const qualityReview = await runQualityReview(task, synthesis, opts);
|
|
2411
2474
|
const t1 = Date.now();
|
|
2412
2475
|
const summary = [
|
|
2413
2476
|
`Schema keys: ${keys.join(", ")}`,
|
|
@@ -2416,30 +2479,9 @@ async function execute14(pieces, args, opts) {
|
|
|
2416
2479
|
`Entries: ${allEntries.length}`,
|
|
2417
2480
|
`Synthesis: ${synthesis}`
|
|
2418
2481
|
].join("\n\n");
|
|
2419
|
-
return new TauOutput(summary, allEntries, store, synthesis, t0, t1);
|
|
2482
|
+
return new TauOutput(summary, allEntries, store, synthesis, t0, t1, qualityReview);
|
|
2420
2483
|
}
|
|
2421
|
-
|
|
2422
|
-
const merged = { ...defaults14, ...opts };
|
|
2423
|
-
const fn = ((pieces, ...args) => {
|
|
2424
|
-
if (!Array.isArray(pieces)) {
|
|
2425
|
-
return makeTau({ ...merged, ...pieces });
|
|
2426
|
-
}
|
|
2427
|
-
return new PatternPromise((resolve, reject) => {
|
|
2428
|
-
execute14(pieces, args, merged).then(resolve, reject);
|
|
2429
|
-
});
|
|
2430
|
-
});
|
|
2431
|
-
let _quiet;
|
|
2432
|
-
Object.defineProperty(fn, "quiet", {
|
|
2433
|
-
get() {
|
|
2434
|
-
if (!_quiet) _quiet = makeTau({ ...merged, quiet: true });
|
|
2435
|
-
return _quiet;
|
|
2436
|
-
},
|
|
2437
|
-
enumerable: true,
|
|
2438
|
-
configurable: true
|
|
2439
|
-
});
|
|
2440
|
-
return fn;
|
|
2441
|
-
}
|
|
2442
|
-
var \u03A4 = makeTau();
|
|
2484
|
+
var \u03A4 = createPatternTag(defaults14, execute14);
|
|
2443
2485
|
|
|
2444
2486
|
// src/patterns/thread.ts
|
|
2445
2487
|
var defaults15 = {
|
|
@@ -2448,27 +2490,6 @@ var defaults15 = {
|
|
|
2448
2490
|
agents: 3,
|
|
2449
2491
|
turns: 3
|
|
2450
2492
|
};
|
|
2451
|
-
var ROLE_SETS4 = {
|
|
2452
|
-
2: ["Proposer \u2014 advocate the best approach", "Critic \u2014 identify weaknesses and gaps"],
|
|
2453
|
-
3: [
|
|
2454
|
-
"Proposer \u2014 suggest the best approach",
|
|
2455
|
-
"Critic \u2014 identify weaknesses, risks, and missing pieces",
|
|
2456
|
-
"Synthesizer \u2014 combine the best ideas into a practical plan"
|
|
2457
|
-
],
|
|
2458
|
-
4: [
|
|
2459
|
-
"Proposer \u2014 advocate a bold solution",
|
|
2460
|
-
"Critic \u2014 identify risks and weaknesses",
|
|
2461
|
-
"Pragmatist \u2014 focus on practical implementation",
|
|
2462
|
-
"Innovator \u2014 propose creative alternatives"
|
|
2463
|
-
],
|
|
2464
|
-
5: [
|
|
2465
|
-
"Proposer",
|
|
2466
|
-
"Critic",
|
|
2467
|
-
"Pragmatist",
|
|
2468
|
-
"Innovator",
|
|
2469
|
-
"Devil's Advocate \u2014 challenge every assumption"
|
|
2470
|
-
]
|
|
2471
|
-
};
|
|
2472
2493
|
var ThreadMessage = class {
|
|
2473
2494
|
constructor(role, turn, content) {
|
|
2474
2495
|
this.role = role;
|
|
@@ -2480,13 +2501,15 @@ var ThreadMessage = class {
|
|
|
2480
2501
|
content;
|
|
2481
2502
|
};
|
|
2482
2503
|
var ThreadOutput = class extends PatternOutput {
|
|
2483
|
-
constructor(text, conclusion, messages, startTime, endTime) {
|
|
2504
|
+
constructor(text, conclusion, messages, startTime, endTime, qualityReview) {
|
|
2484
2505
|
super(text, startTime, endTime);
|
|
2485
2506
|
this.conclusion = conclusion;
|
|
2486
2507
|
this.messages = messages;
|
|
2508
|
+
this.qualityReview = qualityReview;
|
|
2487
2509
|
}
|
|
2488
2510
|
conclusion;
|
|
2489
2511
|
messages;
|
|
2512
|
+
qualityReview;
|
|
2490
2513
|
};
|
|
2491
2514
|
var THREAD_PROMPT = `You are an agent with the role: {role}.
|
|
2492
2515
|
Engage in a multi-agent conversation about the topic.
|
|
@@ -2508,7 +2531,7 @@ async function execute15(pieces, args, opts) {
|
|
|
2508
2531
|
const t0 = Date.now();
|
|
2509
2532
|
const agentCount = opts.agents ?? 3;
|
|
2510
2533
|
const maxTurns = opts.turns ?? 3;
|
|
2511
|
-
const roles = opts.roles ??
|
|
2534
|
+
const roles = opts.roles ?? THREAD_ROLE_SETS[agentCount] ?? THREAD_ROLE_SETS[3] ?? [];
|
|
2512
2535
|
const plannerModel = opts.plannerModel ?? opts.model;
|
|
2513
2536
|
const workerModel = opts.workerModel ?? opts.model;
|
|
2514
2537
|
if (!opts.quiet) {
|
|
@@ -2526,11 +2549,7 @@ async function execute15(pieces, args, opts) {
|
|
|
2526
2549
|
for (let a = 0; a < roles.length; a++) {
|
|
2527
2550
|
const role = roles[a] ?? `Agent ${a + 1}`;
|
|
2528
2551
|
const prompt = buildThreadPrompt(role, thread);
|
|
2529
|
-
const response = await ask(prompt, {
|
|
2530
|
-
model: workerModel,
|
|
2531
|
-
maxTokens: opts.maxTokens,
|
|
2532
|
-
thinkingLevel: opts.thinkingLevel
|
|
2533
|
-
});
|
|
2552
|
+
const response = await ask(prompt, { ...opts, model: workerModel });
|
|
2534
2553
|
messages.push(new ThreadMessage(role, turn, response));
|
|
2535
2554
|
thread += `
|
|
2536
2555
|
[${role}] (Turn ${turn}): ${response}
|
|
@@ -2546,46 +2565,24 @@ ${thread}
|
|
|
2546
2565
|
|
|
2547
2566
|
Synthesize a clear, actionable conclusion.`,
|
|
2548
2567
|
{
|
|
2568
|
+
...opts,
|
|
2549
2569
|
model: plannerModel,
|
|
2550
|
-
maxTokens: opts.maxTokens,
|
|
2551
2570
|
thinkingLevel: "high",
|
|
2552
|
-
system: SYNTHESIS_SYSTEM6
|
|
2571
|
+
system: mergeSystem(opts.system, SYNTHESIS_SYSTEM6)
|
|
2553
2572
|
}
|
|
2554
2573
|
);
|
|
2574
|
+
if (!opts.quiet && opts.qualityCheck) process.stderr.write(" \u2192 Quality review...\n");
|
|
2575
|
+
const qualityReview = await runQualityReview(topic, conclusion, opts);
|
|
2555
2576
|
const t1 = Date.now();
|
|
2556
2577
|
const summary = messages.map(
|
|
2557
2578
|
(m) => `[${m.role}] Turn ${m.turn}: ${m.content.slice(0, 150)}${m.content.length > 150 ? "..." : ""}`
|
|
2558
2579
|
).join("\n");
|
|
2559
|
-
return new ThreadOutput(summary, conclusion, messages, t0, t1);
|
|
2560
|
-
}
|
|
2561
|
-
function makeThread(opts = {}) {
|
|
2562
|
-
const merged = { ...defaults15, ...opts };
|
|
2563
|
-
const fn = ((pieces, ...args) => {
|
|
2564
|
-
if (!Array.isArray(pieces)) {
|
|
2565
|
-
return makeThread({ ...merged, ...pieces });
|
|
2566
|
-
}
|
|
2567
|
-
return new PatternPromise((resolve, reject) => {
|
|
2568
|
-
execute15(pieces, args, merged).then(resolve, reject);
|
|
2569
|
-
});
|
|
2570
|
-
});
|
|
2571
|
-
let _quiet;
|
|
2572
|
-
Object.defineProperty(fn, "quiet", {
|
|
2573
|
-
get() {
|
|
2574
|
-
if (!_quiet) _quiet = makeThread({ ...merged, quiet: true });
|
|
2575
|
-
return _quiet;
|
|
2576
|
-
},
|
|
2577
|
-
enumerable: true,
|
|
2578
|
-
configurable: true
|
|
2579
|
-
});
|
|
2580
|
-
return fn;
|
|
2580
|
+
return new ThreadOutput(summary, conclusion, messages, t0, t1, qualityReview);
|
|
2581
2581
|
}
|
|
2582
|
-
var \u0398 =
|
|
2582
|
+
var \u0398 = createPatternTag(defaults15, execute15);
|
|
2583
2583
|
|
|
2584
2584
|
// src/pi.ts
|
|
2585
2585
|
import {
|
|
2586
|
-
getEnvApiKey as getEnvApiKey2,
|
|
2587
|
-
getModels as getModels2,
|
|
2588
|
-
getProviders as getProviders2,
|
|
2589
2586
|
streamSimple
|
|
2590
2587
|
} from "@earendil-works/pi-ai";
|
|
2591
2588
|
|
|
@@ -2603,10 +2600,28 @@ var PiOutput = class {
|
|
|
2603
2600
|
events;
|
|
2604
2601
|
startTime;
|
|
2605
2602
|
endTime;
|
|
2603
|
+
/** Trace entry for this single LLM call. Populated by the π tag. */
|
|
2604
|
+
trace = [];
|
|
2606
2605
|
/** Duration in milliseconds */
|
|
2607
2606
|
get duration() {
|
|
2608
2607
|
return this.endTime - this.startTime;
|
|
2609
2608
|
}
|
|
2609
|
+
/** Total input tokens (convenience accessor) */
|
|
2610
|
+
get inputTokens() {
|
|
2611
|
+
return this.trace[0]?.inputTokens ?? 0;
|
|
2612
|
+
}
|
|
2613
|
+
/** Total output tokens (convenience accessor) */
|
|
2614
|
+
get outputTokens() {
|
|
2615
|
+
return this.trace[0]?.outputTokens ?? 0;
|
|
2616
|
+
}
|
|
2617
|
+
/** Total tokens (convenience accessor) */
|
|
2618
|
+
get totalTokens() {
|
|
2619
|
+
return this.trace[0]?.totalTokens ?? 0;
|
|
2620
|
+
}
|
|
2621
|
+
/** Total cost in USD (convenience accessor) */
|
|
2622
|
+
get totalCost() {
|
|
2623
|
+
return this.trace[0]?.cost ?? 0;
|
|
2624
|
+
}
|
|
2610
2625
|
toString() {
|
|
2611
2626
|
return this.text;
|
|
2612
2627
|
}
|
|
@@ -2632,90 +2647,13 @@ var defaults16 = {
|
|
|
2632
2647
|
quiet: false,
|
|
2633
2648
|
maxTokens: 4096
|
|
2634
2649
|
};
|
|
2635
|
-
var _piSettings2;
|
|
2636
|
-
function getPiDefaults2() {
|
|
2637
|
-
if (_piSettings2 === void 0) {
|
|
2638
|
-
_piSettings2 = isPiInstalled() ? loadPiSettings() : {};
|
|
2639
|
-
}
|
|
2640
|
-
return _piSettings2;
|
|
2641
|
-
}
|
|
2642
|
-
function allModels2() {
|
|
2643
|
-
const result = [];
|
|
2644
|
-
for (const p of getProviders2()) {
|
|
2645
|
-
const ms = getModels2(p);
|
|
2646
|
-
if (ms && ms.length > 0) result.push(...ms);
|
|
2647
|
-
}
|
|
2648
|
-
return result;
|
|
2649
|
-
}
|
|
2650
|
-
function getConfiguredProviders2() {
|
|
2651
|
-
return getProviders2().filter((p) => getEnvApiKey2(p) !== void 0);
|
|
2652
|
-
}
|
|
2653
|
-
function configuredModels2() {
|
|
2654
|
-
const configured = new Set(getConfiguredProviders2());
|
|
2655
|
-
return allModels2().filter((m) => configured.has(m.provider));
|
|
2656
|
-
}
|
|
2657
|
-
function findModelById2(id) {
|
|
2658
|
-
const all = allModels2();
|
|
2659
|
-
if (id.includes("/")) {
|
|
2660
|
-
const [provider, modelId] = id.split("/", 2);
|
|
2661
|
-
return all.find(
|
|
2662
|
-
(m) => m.provider === provider && (m.id === modelId || m.id.endsWith(`/${modelId}`))
|
|
2663
|
-
);
|
|
2664
|
-
}
|
|
2665
|
-
return all.find((m) => m.id === id || m.id.endsWith(`/${id}`));
|
|
2666
|
-
}
|
|
2667
|
-
function pickModel2(preferred) {
|
|
2668
|
-
if (preferred) {
|
|
2669
|
-
const hit = findModelById2(preferred);
|
|
2670
|
-
if (hit) return hit;
|
|
2671
|
-
}
|
|
2672
|
-
const settings = getPiDefaults2();
|
|
2673
|
-
if (settings.defaultModel) {
|
|
2674
|
-
const hit = findModelById2(settings.defaultModel);
|
|
2675
|
-
if (hit) return hit;
|
|
2676
|
-
}
|
|
2677
|
-
if (settings.defaultProvider) {
|
|
2678
|
-
const providerModels = getModels2(settings.defaultProvider);
|
|
2679
|
-
if (providerModels && providerModels.length > 0) {
|
|
2680
|
-
const configured = new Set(getConfiguredProviders2());
|
|
2681
|
-
if (configured.has(settings.defaultProvider)) {
|
|
2682
|
-
return providerModels[0];
|
|
2683
|
-
}
|
|
2684
|
-
}
|
|
2685
|
-
}
|
|
2686
|
-
const available = configuredModels2();
|
|
2687
|
-
if (available.length > 0) {
|
|
2688
|
-
const order2 = ["claude-sonnet-4-5", "claude-sonnet-4", "gemini-2.5-flash", "gpt-4o-mini"];
|
|
2689
|
-
for (const id of order2) {
|
|
2690
|
-
const m = available.find((m2) => m2.id.includes(id));
|
|
2691
|
-
if (m) return m;
|
|
2692
|
-
}
|
|
2693
|
-
return available[0];
|
|
2694
|
-
}
|
|
2695
|
-
const models = allModels2();
|
|
2696
|
-
if (models.length === 0) return void 0;
|
|
2697
|
-
const order = ["claude-sonnet-4-5", "claude-sonnet-4", "gemini-2.5-flash", "gpt-4o-mini"];
|
|
2698
|
-
for (const id of order) {
|
|
2699
|
-
const m = models.find((m2) => m2.id.includes(id));
|
|
2700
|
-
if (m) return m;
|
|
2701
|
-
}
|
|
2702
|
-
return models[0];
|
|
2703
|
-
}
|
|
2704
|
-
function build2(pieces, args) {
|
|
2705
|
-
let s = "";
|
|
2706
|
-
for (let i = 0; i < pieces.length; i++) {
|
|
2707
|
-
s += pieces[i];
|
|
2708
|
-
if (i < args.length) s += String(args[i]);
|
|
2709
|
-
}
|
|
2710
|
-
return s;
|
|
2711
|
-
}
|
|
2712
2650
|
function makeContext(pieces, args, opts) {
|
|
2713
2651
|
return {
|
|
2714
2652
|
systemPrompt: opts.system,
|
|
2715
2653
|
messages: [
|
|
2716
2654
|
{
|
|
2717
2655
|
role: "user",
|
|
2718
|
-
content:
|
|
2656
|
+
content: build(pieces, args),
|
|
2719
2657
|
timestamp: Date.now()
|
|
2720
2658
|
}
|
|
2721
2659
|
]
|
|
@@ -2724,25 +2662,51 @@ function makeContext(pieces, args, opts) {
|
|
|
2724
2662
|
function makeOpts(opts) {
|
|
2725
2663
|
return {
|
|
2726
2664
|
maxTokens: opts.maxTokens,
|
|
2727
|
-
reasoning: opts.thinkingLevel
|
|
2665
|
+
reasoning: opts.thinkingLevel,
|
|
2666
|
+
timeoutMs: opts.timeoutMs,
|
|
2667
|
+
maxRetries: opts.maxRetries
|
|
2728
2668
|
};
|
|
2729
2669
|
}
|
|
2730
2670
|
async function run(pieces, args, opts) {
|
|
2731
|
-
const model =
|
|
2671
|
+
const model = pickModel(opts.model);
|
|
2732
2672
|
if (!model) throw new Error("pizx/\u03C0: No AI models configured. Run `pi auth login` first.");
|
|
2733
2673
|
const t0 = Date.now();
|
|
2734
2674
|
let text = "";
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
if (
|
|
2675
|
+
let traceEntry;
|
|
2676
|
+
try {
|
|
2677
|
+
for await (const ev of streamSimple(model, makeContext(pieces, args, opts), makeOpts(opts))) {
|
|
2678
|
+
if (ev.type === "text_delta") {
|
|
2679
|
+
text += ev.delta;
|
|
2680
|
+
if (!opts.quiet) process.stdout.write(ev.delta);
|
|
2681
|
+
} else if (ev.type === "done") {
|
|
2682
|
+
const msg = ev.message;
|
|
2683
|
+
if (msg?.usage) {
|
|
2684
|
+
traceEntry = {
|
|
2685
|
+
call: 1,
|
|
2686
|
+
modelId: model.id,
|
|
2687
|
+
promptPreview: build(pieces, args).slice(0, 200),
|
|
2688
|
+
outputPreview: text.slice(0, 200),
|
|
2689
|
+
inputTokens: msg.usage.input,
|
|
2690
|
+
outputTokens: msg.usage.output,
|
|
2691
|
+
cacheReadTokens: msg.usage.cacheRead,
|
|
2692
|
+
cacheWriteTokens: msg.usage.cacheWrite,
|
|
2693
|
+
totalTokens: msg.usage.totalTokens,
|
|
2694
|
+
cost: msg.usage.cost.total,
|
|
2695
|
+
durationMs: Date.now() - t0
|
|
2696
|
+
};
|
|
2697
|
+
}
|
|
2698
|
+
}
|
|
2739
2699
|
}
|
|
2700
|
+
} catch (err) {
|
|
2701
|
+
throw new Error(`pizx/\u03C0: AI generation failed: ${getErrorMessage(err)}`);
|
|
2740
2702
|
}
|
|
2741
2703
|
if (!opts.quiet && text) process.stdout.write("\n");
|
|
2742
|
-
|
|
2704
|
+
const output = new PiOutput(text.trim(), model.id, [], t0, Date.now());
|
|
2705
|
+
if (traceEntry) output.trace = [traceEntry];
|
|
2706
|
+
return output;
|
|
2743
2707
|
}
|
|
2744
2708
|
async function* runStream(pieces, args, opts) {
|
|
2745
|
-
const model =
|
|
2709
|
+
const model = pickModel(opts.model);
|
|
2746
2710
|
if (!model) throw new Error("pizx/\u03C0: No AI models configured");
|
|
2747
2711
|
for await (const ev of streamSimple(model, makeContext(pieces, args, opts), makeOpts(opts))) {
|
|
2748
2712
|
if (ev.type === "text_delta") yield ev.delta;
|
|
@@ -2822,22 +2786,18 @@ var AgentPromise = class extends Promise {
|
|
|
2822
2786
|
var _sharedSession = null;
|
|
2823
2787
|
async function getSession(opts) {
|
|
2824
2788
|
if (_sharedSession && !opts.model) return _sharedSession;
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
for (let i = 0; i < pieces.length; i++) {
|
|
2837
|
-
s += pieces[i];
|
|
2838
|
-
if (i < args.length) s += String(args[i]);
|
|
2789
|
+
try {
|
|
2790
|
+
const result = await createAgentSession2({
|
|
2791
|
+
cwd: opts.cwd,
|
|
2792
|
+
thinkingLevel: opts.thinkingLevel,
|
|
2793
|
+
tools: opts.tools,
|
|
2794
|
+
excludeTools: opts.excludeTools
|
|
2795
|
+
});
|
|
2796
|
+
_sharedSession = result.session;
|
|
2797
|
+
return _sharedSession;
|
|
2798
|
+
} catch (err) {
|
|
2799
|
+
throw new Error(`pizx/\u03A0: Failed to create agent session: ${getErrorMessage(err)}`);
|
|
2839
2800
|
}
|
|
2840
|
-
return s.trim();
|
|
2841
2801
|
}
|
|
2842
2802
|
function getMessageText(msg) {
|
|
2843
2803
|
const content = msg.content;
|
|
@@ -2859,7 +2819,7 @@ function getLastAssistantText(session) {
|
|
|
2859
2819
|
return "";
|
|
2860
2820
|
}
|
|
2861
2821
|
async function execute16(pieces, args, opts) {
|
|
2862
|
-
const prompt =
|
|
2822
|
+
const prompt = build(pieces, args);
|
|
2863
2823
|
const session = await getSession(opts);
|
|
2864
2824
|
const t0 = Date.now();
|
|
2865
2825
|
if (!opts.quiet) {
|
|
@@ -2870,15 +2830,12 @@ async function execute16(pieces, args, opts) {
|
|
|
2870
2830
|
await session.sendUserMessage(prompt);
|
|
2871
2831
|
const t1 = Date.now();
|
|
2872
2832
|
const text = getLastAssistantText(session);
|
|
2873
|
-
const turnCount = session.messages.filter(
|
|
2874
|
-
(m) => m.role === "assistant"
|
|
2875
|
-
).length;
|
|
2833
|
+
const turnCount = session.messages.filter((m) => m.role === "assistant").length;
|
|
2876
2834
|
return new AgentOutput(text || "(no assistant response)", turnCount, t0, t1);
|
|
2877
2835
|
} catch (err) {
|
|
2878
2836
|
const t1 = Date.now();
|
|
2879
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
2880
2837
|
console.error("\u03A0 error:", err);
|
|
2881
|
-
return new AgentOutput(`\u03A0 error: ${
|
|
2838
|
+
return new AgentOutput(`\u03A0 error: ${getErrorMessage(err)}`, 0, t0, t1);
|
|
2882
2839
|
}
|
|
2883
2840
|
}
|
|
2884
2841
|
function makeAgent(opts = {}) {
|
|
@@ -2945,6 +2902,7 @@ export {
|
|
|
2945
2902
|
closeAgent,
|
|
2946
2903
|
configureAgent,
|
|
2947
2904
|
configurePi,
|
|
2905
|
+
createPatternTag,
|
|
2948
2906
|
\u0391,
|
|
2949
2907
|
\u0392,
|
|
2950
2908
|
\u0393,
|