@topce/pizx 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -11,6 +11,11 @@ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:f
11
11
  import { homedir as homedir2 } from "node:os";
12
12
  import { join as join2 } from "node:path";
13
13
 
14
+ // src/utils.ts
15
+ function getErrorMessage(err) {
16
+ return err instanceof Error ? err.message : String(err);
17
+ }
18
+
14
19
  // src/load-pi-settings.ts
15
20
  import { existsSync, readFileSync } from "node:fs";
16
21
  import { homedir } from "node:os";
@@ -88,46 +93,21 @@ function loadPiAuth() {
88
93
  }
89
94
  }
90
95
  } catch (err) {
91
- console.warn(`pizx: failed to parse ${path}: ${err instanceof Error ? err.message : err}`);
96
+ console.warn(`pizx: failed to parse ${path}: ${getErrorMessage(err)}`);
92
97
  }
93
98
  }
94
99
  }
95
100
 
96
101
  // src/patterns/types.ts
97
- import { completeSimple, getEnvApiKey, getModels, getProviders } from "@earendil-works/pi-ai";
98
- var PatternOutput = class {
99
- constructor(text, startTime = Date.now(), endTime = Date.now()) {
100
- this.text = text;
101
- this.startTime = startTime;
102
- this.endTime = endTime;
103
- }
104
- text;
105
- startTime;
106
- endTime;
107
- /** Duration in milliseconds */
108
- get duration() {
109
- return this.endTime - this.startTime;
110
- }
111
- toString() {
112
- return this.text;
113
- }
114
- valueOf() {
115
- return this.text;
116
- }
117
- [Symbol.toPrimitive]() {
118
- return this.text;
119
- }
120
- };
121
- var PatternPromise = class extends Promise {
122
- };
123
- function build(pieces, args) {
124
- let s = "";
125
- for (let i = 0; i < pieces.length; i++) {
126
- s += pieces[i];
127
- if (i < args.length) s += String(args[i]);
128
- }
129
- return s.trim();
130
- }
102
+ import { createInterface } from "node:readline";
103
+ import { completeSimple } from "@earendil-works/pi-ai";
104
+
105
+ // src/model-picker.ts
106
+ import {
107
+ getEnvApiKey,
108
+ getModels,
109
+ getProviders
110
+ } from "@earendil-works/pi-ai";
131
111
  var _piSettings;
132
112
  function getPiDefaults() {
133
113
  if (_piSettings === void 0) {
@@ -171,7 +151,8 @@ function pickModel(preferred) {
171
151
  if (hit) return hit;
172
152
  }
173
153
  if (settings.defaultProvider) {
174
- const providerModels = getModels(settings.defaultProvider);
154
+ const provider = settings.defaultProvider;
155
+ const providerModels = getModels(provider);
175
156
  if (providerModels && providerModels.length > 0) {
176
157
  const configured = new Set(getConfiguredProviders());
177
158
  if (configured.has(settings.defaultProvider)) {
@@ -197,9 +178,138 @@ function pickModel(preferred) {
197
178
  }
198
179
  return models[0];
199
180
  }
181
+
182
+ // src/patterns/types.ts
183
+ var PatternOutput = class {
184
+ constructor(text, startTime = Date.now(), endTime = Date.now()) {
185
+ this.text = text;
186
+ this.startTime = startTime;
187
+ this.endTime = endTime;
188
+ }
189
+ text;
190
+ startTime;
191
+ endTime;
192
+ /** Execution trace: one entry per LLM call within this pattern run. Populated by createPatternTag. */
193
+ trace = [];
194
+ /** Structured phase log: key phases during execution, populated by each pattern. */
195
+ phaseLog = [];
196
+ /** Duration in milliseconds */
197
+ get duration() {
198
+ return this.endTime - this.startTime;
199
+ }
200
+ /** Total input tokens across all calls */
201
+ get inputTokens() {
202
+ return this.trace.reduce((s, t) => s + t.inputTokens, 0);
203
+ }
204
+ /** Total output tokens across all calls */
205
+ get outputTokens() {
206
+ return this.trace.reduce((s, t) => s + t.outputTokens, 0);
207
+ }
208
+ /** Total tokens (input + output) across all calls */
209
+ get totalTokens() {
210
+ return this.trace.reduce((s, t) => s + t.totalTokens, 0);
211
+ }
212
+ /** Total cost in USD across all calls */
213
+ get totalCost() {
214
+ return this.trace.reduce((s, t) => s + t.cost, 0);
215
+ }
216
+ /** Number of LLM calls made during this pattern execution */
217
+ get callCount() {
218
+ return this.trace.length;
219
+ }
220
+ toString() {
221
+ return this.text;
222
+ }
223
+ valueOf() {
224
+ return this.text;
225
+ }
226
+ [Symbol.toPrimitive]() {
227
+ return this.text;
228
+ }
229
+ };
230
+ var PatternPromise = class extends Promise {
231
+ };
232
+ var _trace = null;
233
+ function beginTrace() {
234
+ _trace = [];
235
+ }
236
+ function collectTrace() {
237
+ const t = _trace ?? [];
238
+ _trace = null;
239
+ return t;
240
+ }
241
+ function pushTrace(entry) {
242
+ if (_trace) _trace.push(entry);
243
+ }
244
+ function createPatternTag(defaults17, execute17) {
245
+ function make(opts = {}) {
246
+ const merged = { ...defaults17, ...opts };
247
+ const fn = ((pieces, ...args) => {
248
+ if (!Array.isArray(pieces)) {
249
+ return make({ ...merged, ...pieces });
250
+ }
251
+ beginTrace();
252
+ return new PatternPromise((resolve, reject) => {
253
+ execute17(pieces, args, merged).then(
254
+ (output) => {
255
+ output.trace = collectTrace();
256
+ resolve(output);
257
+ },
258
+ (err) => {
259
+ collectTrace();
260
+ reject(err);
261
+ }
262
+ );
263
+ });
264
+ });
265
+ let _quiet;
266
+ Object.defineProperty(fn, "quiet", {
267
+ get() {
268
+ if (!_quiet) _quiet = make({ ...merged, quiet: true });
269
+ return _quiet;
270
+ },
271
+ enumerable: true,
272
+ configurable: true
273
+ });
274
+ return fn;
275
+ }
276
+ return make();
277
+ }
278
+ function build(pieces, args) {
279
+ let s = "";
280
+ for (let i = 0; i < pieces.length; i++) {
281
+ s += pieces[i];
282
+ if (i < args.length) s += String(args[i]);
283
+ }
284
+ return s.trim();
285
+ }
286
+ function mergeSystem(userSystem, patternSystem) {
287
+ if (!userSystem) return patternSystem;
288
+ return `${userSystem}
289
+
290
+ ${patternSystem}`;
291
+ }
292
+ async function confirmPhase(description, opts) {
293
+ if (!opts.confirm) return true;
294
+ if (!opts.quiet) {
295
+ process.stderr.write(`
296
+ \u2500\u2500 Confirm \u2500\u2500
297
+ ${description}
298
+ Proceed? [Y/n] `);
299
+ }
300
+ const rl = createInterface({ input: process.stdin, output: process.stderr });
301
+ const answer = await new Promise((resolve) => {
302
+ rl.question("", (ans) => resolve(ans));
303
+ });
304
+ rl.close();
305
+ const trimmed = answer.trim().toLowerCase();
306
+ if (trimmed === "" || trimmed === "y" || trimmed === "yes") return true;
307
+ return false;
308
+ }
200
309
  async function ask(prompt, opts = {}) {
201
310
  const model = pickModel(opts.model);
202
311
  if (!model) throw new Error("pizx/patterns: No AI models configured. Run `pi auth login` first.");
312
+ const t0 = Date.now();
203
313
  const result = await completeSimple(
204
314
  model,
205
315
  {
@@ -208,12 +318,74 @@ async function ask(prompt, opts = {}) {
208
318
  },
209
319
  {
210
320
  maxTokens: opts.maxTokens ?? 4096,
211
- reasoning: opts.thinkingLevel ?? "medium"
321
+ reasoning: opts.thinkingLevel ?? "medium",
322
+ timeoutMs: opts.timeoutMs,
323
+ maxRetries: opts.maxRetries
212
324
  }
213
325
  );
326
+ const durationMs = Date.now() - t0;
327
+ if (!result.content || !Array.isArray(result.content)) {
328
+ throw new Error("pizx/patterns: Unexpected response format from AI model.");
329
+ }
214
330
  const text = result.content.filter((c) => c.type === "text").map((c) => c.text).join("");
331
+ if (_trace !== null) {
332
+ pushTrace({
333
+ call: _trace.length + 1,
334
+ modelId: result.model,
335
+ promptPreview: prompt.slice(0, 200),
336
+ outputPreview: text.slice(0, 200),
337
+ inputTokens: result.usage.input,
338
+ outputTokens: result.usage.output,
339
+ cacheReadTokens: result.usage.cacheRead,
340
+ cacheWriteTokens: result.usage.cacheWrite,
341
+ totalTokens: result.usage.totalTokens,
342
+ cost: result.usage.cost.total,
343
+ durationMs
344
+ });
345
+ }
215
346
  return text.trim();
216
347
  }
348
+ var QUALITY_REVIEW_SYSTEM = `You are a quality assurance reviewer. Evaluate the final deliverable against the original request.
349
+
350
+ Output format:
351
+ SCORE: 0.XX (quality score from 0.0 to 1.0)
352
+ ASSESSMENT: (1-2 sentences \u2014 is the output complete, consistent, and actionable?)
353
+ RECOMMENDATION: (1 sentence \u2014 what would improve this output?)`;
354
+ async function runQualityReview(originalRequest, finalOutput, opts) {
355
+ if (!opts.qualityCheck) return void 0;
356
+ const reviewText = await ask(
357
+ `Original request:
358
+ ${originalRequest}
359
+
360
+ Final deliverable:
361
+ ${finalOutput}
362
+
363
+ Evaluate the quality.`,
364
+ {
365
+ model: opts.plannerModel ?? opts.model,
366
+ maxTokens: 512,
367
+ thinkingLevel: "high",
368
+ timeoutMs: opts.timeoutMs,
369
+ maxRetries: opts.maxRetries,
370
+ system: QUALITY_REVIEW_SYSTEM
371
+ }
372
+ );
373
+ const scoreMatch = reviewText.match(/SCORE:\s*([\d.]+)/i);
374
+ const assessMatch = reviewText.match(/ASSESSMENT:\s*(.+)/i);
375
+ const recMatch = reviewText.match(/RECOMMENDATION:\s*(.+)/i);
376
+ const result = {
377
+ score: scoreMatch ? parseFloat(scoreMatch[1]) : 0.5,
378
+ assessment: assessMatch?.[1]?.trim() ?? "(no assessment)",
379
+ recommendation: recMatch?.[1]?.trim() ?? "(no recommendation)"
380
+ };
381
+ if (!opts.quiet) {
382
+ process.stderr.write(` Quality score: ${result.score.toFixed(2)}
383
+ `);
384
+ process.stderr.write(` ${result.assessment.slice(0, 80)}...
385
+ `);
386
+ }
387
+ return result;
388
+ }
217
389
 
218
390
  // src/patterns/adaptive.ts
219
391
  var defaults = {
@@ -277,10 +449,10 @@ async function execute(pieces, args, opts) {
277
449
  }
278
450
  if (!opts.quiet) process.stderr.write(" \u2192 Planning...\n");
279
451
  const planText = await ask(goal, {
452
+ ...opts,
280
453
  model: plannerModel,
281
- maxTokens: opts.maxTokens,
282
454
  thinkingLevel: "high",
283
- system: PLAN_SYSTEM
455
+ system: mergeSystem(opts.system, PLAN_SYSTEM)
284
456
  });
285
457
  const planLines = planText.split("\n");
286
458
  const plannedSteps = [];
@@ -310,10 +482,9 @@ async function execute(pieces, args, opts) {
310
482
  process.stderr.write(` \u2192 Step ${executionStep}: ${currentStep.slice(0, 60)}...
311
483
  `);
312
484
  const result = await ask(currentStep, {
485
+ ...opts,
313
486
  model: workerModel,
314
- maxTokens: opts.maxTokens,
315
- thinkingLevel: opts.thinkingLevel,
316
- system: EXECUTE_SYSTEM
487
+ system: mergeSystem(opts.system, EXECUTE_SYSTEM)
317
488
  });
318
489
  const evaluation = await ask(
319
490
  `Goal: ${goal}
@@ -322,10 +493,11 @@ Result: ${result}
322
493
 
323
494
  Evaluate the result.`,
324
495
  {
496
+ ...opts,
325
497
  model: plannerModel,
326
498
  maxTokens: 512,
327
499
  thinkingLevel: "high",
328
- system: EVALUATE_SYSTEM
500
+ system: mergeSystem(opts.system, EVALUATE_SYSTEM)
329
501
  }
330
502
  );
331
503
  const scoreMatch = evaluation.match(/SCORE:\s*([\d.]+)/i);
@@ -348,8 +520,7 @@ Evaluate the result.`,
348
520
  break;
349
521
  }
350
522
  const adaptUpper = adaptation.toUpperCase();
351
- if (adaptUpper.startsWith("REFINE")) {
352
- } else if (adaptUpper.startsWith("SKIP_NEXT")) {
523
+ if (adaptUpper.startsWith("SKIP_NEXT")) {
353
524
  stepIndex += 2;
354
525
  } else if (adaptUpper.startsWith("ADD")) {
355
526
  const newStep = adaptation.replace(/^ADD\s*/i, "");
@@ -368,36 +539,76 @@ Evaluate the result.`,
368
539
  ).join("\n\n");
369
540
  return new AdaptiveOutput(summary, finalResult, adaptiveSteps, executionStep, t0, t1);
370
541
  }
371
- function makeAdaptive(opts = {}) {
372
- const merged = { ...defaults, ...opts };
373
- const fn = ((pieces, ...args) => {
374
- if (!Array.isArray(pieces)) {
375
- return makeAdaptive({ ...merged, ...pieces });
376
- }
377
- return new PatternPromise((resolve, reject) => {
378
- execute(pieces, args, merged).then(resolve, reject);
379
- });
380
- });
381
- let _quiet;
382
- Object.defineProperty(fn, "quiet", {
383
- get() {
384
- if (!_quiet) _quiet = makeAdaptive({ ...merged, quiet: true });
385
- return _quiet;
386
- },
387
- enumerable: true,
388
- configurable: true
389
- });
390
- return fn;
391
- }
392
- var \u0391 = makeAdaptive();
542
+ var \u0391 = createPatternTag(defaults, execute);
393
543
 
394
- // src/patterns/broadcast.ts
395
- var defaults2 = {
396
- maxTokens: 4096,
397
- thinkingLevel: "medium",
398
- workers: 4
544
+ // src/patterns/role-sets.ts
545
+ var DEBATE_ROLE_SETS = {
546
+ 2: [
547
+ "Optimist \u2014 advocate for the most ambitious approach",
548
+ "Pessimist \u2014 identify risks and failure modes"
549
+ ],
550
+ 3: [
551
+ "Optimist \u2014 advocate the benefits and opportunities",
552
+ "Pessimist \u2014 identify risks, costs, and failure modes",
553
+ "Pragmatist \u2014 focus on practical trade-offs and implementation"
554
+ ],
555
+ 4: [
556
+ "Optimist \u2014 argue for the best-case potential",
557
+ "Pessimist \u2014 highlight worst-case risks and downsides",
558
+ "Pragmatist \u2014 balance pros/cons with practical constraints",
559
+ "Innovator \u2014 propose creative alternatives and novel approaches"
560
+ ],
561
+ 5: [
562
+ "Optimist",
563
+ "Pessimist",
564
+ "Pragmatist",
565
+ "Innovator",
566
+ "User Advocate \u2014 focus on end-user experience and accessibility"
567
+ ]
399
568
  };
400
- var ROLE_SETS = {
569
+ var MEMORY_ROLE_SETS = {
570
+ 2: ["Analyst \u2014 deep analysis of core aspects", "Reviewer \u2014 check for gaps and blind spots"],
571
+ 3: [
572
+ "Analyst \u2014 deep analysis of core aspects",
573
+ "Reviewer \u2014 check for gaps, edge cases, and blind spots",
574
+ "Strategist \u2014 connect findings to actionable insights"
575
+ ],
576
+ 4: [
577
+ "Analyst",
578
+ "Reviewer",
579
+ "Strategist",
580
+ "Innovator \u2014 propose novel angles and creative solutions"
581
+ ],
582
+ 5: [
583
+ "Analyst",
584
+ "Reviewer",
585
+ "Strategist",
586
+ "Innovator",
587
+ "Skeptic \u2014 challenge assumptions and stress-test conclusions"
588
+ ]
589
+ };
590
+ var THREAD_ROLE_SETS = {
591
+ 2: ["Proposer \u2014 advocate the best approach", "Critic \u2014 identify weaknesses and gaps"],
592
+ 3: [
593
+ "Proposer \u2014 suggest the best approach",
594
+ "Critic \u2014 identify weaknesses, risks, and missing pieces",
595
+ "Synthesizer \u2014 combine the best ideas into a practical plan"
596
+ ],
597
+ 4: [
598
+ "Proposer \u2014 advocate a bold solution",
599
+ "Critic \u2014 identify risks and weaknesses",
600
+ "Pragmatist \u2014 focus on practical implementation",
601
+ "Innovator \u2014 propose creative alternatives"
602
+ ],
603
+ 5: [
604
+ "Proposer",
605
+ "Critic",
606
+ "Pragmatist",
607
+ "Innovator",
608
+ "Devil's Advocate \u2014 challenge every assumption"
609
+ ]
610
+ };
611
+ var BROADCAST_ROLE_SETS = {
401
612
  2: [
402
613
  "Technical Expert \u2014 evaluate technical feasibility",
403
614
  "Business Expert \u2014 evaluate business viability"
@@ -421,6 +632,13 @@ var ROLE_SETS = {
421
632
  "Innovation Expert \u2014 suggest novel approaches and alternatives"
422
633
  ]
423
634
  };
635
+
636
+ // src/patterns/broadcast.ts
637
+ var defaults2 = {
638
+ maxTokens: 4096,
639
+ thinkingLevel: "medium",
640
+ workers: 4
641
+ };
424
642
  var BroadcastResponse = class {
425
643
  constructor(role, response, success, error) {
426
644
  this.role = role;
@@ -434,13 +652,15 @@ var BroadcastResponse = class {
434
652
  error;
435
653
  };
436
654
  var BroadcastOutput = class extends PatternOutput {
437
- constructor(text, synthesis, responses, startTime, endTime) {
655
+ constructor(text, synthesis, responses, startTime, endTime, qualityReview) {
438
656
  super(text, startTime, endTime);
439
657
  this.synthesis = synthesis;
440
658
  this.responses = responses;
659
+ this.qualityReview = qualityReview;
441
660
  }
442
661
  synthesis;
443
662
  responses;
663
+ qualityReview;
444
664
  };
445
665
  var WORKER_PROMPT = `You are a {role}.
446
666
 
@@ -455,7 +675,7 @@ async function execute2(pieces, args, opts) {
455
675
  const question = build(pieces, args);
456
676
  const t0 = Date.now();
457
677
  const workerCount = opts.workers ?? 4;
458
- const roles = opts.roles ?? ROLE_SETS[workerCount] ?? ROLE_SETS[4] ?? [];
678
+ const roles = opts.roles ?? BROADCAST_ROLE_SETS[workerCount] ?? BROADCAST_ROLE_SETS[4] ?? [];
459
679
  const plannerModel = opts.plannerModel ?? opts.model;
460
680
  const workerModel = opts.workerModel ?? opts.model;
461
681
  if (!opts.quiet) {
@@ -470,11 +690,7 @@ async function execute2(pieces, args, opts) {
470
690
  const broadcastResults = await Promise.allSettled(
471
691
  roles.map(async (role) => {
472
692
  const prompt = WORKER_PROMPT.replace("{role}", role).replace("{question}", question);
473
- const text = await ask(prompt, {
474
- model: workerModel,
475
- maxTokens: opts.maxTokens,
476
- thinkingLevel: opts.thinkingLevel
477
- });
693
+ const text = await ask(prompt, { ...opts, model: workerModel });
478
694
  return new BroadcastResponse(role, text, true);
479
695
  })
480
696
  );
@@ -499,40 +715,21 @@ ${responsesText}
499
715
 
500
716
  Synthesize a cohesive, actionable recommendation.`,
501
717
  {
718
+ ...opts,
502
719
  model: plannerModel,
503
- maxTokens: opts.maxTokens,
504
720
  thinkingLevel: "high",
505
- system: SYNTHESIS_SYSTEM
721
+ system: mergeSystem(opts.system, SYNTHESIS_SYSTEM)
506
722
  }
507
723
  );
724
+ if (!opts.quiet && opts.qualityCheck) process.stderr.write(" \u2192 Quality review...\n");
725
+ const qualityReview = await runQualityReview(question, synthesis, opts);
508
726
  const t1 = Date.now();
509
727
  const summary = responses.map(
510
728
  (wr) => `[${wr.role}]: ${wr.response.slice(0, 150)}${wr.response.length > 150 ? "..." : ""}`
511
729
  ).join("\n");
512
- return new BroadcastOutput(summary, synthesis, responses, t0, t1);
513
- }
514
- function makeBroadcast(opts = {}) {
515
- const merged = { ...defaults2, ...opts };
516
- const fn = ((pieces, ...args) => {
517
- if (!Array.isArray(pieces)) {
518
- return makeBroadcast({ ...merged, ...pieces });
519
- }
520
- return new PatternPromise((resolve, reject) => {
521
- execute2(pieces, args, merged).then(resolve, reject);
522
- });
523
- });
524
- let _quiet;
525
- Object.defineProperty(fn, "quiet", {
526
- get() {
527
- if (!_quiet) _quiet = makeBroadcast({ ...merged, quiet: true });
528
- return _quiet;
529
- },
530
- enumerable: true,
531
- configurable: true
532
- });
533
- return fn;
730
+ return new BroadcastOutput(summary, synthesis, responses, t0, t1, qualityReview);
534
731
  }
535
- var \u0392 = makeBroadcast();
732
+ var \u0392 = createPatternTag(defaults2, execute2);
536
733
 
537
734
  // src/patterns/chi.ts
538
735
  var defaults3 = {
@@ -552,15 +749,17 @@ var LearningInsight = class {
552
749
  confidence;
553
750
  };
554
751
  var ChiOutput = class extends PatternOutput {
555
- constructor(text, insights, summary, suggestedChanges, startTime, endTime) {
752
+ constructor(text, insights, summary, suggestedChanges, startTime, endTime, qualityReview) {
556
753
  super(text, startTime, endTime);
557
754
  this.insights = insights;
558
755
  this.summary = summary;
559
756
  this.suggestedChanges = suggestedChanges;
757
+ this.qualityReview = qualityReview;
560
758
  }
561
759
  insights;
562
760
  summary;
563
761
  suggestedChanges;
762
+ qualityReview;
564
763
  };
565
764
  var ANALYSIS_SYSTEM = `You are an agent team performance analyst. Review a multi-agent execution and extract structured learnings.
566
765
 
@@ -629,12 +828,13 @@ async function execute3(pieces, args, opts) {
629
828
  `);
630
829
  }
631
830
  const response = await ask(input, {
831
+ ...opts,
632
832
  model: plannerModel,
633
- maxTokens: opts.maxTokens,
634
- thinkingLevel: opts.thinkingLevel,
635
- system: ANALYSIS_SYSTEM
833
+ system: mergeSystem(opts.system, ANALYSIS_SYSTEM)
636
834
  });
637
835
  const { insights, summary, suggestedChanges } = parseInsights(response);
836
+ if (!opts.quiet && opts.qualityCheck) process.stderr.write(" \u2192 Quality review...\n");
837
+ const qualityReview = await runQualityReview(input, response, opts);
638
838
  const t1 = Date.now();
639
839
  const text = [
640
840
  `Insights: ${insights.length} extracted`,
@@ -646,30 +846,9 @@ Summary: ${summary}`,
646
846
  `
647
847
  Changes: ${suggestedChanges}`
648
848
  ].join("\n");
649
- return new ChiOutput(text, insights, summary, suggestedChanges, t0, t1);
849
+ return new ChiOutput(text, insights, summary, suggestedChanges, t0, t1, qualityReview);
650
850
  }
651
- function makeChi(opts = {}) {
652
- const merged = { ...defaults3, ...opts };
653
- const fn = ((pieces, ...args) => {
654
- if (!Array.isArray(pieces)) {
655
- return makeChi({ ...merged, ...pieces });
656
- }
657
- return new PatternPromise((resolve, reject) => {
658
- execute3(pieces, args, merged).then(resolve, reject);
659
- });
660
- });
661
- let _quiet;
662
- Object.defineProperty(fn, "quiet", {
663
- get() {
664
- if (!_quiet) _quiet = makeChi({ ...merged, quiet: true });
665
- return _quiet;
666
- },
667
- enumerable: true,
668
- configurable: true
669
- });
670
- return fn;
671
- }
672
- var \u03A7 = makeChi();
851
+ var \u03A7 = createPatternTag(defaults3, execute3);
673
852
 
674
853
  // src/patterns/critique.ts
675
854
  var defaults4 = {
@@ -724,12 +903,7 @@ async function execute4(pieces, args, opts) {
724
903
  for (let r = 0; r < rounds; r++) {
725
904
  if (r === 0) {
726
905
  if (!opts.quiet) process.stderr.write(" \u2192 Generating initial content...\n");
727
- currentContent = await ask(prompt, {
728
- model: workerModel,
729
- maxTokens: opts.maxTokens,
730
- thinkingLevel: opts.thinkingLevel,
731
- system: void 0
732
- });
906
+ currentContent = await ask(prompt, { ...opts, model: workerModel, system: opts.system });
733
907
  } else {
734
908
  if (!opts.quiet) process.stderr.write(` \u2192 Improving (round ${r + 1})...
735
909
  `);
@@ -744,21 +918,15 @@ Content to improve:
744
918
  ${currentContent}
745
919
 
746
920
  Revise the content based on the critique.`,
747
- {
748
- model: workerModel,
749
- maxTokens: opts.maxTokens,
750
- thinkingLevel: opts.thinkingLevel,
751
- system: IMPROVE_SYSTEM
752
- }
921
+ { ...opts, model: workerModel, system: mergeSystem(opts.system, IMPROVE_SYSTEM) }
753
922
  );
754
923
  }
755
924
  if (!opts.quiet) process.stderr.write(` \u2192 Critiquing (round ${r + 1})...
756
925
  `);
757
926
  const critique = await ask(currentContent, {
927
+ ...opts,
758
928
  model: plannerModel,
759
- maxTokens: opts.maxTokens,
760
- thinkingLevel: opts.thinkingLevel,
761
- system: CRITIQUE_SYSTEM
929
+ system: mergeSystem(opts.system, CRITIQUE_SYSTEM)
762
930
  });
763
931
  critiqueRounds.push(new CritiqueRound(currentContent, critique, r));
764
932
  }
@@ -771,28 +939,7 @@ Critique: ${cr.critique.slice(0, 200)}${cr.critique.length > 200 ? "..." : ""}`
771
939
  ).join("\n\n");
772
940
  return new CritiqueOutput(summary, finalContent, critiqueRounds, t0, t1);
773
941
  }
774
- function makeCritique(opts = {}) {
775
- const merged = { ...defaults4, ...opts };
776
- const fn = ((pieces, ...args) => {
777
- if (!Array.isArray(pieces)) {
778
- return makeCritique({ ...merged, ...pieces });
779
- }
780
- return new PatternPromise((resolve, reject) => {
781
- execute4(pieces, args, merged).then(resolve, reject);
782
- });
783
- });
784
- let _quiet;
785
- Object.defineProperty(fn, "quiet", {
786
- get() {
787
- if (!_quiet) _quiet = makeCritique({ ...merged, quiet: true });
788
- return _quiet;
789
- },
790
- enumerable: true,
791
- configurable: true
792
- });
793
- return fn;
794
- }
795
- var \u03A8 = makeCritique();
942
+ var \u03A8 = createPatternTag(defaults4, execute4);
796
943
 
797
944
  // src/patterns/debate.ts
798
945
  var defaults5 = {
@@ -801,30 +948,6 @@ var defaults5 = {
801
948
  perspectives: 3,
802
949
  rounds: 1
803
950
  };
804
- var ROLE_SETS2 = {
805
- 2: [
806
- "Optimist \u2014 advocate for the most ambitious approach",
807
- "Pessimist \u2014 identify risks and failure modes"
808
- ],
809
- 3: [
810
- "Optimist \u2014 advocate the benefits and opportunities",
811
- "Pessimist \u2014 identify risks, costs, and failure modes",
812
- "Pragmatist \u2014 focus on practical trade-offs and implementation"
813
- ],
814
- 4: [
815
- "Optimist \u2014 argue for the best-case potential",
816
- "Pessimist \u2014 highlight worst-case risks and downsides",
817
- "Pragmatist \u2014 balance pros/cons with practical constraints",
818
- "Innovator \u2014 propose creative alternatives and novel approaches"
819
- ],
820
- 5: [
821
- "Optimist",
822
- "Pessimist",
823
- "Pragmatist",
824
- "Innovator",
825
- "User Advocate \u2014 focus on end-user experience and accessibility"
826
- ]
827
- };
828
951
  var DebatePerspective = class {
829
952
  constructor(role, argument, round = 1) {
830
953
  this.role = role;
@@ -836,15 +959,17 @@ var DebatePerspective = class {
836
959
  round;
837
960
  };
838
961
  var DebateOutput = class extends PatternOutput {
839
- constructor(text, conclusion, perspectives, rounds, startTime, endTime) {
962
+ constructor(text, conclusion, perspectives, rounds, startTime, endTime, qualityReview) {
840
963
  super(text, startTime, endTime);
841
964
  this.conclusion = conclusion;
842
965
  this.perspectives = perspectives;
843
966
  this.rounds = rounds;
967
+ this.qualityReview = qualityReview;
844
968
  }
845
969
  conclusion;
846
970
  perspectives;
847
971
  rounds;
972
+ qualityReview;
848
973
  };
849
974
  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.`;
850
975
  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.`;
@@ -854,7 +979,7 @@ async function execute5(pieces, args, opts) {
854
979
  const t0 = Date.now();
855
980
  const count = opts.perspectives ?? 3;
856
981
  const totalRounds = opts.rounds ?? 1;
857
- const roles = opts.roles ?? ROLE_SETS2[count] ?? ROLE_SETS2[3] ?? [];
982
+ const roles = opts.roles ?? DEBATE_ROLE_SETS[count] ?? DEBATE_ROLE_SETS[3] ?? [];
858
983
  const plannerModel = opts.plannerModel ?? opts.model;
859
984
  const workerModel = opts.workerModel ?? opts.model;
860
985
  if (!opts.quiet) {
@@ -872,10 +997,9 @@ async function execute5(pieces, args, opts) {
872
997
  const round1Results = await Promise.allSettled(
873
998
  roles.map(
874
999
  (role) => ask(question, {
1000
+ ...opts,
875
1001
  model: workerModel,
876
- maxTokens: opts.maxTokens,
877
- thinkingLevel: opts.thinkingLevel,
878
- system: PERSPECTIVE_SYSTEM(role)
1002
+ system: mergeSystem(opts.system, PERSPECTIVE_SYSTEM(role))
879
1003
  }).then((text) => new DebatePerspective(role, text, 1))
880
1004
  )
881
1005
  );
@@ -909,10 +1033,9 @@ ${othersText}
909
1033
 
910
1034
  Refine your position. Address the counter-arguments directly. Strengthen your argument with rebuttals.`;
911
1035
  return ask(prompt, {
1036
+ ...opts,
912
1037
  model: workerModel,
913
- maxTokens: opts.maxTokens,
914
- thinkingLevel: opts.thinkingLevel,
915
- system: REBUTTAL_SYSTEM(role)
1038
+ system: mergeSystem(opts.system, REBUTTAL_SYSTEM(role))
916
1039
  }).then((text) => new DebatePerspective(role, text, round));
917
1040
  })
918
1041
  );
@@ -936,37 +1059,26 @@ Refine your position. Address the counter-arguments directly. Strengthen your ar
936
1059
 
937
1060
  Synthesize a balanced conclusion from the full debate above. Weigh the evidence from all rounds.`,
938
1061
  {
1062
+ ...opts,
939
1063
  model: plannerModel,
940
- maxTokens: opts.maxTokens,
941
1064
  thinkingLevel: "high",
942
- system: SYNTHESIS_SYSTEM2
1065
+ system: mergeSystem(opts.system, SYNTHESIS_SYSTEM2)
943
1066
  }
944
1067
  );
1068
+ if (!opts.quiet && opts.qualityCheck) process.stderr.write(" \u2192 Quality review...\n");
1069
+ const qualityReview = await runQualityReview(question, conclusion, opts);
945
1070
  const t1 = Date.now();
946
- return new DebateOutput(conclusion, conclusion, allPerspectives, totalRounds, t0, t1);
947
- }
948
- function makeDebate(opts = {}) {
949
- const merged = { ...defaults5, ...opts };
950
- const fn = ((pieces, ...args) => {
951
- if (!Array.isArray(pieces)) {
952
- return makeDebate({ ...merged, ...pieces });
953
- }
954
- return new PatternPromise((resolve, reject) => {
955
- execute5(pieces, args, merged).then(resolve, reject);
956
- });
957
- });
958
- let _quiet;
959
- Object.defineProperty(fn, "quiet", {
960
- get() {
961
- if (!_quiet) _quiet = makeDebate({ ...merged, quiet: true });
962
- return _quiet;
963
- },
964
- enumerable: true,
965
- configurable: true
966
- });
967
- return fn;
1071
+ return new DebateOutput(
1072
+ conclusion,
1073
+ conclusion,
1074
+ allPerspectives,
1075
+ totalRounds,
1076
+ t0,
1077
+ t1,
1078
+ qualityReview
1079
+ );
968
1080
  }
969
- var \u0394 = makeDebate();
1081
+ var \u0394 = createPatternTag(defaults5, execute5);
970
1082
 
971
1083
  // src/patterns/fleet.ts
972
1084
  var defaults6 = {
@@ -987,11 +1099,13 @@ var FleetMemberOutput = class {
987
1099
  error;
988
1100
  };
989
1101
  var FleetOutput = class extends PatternOutput {
990
- constructor(text, members, startTime, endTime) {
1102
+ constructor(text, members, startTime, endTime, qualityReview) {
991
1103
  super(text, startTime, endTime);
992
1104
  this.members = members;
1105
+ this.qualityReview = qualityReview;
993
1106
  }
994
1107
  members;
1108
+ qualityReview;
995
1109
  /** Number of successful members */
996
1110
  get successCount() {
997
1111
  return this.members.filter((m) => m.success).length;
@@ -1011,20 +1125,30 @@ function parseTasks(template, explicitTasks) {
1011
1125
  if (lines.length > 1) return lines;
1012
1126
  return [template];
1013
1127
  }
1128
+ function describeTask(task) {
1129
+ if (typeof task === "function") return "(composed pattern)";
1130
+ return task;
1131
+ }
1014
1132
  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.`;
1015
1133
  async function executeTask(task, opts, workerModel) {
1134
+ if (typeof task === "function") {
1135
+ try {
1136
+ const text = await task("");
1137
+ return new FleetMemberOutput("(composed pattern)", text, true);
1138
+ } catch (err) {
1139
+ return new FleetMemberOutput("(composed pattern)", "", false, getErrorMessage(err));
1140
+ }
1141
+ }
1016
1142
  const model = workerModel ?? opts.model;
1017
1143
  try {
1018
1144
  const text = await ask(task, {
1145
+ ...opts,
1019
1146
  model,
1020
- maxTokens: opts.maxTokens,
1021
- thinkingLevel: opts.thinkingLevel,
1022
- system: opts.system ?? FLEET_SYSTEM
1147
+ system: mergeSystem(opts.system, FLEET_SYSTEM)
1023
1148
  });
1024
1149
  return new FleetMemberOutput(task, text, true);
1025
1150
  } catch (err) {
1026
- const msg = err instanceof Error ? err.message : String(err);
1027
- return new FleetMemberOutput(task, "", false, msg);
1151
+ return new FleetMemberOutput(task, "", false, getErrorMessage(err));
1028
1152
  }
1029
1153
  }
1030
1154
  async function execute6(pieces, args, opts) {
@@ -1036,11 +1160,16 @@ async function execute6(pieces, args, opts) {
1036
1160
  process.stderr.write(`\u03A6: Fleet executing ${tasks.length} task(s) in parallel
1037
1161
  `);
1038
1162
  for (let i = 0; i < tasks.length; i++) {
1039
- const t = tasks[i];
1163
+ const t = describeTask(tasks[i]);
1040
1164
  process.stderr.write(` [${i + 1}] ${t.slice(0, 60)}${t.length > 60 ? "..." : ""}
1041
1165
  `);
1042
1166
  }
1043
1167
  }
1168
+ const taskSummary = `Execute ${tasks.length} fleet task(s)?
1169
+ ${tasks.map((t, i) => `${i + 1}. ${describeTask(t).slice(0, 80)}`).join("\n ")}`;
1170
+ if (!await confirmPhase(taskSummary, opts)) {
1171
+ throw new Error("pizx/\u03A6: Execution cancelled by user.");
1172
+ }
1044
1173
  const results = [];
1045
1174
  const concurrency = opts.concurrency ?? 5;
1046
1175
  for (let i = 0; i < tasks.length; i += concurrency) {
@@ -1052,7 +1181,9 @@ async function execute6(pieces, args, opts) {
1052
1181
  if (r.status === "fulfilled") {
1053
1182
  results.push(r.value);
1054
1183
  } else {
1055
- results.push(new FleetMemberOutput(batch[idx], "", false, r.reason?.toString()));
1184
+ results.push(
1185
+ new FleetMemberOutput(describeTask(batch[idx]), "", false, r.reason?.toString())
1186
+ );
1056
1187
  }
1057
1188
  });
1058
1189
  }
@@ -1064,30 +1195,11 @@ async function execute6(pieces, args, opts) {
1064
1195
  const header = `Fleet Results: ${results.filter((r) => r.success).length}/${results.length} succeeded
1065
1196
 
1066
1197
  `;
1067
- return new FleetOutput(header + summary, results, t0, t1);
1198
+ if (!opts.quiet && opts.qualityCheck) process.stderr.write(" \u2192 Quality review...\n");
1199
+ const qualityReview = await runQualityReview(template, header + summary, opts);
1200
+ return new FleetOutput(header + summary, results, t0, t1, qualityReview);
1068
1201
  }
1069
- function makeFleet(opts = {}) {
1070
- const merged = { ...defaults6, ...opts };
1071
- const fn = ((pieces, ...args) => {
1072
- if (!Array.isArray(pieces)) {
1073
- return makeFleet({ ...merged, ...pieces });
1074
- }
1075
- return new PatternPromise((resolve, reject) => {
1076
- execute6(pieces, args, merged).then(resolve, reject);
1077
- });
1078
- });
1079
- let _quiet;
1080
- Object.defineProperty(fn, "quiet", {
1081
- get() {
1082
- if (!_quiet) _quiet = makeFleet({ ...merged, quiet: true });
1083
- return _quiet;
1084
- },
1085
- enumerable: true,
1086
- configurable: true
1087
- });
1088
- return fn;
1089
- }
1090
- var \u03A6 = makeFleet();
1202
+ var \u03A6 = createPatternTag(defaults6, execute6);
1091
1203
 
1092
1204
  // src/patterns/graph.ts
1093
1205
  var defaults7 = {
@@ -1107,13 +1219,15 @@ var GraphNodeResult = class {
1107
1219
  success;
1108
1220
  };
1109
1221
  var GraphOutput = class extends PatternOutput {
1110
- constructor(text, finalOutput, nodeResults, startTime, endTime) {
1222
+ constructor(text, finalOutput, nodeResults, startTime, endTime, qualityReview) {
1111
1223
  super(text, startTime, endTime);
1112
1224
  this.finalOutput = finalOutput;
1113
1225
  this.nodeResults = nodeResults;
1226
+ this.qualityReview = qualityReview;
1114
1227
  }
1115
1228
  finalOutput;
1116
1229
  nodeResults;
1230
+ qualityReview;
1117
1231
  };
1118
1232
  function parseGraph(template, separator) {
1119
1233
  const sep = separator ?? "\u2192";
@@ -1209,10 +1323,9 @@ Your task: ${node.task}`;
1209
1323
  }
1210
1324
  }
1211
1325
  const text = await ask(context, {
1326
+ ...opts,
1212
1327
  model: workerModel,
1213
- maxTokens: opts.maxTokens,
1214
- thinkingLevel: opts.thinkingLevel,
1215
- system: NODE_SYSTEM
1328
+ system: mergeSystem(opts.system, NODE_SYSTEM)
1216
1329
  });
1217
1330
  return { nodeId, task: node.task, text, success: true };
1218
1331
  })
@@ -1230,34 +1343,15 @@ Your task: ${node.task}`;
1230
1343
  const lastBatch = batches[batches.length - 1] ?? [];
1231
1344
  const finalNodeResults = lastBatch.map((id) => results.get(id)).filter(Boolean);
1232
1345
  const finalOutput = finalNodeResults.length > 0 ? finalNodeResults.join("\n\n") : "";
1346
+ if (!opts.quiet && opts.qualityCheck) process.stderr.write(" \u2192 Quality review...\n");
1347
+ const qualityReview = await runQualityReview(template, finalOutput, opts);
1233
1348
  const summary = nodeResults.map(
1234
1349
  (nr) => `[${nr.nodeId}] ${nr.task.slice(0, 80)}...
1235
1350
  ${nr.output.slice(0, 200)}${nr.output.length > 200 ? "..." : ""}`
1236
1351
  ).join("\n\n");
1237
- return new GraphOutput(summary, finalOutput, nodeResults, t0, t1);
1238
- }
1239
- function makeGraph(opts = {}) {
1240
- const merged = { ...defaults7, ...opts };
1241
- const fn = ((pieces, ...args) => {
1242
- if (!Array.isArray(pieces)) {
1243
- return makeGraph({ ...merged, ...pieces });
1244
- }
1245
- return new PatternPromise((resolve, reject) => {
1246
- execute7(pieces, args, merged).then(resolve, reject);
1247
- });
1248
- });
1249
- let _quiet;
1250
- Object.defineProperty(fn, "quiet", {
1251
- get() {
1252
- if (!_quiet) _quiet = makeGraph({ ...merged, quiet: true });
1253
- return _quiet;
1254
- },
1255
- enumerable: true,
1256
- configurable: true
1257
- });
1258
- return fn;
1352
+ return new GraphOutput(summary, finalOutput, nodeResults, t0, t1, qualityReview);
1259
1353
  }
1260
- var \u0393 = makeGraph();
1354
+ var \u0393 = createPatternTag(defaults7, execute7);
1261
1355
 
1262
1356
  // src/patterns/memory.ts
1263
1357
  var defaults8 = {
@@ -1266,27 +1360,6 @@ var defaults8 = {
1266
1360
  agents: 3,
1267
1361
  rounds: 1
1268
1362
  };
1269
- var ROLE_SETS3 = {
1270
- 2: ["Analyst \u2014 deep analysis of core aspects", "Reviewer \u2014 check for gaps and blind spots"],
1271
- 3: [
1272
- "Analyst \u2014 deep analysis of core aspects",
1273
- "Reviewer \u2014 check for gaps, edge cases, and blind spots",
1274
- "Strategist \u2014 connect findings to actionable insights"
1275
- ],
1276
- 4: [
1277
- "Analyst",
1278
- "Reviewer",
1279
- "Strategist",
1280
- "Innovator \u2014 propose novel angles and creative solutions"
1281
- ],
1282
- 5: [
1283
- "Analyst",
1284
- "Reviewer",
1285
- "Strategist",
1286
- "Innovator",
1287
- "Skeptic \u2014 challenge assumptions and stress-test conclusions"
1288
- ]
1289
- };
1290
1363
  var MemoryEntry = class {
1291
1364
  constructor(role, round, content) {
1292
1365
  this.role = role;
@@ -1298,13 +1371,15 @@ var MemoryEntry = class {
1298
1371
  content;
1299
1372
  };
1300
1373
  var MemoryOutput = class extends PatternOutput {
1301
- constructor(text, synthesis, entries, startTime, endTime) {
1374
+ constructor(text, synthesis, entries, startTime, endTime, qualityReview) {
1302
1375
  super(text, startTime, endTime);
1303
1376
  this.synthesis = synthesis;
1304
1377
  this.entries = entries;
1378
+ this.qualityReview = qualityReview;
1305
1379
  }
1306
1380
  synthesis;
1307
1381
  entries;
1382
+ qualityReview;
1308
1383
  };
1309
1384
  var WRITER_PROMPT = `You are a specialist with role: {role}.
1310
1385
 
@@ -1325,7 +1400,7 @@ async function execute8(pieces, args, opts) {
1325
1400
  const t0 = Date.now();
1326
1401
  const agentCount = opts.agents ?? 3;
1327
1402
  const totalRounds = opts.rounds ?? 1;
1328
- const roles = opts.roles ?? ROLE_SETS3[agentCount] ?? ROLE_SETS3[3] ?? [];
1403
+ const roles = opts.roles ?? MEMORY_ROLE_SETS[agentCount] ?? MEMORY_ROLE_SETS[3] ?? [];
1329
1404
  const plannerModel = opts.plannerModel ?? opts.model;
1330
1405
  const workerModel = opts.workerModel ?? opts.model;
1331
1406
  if (!opts.quiet) {
@@ -1342,11 +1417,7 @@ async function execute8(pieces, args, opts) {
1342
1417
  const roundResults = await Promise.allSettled(
1343
1418
  roles.map(async (role) => {
1344
1419
  const prompt = buildWriterPrompt(role, topic, blackboard);
1345
- const text = await ask(prompt, {
1346
- model: workerModel,
1347
- maxTokens: opts.maxTokens,
1348
- thinkingLevel: opts.thinkingLevel
1349
- });
1420
+ const text = await ask(prompt, { ...opts, model: workerModel });
1350
1421
  return { role, text };
1351
1422
  })
1352
1423
  );
@@ -1368,40 +1439,21 @@ ${blackboard}
1368
1439
 
1369
1440
  Consolidate into a comprehensive, structured synthesis.`,
1370
1441
  {
1442
+ ...opts,
1371
1443
  model: plannerModel,
1372
- maxTokens: opts.maxTokens,
1373
1444
  thinkingLevel: "high",
1374
- system: CONSOLIDATOR_SYSTEM
1445
+ system: mergeSystem(opts.system, CONSOLIDATOR_SYSTEM)
1375
1446
  }
1376
1447
  );
1448
+ if (!opts.quiet && opts.qualityCheck) process.stderr.write(" \u2192 Quality review...\n");
1449
+ const qualityReview = await runQualityReview(topic, synthesis, opts);
1377
1450
  const t1 = Date.now();
1378
1451
  const summary = entries.map(
1379
1452
  (e) => `[${e.role}] Round ${e.round}: ${e.content.slice(0, 150)}${e.content.length > 150 ? "..." : ""}`
1380
1453
  ).join("\n");
1381
- return new MemoryOutput(summary, synthesis, entries, t0, t1);
1382
- }
1383
- function makeMemory(opts = {}) {
1384
- const merged = { ...defaults8, ...opts };
1385
- const fn = ((pieces, ...args) => {
1386
- if (!Array.isArray(pieces)) {
1387
- return makeMemory({ ...merged, ...pieces });
1388
- }
1389
- return new PatternPromise((resolve, reject) => {
1390
- execute8(pieces, args, merged).then(resolve, reject);
1391
- });
1392
- });
1393
- let _quiet;
1394
- Object.defineProperty(fn, "quiet", {
1395
- get() {
1396
- if (!_quiet) _quiet = makeMemory({ ...merged, quiet: true });
1397
- return _quiet;
1398
- },
1399
- enumerable: true,
1400
- configurable: true
1401
- });
1402
- return fn;
1454
+ return new MemoryOutput(summary, synthesis, entries, t0, t1, qualityReview);
1403
1455
  }
1404
- var \u039C = makeMemory();
1456
+ var \u039C = createPatternTag(defaults8, execute8);
1405
1457
 
1406
1458
  // src/patterns/nu.ts
1407
1459
  var defaults9 = {
@@ -1421,19 +1473,21 @@ var NuRole = class {
1421
1473
  goal;
1422
1474
  };
1423
1475
  var NuOutput = class extends PatternOutput {
1424
- constructor(text, negotiatedRoles, workflow, workflowReasoning, roleResults, synthesis, startTime, endTime) {
1476
+ constructor(text, negotiatedRoles, workflow, workflowReasoning, roleResults, synthesis, startTime, endTime, qualityReview) {
1425
1477
  super(text, startTime, endTime);
1426
1478
  this.negotiatedRoles = negotiatedRoles;
1427
1479
  this.workflow = workflow;
1428
1480
  this.workflowReasoning = workflowReasoning;
1429
1481
  this.roleResults = roleResults;
1430
1482
  this.synthesis = synthesis;
1483
+ this.qualityReview = qualityReview;
1431
1484
  }
1432
1485
  negotiatedRoles;
1433
1486
  workflow;
1434
1487
  workflowReasoning;
1435
1488
  roleResults;
1436
1489
  synthesis;
1490
+ qualityReview;
1437
1491
  };
1438
1492
  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.
1439
1493
 
@@ -1471,6 +1525,7 @@ async function negotiateRoles(task, opts) {
1471
1525
  const response = await ask(`Task: ${task}
1472
1526
 
1473
1527
  ${prompt}`, {
1528
+ ...opts,
1474
1529
  model: opts.plannerModel ?? opts.model,
1475
1530
  maxTokens: 2048,
1476
1531
  thinkingLevel: "high"
@@ -1507,10 +1562,11 @@ ${rolesText}
1507
1562
 
1508
1563
  Determine the best execution strategy.`,
1509
1564
  {
1565
+ ...opts,
1510
1566
  model: opts.plannerModel ?? opts.model,
1511
1567
  maxTokens: 512,
1512
1568
  thinkingLevel: "high",
1513
- system: WORKFLOW_SYSTEM
1569
+ system: mergeSystem(opts.system, WORKFLOW_SYSTEM)
1514
1570
  }
1515
1571
  );
1516
1572
  const wfMatch = response.match(/WORKFLOW\s*:\s*(.+)/i);
@@ -1529,10 +1585,9 @@ async function executeRoles(roles, task, workflow, opts) {
1529
1585
  let context = task;
1530
1586
  for (const role of roles) {
1531
1587
  const output = await ask(context, {
1588
+ ...opts,
1532
1589
  model: workerModel,
1533
- maxTokens: opts.maxTokens,
1534
- thinkingLevel: opts.thinkingLevel,
1535
- system: EXECUTE_SYSTEM2(role)
1590
+ system: mergeSystem(opts.system, EXECUTE_SYSTEM2(role))
1536
1591
  });
1537
1592
  results.push({ role: role.name, output });
1538
1593
  context = `Previous output from ${role.name}:
@@ -1544,10 +1599,9 @@ Continue with: ${task}`;
1544
1599
  const parallelResults = await Promise.allSettled(
1545
1600
  roles.map(
1546
1601
  (role) => ask(task, {
1602
+ ...opts,
1547
1603
  model: workerModel,
1548
- maxTokens: opts.maxTokens,
1549
- thinkingLevel: opts.thinkingLevel,
1550
- system: EXECUTE_SYSTEM2(role)
1604
+ system: mergeSystem(opts.system, EXECUTE_SYSTEM2(role))
1551
1605
  }).then((text) => ({ role: role.name, output: text })).catch((err) => ({ role: role.name, output: `(failed: ${String(err)})` }))
1552
1606
  )
1553
1607
  );
@@ -1569,10 +1623,10 @@ ${resultsText}
1569
1623
 
1570
1624
  Synthesize a comprehensive final answer.`,
1571
1625
  {
1626
+ ...opts,
1572
1627
  model: opts.plannerModel ?? opts.model,
1573
- maxTokens: opts.maxTokens,
1574
1628
  thinkingLevel: "high",
1575
- system: SYNTHESIS_SYSTEM3
1629
+ system: mergeSystem(opts.system, SYNTHESIS_SYSTEM3)
1576
1630
  }
1577
1631
  );
1578
1632
  }
@@ -1613,6 +1667,8 @@ async function execute9(pieces, args, opts) {
1613
1667
  const roleResults = await executeRoles(roles, task, workflow, opts);
1614
1668
  if (!opts.quiet) process.stderr.write(" \u2192 Synthesizing...\n");
1615
1669
  const synthesis = await synthesize(task, roleResults, { ...opts, plannerModel });
1670
+ if (!opts.quiet && opts.qualityCheck) process.stderr.write(" \u2192 Quality review...\n");
1671
+ const qualityReview = await runQualityReview(task, synthesis, opts);
1616
1672
  const t1 = Date.now();
1617
1673
  const summary = [
1618
1674
  `Roles: ${roles.map((r) => r.name).join(", ")}`,
@@ -1620,30 +1676,19 @@ async function execute9(pieces, args, opts) {
1620
1676
  `Results: ${roleResults.length}/${roles.length} succeeded`,
1621
1677
  `Synthesis: ${synthesis}`
1622
1678
  ].join("\n\n");
1623
- return new NuOutput(summary, roles, workflow, reasoning, roleResults, synthesis, t0, t1);
1624
- }
1625
- function makeNu(opts = {}) {
1626
- const merged = { ...defaults9, ...opts };
1627
- const fn = ((pieces, ...args) => {
1628
- if (!Array.isArray(pieces)) {
1629
- return makeNu({ ...merged, ...pieces });
1630
- }
1631
- return new PatternPromise((resolve, reject) => {
1632
- execute9(pieces, args, merged).then(resolve, reject);
1633
- });
1634
- });
1635
- let _quiet;
1636
- Object.defineProperty(fn, "quiet", {
1637
- get() {
1638
- if (!_quiet) _quiet = makeNu({ ...merged, quiet: true });
1639
- return _quiet;
1640
- },
1641
- enumerable: true,
1642
- configurable: true
1643
- });
1644
- return fn;
1679
+ return new NuOutput(
1680
+ summary,
1681
+ roles,
1682
+ workflow,
1683
+ reasoning,
1684
+ roleResults,
1685
+ synthesis,
1686
+ t0,
1687
+ t1,
1688
+ qualityReview
1689
+ );
1645
1690
  }
1646
- var \u039D = makeNu();
1691
+ var \u039D = createPatternTag(defaults9, execute9);
1647
1692
 
1648
1693
  // src/patterns/orchestrator.ts
1649
1694
  var defaults10 = {
@@ -1663,15 +1708,17 @@ var OrchestratorWorkerResult = class {
1663
1708
  success;
1664
1709
  };
1665
1710
  var OrchestratorOutput = class extends PatternOutput {
1666
- constructor(text, plan, synthesis, workerResults, startTime, endTime) {
1711
+ constructor(text, plan, synthesis, workerResults, startTime, endTime, qualityReview) {
1667
1712
  super(text, startTime, endTime);
1668
1713
  this.plan = plan;
1669
1714
  this.synthesis = synthesis;
1670
1715
  this.workerResults = workerResults;
1716
+ this.qualityReview = qualityReview;
1671
1717
  }
1672
1718
  plan;
1673
1719
  synthesis;
1674
1720
  workerResults;
1721
+ qualityReview;
1675
1722
  };
1676
1723
  var PLANNER_SYSTEM = `You are a senior architect and project planner. Given a high-level request, create a detailed execution plan.
1677
1724
 
@@ -1694,6 +1741,7 @@ async function execute10(pieces, args, opts) {
1694
1741
  const request = build(pieces, args);
1695
1742
  const t0 = Date.now();
1696
1743
  const workerCount = opts.workers ?? 3;
1744
+ const phases = [];
1697
1745
  const plannerModel = opts.plannerModel ?? opts.model;
1698
1746
  const workerModel = opts.workerModel ?? opts.model;
1699
1747
  if (!opts.quiet) {
@@ -1703,11 +1751,18 @@ async function execute10(pieces, args, opts) {
1703
1751
  );
1704
1752
  }
1705
1753
  if (!opts.quiet) process.stderr.write(" \u2192 Planning...\n");
1754
+ const planStart = Date.now();
1706
1755
  const planText = await ask(request, {
1756
+ ...opts,
1707
1757
  model: plannerModel,
1708
- maxTokens: opts.maxTokens,
1709
1758
  thinkingLevel: "high",
1710
- system: PLANNER_SYSTEM.replace("{$workerCount}", String(workerCount))
1759
+ system: mergeSystem(opts.system, PLANNER_SYSTEM.replace("{$workerCount}", String(workerCount)))
1760
+ });
1761
+ phases.push({
1762
+ phase: "plan",
1763
+ durationMs: Date.now() - planStart,
1764
+ description: `Generated plan with ${workerCount} workers`,
1765
+ modelUsed: plannerModel
1711
1766
  });
1712
1767
  const subTasks = [];
1713
1768
  const taskLines = planText.split("\n");
@@ -1731,27 +1786,37 @@ async function execute10(pieces, args, opts) {
1731
1786
  `);
1732
1787
  }
1733
1788
  }
1789
+ const planSummary = tasks.length > 0 ? `Execute ${tasks.length} sub-task(s) as planned?
1790
+ ${tasks.map((t, i) => `${i + 1}. ${t.slice(0, 80)}`).join("\n ")}` : `Execute the plan?`;
1791
+ if (!await confirmPhase(planSummary, opts)) {
1792
+ throw new Error("pizx/\u03A9: Execution cancelled by user.");
1793
+ }
1734
1794
  const workerResults = [];
1735
1795
  const concurrency = opts.concurrency ?? 3;
1796
+ const dispatchStart = Date.now();
1736
1797
  for (let i = 0; i < tasks.length; i += concurrency) {
1737
1798
  const batch = tasks.slice(i, i + concurrency);
1738
1799
  const batchResults = await Promise.allSettled(
1739
1800
  batch.map(
1740
- (task) => ask(task, {
1741
- model: workerModel,
1742
- maxTokens: opts.maxTokens,
1743
- thinkingLevel: opts.thinkingLevel,
1744
- system: WORKER_SYSTEM
1745
- }).then((text) => new OrchestratorWorkerResult(task, text, true)).catch((err) => new OrchestratorWorkerResult(task, String(err), false))
1801
+ (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))
1746
1802
  )
1747
1803
  );
1748
1804
  batchResults.forEach((r) => {
1749
1805
  if (r.status === "fulfilled") workerResults.push(r.value);
1750
1806
  });
1751
1807
  }
1808
+ const succeeded = workerResults.filter((w) => w.success).length;
1809
+ phases.push({
1810
+ phase: "dispatch",
1811
+ durationMs: Date.now() - dispatchStart,
1812
+ description: `Executed ${workerResults.length} worker(s), ${succeeded} succeeded`,
1813
+ modelUsed: workerModel,
1814
+ callCount: workerResults.length
1815
+ });
1752
1816
  if (!opts.quiet) process.stderr.write(" \u2192 Synthesizing results...\n");
1753
1817
  const workerTexts = workerResults.map((wr, i) => `Task ${i + 1}: ${wr.task}
1754
1818
  Result: ${wr.output}`).join("\n\n");
1819
+ const synthStart = Date.now();
1755
1820
  const synthesis = await ask(
1756
1821
  `Original request:
1757
1822
  ${request}
@@ -1764,46 +1829,60 @@ ${workerTexts}
1764
1829
 
1765
1830
  Synthesize a final deliverable.`,
1766
1831
  {
1832
+ ...opts,
1767
1833
  model: plannerModel,
1768
- maxTokens: opts.maxTokens,
1769
1834
  thinkingLevel: "high",
1770
- system: SYNTHESIS_SYSTEM4
1835
+ system: mergeSystem(opts.system, SYNTHESIS_SYSTEM4)
1771
1836
  }
1772
1837
  );
1838
+ phases.push({
1839
+ phase: "synthesize",
1840
+ durationMs: Date.now() - synthStart,
1841
+ description: "Synthesized worker results into final deliverable",
1842
+ modelUsed: plannerModel
1843
+ });
1844
+ if (!opts.quiet && opts.qualityCheck) process.stderr.write(" \u2192 Quality review...\n");
1845
+ const qualityStart = Date.now();
1846
+ const qualityReview = await runQualityReview(request, synthesis, opts);
1847
+ if (qualityReview) {
1848
+ phases.push({
1849
+ phase: "quality-review",
1850
+ durationMs: Date.now() - qualityStart,
1851
+ description: `Score: ${qualityReview.score.toFixed(2)} \u2014 ${qualityReview.assessment.slice(0, 60)}`,
1852
+ modelUsed: plannerModel
1853
+ });
1854
+ }
1773
1855
  const t1 = Date.now();
1856
+ const reviewSection = qualityReview ? `
1857
+
1858
+ Quality Review: ${qualityReview.score.toFixed(2)} \u2014 ${qualityReview.assessment}
1859
+ Recommendation: ${qualityReview.recommendation}` : "";
1774
1860
  const summary = `Plan:
1775
1861
  ${planText}
1776
1862
 
1777
1863
  Workers: ${workerResults.filter((w) => w.success).length}/${workerResults.length} succeeded
1778
1864
 
1779
1865
  Synthesis:
1780
- ${synthesis}`;
1781
- return new OrchestratorOutput(summary, planText, synthesis, workerResults, t0, t1);
1782
- }
1783
- function makeOrchestrator(opts = {}) {
1784
- const merged = { ...defaults10, ...opts };
1785
- const fn = ((pieces, ...args) => {
1786
- if (!Array.isArray(pieces)) {
1787
- return makeOrchestrator({ ...merged, ...pieces });
1788
- }
1789
- return new PatternPromise((resolve, reject) => {
1790
- execute10(pieces, args, merged).then(resolve, reject);
1791
- });
1792
- });
1793
- let _quiet;
1794
- Object.defineProperty(fn, "quiet", {
1795
- get() {
1796
- if (!_quiet) _quiet = makeOrchestrator({ ...merged, quiet: true });
1797
- return _quiet;
1798
- },
1799
- enumerable: true,
1800
- configurable: true
1801
- });
1802
- return fn;
1866
+ ${synthesis}${reviewSection}`;
1867
+ const output = new OrchestratorOutput(
1868
+ summary,
1869
+ planText,
1870
+ synthesis,
1871
+ workerResults,
1872
+ t0,
1873
+ t1,
1874
+ qualityReview
1875
+ );
1876
+ output.phaseLog = phases;
1877
+ return output;
1803
1878
  }
1804
- var \u03A9 = makeOrchestrator();
1879
+ var \u03A9 = createPatternTag(defaults10, execute10);
1805
1880
 
1806
1881
  // src/patterns/pipeline.ts
1882
+ function describeStage(stage) {
1883
+ if (typeof stage === "function") return "(composed pattern)";
1884
+ return stage;
1885
+ }
1807
1886
  var defaults11 = {
1808
1887
  maxTokens: 4096,
1809
1888
  thinkingLevel: "medium"
@@ -1819,13 +1898,15 @@ var PipelineStageResult = class {
1819
1898
  index;
1820
1899
  };
1821
1900
  var PipelineOutput = class extends PatternOutput {
1822
- constructor(text, finalOutput, stages, startTime, endTime) {
1901
+ constructor(text, finalOutput, stages, startTime, endTime, qualityReview) {
1823
1902
  super(text, startTime, endTime);
1824
1903
  this.finalOutput = finalOutput;
1825
1904
  this.stages = stages;
1905
+ this.qualityReview = qualityReview;
1826
1906
  }
1827
1907
  finalOutput;
1828
1908
  stages;
1909
+ qualityReview;
1829
1910
  };
1830
1911
  function parseStages(template, explicitStages, separator) {
1831
1912
  if (explicitStages && explicitStages.length > 0) return explicitStages;
@@ -1867,55 +1948,46 @@ async function execute11(pieces, args, opts) {
1867
1948
  `);
1868
1949
  }
1869
1950
  }
1951
+ const stageSummary = `Run ${stages.length} pipeline stage(s)?
1952
+ ${stages.map((s, i) => `${i + 1}. ${describeStage(s)}`).join("\n ")}`;
1953
+ if (!await confirmPhase(stageSummary, opts)) {
1954
+ throw new Error("pizx/\u039B: Execution cancelled by user.");
1955
+ }
1870
1956
  const stageResults = [];
1871
1957
  let currentInput = "";
1872
1958
  for (let i = 0; i < stages.length; i++) {
1873
1959
  const stage = stages[i];
1960
+ const stageLabel = describeStage(stage);
1874
1961
  const customPrompt = opts.stagePrompts?.[i];
1875
1962
  if (!opts.quiet)
1876
- process.stderr.write(` \u2192 Stage ${i + 1}/${stages.length}: ${stage.slice(0, 50)}...
1963
+ process.stderr.write(` \u2192 Stage ${i + 1}/${stages.length}: ${stageLabel.slice(0, 50)}...
1877
1964
  `);
1878
- const prompt = customPrompt ?? generateStagePrompt(stage, currentInput, i === 0);
1879
- 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.`;
1880
- const output = await ask(prompt, {
1881
- model: workerModel,
1882
- maxTokens: opts.maxTokens,
1883
- thinkingLevel: opts.thinkingLevel,
1884
- system: systemMessage
1885
- });
1886
- stageResults.push(new PipelineStageResult(stage, output, i));
1965
+ let output;
1966
+ if (typeof stage === "function") {
1967
+ output = await stage(currentInput);
1968
+ } else {
1969
+ const prompt = customPrompt ?? generateStagePrompt(stage, currentInput, i === 0);
1970
+ 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.`;
1971
+ output = await ask(prompt, {
1972
+ ...opts,
1973
+ model: workerModel,
1974
+ system: mergeSystem(opts.system, systemMessage)
1975
+ });
1976
+ }
1977
+ stageResults.push(new PipelineStageResult(stageLabel, output, i));
1887
1978
  currentInput = output;
1888
1979
  }
1889
1980
  const t1 = Date.now();
1890
1981
  const finalOutput = currentInput;
1982
+ if (!opts.quiet && opts.qualityCheck) process.stderr.write(" \u2192 Quality review...\n");
1983
+ const qualityReview = await runQualityReview(template, finalOutput, opts);
1891
1984
  const summary = stageResults.map(
1892
1985
  (sr) => `Stage ${sr.index + 1} (${sr.stage}):
1893
1986
  ${sr.output.slice(0, 200)}${sr.output.length > 200 ? "..." : ""}`
1894
1987
  ).join("\n\n");
1895
- return new PipelineOutput(summary, finalOutput, stageResults, t0, t1);
1896
- }
1897
- function makePipeline(opts = {}) {
1898
- const merged = { ...defaults11, ...opts };
1899
- const fn = ((pieces, ...args) => {
1900
- if (!Array.isArray(pieces)) {
1901
- return makePipeline({ ...merged, ...pieces });
1902
- }
1903
- return new PatternPromise((resolve, reject) => {
1904
- execute11(pieces, args, merged).then(resolve, reject);
1905
- });
1906
- });
1907
- let _quiet;
1908
- Object.defineProperty(fn, "quiet", {
1909
- get() {
1910
- if (!_quiet) _quiet = makePipeline({ ...merged, quiet: true });
1911
- return _quiet;
1912
- },
1913
- enumerable: true,
1914
- configurable: true
1915
- });
1916
- return fn;
1988
+ return new PipelineOutput(summary, finalOutput, stageResults, t0, t1, qualityReview);
1917
1989
  }
1918
- var \u039B = makePipeline();
1990
+ var \u039B = createPatternTag(defaults11, execute11);
1919
1991
 
1920
1992
  // src/patterns/ralph.ts
1921
1993
  import { createAgentSession } from "@earendil-works/pi-coding-agent";
@@ -1950,17 +2022,17 @@ async function executeWithTools(goal, opts) {
1950
2022
  });
1951
2023
  try {
1952
2024
  await session.sendUserMessage(goal);
1953
- const msgs = session.messages ?? [];
1954
- for (let i = msgs.length - 1; i >= 0; i--) {
1955
- if (msgs[i].role === "assistant") {
1956
- const c = msgs[i].content;
1957
- if (typeof c === "string") return c.trim();
1958
- if (Array.isArray(c)) {
1959
- const texts = c.filter(
1960
- (x) => x.type === "text" && typeof x.text === "string"
1961
- ).map((x) => x.text);
1962
- if (texts.length > 0) return texts.join("").trim();
1963
- }
2025
+ const messages = session.messages;
2026
+ for (let i = messages.length - 1; i >= 0; i--) {
2027
+ const msg = messages[i];
2028
+ if (msg?.role !== "assistant") continue;
2029
+ const c = "content" in msg ? msg.content : void 0;
2030
+ if (typeof c === "string") return c.trim();
2031
+ if (Array.isArray(c)) {
2032
+ const texts = c.filter(
2033
+ (x) => x.type === "text" && typeof x.text === "string"
2034
+ ).map((x) => x.text);
2035
+ if (texts.length > 0) return texts.join("").trim();
1964
2036
  }
1965
2037
  }
1966
2038
  return "(no assistant response)";
@@ -1995,10 +2067,9 @@ async function execute12(pieces, args, opts) {
1995
2067
  }
1996
2068
  if (!opts.quiet) process.stderr.write(" \u2192 Analyzing...\n");
1997
2069
  const analysis = await ask(currentGoal, {
2070
+ ...opts,
1998
2071
  model: plannerModel,
1999
- maxTokens: opts.maxTokens,
2000
- thinkingLevel: opts.thinkingLevel,
2001
- system: ANALYSIS_SYSTEM2
2072
+ system: mergeSystem(opts.system, ANALYSIS_SYSTEM2)
2002
2073
  });
2003
2074
  if (!opts.quiet) process.stderr.write(" \u2192 Planning...\n");
2004
2075
  const plan = await ask(
@@ -2007,12 +2078,7 @@ async function execute12(pieces, args, opts) {
2007
2078
  Analysis: ${analysis}
2008
2079
 
2009
2080
  Generate an implementation plan.`,
2010
- {
2011
- model: plannerModel,
2012
- maxTokens: opts.maxTokens,
2013
- thinkingLevel: opts.thinkingLevel,
2014
- system: PLAN_SYSTEM2
2015
- }
2081
+ { ...opts, model: plannerModel, system: mergeSystem(opts.system, PLAN_SYSTEM2) }
2016
2082
  );
2017
2083
  if (!opts.quiet) process.stderr.write(" \u2192 Executing...\n");
2018
2084
  const result = opts.useTools ? await executeWithTools(`Implement this plan:
@@ -2025,9 +2091,8 @@ Goal: ${currentGoal}`, {
2025
2091
  ${plan}
2026
2092
 
2027
2093
  Goal: ${currentGoal}`, {
2028
- model: workerModel,
2029
- maxTokens: opts.maxTokens,
2030
- thinkingLevel: opts.thinkingLevel
2094
+ ...opts,
2095
+ model: workerModel
2031
2096
  });
2032
2097
  if (!opts.quiet) process.stderr.write(" \u2192 Reviewing...\n");
2033
2098
  const review = await ask(`Plan:
@@ -2037,10 +2102,11 @@ Result:
2037
2102
  ${result}
2038
2103
 
2039
2104
  Review the implementation.`, {
2105
+ ...opts,
2040
2106
  model: plannerModel,
2041
2107
  maxTokens: 1024,
2042
2108
  thinkingLevel: "high",
2043
- system: REVIEW_SYSTEM
2109
+ system: mergeSystem(opts.system, REVIEW_SYSTEM)
2044
2110
  });
2045
2111
  const shouldContinue = review.includes("ITERATE") && !review.includes("DONE");
2046
2112
  iterations.push({
@@ -2076,28 +2142,7 @@ Original goal: ${goal}`;
2076
2142
  t1
2077
2143
  );
2078
2144
  }
2079
- function makeRalph(opts = {}) {
2080
- const merged = { ...defaults12, ...opts };
2081
- const fn = ((pieces, ...args) => {
2082
- if (!Array.isArray(pieces)) {
2083
- return makeRalph({ ...merged, ...pieces });
2084
- }
2085
- return new PatternPromise((resolve, reject) => {
2086
- execute12(pieces, args, merged).then(resolve, reject);
2087
- });
2088
- });
2089
- let _quiet;
2090
- Object.defineProperty(fn, "quiet", {
2091
- get() {
2092
- if (!_quiet) _quiet = makeRalph({ ...merged, quiet: true });
2093
- return _quiet;
2094
- },
2095
- enumerable: true,
2096
- configurable: true
2097
- });
2098
- return fn;
2099
- }
2100
- var \u03A1 = makeRalph();
2145
+ var \u03A1 = createPatternTag(defaults12, execute12);
2101
2146
 
2102
2147
  // src/patterns/subagent.ts
2103
2148
  var defaults13 = {
@@ -2117,13 +2162,15 @@ var SubagentResult = class {
2117
2162
  success;
2118
2163
  };
2119
2164
  var SubagentOutput = class extends PatternOutput {
2120
- constructor(text, synthesis, subResults, startTime, endTime) {
2165
+ constructor(text, synthesis, subResults, startTime, endTime, qualityReview) {
2121
2166
  super(text, startTime, endTime);
2122
2167
  this.synthesis = synthesis;
2123
2168
  this.subResults = subResults;
2169
+ this.qualityReview = qualityReview;
2124
2170
  }
2125
2171
  synthesis;
2126
2172
  subResults;
2173
+ qualityReview;
2127
2174
  };
2128
2175
  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.`;
2129
2176
  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.`;
@@ -2136,10 +2183,11 @@ ${task}
2136
2183
 
2137
2184
  Output a JSON array of strings.`,
2138
2185
  {
2186
+ ...opts,
2139
2187
  model: opts.model,
2140
2188
  maxTokens: 1024,
2141
2189
  thinkingLevel: "medium",
2142
- system: DECOMPOSE_SYSTEM
2190
+ system: mergeSystem(opts.system, DECOMPOSE_SYSTEM)
2143
2191
  }
2144
2192
  );
2145
2193
  try {
@@ -2160,6 +2208,7 @@ var SUBAGENT_SYSTEM = `You are a domain specialist. Complete your assigned sub-t
2160
2208
  async function execute13(pieces, args, opts) {
2161
2209
  const task = build(pieces, args);
2162
2210
  const t0 = Date.now();
2211
+ const phases = [];
2163
2212
  const plannerModel = opts.plannerModel ?? opts.model;
2164
2213
  const workerModel = opts.workerModel ?? opts.model;
2165
2214
  if (!opts.quiet) {
@@ -2169,7 +2218,14 @@ async function execute13(pieces, args, opts) {
2169
2218
  );
2170
2219
  }
2171
2220
  if (!opts.quiet) process.stderr.write(" \u2192 Decomposing task into sub-tasks...\n");
2221
+ const decomposeStart = Date.now();
2172
2222
  const subTasks = await decomposeTask(task, { ...opts, model: plannerModel });
2223
+ phases.push({
2224
+ phase: "decompose",
2225
+ durationMs: Date.now() - decomposeStart,
2226
+ description: `Decomposed into ${subTasks.length} sub-task(s)`,
2227
+ modelUsed: plannerModel
2228
+ });
2173
2229
  if (!opts.quiet) {
2174
2230
  process.stderr.write(` \u2192 ${subTasks.length} sub-task(s) identified:
2175
2231
  `);
@@ -2179,27 +2235,37 @@ async function execute13(pieces, args, opts) {
2179
2235
  `);
2180
2236
  }
2181
2237
  }
2238
+ const subTaskSummary = `Execute ${subTasks.length} sub-task(s)?
2239
+ ${subTasks.map((st, i) => `${i + 1}. ${st.slice(0, 80)}`).join("\n ")}`;
2240
+ if (!await confirmPhase(subTaskSummary, opts)) {
2241
+ throw new Error("pizx/\u03A3: Execution cancelled by user.");
2242
+ }
2182
2243
  const subResults = [];
2183
2244
  const concurrency = opts.concurrency ?? 4;
2245
+ const execStart = Date.now();
2184
2246
  for (let i = 0; i < subTasks.length; i += concurrency) {
2185
2247
  const batch = subTasks.slice(i, i + concurrency);
2186
2248
  const batchResults = await Promise.allSettled(
2187
2249
  batch.map(
2188
- (st) => ask(st, {
2189
- model: workerModel,
2190
- maxTokens: opts.maxTokens,
2191
- thinkingLevel: opts.thinkingLevel,
2192
- system: SUBAGENT_SYSTEM
2193
- }).then((text) => new SubagentResult(st, text, true)).catch((err) => new SubagentResult(st, String(err), false))
2250
+ (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))
2194
2251
  )
2195
2252
  );
2196
2253
  batchResults.forEach((r) => {
2197
2254
  if (r.status === "fulfilled") subResults.push(r.value);
2198
2255
  });
2199
2256
  }
2257
+ const succeeded = subResults.filter((r) => r.success).length;
2258
+ phases.push({
2259
+ phase: "execute",
2260
+ durationMs: Date.now() - execStart,
2261
+ description: `Executed ${subResults.length} sub-task(s), ${succeeded} succeeded`,
2262
+ modelUsed: workerModel,
2263
+ callCount: subResults.length
2264
+ });
2200
2265
  if (!opts.quiet) process.stderr.write(" \u2192 Synthesizing results...\n");
2201
2266
  const subResultsText = subResults.map((sr, i) => `Sub-task ${i + 1}: ${sr.subTask}
2202
2267
  Result: ${sr.text}`).join("\n\n");
2268
+ const synthStart = Date.now();
2203
2269
  const synthesis = await ask(
2204
2270
  `Original task:
2205
2271
  ${task}
@@ -2208,38 +2274,31 @@ Sub-task results:
2208
2274
  ${subResultsText}
2209
2275
 
2210
2276
  Synthesize a comprehensive answer.`,
2211
- {
2212
- model: plannerModel,
2213
- maxTokens: opts.maxTokens,
2214
- thinkingLevel: opts.thinkingLevel,
2215
- system: SYNTHESIS_SYSTEM5
2216
- }
2277
+ { ...opts, model: plannerModel, system: mergeSystem(opts.system, SYNTHESIS_SYSTEM5) }
2217
2278
  );
2218
- const t1 = Date.now();
2219
- return new SubagentOutput(synthesis, synthesis, subResults, t0, t1);
2220
- }
2221
- function makeSubagent(opts = {}) {
2222
- const merged = { ...defaults13, ...opts };
2223
- const fn = ((pieces, ...args) => {
2224
- if (!Array.isArray(pieces)) {
2225
- return makeSubagent({ ...merged, ...pieces });
2226
- }
2227
- return new PatternPromise((resolve, reject) => {
2228
- execute13(pieces, args, merged).then(resolve, reject);
2229
- });
2230
- });
2231
- let _quiet;
2232
- Object.defineProperty(fn, "quiet", {
2233
- get() {
2234
- if (!_quiet) _quiet = makeSubagent({ ...merged, quiet: true });
2235
- return _quiet;
2236
- },
2237
- enumerable: true,
2238
- configurable: true
2279
+ phases.push({
2280
+ phase: "synthesize",
2281
+ durationMs: Date.now() - synthStart,
2282
+ description: "Synthesized sub-agent results",
2283
+ modelUsed: plannerModel
2239
2284
  });
2240
- return fn;
2285
+ if (!opts.quiet && opts.qualityCheck) process.stderr.write(" \u2192 Quality review...\n");
2286
+ const qStart = Date.now();
2287
+ const qualityReview = await runQualityReview(task, synthesis, opts);
2288
+ if (qualityReview) {
2289
+ phases.push({
2290
+ phase: "quality-review",
2291
+ durationMs: Date.now() - qStart,
2292
+ description: `Score: ${qualityReview.score.toFixed(2)}`,
2293
+ modelUsed: plannerModel
2294
+ });
2295
+ }
2296
+ const t1 = Date.now();
2297
+ const output = new SubagentOutput(synthesis, synthesis, subResults, t0, t1, qualityReview);
2298
+ output.phaseLog = phases;
2299
+ return output;
2241
2300
  }
2242
- var \u03A3 = makeSubagent();
2301
+ var \u03A3 = createPatternTag(defaults13, execute13);
2243
2302
 
2244
2303
  // src/patterns/tau.ts
2245
2304
  var defaults14 = {
@@ -2263,15 +2322,17 @@ var ToolMediatedEntry = class {
2263
2322
  content;
2264
2323
  };
2265
2324
  var TauOutput = class extends PatternOutput {
2266
- constructor(text, entries, finalState, synthesis, startTime, endTime) {
2325
+ constructor(text, entries, finalState, synthesis, startTime, endTime, qualityReview) {
2267
2326
  super(text, startTime, endTime);
2268
2327
  this.entries = entries;
2269
2328
  this.finalState = finalState;
2270
2329
  this.synthesis = synthesis;
2330
+ this.qualityReview = qualityReview;
2271
2331
  }
2272
2332
  entries;
2273
2333
  finalState;
2274
2334
  synthesis;
2335
+ qualityReview;
2275
2336
  };
2276
2337
  var SCHEMA_SYSTEM = `You are a coordination architect. Given a task, design a shared structured context for agent collaboration.
2277
2338
 
@@ -2326,6 +2387,7 @@ async function defineSchema(task, opts) {
2326
2387
  const response = await ask(`Task: ${task}
2327
2388
 
2328
2389
  ${prompt}`, {
2390
+ ...opts,
2329
2391
  model: opts.plannerModel ?? opts.model,
2330
2392
  maxTokens: 1024,
2331
2393
  thinkingLevel: "high"
@@ -2378,10 +2440,9 @@ async function executeRound(roles, assignments, store, round, opts) {
2378
2440
  const systemPrompt = isWrite ? WRITE_SYSTEM(role, keysStr).replace("{store}", storeText) : UPDATE_SYSTEM(role, keysStr).replace("{store}", storeText);
2379
2441
  const task = isWrite ? `Write your initial findings to your assigned keys: ${keysStr}` : `Review the shared context and update your entries for keys: ${keysStr}`;
2380
2442
  const response = await ask(task, {
2443
+ ...opts,
2381
2444
  model: workerModel,
2382
- maxTokens: opts.maxTokens,
2383
- thinkingLevel: opts.thinkingLevel,
2384
- system: systemPrompt
2445
+ system: mergeSystem(opts.system, systemPrompt)
2385
2446
  });
2386
2447
  return { role, response };
2387
2448
  })
@@ -2421,10 +2482,10 @@ ${storeText}
2421
2482
 
2422
2483
  Consolidate into a comprehensive, well-structured synthesis.`,
2423
2484
  {
2485
+ ...opts,
2424
2486
  model: opts.plannerModel ?? opts.model,
2425
- maxTokens: opts.maxTokens,
2426
2487
  thinkingLevel: "high",
2427
- system: CONSOLIDATE_SYSTEM
2488
+ system: mergeSystem(opts.system, CONSOLIDATE_SYSTEM)
2428
2489
  }
2429
2490
  );
2430
2491
  }
@@ -2469,6 +2530,8 @@ async function execute14(pieces, args, opts) {
2469
2530
  }
2470
2531
  if (!opts.quiet) process.stderr.write(" \u2192 Consolidating store...\n");
2471
2532
  const synthesis = await consolidateStore(task, store, { ...opts, plannerModel });
2533
+ if (!opts.quiet && opts.qualityCheck) process.stderr.write(" \u2192 Quality review...\n");
2534
+ const qualityReview = await runQualityReview(task, synthesis, opts);
2472
2535
  const t1 = Date.now();
2473
2536
  const summary = [
2474
2537
  `Schema keys: ${keys.join(", ")}`,
@@ -2477,30 +2540,9 @@ async function execute14(pieces, args, opts) {
2477
2540
  `Entries: ${allEntries.length}`,
2478
2541
  `Synthesis: ${synthesis}`
2479
2542
  ].join("\n\n");
2480
- return new TauOutput(summary, allEntries, store, synthesis, t0, t1);
2481
- }
2482
- function makeTau(opts = {}) {
2483
- const merged = { ...defaults14, ...opts };
2484
- const fn = ((pieces, ...args) => {
2485
- if (!Array.isArray(pieces)) {
2486
- return makeTau({ ...merged, ...pieces });
2487
- }
2488
- return new PatternPromise((resolve, reject) => {
2489
- execute14(pieces, args, merged).then(resolve, reject);
2490
- });
2491
- });
2492
- let _quiet;
2493
- Object.defineProperty(fn, "quiet", {
2494
- get() {
2495
- if (!_quiet) _quiet = makeTau({ ...merged, quiet: true });
2496
- return _quiet;
2497
- },
2498
- enumerable: true,
2499
- configurable: true
2500
- });
2501
- return fn;
2543
+ return new TauOutput(summary, allEntries, store, synthesis, t0, t1, qualityReview);
2502
2544
  }
2503
- var \u03A4 = makeTau();
2545
+ var \u03A4 = createPatternTag(defaults14, execute14);
2504
2546
 
2505
2547
  // src/patterns/thread.ts
2506
2548
  var defaults15 = {
@@ -2509,27 +2551,6 @@ var defaults15 = {
2509
2551
  agents: 3,
2510
2552
  turns: 3
2511
2553
  };
2512
- var ROLE_SETS4 = {
2513
- 2: ["Proposer \u2014 advocate the best approach", "Critic \u2014 identify weaknesses and gaps"],
2514
- 3: [
2515
- "Proposer \u2014 suggest the best approach",
2516
- "Critic \u2014 identify weaknesses, risks, and missing pieces",
2517
- "Synthesizer \u2014 combine the best ideas into a practical plan"
2518
- ],
2519
- 4: [
2520
- "Proposer \u2014 advocate a bold solution",
2521
- "Critic \u2014 identify risks and weaknesses",
2522
- "Pragmatist \u2014 focus on practical implementation",
2523
- "Innovator \u2014 propose creative alternatives"
2524
- ],
2525
- 5: [
2526
- "Proposer",
2527
- "Critic",
2528
- "Pragmatist",
2529
- "Innovator",
2530
- "Devil's Advocate \u2014 challenge every assumption"
2531
- ]
2532
- };
2533
2554
  var ThreadMessage = class {
2534
2555
  constructor(role, turn, content) {
2535
2556
  this.role = role;
@@ -2541,13 +2562,15 @@ var ThreadMessage = class {
2541
2562
  content;
2542
2563
  };
2543
2564
  var ThreadOutput = class extends PatternOutput {
2544
- constructor(text, conclusion, messages, startTime, endTime) {
2565
+ constructor(text, conclusion, messages, startTime, endTime, qualityReview) {
2545
2566
  super(text, startTime, endTime);
2546
2567
  this.conclusion = conclusion;
2547
2568
  this.messages = messages;
2569
+ this.qualityReview = qualityReview;
2548
2570
  }
2549
2571
  conclusion;
2550
2572
  messages;
2573
+ qualityReview;
2551
2574
  };
2552
2575
  var THREAD_PROMPT = `You are an agent with the role: {role}.
2553
2576
  Engage in a multi-agent conversation about the topic.
@@ -2569,7 +2592,7 @@ async function execute15(pieces, args, opts) {
2569
2592
  const t0 = Date.now();
2570
2593
  const agentCount = opts.agents ?? 3;
2571
2594
  const maxTurns = opts.turns ?? 3;
2572
- const roles = opts.roles ?? ROLE_SETS4[agentCount] ?? ROLE_SETS4[3] ?? [];
2595
+ const roles = opts.roles ?? THREAD_ROLE_SETS[agentCount] ?? THREAD_ROLE_SETS[3] ?? [];
2573
2596
  const plannerModel = opts.plannerModel ?? opts.model;
2574
2597
  const workerModel = opts.workerModel ?? opts.model;
2575
2598
  if (!opts.quiet) {
@@ -2587,11 +2610,7 @@ async function execute15(pieces, args, opts) {
2587
2610
  for (let a = 0; a < roles.length; a++) {
2588
2611
  const role = roles[a] ?? `Agent ${a + 1}`;
2589
2612
  const prompt = buildThreadPrompt(role, thread);
2590
- const response = await ask(prompt, {
2591
- model: workerModel,
2592
- maxTokens: opts.maxTokens,
2593
- thinkingLevel: opts.thinkingLevel
2594
- });
2613
+ const response = await ask(prompt, { ...opts, model: workerModel });
2595
2614
  messages.push(new ThreadMessage(role, turn, response));
2596
2615
  thread += `
2597
2616
  [${role}] (Turn ${turn}): ${response}
@@ -2607,46 +2626,24 @@ ${thread}
2607
2626
 
2608
2627
  Synthesize a clear, actionable conclusion.`,
2609
2628
  {
2629
+ ...opts,
2610
2630
  model: plannerModel,
2611
- maxTokens: opts.maxTokens,
2612
2631
  thinkingLevel: "high",
2613
- system: SYNTHESIS_SYSTEM6
2632
+ system: mergeSystem(opts.system, SYNTHESIS_SYSTEM6)
2614
2633
  }
2615
2634
  );
2635
+ if (!opts.quiet && opts.qualityCheck) process.stderr.write(" \u2192 Quality review...\n");
2636
+ const qualityReview = await runQualityReview(topic, conclusion, opts);
2616
2637
  const t1 = Date.now();
2617
2638
  const summary = messages.map(
2618
2639
  (m) => `[${m.role}] Turn ${m.turn}: ${m.content.slice(0, 150)}${m.content.length > 150 ? "..." : ""}`
2619
2640
  ).join("\n");
2620
- return new ThreadOutput(summary, conclusion, messages, t0, t1);
2621
- }
2622
- function makeThread(opts = {}) {
2623
- const merged = { ...defaults15, ...opts };
2624
- const fn = ((pieces, ...args) => {
2625
- if (!Array.isArray(pieces)) {
2626
- return makeThread({ ...merged, ...pieces });
2627
- }
2628
- return new PatternPromise((resolve, reject) => {
2629
- execute15(pieces, args, merged).then(resolve, reject);
2630
- });
2631
- });
2632
- let _quiet;
2633
- Object.defineProperty(fn, "quiet", {
2634
- get() {
2635
- if (!_quiet) _quiet = makeThread({ ...merged, quiet: true });
2636
- return _quiet;
2637
- },
2638
- enumerable: true,
2639
- configurable: true
2640
- });
2641
- return fn;
2641
+ return new ThreadOutput(summary, conclusion, messages, t0, t1, qualityReview);
2642
2642
  }
2643
- var \u0398 = makeThread();
2643
+ var \u0398 = createPatternTag(defaults15, execute15);
2644
2644
 
2645
2645
  // src/pi.ts
2646
2646
  import {
2647
- getEnvApiKey as getEnvApiKey2,
2648
- getModels as getModels2,
2649
- getProviders as getProviders2,
2650
2647
  streamSimple
2651
2648
  } from "@earendil-works/pi-ai";
2652
2649
 
@@ -2664,10 +2661,28 @@ var PiOutput = class {
2664
2661
  events;
2665
2662
  startTime;
2666
2663
  endTime;
2664
+ /** Trace entry for this single LLM call. Populated by the π tag. */
2665
+ trace = [];
2667
2666
  /** Duration in milliseconds */
2668
2667
  get duration() {
2669
2668
  return this.endTime - this.startTime;
2670
2669
  }
2670
+ /** Total input tokens (convenience accessor) */
2671
+ get inputTokens() {
2672
+ return this.trace[0]?.inputTokens ?? 0;
2673
+ }
2674
+ /** Total output tokens (convenience accessor) */
2675
+ get outputTokens() {
2676
+ return this.trace[0]?.outputTokens ?? 0;
2677
+ }
2678
+ /** Total tokens (convenience accessor) */
2679
+ get totalTokens() {
2680
+ return this.trace[0]?.totalTokens ?? 0;
2681
+ }
2682
+ /** Total cost in USD (convenience accessor) */
2683
+ get totalCost() {
2684
+ return this.trace[0]?.cost ?? 0;
2685
+ }
2671
2686
  toString() {
2672
2687
  return this.text;
2673
2688
  }
@@ -2693,90 +2708,13 @@ var defaults16 = {
2693
2708
  quiet: false,
2694
2709
  maxTokens: 4096
2695
2710
  };
2696
- var _piSettings2;
2697
- function getPiDefaults2() {
2698
- if (_piSettings2 === void 0) {
2699
- _piSettings2 = isPiInstalled() ? loadPiSettings() : {};
2700
- }
2701
- return _piSettings2;
2702
- }
2703
- function allModels2() {
2704
- const result = [];
2705
- for (const p of getProviders2()) {
2706
- const ms = getModels2(p);
2707
- if (ms && ms.length > 0) result.push(...ms);
2708
- }
2709
- return result;
2710
- }
2711
- function getConfiguredProviders2() {
2712
- return getProviders2().filter((p) => getEnvApiKey2(p) !== void 0);
2713
- }
2714
- function configuredModels2() {
2715
- const configured = new Set(getConfiguredProviders2());
2716
- return allModels2().filter((m) => configured.has(m.provider));
2717
- }
2718
- function findModelById2(id) {
2719
- const all = allModels2();
2720
- if (id.includes("/")) {
2721
- const [provider, modelId] = id.split("/", 2);
2722
- return all.find(
2723
- (m) => m.provider === provider && (m.id === modelId || m.id.endsWith(`/${modelId}`))
2724
- );
2725
- }
2726
- return all.find((m) => m.id === id || m.id.endsWith(`/${id}`));
2727
- }
2728
- function pickModel2(preferred) {
2729
- if (preferred) {
2730
- const hit = findModelById2(preferred);
2731
- if (hit) return hit;
2732
- }
2733
- const settings = getPiDefaults2();
2734
- if (settings.defaultModel) {
2735
- const hit = findModelById2(settings.defaultModel);
2736
- if (hit) return hit;
2737
- }
2738
- if (settings.defaultProvider) {
2739
- const providerModels = getModels2(settings.defaultProvider);
2740
- if (providerModels && providerModels.length > 0) {
2741
- const configured = new Set(getConfiguredProviders2());
2742
- if (configured.has(settings.defaultProvider)) {
2743
- return providerModels[0];
2744
- }
2745
- }
2746
- }
2747
- const available = configuredModels2();
2748
- if (available.length > 0) {
2749
- const order2 = ["claude-sonnet-4-5", "claude-sonnet-4", "gemini-2.5-flash", "gpt-4o-mini"];
2750
- for (const id of order2) {
2751
- const m = available.find((m2) => m2.id.includes(id));
2752
- if (m) return m;
2753
- }
2754
- return available[0];
2755
- }
2756
- const models = allModels2();
2757
- if (models.length === 0) return void 0;
2758
- const order = ["claude-sonnet-4-5", "claude-sonnet-4", "gemini-2.5-flash", "gpt-4o-mini"];
2759
- for (const id of order) {
2760
- const m = models.find((m2) => m2.id.includes(id));
2761
- if (m) return m;
2762
- }
2763
- return models[0];
2764
- }
2765
- function build2(pieces, args) {
2766
- let s = "";
2767
- for (let i = 0; i < pieces.length; i++) {
2768
- s += pieces[i];
2769
- if (i < args.length) s += String(args[i]);
2770
- }
2771
- return s;
2772
- }
2773
2711
  function makeContext(pieces, args, opts) {
2774
2712
  return {
2775
2713
  systemPrompt: opts.system,
2776
2714
  messages: [
2777
2715
  {
2778
2716
  role: "user",
2779
- content: build2(pieces, args),
2717
+ content: build(pieces, args),
2780
2718
  timestamp: Date.now()
2781
2719
  }
2782
2720
  ]
@@ -2785,25 +2723,51 @@ function makeContext(pieces, args, opts) {
2785
2723
  function makeOpts(opts) {
2786
2724
  return {
2787
2725
  maxTokens: opts.maxTokens,
2788
- reasoning: opts.thinkingLevel
2726
+ reasoning: opts.thinkingLevel,
2727
+ timeoutMs: opts.timeoutMs,
2728
+ maxRetries: opts.maxRetries
2789
2729
  };
2790
2730
  }
2791
2731
  async function run(pieces, args, opts) {
2792
- const model = pickModel2(opts.model);
2732
+ const model = pickModel(opts.model);
2793
2733
  if (!model) throw new Error("pizx/\u03C0: No AI models configured. Run `pi auth login` first.");
2794
2734
  const t0 = Date.now();
2795
2735
  let text = "";
2796
- for await (const ev of streamSimple(model, makeContext(pieces, args, opts), makeOpts(opts))) {
2797
- if (ev.type === "text_delta") {
2798
- text += ev.delta;
2799
- if (!opts.quiet) process.stdout.write(ev.delta);
2736
+ let traceEntry;
2737
+ try {
2738
+ for await (const ev of streamSimple(model, makeContext(pieces, args, opts), makeOpts(opts))) {
2739
+ if (ev.type === "text_delta") {
2740
+ text += ev.delta;
2741
+ if (!opts.quiet) process.stdout.write(ev.delta);
2742
+ } else if (ev.type === "done") {
2743
+ const msg = ev.message;
2744
+ if (msg?.usage) {
2745
+ traceEntry = {
2746
+ call: 1,
2747
+ modelId: model.id,
2748
+ promptPreview: build(pieces, args).slice(0, 200),
2749
+ outputPreview: text.slice(0, 200),
2750
+ inputTokens: msg.usage.input,
2751
+ outputTokens: msg.usage.output,
2752
+ cacheReadTokens: msg.usage.cacheRead,
2753
+ cacheWriteTokens: msg.usage.cacheWrite,
2754
+ totalTokens: msg.usage.totalTokens,
2755
+ cost: msg.usage.cost.total,
2756
+ durationMs: Date.now() - t0
2757
+ };
2758
+ }
2759
+ }
2800
2760
  }
2761
+ } catch (err) {
2762
+ throw new Error(`pizx/\u03C0: AI generation failed: ${getErrorMessage(err)}`);
2801
2763
  }
2802
2764
  if (!opts.quiet && text) process.stdout.write("\n");
2803
- return new PiOutput(text.trim(), model.id, [], t0, Date.now());
2765
+ const output = new PiOutput(text.trim(), model.id, [], t0, Date.now());
2766
+ if (traceEntry) output.trace = [traceEntry];
2767
+ return output;
2804
2768
  }
2805
2769
  async function* runStream(pieces, args, opts) {
2806
- const model = pickModel2(opts.model);
2770
+ const model = pickModel(opts.model);
2807
2771
  if (!model) throw new Error("pizx/\u03C0: No AI models configured");
2808
2772
  for await (const ev of streamSimple(model, makeContext(pieces, args, opts), makeOpts(opts))) {
2809
2773
  if (ev.type === "text_delta") yield ev.delta;
@@ -2880,22 +2844,18 @@ var AgentPromise = class extends Promise {
2880
2844
  var _sharedSession = null;
2881
2845
  async function getSession(opts) {
2882
2846
  if (_sharedSession && !opts.model) return _sharedSession;
2883
- const result = await createAgentSession2({
2884
- cwd: opts.cwd,
2885
- thinkingLevel: opts.thinkingLevel,
2886
- tools: opts.tools,
2887
- excludeTools: opts.excludeTools
2888
- });
2889
- _sharedSession = result.session;
2890
- return _sharedSession;
2891
- }
2892
- function build3(pieces, args) {
2893
- let s = "";
2894
- for (let i = 0; i < pieces.length; i++) {
2895
- s += pieces[i];
2896
- if (i < args.length) s += String(args[i]);
2847
+ try {
2848
+ const result = await createAgentSession2({
2849
+ cwd: opts.cwd,
2850
+ thinkingLevel: opts.thinkingLevel,
2851
+ tools: opts.tools,
2852
+ excludeTools: opts.excludeTools
2853
+ });
2854
+ _sharedSession = result.session;
2855
+ return _sharedSession;
2856
+ } catch (err) {
2857
+ throw new Error(`pizx/\u03A0: Failed to create agent session: ${getErrorMessage(err)}`);
2897
2858
  }
2898
- return s.trim();
2899
2859
  }
2900
2860
  function getMessageText(msg) {
2901
2861
  const content = msg.content;
@@ -2917,7 +2877,7 @@ function getLastAssistantText(session) {
2917
2877
  return "";
2918
2878
  }
2919
2879
  async function execute16(pieces, args, opts) {
2920
- const prompt = build3(pieces, args);
2880
+ const prompt = build(pieces, args);
2921
2881
  const session = await getSession(opts);
2922
2882
  const t0 = Date.now();
2923
2883
  if (!opts.quiet) {
@@ -2928,15 +2888,12 @@ async function execute16(pieces, args, opts) {
2928
2888
  await session.sendUserMessage(prompt);
2929
2889
  const t1 = Date.now();
2930
2890
  const text = getLastAssistantText(session);
2931
- const turnCount = session.messages.filter(
2932
- (m) => m.role === "assistant"
2933
- ).length;
2891
+ const turnCount = session.messages.filter((m) => m.role === "assistant").length;
2934
2892
  return new AgentOutput(text || "(no assistant response)", turnCount, t0, t1);
2935
2893
  } catch (err) {
2936
2894
  const t1 = Date.now();
2937
- const msg = err instanceof Error ? err.message : String(err);
2938
2895
  console.error("\u03A0 error:", err);
2939
- return new AgentOutput(`\u03A0 error: ${msg}`, 0, t0, t1);
2896
+ return new AgentOutput(`\u03A0 error: ${getErrorMessage(err)}`, 0, t0, t1);
2940
2897
  }
2941
2898
  }
2942
2899
  function makeAgent(opts = {}) {
@@ -2998,7 +2955,7 @@ function parseArgs(argv) {
2998
2955
  if (argv[i + 1] && !argv[i + 1].startsWith("-")) flags.model = argv[++i];
2999
2956
  break;
3000
2957
  case "--system":
3001
- if (argv[i + 1]) flags.system = argv[++i];
2958
+ if (argv[i + 1] && !argv[i + 1].startsWith("-")) flags.system = argv[++i];
3002
2959
  break;
3003
2960
  case "-q":
3004
2961
  case "--quiet":
@@ -3039,6 +2996,7 @@ function printHelp() {
3039
2996
  \`\u039B\` Pipeline \u2014 sequential agent chain
3040
2997
  \`\u03A8\` Critique \u2014 generate, critique, improve
3041
2998
  \`\u03A9\` Orchestrator \u2014 plan, dispatch, synthesize
2999
+ \`\u039D\` Nu \u2014 Self-Organizing Teams
3042
3000
 
3043
3001
  ${chalk.bold("Communication Patterns")}
3044
3002
  \`\u0398\` Thread \u2014 multi-agent conversation
@@ -3048,6 +3006,8 @@ function printHelp() {
3048
3006
  ${chalk.bold("Orchestration Topologies")}
3049
3007
  \`\u0391\` Adaptive \u2014 self-adjusting orchestration
3050
3008
  \`\u0393\` Graph \u2014 DAG-based task execution
3009
+ \`\u03A7\` Chi \u2014 Cross-Agent Learning
3010
+ \`\u03A4\` Tau \u2014 Tool-Mediated Orchestration
3051
3011
 
3052
3012
  ${chalk.bold("Example Script")}
3053
3013
  #!/usr/bin/env pizx
@@ -3078,7 +3038,7 @@ async function runPrintMode(flags, args) {
3078
3038
  `);
3079
3039
  }
3080
3040
  } catch (err) {
3081
- console.error("pizx: pi-ai error:", err instanceof Error ? err.message : err);
3041
+ console.error("pizx: pi-ai error:", getErrorMessage(err));
3082
3042
  process2.exit(1);
3083
3043
  }
3084
3044
  }
@@ -3098,6 +3058,9 @@ async function runScriptMode(scriptPath) {
3098
3058
  g.\u03A9 = \u03A9;
3099
3059
  g.\u0398 = \u0398;
3100
3060
  g.\u039C = \u039C;
3061
+ g.\u039D = \u039D;
3062
+ g.\u03A4 = \u03A4;
3063
+ g.\u03A7 = \u03A7;
3101
3064
  g.\u0392 = \u0392;
3102
3065
  g.\u0391 = \u0391;
3103
3066
  g.\u0393 = \u0393;
@@ -3109,11 +3072,7 @@ async function runScriptMode(scriptPath) {
3109
3072
  try {
3110
3073
  await import(url.pathToFileURL(absPath).toString());
3111
3074
  } catch (err) {
3112
- if (err instanceof Error) {
3113
- console.error("pizx:", err.message);
3114
- } else {
3115
- console.error("pizx:", err);
3116
- }
3075
+ console.error("pizx:", getErrorMessage(err));
3117
3076
  process2.exit(1);
3118
3077
  }
3119
3078
  }
@@ -3140,7 +3099,7 @@ async function main() {
3140
3099
  await runScriptMode(script);
3141
3100
  }
3142
3101
  main().catch((err) => {
3143
- console.error("pizx:", err instanceof Error ? err.message : err);
3102
+ console.error("pizx:", getErrorMessage(err));
3144
3103
  process2.exit(1);
3145
3104
  });
3146
3105
  //# sourceMappingURL=cli.js.map