@mjasnikovs/pi-task 0.38.29 → 0.38.30
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/dist/config/config.d.ts +70 -70
- package/dist/config/config.js +26 -35
- package/dist/config/extension-list.d.ts +6 -5
- package/dist/config/extension-list.js +3 -2
- package/dist/config/reasoning-args.d.ts +9 -7
- package/dist/config/reasoning-args.js +12 -10
- package/dist/config/reasoning.d.ts +44 -105
- package/dist/config/reasoning.js +27 -704
- package/dist/config/register.d.ts +34 -48
- package/dist/config/register.js +41 -51
- package/dist/config/tool-list.d.ts +16 -16
- package/dist/config/tool-list.js +1 -1
- package/dist/remote/bridge.d.ts +19 -10
- package/dist/remote/bridge.js +3 -2
- package/dist/remote/broadcast.js +3 -1
- package/dist/remote/events.js +12 -11
- package/dist/remote/history.d.ts +1 -1
- package/dist/remote/protocol.d.ts +6 -3
- package/dist/remote/protocol.js +2 -1
- package/dist/remote/push.d.ts +16 -16
- package/dist/remote/push.js +27 -27
- package/dist/remote/register.d.ts +3 -3
- package/dist/remote/register.js +17 -19
- package/dist/remote/server.d.ts +9 -8
- package/dist/remote/server.js +15 -14
- package/dist/remote/session-state.d.ts +5 -4
- package/dist/remote/session-state.js +8 -5
- package/dist/remote/sw.d.ts +7 -6
- package/dist/remote/sw.js +7 -6
- package/dist/remote/tailscale.d.ts +4 -2
- package/dist/remote/tailscale.js +4 -2
- package/dist/remote/ui-highlight.js +6 -5
- package/dist/remote/ui-render.js +4 -4
- package/dist/remote/ui-script.js +24 -24
- package/dist/remote/ui-styles.d.ts +1 -1
- package/dist/remote/ui-styles.js +10 -13
- package/dist/remote/ui-tools.js +9 -6
- package/dist/shared/child-extensions.d.ts +29 -17
- package/dist/shared/child-extensions.js +29 -17
- package/dist/shared/child-output.d.ts +30 -24
- package/dist/shared/child-output.js +25 -17
- package/dist/shared/child-process.d.ts +47 -40
- package/dist/shared/child-process.js +50 -59
- package/dist/shared/command-watchdog.d.ts +22 -16
- package/dist/shared/command-watchdog.js +28 -21
- package/dist/shared/fs-text.d.ts +16 -10
- package/dist/shared/fs-text.js +16 -10
- package/dist/shared/git-runner.d.ts +25 -25
- package/dist/shared/git-runner.js +25 -25
- package/dist/shared/leaked-tool-call.d.ts +17 -11
- package/dist/shared/leaked-tool-call.js +23 -15
- package/dist/shared/model-endpoint.d.ts +29 -16
- package/dist/shared/model-endpoint.js +33 -21
- package/dist/shared/pi-invocation.d.ts +7 -4
- package/dist/shared/pi-invocation.js +12 -7
- package/dist/shared/pkg-version.d.ts +13 -5
- package/dist/shared/pkg-version.js +13 -5
- package/dist/shared/reasoning-capability.d.ts +35 -24
- package/dist/shared/reasoning-capability.js +35 -24
- package/dist/shared/stream-watchdog.d.ts +60 -44
- package/dist/shared/stream-watchdog.js +62 -45
- package/dist/task/accept-debt.d.ts +41 -43
- package/dist/task/accept-debt.js +73 -65
- package/dist/task/api-synthesis.d.ts +24 -21
- package/dist/task/api-synthesis.js +32 -26
- package/dist/task/apis-contract.d.ts +32 -64
- package/dist/task/apis-contract.js +32 -64
- package/dist/task/artifact-closure.d.ts +27 -13
- package/dist/task/artifact-closure.js +95 -67
- package/dist/task/auto-commit.d.ts +46 -35
- package/dist/task/auto-commit.js +51 -38
- package/dist/task/auto-io.d.ts +45 -25
- package/dist/task/auto-io.js +57 -29
- package/dist/task/auto-orchestrator.d.ts +26 -24
- package/dist/task/auto-orchestrator.js +178 -162
- package/dist/task/auto-prompts.d.ts +36 -24
- package/dist/task/auto-prompts.js +40 -26
- package/dist/task/autofix-ledger.d.ts +27 -25
- package/dist/task/autofix-ledger.js +29 -26
- package/dist/task/batch-test-task.d.ts +20 -12
- package/dist/task/batch-test-task.js +67 -60
- package/dist/task/boot-probe.d.ts +60 -44
- package/dist/task/boot-probe.js +91 -72
- package/dist/task/cancel-input.d.ts +30 -16
- package/dist/task/cancel-input.js +20 -11
- package/dist/task/cancel-points.d.ts +27 -20
- package/dist/task/cancel-points.js +30 -22
- package/dist/task/child-runner.d.ts +46 -51
- package/dist/task/child-runner.js +48 -49
- package/dist/task/child-status.d.ts +23 -16
- package/dist/task/child-status.js +23 -16
- package/dist/task/clamp-output.js +12 -5
- package/dist/task/command-run.d.ts +31 -28
- package/dist/task/command-run.js +44 -35
- package/dist/task/command-shrink.d.ts +25 -18
- package/dist/task/command-shrink.js +37 -31
- package/dist/task/command-watchdog.d.ts +9 -6
- package/dist/task/command-watchdog.js +21 -15
- package/dist/task/context-attribution.d.ts +34 -26
- package/dist/task/context-attribution.js +34 -26
- package/dist/task/context-silence.d.ts +39 -29
- package/dist/task/context-silence.js +35 -25
- package/dist/task/context-usage.d.ts +16 -9
- package/dist/task/context-usage.js +16 -9
- package/dist/task/contracts.d.ts +8 -4
- package/dist/task/contracts.js +25 -17
- package/dist/task/coverage-loop.d.ts +22 -18
- package/dist/task/coverage-loop.js +35 -30
- package/dist/task/critique-probes.d.ts +13 -14
- package/dist/task/critique-probes.js +50 -39
- package/dist/task/debug-log.d.ts +13 -5
- package/dist/task/debug-log.js +32 -20
- package/dist/task/decompose-fidelity.d.ts +11 -9
- package/dist/task/decompose-fidelity.js +38 -33
- package/dist/task/decompose-granularity.d.ts +41 -38
- package/dist/task/decompose-granularity.js +41 -38
- package/dist/task/deep-render-check.d.ts +22 -14
- package/dist/task/deep-render-check.js +40 -31
- package/dist/task/dropped-input.d.ts +12 -7
- package/dist/task/dropped-input.js +5 -2
- package/dist/task/enforce-attribution.d.ts +38 -47
- package/dist/task/enforce-attribution.js +46 -52
- package/dist/task/enforce-guidelines.d.ts +31 -20
- package/dist/task/enforce-guidelines.js +32 -21
- package/dist/task/enrichment.d.ts +7 -2
- package/dist/task/enrichment.js +26 -14
- package/dist/task/env-notes.d.ts +16 -7
- package/dist/task/env-notes.js +48 -31
- package/dist/task/env-template-closure.d.ts +4 -4
- package/dist/task/env-template-closure.js +42 -34
- package/dist/task/external-context.d.ts +28 -21
- package/dist/task/external-context.js +17 -12
- package/dist/task/failure-classifier.d.ts +4 -5
- package/dist/task/failure-classifier.js +6 -7
- package/dist/task/file-inventory.d.ts +15 -11
- package/dist/task/file-inventory.js +25 -22
- package/dist/task/final-gate-fix.d.ts +74 -86
- package/dist/task/final-gate-fix.js +97 -116
- package/dist/task/final-gate-progress.d.ts +29 -46
- package/dist/task/final-gate-progress.js +40 -51
- package/dist/task/final-gate.d.ts +64 -97
- package/dist/task/final-gate.js +192 -199
- package/dist/task/fix-child.d.ts +21 -27
- package/dist/task/fix-child.js +21 -27
- package/dist/task/foreign-path.d.ts +6 -5
- package/dist/task/foreign-path.js +0 -0
- package/dist/task/frozen-conflict.d.ts +9 -10
- package/dist/task/frozen-conflict.js +61 -64
- package/dist/task/frozen-path-guard.d.ts +35 -14
- package/dist/task/frozen-path-guard.js +56 -39
- package/dist/task/gate-child.d.ts +27 -28
- package/dist/task/gate-child.js +36 -35
- package/dist/task/gate-deps.d.ts +34 -27
- package/dist/task/gate-deps.js +169 -159
- package/dist/task/gate-tally.d.ts +77 -80
- package/dist/task/gate-tally.js +65 -68
- package/dist/task/git-state-guard.d.ts +15 -11
- package/dist/task/git-state-guard.js +76 -66
- package/dist/task/impl-widget.d.ts +25 -16
- package/dist/task/impl-widget.js +27 -17
- package/dist/task/implementation-thinking.d.ts +33 -31
- package/dist/task/implementation-thinking.js +5 -6
- package/dist/task/implementation-turn.d.ts +34 -31
- package/dist/task/implementation-turn.js +29 -27
- package/dist/task/inline-markdown.d.ts +20 -7
- package/dist/task/inline-markdown.js +15 -6
- package/dist/task/launch-config-gap.js +25 -39
- package/dist/task/launch-contract.d.ts +18 -21
- package/dist/task/launch-contract.js +28 -30
- package/dist/task/launch-manifest.d.ts +6 -2
- package/dist/task/launch-manifest.js +35 -34
- package/dist/task/ledger.js +16 -14
- package/dist/task/lint-fix.d.ts +6 -8
- package/dist/task/lint-fix.js +67 -69
- package/dist/task/loop-detector.d.ts +9 -8
- package/dist/task/loop-detector.js +16 -12
- package/dist/task/mid-run-input.d.ts +17 -15
- package/dist/task/mid-run-input.js +17 -15
- package/dist/task/orchestrator.d.ts +24 -28
- package/dist/task/orchestrator.js +62 -64
- package/dist/task/orientation.d.ts +18 -23
- package/dist/task/orientation.js +24 -31
- package/dist/task/owned-freeze-conflict.d.ts +21 -20
- package/dist/task/owned-freeze-conflict.js +52 -85
- package/dist/task/owned-freeze-reassign.d.ts +40 -60
- package/dist/task/owned-freeze-reassign.js +41 -61
- package/dist/task/parsers.d.ts +4 -2
- package/dist/task/parsers.js +4 -4
- package/dist/task/phases.d.ts +41 -48
- package/dist/task/phases.js +179 -248
- package/dist/task/plan-io.d.ts +6 -7
- package/dist/task/plan-io.js +6 -7
- package/dist/task/plan-orchestrator.d.ts +10 -8
- package/dist/task/plan-orchestrator.js +14 -10
- package/dist/task/plan-prompts.d.ts +6 -5
- package/dist/task/plan-prompts.js +6 -5
- package/dist/task/plan-readonly.d.ts +4 -5
- package/dist/task/plan-readonly.js +4 -5
- package/dist/task/plan-rounds.d.ts +17 -29
- package/dist/task/plan-rounds.js +21 -34
- package/dist/task/plan-session.d.ts +58 -72
- package/dist/task/plan-session.js +61 -83
- package/dist/task/probe-gaming.d.ts +28 -27
- package/dist/task/probe-gaming.js +0 -0
- package/dist/task/prohibition-probe.d.ts +14 -16
- package/dist/task/prompts.d.ts +3 -4
- package/dist/task/prompts.js +17 -26
- package/dist/task/qa-transcript.d.ts +15 -22
- package/dist/task/qa-transcript.js +15 -21
- package/dist/task/question-box.d.ts +17 -13
- package/dist/task/question-box.js +19 -15
- package/dist/task/question-dedup.d.ts +6 -7
- package/dist/task/question-dedup.js +13 -14
- package/dist/task/question-dialog.d.ts +22 -32
- package/dist/task/question-dialog.js +22 -32
- package/dist/task/question-source.d.ts +18 -44
- package/dist/task/question-source.js +22 -51
- package/dist/task/refuted-constraint.d.ts +11 -31
- package/dist/task/refuted-constraint.js +27 -51
- package/dist/task/regenerable-artifacts.d.ts +12 -31
- package/dist/task/regenerable-artifacts.js +12 -31
- package/dist/task/render-check.d.ts +11 -22
- package/dist/task/render-check.js +33 -46
- package/dist/task/repo-health-check.d.ts +10 -14
- package/dist/task/repo-health-check.js +17 -23
- package/dist/task/requirements.d.ts +38 -71
- package/dist/task/requirements.js +78 -126
- package/dist/task/research-fanout-budget.d.ts +51 -88
- package/dist/task/research-fanout-budget.js +51 -88
- package/dist/task/research-worker.d.ts +29 -39
- package/dist/task/research-worker.js +37 -61
- package/dist/task/resume-gap.d.ts +14 -15
- package/dist/task/root-cause-repair.d.ts +9 -9
- package/dist/task/root-cause-repair.js +28 -40
- package/dist/task/run-bracket.d.ts +10 -13
- package/dist/task/run-end.d.ts +12 -22
- package/dist/task/run-end.js +8 -16
- package/dist/task/run-final-gate.d.ts +19 -21
- package/dist/task/run-final-gate.js +62 -80
- package/dist/task/runner-globs.d.ts +12 -13
- package/dist/task/runner-globs.js +12 -13
- package/dist/task/runner-resolve.d.ts +9 -9
- package/dist/task/runner-resolve.js +22 -23
- package/dist/task/script-escape.d.ts +10 -12
- package/dist/task/script-escape.js +13 -14
- package/dist/task/serve-entry.d.ts +1 -1
- package/dist/task/serve-entry.js +22 -25
- package/dist/task/service-blocks.js +4 -2
- package/dist/task/shipped-source.d.ts +11 -29
- package/dist/task/shipped-source.js +11 -29
- package/dist/task/skip-escape.js +10 -14
- package/dist/task/spec-urls.d.ts +26 -65
- package/dist/task/spec-urls.js +26 -65
- package/dist/task/spec-validation.d.ts +17 -20
- package/dist/task/spec-validation.js +17 -20
- package/dist/task/stall-detector.d.ts +23 -30
- package/dist/task/stall-detector.js +23 -30
- package/dist/task/stream-watchdog.d.ts +14 -12
- package/dist/task/stream-watchdog.js +14 -12
- package/dist/task/substitution-probe.d.ts +17 -20
- package/dist/task/substitution-probe.js +17 -20
- package/dist/task/task-gates.d.ts +36 -41
- package/dist/task/task-gates.js +95 -106
- package/dist/task/task-io.d.ts +4 -4
- package/dist/task/task-io.js +4 -4
- package/dist/task/task-parsers.js +4 -3
- package/dist/task/task-provenance.d.ts +2 -2
- package/dist/task/task-provenance.js +11 -13
- package/dist/task/task-types.d.ts +4 -3
- package/dist/task/terminal-outcome.d.ts +14 -16
- package/dist/task/terminal-outcome.js +12 -14
- package/dist/task/test-assembly.d.ts +13 -20
- package/dist/task/test-assembly.js +13 -20
- package/dist/task/timings.d.ts +5 -3
- package/dist/task/timings.js +5 -3
- package/dist/task/title-label.d.ts +9 -4
- package/dist/task/title-label.js +9 -4
- package/dist/task/type-only-answer.d.ts +44 -52
- package/dist/task/type-only-answer.js +44 -52
- package/dist/task/unfailable-command.d.ts +18 -24
- package/dist/task/unfailable-command.js +21 -27
- package/dist/task/unknown-routing.d.ts +10 -4
- package/dist/task/unknown-routing.js +10 -4
- package/dist/task/user-directives.d.ts +5 -8
- package/dist/task/user-directives.js +5 -8
- package/dist/task/verify-quality.d.ts +18 -22
- package/dist/task/verify-quality.js +45 -46
- package/dist/task/verify-reconcile.d.ts +15 -10
- package/dist/task/verify-reconcile.js +45 -43
- package/dist/task/verify-resolution.d.ts +24 -20
- package/dist/task/verify-resolution.js +51 -50
- package/dist/task/verify-work.d.ts +59 -66
- package/dist/task/verify-work.js +101 -138
- package/dist/task/widget.d.ts +15 -14
- package/dist/task/widget.js +22 -17
- package/dist/task/wiring-claims.d.ts +25 -32
- package/dist/task/wiring-claims.js +30 -35
- package/dist/task/write-guard.d.ts +39 -39
- package/dist/task/write-guard.js +48 -51
- package/dist/task/yolo.d.ts +34 -30
- package/dist/task/yolo.js +42 -37
- package/dist/workers/abstention.d.ts +21 -41
- package/dist/workers/abstention.js +27 -48
- package/dist/workers/brave-search.d.ts +4 -3
- package/dist/workers/brave-search.js +5 -2
- package/dist/workers/brave-warning.d.ts +7 -4
- package/dist/workers/brave-warning.js +19 -7
- package/dist/workers/ddg-search.d.ts +6 -6
- package/dist/workers/ddg-search.js +18 -12
- package/dist/workers/docs-cache.js +5 -2
- package/dist/workers/docs-chunk.d.ts +30 -37
- package/dist/workers/docs-chunk.js +37 -41
- package/dist/workers/docs-core.d.ts +28 -44
- package/dist/workers/docs-core.js +25 -44
- package/dist/workers/docs-index.js +4 -3
- package/dist/workers/docs-lookup.d.ts +15 -22
- package/dist/workers/docs-lookup.js +12 -21
- package/dist/workers/docs-project.d.ts +15 -9
- package/dist/workers/docs-project.js +17 -10
- package/dist/workers/docs-resolve.d.ts +19 -20
- package/dist/workers/docs-resolve.js +35 -32
- package/dist/workers/docs-retrieve.d.ts +5 -6
- package/dist/workers/docs-retrieve.js +18 -15
- package/dist/workers/exa-search.d.ts +9 -6
- package/dist/workers/exa-search.js +23 -12
- package/dist/workers/fetch-core.d.ts +13 -16
- package/dist/workers/fetch-core.js +23 -23
- package/dist/workers/focused-extractor.d.ts +12 -12
- package/dist/workers/focused-extractor.js +16 -19
- package/dist/workers/html-clean.js +24 -14
- package/dist/workers/http-request.d.ts +28 -20
- package/dist/workers/http-request.js +22 -17
- package/dist/workers/npm-version.d.ts +28 -11
- package/dist/workers/npm-version.js +24 -15
- package/dist/workers/phantom-imports.d.ts +15 -12
- package/dist/workers/phantom-imports.js +30 -24
- package/dist/workers/pi-worker-core.d.ts +69 -71
- package/dist/workers/pi-worker-core.js +100 -109
- package/dist/workers/pi-worker-docs.d.ts +24 -19
- package/dist/workers/pi-worker-docs.js +67 -76
- package/dist/workers/pi-worker-fetch.d.ts +7 -3
- package/dist/workers/pi-worker-fetch.js +27 -19
- package/dist/workers/pi-worker-search.js +12 -8
- package/dist/workers/pi-worker.d.ts +9 -4
- package/dist/workers/pi-worker.js +21 -14
- package/dist/workers/reasoning-warning.d.ts +18 -17
- package/dist/workers/reasoning-warning.js +22 -20
- package/dist/workers/research-cache.js +50 -78
- package/dist/workers/search-core.js +7 -5
- package/dist/workers/search-types.d.ts +10 -9
- package/dist/workers/search-types.js +9 -8
- package/dist/workers/session-hint.d.ts +13 -14
- package/dist/workers/session-hint.js +8 -9
- package/dist/workers/shared.d.ts +21 -25
- package/dist/workers/shared.js +0 -0
- package/dist/workers/single-read-extension.d.ts +14 -7
- package/dist/workers/single-read-extension.js +14 -7
- package/dist/workers/single-read-guard.d.ts +25 -28
- package/dist/workers/single-read-guard.js +32 -32
- package/dist/workers/typeonly-log.d.ts +12 -9
- package/dist/workers/typeonly-log.js +29 -33
- package/dist/workers/worker-channels.d.ts +15 -23
- package/dist/workers/worker-channels.js +15 -23
- package/dist/workers/worker-failure.d.ts +38 -46
- package/dist/workers/worker-failure.js +31 -39
- package/dist/workers/worker-kill.d.ts +25 -26
- package/dist/workers/worker-kill.js +16 -19
- package/dist/workers/worker-profiles.d.ts +43 -53
- package/dist/workers/worker-profiles.js +30 -38
- package/package.json +10 -8
|
@@ -1,34 +1,30 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* In-process thrash guards
|
|
2
|
+
* In-process thrash guards, armed by single-read-extension.ts in the TOOLING
|
|
3
|
+
* research worker and the planning children.
|
|
3
4
|
*
|
|
4
|
-
* Two guards, one mechanism — deny a wasteful repeat *inside the run
|
|
5
|
+
* Two guards, one mechanism — deny a wasteful repeat *inside the run*. The
|
|
5
6
|
* extension returns the block from a `tool_call` handler, pi feeds `reason` back
|
|
6
|
-
* as an error tool result, the
|
|
7
|
-
* and-kill only re-spawns a model that deterministically re-thrashes.
|
|
7
|
+
* as an error tool result, and the child continues. No kill, no restart:
|
|
8
|
+
* detect-and-kill only re-spawns a model that deterministically re-thrashes.
|
|
8
9
|
*
|
|
9
|
-
* - SingleReadGuard: "read each LINE of a file once".
|
|
10
|
-
* recorded mx5 run — a healthy TOOLING worker reads each file exactly once
|
|
11
|
-
* (max same-file reads = 1 across 7 tasks). TASK_0017 re-read one file 50×.
|
|
10
|
+
* - SingleReadGuard: "read each LINE of a file once".
|
|
12
11
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* reached the end of the file, and spent the rest of the run asking for the
|
|
19
|
-
* remainder: 197 of 200 tool calls were this guard's own refusal. The guard
|
|
20
|
-
* did not stop a thrash, it CAUSED one.
|
|
12
|
+
* Keying on the resolved path alone — blocking any second read regardless of
|
|
13
|
+
* offset — turns a file bigger than one read into a TRAP. A child paging
|
|
14
|
+
* deliberately, first 80 lines then the next 80, has its second request
|
|
15
|
+
* refused; it never reaches the end of the file and spends the rest of the run
|
|
16
|
+
* asking for the remainder. That guard does not stop a thrash, it causes one.
|
|
21
17
|
*
|
|
22
|
-
* So the unit is the line range, not the file. A request that extends past
|
|
23
|
-
*
|
|
24
|
-
*
|
|
18
|
+
* So the unit is the line range, not the file. A request that extends past the
|
|
19
|
+
* furthest line already delivered is forward paging and passes; one that lies
|
|
20
|
+
* entirely within ground already delivered is a re-read and is blocked.
|
|
25
21
|
*
|
|
26
|
-
* - RepeatedCallGuard: "no identical search twice", for grep/find/ls
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
22
|
+
* - RepeatedCallGuard: "no identical search twice", for grep/find/ls — the
|
|
23
|
+
* shapes the read guard cannot see, such as the same grep pattern re-run
|
|
24
|
+
* against the same path. Keyed on `${toolName}\0${stableStringify(args)}`,
|
|
25
|
+
* byte-identical to the key `LoopDetector.record` builds, so argument key
|
|
26
|
+
* order never causes a miss and only an identical repeat trips. A different
|
|
27
|
+
* pattern on the same file still passes.
|
|
32
28
|
*
|
|
33
29
|
* Pure logic, no I/O — the extension does path resolution and tool routing.
|
|
34
30
|
*/
|
|
@@ -40,10 +36,11 @@ export interface ReadBlock {
|
|
|
40
36
|
* The error text the model receives in place of the re-read's contents.
|
|
41
37
|
*
|
|
42
38
|
* It must say what to do NEXT, and the honest next move depends on whether there
|
|
43
|
-
* is any of the file left: with `covered` lines already delivered, asking for
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
39
|
+
* is any of the file left: with `covered` lines already delivered, asking for line
|
|
40
|
+
* `covered + 1` is always allowed, so the message says so. A bare "do not read it
|
|
41
|
+
* again" is a dead end for a model mid-way through a file — it has nowhere legal
|
|
42
|
+
* to go and keeps asking anyway. A read that reached EOF has `covered` set to
|
|
43
|
+
* Infinity and gets the other wording, with no line to resume from.
|
|
47
44
|
*/
|
|
48
45
|
export declare function singleReadReason(path: string, covered: number): string;
|
|
49
46
|
export declare class SingleReadGuard {
|
|
@@ -1,34 +1,30 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* In-process thrash guards
|
|
2
|
+
* In-process thrash guards, armed by single-read-extension.ts in the TOOLING
|
|
3
|
+
* research worker and the planning children.
|
|
3
4
|
*
|
|
4
|
-
* Two guards, one mechanism — deny a wasteful repeat *inside the run
|
|
5
|
+
* Two guards, one mechanism — deny a wasteful repeat *inside the run*. The
|
|
5
6
|
* extension returns the block from a `tool_call` handler, pi feeds `reason` back
|
|
6
|
-
* as an error tool result, the
|
|
7
|
-
* and-kill only re-spawns a model that deterministically re-thrashes.
|
|
7
|
+
* as an error tool result, and the child continues. No kill, no restart:
|
|
8
|
+
* detect-and-kill only re-spawns a model that deterministically re-thrashes.
|
|
8
9
|
*
|
|
9
|
-
* - SingleReadGuard: "read each LINE of a file once".
|
|
10
|
-
* recorded mx5 run — a healthy TOOLING worker reads each file exactly once
|
|
11
|
-
* (max same-file reads = 1 across 7 tasks). TASK_0017 re-read one file 50×.
|
|
10
|
+
* - SingleReadGuard: "read each LINE of a file once".
|
|
12
11
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* reached the end of the file, and spent the rest of the run asking for the
|
|
19
|
-
* remainder: 197 of 200 tool calls were this guard's own refusal. The guard
|
|
20
|
-
* did not stop a thrash, it CAUSED one.
|
|
12
|
+
* Keying on the resolved path alone — blocking any second read regardless of
|
|
13
|
+
* offset — turns a file bigger than one read into a TRAP. A child paging
|
|
14
|
+
* deliberately, first 80 lines then the next 80, has its second request
|
|
15
|
+
* refused; it never reaches the end of the file and spends the rest of the run
|
|
16
|
+
* asking for the remainder. That guard does not stop a thrash, it causes one.
|
|
21
17
|
*
|
|
22
|
-
* So the unit is the line range, not the file. A request that extends past
|
|
23
|
-
*
|
|
24
|
-
*
|
|
18
|
+
* So the unit is the line range, not the file. A request that extends past the
|
|
19
|
+
* furthest line already delivered is forward paging and passes; one that lies
|
|
20
|
+
* entirely within ground already delivered is a re-read and is blocked.
|
|
25
21
|
*
|
|
26
|
-
* - RepeatedCallGuard: "no identical search twice", for grep/find/ls
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
22
|
+
* - RepeatedCallGuard: "no identical search twice", for grep/find/ls — the
|
|
23
|
+
* shapes the read guard cannot see, such as the same grep pattern re-run
|
|
24
|
+
* against the same path. Keyed on `${toolName}\0${stableStringify(args)}`,
|
|
25
|
+
* byte-identical to the key `LoopDetector.record` builds, so argument key
|
|
26
|
+
* order never causes a miss and only an identical repeat trips. A different
|
|
27
|
+
* pattern on the same file still passes.
|
|
32
28
|
*
|
|
33
29
|
* Pure logic, no I/O — the extension does path resolution and tool routing.
|
|
34
30
|
*/
|
|
@@ -37,10 +33,11 @@ import { stableStringify } from '../task/loop-detector.js';
|
|
|
37
33
|
* The error text the model receives in place of the re-read's contents.
|
|
38
34
|
*
|
|
39
35
|
* It must say what to do NEXT, and the honest next move depends on whether there
|
|
40
|
-
* is any of the file left: with `covered` lines already delivered, asking for
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
36
|
+
* is any of the file left: with `covered` lines already delivered, asking for line
|
|
37
|
+
* `covered + 1` is always allowed, so the message says so. A bare "do not read it
|
|
38
|
+
* again" is a dead end for a model mid-way through a file — it has nowhere legal
|
|
39
|
+
* to go and keeps asking anyway. A read that reached EOF has `covered` set to
|
|
40
|
+
* Infinity and gets the other wording, with no line to resume from.
|
|
44
41
|
*/
|
|
45
42
|
export function singleReadReason(path, covered) {
|
|
46
43
|
if (!Number.isFinite(covered)) {
|
|
@@ -53,7 +50,8 @@ export function singleReadReason(path, covered) {
|
|
|
53
50
|
+ `starting at line ${covered + 1}; otherwise use what you have already gathered and `
|
|
54
51
|
+ `write your final answer now.`);
|
|
55
52
|
}
|
|
56
|
-
/**
|
|
53
|
+
/** pi's own read truncation ceiling (`DEFAULT_MAX_LINES` in its truncate.js): a
|
|
54
|
+
* read that names no `limit` returns at most this many lines. */
|
|
57
55
|
const DEFAULT_READ_LIMIT = 2000;
|
|
58
56
|
/** The 1-based line a read starts at (`offset` absent or junk means line 1). */
|
|
59
57
|
function startLine(offset) {
|
|
@@ -62,9 +60,11 @@ function startLine(offset) {
|
|
|
62
60
|
: 1;
|
|
63
61
|
}
|
|
64
62
|
/**
|
|
65
|
-
* The last line a read reaches
|
|
66
|
-
* as "no limit given" — indistinguishable
|
|
67
|
-
*
|
|
63
|
+
* The last line a read reaches, or Infinity when the read is unbounded. A `limit`
|
|
64
|
+
* at or above pi's own ceiling is treated as "no limit given" — indistinguishable
|
|
65
|
+
* at this layer — and so is a `limit` that is absent, zero, negative or not a
|
|
66
|
+
* number. The generous reading is the safe one, since blocking honest paging is
|
|
67
|
+
* the failure mode this guard has.
|
|
68
68
|
*/
|
|
69
69
|
function endLine(start, limit) {
|
|
70
70
|
if (typeof limit !== 'number' || !Number.isFinite(limit) || limit <= 0)
|
|
@@ -23,12 +23,12 @@ export interface TypeOnlyLogRecord {
|
|
|
23
23
|
* The FULL verification record behind `excerptVerified` — the normalised excerpt that was
|
|
24
24
|
* searched for, plus a sha256 + length of the normalised content it was searched in.
|
|
25
25
|
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
26
|
+
* The other half of the retention above: the answer text says WHAT was claimed, and
|
|
27
|
+
* this says what it was checked against — so a false verdict can be attributed to
|
|
28
|
+
* fabrication (the excerpt is nowhere near the content) rather than to a normaliser
|
|
29
|
+
* gap (a markdown-escape variant of text that IS present) without re-running the
|
|
30
|
+
* lookup. focused-extractor.ts hands the struct to both of its call sites.
|
|
31
|
+
* Optional — older records still parse.
|
|
32
32
|
*/
|
|
33
33
|
excerptCheck?: ExcerptVerification;
|
|
34
34
|
/**
|
|
@@ -50,9 +50,12 @@ export interface TypeOnlyLogRecord {
|
|
|
50
50
|
/**
|
|
51
51
|
* Append one record to the JSONL sink named by `PI_TASK_TYPEONLY_LOG`, if set.
|
|
52
52
|
*
|
|
53
|
-
* @param rec everything but `at` and `unclear
|
|
54
|
-
*
|
|
53
|
+
* @param rec everything but `at` (an ISO timestamp) and `unclear` (the abstention
|
|
54
|
+
* predicate over `answer`), which are derived here so both call sites in
|
|
55
|
+
* pi-worker-docs stamp them identically.
|
|
55
56
|
*/
|
|
56
57
|
export declare function logDocsAnswer(rec: Omit<TypeOnlyLogRecord, 'at' | 'unclear'>, getEnv?: (k: string) => string | undefined): void;
|
|
57
|
-
/** Parse a sink written by {@link logDocsAnswer}
|
|
58
|
+
/** Parse a sink written by {@link logDocsAnswer}. Blank lines are skipped and a
|
|
59
|
+
* malformed one — including the truncated tail a killed process leaves — is dropped
|
|
60
|
+
* rather than thrown. */
|
|
58
61
|
export declare function readTypeOnlyLog(text: string): TypeOnlyLogRecord[];
|
|
@@ -1,40 +1,33 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Firing-rate instrumentation for the TYPE-ONLY detector. Observability only; it
|
|
3
|
+
* changes no behaviour.
|
|
3
4
|
*
|
|
4
|
-
* WHY THIS EXISTS.
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* type-only answer actually occurs. The causal claim "workers stop BECAUSE of type-only
|
|
9
|
-
* answers" was asserted from one static corpus (1 flag in 150 recorded answers, 0.7%) and
|
|
10
|
-
* never measured live. You cannot size an arm, pick a metric, or decide whether the lever is
|
|
11
|
-
* a population fix or a single-case guard without that firing rate.
|
|
5
|
+
* WHY THIS EXISTS. "How often does a type-only answer occur" cannot be answered by
|
|
6
|
+
* counting the times the detector FIRED — a log of firings has no denominator. So
|
|
7
|
+
* every pi-worker-docs answer is recorded, flagged or not, and the rate is
|
|
8
|
+
* computable rather than inferable.
|
|
12
9
|
*
|
|
13
|
-
* WHAT IT DOES. When `PI_TASK_TYPEONLY_LOG` names a file,
|
|
14
|
-
*
|
|
15
|
-
* the same channel, so a rate is computable rather than inferable. With the variable unset
|
|
16
|
-
* this is a no-op and nothing is written.
|
|
10
|
+
* WHAT IT DOES. When `PI_TASK_TYPEONLY_LOG` names a file, each answer appends one
|
|
11
|
+
* JSON line there. Unset or blank and this is a no-op that writes nothing.
|
|
17
12
|
*
|
|
18
|
-
* MECHANICAL, NOT SELF-REPORT. The record is written at the TOOL layer from the
|
|
19
|
-
* shipped detector just returned, next to the same `details` the caller
|
|
20
|
-
* asked whether it thought the answer was a type signature.
|
|
13
|
+
* MECHANICAL, NOT SELF-REPORT. The record is written at the TOOL layer from the
|
|
14
|
+
* verdict the shipped detector just returned, next to the same `details` the caller
|
|
15
|
+
* receives. No model is asked whether it thought the answer was a type signature.
|
|
21
16
|
*
|
|
22
|
-
* BEHAVIOUR-
|
|
23
|
-
* change, so:
|
|
17
|
+
* BEHAVIOUR-NEUTRAL BY CONSTRUCTION:
|
|
24
18
|
* - it is called for its side effect only; nothing reads its return value;
|
|
25
|
-
* - every failure is swallowed
|
|
26
|
-
* docs lookup into an error — instrumentation that can break the thing
|
|
27
|
-
* worse than
|
|
28
|
-
* - it appends
|
|
29
|
-
*
|
|
30
|
-
*
|
|
19
|
+
* - every failure is swallowed. A full disk or an unwritable path must not turn a
|
|
20
|
+
* working docs lookup into an error — instrumentation that can break the thing
|
|
21
|
+
* it measures is worse than none;
|
|
22
|
+
* - it appends SYNCHRONOUSLY, because the process that writes it is a pi child
|
|
23
|
+
* that can exit the moment the tool returns, and a queued async write would be
|
|
24
|
+
* lost.
|
|
31
25
|
*
|
|
32
|
-
* THE FULL ANSWER TEXT IS RETAINED, deliberately.
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
* reconstruct later.
|
|
26
|
+
* THE FULL ANSWER TEXT IS RETAINED, deliberately. Without it, an
|
|
27
|
+
* `excerptVerified === false` cannot afterwards be attributed to fabrication rather
|
|
28
|
+
* than to a normaliser gap, and "is this question type-only every time or does it
|
|
29
|
+
* churn between identical runs" cannot be settled at all — both need the recorded
|
|
30
|
+
* answers re-scored. Cheap to keep, impossible to reconstruct later.
|
|
38
31
|
*/
|
|
39
32
|
import * as fs from 'node:fs';
|
|
40
33
|
import { isAbstention } from './abstention.js';
|
|
@@ -43,8 +36,9 @@ export const TYPEONLY_LOG_ENV = 'PI_TASK_TYPEONLY_LOG';
|
|
|
43
36
|
/**
|
|
44
37
|
* Append one record to the JSONL sink named by `PI_TASK_TYPEONLY_LOG`, if set.
|
|
45
38
|
*
|
|
46
|
-
* @param rec everything but `at` and `unclear
|
|
47
|
-
*
|
|
39
|
+
* @param rec everything but `at` (an ISO timestamp) and `unclear` (the abstention
|
|
40
|
+
* predicate over `answer`), which are derived here so both call sites in
|
|
41
|
+
* pi-worker-docs stamp them identically.
|
|
48
42
|
*/
|
|
49
43
|
export function logDocsAnswer(rec, getEnv = k => process.env[k]) {
|
|
50
44
|
const sink = getEnv(TYPEONLY_LOG_ENV);
|
|
@@ -63,7 +57,9 @@ export function logDocsAnswer(rec, getEnv = k => process.env[k]) {
|
|
|
63
57
|
// succeeded must not be reported as failed because the sink was unwritable.
|
|
64
58
|
}
|
|
65
59
|
}
|
|
66
|
-
/** Parse a sink written by {@link logDocsAnswer}
|
|
60
|
+
/** Parse a sink written by {@link logDocsAnswer}. Blank lines are skipped and a
|
|
61
|
+
* malformed one — including the truncated tail a killed process leaves — is dropped
|
|
62
|
+
* rather than thrown. */
|
|
67
63
|
export function readTypeOnlyLog(text) {
|
|
68
64
|
const out = [];
|
|
69
65
|
for (const line of text.split('\n')) {
|
|
@@ -1,28 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* worker-channels — what a worker TOOL is, as data.
|
|
3
3
|
*
|
|
4
|
-
* `makeWorkerTool`
|
|
5
|
-
* `spec.name` never
|
|
6
|
-
*
|
|
4
|
+
* `makeWorkerTool` gives every worker tool one registration adapter, but
|
|
5
|
+
* `spec.name` never leaves that closure. Without this table the three tool names
|
|
6
|
+
* are re-typed as literals wherever anything else needs them: the tools string
|
|
7
|
+
* and its matching `-e` path list, the grounding set, the debug-log summary and
|
|
8
|
+
* its per-tool parameter shape, and — worst for locality — the GENERIC child
|
|
9
|
+
* runner, which would have to name one tool AND one of its parameters to decide a
|
|
10
|
+
* fan-out deadline extension. Nothing links those edits at compile time. Here
|
|
11
|
+
* each tool is one row.
|
|
7
12
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* • `GROUNDING_RETRIEVAL_TOOLS` was a second copy of the names.
|
|
13
|
-
* • `summarizeToolArgs` was a third, and also re-stated each tool's parameter
|
|
14
|
-
* shape (`module`/`query`, `query`, `url`).
|
|
15
|
-
* • Worst for locality: `runWorker` — the GENERIC child runner — hardcoded one
|
|
16
|
-
* tool's identity AND its parameter, `call.name === 'pi-worker-docs' &&
|
|
17
|
-
* args.module === '.'`, to decide a fan-out deadline extension.
|
|
18
|
-
*
|
|
19
|
-
* A rename or a new tool was five edits in three directories with no compile
|
|
20
|
-
* error linking them. It is one row here now.
|
|
21
|
-
*
|
|
22
|
-
* What is NOT in a row: the tools string's non-worker members (`read`, `grep`,
|
|
23
|
-
* `find`, `ls`) are pi's own built-ins, not channels — they appear in
|
|
24
|
-
* {@link GROUNDING_RETRIEVAL_TOOLS} because grounding is about RETRIEVAL, not
|
|
25
|
-
* about which extension supplies it.
|
|
13
|
+
* What is NOT a row: pi's own built-ins. `read` and `grep` are listed in
|
|
14
|
+
* {@link GROUNDING_RETRIEVAL_TOOLS} because grounding is about RETRIEVAL rather
|
|
15
|
+
* than about which extension supplies it, while `find` and `ls` return names only
|
|
16
|
+
* and are excluded from it.
|
|
26
17
|
*/
|
|
27
18
|
/** One worker tool, and everything the rest of the codebase knows about it. */
|
|
28
19
|
export interface WorkerChannel {
|
|
@@ -49,8 +40,9 @@ export declare const WORKER_CHANNELS: readonly WorkerChannel[];
|
|
|
49
40
|
export declare function workerChannel(toolName: string): WorkerChannel | undefined;
|
|
50
41
|
/**
|
|
51
42
|
* The tools string and the `-e` paths for a set of channels, together — they are
|
|
52
|
-
* one fact and
|
|
53
|
-
*
|
|
43
|
+
* one fact, and two literals would drift. The tools string preserves the order it
|
|
44
|
+
* was asked for; entry paths are de-duplicated, so asking for search AND fetch
|
|
45
|
+
* yields ONE path, since both ship in search-extension.js.
|
|
54
46
|
*/
|
|
55
47
|
export declare function channelSet(names: readonly string[]): {
|
|
56
48
|
tools: string;
|
|
@@ -1,28 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* worker-channels — what a worker TOOL is, as data.
|
|
3
3
|
*
|
|
4
|
-
* `makeWorkerTool`
|
|
5
|
-
* `spec.name` never
|
|
6
|
-
*
|
|
4
|
+
* `makeWorkerTool` gives every worker tool one registration adapter, but
|
|
5
|
+
* `spec.name` never leaves that closure. Without this table the three tool names
|
|
6
|
+
* are re-typed as literals wherever anything else needs them: the tools string
|
|
7
|
+
* and its matching `-e` path list, the grounding set, the debug-log summary and
|
|
8
|
+
* its per-tool parameter shape, and — worst for locality — the GENERIC child
|
|
9
|
+
* runner, which would have to name one tool AND one of its parameters to decide a
|
|
10
|
+
* fan-out deadline extension. Nothing links those edits at compile time. Here
|
|
11
|
+
* each tool is one row.
|
|
7
12
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* • `GROUNDING_RETRIEVAL_TOOLS` was a second copy of the names.
|
|
13
|
-
* • `summarizeToolArgs` was a third, and also re-stated each tool's parameter
|
|
14
|
-
* shape (`module`/`query`, `query`, `url`).
|
|
15
|
-
* • Worst for locality: `runWorker` — the GENERIC child runner — hardcoded one
|
|
16
|
-
* tool's identity AND its parameter, `call.name === 'pi-worker-docs' &&
|
|
17
|
-
* args.module === '.'`, to decide a fan-out deadline extension.
|
|
18
|
-
*
|
|
19
|
-
* A rename or a new tool was five edits in three directories with no compile
|
|
20
|
-
* error linking them. It is one row here now.
|
|
21
|
-
*
|
|
22
|
-
* What is NOT in a row: the tools string's non-worker members (`read`, `grep`,
|
|
23
|
-
* `find`, `ls`) are pi's own built-ins, not channels — they appear in
|
|
24
|
-
* {@link GROUNDING_RETRIEVAL_TOOLS} because grounding is about RETRIEVAL, not
|
|
25
|
-
* about which extension supplies it.
|
|
13
|
+
* What is NOT a row: pi's own built-ins. `read` and `grep` are listed in
|
|
14
|
+
* {@link GROUNDING_RETRIEVAL_TOOLS} because grounding is about RETRIEVAL rather
|
|
15
|
+
* than about which extension supplies it, while `find` and `ls` return names only
|
|
16
|
+
* and are excluded from it.
|
|
26
17
|
*/
|
|
27
18
|
import { fileURLToPath } from 'node:url';
|
|
28
19
|
const DOCS_ENTRY = fileURLToPath(new URL('./docs-extension.js', import.meta.url));
|
|
@@ -64,8 +55,9 @@ export function workerChannel(toolName) {
|
|
|
64
55
|
}
|
|
65
56
|
/**
|
|
66
57
|
* The tools string and the `-e` paths for a set of channels, together — they are
|
|
67
|
-
* one fact and
|
|
68
|
-
*
|
|
58
|
+
* one fact, and two literals would drift. The tools string preserves the order it
|
|
59
|
+
* was asked for; entry paths are de-duplicated, so asking for search AND fetch
|
|
60
|
+
* yields ONE path, since both ship in search-extension.js.
|
|
69
61
|
*/
|
|
70
62
|
export function channelSet(names) {
|
|
71
63
|
// REFUSED, not dropped. Silently skipping an unrecognised name is the exact
|
|
@@ -5,35 +5,34 @@
|
|
|
5
5
|
* Why this module exists. `RunWorkerResult` reports each kill cause as its own
|
|
6
6
|
* optional field (`loopHit`, `timedOut`, `stalled`, `commandTimedOut`,
|
|
7
7
|
* `streamStalled`, `leakedToolCall`, `aborted`, `exitCode`), and every kill path
|
|
8
|
-
* ALSO sets
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
8
|
+
* ALSO sets the two generic ones. `killProc` sets `aborted` on every route out,
|
|
9
|
+
* and pi's own print/json mode installs a SIGTERM handler that exits 143, so a
|
|
10
|
+
* terminated child carries a non-zero exit too. So a consumer cannot read the
|
|
11
|
+
* fields in any order it likes: the specific causes must be matched before the
|
|
12
|
+
* generic `aborted`/`exitCode` ones, or a dead backend is reported to the user as
|
|
13
|
+
* "you cancelled".
|
|
12
14
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* was added to the result and to `finalAttemptFailed`, but the enforce ladder
|
|
18
|
-
* never grew an arm for it, so an enforcement child killed for a hung model
|
|
19
|
-
* stream fell all the way through to `if (aborted) return USER_CANCELLED` — the
|
|
20
|
-
* exact mislabel the comment above that line warns against.
|
|
15
|
+
* Written as prose, or as the source order of each consumer's own hand-rolled
|
|
16
|
+
* ladder, that rule gets a fresh chance to drift per consumer — and the failure is
|
|
17
|
+
* silent: add a new kill cause to the result, forget one ladder's arm for it, and
|
|
18
|
+
* that consumer falls through to `if (aborted)` and reports a cancel.
|
|
21
19
|
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
20
|
+
* So the order is DATA. `FAILURE_RULES` is ordered, the first matching row wins,
|
|
21
|
+
* and consumers `switch` on the resulting `kind` — `classifyEnforceChildFailure`
|
|
22
|
+
* (enforce-guidelines.ts) and `classifyResearchWorker` (research-worker.ts) both
|
|
23
|
+
* call `classifyWorkerFailure` and say only what each cause means to THEM. A new
|
|
24
|
+
* kill cause is one row here plus a compile error in every consumer that has not
|
|
25
|
+
* handled it.
|
|
27
26
|
*/
|
|
28
27
|
import type { LoopHit } from '../task/loop-detector.js';
|
|
29
28
|
import type { WorkerKillId } from './worker-kill.js';
|
|
30
29
|
/**
|
|
31
30
|
* The subset of a finished child result this classification reads.
|
|
32
31
|
*
|
|
33
|
-
* Structural on purpose: `runWorker` returns a superset, and
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
32
|
+
* Structural on purpose: `runWorker` returns a superset, and `EnforceChildResult`
|
|
33
|
+
* extends this interface with the one field enforcement adds. Typing the input as
|
|
34
|
+
* what is actually READ lets both pass without either importing the other's
|
|
35
|
+
* interface.
|
|
37
36
|
*/
|
|
38
37
|
export interface WorkerFailureInput {
|
|
39
38
|
exitCode: number;
|
|
@@ -55,9 +54,9 @@ export interface WorkerFailureInput {
|
|
|
55
54
|
*
|
|
56
55
|
* Note what is NOT here: an empty answer, and a reported `modelError` on a run
|
|
57
56
|
* that still produced text. Neither is a kill — whether they count as a failure
|
|
58
|
-
* is the consumer's policy
|
|
59
|
-
*
|
|
60
|
-
* owns it.
|
|
57
|
+
* is the consumer's policy — research-worker.ts, for one, accepts an explicit
|
|
58
|
+
* empty section after a retry — so folding them in would move a decision out of
|
|
59
|
+
* the module that owns it.
|
|
61
60
|
*/
|
|
62
61
|
export type WorkerFailure = {
|
|
63
62
|
kind: 'stalled';
|
|
@@ -102,9 +101,8 @@ export type WorkerFailureKind = WorkerFailure['kind'];
|
|
|
102
101
|
* class of event: a watchdog, not the model, ended the attempt.
|
|
103
102
|
* 4. `worker-timeout` — the wall-clock backstop.
|
|
104
103
|
* 5. `loop` — killed for repeating one tool call past threshold. After the
|
|
105
|
-
* timeouts
|
|
106
|
-
*
|
|
107
|
-
* can expire.
|
|
104
|
+
* timeouts: a loop kill ends the attempt, so its own timer does not go on to
|
|
105
|
+
* expire as well.
|
|
108
106
|
* 6. `leaked-tool-call` — the model wrote a call as prose instead of invoking
|
|
109
107
|
* it. Only ever set on an otherwise clean run.
|
|
110
108
|
* 7. `aborted` — no specific cause survived, so this really is a cancel.
|
|
@@ -117,35 +115,29 @@ export declare const FAILURE_RULES: ReadonlyArray<{
|
|
|
117
115
|
id: WorkerKillId;
|
|
118
116
|
match: (r: WorkerFailureInput) => WorkerFailure | null;
|
|
119
117
|
}>;
|
|
120
|
-
/**
|
|
121
|
-
* Classify a finished child. Returns `undefined` when nothing killed it —
|
|
122
|
-
* which is not the same as "it answered": the text may still be empty, and that
|
|
123
|
-
* judgement belongs to the caller.
|
|
124
|
-
*/
|
|
125
118
|
/**
|
|
126
119
|
* What a worker failure SAYS to the caller that asked for the work.
|
|
127
120
|
*
|
|
128
|
-
* WHY IT EXISTS. The ladder above already names the cause exactly, with its
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
* put in the debug trail, which a user reading a tool result never sees.
|
|
136
|
-
*
|
|
137
|
-
* That is not only unhelpful; it is why the `pi-worker` tool's 240s cap has no
|
|
138
|
-
* base rate. 53 recorded invocations across eight repos carry 14 failures, and
|
|
139
|
-
* NOTHING in the transcript says which of them ran out of time — the honest
|
|
140
|
-
* bound recoverable from timestamps alone is "somewhere between 0 and 8".
|
|
121
|
+
* WHY IT EXISTS. The ladder above already names the cause exactly, with its detail
|
|
122
|
+
* — which tool hung, how long the stream was idle, which exit code. Answering
|
|
123
|
+
* `if (aborted) return abortedMessage` instead throws all of it away: a wall-clock
|
|
124
|
+
* kill, a hung `bash`, a dead model backend, a loop kill and a user pressing ESC
|
|
125
|
+
* then print the SAME words, and the discriminating value only reaches a debug
|
|
126
|
+
* trail a user reading a tool result never sees. Every arm below returns a
|
|
127
|
+
* different message, and only `aborted` returns the caller's own.
|
|
141
128
|
*
|
|
142
129
|
* A switch, not a table: `WorkerFailure` is a discriminated union carrying a
|
|
143
130
|
* different payload per arm, so the exhaustiveness check is the compiler's and a
|
|
144
|
-
*
|
|
131
|
+
* new arm cannot be added without a message.
|
|
145
132
|
*/
|
|
146
133
|
export declare function describeWorkerFailure(f: WorkerFailure,
|
|
147
134
|
/** What a genuine user cancel says. The caller's wording — only this arm is theirs. */
|
|
148
135
|
abortedMessage: string,
|
|
149
136
|
/** stderr for the `exit` arm; ignored by every other. */
|
|
150
137
|
stderr?: string): string;
|
|
138
|
+
/**
|
|
139
|
+
* Classify a finished child against the ladder. Returns `undefined` when nothing
|
|
140
|
+
* killed it — which is not the same as "it answered": the text may still be empty,
|
|
141
|
+
* and that judgement belongs to the caller.
|
|
142
|
+
*/
|
|
151
143
|
export declare function classifyWorkerFailure(r: WorkerFailureInput): WorkerFailure | undefined;
|