pi-background-tasks 2.1.2 → 2.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/TESTING.md +1 -1
- package/TEST_PLAN.md +2 -2
- package/docs/manifest.json +2 -2
- package/docs/operations/configuration.md +4 -1
- package/docs/operations/troubleshooting.md +3 -2
- package/docs/reference/runtime-contracts.md +30 -30
- package/docs/subsystems/docs-freshness-gate.md +1 -1
- package/docs/subsystems/fusion.md +5 -4
- package/package.json +1 -1
- package/src/core/fusion/child-protocol.ts +3 -12
- package/src/core/fusion/pi-child.ts +9 -78
- package/src/core/fusion/types.ts +2 -1
- package/src/fusion-child-extension.ts +12 -126
package/README.md
CHANGED
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
| Fact | Value |
|
|
27
27
|
| --- | --- |
|
|
28
28
|
| Package | `pi-background-tasks` |
|
|
29
|
-
| Version | `2.1.
|
|
29
|
+
| Version | `2.1.3` |
|
|
30
30
|
| Node engine | `>=22.19.0` |
|
|
31
31
|
| Pi entrypoint | `./extensions/background-tasks.ts` |
|
|
32
32
|
| Package image | [logo.png](https://raw.githubusercontent.com/ismailsaleekh/pi-background-tasks/main/logo.png) |
|
package/TESTING.md
CHANGED
|
@@ -187,7 +187,7 @@ npm run test:rpc
|
|
|
187
187
|
npm run test:agent-loop
|
|
188
188
|
```
|
|
189
189
|
|
|
190
|
-
The Fusion SDK/RPC/scripted-provider tests install a deterministic fake child `pi` in a temp `PATH` from `tests/helpers/fusion-fake-pi.ts`. Parent Pi remains the real SDK/RPC runtime; only direct child `pi --mode text` calls with the package-owned private compact metadata extension are intercepted. SDK coverage proves the Fusion tools return after durable no-child preflight without waiting for delayed children, transfer cancellation ownership away from the completed tool call, remain tracked through status/dock/kill/notification, verify manifest-bound `result.json` plus `merged.md`, and attach complete usage on the first `bg_result` retrieval exactly once. The scripted provider proves launch → no-poll parent response → terminal wake → `bg_result` → verified answer. `PI_CODING_AGENT_DIR` is pointed at the temp agent directory so `fusion-models.json` is never read from the user's real global Pi directory. Fusion v1 public-surface coverage asserts exactly four tools (`fusion_reason`, `fusion_investigate`, `fusion_research`, `fusion_validate`), no public capability argument, retired-tool active-tool removal, `/fusion` mapping to reason/no-tool candidates, closed schemas with Google-compatible enum status, targeted URL fetch not search, URL exfiltration warnings, strict validation verification rules, historical v4 rendering without old-tool activation, and actionable migration errors for `fusion_validate({prompt})`. Fusion context coverage covers both reason conversation projection and clean-task non-interference invariants, including parent-sentinel absence from every clean downstream prompt/artifact and byte-identical clean inputs across unrelated parent sessions. `tests/unit/fusion-context-prompts.test.ts` verifies that a synthetic session carrying more than 1 MB of tool arguments/results still yields a small canonical input, that user and assistant text survive verbatim, that thinking and tool payloads never appear (including no head/tail/preview sentinel), that omission counts, byte totals, and hashes are exact and stable, that repeated construction is byte-identical, that the active Fusion tool leaf and sibling calls stay scope-excluded, that images remain marker-only or ledger-only with no raw base64 in child prompts, and that every retained source block receives exactly one disposition. `tests/unit/fusion-high-cardinality.test.ts` covers the receipt-cardinality regression: a session of many short interleaved tool events (rather than a few enormous results) pins per-receipt cost, proves the compact `omitted_activity` fields are the only model-facing ones, reconciles every receipt against the ledger through `projection_map`, and proves the whole workflow fits a real route budget. `tests/unit/fusion-budget.test.ts` covers stage budgets and stage-local refusal wording; orchestrator coverage derives terminal run progress from durable attempts after usage persistence so late evaluator/merge refusal reports completed, failed, cancelled, and not-started truth instead of claiming zero children. Each route reserves the larger of Fusion's output contract and the model's declared maximum output, the limiting model is selected by conservative byte capacity (including when it is the evaluator rather than a candidate), unknown or too-small capacities fail before spawn, boundary prompts pass at exactly the limit and fail one byte past it, the child system prompt counts as input, dense multi-byte UTF-8 cannot bypass byte accounting, and candidate, evaluator, evaluation-repair, and merger expansions are each rejected before their child is spawned with zero partial launches. `tests/unit/fusion-pi-child.test.ts` covers the post-launch `fusion-runtime-guard.
|
|
190
|
+
The Fusion SDK/RPC/scripted-provider tests install a deterministic fake child `pi` in a temp `PATH` from `tests/helpers/fusion-fake-pi.ts`. Parent Pi remains the real SDK/RPC runtime; only direct child `pi --mode text` calls with the package-owned private compact metadata extension are intercepted. SDK coverage proves the Fusion tools return after durable no-child preflight without waiting for delayed children, transfer cancellation ownership away from the completed tool call, remain tracked through status/dock/kill/notification, verify manifest-bound `result.json` plus `merged.md`, and attach complete usage on the first `bg_result` retrieval exactly once. The scripted provider proves launch → no-poll parent response → terminal wake → `bg_result` → verified answer. `PI_CODING_AGENT_DIR` is pointed at the temp agent directory so `fusion-models.json` is never read from the user's real global Pi directory. Fusion v1 public-surface coverage asserts exactly four tools (`fusion_reason`, `fusion_investigate`, `fusion_research`, `fusion_validate`), no public capability argument, retired-tool active-tool removal, `/fusion` mapping to reason/no-tool candidates, closed schemas with Google-compatible enum status, targeted URL fetch not search, URL exfiltration warnings, strict validation verification rules, historical v4 rendering without old-tool activation, and actionable migration errors for `fusion_validate({prompt})`. Fusion context coverage covers both reason conversation projection and clean-task non-interference invariants, including parent-sentinel absence from every clean downstream prompt/artifact and byte-identical clean inputs across unrelated parent sessions. `tests/unit/fusion-context-prompts.test.ts` verifies that a synthetic session carrying more than 1 MB of tool arguments/results still yields a small canonical input, that user and assistant text survive verbatim, that thinking and tool payloads never appear (including no head/tail/preview sentinel), that omission counts, byte totals, and hashes are exact and stable, that repeated construction is byte-identical, that the active Fusion tool leaf and sibling calls stay scope-excluded, that images remain marker-only or ledger-only with no raw base64 in child prompts, and that every retained source block receives exactly one disposition. `tests/unit/fusion-high-cardinality.test.ts` covers the receipt-cardinality regression: a session of many short interleaved tool events (rather than a few enormous results) pins per-receipt cost, proves the compact `omitted_activity` fields are the only model-facing ones, reconciles every receipt against the ledger through `projection_map`, and proves the whole workflow fits a real route budget. `tests/unit/fusion-budget.test.ts` covers stage budgets and stage-local refusal wording; orchestrator coverage derives terminal run progress from durable attempts after usage persistence so late evaluator/merge refusal reports completed, failed, cancelled, and not-started truth instead of claiming zero children. Each route reserves the larger of Fusion's output contract and the model's declared maximum output, the limiting model is selected by conservative byte capacity (including when it is the evaluator rather than a candidate), unknown or too-small capacities fail before spawn, boundary prompts pass at exactly the limit and fail one byte past it, the child system prompt counts as input, dense multi-byte UTF-8 cannot bypass byte accounting, and candidate, evaluator, evaluation-repair, and merger expansions are each rejected before their child is spawned with zero partial launches. `tests/unit/fusion-pi-child.test.ts` covers the post-launch `fusion-runtime-guard.v2` protocol, BUG-185 removal of live token/output-reservation admission, stable payload normalization, 128-request/192-tool limits, malformed or duplicate evidence rejection, typed parent errors, and failed audit sealing. `tests/unit/fusion-claude-cache.test.ts` pins native pre-serialization `ttl: "1h"` requests, explicit short/none/long policy, call-level compaction opt-out, model compatibility fallback, non-mutation, the four-breakpoint ceiling, subscription prompt-caching-scope beta idempotence, malformed-control refusal, and distinct `child_cache_policy_invalid` parent errors. Child argv tests pin the shared attribution provider → sanitizer → runtime-governor order; root attribution tests pin linked OAuth account/device/session metadata, beta-resource request shape, cache surfaces, one-hour provider usage pricing, and the 200K subscription policy. Compact/result usage tests preserve Anthropic `cacheWrite1h` and provider `reasoning` subsets, and child metadata binds each requested/effective payload observation plus JSON-rendered output accounting in `fusion-child-result.v4`. Live subscription-OAuth acceptance on 2026-08-04 proved cold writes plus exact-repeat reads on Sonnet 4.5 and Opus 5 while both reported `cacheWrite1h = 0`. Separate normal-spawn and exact Fusion-child Opus 5 controls—with unique prompts—still read their caches after 370 idle seconds; the Fusion control wrote and reread 9,922 tokens through the attribution → sanitizer → governor path. Documentation therefore treats positive `cacheWrite1h` as definitive but zero as inconclusive on subscription OAuth; payload intent, provider itemization, and behavioral lifetime remain separate evidence. Terminal `fusion-child-settlement.v3` is published only at `agent_settled`; recovered non-final provider errors must be zero-content/zero-usage retry markers named by that settlement, and one non-final candidate `stop` is accepted only when it is a hash-bound oversized original immediately followed by a same-session replacement. `tests/scripted-provider/fusion-output-recovery.test.ts` drives a real Pi print-mode process and proves one PID/session context, one queued continuation before settlement, tool removal on turn two, original-artifact preservation, and replacement-only stdout. Missing/duplicate/tampered/failed settlements or substantive error records remain fatal. `tests/scripted-provider/fusion-runtime-guard.test.ts` drives a real Pi agent loop through Pi's `openai-codex-responses` adapter against local HTTP and proves provider-payload transforms chain in load order and `ctx.abort()` prevents transport for the execution/cache-policy refusals that remain. `tests/package/typebox-compat.test.ts` pins the TypeBox posture and compiles nullable-array schemas. The release-only `npm run test:compat` packs the package, installs exact supported Pi versions, runs `/jobs`, runs `/fusion` through the installed package entrypoint with the fake child Pi, verifies five child invocations, verifies `/fusion-models` rejects non-TUI mode, requires each supported Pi line to declare terminal `agent_settled` and `before_provider_request`, verifies the installed Anthropic adapter exposes cache breakpoints plus long/tool compatibility controls, asserts the resolved `typebox` is Pi's bundled peer rather than a private or nested copy, and scans the installed package bytes for TypeBox APIs removed in the 1.3.x line. Pi 0.75.5 is intentionally unsupported because it lacks the terminal event required to seal a Fusion audit after retries and compaction. It then drives the current host Pi through a real RPC `fusion_reason` parent-agent loop, checks the persisted tool result carries the complete Pi `Usage.cost` object, invokes `get_session_stats` (the same aggregation boundary used by the TUI footer), reopens the durable session, and verifies identical token/cost totals. All parent and child inference remains deterministic and local.
|
|
191
191
|
|
|
192
192
|
## Coverage summary
|
|
193
193
|
|
package/TEST_PLAN.md
CHANGED
|
@@ -76,14 +76,14 @@ SDK/RPC/scripted-provider/package/compatibility coverage asserts exactly four to
|
|
|
76
76
|
| Stop task from LLM tool | `bg_kill` | | yes | | | | | | Covers running kill and already-finished loud failure. |
|
|
77
77
|
| Fusion command background launch | `/fusion`, managed task, terminal notification, `bg_result` | yes | yes | yes | | yes | yes | | Core unit covers deterministic projection, child argv/stdin/metadata parsing, artifacts, pre-abort handling, and orchestration. SDK verifies `/fusion` returns after durable preflight, all five child invocations continue in the managed task, terminal notification is emitted without a parent rewrite, editor/cancel behavior remains correct, and malformed config launches zero children. RPC verifies command discovery, Unicode request preservation, background terminal delivery, no parent `agent_start`, editor protocol, malformed-config admission failure, child failure notification, and child isolation flags. |
|
|
78
78
|
| Fusion v1 background result | `fusion_reason`, `fusion_investigate`, `fusion_research`, `fusion_validate`, `bg_result` | yes | yes | | | current-host stats/replay | yes | yes | Exactly four workflow tools remain registered; each returns a managed-task receipt after durable no-child preflight. `bg_result` verifies manifest-bound `result.json`/`merged.md`, never truncates, and attaches complete `Usage` exactly once. SDK pins non-blocking launch under delayed children, tool-signal ownership handoff, clean-context isolation, failure coordinates, shutdown cancellation, and repeated-retrieval no-double-counting. Scripted-provider coverage proves no polling between launch and terminal wake. |
|
|
79
|
-
| Fusion Anthropic attribution and sanitization | package-owned `anthropic-attribution.ts`, `@ravshansbox/pi-anthropic-sps`, child `--extension` argv | yes | | | | | yes | | Unit proves a Claude route receives exactly three explicit extensions in fixed order: the package-owned Claude Code OAuth attribution provider, sanitizer, then runtime governor/metadata extension. The repo-local `spawn-anthropic-attribution` entrypoint re-exports the same implementation. Attribution tests pin linked session/account/device metadata, exact model beta policy, beta-resource transport, cache surfaces, one-hour pricing, and the 200K subscription contract; the governor therefore
|
|
79
|
+
| Fusion Anthropic attribution and sanitization | package-owned `anthropic-attribution.ts`, `@ravshansbox/pi-anthropic-sps`, child `--extension` argv | yes | | | | | yes | | Unit proves a Claude route receives exactly three explicit extensions in fixed order: the package-owned Claude Code OAuth attribution provider, sanitizer, then runtime governor/metadata extension. The repo-local `spawn-anthropic-attribution` entrypoint re-exports the same implementation. Attribution tests pin linked session/account/device metadata, exact model beta policy, beta-resource transport, cache surfaces, one-hour pricing, and the 200K subscription contract; the governor therefore observes and validates the final attributed and sanitized payload. Every non-Anthropic provider still receives exactly one extension and resolves neither Claude dependency. Resolution failures remain loud, and package guards require the sanitizer dependency plus provider gate. |
|
|
80
80
|
| Fusion validation workflow | structured `fusion_validate`, workflow profiles, `fusion-manifest.v4`, `fusion-result.v5` | yes | yes | | | | yes | | Public validation rejects legacy `{prompt}` with a migration error, enforces non-empty `scope`/`acceptanceCriteria`, and loudly validates `verification` cross-fields (`provided` ↔ evidence, `not_run` ↔ reason). Core validate orchestration is clean/read-only/advisory, enforces source-finding accounting including singleton, duplicate, exclusion, and merger add/drop cases, and remains no build/test substitute claim. |
|
|
81
81
|
| Fusion context boundaries | canonical input `fusion-input.v5`, reason `context-omission-ledger.json`, clean-task inputs | yes | yes | yes | | | yes | | Unit covers reason/session projection for a >1 MB synthetic tool-heavy session, verbatim user/assistant text, thinking exclusion, zero tool-payload preview bytes, exact and stable omission counts/byte totals/hashes, compact tuple round-trip, receipt-to-ledger reconciliation, active-tool-call-leaf and sibling-call exclusion, and byte-identical repeated construction. Clean-task tests assert investigate/research/validate inputs omit parent system prompt, conversation projection, and omission ledger, stay byte-identical across unrelated parent sessions, and keep parent sentinels out of every clean downstream prompt and artifact. SDK/RPC verify clean validate stdin has no `conversation_projection` or transcript while `/fusion`/reason preserve the projected-conversation path. |
|
|
82
82
|
| Fusion stage budgets | `budget-plan.json` (v4 per-stage forecasts), typed `prompt_budget_exceeded_forecast` / `prompt_budget_exceeded_measured` | yes | | | | | | | Unit covers stage-local launch-refusal wording plus terminal progress derived from durable attempts and persisted usage, so late evaluator/repair/merger budget failures report completed, failed, cancelled, and not-started run truth. Unit also covers the per-family affine estimator, additive segment accounting, multibyte 1.0-token/byte charging, unknown-provider floor visibility, per-route reservation of `max(Fusion output contract, model maximum output)`, byte-capacity route selection, scope guards for small windows, input-only fatal preflight versus warning-only reservations, rejection of unknown/zero/negative/too-small context windows, boundary accept at exactly the limit and reject one byte past, the child system prompt counted as input, per-stage forecasts built from the real prompt builders against each stage's own route, reservation warnings, breach-detector artifacts, safe prompts completing all five calls, persisted route/plan snapshots including negative slack on fatal rejection, and the reproduced 1 MB failure shape now fitting the smallest configured budget. Errors carry stage, measured size, allowed size, limiting model, estimator source, and remediation in both structured detail and message text. |
|
|
83
83
|
| Fusion fixed-purpose profiles | `/fusion`, `fusion_reason`, `fusion_investigate`, `fusion_research`, `fusion_validate`, candidate child argv | yes | yes | yes | | | yes | | Public surface has no caller-selected capability. SDK/RPC pin `/fusion` to reason/no-tool candidates; investigate is read-only, research is targeted URL fetch with public http(s) source validation, and evaluator/merger remain no-tools by stage policy. Package guards reject extra keys and verify schemas are closed. |
|
|
84
84
|
| Fusion research web fetch | `fusion_web_fetch({ url, extract? })`, `candidate-<slot>.attempt-<n>.tool-calls.jsonl` | yes | | | | | yes | live child | Unit covers the closed schema surface through the child extension, registration only when research mode is enabled, unsupported schemes and URL credentials failing before network access, blocked DNS classes, a mixed public-plus-blocked DNS answer failing loudly, a redirect to a blocked address failing loudly, redirect-loop limit failure, Content-Length and streamed-body response caps, unsupported content types, Markdown extraction preserving links/headings/tables/code blocks, script/style stripping, text/plain passthrough with hash and byte count, UTF-8-safe output truncation, and typed timeout. Unit also proves the resolver is consulted once and the connection is pinned to that vetted address, undeclared research URLs are rejected before fetch with only the attempted URL hash audited, and that audit metadata records `url`, `final_url`, `http_status`, `response_bytes`, and `content_sha256` without raw page content. Package guards require `fusion_web_fetch` registration behind the research env flag. Live verification fetched `https://example.com/`, reported the page H1, read a repository constant, and refused instruction-like text from both a repo file and the fetched page. |
|
|
85
85
|
| Fusion multi-message transcript validation | `*.events.jsonl`, `fusion-child-result.v4`, `fusion-child-settlement.v3`, stop reasons `toolUse`/`stop` plus recovered retry/output-cap markers | yes | | | | | | real Pi print mode | Unit accepts a multi-message tool loop, validates increasing cache-observation request ordinals, reconstructs stdout from the final assistant message only, and sums usage across all compact metadata records. Terminal `agent_settled` emits exactly one settlement binding ordered record bytes/count/final hash. Non-final `toolUse` remains normal; non-final `error` is accepted only when it has zero content and usage, is followed by final `stop`, and its ordinal is hash-bound in the settlement. Exactly one non-final `stop` is accepted only as a hash-bound candidate response over 49,152 JSON-rendered bytes immediately followed by its same-session replacement. A real Pi print-mode characterization proves the queued continuation remains in one PID/conversation, disables tools, delays settlement, and outputs only the replacement. Final/non-zero errors, unbound non-final `stop`, `length`, `aborted`, `pending`, missing/duplicate/tampered/failed settlements, and pre-settlement shutdown fail loudly. |
|
|
86
|
-
| Fusion runtime
|
|
86
|
+
| Fusion runtime execution guard | `pi-background-tasks.fusion-runtime-guard.v2`, typed `child_runtime_limit_exceeded` / `child_runtime_payload_invalid` | yes | | | | | mutation guard | scripted provider | BUG-185 unit coverage proves arbitrarily large stable payloads are not refused by subtracting possible output from the context window. Request 128/tool call 192 are allowed and the next is refused; malformed payloads, malformed/duplicate frames, route drift, and clean-looking post-refusal output fail closed; parent errors preserve observed usage. The package mutation guard forbids runtime token-estimator/output-reservation admission from returning. A real local-HTTP Pi loop through the production `openai-codex-responses` adapter proves earlier payload transforms reach the later hook and `ctx.abort()` prevents transport for retained execution/cache-policy refusals. |
|
|
87
87
|
| Fusion stale-action watchdog | `FUSION_CHILD_IDLE_TIMEOUT_MS`, child process lifecycle | yes | | | | | | | Unit proves a child with no stdout or stderr activity fails as `child_timeout` with the stalled-child message and is terminated; stderr activity resets the watchdog and allows success; the 30-minute absolute timeout path remains distinct and is not reported as a stalled child. |
|
|
88
88
|
| Fusion candidate tool-call audit log | `candidate-<slot>.attempt-<n>.tool-calls.jsonl`, `*.seal.json`, `pi-background-tasks.fusion-tool-call.v1` | yes | | | | | | | Unit proves completed tool calls are logged with tool name, byte counts, and hashes while raw arguments/results containing a secret never appear. Children are independently bounded to 192 attempted tool calls and 8 MiB aggregate tool-result bytes; a limit refusal emits structured evidence, aborts, and cannot publish a complete seal. Repeated low-level `agent_end` boundaries publish no seal; terminal `agent_settled` exclusively seals the complete log after all retry/compaction/follow-up work. The 46-call incident regression proves a 22-call prefix is never sealed and duplicate settlement fails without replacement. Shutdown before settlement writes failed evidence and latches process failure. The parent rejects extension diagnostics and missing/failed/mismatched seals and independently rejects aggregate result bytes above 8 MiB. A trailing partial line, ordinal gap, duplicate ordinal, wrong schema version, and inspect-child partial log all fail loudly. |
|
|
89
89
|
| Pi/TypeBox compatibility | `peerDependencies`, packed bytes | yes | | | | | yes | | Unit pins typebox as a `"*"` peer that is neither a runtime nor bundled dependency, requires the resolved TypeBox to be Pi 0.83/0.84's 1.3.x line, requires all four supported Pi/TUI lines in the peer range, scans all package TypeScript for the seven removed TypeBox APIs, and compiles the shipped tool schema plus nullable-array/nullable-string and optional-field shapes under TypeBox 1.3. The release compat gate repeats the removed-API scan against installed package bytes per Pi version. |
|
package/docs/manifest.json
CHANGED
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
"state": "stale-authored-prose"
|
|
88
88
|
},
|
|
89
89
|
{
|
|
90
|
-
"authored_body_sha256": "sha256:
|
|
90
|
+
"authored_body_sha256": "sha256:b9cc1885689abbe978fd4fd5306e11e4526324da10ef0d42cb6c90841ea61925",
|
|
91
91
|
"covers_sources": [
|
|
92
92
|
"extensions/fusion-child.ts",
|
|
93
93
|
"src/core/fusion/anthropic-attribution.ts",
|
|
@@ -791,7 +791,7 @@
|
|
|
791
791
|
"image": "https://raw.githubusercontent.com/ismailsaleekh/pi-background-tasks/main/logo.png",
|
|
792
792
|
"name": "pi-background-tasks",
|
|
793
793
|
"type": "module",
|
|
794
|
-
"version": "2.1.
|
|
794
|
+
"version": "2.1.3"
|
|
795
795
|
},
|
|
796
796
|
"public_surface_ids": [
|
|
797
797
|
"command:bg",
|
|
@@ -101,6 +101,9 @@ These are source constants, not documented operator env knobs:
|
|
|
101
101
|
| Child stale-output watchdog | 20 minutes |
|
|
102
102
|
| Child stdout cap | 32 MiB |
|
|
103
103
|
| Child stderr cap | 4 MiB |
|
|
104
|
+
| Provider requests per child | 128 |
|
|
105
|
+
| Tool calls per child | 192 |
|
|
106
|
+
| Aggregate candidate tool-result bytes | 8 MiB |
|
|
104
107
|
| Candidate output contract | 48 KiB JSON-rendered bytes |
|
|
105
108
|
| Evaluator output contract | 64 KiB JSON-rendered bytes |
|
|
106
109
|
| Merger output contract | 64 KiB JSON-rendered bytes |
|
|
@@ -109,7 +112,7 @@ These are source constants, not documented operator env knobs:
|
|
|
109
112
|
| `fusion_web_fetch` returned content cap | 32 KiB |
|
|
110
113
|
| `fusion_web_fetch` redirect cap | 5 hops |
|
|
111
114
|
|
|
112
|
-
Oversized Fusion outputs fail loudly and are preserved in local artifacts where applicable. They are not forwarded or silently truncated.
|
|
115
|
+
Oversized Fusion outputs fail loudly and are preserved in local artifacts where applicable. They are not forwarded or silently truncated. Post-launch Fusion requests are not admitted or refused by estimating live input tokens and subtracting the model's possible output from its context window; Pi/provider context handling remains authoritative after Fusion's pre-spawn stage-budget checks.
|
|
113
116
|
|
|
114
117
|
## Offline behavior
|
|
115
118
|
|
|
@@ -29,8 +29,9 @@ Start from the symptom, verify the source-owned doc, then apply the remediation.
|
|
|
29
29
|
| Delegate result corruption/hash/identity mismatch | Result package does not match task/seed/route/hash contract | Treat as invalid; inspect artifact bytes. Do not synthesize an answer. |
|
|
30
30
|
| Fusion model unavailable or metered route refusal | Frontier route is not admitted as a Pi subscription/OAuth route, or configured model is stale | Fix `/fusion-models` config to available subscription routes. Never route GPT/Claude-class work through metered APIs. |
|
|
31
31
|
| Fusion prompt budget exceeded | Stage forecast or measured prompt exceeds limiting route capacity after reserving the larger of the Fusion output contract and route maximum output | Use a larger-context or lower-max-output configured subscription route, or reduce explicit request/context. Do not route-substitute after planning. |
|
|
32
|
-
| `
|
|
33
|
-
| `
|
|
32
|
+
| `child_runtime_limit_exceeded` | The child exceeded 128 provider requests or 192 tool calls | Inspect the failed audit seal and split an unbounded task; do not raise limits blindly. |
|
|
33
|
+
| `child_runtime_payload_invalid` | The final provider payload could not be normalized as one stable JSON object | Fix the provider/payload integration; Fusion does not fall back to a lossy serializer. |
|
|
34
|
+
| `child_cache_policy_invalid` | Claude cache policy, retention configuration, or final cache-control shape was invalid | Set `PI_CACHE_RETENTION` to `none`, `short`, or `long`; do not bypass its four-breakpoint or shape checks. |
|
|
34
35
|
| Fusion child timeout vs idle timeout | Absolute timeout is 30 minutes; idle watchdog is 20 minutes of no stdout/stderr activity | Preserve distinction in errors. `FUSION_CHILD_IDLE_TIMEOUT_MS` is a source constant, not documented as env-configurable. |
|
|
35
36
|
| Fusion research URL rejected | Source URL is not declared/public http(s), has credentials, resolves to blocked address class, or redirects unsafely | Provide declared public source URLs with purpose; targeted fetch is not search. |
|
|
36
37
|
| `/fusion-models` rejects in non-TUI mode | Selector requires interactive UI | Use an interactive Pi TUI session to edit config; headless path should fail loudly. |
|
|
@@ -16,27 +16,27 @@ This generated registry lists production environment-variable references, runtim
|
|
|
16
16
|
|
|
17
17
|
| Name | Access | Provenance |
|
|
18
18
|
| --- | --- | --- |
|
|
19
|
-
| `ANTHROPIC_API_KEY` | remove | `src/core/attested-pi-run.ts:135`<br>`src/core/fusion/pi-child.ts:
|
|
20
|
-
| `ANTHROPIC_AUTH_TOKEN` | remove | `src/core/fusion/pi-child.ts:
|
|
21
|
-
| `ANTHROPIC_BASE_URL` | remove | `src/core/attested-pi-run.ts:135`<br>`src/core/fusion/pi-child.ts:
|
|
22
|
-
| `AZURE_OPENAI_AD_TOKEN` | remove | `src/core/fusion/pi-child.ts:
|
|
23
|
-
| `AZURE_OPENAI_API_KEY` | remove | `src/core/fusion/pi-child.ts:
|
|
24
|
-
| `AZURE_OPENAI_API_VERSION` | remove | `src/core/fusion/pi-child.ts:
|
|
25
|
-
| `AZURE_OPENAI_BASE_URL` | remove | `src/core/fusion/pi-child.ts:
|
|
26
|
-
| `AZURE_OPENAI_DEPLOYMENT_NAME_MAP` | remove | `src/core/fusion/pi-child.ts:
|
|
27
|
-
| `AZURE_OPENAI_ENDPOINT` | remove | `src/core/fusion/pi-child.ts:
|
|
28
|
-
| `AZURE_OPENAI_RESOURCE_NAME` | remove | `src/core/fusion/pi-child.ts:
|
|
19
|
+
| `ANTHROPIC_API_KEY` | remove | `src/core/attested-pi-run.ts:135`<br>`src/core/fusion/pi-child.ts:98` |
|
|
20
|
+
| `ANTHROPIC_AUTH_TOKEN` | remove | `src/core/fusion/pi-child.ts:98` |
|
|
21
|
+
| `ANTHROPIC_BASE_URL` | remove | `src/core/attested-pi-run.ts:135`<br>`src/core/fusion/pi-child.ts:98` |
|
|
22
|
+
| `AZURE_OPENAI_AD_TOKEN` | remove | `src/core/fusion/pi-child.ts:98` |
|
|
23
|
+
| `AZURE_OPENAI_API_KEY` | remove | `src/core/fusion/pi-child.ts:98` |
|
|
24
|
+
| `AZURE_OPENAI_API_VERSION` | remove | `src/core/fusion/pi-child.ts:98` |
|
|
25
|
+
| `AZURE_OPENAI_BASE_URL` | remove | `src/core/fusion/pi-child.ts:98` |
|
|
26
|
+
| `AZURE_OPENAI_DEPLOYMENT_NAME_MAP` | remove | `src/core/fusion/pi-child.ts:98` |
|
|
27
|
+
| `AZURE_OPENAI_ENDPOINT` | remove | `src/core/fusion/pi-child.ts:98` |
|
|
28
|
+
| `AZURE_OPENAI_RESOURCE_NAME` | remove | `src/core/fusion/pi-child.ts:98` |
|
|
29
29
|
| `ComSpec` | read | `src/core/common.ts:725`<br>`src/core/common.ts:736` |
|
|
30
|
-
| `OPENAI_API_KEY` | remove | `src/core/attested-pi-run.ts:135`<br>`src/core/fusion/pi-child.ts:
|
|
31
|
-
| `OPENAI_BASE_URL` | remove | `src/core/attested-pi-run.ts:135`<br>`src/core/fusion/pi-child.ts:
|
|
32
|
-
| `OPENROUTER_API_KEY` | remove | `src/core/attested-pi-run.ts:135`<br>`src/core/fusion/pi-child.ts:
|
|
33
|
-
| `OPENROUTER_BASE_URL` | remove | `src/core/attested-pi-run.ts:135`<br>`src/core/fusion/pi-child.ts:
|
|
30
|
+
| `OPENAI_API_KEY` | remove | `src/core/attested-pi-run.ts:135`<br>`src/core/fusion/pi-child.ts:98` |
|
|
31
|
+
| `OPENAI_BASE_URL` | remove | `src/core/attested-pi-run.ts:135`<br>`src/core/fusion/pi-child.ts:98` |
|
|
32
|
+
| `OPENROUTER_API_KEY` | remove | `src/core/attested-pi-run.ts:135`<br>`src/core/fusion/pi-child.ts:98` |
|
|
33
|
+
| `OPENROUTER_BASE_URL` | remove | `src/core/attested-pi-run.ts:135`<br>`src/core/fusion/pi-child.ts:98` |
|
|
34
34
|
| `path` | read | `src/core/common.ts:680` |
|
|
35
35
|
| `Path` | read | `src/core/common.ts:680` |
|
|
36
36
|
| `PATH` | read | `src/core/common.ts:680` |
|
|
37
|
-
| `PI_API_BASE_URL` | remove | `src/core/attested-pi-run.ts:135`<br>`src/core/fusion/pi-child.ts:
|
|
38
|
-
| `PI_API_KEY` | remove | `src/core/attested-pi-run.ts:135`<br>`src/core/fusion/pi-child.ts:
|
|
39
|
-
| `PI_AUTH_FILE` | remove | `src/core/attested-pi-run.ts:135`<br>`src/core/fusion/pi-child.ts:
|
|
37
|
+
| `PI_API_BASE_URL` | remove | `src/core/attested-pi-run.ts:135`<br>`src/core/fusion/pi-child.ts:98` |
|
|
38
|
+
| `PI_API_KEY` | remove | `src/core/attested-pi-run.ts:135`<br>`src/core/fusion/pi-child.ts:98` |
|
|
39
|
+
| `PI_AUTH_FILE` | remove | `src/core/attested-pi-run.ts:135`<br>`src/core/fusion/pi-child.ts:98` |
|
|
40
40
|
| `PI_BG_DELEGATE_ARTIFACT_DIR` | read, write | `src/core/delegate/launch.ts:324`<br>`src/delegate-child-extension.ts:276` |
|
|
41
41
|
| `PI_BG_DELEGATE_LAUNCH_NONCE` | read, write | `src/core/delegate/launch.ts:328`<br>`src/delegate-child-extension.ts:280` |
|
|
42
42
|
| `PI_BG_DELEGATE_SEED_PATH` | read, write | `src/core/delegate/launch.ts:325`<br>`src/delegate-child-extension.ts:277` |
|
|
@@ -48,19 +48,19 @@ This generated registry lists production environment-variable references, runtim
|
|
|
48
48
|
| `PI_BG_REGISTRY_URL` | read | `src/extension.ts:464` |
|
|
49
49
|
| `PI_BG_SHELL` | read | `src/core/common.ts:721` |
|
|
50
50
|
| `PI_BG_SHELL_PATH` | read | `src/core/common.ts:722` |
|
|
51
|
-
| `PI_CACHE_RETENTION` | read, write | `src/core/fusion/anthropic-attribution.ts:577`<br>`src/core/fusion/claude-cache.ts:57`<br>`src/core/fusion/pi-child.ts:
|
|
52
|
-
| `PI_FUSION_CANDIDATE_OUTPUT_RECOVERY_PATH` | read, remove, write | `src/core/fusion/pi-child.ts:
|
|
53
|
-
| `PI_FUSION_RESEARCH_ENABLED` | read, remove, write | `src/core/fusion/pi-child.ts:
|
|
54
|
-
| `PI_FUSION_SOURCE_POLICY_PATH` | read, remove, write | `src/core/fusion/pi-child.ts:
|
|
55
|
-
| `PI_FUSION_SOURCE_POLICY_SHA256` | read, remove, write | `src/core/fusion/pi-child.ts:
|
|
56
|
-
| `PI_FUSION_TOOL_CALL_LOG_PATH` | read, remove, write | `src/core/fusion/pi-child.ts:
|
|
57
|
-
| `PI_MODEL` | remove | `src/core/delegate/launch.ts:301`<br>`src/core/fusion/pi-child.ts:
|
|
51
|
+
| `PI_CACHE_RETENTION` | read, write | `src/core/fusion/anthropic-attribution.ts:577`<br>`src/core/fusion/claude-cache.ts:57`<br>`src/core/fusion/pi-child.ts:271`<br>`src/core/fusion/pi-child.ts:272` |
|
|
52
|
+
| `PI_FUSION_CANDIDATE_OUTPUT_RECOVERY_PATH` | read, remove, write | `src/core/fusion/pi-child.ts:1989`<br>`src/core/fusion/pi-child.ts:98`<br>`src/fusion-child-extension.ts:599` |
|
|
53
|
+
| `PI_FUSION_RESEARCH_ENABLED` | read, remove, write | `src/core/fusion/pi-child.ts:2012`<br>`src/core/fusion/pi-child.ts:98`<br>`src/fusion-child-extension.ts:608` |
|
|
54
|
+
| `PI_FUSION_SOURCE_POLICY_PATH` | read, remove, write | `src/core/fusion/pi-child.ts:2013`<br>`src/core/fusion/pi-child.ts:98`<br>`src/fusion-child-extension.ts:555` |
|
|
55
|
+
| `PI_FUSION_SOURCE_POLICY_SHA256` | read, remove, write | `src/core/fusion/pi-child.ts:2014`<br>`src/core/fusion/pi-child.ts:98`<br>`src/fusion-child-extension.ts:556` |
|
|
56
|
+
| `PI_FUSION_TOOL_CALL_LOG_PATH` | read, remove, write | `src/core/fusion/pi-child.ts:2001`<br>`src/core/fusion/pi-child.ts:98`<br>`src/fusion-child-extension.ts:598` |
|
|
57
|
+
| `PI_MODEL` | remove | `src/core/delegate/launch.ts:301`<br>`src/core/fusion/pi-child.ts:98` |
|
|
58
58
|
| `PI_OFFLINE` | read | `src/extension.ts:456` |
|
|
59
|
-
| `PI_PROVIDER` | remove | `src/core/delegate/launch.ts:301`<br>`src/core/fusion/pi-child.ts:
|
|
60
|
-
| `PI_REASONING_LEVEL` | remove | `src/core/delegate/launch.ts:301`<br>`src/core/fusion/pi-child.ts:
|
|
61
|
-
| `PI_SESSION_FILE` | remove | `src/core/delegate/launch.ts:301`<br>`src/core/fusion/pi-child.ts:
|
|
62
|
-
| `PI_SESSION_ID` | remove | `src/core/delegate/launch.ts:301`<br>`src/core/fusion/pi-child.ts:
|
|
63
|
-
| `PI_SKIP_VERSION_CHECK` | write | `src/core/delegate/launch.ts:323`<br>`src/core/fusion/pi-child.ts:
|
|
59
|
+
| `PI_PROVIDER` | remove | `src/core/delegate/launch.ts:301`<br>`src/core/fusion/pi-child.ts:98` |
|
|
60
|
+
| `PI_REASONING_LEVEL` | remove | `src/core/delegate/launch.ts:301`<br>`src/core/fusion/pi-child.ts:98` |
|
|
61
|
+
| `PI_SESSION_FILE` | remove | `src/core/delegate/launch.ts:301`<br>`src/core/fusion/pi-child.ts:98` |
|
|
62
|
+
| `PI_SESSION_ID` | remove | `src/core/delegate/launch.ts:301`<br>`src/core/fusion/pi-child.ts:98` |
|
|
63
|
+
| `PI_SKIP_VERSION_CHECK` | write | `src/core/delegate/launch.ts:323`<br>`src/core/fusion/pi-child.ts:270` |
|
|
64
64
|
| `PIPELINE_ANTHROPIC_ATTRIBUTION_AUDIT_PATH` | read | `src/core/fusion/anthropic-attribution.ts:1003` |
|
|
65
65
|
| `SHELL` | read | `src/core/common.ts:717` |
|
|
66
66
|
| `SystemRoot` | read | `src/core/windows-taskkill.ts:96` |
|
|
@@ -151,7 +151,7 @@ This generated registry lists production environment-variable references, runtim
|
|
|
151
151
|
| `pi-background-tasks.fusion-result-view.v1` | `src/delegate-extension.ts:669` |
|
|
152
152
|
| `pi-background-tasks.fusion-result.v4` | `src/core/fusion/types.ts:19` |
|
|
153
153
|
| `pi-background-tasks.fusion-result.v5` | `src/core/fusion/types.ts:20` |
|
|
154
|
-
| `pi-background-tasks.fusion-runtime-guard.
|
|
154
|
+
| `pi-background-tasks.fusion-runtime-guard.v2` | `src/core/fusion/child-protocol.ts:24` |
|
|
155
155
|
| `pi-background-tasks.fusion-source-policy.v1` | `src/core/fusion/types.ts:26` |
|
|
156
156
|
| `pi-background-tasks.fusion-tool-call-seal.v1` | `src/core/fusion/child-protocol.ts:21` |
|
|
157
157
|
| `pi-background-tasks.fusion-tool-call.v1` | `src/core/fusion/types.ts:32` |
|
|
@@ -12,7 +12,7 @@ covers_sources: []
|
|
|
12
12
|
This authored section defines the boundary: documentation facts are extracted from package metadata and TypeScript ASTs, then generated into docs and the manifest. Unsupported syntax fails the gate rather than falling back to regex or stale hand-maintained inventories. Public registrations must remain unconditional top-level direct calls or use the one validated local tool-wrapper shape; host/method aliases, computed access, nested or conditional registration, wrapper chaining/passing, constructor helpers, ambiguous public metadata, destructured Pi parameters, and repeated imported registrars are rejected.
|
|
13
13
|
|
|
14
14
|
<!-- pi-docs:begin name="docs-freshness-gate" generator="scripts/docs/generate.mjs" -->
|
|
15
|
-
- Canonical package version: `2.1.
|
|
15
|
+
- Canonical package version: `2.1.3`
|
|
16
16
|
- Governed markdown docs: 40
|
|
17
17
|
- Public surfaces extracted: 30
|
|
18
18
|
- Governed production sources: 48
|
|
@@ -92,7 +92,7 @@ Fusion never calls direct completion APIs. It launches direct child `pi --mode t
|
|
|
92
92
|
|
|
93
93
|
Child text mode writes the final full answer to stdout. The private child extension emits compact reasoning-free metadata frames to stderr for finalized assistant messages: provider/model, stop reason, text block byte counts and hashes, aggregate text hash, the complete Pi `Usage` object (including Anthropic `cacheWrite1h` and provider-reported reasoning subsets), and a closed cache-policy observation. It governs every final `before_provider_request` payload after attribution and sanitization. For Anthropic routes, the child environment defaults `PI_CACHE_RETENTION` to `long` before provider serialization, so the attribution/Pi adapter creates system, final-tool, and final-conversation breakpoints with `ttl: "1h"`; inherited `PI_CACHE_RETENTION=short|none|long` remains explicit, and call-level `cacheRetention="none"` still wins for compaction. The final governor validates and normalizes those upstream-selected breakpoints, falls back to short when model compatibility rejects long retention, preserves no-marker compaction payloads, enforces Anthropic's four-breakpoint ceiling, and appends the subscription prompt-caching-scope beta idempotently. Its `effective_retention` field describes the final payload, not provider acceptance. Provider usage is preserved verbatim: `cacheWrite1h > 0` proves a one-hour write, but zero is inconclusive on subscription OAuth. Live normal-spawn and exact Fusion-child controls each observed a unique cache read after 370 idle seconds despite `cacheWrite1h = 0`; therefore payload observations prove request intent and `cacheRead` proves reuse, while neither zero telemetry nor a six-minute hit alone proves the full one-hour lifetime. Malformed controls or policy values abort before transport. Non-Anthropic payloads and child environments remain unchanged apart from the governor's existing JSON normalization.
|
|
94
94
|
|
|
95
|
-
After cache normalization, the governor
|
|
95
|
+
After cache normalization, the governor validates a stable JSON-object serialization and enforces the 128-provider-request execution limit. It does not estimate live payload tokens, subtract possible model output from the context window, or reject a request by payload size; Pi and the provider own live context handling after the pre-spawn Fusion stage checks. A provider-side context rejection remains a loud child failure and is never route-substituted or hidden. Pi's provider-hook behavior is characterized through the same `openai-codex-responses` transport adapter used by subscription Codex routes in a real local HTTP agent loop: transforms chain in extension load order and `ctx.abort()` prevents transport for the retained cache-policy and execution-limit refusals. Cache observations use `pi-background-tasks.fusion-claude-cache-observation.v1`, state requested/effective retention, source, breakpoint count, and provider-request ordinal, and are hash-bound inside `pi-background-tasks.fusion-child-result.v4` attempt event artifacts. At terminal `agent_settled`, the extension emits exactly one `pi-background-tasks.fusion-child-settlement.v3` frame binding the complete ordered metadata stream by count and SHA-256, the final record/hash, recovered retry-marker ordinals, and any one recovered oversized-original ordinal. The parent validates closed cache/output-contract evidence and increasing request ordinals, reconstructs stdout against the final metadata, requires final stop reason `stop`, verifies model identity, and preserves usage/cost exactly. Non-final `toolUse` records remain normal. A non-final `error` is accepted only when it is a zero-content, empty-hash, zero-usage retry marker, a later final `stop` exists, and the terminal settlement hash/accounts for that exact ordinal. Exactly one non-final `stop` is accepted only as a hash-bound oversized candidate original immediately followed by its same-session replacement. `length`, `aborted`, `pending`, final `error`, error records carrying text or usage, unbound non-final `stop`, missing/duplicate/tampered settlement, and settlement before terminal idleness all fail loudly.
|
|
96
96
|
|
|
97
97
|
Fusion child environments strip session/model/provider variables plus metered credential/base-url variables for OpenRouter, OpenAI, Anthropic, Azure OpenAI, and generic Pi API credentials before launch. Frontier model routes are admitted only when the registry reports subscription OAuth for trusted `anthropic` or `openai-codex` endpoints. There is no fallback, model substitution, endpoint override, or metered API-key route.
|
|
98
98
|
|
|
@@ -112,7 +112,7 @@ Run artifacts are private local evidence under `.pi/fusion/<session-id>-<pid>/<r
|
|
|
112
112
|
|
|
113
113
|
Artifact writes use durable private temp-file/fsync/rename. Manifests enforce legal state transitions and record config, resolved models, fixed capabilities, context policy, tool policy, anonymous map, attempts, artifact refs, cumulative usage, and errors. Successful, failed, and cancelled observed attempts preserve complete Pi usage/cost components, including optional `cacheWrite1h` and `reasoning` subsets; same-session compression includes both provider turns in that one attempt's aggregate; public tool results clone the same `Usage` shape without counting either subset as additional tokens. Terminal failures enrich their stage-local cause from the durable manifest after usage persistence: candidate/evaluator/merger progress reports completed, failed, cancelled, and not-started child facts plus exact usage so far. A late evaluator or merger budget refusal never claims that no child anywhere in the run was created.
|
|
114
114
|
|
|
115
|
-
For tool-enabled children, the private audit journal remains open across every low-level `agent_end`, because Pi may still retry, compact and retry, or process a queued continuation. Only terminal `agent_settled` can exclusively publish the complete hash/count/byte seal. Runtime-guard refusal latches process failure, makes that seal incomplete, and forces the result settlement to failed. The child emits one closed `pi-background-tasks.fusion-runtime-guard.
|
|
115
|
+
For tool-enabled children, the private audit journal remains open across every low-level `agent_end`, because Pi may still retry, compact and retry, or process a queued continuation. Only terminal `agent_settled` can exclusively publish the complete hash/count/byte seal. Runtime-guard refusal latches process failure, makes that seal incomplete, and forces the result settlement to failed. The child emits one closed `pi-background-tasks.fusion-runtime-guard.v2` stderr frame for malformed provider payloads, malformed Claude cache policy, provider-request loops, or tool-call loops. The frame contains the refusal code, route, request/tool ordinals, bounded payload byte/hash evidence where applicable, and a bounded message; it never emits the payload itself. The parent validates this frame and reports typed `child_runtime_limit_exceeded`, `child_runtime_payload_invalid`, or `child_cache_policy_invalid` instead of accepting a later clean-looking result or reducing it to an unexplained exit code. Tool activity after finalization, duplicate settlement, pre-settlement shutdown, extension diagnostics, malformed/duplicate runtime-guard frames, and missing/failed/stale seals are fatal. This lifecycle requires Pi 0.81.1 or newer; older Pi lines do not expose the required terminal event and are not claimed as compatible.
|
|
116
116
|
|
|
117
117
|
The four public Fusion tools return a background launch receipt after the readiness barrier. Tool-launched runs default to terminal notification plus follow-up wake; `/fusion` uses notification-only. The first successful `bg_result` retrieval durably claims and attaches complete Fusion usage exactly once; repeated retrieval returns the answer without duplicating session accounting. Running retrieval never waits.
|
|
118
118
|
|
|
@@ -125,8 +125,9 @@ Cancellation and shutdown are loud and durable when a run store exists. The exte
|
|
|
125
125
|
- Frontier/API route rejected: use Pi Anthropic or Codex subscription OAuth, not OpenAI/OpenRouter/Azure/API-key routes.
|
|
126
126
|
- `prompt_budget_exceeded_forecast`: inspect `budget-plan.json`; the error says whether shortening the request can help or whether session history/scope/model context window is the blocker.
|
|
127
127
|
- `prompt_budget_exceeded_measured`: an exact rendered prompt exceeded capacity after upstream output was known; split the workflow or choose a larger-context subscription route.
|
|
128
|
-
- `
|
|
129
|
-
- `
|
|
128
|
+
- `child_runtime_limit_exceeded`: a child crossed the 128-provider-request or 192-tool-call execution limit. Inspect the failed tool seal and split an unbounded task rather than raising limits blindly.
|
|
129
|
+
- `child_runtime_payload_invalid`: the final provider payload could not be normalized as one stable JSON object. Fix the payload/provider integration; no fallback serialization is attempted.
|
|
130
|
+
- `child_cache_policy_invalid`: `PI_CACHE_RETENTION` or Claude cache-control evidence was malformed. Use exactly `none`, `short`, or `long`; do not bypass cache-policy validation.
|
|
130
131
|
- `child_output_cap` after candidate compression: inspect the final candidate response, its `response.oversized.*` original, and v4/v3 child protocol evidence. The single same-session no-tool compression attempt also exceeded 49,152 JSON-rendered bytes; split the task rather than truncating or starting a repair child.
|
|
131
132
|
- `evaluation schema repair failed`: both evaluator attempts failed the closed JSON contract; inspect `evaluation.attempt-*.response.txt` and errors.
|
|
132
133
|
- `tool-call log invalid`: inspect the candidate `*.tool-calls.jsonl` and `*.seal.json`; missing/partial/unsealed logs, non-allowlisted tools, hash/count mismatches, and over-budget tool output fail by design.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-background-tasks",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.3",
|
|
4
4
|
"description": "Pi extension for durable background shell tasks, read-only delegated agents, local attested Pi runs, and fixed-purpose Fusion workflows through child Pi processes.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "ISC",
|
|
@@ -21,25 +21,21 @@ export const FUSION_TOOL_CALL_SEAL_SCHEMA_VERSION =
|
|
|
21
21
|
'pi-background-tasks.fusion-tool-call-seal.v1' as const;
|
|
22
22
|
export const FUSION_TOOL_CALL_SEAL_SUFFIX = '.seal.json';
|
|
23
23
|
export const FUSION_RUNTIME_GUARD_SCHEMA_VERSION =
|
|
24
|
-
'pi-background-tasks.fusion-runtime-guard.
|
|
24
|
+
'pi-background-tasks.fusion-runtime-guard.v2' as const;
|
|
25
25
|
export const FUSION_RUNTIME_GUARD_PREFIX = '\u001ePI_FUSION_RUNTIME_GUARD ';
|
|
26
26
|
export const FUSION_CHILD_MAX_PROVIDER_REQUESTS = 128;
|
|
27
27
|
export const FUSION_CHILD_MAX_TOOL_CALLS = 192;
|
|
28
|
-
export const FUSION_CHILD_MIN_OUTPUT_RESERVE_TOKENS = 32_768;
|
|
29
|
-
export const FUSION_CHILD_SAFETY_RESERVE_TOKENS = 4_096;
|
|
30
28
|
|
|
31
29
|
/**
|
|
32
30
|
* Aggregate ceiling on tool-result bytes a single candidate child may accumulate.
|
|
33
31
|
*
|
|
34
|
-
* The byte ceiling complements the
|
|
35
|
-
*
|
|
36
|
-
* compaction keeps each individual provider request within the route context window.
|
|
32
|
+
* The byte ceiling complements the tool/request count limits and pre-spawn stage
|
|
33
|
+
* budgets. It remains an independent bound on total tool material across the child run.
|
|
37
34
|
*/
|
|
38
35
|
export const FUSION_CHILD_MAX_TOTAL_TOOL_RESULT_BYTES = 8 * 1024 * 1024;
|
|
39
36
|
|
|
40
37
|
export type FusionRuntimeGuardCode =
|
|
41
38
|
| 'provider_request_limit'
|
|
42
|
-
| 'provider_request_budget'
|
|
43
39
|
| 'provider_payload_invalid'
|
|
44
40
|
| 'claude_cache_policy'
|
|
45
41
|
| 'tool_call_limit';
|
|
@@ -53,11 +49,6 @@ export interface FusionRuntimeGuardRecord {
|
|
|
53
49
|
tool_call_count: number;
|
|
54
50
|
payload_bytes: number;
|
|
55
51
|
payload_sha256: string;
|
|
56
|
-
estimated_input_tokens: number;
|
|
57
|
-
context_window_tokens: number;
|
|
58
|
-
reserved_output_tokens: number;
|
|
59
|
-
safety_reserve_tokens: number;
|
|
60
|
-
allowed_input_tokens: number;
|
|
61
52
|
message: string;
|
|
62
53
|
}
|
|
63
54
|
|
|
@@ -9,10 +9,8 @@ import {
|
|
|
9
9
|
FUSION_CANDIDATE_OUTPUT_RECOVERY_PATH_ENV,
|
|
10
10
|
FUSION_CHILD_MAX_PROVIDER_REQUESTS,
|
|
11
11
|
FUSION_CHILD_MAX_TOOL_CALLS,
|
|
12
|
-
FUSION_CHILD_MIN_OUTPUT_RESERVE_TOKENS,
|
|
13
12
|
FUSION_CHILD_RESULT_PREFIX,
|
|
14
13
|
FUSION_CHILD_RESULT_SCHEMA_VERSION,
|
|
15
|
-
FUSION_CHILD_SAFETY_RESERVE_TOKENS,
|
|
16
14
|
FUSION_CHILD_SETTLEMENT_PREFIX,
|
|
17
15
|
FUSION_CHILD_SETTLEMENT_SCHEMA_VERSION,
|
|
18
16
|
FUSION_RESEARCH_ENABLED_ENV,
|
|
@@ -854,7 +852,6 @@ function parseChildResultMetadata(value: unknown): FusionChildResultMetadata {
|
|
|
854
852
|
|
|
855
853
|
const FUSION_RUNTIME_GUARD_CODES = new Set<FusionRuntimeGuardCode>([
|
|
856
854
|
'provider_request_limit',
|
|
857
|
-
'provider_request_budget',
|
|
858
855
|
'provider_payload_invalid',
|
|
859
856
|
'claude_cache_policy',
|
|
860
857
|
'tool_call_limit',
|
|
@@ -885,11 +882,6 @@ export function parseFusionRuntimeGuard(stderr: Buffer): FusionRuntimeGuardRecor
|
|
|
885
882
|
'tool_call_count',
|
|
886
883
|
'payload_bytes',
|
|
887
884
|
'payload_sha256',
|
|
888
|
-
'estimated_input_tokens',
|
|
889
|
-
'context_window_tokens',
|
|
890
|
-
'reserved_output_tokens',
|
|
891
|
-
'safety_reserve_tokens',
|
|
892
|
-
'allowed_input_tokens',
|
|
893
885
|
'message',
|
|
894
886
|
],
|
|
895
887
|
'fusion runtime guard',
|
|
@@ -914,57 +906,13 @@ export function parseFusionRuntimeGuard(stderr: Buffer): FusionRuntimeGuardRecor
|
|
|
914
906
|
tool_call_count: requireUsageInteger(record, 'tool_call_count', 'fusion runtime guard'),
|
|
915
907
|
payload_bytes: requireUsageInteger(record, 'payload_bytes', 'fusion runtime guard'),
|
|
916
908
|
payload_sha256: requireSha256(record, 'payload_sha256', 'fusion runtime guard'),
|
|
917
|
-
estimated_input_tokens: requireUsageInteger(
|
|
918
|
-
record,
|
|
919
|
-
'estimated_input_tokens',
|
|
920
|
-
'fusion runtime guard',
|
|
921
|
-
),
|
|
922
|
-
context_window_tokens: requireUsageInteger(
|
|
923
|
-
record,
|
|
924
|
-
'context_window_tokens',
|
|
925
|
-
'fusion runtime guard',
|
|
926
|
-
),
|
|
927
|
-
reserved_output_tokens: requirePositiveSafeInteger(
|
|
928
|
-
record,
|
|
929
|
-
'reserved_output_tokens',
|
|
930
|
-
'fusion runtime guard',
|
|
931
|
-
),
|
|
932
|
-
safety_reserve_tokens: requirePositiveSafeInteger(
|
|
933
|
-
record,
|
|
934
|
-
'safety_reserve_tokens',
|
|
935
|
-
'fusion runtime guard',
|
|
936
|
-
),
|
|
937
|
-
allowed_input_tokens: requireUsageInteger(
|
|
938
|
-
record,
|
|
939
|
-
'allowed_input_tokens',
|
|
940
|
-
'fusion runtime guard',
|
|
941
|
-
),
|
|
942
909
|
message: requireNonBlankString(record, 'message', 'fusion runtime guard'),
|
|
943
910
|
};
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
911
|
+
const emptyPayloadHash = createHash('sha256').update(Buffer.alloc(0)).digest('hex');
|
|
912
|
+
if (frame.code === 'claude_cache_policy' || frame.code === 'provider_payload_invalid') {
|
|
913
|
+
if (frame.payload_bytes !== 0 || frame.payload_sha256 !== emptyPayloadHash) {
|
|
914
|
+
throw new Error('fusion runtime guard invalid-payload evidence mismatch');
|
|
947
915
|
}
|
|
948
|
-
const expectedAllowed =
|
|
949
|
-
frame.context_window_tokens - frame.reserved_output_tokens - frame.safety_reserve_tokens;
|
|
950
|
-
if (expectedAllowed < 0 || frame.allowed_input_tokens !== expectedAllowed) {
|
|
951
|
-
throw new Error('fusion runtime guard allowed-input arithmetic mismatch');
|
|
952
|
-
}
|
|
953
|
-
}
|
|
954
|
-
if (frame.code === 'claude_cache_policy') {
|
|
955
|
-
if (
|
|
956
|
-
frame.payload_bytes !== 0 ||
|
|
957
|
-
frame.payload_sha256 !== createHash('sha256').update(Buffer.alloc(0)).digest('hex') ||
|
|
958
|
-
frame.estimated_input_tokens !== 0
|
|
959
|
-
) {
|
|
960
|
-
throw new Error('fusion runtime guard Claude cache policy payload evidence mismatch');
|
|
961
|
-
}
|
|
962
|
-
}
|
|
963
|
-
if (
|
|
964
|
-
frame.code === 'provider_request_budget' &&
|
|
965
|
-
frame.estimated_input_tokens <= frame.allowed_input_tokens
|
|
966
|
-
) {
|
|
967
|
-
throw new Error('fusion runtime guard provider budget code has no token overage');
|
|
968
916
|
}
|
|
969
917
|
if (
|
|
970
918
|
frame.code === 'provider_request_limit' &&
|
|
@@ -976,11 +924,7 @@ export function parseFusionRuntimeGuard(stderr: Buffer): FusionRuntimeGuardRecor
|
|
|
976
924
|
if (frame.tool_call_count <= FUSION_CHILD_MAX_TOOL_CALLS) {
|
|
977
925
|
throw new Error('fusion runtime guard tool call limit was not exceeded');
|
|
978
926
|
}
|
|
979
|
-
if (
|
|
980
|
-
frame.payload_bytes !== 0 ||
|
|
981
|
-
frame.payload_sha256 !== createHash('sha256').update(Buffer.alloc(0)).digest('hex') ||
|
|
982
|
-
frame.estimated_input_tokens !== 0
|
|
983
|
-
) {
|
|
927
|
+
if (frame.payload_bytes !== 0 || frame.payload_sha256 !== emptyPayloadHash) {
|
|
984
928
|
throw new Error('fusion runtime guard tool call limit payload evidence mismatch');
|
|
985
929
|
}
|
|
986
930
|
}
|
|
@@ -1178,22 +1122,7 @@ export function assertFusionRuntimeGuardMatchesModel(
|
|
|
1178
1122
|
);
|
|
1179
1123
|
}
|
|
1180
1124
|
if (routeUnknown && guard.code !== 'provider_payload_invalid') {
|
|
1181
|
-
throw new Error('fusion runtime guard omitted the route for a
|
|
1182
|
-
}
|
|
1183
|
-
if (guard.code === 'provider_payload_invalid') return;
|
|
1184
|
-
const expectedReservedOutput = Math.max(
|
|
1185
|
-
FUSION_CHILD_MIN_OUTPUT_RESERVE_TOKENS,
|
|
1186
|
-
model.maxOutputTokens,
|
|
1187
|
-
);
|
|
1188
|
-
const expectedAllowedInput =
|
|
1189
|
-
model.contextWindow - expectedReservedOutput - FUSION_CHILD_SAFETY_RESERVE_TOKENS;
|
|
1190
|
-
if (
|
|
1191
|
-
guard.context_window_tokens !== model.contextWindow ||
|
|
1192
|
-
guard.reserved_output_tokens !== expectedReservedOutput ||
|
|
1193
|
-
guard.safety_reserve_tokens !== FUSION_CHILD_SAFETY_RESERVE_TOKENS ||
|
|
1194
|
-
guard.allowed_input_tokens !== expectedAllowedInput
|
|
1195
|
-
) {
|
|
1196
|
-
throw new Error('fusion runtime guard capacity evidence does not match the resolved route');
|
|
1125
|
+
throw new Error('fusion runtime guard omitted the route for a route-bound refusal');
|
|
1197
1126
|
}
|
|
1198
1127
|
}
|
|
1199
1128
|
|
|
@@ -2417,7 +2346,9 @@ export async function runPiChild(options: RunPiChildOptions): Promise<FusionChil
|
|
|
2417
2346
|
? 'child_exit_failed'
|
|
2418
2347
|
: runtimeGuard.code === 'claude_cache_policy'
|
|
2419
2348
|
? 'child_cache_policy_invalid'
|
|
2420
|
-
: '
|
|
2349
|
+
: runtimeGuard.code === 'provider_payload_invalid'
|
|
2350
|
+
? 'child_runtime_payload_invalid'
|
|
2351
|
+
: 'child_runtime_limit_exceeded',
|
|
2421
2352
|
options,
|
|
2422
2353
|
),
|
|
2423
2354
|
state.cleanupErrors,
|
package/src/core/fusion/types.ts
CHANGED
|
@@ -640,7 +640,8 @@ export type FusionErrorCode =
|
|
|
640
640
|
| 'child_stdin_failed'
|
|
641
641
|
| 'child_event_invalid'
|
|
642
642
|
| 'child_exit_failed'
|
|
643
|
-
| '
|
|
643
|
+
| 'child_runtime_limit_exceeded'
|
|
644
|
+
| 'child_runtime_payload_invalid'
|
|
644
645
|
| 'child_cache_policy_invalid'
|
|
645
646
|
| 'child_timeout'
|
|
646
647
|
| 'child_output_cap'
|
|
@@ -12,11 +12,6 @@ import { dirname, isAbsolute } from 'node:path';
|
|
|
12
12
|
import { parseJsonText } from './core/common.js';
|
|
13
13
|
import type { ExtensionAPI } from '@earendil-works/pi-coding-agent';
|
|
14
14
|
import { Type, type Static } from 'typebox';
|
|
15
|
-
import {
|
|
16
|
-
estimateInputTokens,
|
|
17
|
-
knownJsonSegment,
|
|
18
|
-
resolveTokenBudgetFamily,
|
|
19
|
-
} from './core/context/token-budget.js';
|
|
20
15
|
import {
|
|
21
16
|
FUSION_TOOL_CALL_LOG_SCHEMA_VERSION,
|
|
22
17
|
FUSION_WEB_FETCH_TOOL_NAME,
|
|
@@ -42,9 +37,7 @@ import {
|
|
|
42
37
|
FUSION_CHILD_MAX_PROVIDER_REQUESTS,
|
|
43
38
|
FUSION_CHILD_MAX_TOOL_CALLS,
|
|
44
39
|
FUSION_CHILD_MAX_TOTAL_TOOL_RESULT_BYTES,
|
|
45
|
-
FUSION_CHILD_MIN_OUTPUT_RESERVE_TOKENS,
|
|
46
40
|
FUSION_CHILD_RESULT_PREFIX,
|
|
47
|
-
FUSION_CHILD_SAFETY_RESERVE_TOKENS,
|
|
48
41
|
FUSION_CHILD_SETTLEMENT_PREFIX,
|
|
49
42
|
FUSION_RESEARCH_ENABLED_ENV,
|
|
50
43
|
FUSION_RUNTIME_GUARD_PREFIX,
|
|
@@ -88,10 +81,8 @@ export {
|
|
|
88
81
|
FUSION_CHILD_MAX_PROVIDER_REQUESTS,
|
|
89
82
|
FUSION_CHILD_MAX_TOOL_CALLS,
|
|
90
83
|
FUSION_CHILD_MAX_TOTAL_TOOL_RESULT_BYTES,
|
|
91
|
-
FUSION_CHILD_MIN_OUTPUT_RESERVE_TOKENS,
|
|
92
84
|
FUSION_CHILD_RESULT_PREFIX,
|
|
93
85
|
FUSION_CHILD_RESULT_SCHEMA_VERSION,
|
|
94
|
-
FUSION_CHILD_SAFETY_RESERVE_TOKENS,
|
|
95
86
|
FUSION_CHILD_SETTLEMENT_PREFIX,
|
|
96
87
|
FUSION_CHILD_SETTLEMENT_SCHEMA_VERSION,
|
|
97
88
|
FUSION_RESEARCH_ENABLED_ENV,
|
|
@@ -370,8 +361,6 @@ export interface FusionRuntimeRequestEvaluationInput {
|
|
|
370
361
|
payload: unknown;
|
|
371
362
|
provider: string | undefined;
|
|
372
363
|
model: string | undefined;
|
|
373
|
-
contextWindowTokens: number | undefined;
|
|
374
|
-
maxOutputTokens: number | undefined;
|
|
375
364
|
requestOrdinal: number;
|
|
376
365
|
toolCallCount: number;
|
|
377
366
|
}
|
|
@@ -384,23 +373,6 @@ function invalidFusionRuntimeRequest(
|
|
|
384
373
|
'provider_payload_invalid' | 'claude_cache_policy'
|
|
385
374
|
> = 'provider_payload_invalid',
|
|
386
375
|
): FusionRuntimeGuardRecord {
|
|
387
|
-
const contextWindowTokens =
|
|
388
|
-
input.contextWindowTokens !== undefined &&
|
|
389
|
-
Number.isSafeInteger(input.contextWindowTokens) &&
|
|
390
|
-
input.contextWindowTokens > 0
|
|
391
|
-
? input.contextWindowTokens
|
|
392
|
-
: 0;
|
|
393
|
-
const modelOutputTokens =
|
|
394
|
-
input.maxOutputTokens !== undefined &&
|
|
395
|
-
Number.isSafeInteger(input.maxOutputTokens) &&
|
|
396
|
-
input.maxOutputTokens > 0
|
|
397
|
-
? input.maxOutputTokens
|
|
398
|
-
: 0;
|
|
399
|
-
const reservedOutputTokens = Math.max(FUSION_CHILD_MIN_OUTPUT_RESERVE_TOKENS, modelOutputTokens);
|
|
400
|
-
const allowedInputTokens = Math.max(
|
|
401
|
-
0,
|
|
402
|
-
contextWindowTokens - reservedOutputTokens - FUSION_CHILD_SAFETY_RESERVE_TOKENS,
|
|
403
|
-
);
|
|
404
376
|
const emptyPayload = Buffer.alloc(0);
|
|
405
377
|
return {
|
|
406
378
|
schema_version: FUSION_RUNTIME_GUARD_SCHEMA_VERSION,
|
|
@@ -411,11 +383,6 @@ function invalidFusionRuntimeRequest(
|
|
|
411
383
|
tool_call_count: input.toolCallCount,
|
|
412
384
|
payload_bytes: 0,
|
|
413
385
|
payload_sha256: sha256(emptyPayload),
|
|
414
|
-
estimated_input_tokens: 0,
|
|
415
|
-
context_window_tokens: contextWindowTokens,
|
|
416
|
-
reserved_output_tokens: reservedOutputTokens,
|
|
417
|
-
safety_reserve_tokens: FUSION_CHILD_SAFETY_RESERVE_TOKENS,
|
|
418
|
-
allowed_input_tokens: allowedInputTokens,
|
|
419
386
|
message: `fusion child could not validate provider request ${String(input.requestOrdinal)}: ${detail}`,
|
|
420
387
|
};
|
|
421
388
|
}
|
|
@@ -455,84 +422,31 @@ export function prepareFusionRuntimeRequest(
|
|
|
455
422
|
export function evaluateFusionRuntimeRequest(
|
|
456
423
|
input: FusionRuntimeRequestEvaluationInput,
|
|
457
424
|
): FusionRuntimeGuardRecord | undefined {
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
let payloadBytes = Buffer.alloc(0);
|
|
461
|
-
let estimatedInputTokens = 0;
|
|
462
|
-
let allowedInputTokens = 0;
|
|
463
|
-
const provider = input.provider ?? 'unknown';
|
|
464
|
-
const model = input.model ?? 'unknown';
|
|
465
|
-
const contextWindowTokens = input.contextWindowTokens ?? 0;
|
|
466
|
-
const reservedOutputTokens = Math.max(
|
|
467
|
-
FUSION_CHILD_MIN_OUTPUT_RESERVE_TOKENS,
|
|
468
|
-
input.maxOutputTokens ?? 0,
|
|
469
|
-
);
|
|
470
|
-
try {
|
|
471
|
-
if (input.provider === undefined || input.model === undefined) {
|
|
472
|
-
throw new Error('active model is unavailable');
|
|
473
|
-
}
|
|
474
|
-
if (!Number.isSafeInteger(contextWindowTokens) || contextWindowTokens <= 0) {
|
|
475
|
-
throw new Error('active model context window is unavailable');
|
|
476
|
-
}
|
|
477
|
-
if (
|
|
478
|
-
input.maxOutputTokens === undefined ||
|
|
479
|
-
!Number.isSafeInteger(input.maxOutputTokens) ||
|
|
480
|
-
input.maxOutputTokens <= 0
|
|
481
|
-
) {
|
|
482
|
-
throw new Error('active model maximum output tokens are unavailable');
|
|
483
|
-
}
|
|
484
|
-
allowedInputTokens =
|
|
485
|
-
contextWindowTokens - reservedOutputTokens - FUSION_CHILD_SAFETY_RESERVE_TOKENS;
|
|
486
|
-
if (allowedInputTokens <= 0) {
|
|
487
|
-
throw new Error('active model has no safe provider input capacity');
|
|
488
|
-
}
|
|
489
|
-
const payloadText = JSON.stringify(input.payload);
|
|
490
|
-
if (payloadText === undefined) throw new Error('provider payload serialized to undefined');
|
|
491
|
-
payloadBytes = Buffer.from(payloadText, 'utf8');
|
|
492
|
-
const family = resolveTokenBudgetFamily({ provider, model });
|
|
493
|
-
estimatedInputTokens = estimateInputTokens({
|
|
494
|
-
family: family.family,
|
|
495
|
-
calibrationBacked: family.backed,
|
|
496
|
-
familyResolution: family.resolution,
|
|
497
|
-
allowedInputTokens,
|
|
498
|
-
scope: 'fusion',
|
|
499
|
-
segments: [knownJsonSegment(payloadText)],
|
|
500
|
-
}).tokens;
|
|
501
|
-
if (input.requestOrdinal > FUSION_CHILD_MAX_PROVIDER_REQUESTS) {
|
|
502
|
-
code = 'provider_request_limit';
|
|
503
|
-
message = `fusion child reached provider request ${String(input.requestOrdinal)}, exceeding the ${String(FUSION_CHILD_MAX_PROVIDER_REQUESTS)}-request execution limit`;
|
|
504
|
-
} else if (estimatedInputTokens > allowedInputTokens) {
|
|
505
|
-
code = 'provider_request_budget';
|
|
506
|
-
message = `fusion child blocked provider request ${String(input.requestOrdinal)} before transport: exact final payload is ${String(payloadBytes.length)} UTF-8 bytes (estimated <= ${String(estimatedInputTokens)} input tokens), exceeding ${String(allowedInputTokens)} allowed input tokens after reserving ${String(reservedOutputTokens)} model output + ${String(FUSION_CHILD_SAFETY_RESERVE_TOKENS)} safety from the ${String(contextWindowTokens)}-token context window`;
|
|
507
|
-
}
|
|
508
|
-
} catch (error) {
|
|
509
|
-
code = 'provider_payload_invalid';
|
|
510
|
-
message = `fusion child could not validate provider request ${String(input.requestOrdinal)}: ${error instanceof Error ? error.message : String(error)}`;
|
|
425
|
+
if (input.provider === undefined || input.model === undefined) {
|
|
426
|
+
return invalidFusionRuntimeRequest(input, 'active model is unavailable');
|
|
511
427
|
}
|
|
512
|
-
if (
|
|
428
|
+
if (input.requestOrdinal <= FUSION_CHILD_MAX_PROVIDER_REQUESTS) return undefined;
|
|
429
|
+
const serialized: unknown = JSON.stringify(input.payload);
|
|
430
|
+
if (typeof serialized !== 'string') {
|
|
431
|
+
return invalidFusionRuntimeRequest(input, 'provider payload serialized to a non-string value');
|
|
432
|
+
}
|
|
433
|
+
const payloadBytes = Buffer.from(serialized, 'utf8');
|
|
513
434
|
return {
|
|
514
435
|
schema_version: FUSION_RUNTIME_GUARD_SCHEMA_VERSION,
|
|
515
|
-
code,
|
|
516
|
-
provider,
|
|
517
|
-
model,
|
|
436
|
+
code: 'provider_request_limit',
|
|
437
|
+
provider: input.provider,
|
|
438
|
+
model: input.model,
|
|
518
439
|
request_ordinal: input.requestOrdinal,
|
|
519
440
|
tool_call_count: input.toolCallCount,
|
|
520
441
|
payload_bytes: payloadBytes.length,
|
|
521
442
|
payload_sha256: sha256(payloadBytes),
|
|
522
|
-
|
|
523
|
-
context_window_tokens: contextWindowTokens,
|
|
524
|
-
reserved_output_tokens: reservedOutputTokens,
|
|
525
|
-
safety_reserve_tokens: FUSION_CHILD_SAFETY_RESERVE_TOKENS,
|
|
526
|
-
allowed_input_tokens: allowedInputTokens,
|
|
527
|
-
message,
|
|
443
|
+
message: `fusion child reached provider request ${String(input.requestOrdinal)}, exceeding the ${String(FUSION_CHILD_MAX_PROVIDER_REQUESTS)}-request execution limit`,
|
|
528
444
|
};
|
|
529
445
|
}
|
|
530
446
|
|
|
531
447
|
export interface FusionRuntimeToolLimitEvaluationInput {
|
|
532
448
|
provider: string | undefined;
|
|
533
449
|
model: string | undefined;
|
|
534
|
-
contextWindowTokens: number | undefined;
|
|
535
|
-
maxOutputTokens: number | undefined;
|
|
536
450
|
requestOrdinal: number;
|
|
537
451
|
toolCallCount: number;
|
|
538
452
|
}
|
|
@@ -541,23 +455,6 @@ export function evaluateFusionRuntimeToolLimit(
|
|
|
541
455
|
input: FusionRuntimeToolLimitEvaluationInput,
|
|
542
456
|
): FusionRuntimeGuardRecord | undefined {
|
|
543
457
|
if (input.toolCallCount <= FUSION_CHILD_MAX_TOOL_CALLS) return undefined;
|
|
544
|
-
const contextWindowTokens =
|
|
545
|
-
input.contextWindowTokens !== undefined &&
|
|
546
|
-
Number.isSafeInteger(input.contextWindowTokens) &&
|
|
547
|
-
input.contextWindowTokens > 0
|
|
548
|
-
? input.contextWindowTokens
|
|
549
|
-
: 0;
|
|
550
|
-
const modelOutputTokens =
|
|
551
|
-
input.maxOutputTokens !== undefined &&
|
|
552
|
-
Number.isSafeInteger(input.maxOutputTokens) &&
|
|
553
|
-
input.maxOutputTokens > 0
|
|
554
|
-
? input.maxOutputTokens
|
|
555
|
-
: 0;
|
|
556
|
-
const reservedOutputTokens = Math.max(FUSION_CHILD_MIN_OUTPUT_RESERVE_TOKENS, modelOutputTokens);
|
|
557
|
-
const allowedInputTokens = Math.max(
|
|
558
|
-
0,
|
|
559
|
-
contextWindowTokens - reservedOutputTokens - FUSION_CHILD_SAFETY_RESERVE_TOKENS,
|
|
560
|
-
);
|
|
561
458
|
const emptyPayload = Buffer.alloc(0);
|
|
562
459
|
return {
|
|
563
460
|
schema_version: FUSION_RUNTIME_GUARD_SCHEMA_VERSION,
|
|
@@ -568,11 +465,6 @@ export function evaluateFusionRuntimeToolLimit(
|
|
|
568
465
|
tool_call_count: input.toolCallCount,
|
|
569
466
|
payload_bytes: 0,
|
|
570
467
|
payload_sha256: sha256(emptyPayload),
|
|
571
|
-
estimated_input_tokens: 0,
|
|
572
|
-
context_window_tokens: contextWindowTokens,
|
|
573
|
-
reserved_output_tokens: reservedOutputTokens,
|
|
574
|
-
safety_reserve_tokens: FUSION_CHILD_SAFETY_RESERVE_TOKENS,
|
|
575
|
-
allowed_input_tokens: allowedInputTokens,
|
|
576
468
|
message: `fusion child reached tool call ${String(input.toolCallCount)}, exceeding the ${String(FUSION_CHILD_MAX_TOOL_CALLS)}-call execution limit`,
|
|
577
469
|
};
|
|
578
470
|
}
|
|
@@ -773,8 +665,6 @@ export default function fusionChildExtension(pi: ExtensionAPI): void {
|
|
|
773
665
|
payload: event.payload,
|
|
774
666
|
provider: model?.provider,
|
|
775
667
|
model: model?.id,
|
|
776
|
-
contextWindowTokens: model?.contextWindow,
|
|
777
|
-
maxOutputTokens: model?.maxTokens,
|
|
778
668
|
requestOrdinal: providerRequestCount,
|
|
779
669
|
toolCallCount,
|
|
780
670
|
},
|
|
@@ -793,8 +683,6 @@ export default function fusionChildExtension(pi: ExtensionAPI): void {
|
|
|
793
683
|
payload: cacheNormalizedPayload,
|
|
794
684
|
provider: model?.provider,
|
|
795
685
|
model: model?.id,
|
|
796
|
-
contextWindowTokens: model?.contextWindow,
|
|
797
|
-
maxOutputTokens: model?.maxTokens,
|
|
798
686
|
requestOrdinal: providerRequestCount,
|
|
799
687
|
toolCallCount,
|
|
800
688
|
});
|
|
@@ -888,8 +776,6 @@ export default function fusionChildExtension(pi: ExtensionAPI): void {
|
|
|
888
776
|
const guard = evaluateFusionRuntimeToolLimit({
|
|
889
777
|
provider: model?.provider,
|
|
890
778
|
model: model?.id,
|
|
891
|
-
contextWindowTokens: model?.contextWindow,
|
|
892
|
-
maxOutputTokens: model?.maxTokens,
|
|
893
779
|
requestOrdinal: providerRequestCount,
|
|
894
780
|
toolCallCount,
|
|
895
781
|
});
|