pi-background-tasks 0.7.4 → 0.7.6
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 +30 -10
- package/TESTING.md +1 -1
- package/TEST_PLAN.md +2 -2
- package/package.json +1 -1
- package/src/core/fusion/artifacts.ts +2 -2
- package/src/core/fusion/budget.ts +483 -199
- package/src/core/fusion/context.ts +81 -82
- package/src/core/fusion/orchestrator.ts +17 -15
- package/src/core/fusion/prompts.ts +7 -7
- package/src/core/fusion/types.ts +88 -62
- package/src/fusion-extension.ts +2 -0
package/src/core/fusion/types.ts
CHANGED
|
@@ -3,12 +3,12 @@ import type { Usage } from '@earendil-works/pi-ai';
|
|
|
3
3
|
export type FusionThinkingLevel = 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max';
|
|
4
4
|
|
|
5
5
|
export const FUSION_MODEL_CONFIG_SCHEMA_VERSION = 'pi-background-tasks.fusion-models.v1';
|
|
6
|
-
export const FUSION_INPUT_SCHEMA_VERSION = 'pi-background-tasks.fusion-input.
|
|
6
|
+
export const FUSION_INPUT_SCHEMA_VERSION = 'pi-background-tasks.fusion-input.v3';
|
|
7
7
|
export const FUSION_EVALUATION_SCHEMA_VERSION = 'pi-background-tasks.fusion-evaluation.v1';
|
|
8
8
|
export const FUSION_RESULT_SCHEMA_VERSION = 'pi-background-tasks.fusion-result.v2';
|
|
9
9
|
export const FUSION_MANIFEST_SCHEMA_VERSION = 'pi-background-tasks.fusion-manifest.v2';
|
|
10
|
-
export const FUSION_CONTEXT_LEDGER_SCHEMA_VERSION = 'pi-background-tasks.fusion-context-ledger.
|
|
11
|
-
export const FUSION_BUDGET_PLAN_SCHEMA_VERSION = 'pi-background-tasks.fusion-budget-plan.
|
|
10
|
+
export const FUSION_CONTEXT_LEDGER_SCHEMA_VERSION = 'pi-background-tasks.fusion-context-ledger.v2';
|
|
11
|
+
export const FUSION_BUDGET_PLAN_SCHEMA_VERSION = 'pi-background-tasks.fusion-budget-plan.v2';
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* Conversation-projection transform shared by every Fusion entry point.
|
|
@@ -18,12 +18,12 @@ export const FUSION_BUDGET_PLAN_SCHEMA_VERSION = 'pi-background-tasks.fusion-bud
|
|
|
18
18
|
* hash-accounted omission receipts. It never truncates retained text and never
|
|
19
19
|
* forwards raw image bytes.
|
|
20
20
|
*/
|
|
21
|
-
export const FUSION_CONTEXT_TRANSFORM_ID = 'visible-conversation-ledger-
|
|
21
|
+
export const FUSION_CONTEXT_TRANSFORM_ID = 'visible-conversation-ledger-v2';
|
|
22
22
|
export const FUSION_BRANCH_FILTER_ID = 'exclude-active-fusion-subtree-v1';
|
|
23
23
|
|
|
24
24
|
/** Entry-point specific context policies. Both use the same payload-exclusion transform. */
|
|
25
|
-
export const FUSION_TOOL_CONTEXT_POLICY_ID = 'fusion-tool-explicit-
|
|
26
|
-
export const FUSION_COMMAND_CONTEXT_POLICY_ID = 'fusion-command-conversation-
|
|
25
|
+
export const FUSION_TOOL_CONTEXT_POLICY_ID = 'fusion-tool-explicit-v2';
|
|
26
|
+
export const FUSION_COMMAND_CONTEXT_POLICY_ID = 'fusion-command-conversation-v2';
|
|
27
27
|
|
|
28
28
|
export const FUSION_IMAGE_OMISSION_PREFIX = '[Image omitted from fusion text transcript: ';
|
|
29
29
|
|
|
@@ -112,7 +112,7 @@ export interface ResolvedFusionModels {
|
|
|
112
112
|
|
|
113
113
|
export type FusionRequestAuthority = 'explicit_text' | 'directive_over_projected_conversation';
|
|
114
114
|
|
|
115
|
-
export interface
|
|
115
|
+
export interface FusionCanonicalRequestV3 {
|
|
116
116
|
/** Entry point that produced this request. */
|
|
117
117
|
source: FusionSource;
|
|
118
118
|
/** How children must weigh `text` against the projected conversation. */
|
|
@@ -144,11 +144,29 @@ export interface FusionOmittedEventRecord {
|
|
|
144
144
|
mime_type?: string;
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
-
export interface
|
|
147
|
+
export interface FusionOmittedActivityProjectionMapEntry {
|
|
148
|
+
canonical_entry_index: number;
|
|
149
|
+
entry_kind: 'omitted_activity';
|
|
150
|
+
ledger_index_first: number;
|
|
151
|
+
ledger_index_last: number;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export interface FusionLedgerOnlyImageProjectionMapEntry {
|
|
155
|
+
entry_kind: 'ledger_only_tool_result_image';
|
|
156
|
+
ledger_index_first: number;
|
|
157
|
+
ledger_index_last: number;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export type FusionContextProjectionMapEntry =
|
|
161
|
+
| FusionOmittedActivityProjectionMapEntry
|
|
162
|
+
| FusionLedgerOnlyImageProjectionMapEntry;
|
|
163
|
+
|
|
164
|
+
export interface FusionContextOmissionLedgerV2 {
|
|
148
165
|
schema_version: typeof FUSION_CONTEXT_LEDGER_SCHEMA_VERSION;
|
|
149
166
|
policy_id: string;
|
|
150
167
|
transform: typeof FUSION_CONTEXT_TRANSFORM_ID;
|
|
151
168
|
entries: readonly FusionOmittedEventRecord[];
|
|
169
|
+
projection_map: readonly FusionContextProjectionMapEntry[];
|
|
152
170
|
root_sha256: string;
|
|
153
171
|
}
|
|
154
172
|
|
|
@@ -169,26 +187,13 @@ export interface FusionOmittedRunCounts {
|
|
|
169
187
|
assistant_thinking?: number;
|
|
170
188
|
tool_calls?: number;
|
|
171
189
|
tool_result_texts?: number;
|
|
172
|
-
tool_result_images?: number;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/** Byte totals for one omitted run, using the same omit-when-zero rule. */
|
|
176
|
-
export interface FusionOmittedRunBytes {
|
|
177
|
-
assistant_thinking?: number;
|
|
178
|
-
tool_call_arguments?: number;
|
|
179
|
-
tool_result_text?: number;
|
|
180
|
-
tool_result_image?: number;
|
|
181
190
|
}
|
|
182
191
|
|
|
183
192
|
export interface FusionProjectionOmissionEntry {
|
|
184
193
|
kind: 'omitted_activity';
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
ledger_index_first: number;
|
|
188
|
-
ledger_index_last: number;
|
|
194
|
+
at: readonly [number, number];
|
|
195
|
+
bytes: number;
|
|
189
196
|
counts: FusionOmittedRunCounts;
|
|
190
|
-
payload_bytes: FusionOmittedRunBytes;
|
|
191
|
-
ledger_run_sha256: string;
|
|
192
197
|
}
|
|
193
198
|
|
|
194
199
|
export type FusionProjectionEntry = FusionProjectionTextEntry | FusionProjectionOmissionEntry;
|
|
@@ -196,7 +201,8 @@ export type FusionProjectionEntry = FusionProjectionTextEntry | FusionProjection
|
|
|
196
201
|
export interface FusionContextPolicyDescriptor {
|
|
197
202
|
id: string;
|
|
198
203
|
transform: typeof FUSION_CONTEXT_TRANSFORM_ID;
|
|
199
|
-
version:
|
|
204
|
+
version: 2;
|
|
205
|
+
receipt_format: 'omitted_activity.v2';
|
|
200
206
|
user_text: 'verbatim';
|
|
201
207
|
assistant_text: 'verbatim';
|
|
202
208
|
assistant_thinking: 'ledger_only';
|
|
@@ -238,21 +244,22 @@ export interface FusionProjectionAccounting {
|
|
|
238
244
|
tool_call_names: readonly FusionToolCallNameCount[];
|
|
239
245
|
ledger_entry_count: number;
|
|
240
246
|
ledger_root_sha256: string;
|
|
247
|
+
omission_receipt_utf8_bytes: number;
|
|
241
248
|
}
|
|
242
249
|
|
|
243
|
-
export interface
|
|
250
|
+
export interface FusionConversationProjectionV3 {
|
|
244
251
|
policy: FusionContextPolicyDescriptor;
|
|
245
252
|
branch_filter: FusionBranchFilterDescriptor;
|
|
246
253
|
entries: readonly FusionProjectionEntry[];
|
|
247
254
|
accounting: FusionProjectionAccounting;
|
|
248
255
|
}
|
|
249
256
|
|
|
250
|
-
export interface
|
|
257
|
+
export interface FusionCanonicalInputV3 {
|
|
251
258
|
schema_version: typeof FUSION_INPUT_SCHEMA_VERSION;
|
|
252
259
|
cwd: string;
|
|
253
260
|
system_prompt: string;
|
|
254
|
-
request:
|
|
255
|
-
conversation_projection:
|
|
261
|
+
request: FusionCanonicalRequestV3;
|
|
262
|
+
conversation_projection: FusionConversationProjectionV3;
|
|
256
263
|
}
|
|
257
264
|
|
|
258
265
|
export interface CandidateAssessment {
|
|
@@ -370,6 +377,7 @@ export type FusionProgressEvent =
|
|
|
370
377
|
| { type: 'candidate_completed'; slot: 1 | 2 | 3; completed: number; total: 3 }
|
|
371
378
|
| { type: 'evaluation_started'; attempt: 1 | 2; repair: boolean }
|
|
372
379
|
| { type: 'evaluation_retry'; errors: readonly string[] }
|
|
380
|
+
| { type: 'budget_warning'; warnings: readonly FusionBudgetWarning[]; error: string }
|
|
373
381
|
| { type: 'merge_started' }
|
|
374
382
|
| { type: 'completed'; runId: string; artifactDir: string }
|
|
375
383
|
| { type: 'failed'; runId: string; artifactDir: string; error: string }
|
|
@@ -395,14 +403,11 @@ export type FusionErrorCode =
|
|
|
395
403
|
| 'state_transition_invalid'
|
|
396
404
|
| 'orchestration_failed';
|
|
397
405
|
|
|
398
|
-
/**
|
|
399
|
-
* Structured detail attached to a `prompt_budget_exceeded` failure so the caller
|
|
400
|
-
* can see exactly which stage, which measured size, which allowed size, and
|
|
401
|
-
* which configured model was the limiting participant.
|
|
402
|
-
*/
|
|
406
|
+
/** Structured detail attached to a `prompt_budget_exceeded` failure. */
|
|
403
407
|
export interface FusionBudgetErrorDetail {
|
|
404
408
|
budget_stage: FusionBudgetStage;
|
|
405
|
-
|
|
409
|
+
slot?: 1 | 2 | 3;
|
|
410
|
+
measurement_kind: 'stage_forecast' | 'rendered_prompt';
|
|
406
411
|
measured_utf8_bytes: number;
|
|
407
412
|
measured_input_tokens_upper_bound: number;
|
|
408
413
|
allowed_input_tokens: number;
|
|
@@ -414,6 +419,8 @@ export interface FusionBudgetErrorDetail {
|
|
|
414
419
|
};
|
|
415
420
|
context_policy_id: string;
|
|
416
421
|
remediation: readonly string[];
|
|
422
|
+
blockers: readonly FusionBudgetBlocker[];
|
|
423
|
+
artifact_dir: string;
|
|
417
424
|
}
|
|
418
425
|
|
|
419
426
|
export interface FusionErrorDetails {
|
|
@@ -535,48 +542,67 @@ export interface FusionRouteCapacity {
|
|
|
535
542
|
allowed_input_tokens: number;
|
|
536
543
|
}
|
|
537
544
|
|
|
545
|
+
export interface FusionBudgetStageComposition {
|
|
546
|
+
visible_text_bytes: number;
|
|
547
|
+
omission_receipt_bytes: number;
|
|
548
|
+
projection_metadata_bytes: number;
|
|
549
|
+
request_bytes: number;
|
|
550
|
+
static_stage_framing_bytes: number;
|
|
551
|
+
upstream_output_contract_bytes: number;
|
|
552
|
+
}
|
|
553
|
+
|
|
538
554
|
export interface FusionStageBudgetPlanEntry {
|
|
539
555
|
budget_stage: FusionBudgetStage;
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
556
|
+
slot?: 1 | 2 | 3;
|
|
557
|
+
route: FusionRouteCapacity;
|
|
558
|
+
conditional: boolean;
|
|
559
|
+
forecast_utf8_bytes: number;
|
|
560
|
+
forecast_input_tokens_upper_bound: number;
|
|
543
561
|
allowed_input_tokens: number;
|
|
544
|
-
|
|
545
|
-
|
|
562
|
+
signed_headroom_tokens: number;
|
|
563
|
+
utilization: number;
|
|
564
|
+
fits: boolean;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
export interface FusionBudgetBlocker extends FusionStageBudgetPlanEntry {
|
|
568
|
+
overage_tokens: number;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
export interface FusionBudgetWarning extends FusionStageBudgetPlanEntry {
|
|
572
|
+
threshold: 0.8;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
export interface FusionBudgetEmptyRequestVerdict {
|
|
576
|
+
request_utf8_bytes: number;
|
|
577
|
+
still_fails_with_empty_request: boolean;
|
|
578
|
+
shortening_request_can_help: boolean;
|
|
579
|
+
minimum_request_byte_reduction: number;
|
|
580
|
+
maximum_safe_request_utf8_bytes: number;
|
|
581
|
+
blockers_with_empty_request: readonly FusionBudgetBlocker[];
|
|
546
582
|
}
|
|
547
583
|
|
|
548
584
|
export interface FusionBudgetPlanV1 {
|
|
549
585
|
schema_version: typeof FUSION_BUDGET_PLAN_SCHEMA_VERSION;
|
|
550
586
|
policy: FusionBudgetPolicyDescriptor;
|
|
551
587
|
routes: readonly FusionRouteCapacity[];
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
588
|
+
stages: readonly FusionStageBudgetPlanEntry[];
|
|
589
|
+
blockers: readonly FusionBudgetBlocker[];
|
|
590
|
+
primary_blocker?: FusionBudgetBlocker;
|
|
591
|
+
primary_blocker_composition?: FusionBudgetStageComposition;
|
|
592
|
+
empty_request: FusionBudgetEmptyRequestVerdict;
|
|
593
|
+
warnings: readonly FusionBudgetWarning[];
|
|
555
594
|
}
|
|
556
595
|
|
|
557
|
-
/**
|
|
558
|
-
* Documented, versioned budget policy.
|
|
559
|
-
*
|
|
560
|
-
* `bytes_per_token_divisor` is a conservative lower bound on UTF-8 bytes per
|
|
561
|
-
* token: token upper bound = ceil(utf8Bytes / divisor). It is deliberately far
|
|
562
|
-
* below the smallest ratio measured across real Fusion prompts so dense
|
|
563
|
-
* non-ASCII input cannot silently exceed a route's window.
|
|
564
|
-
*
|
|
565
|
-
* `downstream_reserve_bytes` is withheld from the canonical input so the
|
|
566
|
-
* evaluator, evaluation-repair, and merger prompts provably have room for the
|
|
567
|
-
* child outputs they embed. It is derived from the enforced per-stage output
|
|
568
|
-
* byte contracts, so it is a guarantee rather than an estimate: a response over
|
|
569
|
-
* its contract fails loudly instead of being embedded. `downstream_reserve_tokens`
|
|
570
|
-
* converts it with the same `bytes_per_token_divisor` used to measure prompts,
|
|
571
|
-
* because reserving output tokens directly would understate the cost of
|
|
572
|
-
* re-embedding those bytes. Neither value is adjusted to fit a particular input.
|
|
573
|
-
*/
|
|
596
|
+
/** Documented, versioned budget policy. */
|
|
574
597
|
export interface FusionBudgetPolicyDescriptor {
|
|
575
|
-
id: 'fusion-budget-policy-
|
|
598
|
+
id: 'fusion-budget-policy-v2';
|
|
576
599
|
bytes_per_token_divisor: number;
|
|
577
600
|
reserved_output_tokens: number;
|
|
578
601
|
framing_reserve_tokens: number;
|
|
579
602
|
safety_reserve_tokens: number;
|
|
580
|
-
|
|
581
|
-
|
|
603
|
+
candidate_output_contract_bytes: number;
|
|
604
|
+
evaluation_output_contract_bytes: number;
|
|
605
|
+
merge_output_contract_bytes: number;
|
|
606
|
+
diagnostics_contract_bytes: number;
|
|
607
|
+
utilization_warning_threshold: 0.8;
|
|
582
608
|
}
|
package/src/fusion-extension.ts
CHANGED
|
@@ -148,6 +148,8 @@ function progressText(event: FusionProgressEvent): string {
|
|
|
148
148
|
return event.repair ? 'fusion: repairing evaluator JSON' : 'fusion: evaluating candidates';
|
|
149
149
|
if (event.type === 'evaluation_retry')
|
|
150
150
|
return `fusion: evaluator schema retry (${String(event.errors.length)} issue${event.errors.length === 1 ? '' : 's'})`;
|
|
151
|
+
if (event.type === 'budget_warning')
|
|
152
|
+
return `fusion: budget warning (${String(event.warnings.length)} stage${event.warnings.length === 1 ? '' : 's'} at or above 80%)`;
|
|
151
153
|
if (event.type === 'merge_started') return 'fusion: merging final answer';
|
|
152
154
|
if (event.type === 'completed') return 'fusion: completed';
|
|
153
155
|
if (event.type === 'cancelled') return `fusion: cancelled (${event.reason})`;
|