pi-background-tasks 0.7.7 → 0.9.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/PUBLISHING.md +7 -7
- package/README.md +64 -7
- package/TEST_PLAN.md +8 -1
- package/package.json +7 -2
- package/src/core/delegate/launch.ts +1 -0
- package/src/core/fusion/artifacts.ts +49 -4
- package/src/core/fusion/budget.ts +21 -12
- package/src/core/fusion/context.ts +7 -2
- package/src/core/fusion/orchestrator.ts +70 -15
- package/src/core/fusion/pi-child.ts +473 -8
- package/src/core/fusion/prompts.ts +151 -3
- package/src/core/fusion/types.ts +84 -2
- package/src/core/fusion/web-fetch.ts +904 -0
- package/src/core/fusion/workflows.ts +130 -0
- package/src/fusion-child-extension.ts +279 -2
- package/src/fusion-extension.ts +182 -27
|
@@ -13,10 +13,6 @@ import {
|
|
|
13
13
|
} from './evaluation.js';
|
|
14
14
|
import { FusionChildRunError, runPiChild, type RunPiChildOptions } from './pi-child.js';
|
|
15
15
|
import {
|
|
16
|
-
FUSION_CANDIDATE_SYSTEM_PROMPT,
|
|
17
|
-
FUSION_EVALUATION_REPAIR_SYSTEM_PROMPT,
|
|
18
|
-
FUSION_EVALUATOR_SYSTEM_PROMPT,
|
|
19
|
-
FUSION_MERGER_SYSTEM_PROMPT,
|
|
20
16
|
buildBlindEvaluationInput,
|
|
21
17
|
buildCandidatePrompt,
|
|
22
18
|
buildEvaluationPrompt,
|
|
@@ -26,11 +22,18 @@ import {
|
|
|
26
22
|
type AnonymousFusionCandidate,
|
|
27
23
|
} from './prompts.js';
|
|
28
24
|
import {
|
|
25
|
+
FUSION_BRAINSTORM_WORKFLOW,
|
|
26
|
+
resolveWorkflowCapability,
|
|
27
|
+
type FusionWorkflowProfile,
|
|
28
|
+
} from './workflows.js';
|
|
29
|
+
import {
|
|
30
|
+
FUSION_DEFAULT_CAPABILITY,
|
|
29
31
|
FUSION_RESULT_SCHEMA_VERSION,
|
|
30
32
|
FusionError,
|
|
31
33
|
addFusionUsage,
|
|
32
34
|
createEmptyFusionUsage,
|
|
33
35
|
type FusionCalibrationViolation,
|
|
36
|
+
type FusionCapability,
|
|
34
37
|
type FusionCanonicalInputV3,
|
|
35
38
|
type FusionCandidateId,
|
|
36
39
|
type FusionContextOmissionLedgerV2,
|
|
@@ -62,6 +65,9 @@ export interface FusionWorkflowInput {
|
|
|
62
65
|
contextLedger: FusionContextOmissionLedgerV2;
|
|
63
66
|
config: FusionModelConfigV1;
|
|
64
67
|
models: ResolvedFusionModels;
|
|
68
|
+
candidateCapability?: FusionCapability | undefined;
|
|
69
|
+
/** Stage framing and capability policy. Defaults to the brainstorm workflow. */
|
|
70
|
+
profile?: FusionWorkflowProfile | undefined;
|
|
65
71
|
signal?: AbortSignal | undefined;
|
|
66
72
|
onProgress?: FusionProgressSink | undefined;
|
|
67
73
|
}
|
|
@@ -179,21 +185,25 @@ function childOptions(
|
|
|
179
185
|
model: ResolvedFusionModel,
|
|
180
186
|
stage: FusionStage,
|
|
181
187
|
attempt: number,
|
|
188
|
+
capability: FusionCapability,
|
|
182
189
|
systemPrompt: string,
|
|
183
190
|
userPrompt: string,
|
|
184
191
|
signal: AbortSignal,
|
|
185
192
|
slot?: CandidateSlot,
|
|
193
|
+
toolCallLogPath?: string,
|
|
186
194
|
): RunPiChildOptions {
|
|
187
195
|
const out: RunPiChildOptions = {
|
|
188
196
|
stage,
|
|
189
197
|
attempt,
|
|
190
198
|
cwd: input.cwd,
|
|
191
199
|
model,
|
|
200
|
+
capability,
|
|
192
201
|
systemPrompt,
|
|
193
202
|
userPrompt,
|
|
194
203
|
signal,
|
|
195
204
|
};
|
|
196
205
|
if (slot !== undefined) out.slot = slot;
|
|
206
|
+
if (toolCallLogPath !== undefined) out.toolCallLogPath = toolCallLogPath;
|
|
197
207
|
return out;
|
|
198
208
|
}
|
|
199
209
|
|
|
@@ -324,11 +334,22 @@ export class FusionOrchestrator {
|
|
|
324
334
|
}
|
|
325
335
|
|
|
326
336
|
async run(input: FusionWorkflowInput): Promise<FusionRunResult> {
|
|
337
|
+
const profile = input.profile ?? FUSION_BRAINSTORM_WORKFLOW;
|
|
338
|
+
// Workflow policy, not caller input: a fixed-capability workflow rejects each
|
|
339
|
+
// other capability here, before a single child exists, rather than silently
|
|
340
|
+
// substituting its own and running a review that never read the code.
|
|
341
|
+
const candidateCapability = resolveWorkflowCapability(profile, input.candidateCapability);
|
|
327
342
|
const storeOptions: CreateFusionArtifactStoreOptions = {
|
|
328
343
|
cwd: input.cwd,
|
|
344
|
+
profile,
|
|
329
345
|
source: input.source,
|
|
330
346
|
config: input.config,
|
|
331
347
|
models: input.models,
|
|
348
|
+
capabilities: {
|
|
349
|
+
candidate: candidateCapability,
|
|
350
|
+
evaluation: FUSION_DEFAULT_CAPABILITY,
|
|
351
|
+
merge: FUSION_DEFAULT_CAPABILITY,
|
|
352
|
+
},
|
|
332
353
|
};
|
|
333
354
|
if (input.sessionId !== undefined) storeOptions.sessionId = input.sessionId;
|
|
334
355
|
if (this.now !== undefined) storeOptions.now = this.now;
|
|
@@ -344,6 +365,8 @@ export class FusionOrchestrator {
|
|
|
344
365
|
const budget = new FusionBudget(
|
|
345
366
|
input.models,
|
|
346
367
|
input.canonicalInput.conversation_projection.policy.id,
|
|
368
|
+
candidateCapability,
|
|
369
|
+
profile,
|
|
347
370
|
);
|
|
348
371
|
const budgetPlan = budget.plan(input.canonicalInput);
|
|
349
372
|
await store.writeBudgetPlan(budgetPlan);
|
|
@@ -363,6 +386,8 @@ export class FusionOrchestrator {
|
|
|
363
386
|
usage,
|
|
364
387
|
budget,
|
|
365
388
|
calibrationWarnings,
|
|
389
|
+
profile,
|
|
390
|
+
candidateCapability,
|
|
366
391
|
);
|
|
367
392
|
await store.transition('candidates_complete');
|
|
368
393
|
input.onProgress?.({ type: 'state', state: 'candidates_complete' });
|
|
@@ -381,6 +406,7 @@ export class FusionOrchestrator {
|
|
|
381
406
|
blindInput,
|
|
382
407
|
budget,
|
|
383
408
|
calibrationWarnings,
|
|
409
|
+
profile,
|
|
384
410
|
);
|
|
385
411
|
await store.writeEvaluationJson(evaluation);
|
|
386
412
|
await store.transition('evaluation_complete');
|
|
@@ -390,7 +416,7 @@ export class FusionOrchestrator {
|
|
|
390
416
|
input.onProgress?.({ type: 'state', state: 'merging' });
|
|
391
417
|
const mergeInput = buildMergeInput(input.canonicalInput, shuffled.candidates, evaluation);
|
|
392
418
|
const mergePrompt = buildMergePrompt(mergeInput);
|
|
393
|
-
budget.assertStagePrompt('merge',
|
|
419
|
+
budget.assertStagePrompt('merge', profile.mergerSystemPrompt, mergePrompt);
|
|
394
420
|
input.onProgress?.({ type: 'merge_started' });
|
|
395
421
|
const merged = await this.runChildWithRetry(
|
|
396
422
|
input,
|
|
@@ -398,9 +424,11 @@ export class FusionOrchestrator {
|
|
|
398
424
|
usage,
|
|
399
425
|
input.models.merger,
|
|
400
426
|
'merge',
|
|
401
|
-
|
|
427
|
+
profile.mergerSystemPrompt,
|
|
402
428
|
mergePrompt,
|
|
403
429
|
input.signal ?? new AbortController().signal,
|
|
430
|
+
// Stage policy, not caller input: evaluator and merger are always reasoning-only.
|
|
431
|
+
FUSION_DEFAULT_CAPABILITY,
|
|
404
432
|
undefined,
|
|
405
433
|
'md',
|
|
406
434
|
);
|
|
@@ -412,7 +440,7 @@ export class FusionOrchestrator {
|
|
|
412
440
|
budget,
|
|
413
441
|
calibrationWarnings,
|
|
414
442
|
'merge',
|
|
415
|
-
|
|
443
|
+
profile.mergerSystemPrompt,
|
|
416
444
|
mergePrompt,
|
|
417
445
|
merged,
|
|
418
446
|
);
|
|
@@ -426,6 +454,7 @@ export class FusionOrchestrator {
|
|
|
426
454
|
details: {
|
|
427
455
|
schema_version: FUSION_RESULT_SCHEMA_VERSION,
|
|
428
456
|
run_id: store.runId,
|
|
457
|
+
workflow: profile.id,
|
|
429
458
|
source: input.source,
|
|
430
459
|
status: 'completed',
|
|
431
460
|
artifact_dir: store.artifactDir,
|
|
@@ -480,14 +509,17 @@ export class FusionOrchestrator {
|
|
|
480
509
|
usage: FusionUsage,
|
|
481
510
|
budget: FusionBudget,
|
|
482
511
|
calibrationWarnings: FusionCalibrationViolation[],
|
|
512
|
+
profile: FusionWorkflowProfile,
|
|
513
|
+
candidateCapability: FusionCapability,
|
|
483
514
|
): Promise<readonly CandidateResult[]> {
|
|
484
515
|
const controller = new AbortController();
|
|
485
516
|
const abortListener = () => controller.abort();
|
|
486
517
|
input.signal?.addEventListener('abort', abortListener, { once: true });
|
|
487
518
|
if (input.signal?.aborted) controller.abort();
|
|
519
|
+
const systemPrompt = profile.candidateSystemPrompt(candidateCapability);
|
|
488
520
|
const prompt = buildCandidatePrompt(input.canonicalInput);
|
|
489
521
|
for (const slot of [1, 2, 3] as const) {
|
|
490
|
-
budget.assertStagePrompt('candidate',
|
|
522
|
+
budget.assertStagePrompt('candidate', systemPrompt, prompt, slot);
|
|
491
523
|
}
|
|
492
524
|
let primaryError: unknown;
|
|
493
525
|
let completed = 0;
|
|
@@ -507,9 +539,10 @@ export class FusionOrchestrator {
|
|
|
507
539
|
usage,
|
|
508
540
|
model,
|
|
509
541
|
'candidate',
|
|
510
|
-
|
|
542
|
+
systemPrompt,
|
|
511
543
|
prompt,
|
|
512
544
|
controller.signal,
|
|
545
|
+
candidateCapability,
|
|
513
546
|
slot,
|
|
514
547
|
'md',
|
|
515
548
|
).then(async (result) => {
|
|
@@ -520,7 +553,7 @@ export class FusionOrchestrator {
|
|
|
520
553
|
budget,
|
|
521
554
|
calibrationWarnings,
|
|
522
555
|
'candidate',
|
|
523
|
-
|
|
556
|
+
systemPrompt,
|
|
524
557
|
prompt,
|
|
525
558
|
result,
|
|
526
559
|
slot,
|
|
@@ -562,9 +595,10 @@ export class FusionOrchestrator {
|
|
|
562
595
|
blindInput: Parameters<typeof buildEvaluationPrompt>[0],
|
|
563
596
|
budget: FusionBudget,
|
|
564
597
|
calibrationWarnings: FusionCalibrationViolation[],
|
|
598
|
+
profile: FusionWorkflowProfile,
|
|
565
599
|
): Promise<FusionEvaluationV1> {
|
|
566
600
|
const firstPrompt = buildEvaluationPrompt(blindInput);
|
|
567
|
-
budget.assertStagePrompt('evaluation',
|
|
601
|
+
budget.assertStagePrompt('evaluation', profile.evaluatorSystemPrompt, firstPrompt);
|
|
568
602
|
const first = await this.runEvaluationAttempt(
|
|
569
603
|
input,
|
|
570
604
|
store,
|
|
@@ -574,6 +608,7 @@ export class FusionOrchestrator {
|
|
|
574
608
|
firstPrompt,
|
|
575
609
|
1,
|
|
576
610
|
false,
|
|
611
|
+
profile,
|
|
577
612
|
);
|
|
578
613
|
if (first.evaluation !== undefined) return first.evaluation;
|
|
579
614
|
const errors = boundedEvaluationErrors(first.errors);
|
|
@@ -586,7 +621,7 @@ export class FusionOrchestrator {
|
|
|
586
621
|
});
|
|
587
622
|
budget.assertStagePrompt(
|
|
588
623
|
'evaluation_repair',
|
|
589
|
-
|
|
624
|
+
profile.evaluationRepairSystemPrompt,
|
|
590
625
|
repairPrompt,
|
|
591
626
|
);
|
|
592
627
|
const second = await this.runEvaluationAttempt(
|
|
@@ -598,6 +633,7 @@ export class FusionOrchestrator {
|
|
|
598
633
|
repairPrompt,
|
|
599
634
|
2,
|
|
600
635
|
true,
|
|
636
|
+
profile,
|
|
601
637
|
);
|
|
602
638
|
if (second.evaluation !== undefined) return second.evaluation;
|
|
603
639
|
throw new FusionError(
|
|
@@ -619,11 +655,12 @@ export class FusionOrchestrator {
|
|
|
619
655
|
prompt: string,
|
|
620
656
|
attempt: 1 | 2,
|
|
621
657
|
repair: boolean,
|
|
658
|
+
profile: FusionWorkflowProfile,
|
|
622
659
|
): Promise<EvaluationAttemptResult> {
|
|
623
660
|
input.onProgress?.({ type: 'evaluation_started', attempt, repair });
|
|
624
661
|
const systemPrompt = repair
|
|
625
|
-
?
|
|
626
|
-
:
|
|
662
|
+
? profile.evaluationRepairSystemPrompt
|
|
663
|
+
: profile.evaluatorSystemPrompt;
|
|
627
664
|
const result = await this.runChildWithRetry(
|
|
628
665
|
input,
|
|
629
666
|
store,
|
|
@@ -633,6 +670,8 @@ export class FusionOrchestrator {
|
|
|
633
670
|
systemPrompt,
|
|
634
671
|
prompt,
|
|
635
672
|
input.signal ?? new AbortController().signal,
|
|
673
|
+
// Stage policy, not caller input: evaluator and merger are always reasoning-only.
|
|
674
|
+
FUSION_DEFAULT_CAPABILITY,
|
|
636
675
|
undefined,
|
|
637
676
|
'txt',
|
|
638
677
|
attempt,
|
|
@@ -700,6 +739,7 @@ export class FusionOrchestrator {
|
|
|
700
739
|
systemPrompt: string,
|
|
701
740
|
userPrompt: string,
|
|
702
741
|
signal: AbortSignal,
|
|
742
|
+
capability: FusionCapability,
|
|
703
743
|
slot: CandidateSlot | undefined,
|
|
704
744
|
responseKind: 'md' | 'txt',
|
|
705
745
|
fixedAttempt?: 1 | 2,
|
|
@@ -709,9 +749,24 @@ export class FusionOrchestrator {
|
|
|
709
749
|
if (stage === 'candidate' && slot !== undefined) {
|
|
710
750
|
input.onProgress?.({ type: 'candidate_started', slot, attempt: logicalAttempt });
|
|
711
751
|
}
|
|
752
|
+
const toolCallLogPath =
|
|
753
|
+
capability !== 'reason'
|
|
754
|
+
? store.childToolCallLogPath(stage, slot, logicalAttempt)
|
|
755
|
+
: undefined;
|
|
712
756
|
try {
|
|
713
757
|
return await this.childRunner(
|
|
714
|
-
childOptions(
|
|
758
|
+
childOptions(
|
|
759
|
+
input,
|
|
760
|
+
model,
|
|
761
|
+
stage,
|
|
762
|
+
logicalAttempt,
|
|
763
|
+
capability,
|
|
764
|
+
systemPrompt,
|
|
765
|
+
userPrompt,
|
|
766
|
+
signal,
|
|
767
|
+
slot,
|
|
768
|
+
toolCallLogPath,
|
|
769
|
+
),
|
|
715
770
|
);
|
|
716
771
|
} catch (error) {
|
|
717
772
|
if (!signal.aborted && retryableSpawn(error, launchTry) && launchTry === 1) continue;
|