@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,33 +1,33 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* git-runner — the
|
|
3
|
-
*
|
|
4
|
-
* WHY IT EXISTS. The right shape already existed, privately, inside
|
|
5
|
-
* `task/git-state-guard.ts`: an abort-aware async runner carrying an injectable
|
|
6
|
-
* `spawnFn` seam, returning `{stdout, exitCode}` and never throwing. Nothing
|
|
7
|
-
* outside that file could reach it, so ~27 other sites hand-rolled their own —
|
|
8
|
-
* with FOUR incompatible failure contracts (throws / returns null / returns '' /
|
|
9
|
-
* returns a result object) and THREE different maxBuffer limits. A caller reading
|
|
10
|
-
* one of them learns nothing about the next, and a git failure means something
|
|
11
|
-
* different at every site. Lifting the seam here does not add a capability; it
|
|
12
|
-
* removes the ambiguity about which contract you are holding.
|
|
2
|
+
* git-runner — the shared async way to run `git`, and the one to reach for.
|
|
13
3
|
*
|
|
14
4
|
* THE CONTRACT, deliberately narrow:
|
|
15
|
-
* - NEVER THROWS.
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
5
|
+
* - NEVER THROWS. Every failure arrives as a non-zero `exitCode`, measured
|
|
6
|
+
* rather than assumed: a non-repo cwd answers 128, a bogus subcommand
|
|
7
|
+
* answers 1, `git rev-parse --verify HEAD` on a freshly-init'd repo with an
|
|
8
|
+
* unborn HEAD answers 128, and even a MISSING binary comes back as
|
|
9
|
+
* `{exitCode: 1, aborted: false}` instead of rejecting. Callers branch on
|
|
10
|
+
* the number, they do not wrap in try/catch, and every guard built on this
|
|
11
|
+
* treats "git could not tell me" as "no claim" rather than a crash.
|
|
20
12
|
* - Only `stdout` and `exitCode` are exposed. stderr is deliberately absent:
|
|
21
|
-
* the
|
|
22
|
-
* sniffing) also
|
|
23
|
-
* two fields nobody else reads onto every call site.
|
|
13
|
+
* the caller that legitimately needs it (auto-commit's identity-failure
|
|
14
|
+
* sniffing) also needs `aborted`, and widening this type for it would push
|
|
15
|
+
* two fields nobody else reads onto every call site. That one caller goes
|
|
16
|
+
* to `runChildDefault` directly instead.
|
|
24
17
|
* - `signal` is honoured by the underlying runChild, including its listener
|
|
25
|
-
* detach discipline
|
|
26
|
-
*
|
|
27
|
-
* - `env` entries are MERGED over `process.env
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
18
|
+
* detach discipline — a run-long orchestrator signal does not accumulate
|
|
19
|
+
* one listener per git invocation.
|
|
20
|
+
* - `env` entries are MERGED over `process.env`, not substituted for it, which
|
|
21
|
+
* is what lets git-state-guard point `GIT_INDEX_FILE` at a throwaway index
|
|
22
|
+
* without losing PATH and HOME. Confirmed: such a call still resolves the
|
|
23
|
+
* repo normally.
|
|
24
|
+
* - `spawnFn` is the test seam: pass a fake from `test/test-utils/fake-spawn.ts`
|
|
25
|
+
* and the runner never touches a real repo.
|
|
26
|
+
*
|
|
27
|
+
* It is NOT universal, which matters before assuming any git call arrived here.
|
|
28
|
+
* Several sites still invoke git themselves with `spawnSync`, each carrying its
|
|
29
|
+
* own timeout and one its own maxBuffer, and accept-debt goes through the
|
|
30
|
+
* bounded command runner instead.
|
|
31
31
|
*/
|
|
32
32
|
import { type SpawnFn } from './child-process.js';
|
|
33
33
|
export interface GitRunner {
|
|
@@ -1,33 +1,33 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* git-runner — the
|
|
3
|
-
*
|
|
4
|
-
* WHY IT EXISTS. The right shape already existed, privately, inside
|
|
5
|
-
* `task/git-state-guard.ts`: an abort-aware async runner carrying an injectable
|
|
6
|
-
* `spawnFn` seam, returning `{stdout, exitCode}` and never throwing. Nothing
|
|
7
|
-
* outside that file could reach it, so ~27 other sites hand-rolled their own —
|
|
8
|
-
* with FOUR incompatible failure contracts (throws / returns null / returns '' /
|
|
9
|
-
* returns a result object) and THREE different maxBuffer limits. A caller reading
|
|
10
|
-
* one of them learns nothing about the next, and a git failure means something
|
|
11
|
-
* different at every site. Lifting the seam here does not add a capability; it
|
|
12
|
-
* removes the ambiguity about which contract you are holding.
|
|
2
|
+
* git-runner — the shared async way to run `git`, and the one to reach for.
|
|
13
3
|
*
|
|
14
4
|
* THE CONTRACT, deliberately narrow:
|
|
15
|
-
* - NEVER THROWS.
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
5
|
+
* - NEVER THROWS. Every failure arrives as a non-zero `exitCode`, measured
|
|
6
|
+
* rather than assumed: a non-repo cwd answers 128, a bogus subcommand
|
|
7
|
+
* answers 1, `git rev-parse --verify HEAD` on a freshly-init'd repo with an
|
|
8
|
+
* unborn HEAD answers 128, and even a MISSING binary comes back as
|
|
9
|
+
* `{exitCode: 1, aborted: false}` instead of rejecting. Callers branch on
|
|
10
|
+
* the number, they do not wrap in try/catch, and every guard built on this
|
|
11
|
+
* treats "git could not tell me" as "no claim" rather than a crash.
|
|
20
12
|
* - Only `stdout` and `exitCode` are exposed. stderr is deliberately absent:
|
|
21
|
-
* the
|
|
22
|
-
* sniffing) also
|
|
23
|
-
* two fields nobody else reads onto every call site.
|
|
13
|
+
* the caller that legitimately needs it (auto-commit's identity-failure
|
|
14
|
+
* sniffing) also needs `aborted`, and widening this type for it would push
|
|
15
|
+
* two fields nobody else reads onto every call site. That one caller goes
|
|
16
|
+
* to `runChildDefault` directly instead.
|
|
24
17
|
* - `signal` is honoured by the underlying runChild, including its listener
|
|
25
|
-
* detach discipline
|
|
26
|
-
*
|
|
27
|
-
* - `env` entries are MERGED over `process.env
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
18
|
+
* detach discipline — a run-long orchestrator signal does not accumulate
|
|
19
|
+
* one listener per git invocation.
|
|
20
|
+
* - `env` entries are MERGED over `process.env`, not substituted for it, which
|
|
21
|
+
* is what lets git-state-guard point `GIT_INDEX_FILE` at a throwaway index
|
|
22
|
+
* without losing PATH and HOME. Confirmed: such a call still resolves the
|
|
23
|
+
* repo normally.
|
|
24
|
+
* - `spawnFn` is the test seam: pass a fake from `test/test-utils/fake-spawn.ts`
|
|
25
|
+
* and the runner never touches a real repo.
|
|
26
|
+
*
|
|
27
|
+
* It is NOT universal, which matters before assuming any git call arrived here.
|
|
28
|
+
* Several sites still invoke git themselves with `spawnSync`, each carrying its
|
|
29
|
+
* own timeout and one its own maxBuffer, and accept-debt goes through the
|
|
30
|
+
* bounded command runner instead.
|
|
31
31
|
*/
|
|
32
32
|
import { runChildDefault } from './child-process.js';
|
|
33
33
|
export function makeGit(cwd, signal, spawnFn) {
|
|
@@ -2,10 +2,9 @@
|
|
|
2
2
|
* Detect tool calls that leaked into a child's assistant *text* instead of
|
|
3
3
|
* being executed.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* pi's harness doesn't recognise — e.g.
|
|
5
|
+
* A call only counts when a structured `tool_execution_start` event fires —
|
|
6
|
+
* shared/child-process.ts recognises nothing else. Model-side tool-call markup
|
|
7
|
+
* like
|
|
9
8
|
*
|
|
10
9
|
* <tool_call>
|
|
11
10
|
* <function=bash>
|
|
@@ -13,14 +12,21 @@
|
|
|
13
12
|
* </function>
|
|
14
13
|
* </tool_call>
|
|
15
14
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* the unexecuted call flows downstream — a silently skipped beat.
|
|
15
|
+
* is not a format pi itself parses: those tags appear nowhere in any installed
|
|
16
|
+
* pi package. So whether such a turn RUNS is decided entirely by the inference
|
|
17
|
+
* server in front of it, and both outcomes are real.
|
|
20
18
|
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
19
|
+
* Checked against a live endpoint, the server parsed the dialect itself and
|
|
20
|
+
* handed pi structured tool calls — the markup EXECUTED rather than leaking, and
|
|
21
|
+
* the parse was sloppy enough to fold the closing tags and the surrounding prose
|
|
22
|
+
* into the command argument. A server that does not parse it produces the case
|
|
23
|
+
* this module exists for: pi receives the markup as ordinary assistant text, the
|
|
24
|
+
* command never runs, no event fires, and pi-task's guards never see it. The
|
|
25
|
+
* turn then clears its only acceptance gates — non-empty assistant text and exit
|
|
26
|
+
* 0 — and the unexecuted call flows downstream as a silently skipped beat.
|
|
27
|
+
*
|
|
28
|
+
* pi-task cannot fix the mismatch. What it CAN do is notice the markup in the
|
|
29
|
+
* answer and refuse the turn, so the skip becomes visible instead of silent.
|
|
24
30
|
*/
|
|
25
31
|
export declare const MAX_LEAK_RETRIES = 2;
|
|
26
32
|
/**
|
|
@@ -2,10 +2,9 @@
|
|
|
2
2
|
* Detect tool calls that leaked into a child's assistant *text* instead of
|
|
3
3
|
* being executed.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* pi's harness doesn't recognise — e.g.
|
|
5
|
+
* A call only counts when a structured `tool_execution_start` event fires —
|
|
6
|
+
* shared/child-process.ts recognises nothing else. Model-side tool-call markup
|
|
7
|
+
* like
|
|
9
8
|
*
|
|
10
9
|
* <tool_call>
|
|
11
10
|
* <function=bash>
|
|
@@ -13,25 +12,34 @@
|
|
|
13
12
|
* </function>
|
|
14
13
|
* </tool_call>
|
|
15
14
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* the unexecuted call flows downstream — a silently skipped beat.
|
|
15
|
+
* is not a format pi itself parses: those tags appear nowhere in any installed
|
|
16
|
+
* pi package. So whether such a turn RUNS is decided entirely by the inference
|
|
17
|
+
* server in front of it, and both outcomes are real.
|
|
20
18
|
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
19
|
+
* Checked against a live endpoint, the server parsed the dialect itself and
|
|
20
|
+
* handed pi structured tool calls — the markup EXECUTED rather than leaking, and
|
|
21
|
+
* the parse was sloppy enough to fold the closing tags and the surrounding prose
|
|
22
|
+
* into the command argument. A server that does not parse it produces the case
|
|
23
|
+
* this module exists for: pi receives the markup as ordinary assistant text, the
|
|
24
|
+
* command never runs, no event fires, and pi-task's guards never see it. The
|
|
25
|
+
* turn then clears its only acceptance gates — non-empty assistant text and exit
|
|
26
|
+
* 0 — and the unexecuted call flows downstream as a silently skipped beat.
|
|
27
|
+
*
|
|
28
|
+
* pi-task cannot fix the mismatch. What it CAN do is notice the markup in the
|
|
29
|
+
* answer and refuse the turn, so the skip becomes visible instead of silent.
|
|
24
30
|
*/
|
|
25
31
|
// A child that wrote a tool call as plain text (wrong dialect, never executed)
|
|
26
32
|
// gets re-prompted with a correction hint up to this many times before the
|
|
27
33
|
// caller gives up. Mirrors MAX_LOOP_RESTARTS: 3 attempts total.
|
|
28
34
|
export const MAX_LEAK_RETRIES = 2;
|
|
29
|
-
// The Hermes-style wrapper
|
|
30
|
-
//
|
|
35
|
+
// The Hermes-style wrapper. Nothing else in this codebase emits the tag — its
|
|
36
|
+
// only other appearance is the correction hint below, which names it back to the
|
|
37
|
+
// model — so seeing it in an answer is signal enough on its own.
|
|
31
38
|
const TOOL_CALL_WRAPPER = /<tool_call\b[^>]*>/i;
|
|
32
39
|
// The "XML function call" dialect: <function=name> … <parameter=key>. Either tag
|
|
33
|
-
// alone is too weak
|
|
34
|
-
//
|
|
40
|
+
// alone is too weak — one can appear in prose or in source — so the structural
|
|
41
|
+
// PAIR is required. Confirmed: a lone <function=bash> and a lone
|
|
42
|
+
// <parameter=command> each return null, and only the two together flag.
|
|
35
43
|
const FUNCTION_TAG = /<function=[\w.-]+\s*>/i;
|
|
36
44
|
const PARAMETER_TAG = /<parameter=[\w.-]+\s*>/i;
|
|
37
45
|
/**
|
|
@@ -1,21 +1,26 @@
|
|
|
1
1
|
/** Base URLs of every custom provider pi is configured with (possibly none). */
|
|
2
2
|
export declare function discoverModelEndpoints(agentDir?: string): string[];
|
|
3
3
|
/**
|
|
4
|
-
* true → at least one endpoint ANSWERED
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* true → at least one endpoint ANSWERED. Any HTTP status counts, because the
|
|
5
|
+
* question is liveness, not correctness: probing a path that 404s still returns
|
|
6
|
+
* true, while a closed port returns false. Both confirmed against a live server.
|
|
7
|
+
* An empty list is true — nothing to probe means never kill.
|
|
8
|
+
*
|
|
9
|
+
* `models` is joined RELATIVELY here, and deliberately: it lives under the
|
|
10
|
+
* OpenAI-compatible prefix a baseUrl already carries. Contrast `/props` below.
|
|
7
11
|
*/
|
|
8
12
|
export declare function probeModelEndpoints(urls: string[], timeoutMs?: number): Promise<boolean>;
|
|
9
13
|
/**
|
|
10
14
|
* What a llama.cpp server's own chat template can actually do about reasoning,
|
|
11
15
|
* as reported by `GET /props`.
|
|
12
16
|
*
|
|
13
|
-
* This is the only source of truth that does NOT come from models.json
|
|
14
|
-
* answers the
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
17
|
+
* This is the only source of truth that does NOT come from models.json, and it
|
|
18
|
+
* answers the question the host-side clamp cannot: is models.json lying about
|
|
19
|
+
* the server? The case that matters is pi's built-in llama.cpp provider, which
|
|
20
|
+
* really does hardcode `reasoning: false` — the literal line is in
|
|
21
|
+
* `extensions/llama/provider.js`, under `LLAMA_PROVIDER_ID = "llama.cpp"`. So
|
|
22
|
+
* anyone who reached their server through `/login llama.cpp` rather than a
|
|
23
|
+
* hand-written provider entry has a dead knob and nothing to tell them so.
|
|
19
24
|
*/
|
|
20
25
|
export interface ChatTemplateCaps {
|
|
21
26
|
/** The template reads `reasoning_effort` — i.e. levels, not just on/off. */
|
|
@@ -30,13 +35,21 @@ export interface ChatTemplateCaps {
|
|
|
30
35
|
* answer worth having" — not a llama.cpp server, unreachable, or a body in a
|
|
31
36
|
* shape this does not recognise.
|
|
32
37
|
*
|
|
33
|
-
* `null` is a first-class result, not an error:
|
|
34
|
-
* returns it, and the caller must degrade to the models.json view
|
|
35
|
-
* warn about a server it could not read. Never throws
|
|
38
|
+
* `null` is a first-class result, not an error: a backend that does not serve
|
|
39
|
+
* this shape returns it, and the caller must degrade to the models.json view
|
|
40
|
+
* rather than warn about a server it could not read. Never throws — a closed
|
|
41
|
+
* port answers `null`, confirmed.
|
|
42
|
+
*
|
|
43
|
+
* The LEADING SLASH in `/props` is load-bearing, because `/props` lives at the
|
|
44
|
+
* server ROOT while a configured baseUrl carries an OpenAI-compatible prefix.
|
|
45
|
+
* How a relative `'props'` resolves depends on whether that prefix ends in a
|
|
46
|
+
* slash, which is not something this can rely on:
|
|
47
|
+
*
|
|
48
|
+
* new URL('props', 'http://host/v1') → /props
|
|
49
|
+
* new URL('props', 'http://host/v1/') → /v1/props ← 404
|
|
50
|
+
* new URL('/props', either) → /props
|
|
36
51
|
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* the server root, so a relative `'props'` would resolve to `/v1/props` and 404 —
|
|
40
|
-
* which this would report as `null`, i.e. as a silent loss of the better signal.
|
|
52
|
+
* A 404 would come back from here as `null`, silently losing the better signal.
|
|
53
|
+
* The absolute form is right for both.
|
|
41
54
|
*/
|
|
42
55
|
export declare function probeChatTemplateCaps(baseUrl: string, timeoutMs?: number): Promise<ChatTemplateCaps | null>;
|
|
@@ -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[];
|