@mjasnikovs/pi-task 0.38.29 → 0.38.31
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/index.js +2 -0
- 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 +85 -16
- package/dist/shared/command-watchdog.js +115 -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 +192 -165
- 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 +124 -55
- package/dist/task/child-runner.js +298 -90
- 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 +30 -8
- 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-guards.d.ts +26 -0
- package/dist/task/implementation-guards.js +177 -0
- package/dist/task/implementation-thinking.d.ts +33 -31
- package/dist/task/implementation-thinking.js +5 -6
- package/dist/task/implementation-turn.d.ts +39 -31
- package/dist/task/implementation-turn.js +41 -28
- 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 +27 -8
- package/dist/task/loop-detector.js +38 -14
- 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 +89 -66
- 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 +196 -252
- 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 +13 -12
- package/dist/workers/focused-extractor.js +27 -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 +65 -96
- package/dist/workers/pi-worker-core.js +93 -181
- 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 +27 -30
- package/dist/workers/single-read-guard.js +36 -36
- 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 +54 -56
- package/dist/workers/worker-profiles.js +63 -39
- package/package.json +10 -8
|
@@ -2,18 +2,18 @@
|
|
|
2
2
|
* model-endpoint — discovery + reachability probe for the model backend(s) a
|
|
3
3
|
* child pi process talks to.
|
|
4
4
|
*
|
|
5
|
-
* The failure this serves
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
5
|
+
* The failure this serves: the model server dies mid-child and the child hangs
|
|
6
|
+
* mute. pi's own connection-error handling cannot help, because it runs from a
|
|
7
|
+
* catch — a request that FAILS reaches it, a request that simply never answers
|
|
8
|
+
* does not. The stall guard in runChild uses this module to tell the two apart:
|
|
9
|
+
* silence alone could be honest long work, since prompt processing emits nothing
|
|
10
|
+
* while it runs, so only "no output AND the endpoint does not answer" counts as
|
|
11
|
+
* a dead backend.
|
|
12
12
|
*
|
|
13
|
-
* Discovery is generic
|
|
14
|
-
*
|
|
15
|
-
* No discoverable endpoint
|
|
16
|
-
* on a backend we cannot see
|
|
13
|
+
* Discovery is generic — the custom providers pi is configured with, read from
|
|
14
|
+
* models.json `providers.*.baseUrl`, with no provider or server name hardcoded.
|
|
15
|
+
* No discoverable endpoint means nothing to probe, and the guard then NEVER
|
|
16
|
+
* kills: a child on a backend we cannot see gets the benefit of the doubt.
|
|
17
17
|
*/
|
|
18
18
|
import * as fs from 'node:fs';
|
|
19
19
|
import * as os from 'node:os';
|
|
@@ -34,9 +34,13 @@ export function discoverModelEndpoints(agentDir = path.join(os.homedir(), '.pi',
|
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
/**
|
|
37
|
-
* true → at least one endpoint ANSWERED
|
|
38
|
-
*
|
|
39
|
-
*
|
|
37
|
+
* true → at least one endpoint ANSWERED. Any HTTP status counts, because the
|
|
38
|
+
* question is liveness, not correctness: probing a path that 404s still returns
|
|
39
|
+
* true, while a closed port returns false. Both confirmed against a live server.
|
|
40
|
+
* An empty list is true — nothing to probe means never kill.
|
|
41
|
+
*
|
|
42
|
+
* `models` is joined RELATIVELY here, and deliberately: it lives under the
|
|
43
|
+
* OpenAI-compatible prefix a baseUrl already carries. Contrast `/props` below.
|
|
40
44
|
*/
|
|
41
45
|
export async function probeModelEndpoints(urls, timeoutMs = 5_000) {
|
|
42
46
|
if (urls.length === 0)
|
|
@@ -59,14 +63,22 @@ export async function probeModelEndpoints(urls, timeoutMs = 5_000) {
|
|
|
59
63
|
* answer worth having" — not a llama.cpp server, unreachable, or a body in a
|
|
60
64
|
* shape this does not recognise.
|
|
61
65
|
*
|
|
62
|
-
* `null` is a first-class result, not an error:
|
|
63
|
-
* returns it, and the caller must degrade to the models.json view
|
|
64
|
-
* warn about a server it could not read. Never throws
|
|
66
|
+
* `null` is a first-class result, not an error: a backend that does not serve
|
|
67
|
+
* this shape returns it, and the caller must degrade to the models.json view
|
|
68
|
+
* rather than warn about a server it could not read. Never throws — a closed
|
|
69
|
+
* port answers `null`, confirmed.
|
|
70
|
+
*
|
|
71
|
+
* The LEADING SLASH in `/props` is load-bearing, because `/props` lives at the
|
|
72
|
+
* server ROOT while a configured baseUrl carries an OpenAI-compatible prefix.
|
|
73
|
+
* How a relative `'props'` resolves depends on whether that prefix ends in a
|
|
74
|
+
* slash, which is not something this can rely on:
|
|
75
|
+
*
|
|
76
|
+
* new URL('props', 'http://host/v1') → /props
|
|
77
|
+
* new URL('props', 'http://host/v1/') → /v1/props ← 404
|
|
78
|
+
* new URL('/props', either) → /props
|
|
65
79
|
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
* the server root, so a relative `'props'` would resolve to `/v1/props` and 404 —
|
|
69
|
-
* which this would report as `null`, i.e. as a silent loss of the better signal.
|
|
80
|
+
* A 404 would come back from here as `null`, silently losing the better signal.
|
|
81
|
+
* The absolute form is right for both.
|
|
70
82
|
*/
|
|
71
83
|
export async function probeChatTemplateCaps(baseUrl, timeoutMs = 2_000) {
|
|
72
84
|
try {
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
/** Pick the right way to re-invoke pi: prefer the current pi script under the
|
|
2
|
-
* current node/bun runtime; fall back to the `pi` shim on PATH.
|
|
3
|
-
*
|
|
2
|
+
* current node/bun runtime; fall back to the `pi` shim on PATH. This mirrors
|
|
3
|
+
* pi's own subagent example, which ships a function of the same name and the
|
|
4
|
+
* same three-step shape in `examples/extensions/subagent/index.ts`. What is
|
|
5
|
+
* added here is the `PI_BIN` override, the `/$bunfs/root/` guard, and `stdin`.
|
|
4
6
|
*
|
|
5
7
|
* `stdin`, when given, is the prompt to feed the child over stdin instead of as
|
|
6
8
|
* an argv element — pi reads its prompt from stdin when no positional message
|
|
7
|
-
* is passed, which keeps a large prompt off the
|
|
8
|
-
*
|
|
9
|
+
* is passed, which keeps a large prompt off the argv ceiling that would
|
|
10
|
+
* otherwise fail the spawn outright (see runChild). It is threaded through
|
|
11
|
+
* unchanged: every branch below returns it as given. */
|
|
9
12
|
export declare function getPiInvocation(args: string[], stdin?: string): {
|
|
10
13
|
command: string;
|
|
11
14
|
args: string[];
|
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
import * as fs from 'node:fs';
|
|
2
2
|
import * as path from 'node:path';
|
|
3
3
|
/** Pick the right way to re-invoke pi: prefer the current pi script under the
|
|
4
|
-
* current node/bun runtime; fall back to the `pi` shim on PATH.
|
|
5
|
-
*
|
|
4
|
+
* current node/bun runtime; fall back to the `pi` shim on PATH. This mirrors
|
|
5
|
+
* pi's own subagent example, which ships a function of the same name and the
|
|
6
|
+
* same three-step shape in `examples/extensions/subagent/index.ts`. What is
|
|
7
|
+
* added here is the `PI_BIN` override, the `/$bunfs/root/` guard, and `stdin`.
|
|
6
8
|
*
|
|
7
9
|
* `stdin`, when given, is the prompt to feed the child over stdin instead of as
|
|
8
10
|
* an argv element — pi reads its prompt from stdin when no positional message
|
|
9
|
-
* is passed, which keeps a large prompt off the
|
|
10
|
-
*
|
|
11
|
+
* is passed, which keeps a large prompt off the argv ceiling that would
|
|
12
|
+
* otherwise fail the spawn outright (see runChild). It is threaded through
|
|
13
|
+
* unchanged: every branch below returns it as given. */
|
|
11
14
|
export function getPiInvocation(args, stdin) {
|
|
12
|
-
// Test/dev override: point at a specific pi binary directly.
|
|
13
|
-
// re-invoke-current-script heuristic, which goes wrong under
|
|
14
|
-
//
|
|
15
|
+
// Test/dev override: point at a specific pi binary directly. It bypasses the
|
|
16
|
+
// re-invoke-current-script heuristic below, which goes wrong under the test
|
|
17
|
+
// runner — confirmed by printing it from inside a test, where `process.argv[1]`
|
|
18
|
+
// is the `.test.ts` file itself. Without this the child would be the runtime
|
|
19
|
+
// re-running a test file, not pi.
|
|
15
20
|
if (process.env.PI_BIN) {
|
|
16
21
|
return { command: process.env.PI_BIN, args, stdin };
|
|
17
22
|
}
|
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The installed pi-task version, read from package.json
|
|
3
|
-
* has to
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
2
|
+
* The installed pi-task version, read from package.json on every call so no
|
|
3
|
+
* build step has to bake it in and nothing needs regenerating on release.
|
|
4
|
+
*
|
|
5
|
+
* Two levels up is right for BOTH trees: `src/<dir>/../..` and `dist/<dir>/../..`
|
|
6
|
+
* each land on the package root, because tsconfig.build.json sets
|
|
7
|
+
* `rootDir: "src"` and tsc therefore reproduces the directory layout under dist.
|
|
8
|
+
* Called from each, both answer the version package.json declares.
|
|
9
|
+
*
|
|
10
|
+
* There are two ways to reach the '0.0.0' fallback and neither throws: an absent
|
|
11
|
+
* or unreadable package.json is caught, and a `version` that is not a string
|
|
12
|
+
* fails the typeof guard. Both were run. Throwing would be wrong for what the
|
|
13
|
+
* two callers do with it — one builds a fetch User-Agent, the other the title on
|
|
14
|
+
* the /task-config settings box. Neither is worth failing a session over.
|
|
7
15
|
*/
|
|
8
16
|
export declare function readPkgVersion(): string;
|
|
@@ -2,11 +2,19 @@ import { readFileSync } from 'node:fs';
|
|
|
2
2
|
import { dirname, join } from 'node:path';
|
|
3
3
|
import { fileURLToPath } from 'node:url';
|
|
4
4
|
/**
|
|
5
|
-
* The installed pi-task version, read from package.json
|
|
6
|
-
* has to
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
5
|
+
* The installed pi-task version, read from package.json on every call so no
|
|
6
|
+
* build step has to bake it in and nothing needs regenerating on release.
|
|
7
|
+
*
|
|
8
|
+
* Two levels up is right for BOTH trees: `src/<dir>/../..` and `dist/<dir>/../..`
|
|
9
|
+
* each land on the package root, because tsconfig.build.json sets
|
|
10
|
+
* `rootDir: "src"` and tsc therefore reproduces the directory layout under dist.
|
|
11
|
+
* Called from each, both answer the version package.json declares.
|
|
12
|
+
*
|
|
13
|
+
* There are two ways to reach the '0.0.0' fallback and neither throws: an absent
|
|
14
|
+
* or unreadable package.json is caught, and a `version` that is not a string
|
|
15
|
+
* fails the typeof guard. Both were run. Throwing would be wrong for what the
|
|
16
|
+
* two callers do with it — one builds a fetch User-Agent, the other the title on
|
|
17
|
+
* the /task-config settings box. Neither is worth failing a session over.
|
|
10
18
|
*/
|
|
11
19
|
export function readPkgVersion() {
|
|
12
20
|
try {
|
|
@@ -3,31 +3,38 @@
|
|
|
3
3
|
*
|
|
4
4
|
* WHY A LOCAL COPY OF PI'S CLAMP
|
|
5
5
|
* ------------------------------
|
|
6
|
-
* pi
|
|
7
|
-
*
|
|
6
|
+
* pi does not report that it ignored or downgraded a level. Captured on the wire,
|
|
7
|
+
* with a logging proxy between pi and the model server. All three runs completed
|
|
8
|
+
* normally and printed no warning of any kind:
|
|
8
9
|
*
|
|
9
10
|
* 1. a model with `reasoning: false` + `--thinking medium`
|
|
10
|
-
* → the body carries NO reasoning field
|
|
11
|
-
*
|
|
12
|
-
*
|
|
11
|
+
* → the request body carries NO reasoning field and no
|
|
12
|
+
* `chat_template_kwargs`. The level is erased, not refused.
|
|
13
|
+
* 2. `thinkingLevelMap: {off: null, …}` + `--thinking off`
|
|
14
|
+
* → thinking STAYS ON: the body arrives with
|
|
15
|
+
* `chat_template_kwargs.enable_thinking: true`. The clamp walks UP one
|
|
16
|
+
* rung at a time, so `off` lands on `minimal` — not on `medium`.
|
|
13
17
|
* 3. `--thinking low` where `low: null`
|
|
14
|
-
* →
|
|
18
|
+
* → `medium` on the wire.
|
|
15
19
|
*
|
|
16
20
|
* All three are the same arithmetic, and it is pure: `getSupportedThinkingLevels`
|
|
17
|
-
* / `clampThinkingLevel` in @earendil-works/pi-ai's models
|
|
21
|
+
* / `clampThinkingLevel` in @earendil-works/pi-ai's `models.js`. Reproducing it
|
|
18
22
|
* lets one predicate — `clampToModel(m, wanted) !== wanted` — catch all three
|
|
19
23
|
* host-side, before a single request is sent.
|
|
20
24
|
*
|
|
21
25
|
* Reimplemented rather than imported because `@earendil-works/pi-ai` is neither a
|
|
22
|
-
* dependency nor a peerDependency of pi-task
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
+
* dependency, a devDependency nor a peerDependency of pi-task — it is in none of
|
|
27
|
+
* the three, and sits in node_modules only because pi-coding-agent depends on it.
|
|
28
|
+
* Importing it would take a hard dependency on a transitive package for twenty
|
|
29
|
+
* lines of arithmetic. SOURCE OF TRUTH is that module, and what follows is
|
|
30
|
+
* line-for-line identical to it, ladder included. Nothing here imports pi-ai, so
|
|
31
|
+
* an upstream change will not fail a test — the two have to be re-compared.
|
|
26
32
|
*/
|
|
27
33
|
import { type ReasoningGroup, type GroupSetting } from '../config/reasoning.js';
|
|
28
34
|
/**
|
|
29
|
-
* pi's own level ladder, in order
|
|
30
|
-
*
|
|
35
|
+
* pi's own level ladder, in order — the same seven names, in the same sequence,
|
|
36
|
+
* as `EXTENDED_THINKING_LEVELS` in pi-ai's models.js. The order IS the algorithm:
|
|
37
|
+
* an unsupported level is resolved by walking UP first, then down.
|
|
31
38
|
*/
|
|
32
39
|
export declare const THINKING_LADDER: readonly ["off", "minimal", "low", "medium", "high", "xhigh", "max"];
|
|
33
40
|
export type LadderLevel = (typeof THINKING_LADDER)[number];
|
|
@@ -48,9 +55,11 @@ export interface ReasoningModelFacts {
|
|
|
48
55
|
* 1: the knob is not rejected, it is erased.
|
|
49
56
|
* - a MISSING map entry means "supported" for the standard levels but
|
|
50
57
|
* "unsupported" for `xhigh` / `max`, which are opt-in and must be declared.
|
|
51
|
-
* This is why config/reasoning.ts
|
|
52
|
-
*
|
|
53
|
-
*
|
|
58
|
+
* This is why config/reasoning.ts offers neither: without a map the raw
|
|
59
|
+
* string reaches the server, and a chat template that does not know the level
|
|
60
|
+
* fails rather than clamping. Confirmed against a live server — an effort
|
|
61
|
+
* string its template does not handle comes back HTTP 500, raised from inside
|
|
62
|
+
* the template itself, while one it does handle returns 200.
|
|
54
63
|
*/
|
|
55
64
|
export declare function supportedThinkingLevels(model: ReasoningModelFacts): LadderLevel[];
|
|
56
65
|
/**
|
|
@@ -69,15 +78,17 @@ export interface ReasoningMismatch {
|
|
|
69
78
|
/**
|
|
70
79
|
* Every group whose setting the model will silently change.
|
|
71
80
|
*
|
|
72
|
-
* `inherit` groups are skipped entirely,
|
|
73
|
-
*
|
|
74
|
-
*
|
|
81
|
+
* `inherit` groups are skipped entirely, because an inherited group asks for
|
|
82
|
+
* nothing. That is not the same as a quiet default: the shipped table is mostly
|
|
83
|
+
* DECIDED, with a single cell left on `inherit`, so a default install is not
|
|
84
|
+
* silent. Run against a `reasoning: false` model it reports a mismatch for every
|
|
85
|
+
* group whose level that model cannot honour.
|
|
75
86
|
*
|
|
76
87
|
* It reports mismatches in BOTH directions, which is wider than "warn when
|
|
77
|
-
* reasoning is on but unsupported". The
|
|
78
|
-
*
|
|
79
|
-
* turned thinking off still pays for it — and it is the same
|
|
80
|
-
* about one direction while staying silent about the other
|
|
81
|
-
* feature
|
|
88
|
+
* reasoning is on but unsupported". The mirror case is the one captured on the
|
|
89
|
+
* wire — `off` clamped UP with `enable_thinking: true` still going out, so a
|
|
90
|
+
* user who turned thinking off still pays for it — and it is the same
|
|
91
|
+
* comparison. Warning about one direction while staying silent about the other
|
|
92
|
+
* would ship this feature unable to see its own failure mode.
|
|
82
93
|
*/
|
|
83
94
|
export declare function reasoningMismatches(model: ReasoningModelFacts | undefined, levels: Readonly<Record<ReasoningGroup, GroupSetting>>): ReasoningMismatch[];
|
|
@@ -3,31 +3,38 @@
|
|
|
3
3
|
*
|
|
4
4
|
* WHY A LOCAL COPY OF PI'S CLAMP
|
|
5
5
|
* ------------------------------
|
|
6
|
-
* pi
|
|
7
|
-
*
|
|
6
|
+
* pi does not report that it ignored or downgraded a level. Captured on the wire,
|
|
7
|
+
* with a logging proxy between pi and the model server. All three runs completed
|
|
8
|
+
* normally and printed no warning of any kind:
|
|
8
9
|
*
|
|
9
10
|
* 1. a model with `reasoning: false` + `--thinking medium`
|
|
10
|
-
* → the body carries NO reasoning field
|
|
11
|
-
*
|
|
12
|
-
*
|
|
11
|
+
* → the request body carries NO reasoning field and no
|
|
12
|
+
* `chat_template_kwargs`. The level is erased, not refused.
|
|
13
|
+
* 2. `thinkingLevelMap: {off: null, …}` + `--thinking off`
|
|
14
|
+
* → thinking STAYS ON: the body arrives with
|
|
15
|
+
* `chat_template_kwargs.enable_thinking: true`. The clamp walks UP one
|
|
16
|
+
* rung at a time, so `off` lands on `minimal` — not on `medium`.
|
|
13
17
|
* 3. `--thinking low` where `low: null`
|
|
14
|
-
* →
|
|
18
|
+
* → `medium` on the wire.
|
|
15
19
|
*
|
|
16
20
|
* All three are the same arithmetic, and it is pure: `getSupportedThinkingLevels`
|
|
17
|
-
* / `clampThinkingLevel` in @earendil-works/pi-ai's models
|
|
21
|
+
* / `clampThinkingLevel` in @earendil-works/pi-ai's `models.js`. Reproducing it
|
|
18
22
|
* lets one predicate — `clampToModel(m, wanted) !== wanted` — catch all three
|
|
19
23
|
* host-side, before a single request is sent.
|
|
20
24
|
*
|
|
21
25
|
* Reimplemented rather than imported because `@earendil-works/pi-ai` is neither a
|
|
22
|
-
* dependency nor a peerDependency of pi-task
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
+
* dependency, a devDependency nor a peerDependency of pi-task — it is in none of
|
|
27
|
+
* the three, and sits in node_modules only because pi-coding-agent depends on it.
|
|
28
|
+
* Importing it would take a hard dependency on a transitive package for twenty
|
|
29
|
+
* lines of arithmetic. SOURCE OF TRUTH is that module, and what follows is
|
|
30
|
+
* line-for-line identical to it, ladder included. Nothing here imports pi-ai, so
|
|
31
|
+
* an upstream change will not fail a test — the two have to be re-compared.
|
|
26
32
|
*/
|
|
27
33
|
import { REASONING_GROUPS } from '../config/reasoning.js';
|
|
28
34
|
/**
|
|
29
|
-
* pi's own level ladder, in order
|
|
30
|
-
*
|
|
35
|
+
* pi's own level ladder, in order — the same seven names, in the same sequence,
|
|
36
|
+
* as `EXTENDED_THINKING_LEVELS` in pi-ai's models.js. The order IS the algorithm:
|
|
37
|
+
* an unsupported level is resolved by walking UP first, then down.
|
|
31
38
|
*/
|
|
32
39
|
export const THINKING_LADDER = ['off', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max'];
|
|
33
40
|
/**
|
|
@@ -38,9 +45,11 @@ export const THINKING_LADDER = ['off', 'minimal', 'low', 'medium', 'high', 'xhig
|
|
|
38
45
|
* 1: the knob is not rejected, it is erased.
|
|
39
46
|
* - a MISSING map entry means "supported" for the standard levels but
|
|
40
47
|
* "unsupported" for `xhigh` / `max`, which are opt-in and must be declared.
|
|
41
|
-
* This is why config/reasoning.ts
|
|
42
|
-
*
|
|
43
|
-
*
|
|
48
|
+
* This is why config/reasoning.ts offers neither: without a map the raw
|
|
49
|
+
* string reaches the server, and a chat template that does not know the level
|
|
50
|
+
* fails rather than clamping. Confirmed against a live server — an effort
|
|
51
|
+
* string its template does not handle comes back HTTP 500, raised from inside
|
|
52
|
+
* the template itself, while one it does handle returns 200.
|
|
44
53
|
*/
|
|
45
54
|
export function supportedThinkingLevels(model) {
|
|
46
55
|
if (!model.reasoning)
|
|
@@ -80,16 +89,18 @@ export function clampToModel(model, level) {
|
|
|
80
89
|
/**
|
|
81
90
|
* Every group whose setting the model will silently change.
|
|
82
91
|
*
|
|
83
|
-
* `inherit` groups are skipped entirely,
|
|
84
|
-
*
|
|
85
|
-
*
|
|
92
|
+
* `inherit` groups are skipped entirely, because an inherited group asks for
|
|
93
|
+
* nothing. That is not the same as a quiet default: the shipped table is mostly
|
|
94
|
+
* DECIDED, with a single cell left on `inherit`, so a default install is not
|
|
95
|
+
* silent. Run against a `reasoning: false` model it reports a mismatch for every
|
|
96
|
+
* group whose level that model cannot honour.
|
|
86
97
|
*
|
|
87
98
|
* It reports mismatches in BOTH directions, which is wider than "warn when
|
|
88
|
-
* reasoning is on but unsupported". The
|
|
89
|
-
*
|
|
90
|
-
* turned thinking off still pays for it — and it is the same
|
|
91
|
-
* about one direction while staying silent about the other
|
|
92
|
-
* feature
|
|
99
|
+
* reasoning is on but unsupported". The mirror case is the one captured on the
|
|
100
|
+
* wire — `off` clamped UP with `enable_thinking: true` still going out, so a
|
|
101
|
+
* user who turned thinking off still pays for it — and it is the same
|
|
102
|
+
* comparison. Warning about one direction while staying silent about the other
|
|
103
|
+
* would ship this feature unable to see its own failure mode.
|
|
93
104
|
*/
|
|
94
105
|
export function reasoningMismatches(model, levels) {
|
|
95
106
|
// No model resolved yet (session still starting, or none selected): say
|
|
@@ -2,25 +2,30 @@
|
|
|
2
2
|
* Model-stream watchdog — the inactivity machine for a stream that goes SILENT
|
|
3
3
|
* without erroring.
|
|
4
4
|
*
|
|
5
|
-
* WHY
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* - the connection-error retry
|
|
10
|
-
*
|
|
11
|
-
* - the command watchdog never fires: it
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
5
|
+
* WHY: a turn can die mid-stream — the last thing recorded is an ordinary
|
|
6
|
+
* assistant message, then nothing, while the model server stays healthy. A hung
|
|
7
|
+
* or silently-dropped stream throws NOTHING, so none of the three guards that
|
|
8
|
+
* already exist can see it:
|
|
9
|
+
* - the connection-error retry never fires. child-runner reaches it only
|
|
10
|
+
* inside `if (r.modelError)`, and a silent hang reports no error at all.
|
|
11
|
+
* - the command watchdog never fires: it arms per tool call and covers only
|
|
12
|
+
* TOOL executions.
|
|
13
|
+
* - the child stall guard never fires: it kills only when a probe finds the
|
|
14
|
+
* endpoint UNREACHABLE, and here the endpoint answers fine. The stream is
|
|
15
|
+
* what died, not the server.
|
|
15
16
|
*
|
|
16
|
-
* WHAT THIS MEASURES: time since the
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
17
|
+
* WHAT THIS MEASURES: time since the last sign of life, NOT wall-clock and NOT
|
|
18
|
+
* time-to-first-token. What counts as a sign differs by surface — for the main
|
|
19
|
+
* session it is any of six pi events (`before_provider_request`,
|
|
20
|
+
* `after_provider_response`, `turn_start`, `message_start`, `message_update`,
|
|
21
|
+
* `message_end`), with every text, thinking and tool-call delta arriving as
|
|
22
|
+
* `message_update`; for a child it is any stdout or stderr CHUNK. A slow model
|
|
23
|
+
* that emits something occasionally is working and must never be killed. Zero
|
|
24
|
+
* for the whole window is a hang.
|
|
20
25
|
*
|
|
21
|
-
* WHY THE DEFAULT IS GENEROUS:
|
|
22
|
-
*
|
|
23
|
-
*
|
|
26
|
+
* WHY THE DEFAULT IS GENEROUS: prompt processing legitimately emits nothing
|
|
27
|
+
* while it runs, so a tight ceiling would kill honest long prompts. This guard
|
|
28
|
+
* exists to bound dead air, not to police slowness. See
|
|
24
29
|
* DEFAULT_STREAM_INACTIVITY_MS.
|
|
25
30
|
*
|
|
26
31
|
* TWO SURFACES, one machine (same split as command-watchdog.ts):
|
|
@@ -38,15 +43,19 @@
|
|
|
38
43
|
import type { TimerHandle } from './command-watchdog.js';
|
|
39
44
|
export type { TimerHandle };
|
|
40
45
|
/**
|
|
41
|
-
* Default inactivity ceiling
|
|
42
|
-
*
|
|
43
|
-
*
|
|
46
|
+
* Default inactivity ceiling. Sized by the constraint that a local model's first
|
|
47
|
+
* token can legitimately be a long way off, so the number has to clear honest
|
|
48
|
+
* prompt processing rather than sit close to it.
|
|
44
49
|
*/
|
|
45
50
|
export declare const DEFAULT_STREAM_INACTIVITY_MS: number;
|
|
46
51
|
/**
|
|
47
|
-
* How often the machine checks the idle clock. A poll
|
|
48
|
-
* timeout on every token
|
|
49
|
-
*
|
|
52
|
+
* How often the machine checks the idle clock. A poll, rather than re-arming a
|
|
53
|
+
* timeout on every token, keeps the cost per window constant instead of per
|
|
54
|
+
* event — and "thousands of events" is not a figure of speech: one captured turn
|
|
55
|
+
* emitted over two thousand, nearly all of them `message_update`.
|
|
56
|
+
*
|
|
57
|
+
* A quarter of the window, clamped: never tighter than 50ms, never looser than
|
|
58
|
+
* 30s. The child stall guard polls with the same shape and its own divisor.
|
|
50
59
|
*/
|
|
51
60
|
export declare function pollIntervalMs(timeoutMs: number): number;
|
|
52
61
|
export interface StreamWatchdogDeps {
|
|
@@ -69,12 +78,14 @@ export declare class StreamWatchdog {
|
|
|
69
78
|
* legitimately idle, and that window belongs to the command watchdog, not to
|
|
70
79
|
* this one — without it a 10-minute build looks identical to a hung stream.
|
|
71
80
|
*
|
|
72
|
-
* A SET, not a boolean
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
81
|
+
* A SET, not a boolean, and pi's own loop is why. `executeToolCallsParallel`
|
|
82
|
+
* in agent-loop.js emits EVERY `tool_execution_start` up front, before any
|
|
83
|
+
* call is prepared; a call that prepares "immediate" gets its end emitted
|
|
84
|
+
* inline right there, while the rest are deferred as closures and settle
|
|
85
|
+
* through a `Promise.all`. So an end can arrive while earlier siblings are
|
|
86
|
+
* still running. A boolean would be cleared by that first end and leave the
|
|
87
|
+
* long build exposed to a false fire. Same per-toolCallId idiom the command
|
|
88
|
+
* watchdog uses.
|
|
78
89
|
*/
|
|
79
90
|
private readonly active;
|
|
80
91
|
/** Nesting depth for callers that cannot supply an id, counted so an unkeyed
|
|
@@ -107,27 +118,32 @@ export declare class StreamWatchdog {
|
|
|
107
118
|
* cancels it on stop/fire, and runChild's cleanup() stops the watchdog on every
|
|
108
119
|
* settle path (close, error, abort), so it cannot outlive the child it watches.
|
|
109
120
|
*
|
|
110
|
-
* The poll is REF'd, deliberately.
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
121
|
+
* The poll is REF'd, deliberately. Unref'd reads better — a pending watchdog poll
|
|
122
|
+
* should never keep the process alive at exit — but an unref'd timer is only
|
|
123
|
+
* guaranteed to fire while something ref'd is still pending, and that guarantee
|
|
124
|
+
* is not the platform-independent thing it looks like.
|
|
125
|
+
*
|
|
126
|
+
* Measured here, on both runtimes: with nothing else pending an unref'd timer
|
|
127
|
+
* never fires at all, the process just exits; with a spawned child holding its
|
|
128
|
+
* stdout and stderr pipes open it fires on schedule throughout. A silent child
|
|
129
|
+
* is the SECOND case — its pipes are still ref'd work — so on this platform the
|
|
130
|
+
* unref would not have broken the child guard. The reason to keep it ref'd is
|
|
131
|
+
* that this machine also runs in the main session, where no such handle is
|
|
132
|
+
* guaranteed, and the failure mode is silent: a watchdog that never fires looks
|
|
133
|
+
* exactly like a stream that never hung.
|
|
116
134
|
*
|
|
117
|
-
* That state — no ref'd work outstanding — is EXACTLY the state this watchdog
|
|
118
|
-
* exists to police: a child whose model stream has gone silent. So the unref
|
|
119
|
-
* disabled the guard precisely when it was needed, and every stream-stall
|
|
120
|
-
* integration test hung forever on windows (CI runs 30476786365, 30477802633,
|
|
121
|
-
* 30478455402 — it hangs at v0.24.1 too, so this predates that release).
|
|
122
135
|
* A poll that can delay exit by one interval is the cheaper failure.
|
|
123
136
|
*/
|
|
124
137
|
export declare const realStreamTimerDeps: Pick<StreamWatchdogDeps, 'now' | 'schedule' | 'cancel'>;
|
|
125
138
|
/**
|
|
126
139
|
* The cause string a CHILD's stream stall is reported as. Phrased so
|
|
127
|
-
* {@link isConnectionError} (child-runner.ts) matches it —
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
140
|
+
* {@link isConnectionError} (child-runner.ts) matches it — checked by running the
|
|
141
|
+
* round-trip, and it does. The whole point is to route a silent hang into the
|
|
142
|
+
* retry path that already exists for a LOUD connection failure rather than
|
|
143
|
+
* inventing a second one, so the phrase "connection lost" is load-bearing, not
|
|
144
|
+
* decoration: reword it past that predicate and stream stalls stop retrying.
|
|
145
|
+
* Honest about who killed it, too — pi-task aborted the request, the provider
|
|
146
|
+
* reported nothing.
|
|
131
147
|
*/
|
|
132
148
|
export declare function streamStallCause(idleMs: number): string;
|
|
133
149
|
/**
|