pi-background-tasks 2.1.1 → 2.1.2
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 +12 -11
- package/TEST_PLAN.md +3 -3
- package/docs/manifest.json +3 -3
- package/docs/reference/runtime-contracts.md +6 -6
- package/docs/subsystems/delegation.md +2 -2
- package/docs/subsystems/docs-freshness-gate.md +1 -1
- package/package.json +6 -6
- package/src/core/delegate/hook-contract.ts +14 -13
- package/src/delegate-child-extension.ts +12 -13
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.2` |
|
|
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
|
@@ -35,29 +35,30 @@ real Pi agent loop against a deterministic scripted provider and records what Pi
|
|
|
35
35
|
guard depends on that behaviour and it must be proven by execution rather than read
|
|
36
36
|
from type declarations.
|
|
37
37
|
|
|
38
|
-
The
|
|
38
|
+
The conservative guarantees shared by every supported Pi line are written to
|
|
39
39
|
`tests/scripted-provider/pi-hook-contract-evidence.json` and shipped as
|
|
40
40
|
`src/core/delegate/hook-contract-evidence.json`. A package test asserts the two are
|
|
41
|
-
byte-identical, so the runtime gate and
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
byte-identical, so the runtime gate and its proving evidence cannot drift apart. If the evidence file already exists, the gate **compares** against it rather
|
|
42
|
+
than rewriting it: a change in a required Pi hook invariant fails loudly and forces
|
|
43
|
+
a deliberate re-review of the child guard instead of silent regeneration. The
|
|
44
|
+
release compatibility gate additionally pins each supported line's exact abort mode.
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
Across the supported Pi lines, the gates establish by execution:
|
|
47
47
|
|
|
48
48
|
| Question | Observed |
|
|
49
49
|
|---|---|
|
|
50
50
|
| Does `context` fire before every model call? | yes, once per call, in extension load order |
|
|
51
51
|
| Do messages returned from `context` reach the provider? | yes |
|
|
52
52
|
| Does **throwing** in `context` prevent the provider call? | **no** — Pi catches it and dispatches anyway |
|
|
53
|
-
| Does `ctx.abort()` prevent
|
|
53
|
+
| Does `ctx.abort()` prevent transport? | yes; Pi 0.81.1–0.83.0 invoke the provider with an already-aborted signal, while Pi 0.84.0 skips provider invocation during signal-aware auth resolution; every line terminates |
|
|
54
54
|
| Does `tool_result` fire before the transcript entry, and can a handler replace it? | yes, chained in load order; the replacement reaches the provider and the original does not |
|
|
55
55
|
| Do tool-call id, role, and `isError` survive replacement? | yes |
|
|
56
56
|
|
|
57
|
-
Because
|
|
58
|
-
|
|
59
|
-
outgoing message set. A Pi build that cannot provide the
|
|
60
|
-
`bg_delegate` to refuse to spawn with a typed
|
|
57
|
+
Because a throw is not a barrier and older supported Pi lines still enter the
|
|
58
|
+
provider with an aborted signal, the child guard uses abort **and** removes the
|
|
59
|
+
oversized content from the outgoing message set. A Pi build that cannot provide the
|
|
60
|
+
required guarantees causes `bg_delegate` to refuse to spawn with a typed
|
|
61
|
+
`delegate_hook_contract_unsupported`.
|
|
61
62
|
|
|
62
63
|
Full interactive gate:
|
|
63
64
|
|
package/TEST_PLAN.md
CHANGED
|
@@ -40,7 +40,7 @@ The table below remains the exhaustive acceptance source. Do not replace it with
|
|
|
40
40
|
| Smoke | `npm run smoke` | no | implemented; isolated load-only |
|
|
41
41
|
| Large-context smoke | `npm run smoke:large-context` | release gate | implemented; rebuilds the production failure byte composition, proves the pre-fix input is rejected and the post-fix projection fits all four stages against the smallest configured route, with no inference and no child spawn |
|
|
42
42
|
| Live subscription evidence | `npx tsx scripts/delegate-live-run.ts` | release gate | implemented; one real subscription-OAuth child on the parent's current route, large seeded session, hash-verified answer, and explicit leak checks. Caught two defects no offline gate did (undelivered prompt, seed-not-prompt budgeting), both now pinned by unit and mutation tests |
|
|
43
|
-
| Compatibility | `npm run test:compat` | release gate | implemented; exact Pi `0.81.1`, `0.82.1`, `0.83.0` pack/install plus `/jobs`, `/fusion`, and `/fusion-models` surfaces, per-version `agent_settled`/`before_provider_request` declarations, Anthropic cache-adapter contracts, and bundled-TypeBox peer verification, removed-TypeBox-API scan of installed package bytes, followed by a current-host real `fusion_reason` session-stat and replay witness |
|
|
43
|
+
| Compatibility | `npm run test:compat` | release gate | implemented; exact Pi `0.81.1`, `0.82.1`, `0.83.0`, `0.84.0` pack/install plus `/jobs`, `/fusion`, and `/fusion-models` surfaces, per-version context-abort transport barriers, `agent_settled`/`before_provider_request` declarations, Anthropic cache-adapter contracts, and bundled-TypeBox peer verification, removed-TypeBox-API scan of installed package bytes, followed by a current-host real `fusion_reason` session-stat and replay witness |
|
|
44
44
|
| Docs verification | `npm run docs:verify` | prepack/release gate | implemented; offline docs freshness, generated region/index/manifest/link/reachability/coverage checks with advisory attestation state; optional `docs:verify:attestations` enforces fresh receipts |
|
|
45
45
|
| Docs tests | `npm run test:docs` | targeted docs gate | implemented; docs-gate unit/package tests |
|
|
46
46
|
| Payload policy | `npm run payload:check` | prepack/release gate | implemented; package payload/docs/assets exclusions and inclusions |
|
|
@@ -86,8 +86,8 @@ SDK/RPC/scripted-provider/package/compatibility coverage asserts exactly four to
|
|
|
86
86
|
| Fusion runtime context governor | `pi-background-tasks.fusion-runtime-guard.v1`, typed `child_runtime_budget_exceeded` | yes | | | | | | scripted provider | Unit proves every exact final provider payload is serialized, hashed, and conservatively estimated against `contextWindow - max(32,768, model.maxTokens) - 4,096`; request 128/tool call 192 are allowed and the next is refused; malformed/duplicate frames and clean-looking post-refusal output fail closed; parent errors preserve observed usage. A real local-HTTP Pi loop through the production `openai-codex-responses` adapter proves earlier payload transforms reach the later governor and `ctx.abort()` prevents network transport. |
|
|
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
|
-
| 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'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. |
|
|
90
|
-
| Pi hook contract | `npm run test:hook-contract`, `tests/scripted-provider/pi-hook-contract-evidence.json`, `src/core/delegate/hook-contract-evidence.json` | | | | | | evidence parity | yes | Executes real Pi agent loops and records, rather than assumes: Fusion `before_provider_request` transformations chain in extension load order through the Codex transport adapter and abort before local HTTP transport; Delegate `context` fires once before every model call in load order; returned messages reach the provider; **throwing** in `context` does NOT block dispatch (Pi catches and continues); `ctx.abort()`
|
|
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. |
|
|
90
|
+
| Pi hook contract | `npm run test:hook-contract`, `tests/scripted-provider/pi-hook-contract-evidence.json`, `src/core/delegate/hook-contract-evidence.json` | | | | | | evidence parity | yes | Executes real Pi agent loops and records, rather than assumes: Fusion `before_provider_request` transformations chain in extension load order through the Codex transport adapter and abort before local HTTP transport; Delegate `context` fires once before every model call in load order; returned messages reach the provider; **throwing** in `context` does NOT block dispatch (Pi catches and continues); `ctx.abort()` either skips provider invocation (Pi 0.84) or delivers an already-aborted signal (older supported lines), blocks transport, and terminates the run; `tool_result` fires before the transcript entry, chains in load order, replacement reaches the provider while the original does not, and toolCallId/role/`isError` survive. Handler ordering across two separate probe extensions is pinned. The evidence file is compared, never silently regenerated, and a package test asserts the shipped copy is byte-identical. |
|
|
91
91
|
| Delegate context seeding | `bg_delegate` seed `pi-background-tasks.delegate-seed.v1`, `seed.json`, `context-omission-ledger.json` | yes | yes | | | | mutation guard | yes | Unit covers verbatim visible user/assistant text, complete exclusion of thinking/tool-call arguments/tool-result payloads, marker-only images with no raw bytes anywhere in the seed, exclusion of the in-flight `bg_delegate` call **and every sibling call in the same assistant message** (two delegates launched together get byte-identical projected history), the prompt preserved exactly and marked `explicit_text` authority, zero payload-preview bytes, byte-identical construction across repeated builds and across separate processes via a fixed-leaf fixture, and refusal of a blank prompt. Receive-side verification rejects a single mutated byte, a foreign task identity, a structurally malformed seed whose hash matches, a directive whose hash disagrees with its text, and an unsupported capability. SDK proves the projected parent text actually reaches the child. |
|
|
92
92
|
| Delegate route pinning | `bg_delegate` `route`, `route_attestations` | yes | yes | | | | mutation guard | yes | Unit covers defaulting to the parent current model, explicit pinning, refusal of an unavailable route with `route_unresolved` and no substitution, refusal of a route with no declared context window with `route_capacity_unknown` rather than assuming one, and refusal when neither is available. The result package rejects a mismatched route, a mismatched attestation, and a package carrying no attestation at all. The scripted-provider gate proves an observed route drift prevents a success commit entirely. The mutation guard fails if a fallback list or first-available selection appears. |
|
|
93
93
|
| Delegate budget and guard | `budget-plan.json`, typed `seed_budget_exceeded` / `provider_context_budget_exhausted` | yes | yes | | | | mutation guard | yes | Unit covers reserve subtraction, exact-boundary accept and one-byte-past reject, the child system prompt counted as input, multi-byte UTF-8 measured by bytes, refusal of unusable windows without defaulting, and a total runtime governor that cannot throw from inside a hook. Preflight rejection is proven to create **zero** children and **zero** artifacts for hook-contract, budget, and blank-prompt refusals, with the artifact directory verified absent. The scripted-provider gate proves an over-budget model call is blocked in a real agent loop and produces a typed terminal record with no committed result. |
|
package/docs/manifest.json
CHANGED
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"state": "pass"
|
|
66
66
|
},
|
|
67
67
|
{
|
|
68
|
-
"authored_body_sha256": "sha256:
|
|
68
|
+
"authored_body_sha256": "sha256:60b6235d33b9c7df1b1494c0c071862aee059074ce58058c103f9a71d5d9e7d8",
|
|
69
69
|
"covers_sources": [
|
|
70
70
|
"extensions/delegate-child.ts",
|
|
71
71
|
"src/core/delegate/artifacts.ts",
|
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
"rel": "docs/subsystems/delegation.md",
|
|
85
85
|
"required": true,
|
|
86
86
|
"reviewer": "gpt-5.5-final-delegation-review-panel-plus-timeout-delta",
|
|
87
|
-
"state": "stale-
|
|
87
|
+
"state": "stale-authored-prose"
|
|
88
88
|
},
|
|
89
89
|
{
|
|
90
90
|
"authored_body_sha256": "sha256:200168b5db6e14947b5dbee9aef51c4e14d57de0df7716776250193b26b57289",
|
|
@@ -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.2"
|
|
795
795
|
},
|
|
796
796
|
"public_surface_ids": [
|
|
797
797
|
"command:bg",
|
|
@@ -37,11 +37,11 @@ This generated registry lists production environment-variable references, runtim
|
|
|
37
37
|
| `PI_API_BASE_URL` | remove | `src/core/attested-pi-run.ts:135`<br>`src/core/fusion/pi-child.ts:100` |
|
|
38
38
|
| `PI_API_KEY` | remove | `src/core/attested-pi-run.ts:135`<br>`src/core/fusion/pi-child.ts:100` |
|
|
39
39
|
| `PI_AUTH_FILE` | remove | `src/core/attested-pi-run.ts:135`<br>`src/core/fusion/pi-child.ts:100` |
|
|
40
|
-
| `PI_BG_DELEGATE_ARTIFACT_DIR` | read, write | `src/core/delegate/launch.ts:324`<br>`src/delegate-child-extension.ts:
|
|
41
|
-
| `PI_BG_DELEGATE_LAUNCH_NONCE` | read, write | `src/core/delegate/launch.ts:328`<br>`src/delegate-child-extension.ts:
|
|
42
|
-
| `PI_BG_DELEGATE_SEED_PATH` | read, write | `src/core/delegate/launch.ts:325`<br>`src/delegate-child-extension.ts:
|
|
43
|
-
| `PI_BG_DELEGATE_SEED_SHA256` | read, write | `src/core/delegate/launch.ts:326`<br>`src/delegate-child-extension.ts:
|
|
44
|
-
| `PI_BG_DELEGATE_TASK_ID` | read, write | `src/core/delegate/launch.ts:327`<br>`src/delegate-child-extension.ts:
|
|
40
|
+
| `PI_BG_DELEGATE_ARTIFACT_DIR` | read, write | `src/core/delegate/launch.ts:324`<br>`src/delegate-child-extension.ts:276` |
|
|
41
|
+
| `PI_BG_DELEGATE_LAUNCH_NONCE` | read, write | `src/core/delegate/launch.ts:328`<br>`src/delegate-child-extension.ts:280` |
|
|
42
|
+
| `PI_BG_DELEGATE_SEED_PATH` | read, write | `src/core/delegate/launch.ts:325`<br>`src/delegate-child-extension.ts:277` |
|
|
43
|
+
| `PI_BG_DELEGATE_SEED_SHA256` | read, write | `src/core/delegate/launch.ts:326`<br>`src/delegate-child-extension.ts:278` |
|
|
44
|
+
| `PI_BG_DELEGATE_TASK_ID` | read, write | `src/core/delegate/launch.ts:327`<br>`src/delegate-child-extension.ts:279` |
|
|
45
45
|
| `PI_BG_DISABLE_PI_TELEMETRY` | read | `src/core/registry.ts:194` |
|
|
46
46
|
| `PI_BG_DISABLE_UPDATE_CHECK` | read | `src/extension.ts:455` |
|
|
47
47
|
| `PI_BG_MAX_OUTPUT_BYTES` | read | `src/core/registry.ts:68` |
|
|
@@ -117,7 +117,7 @@ This generated registry lists production environment-variable references, runtim
|
|
|
117
117
|
| --- | --- |
|
|
118
118
|
| `phase2.pi_task_attestation.v1` | `src/core/attested-pi-run.ts:20` |
|
|
119
119
|
| `pi-background-tasks.delegate-budget-plan.v2` | `src/core/delegate/types.ts:21` |
|
|
120
|
-
| `pi-background-tasks.delegate-child-terminal.v1` | `src/delegate-child-extension.ts:
|
|
120
|
+
| `pi-background-tasks.delegate-child-terminal.v1` | `src/delegate-child-extension.ts:380` |
|
|
121
121
|
| `pi-background-tasks.delegate-hook-contract.v1` | `src/core/delegate/hook-contract.ts:15` |
|
|
122
122
|
| `pi-background-tasks.delegate-launch.v1` | `src/delegate-extension.ts:398` |
|
|
123
123
|
| `pi-background-tasks.delegate-ledger.v1` | `src/core/delegate/types.ts:16` |
|
|
@@ -185,6 +185,6 @@ Each `DelegateError` renders code, message, child-created flag, artifact locatio
|
|
|
185
185
|
|
|
186
186
|
The child guard relies on Pi hook behavior proven by `tests/scripted-provider/pi-hook-contract.test.ts`; shipped evidence is byte-identical to `src/core/delegate/hook-contract-evidence.json`.
|
|
187
187
|
|
|
188
|
-
Required guarantees include context hook ordering, returned context messages reaching the provider, abort blocking
|
|
188
|
+
Required guarantees include context hook ordering, returned context messages reaching the provider, abort blocking transport, abort terminating the run, context throw isolation, tool-result replacement before transcript entry, replacement identity preservation, and extension load order.
|
|
189
189
|
|
|
190
|
-
Pi 0.83
|
|
190
|
+
Exact-version evidence covers both supported abort modes: Pi 0.81.1–0.83.0 invoke the provider with an already-aborted signal, while Pi 0.84.0 propagates that signal through auth resolution and skips provider invocation. Context throws still do not block dispatch. The guard is built fail-closed across both modes: it aborts and returns a suppressed message set, so the original oversized content is not dispatched even if a provider ignored the aborted signal. Missing/malformed/unsupported evidence fails with `delegate_hook_contract_unsupported`; the guard is not weakened at runtime.
|
|
@@ -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.2`
|
|
16
16
|
- Governed markdown docs: 40
|
|
17
17
|
- Public surfaces extracted: 30
|
|
18
18
|
- Governed production sources: 48
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-background-tasks",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.2",
|
|
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",
|
|
@@ -83,14 +83,14 @@
|
|
|
83
83
|
]
|
|
84
84
|
},
|
|
85
85
|
"peerDependencies": {
|
|
86
|
-
"@earendil-works/pi-coding-agent": "^0.81.1 || ^0.82.1 || ^0.83.0",
|
|
87
|
-
"@earendil-works/pi-tui": "^0.81.1 || ^0.82.1 || ^0.83.0",
|
|
86
|
+
"@earendil-works/pi-coding-agent": "^0.81.1 || ^0.82.1 || ^0.83.0 || ^0.84.0",
|
|
87
|
+
"@earendil-works/pi-tui": "^0.81.1 || ^0.82.1 || ^0.83.0 || ^0.84.0",
|
|
88
88
|
"typebox": "*"
|
|
89
89
|
},
|
|
90
90
|
"devDependencies": {
|
|
91
|
-
"@earendil-works/pi-ai": "^0.
|
|
92
|
-
"@earendil-works/pi-coding-agent": "^0.
|
|
93
|
-
"@earendil-works/pi-tui": "^0.
|
|
91
|
+
"@earendil-works/pi-ai": "^0.84.0",
|
|
92
|
+
"@earendil-works/pi-coding-agent": "^0.84.0",
|
|
93
|
+
"@earendil-works/pi-tui": "^0.84.0",
|
|
94
94
|
"@types/node": "^24.0.0",
|
|
95
95
|
"@types/turndown": "5.0.6",
|
|
96
96
|
"tsx": "^4.19.0",
|
|
@@ -22,14 +22,15 @@ export const DELEGATE_HOOK_CONTRACT_SCHEMA_VERSION =
|
|
|
22
22
|
* `ctx.abort()` so the request is never issued, then report a typed failure over
|
|
23
23
|
* the child result channel.
|
|
24
24
|
*
|
|
25
|
-
* Empirically established
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
25
|
+
* Empirically established across the supported Pi lines by the characterisation
|
|
26
|
+
* and exact-version compatibility gates: Pi 0.81.1-0.83.0 invoke the provider
|
|
27
|
+
* entry point with an already-aborted `AbortSignal`, while Pi 0.84.0 propagates
|
|
28
|
+
* that signal through auth resolution and skips the entry point. No network
|
|
29
|
+
* request is issued in either mode, and the run terminates. Throwing from a
|
|
30
|
+
* `context` handler is NOT a barrier at all: Pi catches the exception, reports
|
|
31
|
+
* it as an extension error, and continues dispatch. The guard therefore uses
|
|
32
|
+
* abort, never a throw, and additionally suppresses the oversized content itself
|
|
33
|
+
* so a non-conforming provider cannot transmit it.
|
|
33
34
|
*
|
|
34
35
|
* `tool-result-spill-v1`: replace an oversized `tool_result` payload with an
|
|
35
36
|
* explicit hash-accounted receipt before it enters the transcript.
|
|
@@ -65,11 +66,11 @@ export interface DelegateHookContractEvidence {
|
|
|
65
66
|
* Guarantees the child guard actually depends on.
|
|
66
67
|
*
|
|
67
68
|
* `context_throw_blocks_provider_call` and
|
|
68
|
-
* `context_abort_skips_stream_invocation` are deliberately absent
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
* the oversized content from the outgoing message set, so the request
|
|
72
|
-
* issued and could not carry the content even if it were.
|
|
69
|
+
* `context_abort_skips_stream_invocation` are deliberately absent. Throws do
|
|
70
|
+
* not block dispatch, and skipping the stream entry point is not shared by every
|
|
71
|
+
* supported Pi line. The guard needs neither behavior: it aborts the run AND
|
|
72
|
+
* removes the oversized content from the outgoing message set, so the request
|
|
73
|
+
* cannot be issued and could not carry the content even if it were.
|
|
73
74
|
*/
|
|
74
75
|
export const DELEGATE_REQUIRED_HOOK_GUARANTEES: readonly DelegateHookGuaranteeName[] = [
|
|
75
76
|
'context_fires_before_every_model_call',
|
|
@@ -36,18 +36,17 @@ import {
|
|
|
36
36
|
* - enforcing turn and tool-call limits;
|
|
37
37
|
* - committing exactly one result package atomically.
|
|
38
38
|
*
|
|
39
|
-
* Measured
|
|
40
|
-
* `tests/scripted-provider/pi-hook-contract.test.ts`):
|
|
39
|
+
* Measured behavior across the supported Pi lines (see
|
|
40
|
+
* `tests/scripted-provider/pi-hook-contract.test.ts` and `scripts/test-compat.ts`):
|
|
41
41
|
*
|
|
42
|
-
* - Throwing from a `context` handler does NOT stop
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
* -
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
* because the content is no longer there.
|
|
42
|
+
* - Throwing from a `context` handler does NOT stop dispatch. Pi catches the
|
|
43
|
+
* exception and continues, so a throw is never used as a barrier here.
|
|
44
|
+
* - `ctx.abort()` blocks transport in both supported modes: Pi 0.81.1-0.83.0
|
|
45
|
+
* invoke the provider with an already-aborted signal, while Pi 0.84.0 skips
|
|
46
|
+
* the provider entry point during signal-aware auth resolution.
|
|
47
|
+
* - The guard ALSO replaces the offending content in the returned message set.
|
|
48
|
+
* Even a non-conforming provider could not transmit the content because the
|
|
49
|
+
* content is no longer there.
|
|
51
50
|
*/
|
|
52
51
|
|
|
53
52
|
const SPILL_DIRNAME = 'spill';
|
|
@@ -471,8 +470,8 @@ export default function delegateChildExtension(pi: ExtensionAPI): void {
|
|
|
471
470
|
if (verdict.withinBudget) return undefined;
|
|
472
471
|
const message = `delegate child context reached ${String(verdict.measuredTokens)} input tokens against a ${String(verdict.allowedTokens)}-token allowance on route ${seed.route.qualified_id}, over by ${String(verdict.overageTokens)}; estimator family ${verdict.rateSource.family}, source ${verdict.rateSource.source}, backed=${String(verdict.backed)}, dominant_byte_class=${verdict.dominantByteClass}, rate ${String(verdict.rateSource.effective_rate_bytes_per_token_x100)}/100 B/tok + ${String(verdict.rateSource.affine_f_tokens)} tokens`;
|
|
473
472
|
latch('provider_context_budget_exhausted', message);
|
|
474
|
-
// Barrier one: terminate the run.
|
|
475
|
-
// provider
|
|
473
|
+
// Barrier one: terminate the run. Depending on the supported Pi line,
|
|
474
|
+
// this skips provider dispatch or hands it an already-aborted signal.
|
|
476
475
|
ctx.abort();
|
|
477
476
|
// Barrier two: remove the content itself, so the request could not carry it
|
|
478
477
|
// even if a provider ignored the aborted signal. Retaining only the first
|