@pi-unipi/background-tasks 2.6.1

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.
Files changed (116) hide show
  1. package/README.md +87 -0
  2. package/extensions/anthropic-attribution.ts +1 -0
  3. package/extensions/delegate-child.ts +1 -0
  4. package/extensions/fusion-child.ts +1 -0
  5. package/package.json +40 -0
  6. package/src/__tests__/anthropic-attribution.test.ts +195 -0
  7. package/src/__tests__/config.test.ts +137 -0
  8. package/src/__tests__/core.test.ts +493 -0
  9. package/src/__tests__/delegate-artifacts.test.ts +528 -0
  10. package/src/__tests__/delegate-budget.test.ts +456 -0
  11. package/src/__tests__/delegate-launch.test.ts +676 -0
  12. package/src/__tests__/delegate-result-package.test.ts +350 -0
  13. package/src/__tests__/delegate-seed.test.ts +392 -0
  14. package/src/__tests__/durable-fs.test.ts +559 -0
  15. package/src/__tests__/extension-api.test.ts +579 -0
  16. package/src/__tests__/fusion-artifacts.test.ts +1039 -0
  17. package/src/__tests__/fusion-budget.test.ts +1356 -0
  18. package/src/__tests__/fusion-claude-cache.test.ts +320 -0
  19. package/src/__tests__/fusion-config.test.ts +335 -0
  20. package/src/__tests__/fusion-context-prompts.test.ts +670 -0
  21. package/src/__tests__/fusion-evaluation.test.ts +315 -0
  22. package/src/__tests__/fusion-extraction-equivalence.test.ts +58 -0
  23. package/src/__tests__/fusion-golden-bytes.test.ts +35 -0
  24. package/src/__tests__/fusion-high-cardinality.test.ts +192 -0
  25. package/src/__tests__/fusion-model-selector.test.ts +205 -0
  26. package/src/__tests__/fusion-orchestrator.test.ts +1194 -0
  27. package/src/__tests__/fusion-rpc.test.ts +369 -0
  28. package/src/__tests__/fusion-sdk.test.ts +1226 -0
  29. package/src/__tests__/fusion-v5-core.test.ts +219 -0
  30. package/src/__tests__/fusion-validate-orchestrator.test.ts +240 -0
  31. package/src/__tests__/fusion-web-fetch.test.ts +485 -0
  32. package/src/__tests__/fusion-workflows.test.ts +59 -0
  33. package/src/__tests__/helpers/delegate-deterministic-seed.ts +109 -0
  34. package/src/__tests__/helpers/delegate-seed-subprocess.ts +10 -0
  35. package/src/__tests__/helpers/fusion-canonical-subprocess.ts +21 -0
  36. package/src/__tests__/helpers/fusion-canonical.ts +140 -0
  37. package/src/__tests__/helpers/fusion-fake-pi.ts +279 -0
  38. package/src/__tests__/helpers/fusion-golden-corpus.ts +500 -0
  39. package/src/__tests__/helpers/fusion-high-cardinality.ts +140 -0
  40. package/src/__tests__/helpers/normalize.ts +22 -0
  41. package/src/__tests__/helpers/pi-hook-contract-evidence.json +18 -0
  42. package/src/__tests__/pi-launch.test.ts +202 -0
  43. package/src/__tests__/registry.test.ts +1580 -0
  44. package/src/__tests__/scripted-provider/delegate-ambient-provider.test.ts +130 -0
  45. package/src/__tests__/scripted-provider/delegate-child-guard.test.ts +631 -0
  46. package/src/__tests__/scripted-provider/delegate-guard-provider.ts +403 -0
  47. package/src/__tests__/scripted-provider/follow-up.test.ts +448 -0
  48. package/src/__tests__/scripted-provider/fusion-output-recovery.test.ts +132 -0
  49. package/src/__tests__/scripted-provider/fusion-reason.test.ts +310 -0
  50. package/src/__tests__/scripted-provider/fusion-runtime-guard.test.ts +163 -0
  51. package/src/__tests__/scripted-provider/hook-contract-provider.ts +179 -0
  52. package/src/__tests__/scripted-provider/hook-probe-a.ts +3 -0
  53. package/src/__tests__/scripted-provider/hook-probe-b.ts +3 -0
  54. package/src/__tests__/scripted-provider/hook-probe-extension.ts +126 -0
  55. package/src/__tests__/scripted-provider/output-recovery-provider.ts +153 -0
  56. package/src/__tests__/scripted-provider/pi-hook-contract-evidence.json +18 -0
  57. package/src/__tests__/scripted-provider/pi-hook-contract.test.ts +477 -0
  58. package/src/__tests__/scripted-provider/runtime-guard-probe.ts +28 -0
  59. package/src/__tests__/scripted-provider/runtime-guard-provider.ts +49 -0
  60. package/src/__tests__/scripted-provider/scripted-provider-extension.ts +408 -0
  61. package/src/__tests__/task-manager.test.ts +479 -0
  62. package/src/__tests__/windows-taskkill.test.ts +161 -0
  63. package/src/anthropic-attribution-path.ts +21 -0
  64. package/src/anthropic-attribution.ts +1983 -0
  65. package/src/attested-pi-run.ts +612 -0
  66. package/src/child-process.ts +55 -0
  67. package/src/common.ts +8 -0
  68. package/src/config.ts +292 -0
  69. package/src/context-parent-snapshot.ts +142 -0
  70. package/src/context-token-budget.ts +903 -0
  71. package/src/context-visible-conversation-v2.ts +551 -0
  72. package/src/delegate/artifacts.ts +487 -0
  73. package/src/delegate/budget.ts +415 -0
  74. package/src/delegate/hook-contract-evidence.json +18 -0
  75. package/src/delegate/hook-contract.ts +154 -0
  76. package/src/delegate/launch.ts +497 -0
  77. package/src/delegate/result-package.ts +459 -0
  78. package/src/delegate/runner.ts +449 -0
  79. package/src/delegate/seed.ts +423 -0
  80. package/src/delegate/types.ts +323 -0
  81. package/src/delegate-child-extension.ts +978 -0
  82. package/src/delegate-extension.ts +806 -0
  83. package/src/durable-fs.ts +386 -0
  84. package/src/extension-api.ts +548 -0
  85. package/src/fixtures/delegate-context-incident.json +17 -0
  86. package/src/fixtures/fusion-golden-bytes.json +310 -0
  87. package/src/fixtures/fusion-validate-golden-bytes.json +282 -0
  88. package/src/fusion/artifacts.ts +967 -0
  89. package/src/fusion/budget.ts +1162 -0
  90. package/src/fusion/child-protocol.ts +305 -0
  91. package/src/fusion/claude-cache.ts +207 -0
  92. package/src/fusion/clean-context.ts +91 -0
  93. package/src/fusion/config.ts +449 -0
  94. package/src/fusion/context.ts +265 -0
  95. package/src/fusion/evaluation.ts +800 -0
  96. package/src/fusion/orchestrator.ts +1288 -0
  97. package/src/fusion/output-contract.ts +34 -0
  98. package/src/fusion/pi-child.ts +2373 -0
  99. package/src/fusion/prompts.ts +345 -0
  100. package/src/fusion/result-package.ts +959 -0
  101. package/src/fusion/source-policy.ts +257 -0
  102. package/src/fusion/types.ts +1139 -0
  103. package/src/fusion/web-fetch.ts +1060 -0
  104. package/src/fusion/workflows.ts +184 -0
  105. package/src/fusion-child-extension.ts +1052 -0
  106. package/src/fusion-extension.ts +1293 -0
  107. package/src/index.ts +295 -0
  108. package/src/pi-launch.ts +225 -0
  109. package/src/registry.ts +2424 -0
  110. package/src/settings-overlay.ts +208 -0
  111. package/src/task-manager.ts +774 -0
  112. package/src/tools.ts +530 -0
  113. package/src/turndown.d.ts +15 -0
  114. package/src/types.ts +963 -0
  115. package/src/ui/fusion-model-selector.ts +322 -0
  116. package/src/windows-taskkill.ts +250 -0
@@ -0,0 +1,1139 @@
1
+ import type { Usage } from '@earendil-works/pi-ai';
2
+ import type {
3
+ EstimateInputTokensResult,
4
+ TokenBudgetByteClassBreakdown,
5
+ TokenBudgetDominantByteClass,
6
+ TokenBudgetFamily,
7
+ TokenBudgetFamilyCalibration,
8
+ TokenBudgetRateSource,
9
+ } from '../context-token-budget.js';
10
+
11
+ export type FusionThinkingLevel = 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max';
12
+
13
+ export const FUSION_MODEL_CONFIG_SCHEMA_VERSION = 'pi-background-tasks.fusion-models.v1';
14
+ export const FUSION_LEGACY_INPUT_SCHEMA_VERSION = 'pi-background-tasks.fusion-input.v4';
15
+ export const FUSION_INPUT_SCHEMA_VERSION = 'pi-background-tasks.fusion-input.v5';
16
+ export const FUSION_EVALUATION_SCHEMA_VERSION = 'pi-background-tasks.fusion-evaluation.v1';
17
+ export const FUSION_VALIDATE_CANDIDATE_SCHEMA_VERSION =
18
+ 'pi-background-tasks.fusion-validation-candidate.v1';
19
+ export const FUSION_LEGACY_RESULT_SCHEMA_VERSION = 'pi-background-tasks.fusion-result.v4';
20
+ export const FUSION_RESULT_SCHEMA_VERSION = 'pi-background-tasks.fusion-result.v5';
21
+ export const FUSION_COMMITTED_RESULT_SCHEMA_VERSION =
22
+ 'pi-background-tasks.fusion-committed-result.v1';
23
+ export const FUSION_LEGACY_MANIFEST_SCHEMA_VERSION = 'pi-background-tasks.fusion-manifest.v3';
24
+ export const FUSION_MANIFEST_SCHEMA_VERSION = 'pi-background-tasks.fusion-manifest.v4';
25
+ export const FUSION_CONTEXT_LEDGER_SCHEMA_VERSION = 'pi-background-tasks.fusion-context-ledger.v2';
26
+ export const FUSION_SOURCE_POLICY_SCHEMA_VERSION = 'pi-background-tasks.fusion-source-policy.v1';
27
+ export const FUSION_BUDGET_PLAN_SCHEMA_VERSION = 'pi-background-tasks.fusion-budget-plan.v4';
28
+ export const FUSION_CALIBRATION_VIOLATION_SCHEMA_VERSION =
29
+ 'pi-background-tasks.fusion-calibration-violation.v2';
30
+ export const FUSION_VALIDATE_CANDIDATE_CONTRACT_EVENT_SCHEMA_VERSION =
31
+ 'pi-background-tasks.fusion-validation-candidate-contract-event.v1';
32
+ export const FUSION_TOOL_CALL_LOG_SCHEMA_VERSION = 'pi-background-tasks.fusion-tool-call.v1';
33
+ export const FUSION_FAILURE_SUMMARY_SCHEMA_VERSION =
34
+ 'pi-background-tasks.fusion-failure-summary.v1';
35
+
36
+ /**
37
+ * Conversation-projection transform shared by every Fusion entry point.
38
+ *
39
+ * The transform keeps visible user/assistant conversational text verbatim and
40
+ * replaces assistant thinking plus all tool traffic with deterministic,
41
+ * hash-accounted omission receipts. It never truncates retained text and never
42
+ * forwards raw image bytes.
43
+ */
44
+ export const FUSION_CONTEXT_TRANSFORM_ID = 'visible-conversation-ledger-v2';
45
+ export const FUSION_BRANCH_FILTER_ID = 'exclude-active-fusion-subtree-v1';
46
+
47
+ /** Entry-point specific context policies. Both use the same payload-exclusion transform. */
48
+ export const FUSION_TOOL_CONTEXT_POLICY_ID = 'fusion-tool-explicit-v2';
49
+ export const FUSION_COMMAND_CONTEXT_POLICY_ID = 'fusion-command-conversation-v2';
50
+
51
+ export const FUSION_IMAGE_OMISSION_PREFIX = '[Image omitted from fusion text transcript: ';
52
+
53
+ export const FUSION_CANDIDATE_IDS = ['A', 'B', 'C'] as const;
54
+ export type FusionCandidateId = (typeof FUSION_CANDIDATE_IDS)[number];
55
+
56
+ export const FUSION_STAGE_VALUES = ['candidate', 'evaluation', 'merge'] as const;
57
+ export type FusionStage = (typeof FUSION_STAGE_VALUES)[number];
58
+
59
+ export const FUSION_CAPABILITY_VALUES = Object.freeze(['reason', 'inspect', 'research'] as const);
60
+ export type FusionCapability = (typeof FUSION_CAPABILITY_VALUES)[number];
61
+
62
+ /** No-tools capability for reason candidates, evaluator, repair, and merger. */
63
+ export const FUSION_NO_TOOLS_CAPABILITY: FusionCapability = 'reason';
64
+ /** Legacy default retained for old type imports only. New workflows never default. */
65
+ export const FUSION_BRAINSTORM_DEFAULT_CAPABILITY: FusionCapability = 'inspect';
66
+ /** @deprecated New v5 workflows have no caller capability default. */
67
+ export const FUSION_DEFAULT_CAPABILITY: FusionCapability = FUSION_BRAINSTORM_DEFAULT_CAPABILITY;
68
+
69
+ export const FUSION_WEB_FETCH_TOOL_NAME = 'fusion_web_fetch' as const;
70
+ export const FUSION_INSPECT_TOOLS = Object.freeze(['read', 'grep', 'find', 'ls'] as const);
71
+ export const FUSION_RESEARCH_TOOLS = Object.freeze([
72
+ 'read',
73
+ 'grep',
74
+ 'find',
75
+ 'ls',
76
+ FUSION_WEB_FETCH_TOOL_NAME,
77
+ ] as const);
78
+
79
+ /**
80
+ * Workflow identities sharing one orchestrator, one context projection, one
81
+ * evaluation schema, and one artifact store. A workflow selects stage framing and
82
+ * capability policy only; it never changes the canonical input schema.
83
+ */
84
+ export const FUSION_WORKFLOW_IDS = Object.freeze([
85
+ 'reason',
86
+ 'investigate',
87
+ 'research',
88
+ 'validate',
89
+ ] as const);
90
+ export type FusionWorkflowId = (typeof FUSION_WORKFLOW_IDS)[number];
91
+ export const FUSION_PUBLIC_WORKFLOW_NAMES = Object.freeze([
92
+ 'fusion_reason',
93
+ 'fusion_investigate',
94
+ 'fusion_research',
95
+ 'fusion_validate',
96
+ ] as const);
97
+ export type FusionPublicWorkflowName = (typeof FUSION_PUBLIC_WORKFLOW_NAMES)[number];
98
+ export type FusionContextKind = 'session_projection' | 'clean_task';
99
+
100
+ /**
101
+ * The single capability the validate workflow ever runs candidates with.
102
+ *
103
+ * Deliberately separate from the caller-selectable brainstorm default. Although
104
+ * both workflows currently give candidates read-only inspection, validation pins
105
+ * that capability as fixed policy rather than exposing a caller override.
106
+ */
107
+ export const FUSION_VALIDATE_CAPABILITY: FusionCapability = 'inspect';
108
+
109
+ export const FUSION_FORBIDDEN_TOOLS = Object.freeze([
110
+ 'bash',
111
+ 'edit',
112
+ 'write',
113
+ 'fusion_brainstorm',
114
+ 'fusion_reason',
115
+ 'fusion_investigate',
116
+ 'fusion_research',
117
+ 'fusion_validate',
118
+ 'bg_delegate',
119
+ 'bg_result',
120
+ 'bg_run',
121
+ 'bg_kill',
122
+ 'bg_status',
123
+ 'bg_logs',
124
+ 'bg_run_pi_attested',
125
+ ] as const);
126
+
127
+ /**
128
+ * Prompt-expansion stages guarded by deterministic size accounting. `evaluation`
129
+ * and `evaluation_repair` share the evaluator model but render different prompts.
130
+ */
131
+ export const FUSION_BUDGET_STAGE_VALUES = [
132
+ 'candidate',
133
+ 'evaluation',
134
+ 'evaluation_repair',
135
+ 'merge',
136
+ ] as const;
137
+ export type FusionBudgetStage = (typeof FUSION_BUDGET_STAGE_VALUES)[number];
138
+
139
+ export const FUSION_SOURCE_VALUES = ['command', 'tool'] as const;
140
+ export type FusionSource = (typeof FUSION_SOURCE_VALUES)[number];
141
+
142
+ export const FUSION_STATE_VALUES = [
143
+ 'initializing',
144
+ 'candidates_running',
145
+ 'candidates_complete',
146
+ 'evaluating',
147
+ 'evaluation_complete',
148
+ 'merging',
149
+ 'completed',
150
+ 'failed',
151
+ 'cancelled',
152
+ ] as const;
153
+ export type FusionState = (typeof FUSION_STATE_VALUES)[number];
154
+ export type FusionTerminalState = Extract<FusionState, 'completed' | 'failed' | 'cancelled'>;
155
+ export type FusionNonterminalState = Exclude<FusionState, FusionTerminalState>;
156
+
157
+ export const FUSION_NONTERMINAL_STATE_VALUES = [
158
+ 'initializing',
159
+ 'candidates_running',
160
+ 'candidates_complete',
161
+ 'evaluating',
162
+ 'evaluation_complete',
163
+ 'merging',
164
+ ] as const satisfies readonly FusionNonterminalState[];
165
+
166
+ export const FUSION_TERMINAL_STATE_VALUES = ['completed', 'failed', 'cancelled'] as const;
167
+
168
+ export type FusionModelSelection = '$current' | string;
169
+
170
+ export interface FusionModelConfigV1 {
171
+ schema_version: typeof FUSION_MODEL_CONFIG_SCHEMA_VERSION;
172
+ candidates: readonly [FusionModelSelection, FusionModelSelection, FusionModelSelection];
173
+ evaluator: FusionModelSelection;
174
+ merger: FusionModelSelection;
175
+ }
176
+
177
+ export interface FusionModelConfigRevision {
178
+ path: string;
179
+ exists: boolean;
180
+ sha256: string | null;
181
+ }
182
+
183
+ export interface LoadedFusionModelConfig {
184
+ config: FusionModelConfigV1;
185
+ revision: FusionModelConfigRevision;
186
+ }
187
+
188
+ export interface ResolvedFusionModel {
189
+ selection: string;
190
+ source: 'current' | 'configured';
191
+ provider: string;
192
+ model: string;
193
+ qualifiedId: string;
194
+ thinkingLevel: FusionThinkingLevel;
195
+ contextWindow: number;
196
+ maxOutputTokens: number;
197
+ }
198
+
199
+ export interface ResolvedFusionModels {
200
+ candidates: readonly [ResolvedFusionModel, ResolvedFusionModel, ResolvedFusionModel];
201
+ evaluator: ResolvedFusionModel;
202
+ merger: ResolvedFusionModel;
203
+ }
204
+
205
+ export type FusionRequestAuthority = 'explicit_text' | 'directive_over_projected_conversation';
206
+
207
+ export interface FusionCanonicalRequestV3 {
208
+ /** Entry point that produced this request. */
209
+ source: FusionSource;
210
+ /** How children must weigh `text` against the projected conversation. */
211
+ authority: FusionRequestAuthority;
212
+ /** Verbatim request text. Never clipped, never rewritten. */
213
+ text: string;
214
+ /** Lowercase SHA-256 of the UTF-8 request bytes. */
215
+ sha256: string;
216
+ }
217
+
218
+ export const FUSION_OMITTED_EVENT_KINDS = [
219
+ 'assistant_thinking',
220
+ 'tool_call',
221
+ 'tool_result_text',
222
+ 'tool_result_image',
223
+ ] as const;
224
+ export type FusionOmittedEventKind = (typeof FUSION_OMITTED_EVENT_KINDS)[number];
225
+
226
+ /** One omitted conversation event. Ledger rows never leave the local artifact directory. */
227
+ export interface FusionOmittedEventRecord {
228
+ index: number;
229
+ source_ordinal: number;
230
+ block_ordinal: number;
231
+ kind: FusionOmittedEventKind;
232
+ payload_bytes: number;
233
+ payload_sha256: string;
234
+ tool_name?: string;
235
+ tool_call_id?: string;
236
+ mime_type?: string;
237
+ }
238
+
239
+ export interface FusionOmittedActivityProjectionMapEntry {
240
+ canonical_entry_index: number;
241
+ entry_kind: 'omitted_activity';
242
+ ledger_index_first: number;
243
+ ledger_index_last: number;
244
+ }
245
+
246
+ export interface FusionLedgerOnlyImageProjectionMapEntry {
247
+ entry_kind: 'ledger_only_tool_result_image';
248
+ ledger_index_first: number;
249
+ ledger_index_last: number;
250
+ }
251
+
252
+ export type FusionContextProjectionMapEntry =
253
+ | FusionOmittedActivityProjectionMapEntry
254
+ | FusionLedgerOnlyImageProjectionMapEntry;
255
+
256
+ export interface FusionContextOmissionLedgerV2 {
257
+ schema_version: typeof FUSION_CONTEXT_LEDGER_SCHEMA_VERSION;
258
+ policy_id: string;
259
+ transform: typeof FUSION_CONTEXT_TRANSFORM_ID;
260
+ entries: readonly FusionOmittedEventRecord[];
261
+ projection_map: readonly FusionContextProjectionMapEntry[];
262
+ root_sha256: string;
263
+ }
264
+
265
+ export type FusionProjectionTextEntry = [
266
+ tag: 't',
267
+ role: 'u' | 'a',
268
+ sourceOrdinal: number,
269
+ blockOrdinal: number,
270
+ text: string,
271
+ ];
272
+
273
+ export type FusionProjectionOmissionCounts = [
274
+ assistantThinking: number,
275
+ toolCalls: number,
276
+ toolResults: number,
277
+ ];
278
+
279
+ export type FusionProjectionOmissionEntry = [
280
+ tag: 'o',
281
+ sourceOrdinalSpan: [first: number, last: number],
282
+ bytes: number,
283
+ counts: FusionProjectionOmissionCounts,
284
+ ];
285
+
286
+ export type FusionProjectionEntry = FusionProjectionTextEntry | FusionProjectionOmissionEntry;
287
+
288
+ export interface FusionContextPolicyDescriptor {
289
+ id: string;
290
+ transform: typeof FUSION_CONTEXT_TRANSFORM_ID;
291
+ version: 2;
292
+ receipt_format: 'omitted_activity.v2';
293
+ user_text: 'verbatim';
294
+ assistant_text: 'verbatim';
295
+ assistant_thinking: 'ledger_only';
296
+ tool_call_arguments: 'ledger_only';
297
+ tool_results: 'ledger_only';
298
+ tool_payload_preview_bytes: 0;
299
+ images: 'marker_or_ledger_only';
300
+ unknown_block_behavior: 'error';
301
+ }
302
+
303
+ export interface FusionBranchFilterDescriptor {
304
+ id: typeof FUSION_BRANCH_FILTER_ID;
305
+ tool_name: string;
306
+ tool_call_id: string | null;
307
+ active_tool_call_leaf_excluded: boolean;
308
+ }
309
+
310
+ export interface FusionToolCallNameCount {
311
+ name: string;
312
+ calls: number;
313
+ }
314
+
315
+ export interface FusionProjectionAccounting {
316
+ message_count: number;
317
+ included_text_entry_count: number;
318
+ included_user_text_bytes: number;
319
+ included_assistant_text_bytes: number;
320
+ included_image_marker_count: number;
321
+ empty_text_block_count: number;
322
+ omitted_run_count: number;
323
+ omitted_event_count: number;
324
+ omitted_thinking_bytes: number;
325
+ omitted_tool_call_count: number;
326
+ omitted_tool_call_argument_bytes: number;
327
+ omitted_tool_result_text_count: number;
328
+ omitted_tool_result_text_bytes: number;
329
+ omitted_tool_result_image_count: number;
330
+ omitted_tool_result_image_bytes: number;
331
+ tool_call_names: readonly FusionToolCallNameCount[];
332
+ ledger_entry_count: number;
333
+ ledger_root_sha256: string;
334
+ omission_receipt_utf8_bytes: number;
335
+ }
336
+
337
+ export interface FusionConversationProjectionV4 {
338
+ policy: FusionContextPolicyDescriptor;
339
+ branch_filter: FusionBranchFilterDescriptor;
340
+ entries: readonly FusionProjectionEntry[];
341
+ accounting: FusionProjectionAccounting;
342
+ }
343
+
344
+ export type FusionConversationProjectionV3 = FusionConversationProjectionV4;
345
+
346
+ export interface FusionDeclaredSourceV1 {
347
+ url: string;
348
+ canonical_url: string;
349
+ purpose: string;
350
+ sha256: string;
351
+ }
352
+
353
+ export interface FusionCleanTaskContextV1 {
354
+ kind: 'clean_task';
355
+ policy_id: 'fusion-clean-task-v1';
356
+ declared_sources: readonly FusionDeclaredSourceV1[];
357
+ }
358
+
359
+ export interface FusionSessionProjectionContextV1 {
360
+ kind: 'session_projection';
361
+ policy_id: 'fusion-session-projection-v1';
362
+ system_prompt: string;
363
+ conversation_projection: FusionConversationProjectionV4;
364
+ }
365
+
366
+ export interface FusionCanonicalInputV5Base {
367
+ schema_version: typeof FUSION_INPUT_SCHEMA_VERSION;
368
+ workflow?: FusionWorkflowId | undefined;
369
+ cwd: string;
370
+ request: FusionCanonicalRequestV3;
371
+ }
372
+
373
+ export interface FusionSessionProjectionCanonicalInputV5 extends FusionCanonicalInputV5Base {
374
+ workflow?: FusionWorkflowId | undefined;
375
+ /** @deprecated v4 readability alias. Present only for session-projection inputs at runtime. */
376
+ system_prompt: string;
377
+ /** @deprecated v4 readability alias. Present only for session-projection inputs at runtime. */
378
+ conversation_projection: FusionConversationProjectionV4;
379
+ context?: FusionSessionProjectionContextV1 | undefined;
380
+ }
381
+
382
+ export interface FusionCleanTaskCanonicalInputV5 extends FusionCanonicalInputV5Base {
383
+ workflow: Exclude<FusionWorkflowId, 'reason'>;
384
+ context: FusionCleanTaskContextV1;
385
+ }
386
+
387
+ export type FusionCanonicalInputV5 =
388
+ | FusionSessionProjectionCanonicalInputV5
389
+ | FusionCleanTaskCanonicalInputV5;
390
+
391
+ /** Legacy v4 shape retained for frozen golden fixtures/readability only. */
392
+ export interface FusionCanonicalInputV4 {
393
+ schema_version: typeof FUSION_LEGACY_INPUT_SCHEMA_VERSION;
394
+ cwd: string;
395
+ system_prompt: string;
396
+ request: FusionCanonicalRequestV3;
397
+ conversation_projection: FusionConversationProjectionV4;
398
+ }
399
+
400
+ export type FusionCanonicalInputV3 = FusionCanonicalInputV5;
401
+
402
+ export interface FusionSourcePolicyV1 {
403
+ schema_version: typeof FUSION_SOURCE_POLICY_SCHEMA_VERSION;
404
+ workflow: 'research';
405
+ cwd: string;
406
+ sources: readonly FusionDeclaredSourceV1[];
407
+ root_sha256: string;
408
+ }
409
+
410
+ export interface FusionSourcePolicyArtifactRef extends FusionArtifactRef {
411
+ root_sha256: string;
412
+ }
413
+
414
+ export interface CandidateAssessment {
415
+ candidate_id: FusionCandidateId;
416
+ summary: string;
417
+ strengths: readonly string[];
418
+ limitations: readonly string[];
419
+ useful_contributions: readonly string[];
420
+ risks: readonly string[];
421
+ }
422
+
423
+ export interface FusionConflictPosition {
424
+ candidate_id: FusionCandidateId;
425
+ position: string;
426
+ }
427
+
428
+ export interface FusionConflict {
429
+ topic: string;
430
+ positions: readonly FusionConflictPosition[];
431
+ resolution: string;
432
+ }
433
+
434
+ export interface FusionSynthesisContribution {
435
+ candidate_id: FusionCandidateId;
436
+ contribution: string;
437
+ }
438
+
439
+ export interface FusionSynthesisPlan {
440
+ must_include: readonly FusionSynthesisContribution[];
441
+ must_resolve: readonly string[];
442
+ must_avoid: readonly string[];
443
+ }
444
+
445
+ export type FusionValidationSeverity = 'critical' | 'high' | 'minor';
446
+
447
+ export interface FusionValidationFindingRecord {
448
+ id: string;
449
+ candidate_id: FusionCandidateId;
450
+ severity: FusionValidationSeverity;
451
+ location: string;
452
+ evidence: string;
453
+ impact: string;
454
+ summary: string;
455
+ }
456
+
457
+ export interface FusionValidationFindingDecision {
458
+ source_id: string;
459
+ disposition: 'include' | 'exclude';
460
+ rationale: string;
461
+ group_id?: string | undefined;
462
+ }
463
+
464
+ export interface FusionValidationFindingGroup {
465
+ group_id: string;
466
+ source_ids: readonly string[];
467
+ severity: FusionValidationSeverity;
468
+ location: string;
469
+ evidence: string;
470
+ impact: string;
471
+ summary: string;
472
+ rationale: string;
473
+ }
474
+
475
+ export interface FusionValidationFindingAccounting {
476
+ findings: readonly FusionValidationFindingRecord[];
477
+ decisions: readonly FusionValidationFindingDecision[];
478
+ groups: readonly FusionValidationFindingGroup[];
479
+ }
480
+
481
+ export interface FusionValidationCandidateReportV1 {
482
+ schema_version: typeof FUSION_VALIDATE_CANDIDATE_SCHEMA_VERSION;
483
+ findings: readonly Omit<FusionValidationFindingRecord, 'id' | 'candidate_id'>[];
484
+ verified: readonly string[];
485
+ limitations: readonly string[];
486
+ }
487
+
488
+ export interface FusionEvaluationV1 {
489
+ schema_version: typeof FUSION_EVALUATION_SCHEMA_VERSION;
490
+ candidate_assessments: readonly [CandidateAssessment, CandidateAssessment, CandidateAssessment];
491
+ agreements: readonly string[];
492
+ conflicts: readonly FusionConflict[];
493
+ synthesis_plan: FusionSynthesisPlan;
494
+ validation_accounting?: FusionValidationFindingAccounting | undefined;
495
+ }
496
+
497
+ /** Exact Pi usage contract used at the child, artifact, and host tool-result boundaries. */
498
+ export type FusionUsage = Omit<Usage, 'reasoning'> & { reasoning?: number | undefined };
499
+
500
+ const EMPTY_FUSION_COST: Usage['cost'] = Object.freeze({
501
+ input: 0,
502
+ output: 0,
503
+ cacheRead: 0,
504
+ cacheWrite: 0,
505
+ total: 0,
506
+ });
507
+
508
+ export const EMPTY_FUSION_USAGE: FusionUsage = Object.freeze({
509
+ input: 0,
510
+ output: 0,
511
+ cacheRead: 0,
512
+ cacheWrite: 0,
513
+ totalTokens: 0,
514
+ cost: EMPTY_FUSION_COST,
515
+ });
516
+
517
+ export function createEmptyFusionUsage(): FusionUsage {
518
+ return cloneFusionUsage(EMPTY_FUSION_USAGE);
519
+ }
520
+
521
+ export function cloneFusionUsage(usage: FusionUsage): FusionUsage {
522
+ return {
523
+ input: usage.input,
524
+ output: usage.output,
525
+ cacheRead: usage.cacheRead,
526
+ cacheWrite: usage.cacheWrite,
527
+ ...(usage.cacheWrite1h === undefined ? {} : { cacheWrite1h: usage.cacheWrite1h }),
528
+ ...(usage.reasoning === undefined ? {} : { reasoning: usage.reasoning as number | undefined }),
529
+ totalTokens: usage.totalTokens,
530
+ cost: {
531
+ input: usage.cost.input,
532
+ output: usage.cost.output,
533
+ cacheRead: usage.cost.cacheRead,
534
+ cacheWrite: usage.cost.cacheWrite,
535
+ total: usage.cost.total,
536
+ },
537
+ };
538
+ }
539
+
540
+ export function addFusionUsage(target: FusionUsage, delta: FusionUsage): void {
541
+ target.input += delta.input;
542
+ target.output += delta.output;
543
+ target.cacheRead += delta.cacheRead;
544
+ target.cacheWrite += delta.cacheWrite;
545
+ if (delta.cacheWrite1h !== undefined) {
546
+ target.cacheWrite1h = (target.cacheWrite1h ?? 0) + delta.cacheWrite1h;
547
+ }
548
+ if (delta.reasoning !== undefined) {
549
+ target.reasoning = (target.reasoning ?? 0) + delta.reasoning;
550
+ }
551
+ target.totalTokens += delta.totalTokens;
552
+ target.cost.input += delta.cost.input;
553
+ target.cost.output += delta.cost.output;
554
+ target.cost.cacheRead += delta.cost.cacheRead;
555
+ target.cost.cacheWrite += delta.cost.cacheWrite;
556
+ target.cost.total += delta.cost.total;
557
+ }
558
+
559
+ export type FusionRunStageProgressStatus = 'not_started' | 'incomplete' | 'completed';
560
+
561
+ export interface FusionRunStageProgress {
562
+ status: FusionRunStageProgressStatus;
563
+ attempts_recorded: number;
564
+ children_created: number;
565
+ children_completed: number;
566
+ children_failed: number;
567
+ children_cancelled: number;
568
+ not_started_slots?: number | undefined;
569
+ }
570
+
571
+ export interface FusionRunProgress {
572
+ manifest_state: FusionState;
573
+ candidates: FusionRunStageProgress;
574
+ evaluation: FusionRunStageProgress;
575
+ merge: FusionRunStageProgress;
576
+ usage_so_far: FusionUsage;
577
+ }
578
+
579
+ export interface FusionResultBudgetDetails {
580
+ policy_id: string;
581
+ calibration_version: string;
582
+ route_table: readonly FusionRouteCapacity[];
583
+ rate_sources: readonly TokenBudgetRateSource[];
584
+ unknown_provider_warnings: readonly string[];
585
+ calibration_warnings: readonly FusionCalibrationViolation[];
586
+ }
587
+
588
+ export interface FusionCommittedResultV1 {
589
+ schema_version: typeof FUSION_COMMITTED_RESULT_SCHEMA_VERSION;
590
+ run_id: string;
591
+ merged: FusionArtifactRef;
592
+ details: FusionResultDetails;
593
+ }
594
+
595
+ export interface FusionResultDetails {
596
+ schema_version: typeof FUSION_RESULT_SCHEMA_VERSION;
597
+ run_id: string;
598
+ workflow: FusionWorkflowId;
599
+ source: FusionSource;
600
+ status: 'completed';
601
+ context: { kind: FusionContextKind; policy_id: string };
602
+ tool_policy: {
603
+ candidate_tools: readonly string[];
604
+ evaluation_tools: readonly [];
605
+ merge_tools: readonly [];
606
+ };
607
+ artifact_dir: string;
608
+ models: {
609
+ candidates: readonly [string, string, string];
610
+ evaluator: string;
611
+ merger: string;
612
+ thinking_level: string;
613
+ };
614
+ evaluator_attempts: number;
615
+ usage: FusionUsage;
616
+ budget: FusionResultBudgetDetails;
617
+ }
618
+
619
+ export type FusionProgressEvent =
620
+ | { type: 'state'; state: FusionState }
621
+ | { type: 'candidate_started'; slot: 1 | 2 | 3; attempt: number }
622
+ | { type: 'candidate_completed'; slot: 1 | 2 | 3; completed: number; total: 3 }
623
+ | { type: 'evaluation_started'; attempt: 1 | 2; repair: boolean }
624
+ | { type: 'evaluation_retry'; errors: readonly string[] }
625
+ | { type: 'budget_warning'; warnings: readonly FusionBudgetWarning[]; error: string }
626
+ | { type: 'calibration_warning'; warning: FusionCalibrationViolation; artifact: string }
627
+ | { type: 'merge_started' }
628
+ | { type: 'completed'; runId: string; artifactDir: string }
629
+ | { type: 'failed'; runId: string; artifactDir: string; error: string }
630
+ | { type: 'cancelled'; runId: string; artifactDir: string; reason: string };
631
+
632
+ export type FusionErrorCode =
633
+ | 'config_invalid'
634
+ | 'config_conflict'
635
+ | 'model_unavailable'
636
+ | 'context_capture_failed'
637
+ | 'context_policy_unsupported_block'
638
+ | 'prompt_budget_exceeded_forecast'
639
+ | 'prompt_budget_exceeded_measured'
640
+ | 'model_capacity_unknown'
641
+ | 'child_spawn_failed'
642
+ | 'child_stdin_failed'
643
+ | 'child_event_invalid'
644
+ | 'child_exit_failed'
645
+ | 'child_runtime_limit_exceeded'
646
+ | 'child_runtime_payload_invalid'
647
+ | 'child_cache_policy_invalid'
648
+ | 'child_timeout'
649
+ | 'child_output_cap'
650
+ | 'child_cancelled'
651
+ | 'evaluation_invalid'
652
+ | 'artifact_error'
653
+ | 'state_transition_invalid'
654
+ | 'orchestration_failed';
655
+
656
+ export type FusionBudgetCheckKind = 'input_only_preflight' | 'rendered_prompt';
657
+
658
+ export interface FusionBudgetComponentBreakdown {
659
+ visible_text: { bytes: number; tokens: number };
660
+ omission_receipts: { bytes: number; tokens: number };
661
+ projection_metadata: { bytes: number; tokens: number };
662
+ request: { bytes: number; tokens: number };
663
+ static_stage_framing: { bytes: number; tokens: number };
664
+ upstream_output_contracts: { bytes: number; tokens: number };
665
+ }
666
+
667
+ export interface FusionBudgetDenseRegion {
668
+ offset: number;
669
+ len: number;
670
+ detector: 'not_implemented_step_6';
671
+ }
672
+
673
+ export interface FusionBudgetRouteTableEntry {
674
+ role: FusionRouteCapacity['role'];
675
+ qualified_id: string;
676
+ allowed_input_tokens: number;
677
+ family: TokenBudgetFamily;
678
+ effective_rate_bytes_per_token_x100: number;
679
+ byte_capacity_utf8_bytes: number;
680
+ backed: boolean;
681
+ }
682
+
683
+ export interface FusionBudgetCounterfactuals {
684
+ empty_request: FusionBudgetEmptyRequestVerdict;
685
+ without_reservation: {
686
+ forecast_input_tokens_upper_bound: number;
687
+ signed_headroom_tokens: number;
688
+ fits: boolean;
689
+ };
690
+ at_median_rate: {
691
+ forecast_input_tokens_upper_bound: number | null;
692
+ signed_headroom_tokens: number | null;
693
+ fits: boolean | null;
694
+ };
695
+ }
696
+
697
+ /** Structured detail attached to a split prompt-budget failure. */
698
+ export interface FusionBudgetErrorDetail {
699
+ budget_stage: FusionBudgetStage;
700
+ slot?: 1 | 2 | 3;
701
+ measurement_kind: 'stage_forecast' | 'rendered_prompt';
702
+ check_kind: FusionBudgetCheckKind;
703
+ measured_utf8_bytes: number;
704
+ measured_input_tokens_upper_bound: number;
705
+ allowed_input_tokens: number;
706
+ limiting_model: {
707
+ provider: string;
708
+ model: string;
709
+ qualified_id: string;
710
+ context_window_tokens: number;
711
+ };
712
+ rate_source: TokenBudgetRateSource;
713
+ backed: boolean;
714
+ dominant_byte_class: TokenBudgetDominantByteClass;
715
+ component_breakdown: FusionBudgetComponentBreakdown;
716
+ byte_class_breakdown: TokenBudgetByteClassBreakdown;
717
+ dense_regions: readonly FusionBudgetDenseRegion[];
718
+ bytes_over: number;
719
+ tokens_over: number;
720
+ required_allowed_tokens: number;
721
+ route_table: readonly FusionBudgetRouteTableEntry[];
722
+ counterfactuals: FusionBudgetCounterfactuals;
723
+ stage_upstream_actuals: readonly { stage: FusionStage; bytes: number }[];
724
+ policy_id: string;
725
+ calibration_version: string;
726
+ context_policy_id: string;
727
+ remediation: readonly string[];
728
+ blockers: readonly FusionBudgetBlocker[];
729
+ artifact_dir: string;
730
+ }
731
+
732
+ export interface FusionErrorDetails {
733
+ code: FusionErrorCode;
734
+ stage?: FusionStage;
735
+ slot?: 1 | 2 | 3;
736
+ attempt?: number;
737
+ artifactDir?: string;
738
+ transient?: boolean;
739
+ childCreated?: boolean;
740
+ budget?: FusionBudgetErrorDetail;
741
+ runProgress?: FusionRunProgress;
742
+ }
743
+
744
+ export class FusionError extends Error {
745
+ readonly code: FusionErrorCode;
746
+ readonly stage: FusionStage | undefined;
747
+ readonly slot: 1 | 2 | 3 | undefined;
748
+ readonly attempt: number | undefined;
749
+ readonly artifactDir: string | undefined;
750
+ readonly transient: boolean;
751
+ readonly childCreated: boolean;
752
+ readonly budget: FusionBudgetErrorDetail | undefined;
753
+ readonly runProgress: FusionRunProgress | undefined;
754
+
755
+ constructor(message: string, details: FusionErrorDetails) {
756
+ super(message);
757
+ this.name = 'FusionError';
758
+ this.code = details.code;
759
+ this.stage = details.stage;
760
+ this.slot = details.slot;
761
+ this.attempt = details.attempt;
762
+ this.artifactDir = details.artifactDir;
763
+ this.transient = details.transient ?? false;
764
+ this.childCreated = details.childCreated ?? true;
765
+ this.budget = details.budget;
766
+ this.runProgress = details.runProgress;
767
+ }
768
+ }
769
+
770
+ export interface FusionChildUsage extends FusionUsage {
771
+ provider: string;
772
+ model: string;
773
+ qualifiedId: string;
774
+ }
775
+
776
+ export type FusionToolCallLogStatus = 'ok' | 'error';
777
+
778
+ export interface FusionToolCallLogRecord {
779
+ schema_version: typeof FUSION_TOOL_CALL_LOG_SCHEMA_VERSION;
780
+ ordinal: number;
781
+ tool_name: string;
782
+ arguments_sha256: string;
783
+ arguments_bytes: number;
784
+ result_bytes: number;
785
+ result_sha256: string;
786
+ status: FusionToolCallLogStatus;
787
+ duration_ms: number;
788
+ url?: string | undefined;
789
+ /** SHA-256 of a rejected attempted fetch URL; raw rejected URLs are never persisted. */
790
+ rejected_url_sha256?: string | undefined;
791
+ final_url?: string | undefined;
792
+ http_status?: number | undefined;
793
+ response_bytes?: number | undefined;
794
+ content_sha256?: string | undefined;
795
+ }
796
+
797
+ export interface FusionToolCallLogSummary {
798
+ count: number;
799
+ total_result_bytes: number;
800
+ trace_complete: boolean;
801
+ }
802
+
803
+ export interface FusionToolCallTrace {
804
+ bytes: Buffer;
805
+ records: readonly FusionToolCallLogRecord[];
806
+ summary: FusionToolCallLogSummary;
807
+ }
808
+
809
+ export interface FusionCandidateOutputRecovery {
810
+ kind: 'same_session_compression';
811
+ limit_bytes: number;
812
+ original_record_index: number;
813
+ replacement_record_index: number | null;
814
+ original_json_rendered_bytes: number;
815
+ replacement_json_rendered_bytes: number | null;
816
+ original_text_sha256: string;
817
+ original_text: string;
818
+ status: 'completed' | 'failed';
819
+ }
820
+
821
+ export interface FusionChildRunResult {
822
+ stage: FusionStage;
823
+ slot?: 1 | 2 | 3;
824
+ attempt: number;
825
+ provider: string;
826
+ model: string;
827
+ qualifiedId: string;
828
+ text: string;
829
+ /** Aggregate usage across the complete child agent loop. */
830
+ usage: FusionUsage;
831
+ /** First provider request, used for like-for-like prompt forecast calibration. */
832
+ firstRequestUsage?: FusionUsage;
833
+ /** Number of provider requests represented by aggregate usage. */
834
+ providerRequestCount?: number;
835
+ outputRecovery?: FusionCandidateOutputRecovery;
836
+ events: Buffer;
837
+ stderr: Buffer;
838
+ exitCode: number;
839
+ signal: NodeJS.Signals | null;
840
+ toolCallTrace?: FusionToolCallTrace;
841
+ }
842
+
843
+ export interface FusionAttemptOutputRecoveryRecord {
844
+ kind: 'same_session_compression';
845
+ status: 'completed' | 'failed';
846
+ limit_bytes: number;
847
+ original_response_path: string;
848
+ original_record_index: number;
849
+ replacement_record_index: number | null;
850
+ original_json_rendered_bytes: number;
851
+ replacement_json_rendered_bytes: number | null;
852
+ original_text_sha256: string;
853
+ }
854
+
855
+ export interface FusionAttemptArtifactRecord {
856
+ stage: FusionStage;
857
+ slot?: 1 | 2 | 3;
858
+ attempt: number;
859
+ status: 'completed' | 'failed' | 'cancelled';
860
+ child_created: boolean;
861
+ prompt_path: string;
862
+ events_path?: string;
863
+ stderr_path?: string;
864
+ response_path?: string;
865
+ partial_response_path?: string;
866
+ tool_calls_path?: string;
867
+ tool_calls?: FusionToolCallLogSummary;
868
+ output_recovery?: FusionAttemptOutputRecoveryRecord;
869
+ provider?: string;
870
+ model?: string;
871
+ qualifiedId?: string;
872
+ usage?: FusionUsage;
873
+ error?: string;
874
+ }
875
+
876
+ export interface FusionArtifactRef {
877
+ path: string;
878
+ byte_length: number;
879
+ sha256: string;
880
+ }
881
+
882
+ export type FusionFailureArtifactClassification =
883
+ | 'complete_stage_output'
884
+ | 'partial_stage_output'
885
+ | 'oversized_original'
886
+ | 'empty_rejected_output'
887
+ | 'evidence_only';
888
+
889
+ export interface FusionFailureEvidenceArtifact {
890
+ name: string;
891
+ classification: FusionFailureArtifactClassification;
892
+ ref: FusionArtifactRef;
893
+ }
894
+
895
+ export interface FusionFailureAttemptMetadata {
896
+ stage: FusionStage;
897
+ slot?: 1 | 2 | 3 | undefined;
898
+ attempt: number;
899
+ status: 'completed' | 'failed' | 'cancelled';
900
+ child_created: boolean;
901
+ }
902
+
903
+ export interface FusionFailureList<T> {
904
+ listed: readonly T[];
905
+ omitted_count: number;
906
+ }
907
+
908
+ export interface FusionFailureMessageMetadata {
909
+ byte_length: number;
910
+ sha256: string;
911
+ inline_message?: string | undefined;
912
+ omission_reason?: 'exceeds_inline_message_bytes_cap' | 'result_view_byte_budget' | undefined;
913
+ }
914
+
915
+ export interface FusionFailureSummaryV1 {
916
+ schema_version: typeof FUSION_FAILURE_SUMMARY_SCHEMA_VERSION;
917
+ run_id: string;
918
+ workflow: FusionWorkflowId;
919
+ source: FusionSource;
920
+ terminal_state: Exclude<FusionTerminalState, 'completed'>;
921
+ created_at: string;
922
+ answer: { present: false; reason: 'run_did_not_commit' };
923
+ failure: {
924
+ code: FusionErrorCode | null;
925
+ stage?: FusionStage | undefined;
926
+ slot?: 1 | 2 | 3 | undefined;
927
+ attempt?: number | undefined;
928
+ child_created: boolean;
929
+ message: FusionFailureMessageMetadata;
930
+ };
931
+ progress: FusionRunProgress;
932
+ usage_so_far: FusionUsage;
933
+ attempts: FusionFailureList<FusionFailureAttemptMetadata>;
934
+ evidence_artifacts: FusionFailureList<FusionFailureEvidenceArtifact>;
935
+ remediation_ids: readonly (
936
+ | 'inspect_manifest_bound_evidence'
937
+ | 'inspect_terminal_error'
938
+ | 'split_or_reduce_work'
939
+ | 'retry_same_route_after_operator_review'
940
+ )[];
941
+ }
942
+
943
+ export interface FusionFailureViewFailure {
944
+ code?: FusionErrorCode | null | undefined;
945
+ stage?: FusionStage | undefined;
946
+ slot?: 1 | 2 | 3 | undefined;
947
+ attempt?: number | undefined;
948
+ child_created?: boolean | undefined;
949
+ message: FusionFailureMessageMetadata;
950
+ }
951
+
952
+ export interface FusionFailureResultView {
953
+ schema_version: typeof FUSION_FAILURE_SUMMARY_SCHEMA_VERSION;
954
+ summary_status: 'verified' | 'legacy_manifest_only' | 'unavailable' | 'integrity_failed';
955
+ terminal_state: Exclude<FusionTerminalState, 'completed'>;
956
+ answer: { present: false; reason: 'run_did_not_commit' };
957
+ failure?: FusionFailureViewFailure | undefined;
958
+ progress?: FusionRunProgress | undefined;
959
+ usage_so_far?: FusionUsage | undefined;
960
+ attempts?: FusionFailureList<FusionFailureAttemptMetadata> | undefined;
961
+ evidence_artifacts?: FusionFailureList<FusionFailureEvidenceArtifact> | undefined;
962
+ remediation_ids?: FusionFailureSummaryV1['remediation_ids'] | undefined;
963
+ failure_summary_ref?: FusionArtifactRef | undefined;
964
+ summary_unavailable_reason?: 'no_durable_summary' | 'manifest_untrusted' | 'summary_integrity_failed' | undefined;
965
+ }
966
+
967
+ export interface FusionArtifactManifest {
968
+ schema_version: typeof FUSION_MANIFEST_SCHEMA_VERSION;
969
+ run_id: string;
970
+ workflow: FusionWorkflowId;
971
+ source: FusionSource;
972
+ state: FusionState;
973
+ created_at: string;
974
+ updated_at: string;
975
+ cwd: string;
976
+ config: FusionModelConfigV1;
977
+ models: {
978
+ candidates: readonly [string, string, string];
979
+ evaluator: string;
980
+ merger: string;
981
+ thinking_level: string;
982
+ };
983
+ capabilities: {
984
+ candidate: FusionCapability;
985
+ evaluation: FusionCapability;
986
+ merge: FusionCapability;
987
+ };
988
+ context: {
989
+ kind: FusionContextKind;
990
+ policy_id: string;
991
+ ledger_artifact?: string;
992
+ source_policy_artifact?: string;
993
+ };
994
+ tool_policy: {
995
+ candidate_tools: readonly string[];
996
+ evaluation_tools: readonly [];
997
+ merge_tools: readonly [];
998
+ };
999
+ usage: FusionUsage;
1000
+ attempts: readonly FusionAttemptArtifactRecord[];
1001
+ artifacts: Readonly<Record<string, FusionArtifactRef>>;
1002
+ anonymous_map?: Readonly<Record<FusionCandidateId, 1 | 2 | 3>>;
1003
+ error?: string;
1004
+ }
1005
+
1006
+ export interface FusionRunResult {
1007
+ mergedText: string;
1008
+ details: FusionResultDetails;
1009
+ }
1010
+
1011
+ /** Snapshot of one configured route's verified input capacity for one stage. */
1012
+ export interface FusionRouteCapacity {
1013
+ role: 'candidate-1' | 'candidate-2' | 'candidate-3' | 'evaluator' | 'merger';
1014
+ provider: string;
1015
+ model: string;
1016
+ qualified_id: string;
1017
+ context_window_tokens: number;
1018
+ reserved_output_tokens: number;
1019
+ framing_reserve_tokens: number;
1020
+ safety_reserve_tokens: number;
1021
+ allowed_input_tokens: number;
1022
+ family: TokenBudgetFamily;
1023
+ rate_source: TokenBudgetRateSource;
1024
+ byte_capacity_utf8_bytes: number;
1025
+ }
1026
+
1027
+ export interface FusionBudgetStageComposition {
1028
+ visible_text_bytes: number;
1029
+ omission_receipt_bytes: number;
1030
+ projection_metadata_bytes: number;
1031
+ request_bytes: number;
1032
+ static_stage_framing_bytes: number;
1033
+ upstream_output_contract_bytes: number;
1034
+ }
1035
+
1036
+ export interface FusionStageBudgetPlanEntry {
1037
+ budget_stage: FusionBudgetStage;
1038
+ slot?: 1 | 2 | 3;
1039
+ route: FusionRouteCapacity;
1040
+ conditional: boolean;
1041
+ check_kind: 'input_only_preflight';
1042
+ input_utf8_bytes: number;
1043
+ upstream_output_contract_bytes: number;
1044
+ forecast_utf8_bytes: number;
1045
+ input_only_input_tokens_upper_bound: number;
1046
+ forecast_input_tokens_upper_bound: number;
1047
+ allowed_input_tokens: number;
1048
+ input_only_signed_headroom_tokens: number;
1049
+ signed_headroom_tokens: number;
1050
+ input_only_utilization_basis_points: number;
1051
+ utilization_basis_points: number;
1052
+ input_only_estimate: EstimateInputTokensResult;
1053
+ reservation_estimate: EstimateInputTokensResult;
1054
+ fits: boolean;
1055
+ reservation_fits: boolean;
1056
+ }
1057
+
1058
+ export interface FusionBudgetBlocker extends FusionStageBudgetPlanEntry {
1059
+ overage_tokens: number;
1060
+ bytes_over: number;
1061
+ }
1062
+
1063
+ export interface FusionBudgetWarning extends FusionStageBudgetPlanEntry {
1064
+ warning_kind: 'input_utilization' | 'worst_case_reservation';
1065
+ threshold_basis_points: number;
1066
+ }
1067
+
1068
+ export interface FusionBudgetEmptyRequestVerdict {
1069
+ request_utf8_bytes: number;
1070
+ still_fails_with_empty_request: boolean;
1071
+ shortening_request_can_help: boolean;
1072
+ minimum_request_byte_reduction: number;
1073
+ maximum_safe_request_utf8_bytes: number;
1074
+ blockers_with_empty_request: readonly FusionBudgetBlocker[];
1075
+ }
1076
+
1077
+ export interface FusionBudgetPlanV1 {
1078
+ schema_version: typeof FUSION_BUDGET_PLAN_SCHEMA_VERSION;
1079
+ workflow: FusionWorkflowId;
1080
+ context: { kind: FusionContextKind; policy_id: string };
1081
+ fixed_candidate_policy: { capability: FusionCapability; tools: readonly string[] };
1082
+ tool_policy: {
1083
+ candidate_tools: readonly string[];
1084
+ evaluation_tools: readonly [];
1085
+ merge_tools: readonly [];
1086
+ };
1087
+ policy: FusionBudgetPolicyDescriptor;
1088
+ routes: readonly FusionRouteCapacity[];
1089
+ stages: readonly FusionStageBudgetPlanEntry[];
1090
+ blockers: readonly FusionBudgetBlocker[];
1091
+ primary_blocker?: FusionBudgetBlocker;
1092
+ primary_blocker_composition?: FusionBudgetStageComposition;
1093
+ empty_request: FusionBudgetEmptyRequestVerdict;
1094
+ warnings: readonly FusionBudgetWarning[];
1095
+ }
1096
+
1097
+ /** Documented, versioned budget policy. */
1098
+ export interface FusionBudgetPolicyDescriptor {
1099
+ id: 'fusion-budget-policy-v4';
1100
+ route_output_reserve_strategy: 'max_fusion_contract_or_model_max';
1101
+ calibration_version: string;
1102
+ calibration_table: Readonly<Record<TokenBudgetFamily, TokenBudgetFamilyCalibration>>;
1103
+ reserved_output_tokens: number;
1104
+ framing_reserve_tokens: number;
1105
+ safety_reserve_tokens: number;
1106
+ candidate_output_contract_bytes: number;
1107
+ evaluation_output_contract_bytes: number;
1108
+ merge_output_contract_bytes: number;
1109
+ diagnostics_contract_bytes: number;
1110
+ utilization_warning_threshold_basis_points: 8000;
1111
+ }
1112
+
1113
+ export interface FusionCalibrationViolation {
1114
+ schema_version: typeof FUSION_CALIBRATION_VIOLATION_SCHEMA_VERSION;
1115
+ stage: FusionStage;
1116
+ slot?: 1 | 2 | 3;
1117
+ attempt: number;
1118
+ route: {
1119
+ provider: string;
1120
+ model: string;
1121
+ qualified_id: string;
1122
+ };
1123
+ family: TokenBudgetFamily;
1124
+ rate_source: TokenBudgetRateSource;
1125
+ prompt_utf8_bytes: number;
1126
+ prompt_sha256: string;
1127
+ observation_scope: 'first_provider_request';
1128
+ provider_request_count: number;
1129
+ forecast_input_tokens: number;
1130
+ billed_input_tokens: number;
1131
+ billed_input_breakdown: {
1132
+ input: number;
1133
+ cache_read: number;
1134
+ cache_write: number;
1135
+ };
1136
+ under_forecast_tokens: number;
1137
+ byte_class_breakdown: TokenBudgetByteClassBreakdown;
1138
+ dominant_byte_class: TokenBudgetDominantByteClass;
1139
+ }