@topce/pizx 0.1.0 → 0.4.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 +312 -20
- package/dist/cli.js +775 -733
- package/dist/cli.js.map +4 -4
- package/dist/index.js +770 -726
- 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,23 +112,261 @@ function pickModel(preferred) {
|
|
|
136
112
|
}
|
|
137
113
|
return models[0];
|
|
138
114
|
}
|
|
115
|
+
|
|
116
|
+
// src/skill-loader.ts
|
|
117
|
+
import { readFile } from "node:fs/promises";
|
|
118
|
+
import { homedir as homedir2 } from "node:os";
|
|
119
|
+
import { join as join2 } from "node:path";
|
|
120
|
+
var SKILL_PATHS = [
|
|
121
|
+
".pi/skills",
|
|
122
|
+
".agents/skills",
|
|
123
|
+
"skills",
|
|
124
|
+
join2(homedir2(), ".pi", "agent", "skills"),
|
|
125
|
+
join2(homedir2(), ".codewhale", "skills"),
|
|
126
|
+
join2(homedir2(), ".claude", "skills")
|
|
127
|
+
];
|
|
128
|
+
async function loadSkillContent(name) {
|
|
129
|
+
for (const base of SKILL_PATHS) {
|
|
130
|
+
const candidate = join2(base, name, "SKILL.md");
|
|
131
|
+
try {
|
|
132
|
+
return await readFile(candidate, "utf-8");
|
|
133
|
+
} catch {
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return void 0;
|
|
137
|
+
}
|
|
138
|
+
async function loadSkillContents(names) {
|
|
139
|
+
const map = /* @__PURE__ */ new Map();
|
|
140
|
+
for (const name of names) {
|
|
141
|
+
const content = await loadSkillContent(name);
|
|
142
|
+
if (content) map.set(name, content);
|
|
143
|
+
}
|
|
144
|
+
return map;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// src/patterns/types.ts
|
|
148
|
+
var PatternOutput = class {
|
|
149
|
+
constructor(text, startTime = Date.now(), endTime = Date.now()) {
|
|
150
|
+
this.text = text;
|
|
151
|
+
this.startTime = startTime;
|
|
152
|
+
this.endTime = endTime;
|
|
153
|
+
}
|
|
154
|
+
text;
|
|
155
|
+
startTime;
|
|
156
|
+
endTime;
|
|
157
|
+
/** Execution trace: one entry per LLM call within this pattern run. Populated by createPatternTag. */
|
|
158
|
+
trace = [];
|
|
159
|
+
/** Structured phase log: key phases during execution, populated by each pattern. */
|
|
160
|
+
phaseLog = [];
|
|
161
|
+
/** Duration in milliseconds */
|
|
162
|
+
get duration() {
|
|
163
|
+
return this.endTime - this.startTime;
|
|
164
|
+
}
|
|
165
|
+
/** Total input tokens across all calls */
|
|
166
|
+
get inputTokens() {
|
|
167
|
+
return this.trace.reduce((s, t) => s + t.inputTokens, 0);
|
|
168
|
+
}
|
|
169
|
+
/** Total output tokens across all calls */
|
|
170
|
+
get outputTokens() {
|
|
171
|
+
return this.trace.reduce((s, t) => s + t.outputTokens, 0);
|
|
172
|
+
}
|
|
173
|
+
/** Total tokens (input + output) across all calls */
|
|
174
|
+
get totalTokens() {
|
|
175
|
+
return this.trace.reduce((s, t) => s + t.totalTokens, 0);
|
|
176
|
+
}
|
|
177
|
+
/** Total cost in USD across all calls */
|
|
178
|
+
get totalCost() {
|
|
179
|
+
return this.trace.reduce((s, t) => s + t.cost, 0);
|
|
180
|
+
}
|
|
181
|
+
/** Number of LLM calls made during this pattern execution */
|
|
182
|
+
get callCount() {
|
|
183
|
+
return this.trace.length;
|
|
184
|
+
}
|
|
185
|
+
toString() {
|
|
186
|
+
return this.text;
|
|
187
|
+
}
|
|
188
|
+
valueOf() {
|
|
189
|
+
return this.text;
|
|
190
|
+
}
|
|
191
|
+
[Symbol.toPrimitive]() {
|
|
192
|
+
return this.text;
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
var PatternPromise = class extends Promise {
|
|
196
|
+
};
|
|
197
|
+
var _trace = null;
|
|
198
|
+
function beginTrace() {
|
|
199
|
+
_trace = [];
|
|
200
|
+
}
|
|
201
|
+
function collectTrace() {
|
|
202
|
+
const t = _trace ?? [];
|
|
203
|
+
_trace = null;
|
|
204
|
+
return t;
|
|
205
|
+
}
|
|
206
|
+
function pushTrace(entry) {
|
|
207
|
+
if (_trace) _trace.push(entry);
|
|
208
|
+
}
|
|
209
|
+
function createPatternTag(defaults17, execute17) {
|
|
210
|
+
function make(opts = {}) {
|
|
211
|
+
const merged = { ...defaults17, ...opts };
|
|
212
|
+
const fn = ((pieces, ...args) => {
|
|
213
|
+
if (!Array.isArray(pieces)) {
|
|
214
|
+
return make({ ...merged, ...pieces });
|
|
215
|
+
}
|
|
216
|
+
beginTrace();
|
|
217
|
+
return new PatternPromise((resolve, reject) => {
|
|
218
|
+
execute17(pieces, args, merged).then(
|
|
219
|
+
(output) => {
|
|
220
|
+
output.trace = collectTrace();
|
|
221
|
+
resolve(output);
|
|
222
|
+
},
|
|
223
|
+
(err) => {
|
|
224
|
+
collectTrace();
|
|
225
|
+
reject(err);
|
|
226
|
+
}
|
|
227
|
+
);
|
|
228
|
+
});
|
|
229
|
+
});
|
|
230
|
+
let _quiet;
|
|
231
|
+
Object.defineProperty(fn, "quiet", {
|
|
232
|
+
get() {
|
|
233
|
+
if (!_quiet) _quiet = make({ ...merged, quiet: true });
|
|
234
|
+
return _quiet;
|
|
235
|
+
},
|
|
236
|
+
enumerable: true,
|
|
237
|
+
configurable: true
|
|
238
|
+
});
|
|
239
|
+
return fn;
|
|
240
|
+
}
|
|
241
|
+
return make();
|
|
242
|
+
}
|
|
243
|
+
function build(pieces, args) {
|
|
244
|
+
let s = "";
|
|
245
|
+
for (let i = 0; i < pieces.length; i++) {
|
|
246
|
+
s += pieces[i];
|
|
247
|
+
if (i < args.length) s += String(args[i]);
|
|
248
|
+
}
|
|
249
|
+
return s.trim();
|
|
250
|
+
}
|
|
251
|
+
function mergeSystem(userSystem, patternSystem) {
|
|
252
|
+
if (!userSystem) return patternSystem;
|
|
253
|
+
return `${userSystem}
|
|
254
|
+
|
|
255
|
+
${patternSystem}`;
|
|
256
|
+
}
|
|
257
|
+
async function confirmPhase(description, opts) {
|
|
258
|
+
if (!opts.confirm) return true;
|
|
259
|
+
if (!opts.quiet) {
|
|
260
|
+
process.stderr.write(`
|
|
261
|
+
\u2500\u2500 Confirm \u2500\u2500
|
|
262
|
+
${description}
|
|
263
|
+
Proceed? [Y/n] `);
|
|
264
|
+
}
|
|
265
|
+
const rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
266
|
+
const answer = await new Promise((resolve) => {
|
|
267
|
+
rl.question("", (ans) => resolve(ans));
|
|
268
|
+
});
|
|
269
|
+
rl.close();
|
|
270
|
+
const trimmed = answer.trim().toLowerCase();
|
|
271
|
+
if (trimmed === "" || trimmed === "y" || trimmed === "yes") return true;
|
|
272
|
+
return false;
|
|
273
|
+
}
|
|
139
274
|
async function ask(prompt, opts = {}) {
|
|
140
275
|
const model = pickModel(opts.model);
|
|
141
276
|
if (!model) throw new Error("pizx/patterns: No AI models configured. Run `pi auth login` first.");
|
|
277
|
+
let systemPrompt = opts.system;
|
|
278
|
+
if (opts.skills && opts.skills.length > 0) {
|
|
279
|
+
const skillMap = await loadSkillContents(opts.skills);
|
|
280
|
+
if (skillMap.size > 0) {
|
|
281
|
+
const skillBlocks = [];
|
|
282
|
+
for (const [name, content] of skillMap) {
|
|
283
|
+
skillBlocks.push(`Skill context (${name}):
|
|
284
|
+
${content}`);
|
|
285
|
+
}
|
|
286
|
+
const skillContext = skillBlocks.join("\n\n");
|
|
287
|
+
systemPrompt = systemPrompt ? `${systemPrompt}
|
|
288
|
+
|
|
289
|
+
${skillContext}` : skillContext;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
const t0 = Date.now();
|
|
142
293
|
const result = await completeSimple(
|
|
143
294
|
model,
|
|
144
295
|
{
|
|
145
|
-
systemPrompt
|
|
296
|
+
systemPrompt,
|
|
146
297
|
messages: [{ role: "user", content: prompt, timestamp: Date.now() }]
|
|
147
298
|
},
|
|
148
299
|
{
|
|
149
300
|
maxTokens: opts.maxTokens ?? 4096,
|
|
150
|
-
reasoning: opts.thinkingLevel ?? "medium"
|
|
301
|
+
reasoning: opts.thinkingLevel ?? "medium",
|
|
302
|
+
thinkingBudgets: opts.thinkingBudgets,
|
|
303
|
+
timeoutMs: opts.timeoutMs,
|
|
304
|
+
maxRetries: opts.maxRetries
|
|
151
305
|
}
|
|
152
306
|
);
|
|
307
|
+
const durationMs = Date.now() - t0;
|
|
308
|
+
if (!result.content || !Array.isArray(result.content)) {
|
|
309
|
+
throw new Error("pizx/patterns: Unexpected response format from AI model.");
|
|
310
|
+
}
|
|
153
311
|
const text = result.content.filter((c) => c.type === "text").map((c) => c.text).join("");
|
|
312
|
+
if (_trace !== null) {
|
|
313
|
+
pushTrace({
|
|
314
|
+
call: _trace.length + 1,
|
|
315
|
+
modelId: result.model,
|
|
316
|
+
promptPreview: prompt.slice(0, 200),
|
|
317
|
+
outputPreview: text.slice(0, 200),
|
|
318
|
+
inputTokens: result.usage.input,
|
|
319
|
+
outputTokens: result.usage.output,
|
|
320
|
+
cacheReadTokens: result.usage.cacheRead,
|
|
321
|
+
cacheWriteTokens: result.usage.cacheWrite,
|
|
322
|
+
totalTokens: result.usage.totalTokens,
|
|
323
|
+
cost: result.usage.cost.total,
|
|
324
|
+
durationMs
|
|
325
|
+
});
|
|
326
|
+
}
|
|
154
327
|
return text.trim();
|
|
155
328
|
}
|
|
329
|
+
var QUALITY_REVIEW_SYSTEM = `You are a quality assurance reviewer. Evaluate the final deliverable against the original request.
|
|
330
|
+
|
|
331
|
+
Output format:
|
|
332
|
+
SCORE: 0.XX (quality score from 0.0 to 1.0)
|
|
333
|
+
ASSESSMENT: (1-2 sentences \u2014 is the output complete, consistent, and actionable?)
|
|
334
|
+
RECOMMENDATION: (1 sentence \u2014 what would improve this output?)`;
|
|
335
|
+
async function runQualityReview(originalRequest, finalOutput, opts) {
|
|
336
|
+
if (!opts.qualityCheck) return void 0;
|
|
337
|
+
const reviewText = await ask(
|
|
338
|
+
`Original request:
|
|
339
|
+
${originalRequest}
|
|
340
|
+
|
|
341
|
+
Final deliverable:
|
|
342
|
+
${finalOutput}
|
|
343
|
+
|
|
344
|
+
Evaluate the quality.`,
|
|
345
|
+
{
|
|
346
|
+
model: opts.plannerModel ?? opts.model,
|
|
347
|
+
maxTokens: 512,
|
|
348
|
+
thinkingLevel: "high",
|
|
349
|
+
timeoutMs: opts.timeoutMs,
|
|
350
|
+
maxRetries: opts.maxRetries,
|
|
351
|
+
system: QUALITY_REVIEW_SYSTEM
|
|
352
|
+
}
|
|
353
|
+
);
|
|
354
|
+
const scoreMatch = reviewText.match(/SCORE:\s*([\d.]+)/i);
|
|
355
|
+
const assessMatch = reviewText.match(/ASSESSMENT:\s*(.+)/i);
|
|
356
|
+
const recMatch = reviewText.match(/RECOMMENDATION:\s*(.+)/i);
|
|
357
|
+
const result = {
|
|
358
|
+
score: scoreMatch ? parseFloat(scoreMatch[1]) : 0.5,
|
|
359
|
+
assessment: assessMatch?.[1]?.trim() ?? "(no assessment)",
|
|
360
|
+
recommendation: recMatch?.[1]?.trim() ?? "(no recommendation)"
|
|
361
|
+
};
|
|
362
|
+
if (!opts.quiet) {
|
|
363
|
+
process.stderr.write(` Quality score: ${result.score.toFixed(2)}
|
|
364
|
+
`);
|
|
365
|
+
process.stderr.write(` ${result.assessment.slice(0, 80)}...
|
|
366
|
+
`);
|
|
367
|
+
}
|
|
368
|
+
return result;
|
|
369
|
+
}
|
|
156
370
|
|
|
157
371
|
// src/patterns/adaptive.ts
|
|
158
372
|
var defaults = {
|
|
@@ -216,10 +430,10 @@ async function execute(pieces, args, opts) {
|
|
|
216
430
|
}
|
|
217
431
|
if (!opts.quiet) process.stderr.write(" \u2192 Planning...\n");
|
|
218
432
|
const planText = await ask(goal, {
|
|
433
|
+
...opts,
|
|
219
434
|
model: plannerModel,
|
|
220
|
-
maxTokens: opts.maxTokens,
|
|
221
435
|
thinkingLevel: "high",
|
|
222
|
-
system: PLAN_SYSTEM
|
|
436
|
+
system: mergeSystem(opts.system, PLAN_SYSTEM)
|
|
223
437
|
});
|
|
224
438
|
const planLines = planText.split("\n");
|
|
225
439
|
const plannedSteps = [];
|
|
@@ -249,10 +463,9 @@ async function execute(pieces, args, opts) {
|
|
|
249
463
|
process.stderr.write(` \u2192 Step ${executionStep}: ${currentStep.slice(0, 60)}...
|
|
250
464
|
`);
|
|
251
465
|
const result = await ask(currentStep, {
|
|
466
|
+
...opts,
|
|
252
467
|
model: workerModel,
|
|
253
|
-
|
|
254
|
-
thinkingLevel: opts.thinkingLevel,
|
|
255
|
-
system: EXECUTE_SYSTEM
|
|
468
|
+
system: mergeSystem(opts.system, EXECUTE_SYSTEM)
|
|
256
469
|
});
|
|
257
470
|
const evaluation = await ask(
|
|
258
471
|
`Goal: ${goal}
|
|
@@ -261,10 +474,11 @@ Result: ${result}
|
|
|
261
474
|
|
|
262
475
|
Evaluate the result.`,
|
|
263
476
|
{
|
|
477
|
+
...opts,
|
|
264
478
|
model: plannerModel,
|
|
265
479
|
maxTokens: 512,
|
|
266
480
|
thinkingLevel: "high",
|
|
267
|
-
system: EVALUATE_SYSTEM
|
|
481
|
+
system: mergeSystem(opts.system, EVALUATE_SYSTEM)
|
|
268
482
|
}
|
|
269
483
|
);
|
|
270
484
|
const scoreMatch = evaluation.match(/SCORE:\s*([\d.]+)/i);
|
|
@@ -287,8 +501,7 @@ Evaluate the result.`,
|
|
|
287
501
|
break;
|
|
288
502
|
}
|
|
289
503
|
const adaptUpper = adaptation.toUpperCase();
|
|
290
|
-
if (adaptUpper.startsWith("
|
|
291
|
-
} else if (adaptUpper.startsWith("SKIP_NEXT")) {
|
|
504
|
+
if (adaptUpper.startsWith("SKIP_NEXT")) {
|
|
292
505
|
stepIndex += 2;
|
|
293
506
|
} else if (adaptUpper.startsWith("ADD")) {
|
|
294
507
|
const newStep = adaptation.replace(/^ADD\s*/i, "");
|
|
@@ -307,36 +520,76 @@ Evaluate the result.`,
|
|
|
307
520
|
).join("\n\n");
|
|
308
521
|
return new AdaptiveOutput(summary, finalResult, adaptiveSteps, executionStep, t0, t1);
|
|
309
522
|
}
|
|
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();
|
|
523
|
+
var \u0391 = createPatternTag(defaults, execute);
|
|
332
524
|
|
|
333
|
-
// src/patterns/
|
|
334
|
-
var
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
525
|
+
// src/patterns/role-sets.ts
|
|
526
|
+
var DEBATE_ROLE_SETS = {
|
|
527
|
+
2: [
|
|
528
|
+
"Optimist \u2014 advocate for the most ambitious approach",
|
|
529
|
+
"Pessimist \u2014 identify risks and failure modes"
|
|
530
|
+
],
|
|
531
|
+
3: [
|
|
532
|
+
"Optimist \u2014 advocate the benefits and opportunities",
|
|
533
|
+
"Pessimist \u2014 identify risks, costs, and failure modes",
|
|
534
|
+
"Pragmatist \u2014 focus on practical trade-offs and implementation"
|
|
535
|
+
],
|
|
536
|
+
4: [
|
|
537
|
+
"Optimist \u2014 argue for the best-case potential",
|
|
538
|
+
"Pessimist \u2014 highlight worst-case risks and downsides",
|
|
539
|
+
"Pragmatist \u2014 balance pros/cons with practical constraints",
|
|
540
|
+
"Innovator \u2014 propose creative alternatives and novel approaches"
|
|
541
|
+
],
|
|
542
|
+
5: [
|
|
543
|
+
"Optimist",
|
|
544
|
+
"Pessimist",
|
|
545
|
+
"Pragmatist",
|
|
546
|
+
"Innovator",
|
|
547
|
+
"User Advocate \u2014 focus on end-user experience and accessibility"
|
|
548
|
+
]
|
|
549
|
+
};
|
|
550
|
+
var MEMORY_ROLE_SETS = {
|
|
551
|
+
2: ["Analyst \u2014 deep analysis of core aspects", "Reviewer \u2014 check for gaps and blind spots"],
|
|
552
|
+
3: [
|
|
553
|
+
"Analyst \u2014 deep analysis of core aspects",
|
|
554
|
+
"Reviewer \u2014 check for gaps, edge cases, and blind spots",
|
|
555
|
+
"Strategist \u2014 connect findings to actionable insights"
|
|
556
|
+
],
|
|
557
|
+
4: [
|
|
558
|
+
"Analyst",
|
|
559
|
+
"Reviewer",
|
|
560
|
+
"Strategist",
|
|
561
|
+
"Innovator \u2014 propose novel angles and creative solutions"
|
|
562
|
+
],
|
|
563
|
+
5: [
|
|
564
|
+
"Analyst",
|
|
565
|
+
"Reviewer",
|
|
566
|
+
"Strategist",
|
|
567
|
+
"Innovator",
|
|
568
|
+
"Skeptic \u2014 challenge assumptions and stress-test conclusions"
|
|
569
|
+
]
|
|
570
|
+
};
|
|
571
|
+
var THREAD_ROLE_SETS = {
|
|
572
|
+
2: ["Proposer \u2014 advocate the best approach", "Critic \u2014 identify weaknesses and gaps"],
|
|
573
|
+
3: [
|
|
574
|
+
"Proposer \u2014 suggest the best approach",
|
|
575
|
+
"Critic \u2014 identify weaknesses, risks, and missing pieces",
|
|
576
|
+
"Synthesizer \u2014 combine the best ideas into a practical plan"
|
|
577
|
+
],
|
|
578
|
+
4: [
|
|
579
|
+
"Proposer \u2014 advocate a bold solution",
|
|
580
|
+
"Critic \u2014 identify risks and weaknesses",
|
|
581
|
+
"Pragmatist \u2014 focus on practical implementation",
|
|
582
|
+
"Innovator \u2014 propose creative alternatives"
|
|
583
|
+
],
|
|
584
|
+
5: [
|
|
585
|
+
"Proposer",
|
|
586
|
+
"Critic",
|
|
587
|
+
"Pragmatist",
|
|
588
|
+
"Innovator",
|
|
589
|
+
"Devil's Advocate \u2014 challenge every assumption"
|
|
590
|
+
]
|
|
338
591
|
};
|
|
339
|
-
var
|
|
592
|
+
var BROADCAST_ROLE_SETS = {
|
|
340
593
|
2: [
|
|
341
594
|
"Technical Expert \u2014 evaluate technical feasibility",
|
|
342
595
|
"Business Expert \u2014 evaluate business viability"
|
|
@@ -360,6 +613,13 @@ var ROLE_SETS = {
|
|
|
360
613
|
"Innovation Expert \u2014 suggest novel approaches and alternatives"
|
|
361
614
|
]
|
|
362
615
|
};
|
|
616
|
+
|
|
617
|
+
// src/patterns/broadcast.ts
|
|
618
|
+
var defaults2 = {
|
|
619
|
+
maxTokens: 4096,
|
|
620
|
+
thinkingLevel: "medium",
|
|
621
|
+
workers: 4
|
|
622
|
+
};
|
|
363
623
|
var BroadcastResponse = class {
|
|
364
624
|
constructor(role, response, success, error) {
|
|
365
625
|
this.role = role;
|
|
@@ -373,13 +633,15 @@ var BroadcastResponse = class {
|
|
|
373
633
|
error;
|
|
374
634
|
};
|
|
375
635
|
var BroadcastOutput = class extends PatternOutput {
|
|
376
|
-
constructor(text, synthesis, responses, startTime, endTime) {
|
|
636
|
+
constructor(text, synthesis, responses, startTime, endTime, qualityReview) {
|
|
377
637
|
super(text, startTime, endTime);
|
|
378
638
|
this.synthesis = synthesis;
|
|
379
639
|
this.responses = responses;
|
|
640
|
+
this.qualityReview = qualityReview;
|
|
380
641
|
}
|
|
381
642
|
synthesis;
|
|
382
643
|
responses;
|
|
644
|
+
qualityReview;
|
|
383
645
|
};
|
|
384
646
|
var WORKER_PROMPT = `You are a {role}.
|
|
385
647
|
|
|
@@ -394,7 +656,7 @@ async function execute2(pieces, args, opts) {
|
|
|
394
656
|
const question = build(pieces, args);
|
|
395
657
|
const t0 = Date.now();
|
|
396
658
|
const workerCount = opts.workers ?? 4;
|
|
397
|
-
const roles = opts.roles ??
|
|
659
|
+
const roles = opts.roles ?? BROADCAST_ROLE_SETS[workerCount] ?? BROADCAST_ROLE_SETS[4] ?? [];
|
|
398
660
|
const plannerModel = opts.plannerModel ?? opts.model;
|
|
399
661
|
const workerModel = opts.workerModel ?? opts.model;
|
|
400
662
|
if (!opts.quiet) {
|
|
@@ -409,11 +671,7 @@ async function execute2(pieces, args, opts) {
|
|
|
409
671
|
const broadcastResults = await Promise.allSettled(
|
|
410
672
|
roles.map(async (role) => {
|
|
411
673
|
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
|
-
});
|
|
674
|
+
const text = await ask(prompt, { ...opts, model: workerModel });
|
|
417
675
|
return new BroadcastResponse(role, text, true);
|
|
418
676
|
})
|
|
419
677
|
);
|
|
@@ -438,40 +696,21 @@ ${responsesText}
|
|
|
438
696
|
|
|
439
697
|
Synthesize a cohesive, actionable recommendation.`,
|
|
440
698
|
{
|
|
699
|
+
...opts,
|
|
441
700
|
model: plannerModel,
|
|
442
|
-
maxTokens: opts.maxTokens,
|
|
443
701
|
thinkingLevel: "high",
|
|
444
|
-
system: SYNTHESIS_SYSTEM
|
|
702
|
+
system: mergeSystem(opts.system, SYNTHESIS_SYSTEM)
|
|
445
703
|
}
|
|
446
704
|
);
|
|
705
|
+
if (!opts.quiet && opts.qualityCheck) process.stderr.write(" \u2192 Quality review...\n");
|
|
706
|
+
const qualityReview = await runQualityReview(question, synthesis, opts);
|
|
447
707
|
const t1 = Date.now();
|
|
448
708
|
const summary = responses.map(
|
|
449
709
|
(wr) => `[${wr.role}]: ${wr.response.slice(0, 150)}${wr.response.length > 150 ? "..." : ""}`
|
|
450
710
|
).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;
|
|
711
|
+
return new BroadcastOutput(summary, synthesis, responses, t0, t1, qualityReview);
|
|
473
712
|
}
|
|
474
|
-
var \u0392 =
|
|
713
|
+
var \u0392 = createPatternTag(defaults2, execute2);
|
|
475
714
|
|
|
476
715
|
// src/patterns/chi.ts
|
|
477
716
|
var defaults3 = {
|
|
@@ -491,15 +730,17 @@ var LearningInsight = class {
|
|
|
491
730
|
confidence;
|
|
492
731
|
};
|
|
493
732
|
var ChiOutput = class extends PatternOutput {
|
|
494
|
-
constructor(text, insights, summary, suggestedChanges, startTime, endTime) {
|
|
733
|
+
constructor(text, insights, summary, suggestedChanges, startTime, endTime, qualityReview) {
|
|
495
734
|
super(text, startTime, endTime);
|
|
496
735
|
this.insights = insights;
|
|
497
736
|
this.summary = summary;
|
|
498
737
|
this.suggestedChanges = suggestedChanges;
|
|
738
|
+
this.qualityReview = qualityReview;
|
|
499
739
|
}
|
|
500
740
|
insights;
|
|
501
741
|
summary;
|
|
502
742
|
suggestedChanges;
|
|
743
|
+
qualityReview;
|
|
503
744
|
};
|
|
504
745
|
var ANALYSIS_SYSTEM = `You are an agent team performance analyst. Review a multi-agent execution and extract structured learnings.
|
|
505
746
|
|
|
@@ -568,12 +809,13 @@ async function execute3(pieces, args, opts) {
|
|
|
568
809
|
`);
|
|
569
810
|
}
|
|
570
811
|
const response = await ask(input, {
|
|
812
|
+
...opts,
|
|
571
813
|
model: plannerModel,
|
|
572
|
-
|
|
573
|
-
thinkingLevel: opts.thinkingLevel,
|
|
574
|
-
system: ANALYSIS_SYSTEM
|
|
814
|
+
system: mergeSystem(opts.system, ANALYSIS_SYSTEM)
|
|
575
815
|
});
|
|
576
816
|
const { insights, summary, suggestedChanges } = parseInsights(response);
|
|
817
|
+
if (!opts.quiet && opts.qualityCheck) process.stderr.write(" \u2192 Quality review...\n");
|
|
818
|
+
const qualityReview = await runQualityReview(input, response, opts);
|
|
577
819
|
const t1 = Date.now();
|
|
578
820
|
const text = [
|
|
579
821
|
`Insights: ${insights.length} extracted`,
|
|
@@ -585,30 +827,9 @@ Summary: ${summary}`,
|
|
|
585
827
|
`
|
|
586
828
|
Changes: ${suggestedChanges}`
|
|
587
829
|
].join("\n");
|
|
588
|
-
return new ChiOutput(text, insights, summary, suggestedChanges, t0, t1);
|
|
830
|
+
return new ChiOutput(text, insights, summary, suggestedChanges, t0, t1, qualityReview);
|
|
589
831
|
}
|
|
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();
|
|
832
|
+
var \u03A7 = createPatternTag(defaults3, execute3);
|
|
612
833
|
|
|
613
834
|
// src/patterns/critique.ts
|
|
614
835
|
var defaults4 = {
|
|
@@ -663,12 +884,7 @@ async function execute4(pieces, args, opts) {
|
|
|
663
884
|
for (let r = 0; r < rounds; r++) {
|
|
664
885
|
if (r === 0) {
|
|
665
886
|
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
|
-
});
|
|
887
|
+
currentContent = await ask(prompt, { ...opts, model: workerModel, system: opts.system });
|
|
672
888
|
} else {
|
|
673
889
|
if (!opts.quiet) process.stderr.write(` \u2192 Improving (round ${r + 1})...
|
|
674
890
|
`);
|
|
@@ -683,21 +899,15 @@ Content to improve:
|
|
|
683
899
|
${currentContent}
|
|
684
900
|
|
|
685
901
|
Revise the content based on the critique.`,
|
|
686
|
-
{
|
|
687
|
-
model: workerModel,
|
|
688
|
-
maxTokens: opts.maxTokens,
|
|
689
|
-
thinkingLevel: opts.thinkingLevel,
|
|
690
|
-
system: IMPROVE_SYSTEM
|
|
691
|
-
}
|
|
902
|
+
{ ...opts, model: workerModel, system: mergeSystem(opts.system, IMPROVE_SYSTEM) }
|
|
692
903
|
);
|
|
693
904
|
}
|
|
694
905
|
if (!opts.quiet) process.stderr.write(` \u2192 Critiquing (round ${r + 1})...
|
|
695
906
|
`);
|
|
696
907
|
const critique = await ask(currentContent, {
|
|
908
|
+
...opts,
|
|
697
909
|
model: plannerModel,
|
|
698
|
-
|
|
699
|
-
thinkingLevel: opts.thinkingLevel,
|
|
700
|
-
system: CRITIQUE_SYSTEM
|
|
910
|
+
system: mergeSystem(opts.system, CRITIQUE_SYSTEM)
|
|
701
911
|
});
|
|
702
912
|
critiqueRounds.push(new CritiqueRound(currentContent, critique, r));
|
|
703
913
|
}
|
|
@@ -710,28 +920,7 @@ Critique: ${cr.critique.slice(0, 200)}${cr.critique.length > 200 ? "..." : ""}`
|
|
|
710
920
|
).join("\n\n");
|
|
711
921
|
return new CritiqueOutput(summary, finalContent, critiqueRounds, t0, t1);
|
|
712
922
|
}
|
|
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();
|
|
923
|
+
var \u03A8 = createPatternTag(defaults4, execute4);
|
|
735
924
|
|
|
736
925
|
// src/patterns/debate.ts
|
|
737
926
|
var defaults5 = {
|
|
@@ -740,30 +929,6 @@ var defaults5 = {
|
|
|
740
929
|
perspectives: 3,
|
|
741
930
|
rounds: 1
|
|
742
931
|
};
|
|
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
932
|
var DebatePerspective = class {
|
|
768
933
|
constructor(role, argument, round = 1) {
|
|
769
934
|
this.role = role;
|
|
@@ -775,15 +940,17 @@ var DebatePerspective = class {
|
|
|
775
940
|
round;
|
|
776
941
|
};
|
|
777
942
|
var DebateOutput = class extends PatternOutput {
|
|
778
|
-
constructor(text, conclusion, perspectives, rounds, startTime, endTime) {
|
|
943
|
+
constructor(text, conclusion, perspectives, rounds, startTime, endTime, qualityReview) {
|
|
779
944
|
super(text, startTime, endTime);
|
|
780
945
|
this.conclusion = conclusion;
|
|
781
946
|
this.perspectives = perspectives;
|
|
782
947
|
this.rounds = rounds;
|
|
948
|
+
this.qualityReview = qualityReview;
|
|
783
949
|
}
|
|
784
950
|
conclusion;
|
|
785
951
|
perspectives;
|
|
786
952
|
rounds;
|
|
953
|
+
qualityReview;
|
|
787
954
|
};
|
|
788
955
|
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
956
|
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 +960,7 @@ async function execute5(pieces, args, opts) {
|
|
|
793
960
|
const t0 = Date.now();
|
|
794
961
|
const count = opts.perspectives ?? 3;
|
|
795
962
|
const totalRounds = opts.rounds ?? 1;
|
|
796
|
-
const roles = opts.roles ??
|
|
963
|
+
const roles = opts.roles ?? DEBATE_ROLE_SETS[count] ?? DEBATE_ROLE_SETS[3] ?? [];
|
|
797
964
|
const plannerModel = opts.plannerModel ?? opts.model;
|
|
798
965
|
const workerModel = opts.workerModel ?? opts.model;
|
|
799
966
|
if (!opts.quiet) {
|
|
@@ -811,10 +978,9 @@ async function execute5(pieces, args, opts) {
|
|
|
811
978
|
const round1Results = await Promise.allSettled(
|
|
812
979
|
roles.map(
|
|
813
980
|
(role) => ask(question, {
|
|
981
|
+
...opts,
|
|
814
982
|
model: workerModel,
|
|
815
|
-
|
|
816
|
-
thinkingLevel: opts.thinkingLevel,
|
|
817
|
-
system: PERSPECTIVE_SYSTEM(role)
|
|
983
|
+
system: mergeSystem(opts.system, PERSPECTIVE_SYSTEM(role))
|
|
818
984
|
}).then((text) => new DebatePerspective(role, text, 1))
|
|
819
985
|
)
|
|
820
986
|
);
|
|
@@ -848,10 +1014,9 @@ ${othersText}
|
|
|
848
1014
|
|
|
849
1015
|
Refine your position. Address the counter-arguments directly. Strengthen your argument with rebuttals.`;
|
|
850
1016
|
return ask(prompt, {
|
|
1017
|
+
...opts,
|
|
851
1018
|
model: workerModel,
|
|
852
|
-
|
|
853
|
-
thinkingLevel: opts.thinkingLevel,
|
|
854
|
-
system: REBUTTAL_SYSTEM(role)
|
|
1019
|
+
system: mergeSystem(opts.system, REBUTTAL_SYSTEM(role))
|
|
855
1020
|
}).then((text) => new DebatePerspective(role, text, round));
|
|
856
1021
|
})
|
|
857
1022
|
);
|
|
@@ -875,37 +1040,31 @@ Refine your position. Address the counter-arguments directly. Strengthen your ar
|
|
|
875
1040
|
|
|
876
1041
|
Synthesize a balanced conclusion from the full debate above. Weigh the evidence from all rounds.`,
|
|
877
1042
|
{
|
|
1043
|
+
...opts,
|
|
878
1044
|
model: plannerModel,
|
|
879
|
-
maxTokens: opts.maxTokens,
|
|
880
1045
|
thinkingLevel: "high",
|
|
881
|
-
system: SYNTHESIS_SYSTEM2
|
|
1046
|
+
system: mergeSystem(opts.system, SYNTHESIS_SYSTEM2)
|
|
882
1047
|
}
|
|
883
1048
|
);
|
|
1049
|
+
if (!opts.quiet && opts.qualityCheck) process.stderr.write(" \u2192 Quality review...\n");
|
|
1050
|
+
const qualityReview = await runQualityReview(question, conclusion, opts);
|
|
884
1051
|
const t1 = Date.now();
|
|
885
|
-
return new DebateOutput(
|
|
1052
|
+
return new DebateOutput(
|
|
1053
|
+
conclusion,
|
|
1054
|
+
conclusion,
|
|
1055
|
+
allPerspectives,
|
|
1056
|
+
totalRounds,
|
|
1057
|
+
t0,
|
|
1058
|
+
t1,
|
|
1059
|
+
qualityReview
|
|
1060
|
+
);
|
|
886
1061
|
}
|
|
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;
|
|
1062
|
+
var \u0394 = createPatternTag(defaults5, execute5);
|
|
1063
|
+
|
|
1064
|
+
// src/utils.ts
|
|
1065
|
+
function getErrorMessage(err) {
|
|
1066
|
+
return err instanceof Error ? err.message : String(err);
|
|
907
1067
|
}
|
|
908
|
-
var \u0394 = makeDebate();
|
|
909
1068
|
|
|
910
1069
|
// src/patterns/fleet.ts
|
|
911
1070
|
var defaults6 = {
|
|
@@ -926,11 +1085,13 @@ var FleetMemberOutput = class {
|
|
|
926
1085
|
error;
|
|
927
1086
|
};
|
|
928
1087
|
var FleetOutput = class extends PatternOutput {
|
|
929
|
-
constructor(text, members, startTime, endTime) {
|
|
1088
|
+
constructor(text, members, startTime, endTime, qualityReview) {
|
|
930
1089
|
super(text, startTime, endTime);
|
|
931
1090
|
this.members = members;
|
|
1091
|
+
this.qualityReview = qualityReview;
|
|
932
1092
|
}
|
|
933
1093
|
members;
|
|
1094
|
+
qualityReview;
|
|
934
1095
|
/** Number of successful members */
|
|
935
1096
|
get successCount() {
|
|
936
1097
|
return this.members.filter((m) => m.success).length;
|
|
@@ -950,20 +1111,30 @@ function parseTasks(template, explicitTasks) {
|
|
|
950
1111
|
if (lines.length > 1) return lines;
|
|
951
1112
|
return [template];
|
|
952
1113
|
}
|
|
1114
|
+
function describeTask(task) {
|
|
1115
|
+
if (typeof task === "function") return "(composed pattern)";
|
|
1116
|
+
return task;
|
|
1117
|
+
}
|
|
953
1118
|
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
1119
|
async function executeTask(task, opts, workerModel) {
|
|
1120
|
+
if (typeof task === "function") {
|
|
1121
|
+
try {
|
|
1122
|
+
const text = await task("");
|
|
1123
|
+
return new FleetMemberOutput("(composed pattern)", text, true);
|
|
1124
|
+
} catch (err) {
|
|
1125
|
+
return new FleetMemberOutput("(composed pattern)", "", false, getErrorMessage(err));
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
955
1128
|
const model = workerModel ?? opts.model;
|
|
956
1129
|
try {
|
|
957
1130
|
const text = await ask(task, {
|
|
1131
|
+
...opts,
|
|
958
1132
|
model,
|
|
959
|
-
|
|
960
|
-
thinkingLevel: opts.thinkingLevel,
|
|
961
|
-
system: opts.system ?? FLEET_SYSTEM
|
|
1133
|
+
system: mergeSystem(opts.system, FLEET_SYSTEM)
|
|
962
1134
|
});
|
|
963
1135
|
return new FleetMemberOutput(task, text, true);
|
|
964
1136
|
} catch (err) {
|
|
965
|
-
|
|
966
|
-
return new FleetMemberOutput(task, "", false, msg);
|
|
1137
|
+
return new FleetMemberOutput(task, "", false, getErrorMessage(err));
|
|
967
1138
|
}
|
|
968
1139
|
}
|
|
969
1140
|
async function execute6(pieces, args, opts) {
|
|
@@ -975,11 +1146,16 @@ async function execute6(pieces, args, opts) {
|
|
|
975
1146
|
process.stderr.write(`\u03A6: Fleet executing ${tasks.length} task(s) in parallel
|
|
976
1147
|
`);
|
|
977
1148
|
for (let i = 0; i < tasks.length; i++) {
|
|
978
|
-
const t = tasks[i];
|
|
1149
|
+
const t = describeTask(tasks[i]);
|
|
979
1150
|
process.stderr.write(` [${i + 1}] ${t.slice(0, 60)}${t.length > 60 ? "..." : ""}
|
|
980
1151
|
`);
|
|
981
1152
|
}
|
|
982
1153
|
}
|
|
1154
|
+
const taskSummary = `Execute ${tasks.length} fleet task(s)?
|
|
1155
|
+
${tasks.map((t, i) => `${i + 1}. ${describeTask(t).slice(0, 80)}`).join("\n ")}`;
|
|
1156
|
+
if (!await confirmPhase(taskSummary, opts)) {
|
|
1157
|
+
throw new Error("pizx/\u03A6: Execution cancelled by user.");
|
|
1158
|
+
}
|
|
983
1159
|
const results = [];
|
|
984
1160
|
const concurrency = opts.concurrency ?? 5;
|
|
985
1161
|
for (let i = 0; i < tasks.length; i += concurrency) {
|
|
@@ -991,7 +1167,9 @@ async function execute6(pieces, args, opts) {
|
|
|
991
1167
|
if (r.status === "fulfilled") {
|
|
992
1168
|
results.push(r.value);
|
|
993
1169
|
} else {
|
|
994
|
-
results.push(
|
|
1170
|
+
results.push(
|
|
1171
|
+
new FleetMemberOutput(describeTask(batch[idx]), "", false, r.reason?.toString())
|
|
1172
|
+
);
|
|
995
1173
|
}
|
|
996
1174
|
});
|
|
997
1175
|
}
|
|
@@ -1003,30 +1181,11 @@ async function execute6(pieces, args, opts) {
|
|
|
1003
1181
|
const header = `Fleet Results: ${results.filter((r) => r.success).length}/${results.length} succeeded
|
|
1004
1182
|
|
|
1005
1183
|
`;
|
|
1006
|
-
|
|
1007
|
-
|
|
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;
|
|
1184
|
+
if (!opts.quiet && opts.qualityCheck) process.stderr.write(" \u2192 Quality review...\n");
|
|
1185
|
+
const qualityReview = await runQualityReview(template, header + summary, opts);
|
|
1186
|
+
return new FleetOutput(header + summary, results, t0, t1, qualityReview);
|
|
1028
1187
|
}
|
|
1029
|
-
var \u03A6 =
|
|
1188
|
+
var \u03A6 = createPatternTag(defaults6, execute6);
|
|
1030
1189
|
|
|
1031
1190
|
// src/patterns/graph.ts
|
|
1032
1191
|
var defaults7 = {
|
|
@@ -1046,13 +1205,15 @@ var GraphNodeResult = class {
|
|
|
1046
1205
|
success;
|
|
1047
1206
|
};
|
|
1048
1207
|
var GraphOutput = class extends PatternOutput {
|
|
1049
|
-
constructor(text, finalOutput, nodeResults, startTime, endTime) {
|
|
1208
|
+
constructor(text, finalOutput, nodeResults, startTime, endTime, qualityReview) {
|
|
1050
1209
|
super(text, startTime, endTime);
|
|
1051
1210
|
this.finalOutput = finalOutput;
|
|
1052
1211
|
this.nodeResults = nodeResults;
|
|
1212
|
+
this.qualityReview = qualityReview;
|
|
1053
1213
|
}
|
|
1054
1214
|
finalOutput;
|
|
1055
1215
|
nodeResults;
|
|
1216
|
+
qualityReview;
|
|
1056
1217
|
};
|
|
1057
1218
|
function parseGraph(template, separator) {
|
|
1058
1219
|
const sep = separator ?? "\u2192";
|
|
@@ -1148,10 +1309,9 @@ Your task: ${node.task}`;
|
|
|
1148
1309
|
}
|
|
1149
1310
|
}
|
|
1150
1311
|
const text = await ask(context, {
|
|
1312
|
+
...opts,
|
|
1151
1313
|
model: workerModel,
|
|
1152
|
-
|
|
1153
|
-
thinkingLevel: opts.thinkingLevel,
|
|
1154
|
-
system: NODE_SYSTEM
|
|
1314
|
+
system: mergeSystem(opts.system, NODE_SYSTEM)
|
|
1155
1315
|
});
|
|
1156
1316
|
return { nodeId, task: node.task, text, success: true };
|
|
1157
1317
|
})
|
|
@@ -1169,34 +1329,15 @@ Your task: ${node.task}`;
|
|
|
1169
1329
|
const lastBatch = batches[batches.length - 1] ?? [];
|
|
1170
1330
|
const finalNodeResults = lastBatch.map((id) => results.get(id)).filter(Boolean);
|
|
1171
1331
|
const finalOutput = finalNodeResults.length > 0 ? finalNodeResults.join("\n\n") : "";
|
|
1332
|
+
if (!opts.quiet && opts.qualityCheck) process.stderr.write(" \u2192 Quality review...\n");
|
|
1333
|
+
const qualityReview = await runQualityReview(template, finalOutput, opts);
|
|
1172
1334
|
const summary = nodeResults.map(
|
|
1173
1335
|
(nr) => `[${nr.nodeId}] ${nr.task.slice(0, 80)}...
|
|
1174
1336
|
${nr.output.slice(0, 200)}${nr.output.length > 200 ? "..." : ""}`
|
|
1175
1337
|
).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;
|
|
1338
|
+
return new GraphOutput(summary, finalOutput, nodeResults, t0, t1, qualityReview);
|
|
1198
1339
|
}
|
|
1199
|
-
var \u0393 =
|
|
1340
|
+
var \u0393 = createPatternTag(defaults7, execute7);
|
|
1200
1341
|
|
|
1201
1342
|
// src/patterns/memory.ts
|
|
1202
1343
|
var defaults8 = {
|
|
@@ -1205,27 +1346,6 @@ var defaults8 = {
|
|
|
1205
1346
|
agents: 3,
|
|
1206
1347
|
rounds: 1
|
|
1207
1348
|
};
|
|
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
1349
|
var MemoryEntry = class {
|
|
1230
1350
|
constructor(role, round, content) {
|
|
1231
1351
|
this.role = role;
|
|
@@ -1237,13 +1357,15 @@ var MemoryEntry = class {
|
|
|
1237
1357
|
content;
|
|
1238
1358
|
};
|
|
1239
1359
|
var MemoryOutput = class extends PatternOutput {
|
|
1240
|
-
constructor(text, synthesis, entries, startTime, endTime) {
|
|
1360
|
+
constructor(text, synthesis, entries, startTime, endTime, qualityReview) {
|
|
1241
1361
|
super(text, startTime, endTime);
|
|
1242
1362
|
this.synthesis = synthesis;
|
|
1243
1363
|
this.entries = entries;
|
|
1364
|
+
this.qualityReview = qualityReview;
|
|
1244
1365
|
}
|
|
1245
1366
|
synthesis;
|
|
1246
1367
|
entries;
|
|
1368
|
+
qualityReview;
|
|
1247
1369
|
};
|
|
1248
1370
|
var WRITER_PROMPT = `You are a specialist with role: {role}.
|
|
1249
1371
|
|
|
@@ -1264,7 +1386,7 @@ async function execute8(pieces, args, opts) {
|
|
|
1264
1386
|
const t0 = Date.now();
|
|
1265
1387
|
const agentCount = opts.agents ?? 3;
|
|
1266
1388
|
const totalRounds = opts.rounds ?? 1;
|
|
1267
|
-
const roles = opts.roles ??
|
|
1389
|
+
const roles = opts.roles ?? MEMORY_ROLE_SETS[agentCount] ?? MEMORY_ROLE_SETS[3] ?? [];
|
|
1268
1390
|
const plannerModel = opts.plannerModel ?? opts.model;
|
|
1269
1391
|
const workerModel = opts.workerModel ?? opts.model;
|
|
1270
1392
|
if (!opts.quiet) {
|
|
@@ -1281,11 +1403,7 @@ async function execute8(pieces, args, opts) {
|
|
|
1281
1403
|
const roundResults = await Promise.allSettled(
|
|
1282
1404
|
roles.map(async (role) => {
|
|
1283
1405
|
const prompt = buildWriterPrompt(role, topic, blackboard);
|
|
1284
|
-
const text = await ask(prompt, {
|
|
1285
|
-
model: workerModel,
|
|
1286
|
-
maxTokens: opts.maxTokens,
|
|
1287
|
-
thinkingLevel: opts.thinkingLevel
|
|
1288
|
-
});
|
|
1406
|
+
const text = await ask(prompt, { ...opts, model: workerModel });
|
|
1289
1407
|
return { role, text };
|
|
1290
1408
|
})
|
|
1291
1409
|
);
|
|
@@ -1307,40 +1425,21 @@ ${blackboard}
|
|
|
1307
1425
|
|
|
1308
1426
|
Consolidate into a comprehensive, structured synthesis.`,
|
|
1309
1427
|
{
|
|
1428
|
+
...opts,
|
|
1310
1429
|
model: plannerModel,
|
|
1311
|
-
maxTokens: opts.maxTokens,
|
|
1312
1430
|
thinkingLevel: "high",
|
|
1313
|
-
system: CONSOLIDATOR_SYSTEM
|
|
1431
|
+
system: mergeSystem(opts.system, CONSOLIDATOR_SYSTEM)
|
|
1314
1432
|
}
|
|
1315
1433
|
);
|
|
1434
|
+
if (!opts.quiet && opts.qualityCheck) process.stderr.write(" \u2192 Quality review...\n");
|
|
1435
|
+
const qualityReview = await runQualityReview(topic, synthesis, opts);
|
|
1316
1436
|
const t1 = Date.now();
|
|
1317
1437
|
const summary = entries.map(
|
|
1318
1438
|
(e) => `[${e.role}] Round ${e.round}: ${e.content.slice(0, 150)}${e.content.length > 150 ? "..." : ""}`
|
|
1319
1439
|
).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;
|
|
1440
|
+
return new MemoryOutput(summary, synthesis, entries, t0, t1, qualityReview);
|
|
1342
1441
|
}
|
|
1343
|
-
var \u039C =
|
|
1442
|
+
var \u039C = createPatternTag(defaults8, execute8);
|
|
1344
1443
|
|
|
1345
1444
|
// src/patterns/nu.ts
|
|
1346
1445
|
var defaults9 = {
|
|
@@ -1360,19 +1459,21 @@ var NuRole = class {
|
|
|
1360
1459
|
goal;
|
|
1361
1460
|
};
|
|
1362
1461
|
var NuOutput = class extends PatternOutput {
|
|
1363
|
-
constructor(text, negotiatedRoles, workflow, workflowReasoning, roleResults, synthesis, startTime, endTime) {
|
|
1462
|
+
constructor(text, negotiatedRoles, workflow, workflowReasoning, roleResults, synthesis, startTime, endTime, qualityReview) {
|
|
1364
1463
|
super(text, startTime, endTime);
|
|
1365
1464
|
this.negotiatedRoles = negotiatedRoles;
|
|
1366
1465
|
this.workflow = workflow;
|
|
1367
1466
|
this.workflowReasoning = workflowReasoning;
|
|
1368
1467
|
this.roleResults = roleResults;
|
|
1369
1468
|
this.synthesis = synthesis;
|
|
1469
|
+
this.qualityReview = qualityReview;
|
|
1370
1470
|
}
|
|
1371
1471
|
negotiatedRoles;
|
|
1372
1472
|
workflow;
|
|
1373
1473
|
workflowReasoning;
|
|
1374
1474
|
roleResults;
|
|
1375
1475
|
synthesis;
|
|
1476
|
+
qualityReview;
|
|
1376
1477
|
};
|
|
1377
1478
|
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
1479
|
|
|
@@ -1410,6 +1511,7 @@ async function negotiateRoles(task, opts) {
|
|
|
1410
1511
|
const response = await ask(`Task: ${task}
|
|
1411
1512
|
|
|
1412
1513
|
${prompt}`, {
|
|
1514
|
+
...opts,
|
|
1413
1515
|
model: opts.plannerModel ?? opts.model,
|
|
1414
1516
|
maxTokens: 2048,
|
|
1415
1517
|
thinkingLevel: "high"
|
|
@@ -1446,10 +1548,11 @@ ${rolesText}
|
|
|
1446
1548
|
|
|
1447
1549
|
Determine the best execution strategy.`,
|
|
1448
1550
|
{
|
|
1551
|
+
...opts,
|
|
1449
1552
|
model: opts.plannerModel ?? opts.model,
|
|
1450
1553
|
maxTokens: 512,
|
|
1451
1554
|
thinkingLevel: "high",
|
|
1452
|
-
system: WORKFLOW_SYSTEM
|
|
1555
|
+
system: mergeSystem(opts.system, WORKFLOW_SYSTEM)
|
|
1453
1556
|
}
|
|
1454
1557
|
);
|
|
1455
1558
|
const wfMatch = response.match(/WORKFLOW\s*:\s*(.+)/i);
|
|
@@ -1468,10 +1571,9 @@ async function executeRoles(roles, task, workflow, opts) {
|
|
|
1468
1571
|
let context = task;
|
|
1469
1572
|
for (const role of roles) {
|
|
1470
1573
|
const output = await ask(context, {
|
|
1574
|
+
...opts,
|
|
1471
1575
|
model: workerModel,
|
|
1472
|
-
|
|
1473
|
-
thinkingLevel: opts.thinkingLevel,
|
|
1474
|
-
system: EXECUTE_SYSTEM2(role)
|
|
1576
|
+
system: mergeSystem(opts.system, EXECUTE_SYSTEM2(role))
|
|
1475
1577
|
});
|
|
1476
1578
|
results.push({ role: role.name, output });
|
|
1477
1579
|
context = `Previous output from ${role.name}:
|
|
@@ -1483,10 +1585,9 @@ Continue with: ${task}`;
|
|
|
1483
1585
|
const parallelResults = await Promise.allSettled(
|
|
1484
1586
|
roles.map(
|
|
1485
1587
|
(role) => ask(task, {
|
|
1588
|
+
...opts,
|
|
1486
1589
|
model: workerModel,
|
|
1487
|
-
|
|
1488
|
-
thinkingLevel: opts.thinkingLevel,
|
|
1489
|
-
system: EXECUTE_SYSTEM2(role)
|
|
1590
|
+
system: mergeSystem(opts.system, EXECUTE_SYSTEM2(role))
|
|
1490
1591
|
}).then((text) => ({ role: role.name, output: text })).catch((err) => ({ role: role.name, output: `(failed: ${String(err)})` }))
|
|
1491
1592
|
)
|
|
1492
1593
|
);
|
|
@@ -1508,10 +1609,10 @@ ${resultsText}
|
|
|
1508
1609
|
|
|
1509
1610
|
Synthesize a comprehensive final answer.`,
|
|
1510
1611
|
{
|
|
1612
|
+
...opts,
|
|
1511
1613
|
model: opts.plannerModel ?? opts.model,
|
|
1512
|
-
maxTokens: opts.maxTokens,
|
|
1513
1614
|
thinkingLevel: "high",
|
|
1514
|
-
system: SYNTHESIS_SYSTEM3
|
|
1615
|
+
system: mergeSystem(opts.system, SYNTHESIS_SYSTEM3)
|
|
1515
1616
|
}
|
|
1516
1617
|
);
|
|
1517
1618
|
}
|
|
@@ -1549,40 +1650,31 @@ async function execute9(pieces, args, opts) {
|
|
|
1549
1650
|
}
|
|
1550
1651
|
if (!opts.quiet) process.stderr.write(` \u2192 Executing (${workflow})...
|
|
1551
1652
|
`);
|
|
1552
|
-
const roleResults = await executeRoles(roles, task, workflow, opts);
|
|
1553
|
-
if (!opts.quiet) process.stderr.write(" \u2192 Synthesizing...\n");
|
|
1554
|
-
const synthesis = await synthesize(task, roleResults, { ...opts, plannerModel });
|
|
1555
|
-
|
|
1556
|
-
const
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
`
|
|
1560
|
-
`
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
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;
|
|
1653
|
+
const roleResults = await executeRoles(roles, task, workflow, opts);
|
|
1654
|
+
if (!opts.quiet) process.stderr.write(" \u2192 Synthesizing...\n");
|
|
1655
|
+
const synthesis = await synthesize(task, roleResults, { ...opts, plannerModel });
|
|
1656
|
+
if (!opts.quiet && opts.qualityCheck) process.stderr.write(" \u2192 Quality review...\n");
|
|
1657
|
+
const qualityReview = await runQualityReview(task, synthesis, opts);
|
|
1658
|
+
const t1 = Date.now();
|
|
1659
|
+
const summary = [
|
|
1660
|
+
`Roles: ${roles.map((r) => r.name).join(", ")}`,
|
|
1661
|
+
`Workflow: ${workflow} (${reasoning})`,
|
|
1662
|
+
`Results: ${roleResults.length}/${roles.length} succeeded`,
|
|
1663
|
+
`Synthesis: ${synthesis}`
|
|
1664
|
+
].join("\n\n");
|
|
1665
|
+
return new NuOutput(
|
|
1666
|
+
summary,
|
|
1667
|
+
roles,
|
|
1668
|
+
workflow,
|
|
1669
|
+
reasoning,
|
|
1670
|
+
roleResults,
|
|
1671
|
+
synthesis,
|
|
1672
|
+
t0,
|
|
1673
|
+
t1,
|
|
1674
|
+
qualityReview
|
|
1675
|
+
);
|
|
1584
1676
|
}
|
|
1585
|
-
var \u039D =
|
|
1677
|
+
var \u039D = createPatternTag(defaults9, execute9);
|
|
1586
1678
|
|
|
1587
1679
|
// src/patterns/orchestrator.ts
|
|
1588
1680
|
var defaults10 = {
|
|
@@ -1602,15 +1694,17 @@ var OrchestratorWorkerResult = class {
|
|
|
1602
1694
|
success;
|
|
1603
1695
|
};
|
|
1604
1696
|
var OrchestratorOutput = class extends PatternOutput {
|
|
1605
|
-
constructor(text, plan, synthesis, workerResults, startTime, endTime) {
|
|
1697
|
+
constructor(text, plan, synthesis, workerResults, startTime, endTime, qualityReview) {
|
|
1606
1698
|
super(text, startTime, endTime);
|
|
1607
1699
|
this.plan = plan;
|
|
1608
1700
|
this.synthesis = synthesis;
|
|
1609
1701
|
this.workerResults = workerResults;
|
|
1702
|
+
this.qualityReview = qualityReview;
|
|
1610
1703
|
}
|
|
1611
1704
|
plan;
|
|
1612
1705
|
synthesis;
|
|
1613
1706
|
workerResults;
|
|
1707
|
+
qualityReview;
|
|
1614
1708
|
};
|
|
1615
1709
|
var PLANNER_SYSTEM = `You are a senior architect and project planner. Given a high-level request, create a detailed execution plan.
|
|
1616
1710
|
|
|
@@ -1633,6 +1727,7 @@ async function execute10(pieces, args, opts) {
|
|
|
1633
1727
|
const request = build(pieces, args);
|
|
1634
1728
|
const t0 = Date.now();
|
|
1635
1729
|
const workerCount = opts.workers ?? 3;
|
|
1730
|
+
const phases = [];
|
|
1636
1731
|
const plannerModel = opts.plannerModel ?? opts.model;
|
|
1637
1732
|
const workerModel = opts.workerModel ?? opts.model;
|
|
1638
1733
|
if (!opts.quiet) {
|
|
@@ -1642,11 +1737,18 @@ async function execute10(pieces, args, opts) {
|
|
|
1642
1737
|
);
|
|
1643
1738
|
}
|
|
1644
1739
|
if (!opts.quiet) process.stderr.write(" \u2192 Planning...\n");
|
|
1740
|
+
const planStart = Date.now();
|
|
1645
1741
|
const planText = await ask(request, {
|
|
1742
|
+
...opts,
|
|
1646
1743
|
model: plannerModel,
|
|
1647
|
-
maxTokens: opts.maxTokens,
|
|
1648
1744
|
thinkingLevel: "high",
|
|
1649
|
-
system: PLANNER_SYSTEM.replace("{$workerCount}", String(workerCount))
|
|
1745
|
+
system: mergeSystem(opts.system, PLANNER_SYSTEM.replace("{$workerCount}", String(workerCount)))
|
|
1746
|
+
});
|
|
1747
|
+
phases.push({
|
|
1748
|
+
phase: "plan",
|
|
1749
|
+
durationMs: Date.now() - planStart,
|
|
1750
|
+
description: `Generated plan with ${workerCount} workers`,
|
|
1751
|
+
modelUsed: plannerModel
|
|
1650
1752
|
});
|
|
1651
1753
|
const subTasks = [];
|
|
1652
1754
|
const taskLines = planText.split("\n");
|
|
@@ -1670,27 +1772,37 @@ async function execute10(pieces, args, opts) {
|
|
|
1670
1772
|
`);
|
|
1671
1773
|
}
|
|
1672
1774
|
}
|
|
1775
|
+
const planSummary = tasks.length > 0 ? `Execute ${tasks.length} sub-task(s) as planned?
|
|
1776
|
+
${tasks.map((t, i) => `${i + 1}. ${t.slice(0, 80)}`).join("\n ")}` : `Execute the plan?`;
|
|
1777
|
+
if (!await confirmPhase(planSummary, opts)) {
|
|
1778
|
+
throw new Error("pizx/\u03A9: Execution cancelled by user.");
|
|
1779
|
+
}
|
|
1673
1780
|
const workerResults = [];
|
|
1674
1781
|
const concurrency = opts.concurrency ?? 3;
|
|
1782
|
+
const dispatchStart = Date.now();
|
|
1675
1783
|
for (let i = 0; i < tasks.length; i += concurrency) {
|
|
1676
1784
|
const batch = tasks.slice(i, i + concurrency);
|
|
1677
1785
|
const batchResults = await Promise.allSettled(
|
|
1678
1786
|
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))
|
|
1787
|
+
(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
1788
|
)
|
|
1686
1789
|
);
|
|
1687
1790
|
batchResults.forEach((r) => {
|
|
1688
1791
|
if (r.status === "fulfilled") workerResults.push(r.value);
|
|
1689
1792
|
});
|
|
1690
1793
|
}
|
|
1794
|
+
const succeeded = workerResults.filter((w) => w.success).length;
|
|
1795
|
+
phases.push({
|
|
1796
|
+
phase: "dispatch",
|
|
1797
|
+
durationMs: Date.now() - dispatchStart,
|
|
1798
|
+
description: `Executed ${workerResults.length} worker(s), ${succeeded} succeeded`,
|
|
1799
|
+
modelUsed: workerModel,
|
|
1800
|
+
callCount: workerResults.length
|
|
1801
|
+
});
|
|
1691
1802
|
if (!opts.quiet) process.stderr.write(" \u2192 Synthesizing results...\n");
|
|
1692
1803
|
const workerTexts = workerResults.map((wr, i) => `Task ${i + 1}: ${wr.task}
|
|
1693
1804
|
Result: ${wr.output}`).join("\n\n");
|
|
1805
|
+
const synthStart = Date.now();
|
|
1694
1806
|
const synthesis = await ask(
|
|
1695
1807
|
`Original request:
|
|
1696
1808
|
${request}
|
|
@@ -1703,46 +1815,60 @@ ${workerTexts}
|
|
|
1703
1815
|
|
|
1704
1816
|
Synthesize a final deliverable.`,
|
|
1705
1817
|
{
|
|
1818
|
+
...opts,
|
|
1706
1819
|
model: plannerModel,
|
|
1707
|
-
maxTokens: opts.maxTokens,
|
|
1708
1820
|
thinkingLevel: "high",
|
|
1709
|
-
system: SYNTHESIS_SYSTEM4
|
|
1821
|
+
system: mergeSystem(opts.system, SYNTHESIS_SYSTEM4)
|
|
1710
1822
|
}
|
|
1711
1823
|
);
|
|
1824
|
+
phases.push({
|
|
1825
|
+
phase: "synthesize",
|
|
1826
|
+
durationMs: Date.now() - synthStart,
|
|
1827
|
+
description: "Synthesized worker results into final deliverable",
|
|
1828
|
+
modelUsed: plannerModel
|
|
1829
|
+
});
|
|
1830
|
+
if (!opts.quiet && opts.qualityCheck) process.stderr.write(" \u2192 Quality review...\n");
|
|
1831
|
+
const qualityStart = Date.now();
|
|
1832
|
+
const qualityReview = await runQualityReview(request, synthesis, opts);
|
|
1833
|
+
if (qualityReview) {
|
|
1834
|
+
phases.push({
|
|
1835
|
+
phase: "quality-review",
|
|
1836
|
+
durationMs: Date.now() - qualityStart,
|
|
1837
|
+
description: `Score: ${qualityReview.score.toFixed(2)} \u2014 ${qualityReview.assessment.slice(0, 60)}`,
|
|
1838
|
+
modelUsed: plannerModel
|
|
1839
|
+
});
|
|
1840
|
+
}
|
|
1712
1841
|
const t1 = Date.now();
|
|
1842
|
+
const reviewSection = qualityReview ? `
|
|
1843
|
+
|
|
1844
|
+
Quality Review: ${qualityReview.score.toFixed(2)} \u2014 ${qualityReview.assessment}
|
|
1845
|
+
Recommendation: ${qualityReview.recommendation}` : "";
|
|
1713
1846
|
const summary = `Plan:
|
|
1714
1847
|
${planText}
|
|
1715
1848
|
|
|
1716
1849
|
Workers: ${workerResults.filter((w) => w.success).length}/${workerResults.length} succeeded
|
|
1717
1850
|
|
|
1718
1851
|
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;
|
|
1852
|
+
${synthesis}${reviewSection}`;
|
|
1853
|
+
const output = new OrchestratorOutput(
|
|
1854
|
+
summary,
|
|
1855
|
+
planText,
|
|
1856
|
+
synthesis,
|
|
1857
|
+
workerResults,
|
|
1858
|
+
t0,
|
|
1859
|
+
t1,
|
|
1860
|
+
qualityReview
|
|
1861
|
+
);
|
|
1862
|
+
output.phaseLog = phases;
|
|
1863
|
+
return output;
|
|
1742
1864
|
}
|
|
1743
|
-
var \u03A9 =
|
|
1865
|
+
var \u03A9 = createPatternTag(defaults10, execute10);
|
|
1744
1866
|
|
|
1745
1867
|
// src/patterns/pipeline.ts
|
|
1868
|
+
function describeStage(stage) {
|
|
1869
|
+
if (typeof stage === "function") return "(composed pattern)";
|
|
1870
|
+
return stage;
|
|
1871
|
+
}
|
|
1746
1872
|
var defaults11 = {
|
|
1747
1873
|
maxTokens: 4096,
|
|
1748
1874
|
thinkingLevel: "medium"
|
|
@@ -1758,13 +1884,15 @@ var PipelineStageResult = class {
|
|
|
1758
1884
|
index;
|
|
1759
1885
|
};
|
|
1760
1886
|
var PipelineOutput = class extends PatternOutput {
|
|
1761
|
-
constructor(text, finalOutput, stages, startTime, endTime) {
|
|
1887
|
+
constructor(text, finalOutput, stages, startTime, endTime, qualityReview) {
|
|
1762
1888
|
super(text, startTime, endTime);
|
|
1763
1889
|
this.finalOutput = finalOutput;
|
|
1764
1890
|
this.stages = stages;
|
|
1891
|
+
this.qualityReview = qualityReview;
|
|
1765
1892
|
}
|
|
1766
1893
|
finalOutput;
|
|
1767
1894
|
stages;
|
|
1895
|
+
qualityReview;
|
|
1768
1896
|
};
|
|
1769
1897
|
function parseStages(template, explicitStages, separator) {
|
|
1770
1898
|
if (explicitStages && explicitStages.length > 0) return explicitStages;
|
|
@@ -1806,55 +1934,46 @@ async function execute11(pieces, args, opts) {
|
|
|
1806
1934
|
`);
|
|
1807
1935
|
}
|
|
1808
1936
|
}
|
|
1937
|
+
const stageSummary = `Run ${stages.length} pipeline stage(s)?
|
|
1938
|
+
${stages.map((s, i) => `${i + 1}. ${describeStage(s)}`).join("\n ")}`;
|
|
1939
|
+
if (!await confirmPhase(stageSummary, opts)) {
|
|
1940
|
+
throw new Error("pizx/\u039B: Execution cancelled by user.");
|
|
1941
|
+
}
|
|
1809
1942
|
const stageResults = [];
|
|
1810
1943
|
let currentInput = "";
|
|
1811
1944
|
for (let i = 0; i < stages.length; i++) {
|
|
1812
1945
|
const stage = stages[i];
|
|
1946
|
+
const stageLabel = describeStage(stage);
|
|
1813
1947
|
const customPrompt = opts.stagePrompts?.[i];
|
|
1814
1948
|
if (!opts.quiet)
|
|
1815
|
-
process.stderr.write(` \u2192 Stage ${i + 1}/${stages.length}: ${
|
|
1949
|
+
process.stderr.write(` \u2192 Stage ${i + 1}/${stages.length}: ${stageLabel.slice(0, 50)}...
|
|
1816
1950
|
`);
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1951
|
+
let output;
|
|
1952
|
+
if (typeof stage === "function") {
|
|
1953
|
+
output = await stage(currentInput);
|
|
1954
|
+
} else {
|
|
1955
|
+
const prompt = customPrompt ?? generateStagePrompt(stage, currentInput, i === 0);
|
|
1956
|
+
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.`;
|
|
1957
|
+
output = await ask(prompt, {
|
|
1958
|
+
...opts,
|
|
1959
|
+
model: workerModel,
|
|
1960
|
+
system: mergeSystem(opts.system, systemMessage)
|
|
1961
|
+
});
|
|
1962
|
+
}
|
|
1963
|
+
stageResults.push(new PipelineStageResult(stageLabel, output, i));
|
|
1826
1964
|
currentInput = output;
|
|
1827
1965
|
}
|
|
1828
1966
|
const t1 = Date.now();
|
|
1829
1967
|
const finalOutput = currentInput;
|
|
1968
|
+
if (!opts.quiet && opts.qualityCheck) process.stderr.write(" \u2192 Quality review...\n");
|
|
1969
|
+
const qualityReview = await runQualityReview(template, finalOutput, opts);
|
|
1830
1970
|
const summary = stageResults.map(
|
|
1831
1971
|
(sr) => `Stage ${sr.index + 1} (${sr.stage}):
|
|
1832
1972
|
${sr.output.slice(0, 200)}${sr.output.length > 200 ? "..." : ""}`
|
|
1833
1973
|
).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;
|
|
1974
|
+
return new PipelineOutput(summary, finalOutput, stageResults, t0, t1, qualityReview);
|
|
1856
1975
|
}
|
|
1857
|
-
var \u039B =
|
|
1976
|
+
var \u039B = createPatternTag(defaults11, execute11);
|
|
1858
1977
|
|
|
1859
1978
|
// src/patterns/ralph.ts
|
|
1860
1979
|
import { createAgentSession } from "@earendil-works/pi-coding-agent";
|
|
@@ -1889,17 +2008,17 @@ async function executeWithTools(goal, opts) {
|
|
|
1889
2008
|
});
|
|
1890
2009
|
try {
|
|
1891
2010
|
await session.sendUserMessage(goal);
|
|
1892
|
-
const
|
|
1893
|
-
for (let i =
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
2011
|
+
const messages = session.messages;
|
|
2012
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
2013
|
+
const msg = messages[i];
|
|
2014
|
+
if (msg?.role !== "assistant") continue;
|
|
2015
|
+
const c = "content" in msg ? msg.content : void 0;
|
|
2016
|
+
if (typeof c === "string") return c.trim();
|
|
2017
|
+
if (Array.isArray(c)) {
|
|
2018
|
+
const texts = c.filter(
|
|
2019
|
+
(x) => x.type === "text" && typeof x.text === "string"
|
|
2020
|
+
).map((x) => x.text);
|
|
2021
|
+
if (texts.length > 0) return texts.join("").trim();
|
|
1903
2022
|
}
|
|
1904
2023
|
}
|
|
1905
2024
|
return "(no assistant response)";
|
|
@@ -1934,10 +2053,9 @@ async function execute12(pieces, args, opts) {
|
|
|
1934
2053
|
}
|
|
1935
2054
|
if (!opts.quiet) process.stderr.write(" \u2192 Analyzing...\n");
|
|
1936
2055
|
const analysis = await ask(currentGoal, {
|
|
2056
|
+
...opts,
|
|
1937
2057
|
model: plannerModel,
|
|
1938
|
-
|
|
1939
|
-
thinkingLevel: opts.thinkingLevel,
|
|
1940
|
-
system: ANALYSIS_SYSTEM2
|
|
2058
|
+
system: mergeSystem(opts.system, ANALYSIS_SYSTEM2)
|
|
1941
2059
|
});
|
|
1942
2060
|
if (!opts.quiet) process.stderr.write(" \u2192 Planning...\n");
|
|
1943
2061
|
const plan = await ask(
|
|
@@ -1946,12 +2064,7 @@ async function execute12(pieces, args, opts) {
|
|
|
1946
2064
|
Analysis: ${analysis}
|
|
1947
2065
|
|
|
1948
2066
|
Generate an implementation plan.`,
|
|
1949
|
-
{
|
|
1950
|
-
model: plannerModel,
|
|
1951
|
-
maxTokens: opts.maxTokens,
|
|
1952
|
-
thinkingLevel: opts.thinkingLevel,
|
|
1953
|
-
system: PLAN_SYSTEM2
|
|
1954
|
-
}
|
|
2067
|
+
{ ...opts, model: plannerModel, system: mergeSystem(opts.system, PLAN_SYSTEM2) }
|
|
1955
2068
|
);
|
|
1956
2069
|
if (!opts.quiet) process.stderr.write(" \u2192 Executing...\n");
|
|
1957
2070
|
const result = opts.useTools ? await executeWithTools(`Implement this plan:
|
|
@@ -1964,9 +2077,8 @@ Goal: ${currentGoal}`, {
|
|
|
1964
2077
|
${plan}
|
|
1965
2078
|
|
|
1966
2079
|
Goal: ${currentGoal}`, {
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
thinkingLevel: opts.thinkingLevel
|
|
2080
|
+
...opts,
|
|
2081
|
+
model: workerModel
|
|
1970
2082
|
});
|
|
1971
2083
|
if (!opts.quiet) process.stderr.write(" \u2192 Reviewing...\n");
|
|
1972
2084
|
const review = await ask(`Plan:
|
|
@@ -1976,10 +2088,11 @@ Result:
|
|
|
1976
2088
|
${result}
|
|
1977
2089
|
|
|
1978
2090
|
Review the implementation.`, {
|
|
2091
|
+
...opts,
|
|
1979
2092
|
model: plannerModel,
|
|
1980
2093
|
maxTokens: 1024,
|
|
1981
2094
|
thinkingLevel: "high",
|
|
1982
|
-
system: REVIEW_SYSTEM
|
|
2095
|
+
system: mergeSystem(opts.system, REVIEW_SYSTEM)
|
|
1983
2096
|
});
|
|
1984
2097
|
const shouldContinue = review.includes("ITERATE") && !review.includes("DONE");
|
|
1985
2098
|
iterations.push({
|
|
@@ -2015,28 +2128,7 @@ Original goal: ${goal}`;
|
|
|
2015
2128
|
t1
|
|
2016
2129
|
);
|
|
2017
2130
|
}
|
|
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();
|
|
2131
|
+
var \u03A1 = createPatternTag(defaults12, execute12);
|
|
2040
2132
|
|
|
2041
2133
|
// src/patterns/subagent.ts
|
|
2042
2134
|
var defaults13 = {
|
|
@@ -2056,13 +2148,15 @@ var SubagentResult = class {
|
|
|
2056
2148
|
success;
|
|
2057
2149
|
};
|
|
2058
2150
|
var SubagentOutput = class extends PatternOutput {
|
|
2059
|
-
constructor(text, synthesis, subResults, startTime, endTime) {
|
|
2151
|
+
constructor(text, synthesis, subResults, startTime, endTime, qualityReview) {
|
|
2060
2152
|
super(text, startTime, endTime);
|
|
2061
2153
|
this.synthesis = synthesis;
|
|
2062
2154
|
this.subResults = subResults;
|
|
2155
|
+
this.qualityReview = qualityReview;
|
|
2063
2156
|
}
|
|
2064
2157
|
synthesis;
|
|
2065
2158
|
subResults;
|
|
2159
|
+
qualityReview;
|
|
2066
2160
|
};
|
|
2067
2161
|
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
2162
|
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 +2169,11 @@ ${task}
|
|
|
2075
2169
|
|
|
2076
2170
|
Output a JSON array of strings.`,
|
|
2077
2171
|
{
|
|
2172
|
+
...opts,
|
|
2078
2173
|
model: opts.model,
|
|
2079
2174
|
maxTokens: 1024,
|
|
2080
2175
|
thinkingLevel: "medium",
|
|
2081
|
-
system: DECOMPOSE_SYSTEM
|
|
2176
|
+
system: mergeSystem(opts.system, DECOMPOSE_SYSTEM)
|
|
2082
2177
|
}
|
|
2083
2178
|
);
|
|
2084
2179
|
try {
|
|
@@ -2099,6 +2194,7 @@ var SUBAGENT_SYSTEM = `You are a domain specialist. Complete your assigned sub-t
|
|
|
2099
2194
|
async function execute13(pieces, args, opts) {
|
|
2100
2195
|
const task = build(pieces, args);
|
|
2101
2196
|
const t0 = Date.now();
|
|
2197
|
+
const phases = [];
|
|
2102
2198
|
const plannerModel = opts.plannerModel ?? opts.model;
|
|
2103
2199
|
const workerModel = opts.workerModel ?? opts.model;
|
|
2104
2200
|
if (!opts.quiet) {
|
|
@@ -2108,7 +2204,14 @@ async function execute13(pieces, args, opts) {
|
|
|
2108
2204
|
);
|
|
2109
2205
|
}
|
|
2110
2206
|
if (!opts.quiet) process.stderr.write(" \u2192 Decomposing task into sub-tasks...\n");
|
|
2207
|
+
const decomposeStart = Date.now();
|
|
2111
2208
|
const subTasks = await decomposeTask(task, { ...opts, model: plannerModel });
|
|
2209
|
+
phases.push({
|
|
2210
|
+
phase: "decompose",
|
|
2211
|
+
durationMs: Date.now() - decomposeStart,
|
|
2212
|
+
description: `Decomposed into ${subTasks.length} sub-task(s)`,
|
|
2213
|
+
modelUsed: plannerModel
|
|
2214
|
+
});
|
|
2112
2215
|
if (!opts.quiet) {
|
|
2113
2216
|
process.stderr.write(` \u2192 ${subTasks.length} sub-task(s) identified:
|
|
2114
2217
|
`);
|
|
@@ -2118,27 +2221,37 @@ async function execute13(pieces, args, opts) {
|
|
|
2118
2221
|
`);
|
|
2119
2222
|
}
|
|
2120
2223
|
}
|
|
2224
|
+
const subTaskSummary = `Execute ${subTasks.length} sub-task(s)?
|
|
2225
|
+
${subTasks.map((st, i) => `${i + 1}. ${st.slice(0, 80)}`).join("\n ")}`;
|
|
2226
|
+
if (!await confirmPhase(subTaskSummary, opts)) {
|
|
2227
|
+
throw new Error("pizx/\u03A3: Execution cancelled by user.");
|
|
2228
|
+
}
|
|
2121
2229
|
const subResults = [];
|
|
2122
2230
|
const concurrency = opts.concurrency ?? 4;
|
|
2231
|
+
const execStart = Date.now();
|
|
2123
2232
|
for (let i = 0; i < subTasks.length; i += concurrency) {
|
|
2124
2233
|
const batch = subTasks.slice(i, i + concurrency);
|
|
2125
2234
|
const batchResults = await Promise.allSettled(
|
|
2126
2235
|
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))
|
|
2236
|
+
(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
2237
|
)
|
|
2134
2238
|
);
|
|
2135
2239
|
batchResults.forEach((r) => {
|
|
2136
2240
|
if (r.status === "fulfilled") subResults.push(r.value);
|
|
2137
2241
|
});
|
|
2138
2242
|
}
|
|
2243
|
+
const succeeded = subResults.filter((r) => r.success).length;
|
|
2244
|
+
phases.push({
|
|
2245
|
+
phase: "execute",
|
|
2246
|
+
durationMs: Date.now() - execStart,
|
|
2247
|
+
description: `Executed ${subResults.length} sub-task(s), ${succeeded} succeeded`,
|
|
2248
|
+
modelUsed: workerModel,
|
|
2249
|
+
callCount: subResults.length
|
|
2250
|
+
});
|
|
2139
2251
|
if (!opts.quiet) process.stderr.write(" \u2192 Synthesizing results...\n");
|
|
2140
2252
|
const subResultsText = subResults.map((sr, i) => `Sub-task ${i + 1}: ${sr.subTask}
|
|
2141
2253
|
Result: ${sr.text}`).join("\n\n");
|
|
2254
|
+
const synthStart = Date.now();
|
|
2142
2255
|
const synthesis = await ask(
|
|
2143
2256
|
`Original task:
|
|
2144
2257
|
${task}
|
|
@@ -2147,38 +2260,31 @@ Sub-task results:
|
|
|
2147
2260
|
${subResultsText}
|
|
2148
2261
|
|
|
2149
2262
|
Synthesize a comprehensive answer.`,
|
|
2150
|
-
{
|
|
2151
|
-
model: plannerModel,
|
|
2152
|
-
maxTokens: opts.maxTokens,
|
|
2153
|
-
thinkingLevel: opts.thinkingLevel,
|
|
2154
|
-
system: SYNTHESIS_SYSTEM5
|
|
2155
|
-
}
|
|
2263
|
+
{ ...opts, model: plannerModel, system: mergeSystem(opts.system, SYNTHESIS_SYSTEM5) }
|
|
2156
2264
|
);
|
|
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
|
|
2265
|
+
phases.push({
|
|
2266
|
+
phase: "synthesize",
|
|
2267
|
+
durationMs: Date.now() - synthStart,
|
|
2268
|
+
description: "Synthesized sub-agent results",
|
|
2269
|
+
modelUsed: plannerModel
|
|
2178
2270
|
});
|
|
2179
|
-
|
|
2271
|
+
if (!opts.quiet && opts.qualityCheck) process.stderr.write(" \u2192 Quality review...\n");
|
|
2272
|
+
const qStart = Date.now();
|
|
2273
|
+
const qualityReview = await runQualityReview(task, synthesis, opts);
|
|
2274
|
+
if (qualityReview) {
|
|
2275
|
+
phases.push({
|
|
2276
|
+
phase: "quality-review",
|
|
2277
|
+
durationMs: Date.now() - qStart,
|
|
2278
|
+
description: `Score: ${qualityReview.score.toFixed(2)}`,
|
|
2279
|
+
modelUsed: plannerModel
|
|
2280
|
+
});
|
|
2281
|
+
}
|
|
2282
|
+
const t1 = Date.now();
|
|
2283
|
+
const output = new SubagentOutput(synthesis, synthesis, subResults, t0, t1, qualityReview);
|
|
2284
|
+
output.phaseLog = phases;
|
|
2285
|
+
return output;
|
|
2180
2286
|
}
|
|
2181
|
-
var \u03A3 =
|
|
2287
|
+
var \u03A3 = createPatternTag(defaults13, execute13);
|
|
2182
2288
|
|
|
2183
2289
|
// src/patterns/tau.ts
|
|
2184
2290
|
var defaults14 = {
|
|
@@ -2202,15 +2308,17 @@ var ToolMediatedEntry = class {
|
|
|
2202
2308
|
content;
|
|
2203
2309
|
};
|
|
2204
2310
|
var TauOutput = class extends PatternOutput {
|
|
2205
|
-
constructor(text, entries, finalState, synthesis, startTime, endTime) {
|
|
2311
|
+
constructor(text, entries, finalState, synthesis, startTime, endTime, qualityReview) {
|
|
2206
2312
|
super(text, startTime, endTime);
|
|
2207
2313
|
this.entries = entries;
|
|
2208
2314
|
this.finalState = finalState;
|
|
2209
2315
|
this.synthesis = synthesis;
|
|
2316
|
+
this.qualityReview = qualityReview;
|
|
2210
2317
|
}
|
|
2211
2318
|
entries;
|
|
2212
2319
|
finalState;
|
|
2213
2320
|
synthesis;
|
|
2321
|
+
qualityReview;
|
|
2214
2322
|
};
|
|
2215
2323
|
var SCHEMA_SYSTEM = `You are a coordination architect. Given a task, design a shared structured context for agent collaboration.
|
|
2216
2324
|
|
|
@@ -2265,6 +2373,7 @@ async function defineSchema(task, opts) {
|
|
|
2265
2373
|
const response = await ask(`Task: ${task}
|
|
2266
2374
|
|
|
2267
2375
|
${prompt}`, {
|
|
2376
|
+
...opts,
|
|
2268
2377
|
model: opts.plannerModel ?? opts.model,
|
|
2269
2378
|
maxTokens: 1024,
|
|
2270
2379
|
thinkingLevel: "high"
|
|
@@ -2317,10 +2426,9 @@ async function executeRound(roles, assignments, store, round, opts) {
|
|
|
2317
2426
|
const systemPrompt = isWrite ? WRITE_SYSTEM(role, keysStr).replace("{store}", storeText) : UPDATE_SYSTEM(role, keysStr).replace("{store}", storeText);
|
|
2318
2427
|
const task = isWrite ? `Write your initial findings to your assigned keys: ${keysStr}` : `Review the shared context and update your entries for keys: ${keysStr}`;
|
|
2319
2428
|
const response = await ask(task, {
|
|
2429
|
+
...opts,
|
|
2320
2430
|
model: workerModel,
|
|
2321
|
-
|
|
2322
|
-
thinkingLevel: opts.thinkingLevel,
|
|
2323
|
-
system: systemPrompt
|
|
2431
|
+
system: mergeSystem(opts.system, systemPrompt)
|
|
2324
2432
|
});
|
|
2325
2433
|
return { role, response };
|
|
2326
2434
|
})
|
|
@@ -2360,10 +2468,10 @@ ${storeText}
|
|
|
2360
2468
|
|
|
2361
2469
|
Consolidate into a comprehensive, well-structured synthesis.`,
|
|
2362
2470
|
{
|
|
2471
|
+
...opts,
|
|
2363
2472
|
model: opts.plannerModel ?? opts.model,
|
|
2364
|
-
maxTokens: opts.maxTokens,
|
|
2365
2473
|
thinkingLevel: "high",
|
|
2366
|
-
system: CONSOLIDATE_SYSTEM
|
|
2474
|
+
system: mergeSystem(opts.system, CONSOLIDATE_SYSTEM)
|
|
2367
2475
|
}
|
|
2368
2476
|
);
|
|
2369
2477
|
}
|
|
@@ -2408,6 +2516,8 @@ async function execute14(pieces, args, opts) {
|
|
|
2408
2516
|
}
|
|
2409
2517
|
if (!opts.quiet) process.stderr.write(" \u2192 Consolidating store...\n");
|
|
2410
2518
|
const synthesis = await consolidateStore(task, store, { ...opts, plannerModel });
|
|
2519
|
+
if (!opts.quiet && opts.qualityCheck) process.stderr.write(" \u2192 Quality review...\n");
|
|
2520
|
+
const qualityReview = await runQualityReview(task, synthesis, opts);
|
|
2411
2521
|
const t1 = Date.now();
|
|
2412
2522
|
const summary = [
|
|
2413
2523
|
`Schema keys: ${keys.join(", ")}`,
|
|
@@ -2416,30 +2526,9 @@ async function execute14(pieces, args, opts) {
|
|
|
2416
2526
|
`Entries: ${allEntries.length}`,
|
|
2417
2527
|
`Synthesis: ${synthesis}`
|
|
2418
2528
|
].join("\n\n");
|
|
2419
|
-
return new TauOutput(summary, allEntries, store, synthesis, t0, t1);
|
|
2420
|
-
}
|
|
2421
|
-
function makeTau(opts = {}) {
|
|
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;
|
|
2529
|
+
return new TauOutput(summary, allEntries, store, synthesis, t0, t1, qualityReview);
|
|
2441
2530
|
}
|
|
2442
|
-
var \u03A4 =
|
|
2531
|
+
var \u03A4 = createPatternTag(defaults14, execute14);
|
|
2443
2532
|
|
|
2444
2533
|
// src/patterns/thread.ts
|
|
2445
2534
|
var defaults15 = {
|
|
@@ -2448,27 +2537,6 @@ var defaults15 = {
|
|
|
2448
2537
|
agents: 3,
|
|
2449
2538
|
turns: 3
|
|
2450
2539
|
};
|
|
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
2540
|
var ThreadMessage = class {
|
|
2473
2541
|
constructor(role, turn, content) {
|
|
2474
2542
|
this.role = role;
|
|
@@ -2480,13 +2548,15 @@ var ThreadMessage = class {
|
|
|
2480
2548
|
content;
|
|
2481
2549
|
};
|
|
2482
2550
|
var ThreadOutput = class extends PatternOutput {
|
|
2483
|
-
constructor(text, conclusion, messages, startTime, endTime) {
|
|
2551
|
+
constructor(text, conclusion, messages, startTime, endTime, qualityReview) {
|
|
2484
2552
|
super(text, startTime, endTime);
|
|
2485
2553
|
this.conclusion = conclusion;
|
|
2486
2554
|
this.messages = messages;
|
|
2555
|
+
this.qualityReview = qualityReview;
|
|
2487
2556
|
}
|
|
2488
2557
|
conclusion;
|
|
2489
2558
|
messages;
|
|
2559
|
+
qualityReview;
|
|
2490
2560
|
};
|
|
2491
2561
|
var THREAD_PROMPT = `You are an agent with the role: {role}.
|
|
2492
2562
|
Engage in a multi-agent conversation about the topic.
|
|
@@ -2508,7 +2578,7 @@ async function execute15(pieces, args, opts) {
|
|
|
2508
2578
|
const t0 = Date.now();
|
|
2509
2579
|
const agentCount = opts.agents ?? 3;
|
|
2510
2580
|
const maxTurns = opts.turns ?? 3;
|
|
2511
|
-
const roles = opts.roles ??
|
|
2581
|
+
const roles = opts.roles ?? THREAD_ROLE_SETS[agentCount] ?? THREAD_ROLE_SETS[3] ?? [];
|
|
2512
2582
|
const plannerModel = opts.plannerModel ?? opts.model;
|
|
2513
2583
|
const workerModel = opts.workerModel ?? opts.model;
|
|
2514
2584
|
if (!opts.quiet) {
|
|
@@ -2526,11 +2596,7 @@ async function execute15(pieces, args, opts) {
|
|
|
2526
2596
|
for (let a = 0; a < roles.length; a++) {
|
|
2527
2597
|
const role = roles[a] ?? `Agent ${a + 1}`;
|
|
2528
2598
|
const prompt = buildThreadPrompt(role, thread);
|
|
2529
|
-
const response = await ask(prompt, {
|
|
2530
|
-
model: workerModel,
|
|
2531
|
-
maxTokens: opts.maxTokens,
|
|
2532
|
-
thinkingLevel: opts.thinkingLevel
|
|
2533
|
-
});
|
|
2599
|
+
const response = await ask(prompt, { ...opts, model: workerModel });
|
|
2534
2600
|
messages.push(new ThreadMessage(role, turn, response));
|
|
2535
2601
|
thread += `
|
|
2536
2602
|
[${role}] (Turn ${turn}): ${response}
|
|
@@ -2546,46 +2612,24 @@ ${thread}
|
|
|
2546
2612
|
|
|
2547
2613
|
Synthesize a clear, actionable conclusion.`,
|
|
2548
2614
|
{
|
|
2615
|
+
...opts,
|
|
2549
2616
|
model: plannerModel,
|
|
2550
|
-
maxTokens: opts.maxTokens,
|
|
2551
2617
|
thinkingLevel: "high",
|
|
2552
|
-
system: SYNTHESIS_SYSTEM6
|
|
2618
|
+
system: mergeSystem(opts.system, SYNTHESIS_SYSTEM6)
|
|
2553
2619
|
}
|
|
2554
2620
|
);
|
|
2621
|
+
if (!opts.quiet && opts.qualityCheck) process.stderr.write(" \u2192 Quality review...\n");
|
|
2622
|
+
const qualityReview = await runQualityReview(topic, conclusion, opts);
|
|
2555
2623
|
const t1 = Date.now();
|
|
2556
2624
|
const summary = messages.map(
|
|
2557
2625
|
(m) => `[${m.role}] Turn ${m.turn}: ${m.content.slice(0, 150)}${m.content.length > 150 ? "..." : ""}`
|
|
2558
2626
|
).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;
|
|
2627
|
+
return new ThreadOutput(summary, conclusion, messages, t0, t1, qualityReview);
|
|
2581
2628
|
}
|
|
2582
|
-
var \u0398 =
|
|
2629
|
+
var \u0398 = createPatternTag(defaults15, execute15);
|
|
2583
2630
|
|
|
2584
2631
|
// src/pi.ts
|
|
2585
2632
|
import {
|
|
2586
|
-
getEnvApiKey as getEnvApiKey2,
|
|
2587
|
-
getModels as getModels2,
|
|
2588
|
-
getProviders as getProviders2,
|
|
2589
2633
|
streamSimple
|
|
2590
2634
|
} from "@earendil-works/pi-ai";
|
|
2591
2635
|
|
|
@@ -2603,10 +2647,28 @@ var PiOutput = class {
|
|
|
2603
2647
|
events;
|
|
2604
2648
|
startTime;
|
|
2605
2649
|
endTime;
|
|
2650
|
+
/** Trace entry for this single LLM call. Populated by the π tag. */
|
|
2651
|
+
trace = [];
|
|
2606
2652
|
/** Duration in milliseconds */
|
|
2607
2653
|
get duration() {
|
|
2608
2654
|
return this.endTime - this.startTime;
|
|
2609
2655
|
}
|
|
2656
|
+
/** Total input tokens (convenience accessor) */
|
|
2657
|
+
get inputTokens() {
|
|
2658
|
+
return this.trace[0]?.inputTokens ?? 0;
|
|
2659
|
+
}
|
|
2660
|
+
/** Total output tokens (convenience accessor) */
|
|
2661
|
+
get outputTokens() {
|
|
2662
|
+
return this.trace[0]?.outputTokens ?? 0;
|
|
2663
|
+
}
|
|
2664
|
+
/** Total tokens (convenience accessor) */
|
|
2665
|
+
get totalTokens() {
|
|
2666
|
+
return this.trace[0]?.totalTokens ?? 0;
|
|
2667
|
+
}
|
|
2668
|
+
/** Total cost in USD (convenience accessor) */
|
|
2669
|
+
get totalCost() {
|
|
2670
|
+
return this.trace[0]?.cost ?? 0;
|
|
2671
|
+
}
|
|
2610
2672
|
toString() {
|
|
2611
2673
|
return this.text;
|
|
2612
2674
|
}
|
|
@@ -2632,90 +2694,16 @@ var defaults16 = {
|
|
|
2632
2694
|
quiet: false,
|
|
2633
2695
|
maxTokens: 4096
|
|
2634
2696
|
};
|
|
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
2697
|
function makeContext(pieces, args, opts) {
|
|
2698
|
+
const systemParts = [];
|
|
2699
|
+
if (opts.system) systemParts.push(opts.system);
|
|
2700
|
+
if (opts.appendSystemPrompt) systemParts.push(opts.appendSystemPrompt);
|
|
2713
2701
|
return {
|
|
2714
|
-
systemPrompt:
|
|
2702
|
+
systemPrompt: systemParts.length > 0 ? systemParts.join("\n\n") : void 0,
|
|
2715
2703
|
messages: [
|
|
2716
2704
|
{
|
|
2717
2705
|
role: "user",
|
|
2718
|
-
content:
|
|
2706
|
+
content: build(pieces, args),
|
|
2719
2707
|
timestamp: Date.now()
|
|
2720
2708
|
}
|
|
2721
2709
|
]
|
|
@@ -2724,25 +2712,52 @@ function makeContext(pieces, args, opts) {
|
|
|
2724
2712
|
function makeOpts(opts) {
|
|
2725
2713
|
return {
|
|
2726
2714
|
maxTokens: opts.maxTokens,
|
|
2727
|
-
reasoning: opts.thinkingLevel
|
|
2715
|
+
reasoning: opts.thinkingLevel,
|
|
2716
|
+
thinkingBudgets: opts.thinkingBudgets,
|
|
2717
|
+
timeoutMs: opts.timeoutMs,
|
|
2718
|
+
maxRetries: opts.maxRetries
|
|
2728
2719
|
};
|
|
2729
2720
|
}
|
|
2730
2721
|
async function run(pieces, args, opts) {
|
|
2731
|
-
const model =
|
|
2722
|
+
const model = pickModel(opts.model);
|
|
2732
2723
|
if (!model) throw new Error("pizx/\u03C0: No AI models configured. Run `pi auth login` first.");
|
|
2733
2724
|
const t0 = Date.now();
|
|
2734
2725
|
let text = "";
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
if (
|
|
2726
|
+
let traceEntry;
|
|
2727
|
+
try {
|
|
2728
|
+
for await (const ev of streamSimple(model, makeContext(pieces, args, opts), makeOpts(opts))) {
|
|
2729
|
+
if (ev.type === "text_delta") {
|
|
2730
|
+
text += ev.delta;
|
|
2731
|
+
if (!opts.quiet) process.stdout.write(ev.delta);
|
|
2732
|
+
} else if (ev.type === "done") {
|
|
2733
|
+
const msg = ev.message;
|
|
2734
|
+
if (msg?.usage) {
|
|
2735
|
+
traceEntry = {
|
|
2736
|
+
call: 1,
|
|
2737
|
+
modelId: model.id,
|
|
2738
|
+
promptPreview: build(pieces, args).slice(0, 200),
|
|
2739
|
+
outputPreview: text.slice(0, 200),
|
|
2740
|
+
inputTokens: msg.usage.input,
|
|
2741
|
+
outputTokens: msg.usage.output,
|
|
2742
|
+
cacheReadTokens: msg.usage.cacheRead,
|
|
2743
|
+
cacheWriteTokens: msg.usage.cacheWrite,
|
|
2744
|
+
totalTokens: msg.usage.totalTokens,
|
|
2745
|
+
cost: msg.usage.cost.total,
|
|
2746
|
+
durationMs: Date.now() - t0
|
|
2747
|
+
};
|
|
2748
|
+
}
|
|
2749
|
+
}
|
|
2739
2750
|
}
|
|
2751
|
+
} catch (err) {
|
|
2752
|
+
throw new Error(`pizx/\u03C0: AI generation failed: ${getErrorMessage(err)}`);
|
|
2740
2753
|
}
|
|
2741
2754
|
if (!opts.quiet && text) process.stdout.write("\n");
|
|
2742
|
-
|
|
2755
|
+
const output = new PiOutput(text.trim(), model.id, [], t0, Date.now());
|
|
2756
|
+
if (traceEntry) output.trace = [traceEntry];
|
|
2757
|
+
return output;
|
|
2743
2758
|
}
|
|
2744
2759
|
async function* runStream(pieces, args, opts) {
|
|
2745
|
-
const model =
|
|
2760
|
+
const model = pickModel(opts.model);
|
|
2746
2761
|
if (!model) throw new Error("pizx/\u03C0: No AI models configured");
|
|
2747
2762
|
for await (const ev of streamSimple(model, makeContext(pieces, args, opts), makeOpts(opts))) {
|
|
2748
2763
|
if (ev.type === "text_delta") yield ev.delta;
|
|
@@ -2788,7 +2803,10 @@ function configurePi(opts) {
|
|
|
2788
2803
|
}
|
|
2789
2804
|
|
|
2790
2805
|
// src/pi-agent.ts
|
|
2791
|
-
import {
|
|
2806
|
+
import {
|
|
2807
|
+
createAgentSession as createAgentSession2,
|
|
2808
|
+
DefaultResourceLoader
|
|
2809
|
+
} from "@earendil-works/pi-coding-agent";
|
|
2792
2810
|
var _agentDefaults = {
|
|
2793
2811
|
quiet: false,
|
|
2794
2812
|
maxTurns: 10
|
|
@@ -2820,24 +2838,49 @@ var AgentOutput = class {
|
|
|
2820
2838
|
var AgentPromise = class extends Promise {
|
|
2821
2839
|
};
|
|
2822
2840
|
var _sharedSession = null;
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
const
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2841
|
+
function createLoader(opts) {
|
|
2842
|
+
const hasSystem = opts.system !== void 0;
|
|
2843
|
+
const hasAppend = opts.appendSystemPrompt !== void 0;
|
|
2844
|
+
const hasSkills = opts.skills && opts.skills.length > 0;
|
|
2845
|
+
if (!hasSystem && !hasAppend && !hasSkills) return void 0;
|
|
2846
|
+
return new DefaultResourceLoader({
|
|
2847
|
+
cwd: opts.cwd ?? process.cwd(),
|
|
2848
|
+
agentDir: "",
|
|
2849
|
+
systemPrompt: opts.system,
|
|
2850
|
+
appendSystemPrompt: opts.appendSystemPrompt ? [opts.appendSystemPrompt] : void 0
|
|
2830
2851
|
});
|
|
2831
|
-
_sharedSession = result.session;
|
|
2832
|
-
return _sharedSession;
|
|
2833
2852
|
}
|
|
2834
|
-
function
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
if (
|
|
2853
|
+
async function getSession(opts) {
|
|
2854
|
+
if (_sharedSession && !opts.model) return _sharedSession;
|
|
2855
|
+
try {
|
|
2856
|
+
const loader = createLoader(opts);
|
|
2857
|
+
if (opts.skills && opts.skills.length > 0 && loader) {
|
|
2858
|
+
const skillMap = await loadSkillContents(opts.skills);
|
|
2859
|
+
const skillPaths = [];
|
|
2860
|
+
for (const [name] of skillMap) {
|
|
2861
|
+
for (const base of SKILL_PATHS) {
|
|
2862
|
+
skillPaths.push({
|
|
2863
|
+
path: `${base}/${name}`,
|
|
2864
|
+
metadata: { source: "pizx", scope: "project", origin: "top-level" }
|
|
2865
|
+
});
|
|
2866
|
+
}
|
|
2867
|
+
}
|
|
2868
|
+
if (skillPaths.length > 0) {
|
|
2869
|
+
loader.extendResources({ skillPaths });
|
|
2870
|
+
}
|
|
2871
|
+
}
|
|
2872
|
+
const result = await createAgentSession2({
|
|
2873
|
+
cwd: opts.cwd,
|
|
2874
|
+
thinkingLevel: opts.thinkingLevel,
|
|
2875
|
+
tools: opts.tools,
|
|
2876
|
+
excludeTools: opts.excludeTools,
|
|
2877
|
+
resourceLoader: loader
|
|
2878
|
+
});
|
|
2879
|
+
_sharedSession = result.session;
|
|
2880
|
+
return _sharedSession;
|
|
2881
|
+
} catch (err) {
|
|
2882
|
+
throw new Error(`pizx/\u03A0: Failed to create agent session: ${getErrorMessage(err)}`);
|
|
2839
2883
|
}
|
|
2840
|
-
return s.trim();
|
|
2841
2884
|
}
|
|
2842
2885
|
function getMessageText(msg) {
|
|
2843
2886
|
const content = msg.content;
|
|
@@ -2859,7 +2902,7 @@ function getLastAssistantText(session) {
|
|
|
2859
2902
|
return "";
|
|
2860
2903
|
}
|
|
2861
2904
|
async function execute16(pieces, args, opts) {
|
|
2862
|
-
const prompt =
|
|
2905
|
+
const prompt = build(pieces, args);
|
|
2863
2906
|
const session = await getSession(opts);
|
|
2864
2907
|
const t0 = Date.now();
|
|
2865
2908
|
if (!opts.quiet) {
|
|
@@ -2870,15 +2913,12 @@ async function execute16(pieces, args, opts) {
|
|
|
2870
2913
|
await session.sendUserMessage(prompt);
|
|
2871
2914
|
const t1 = Date.now();
|
|
2872
2915
|
const text = getLastAssistantText(session);
|
|
2873
|
-
const turnCount = session.messages.filter(
|
|
2874
|
-
(m) => m.role === "assistant"
|
|
2875
|
-
).length;
|
|
2916
|
+
const turnCount = session.messages.filter((m) => m.role === "assistant").length;
|
|
2876
2917
|
return new AgentOutput(text || "(no assistant response)", turnCount, t0, t1);
|
|
2877
2918
|
} catch (err) {
|
|
2878
2919
|
const t1 = Date.now();
|
|
2879
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
2880
2920
|
console.error("\u03A0 error:", err);
|
|
2881
|
-
return new AgentOutput(`\u03A0 error: ${
|
|
2921
|
+
return new AgentOutput(`\u03A0 error: ${getErrorMessage(err)}`, 0, t0, t1);
|
|
2882
2922
|
}
|
|
2883
2923
|
}
|
|
2884
2924
|
function makeAgent(opts = {}) {
|
|
@@ -2938,6 +2978,7 @@ export {
|
|
|
2938
2978
|
PipelineOutput,
|
|
2939
2979
|
PipelineStageResult,
|
|
2940
2980
|
RalphOutput,
|
|
2981
|
+
SKILL_PATHS,
|
|
2941
2982
|
SubagentOutput,
|
|
2942
2983
|
SubagentResult,
|
|
2943
2984
|
ThreadMessage,
|
|
@@ -2945,6 +2986,9 @@ export {
|
|
|
2945
2986
|
closeAgent,
|
|
2946
2987
|
configureAgent,
|
|
2947
2988
|
configurePi,
|
|
2989
|
+
createPatternTag,
|
|
2990
|
+
loadSkillContent,
|
|
2991
|
+
loadSkillContents,
|
|
2948
2992
|
\u0391,
|
|
2949
2993
|
\u0392,
|
|
2950
2994
|
\u0393,
|