@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,22 +2,22 @@
|
|
|
2
2
|
* One-line startup hint shown when /task-config asks for a thinking level the
|
|
3
3
|
* connected model will not honour.
|
|
4
4
|
*
|
|
5
|
-
* WHY IT HAS TO EXIST. pi
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
5
|
+
* WHY IT HAS TO EXIST. pi silently rewrites the level and says nothing. Its own
|
|
6
|
+
* `clampThinkingLevel` (pi-ai models.js) shows both halves: a model with
|
|
7
|
+
* `reasoning: false` supports only `["off"]`, so every requested level collapses
|
|
8
|
+
* there; and a level the model's `thinkingLevelMap` nulls is filtered out, after
|
|
9
|
+
* which the clamp scans UPWARD before downward — so asking for `off` on a model
|
|
10
|
+
* that nulls `off` gets the next level that IS available, and thinking stays on.
|
|
11
|
+
* A reasoning profile the user set and the model erased is worse than no profile
|
|
12
|
+
* feature, because it looks like it worked.
|
|
12
13
|
*
|
|
13
14
|
* ANTI-NAG. This warns once per session and clears on the first keystroke, and
|
|
14
15
|
* that is the whole mechanism — deliberately no "already warned about model X"
|
|
15
16
|
* file. Such a record goes stale the moment models.json is edited, and would
|
|
16
17
|
* suppress the warning at exactly the moment a `/model` switch made it true.
|
|
17
|
-
* brave-warning.ts nags every session for a standing misconfiguration and that
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* model and nothing renders at all.
|
|
18
|
+
* brave-warning.ts nags every session for a standing misconfiguration and that is
|
|
19
|
+
* correct; this is the same class. Setting a group back to `inherit` is what
|
|
20
|
+
* silences it: an all-`inherit` table yields no mismatches for any model.
|
|
21
21
|
*/
|
|
22
22
|
import { getConfig } from '../config/config.js';
|
|
23
23
|
import { effectiveReasoning } from '../config/reasoning.js';
|
|
@@ -30,9 +30,9 @@ const WIDGET_KEY = 'pi-task-reasoning-warning';
|
|
|
30
30
|
*
|
|
31
31
|
* Names the MODEL it checked, because children carry no `-m` and resolve pi's
|
|
32
32
|
* default model, which need not be the host session's — a warning that does not
|
|
33
|
-
* say what it looked at cannot be acted on. Names at most two groups
|
|
34
|
-
*
|
|
35
|
-
* reads.
|
|
33
|
+
* say what it looked at cannot be acted on. Names at most two groups and appends
|
|
34
|
+
* `(+N more)` only when there are more than two, since a line long enough to list
|
|
35
|
+
* every group is a line nobody reads. Null when nothing mismatched.
|
|
36
36
|
*/
|
|
37
37
|
export function formatReasoningWarning(modelName, mismatches) {
|
|
38
38
|
if (mismatches.length === 0)
|
|
@@ -51,9 +51,10 @@ export function formatReasoningWarning(modelName, mismatches) {
|
|
|
51
51
|
* The extra cause line, when the SERVER disagrees with models.json.
|
|
52
52
|
*
|
|
53
53
|
* This is the `/login llama.cpp` case and the only thing the host-side clamp
|
|
54
|
-
* cannot see: pi
|
|
55
|
-
* a perfectly capable server is described to pi
|
|
56
|
-
* Returns null whenever the two agree,
|
|
54
|
+
* cannot see: pi ships llama.cpp as a built-in extension whose provider entry
|
|
55
|
+
* hardcodes `reasoning: false`, so a perfectly capable server is described to pi
|
|
56
|
+
* as having no reasoning at all. Returns null whenever the two agree, and null
|
|
57
|
+
* when the probe answered nothing, so an unreachable server adds no cause line.
|
|
57
58
|
*/
|
|
58
59
|
export function formatCapabilityConflict(serverSupportsEffort, modelDeclaresReasoning) {
|
|
59
60
|
if (serverSupportsEffort === null)
|
|
@@ -90,9 +91,10 @@ probe = probeChatTemplateCaps) {
|
|
|
90
91
|
const base = formatReasoningWarning(model?.name ?? model?.id ?? 'unknown', mismatches);
|
|
91
92
|
if (base === null)
|
|
92
93
|
return null;
|
|
93
|
-
// Fire-and-forget: the server probe only ever REFINES the cause line, so
|
|
94
|
-
//
|
|
95
|
-
//
|
|
94
|
+
// Fire-and-forget: the server probe only ever REFINES the cause line, so it
|
|
95
|
+
// must not delay the warning or be able to prevent it. `probeChatTemplateCaps`
|
|
96
|
+
// carries its own short timeout and returns null on any failure, so a
|
|
97
|
+
// backend that does not answer `/props` costs nothing.
|
|
96
98
|
const baseUrl = model?.baseUrl;
|
|
97
99
|
if (model === undefined || baseUrl === undefined || baseUrl === '')
|
|
98
100
|
return { text: base };
|
|
@@ -2,13 +2,11 @@
|
|
|
2
2
|
* research-cache — a per-run cache of docs/search/fetch worker RESULTS, shared
|
|
3
3
|
* across the sibling task pipelines of one /task-auto run.
|
|
4
4
|
*
|
|
5
|
-
* The failure
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* ask a question can answer every later one from a shared digest instead of a fresh
|
|
11
|
-
* network round-trip plus child-summariser spawn.
|
|
5
|
+
* The failure it serves: every sibling task pipeline in a run re-fetches the SAME
|
|
6
|
+
* external docs and re-runs the SAME searches. Each of those worker results is a
|
|
7
|
+
* deterministic function of (tool, package/url, query) that does not change within a
|
|
8
|
+
* run — so the first pipeline to ask a question can answer every later one from a
|
|
9
|
+
* shared digest instead of a fresh network round-trip plus a child-summariser spawn.
|
|
12
10
|
*
|
|
13
11
|
* SCOPE — stable external lookups only: npm-package docs, web search, web fetch. A
|
|
14
12
|
* PROJECT-SOURCE (`.`) docs lookup is deliberately NOT cached: the working tree
|
|
@@ -25,27 +23,17 @@
|
|
|
25
23
|
* a run started with the feature flag OFF (no id in the environment) does not cache
|
|
26
24
|
* at all — the cache is inert unless the orchestrator turned it on for this run.
|
|
27
25
|
*
|
|
28
|
-
* RESUME REUSE
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* 201 → 11 → 3 → 5 → 8. The audit read the 8-entry tail and concluded the cache was
|
|
33
|
-
* near-useless; it was in fact working, and the resume threw the work away. The old
|
|
34
|
-
* comment called a resume re-fetch "only slightly less reuse", which holds for a
|
|
35
|
-
* 5-task run and fails badly for a 32-task one.
|
|
26
|
+
* RESUME REUSE. A resume that stamps a fresh id makes the first store drop everything
|
|
27
|
+
* the interrupted run had built, so the longer the run, the more a resume throws away.
|
|
28
|
+
* A resume therefore REUSES the interrupted run's id — but only on POSITIVE evidence
|
|
29
|
+
* that the digests still describe the same dependency surface.
|
|
36
30
|
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
31
|
+
* PER-PACKAGE INVALIDATION. One fingerprint over the whole dependency block cannot be
|
|
32
|
+
* that evidence: a greenfield run ADDS dependencies every few tasks, so every resume
|
|
33
|
+
* sees a moved fingerprint and keeps nothing. Adding a package invalidates nothing that
|
|
34
|
+
* was already cached; only the package a digest is ABOUT going stale does.
|
|
39
35
|
*
|
|
40
|
-
*
|
|
41
|
-
* over the whole dependency block: any change anywhere ⇒ wipe. That gate can never hold
|
|
42
|
-
* on the projects /task actually builds — a greenfield run ADDS dependencies every few
|
|
43
|
-
* tasks (run 14: hono/zod at T10, shadcn at T25, playwright-ct at T28), so all five of
|
|
44
|
-
* its resumes saw a moved fingerprint and the run ended with ONE cached entry. Adding a
|
|
45
|
-
* package invalidates nothing that was already cached; only the package a digest is
|
|
46
|
-
* ABOUT going stale does.
|
|
47
|
-
*
|
|
48
|
-
* So invalidation is now per entry. Every docs entry records the package it describes
|
|
36
|
+
* So invalidation is per entry. Every docs entry records the package it describes
|
|
49
37
|
* and the version declared for it at store time (a structured field on the entry, not
|
|
50
38
|
* something re-parsed out of the key — keys embed the tool name with a \0 separator and
|
|
51
39
|
* are the wrong place to carry meaning). A resume keeps the run id and drops only the
|
|
@@ -53,45 +41,38 @@
|
|
|
53
41
|
*
|
|
54
42
|
* STALENESS TRADE, decided deliberately: search and fetch entries are kept
|
|
55
43
|
* unconditionally, even across a dependency bump. A kept search result about package X
|
|
56
|
-
* may describe an older X. That is accepted — docs is the version-sensitive channel
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
44
|
+
* may describe an older X. That is accepted — docs is the version-sensitive channel,
|
|
45
|
+
* pinned to the INSTALLED package, and search is discovery, where re-running every query
|
|
46
|
+
* on every resume costs far more than the rare staleness does. A run that must not
|
|
47
|
+
* tolerate it can disable the cache outright.
|
|
60
48
|
*
|
|
61
49
|
* A file written before per-entry provenance shipped (no `pkgv` marker) carries no way
|
|
62
50
|
* to tell its docs entries apart, so it still falls back to a fresh id: every
|
|
63
51
|
* inconclusive path costs time, never correctness.
|
|
64
52
|
*
|
|
65
|
-
* CONCURRENT WRITERS
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
* left 1 entry in-process and 11 of 40 across four child processes.
|
|
53
|
+
* CONCURRENT WRITERS. Storing is a read-modify-write over ONE file, and its writers are
|
|
54
|
+
* concurrent on two axes at once: makeWorkerTool registers the research tools with
|
|
55
|
+
* `executionMode: 'parallel'`, so a single child can issue several docs calls in the same
|
|
56
|
+
* millisecond, and the research phase runs its worker children as separate PROCESSES.
|
|
57
|
+
* Unsynchronised, that is a classic lost update — last writer wins, and everything read
|
|
58
|
+
* before it is discarded.
|
|
72
59
|
*
|
|
73
60
|
* So the read-modify-write is serialised twice over: an in-process queue per cache file
|
|
74
61
|
* (siblings inside one child never touch the filesystem lock at all) wrapped in an
|
|
75
62
|
* advisory lock directory beside the file, which is what makes it hold across processes.
|
|
76
|
-
* An atomic `mkdir` is the lock —
|
|
77
|
-
*
|
|
63
|
+
* An atomic `mkdir` is the lock — create-or-fail with no fd bookkeeping. With both in
|
|
64
|
+
* place, 40 concurrent stores keep 40 entries, whether they come from one process or
|
|
65
|
+
* from four.
|
|
78
66
|
*
|
|
79
67
|
* The lock is BEST-EFFORT LIKE EVERYTHING ELSE HERE: acquisition is bounded, and a
|
|
80
68
|
* writer that cannot get in within the timeout SKIPS its store rather than waiting. A
|
|
81
69
|
* skipped store costs one re-lookup later; a blocked store would stall a worker, which
|
|
82
|
-
* this cache is never allowed to do.
|
|
83
|
-
*
|
|
84
|
-
* WHAT THE FIX IS WORTH, measured before it was built (scripts/research-cache-
|
|
85
|
-
* write-loss-step0.ts, re-runnable): the lost updates are real but nearly free. mx5 lost
|
|
86
|
-
* ~70 of 204 attempted keys, all in the docs channel — and asked ZERO of them twice, so
|
|
87
|
-
* nothing lost was ever wanted again. IAR1 and godot-engine retained more distinct keys
|
|
88
|
-
* than the logs show attempted, i.e. lost nothing at all. Estimated recovery on all three
|
|
89
|
-
* projects: 0s per run. This is a correctness fix, not a performance one; it stops the
|
|
90
|
-
* cache silently discarding work, and it will matter to a run whose research phase does
|
|
91
|
-
* repeat itself. Do not oversell it.
|
|
70
|
+
* this cache is never allowed to do. This is a correctness fix, not a performance one:
|
|
71
|
+
* it stops the cache silently discarding work.
|
|
92
72
|
*
|
|
93
73
|
* Stored under `.pi-tasks/` (sibling of env-notes.md / contracts.md), which the
|
|
94
|
-
* git-state guard
|
|
74
|
+
* git-state guard excludes by pathspec (`:(exclude).pi-tasks`) and discardEdits leaves
|
|
75
|
+
* alone. Best-effort throughout: any I/O or
|
|
95
76
|
* parse failure falls back to a live fetch — the cache only ever saves time, it can
|
|
96
77
|
* never change an answer or block a worker.
|
|
97
78
|
*/
|
|
@@ -103,16 +84,14 @@ const RESEARCH_CACHE_FILE = 'research-cache.json';
|
|
|
103
84
|
export const RESEARCH_RUN_ID_ENV = 'PI_TASK_RUN_ID';
|
|
104
85
|
/**
|
|
105
86
|
* Cap stored entries so a chatty run cannot grow the file unboundedly; the newest
|
|
106
|
-
* (by write time) are kept
|
|
107
|
-
* lookups (dozens), so a real run never evicts a still-useful digest.
|
|
87
|
+
* (by write time) are kept and the oldest evicted.
|
|
108
88
|
*/
|
|
109
89
|
const MAX_ENTRIES = 250;
|
|
110
90
|
/** Lock directory guarding the cache file's read-modify-write, created beside it. */
|
|
111
91
|
const LOCK_SUFFIX = '.lock';
|
|
112
92
|
/**
|
|
113
|
-
* How long a writer waits for the lock before giving up and skipping its store.
|
|
114
|
-
*
|
|
115
|
-
* at these file sizes) and well below anything a worker would notice.
|
|
93
|
+
* How long a writer waits for the lock before giving up and skipping its store. The
|
|
94
|
+
* critical section it queues behind is one small read plus one small write.
|
|
116
95
|
*/
|
|
117
96
|
const LOCK_TIMEOUT_MS = 2_000;
|
|
118
97
|
/** Poll interval while the lock is held by someone else. */
|
|
@@ -125,26 +104,20 @@ const LOCK_POLL_MS = 10;
|
|
|
125
104
|
const RENAME_TIMEOUT_MS = 500;
|
|
126
105
|
/**
|
|
127
106
|
* A lock older than this is treated as abandoned and removed. Two writers can both
|
|
128
|
-
* decide that and both proceed, which degrades
|
|
129
|
-
*
|
|
130
|
-
*
|
|
107
|
+
* decide that and both proceed, which degrades to one lost update — strictly better
|
|
108
|
+
* than a crashed child wedging the cache for the rest of the run. Sized far above the
|
|
109
|
+
* critical section, so a live holder is never stolen from.
|
|
131
110
|
*/
|
|
132
111
|
const LOCK_STALE_MS = 30_000;
|
|
133
112
|
/**
|
|
134
113
|
* Filesystem errors that mean "try again in a moment", not "this will never work".
|
|
135
114
|
*
|
|
136
115
|
* POSIX gives `mkdir` two clean answers when someone else holds the lock: it succeeds,
|
|
137
|
-
* or it is EEXIST.
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
* missing. That is the whole of CI's `39 of 40` on windows-latest; the same run's
|
|
143
|
-
* ubuntu half is green because POSIX never produces the code.
|
|
144
|
-
*
|
|
145
|
-
* `rename` over an existing file has the same shape on Windows — it fails while any
|
|
146
|
-
* other handle is open on the target, including a scanner's — so the cache write
|
|
147
|
-
* retries on this set too.
|
|
116
|
+
* or it is EEXIST. Other platforms add more, and a lock contention reported under a code
|
|
117
|
+
* an EEXIST-only check reads as fatal skips the store SILENTLY — no throw, no log, exit
|
|
118
|
+
* code 0, one entry missing. `rename` over an existing file has the same shape. Both
|
|
119
|
+
* therefore retry on this whole set; research-cache.test.ts is what holds the membership
|
|
120
|
+
* in place.
|
|
148
121
|
*/
|
|
149
122
|
const RETRYABLE_FS_CODES = new Set(['EEXIST', 'EPERM', 'EACCES', 'EBUSY', 'ENOTEMPTY']);
|
|
150
123
|
/** Is this a transient filesystem error worth retrying inside the caller's deadline? */
|
|
@@ -343,11 +316,10 @@ async function writeCacheFile(cwd, out) {
|
|
|
343
316
|
try {
|
|
344
317
|
await fsp.mkdir(tasksDir(cwd), { recursive: true });
|
|
345
318
|
await fsp.writeFile(tmp, JSON.stringify(out), 'utf8');
|
|
346
|
-
// The replace, not the write, is the part
|
|
347
|
-
//
|
|
348
|
-
//
|
|
349
|
-
//
|
|
350
|
-
// swallowed. The lock is still held throughout.
|
|
319
|
+
// The replace, not the write, is the part a filesystem can transiently refuse
|
|
320
|
+
// when another handle is open on the target. The whole point of the lock above
|
|
321
|
+
// is that this write is not lost, so a refusal in RETRYABLE_FS_CODES is retried
|
|
322
|
+
// inside a bounded budget rather than swallowed. The lock is held throughout.
|
|
351
323
|
const deadline = Date.now() + RENAME_TIMEOUT_MS;
|
|
352
324
|
for (;;) {
|
|
353
325
|
try {
|
|
@@ -391,10 +363,10 @@ async function acquireLock(lockPath, deadline) {
|
|
|
391
363
|
catch (err) {
|
|
392
364
|
if (!isRetryableFsError(err))
|
|
393
365
|
return false;
|
|
394
|
-
//
|
|
395
|
-
// RETRYABLE_FS_CODES)
|
|
396
|
-
//
|
|
397
|
-
//
|
|
366
|
+
// Retryable but NOT EEXIST ⇒ the directory is on its way out (see
|
|
367
|
+
// RETRYABLE_FS_CODES), so there is no lock to inspect for staleness. Wait
|
|
368
|
+
// one poll and try to create it again rather than reporting a hold that
|
|
369
|
+
// nobody has.
|
|
398
370
|
if (!isHeldError(err)) {
|
|
399
371
|
if (Date.now() >= deadline)
|
|
400
372
|
return false;
|
|
@@ -45,11 +45,13 @@ export async function search(input) {
|
|
|
45
45
|
}
|
|
46
46
|
catch (err) {
|
|
47
47
|
// Which throws already carry a finished user-facing message is the engine's
|
|
48
|
-
// own fact, so
|
|
49
|
-
//
|
|
50
|
-
//
|
|
51
|
-
//
|
|
52
|
-
//
|
|
48
|
+
// own fact, so `errorName` is a row rather than an `err.name` check welded
|
|
49
|
+
// into a brave-only branch. It stays a STRING match either way — a class
|
|
50
|
+
// rename that leaves the row untouched goes unnoticed, and only the wrapped
|
|
51
|
+
// wording changes.
|
|
52
|
+
//
|
|
53
|
+
// No `errorName` means every throw's message is used verbatim; a name that
|
|
54
|
+
// does not match is passed through `wrapUnknownError`.
|
|
53
55
|
const message = err instanceof Error ? err.message : String(err);
|
|
54
56
|
const known = adapter.errorName === undefined
|
|
55
57
|
|| (err instanceof Error && err.name === adapter.errorName);
|
|
@@ -8,26 +8,27 @@ export interface SearchResult {
|
|
|
8
8
|
* Which engine backs pi-worker-search and the freshness/enrichment lookups.
|
|
9
9
|
* - `exa` — Exa's public MCP endpoint; no key needed (default).
|
|
10
10
|
* - `ddg` — DuckDuckGo's HTML endpoint; no key needed.
|
|
11
|
-
* - `brave` — Brave Search API; needs BRAVE_SEARCH_API_KEY.
|
|
11
|
+
* - `brave` — Brave Search API; needs BRAVE_SEARCH_API_KEY, or BRAVE_API_KEY.
|
|
12
12
|
*/
|
|
13
13
|
export type SearchProvider = 'exa' | 'ddg' | 'brave';
|
|
14
14
|
export declare const SEARCH_PROVIDERS: readonly SearchProvider[];
|
|
15
15
|
/**
|
|
16
16
|
* The API-key env vars an engine needs, in lookup order. Empty = keyless.
|
|
17
17
|
*
|
|
18
|
-
* Declared beside the engine ids rather than inside `search()`, because two
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* pair with a comment saying it "mirrors search-core's lookup" — the shape a
|
|
23
|
-
* table exists to make impossible.
|
|
18
|
+
* Declared beside the engine ids rather than inside `search()`, because two places
|
|
19
|
+
* ask the question: the search itself, and `searchConfigured` in phases.ts, which
|
|
20
|
+
* decides whether the APIS research worker is handed the search tool at all. Both
|
|
21
|
+
* go through {@link searchProviderKey}, so neither can restate the env pair.
|
|
24
22
|
*/
|
|
25
23
|
export declare const SEARCH_PROVIDER_KEY_ENV: Record<SearchProvider, readonly string[]>;
|
|
26
|
-
/** The engine's key, or `null` when it needs one and none is set. `''` = keyless.
|
|
24
|
+
/** The engine's key, or `null` when it needs one and none is set. `''` = keyless.
|
|
25
|
+
* The vars are tried in list order and the first non-empty one wins. */
|
|
27
26
|
export declare function searchProviderKey(provider: SearchProvider, getEnv: (k: string) => string | undefined): string | null;
|
|
28
27
|
/**
|
|
29
28
|
* Human-readable engine names for the config UI. The short ids stay the stored
|
|
30
|
-
* value
|
|
29
|
+
* value, so a config file survives a label change; register.ts is the display
|
|
30
|
+
* layer that maps between them, and search-core uses a label only inside a
|
|
31
|
+
* fallback message.
|
|
31
32
|
*/
|
|
32
33
|
export declare const SEARCH_PROVIDER_LABELS: Record<SearchProvider, string>;
|
|
33
34
|
export declare function providerForLabel(label: string): SearchProvider | undefined;
|
|
@@ -2,19 +2,18 @@ export const SEARCH_PROVIDERS = ['exa', 'ddg', 'brave'];
|
|
|
2
2
|
/**
|
|
3
3
|
* The API-key env vars an engine needs, in lookup order. Empty = keyless.
|
|
4
4
|
*
|
|
5
|
-
* Declared beside the engine ids rather than inside `search()`, because two
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* pair with a comment saying it "mirrors search-core's lookup" — the shape a
|
|
10
|
-
* table exists to make impossible.
|
|
5
|
+
* Declared beside the engine ids rather than inside `search()`, because two places
|
|
6
|
+
* ask the question: the search itself, and `searchConfigured` in phases.ts, which
|
|
7
|
+
* decides whether the APIS research worker is handed the search tool at all. Both
|
|
8
|
+
* go through {@link searchProviderKey}, so neither can restate the env pair.
|
|
11
9
|
*/
|
|
12
10
|
export const SEARCH_PROVIDER_KEY_ENV = {
|
|
13
11
|
exa: [],
|
|
14
12
|
ddg: [],
|
|
15
13
|
brave: ['BRAVE_SEARCH_API_KEY', 'BRAVE_API_KEY']
|
|
16
14
|
};
|
|
17
|
-
/** The engine's key, or `null` when it needs one and none is set. `''` = keyless.
|
|
15
|
+
/** The engine's key, or `null` when it needs one and none is set. `''` = keyless.
|
|
16
|
+
* The vars are tried in list order and the first non-empty one wins. */
|
|
18
17
|
export function searchProviderKey(provider, getEnv) {
|
|
19
18
|
const vars = SEARCH_PROVIDER_KEY_ENV[provider];
|
|
20
19
|
if (vars.length === 0)
|
|
@@ -28,7 +27,9 @@ export function searchProviderKey(provider, getEnv) {
|
|
|
28
27
|
}
|
|
29
28
|
/**
|
|
30
29
|
* Human-readable engine names for the config UI. The short ids stay the stored
|
|
31
|
-
* value
|
|
30
|
+
* value, so a config file survives a label change; register.ts is the display
|
|
31
|
+
* layer that maps between them, and search-core uses a label only inside a
|
|
32
|
+
* fallback message.
|
|
32
33
|
*/
|
|
33
34
|
export const SEARCH_PROVIDER_LABELS = {
|
|
34
35
|
exa: 'Exa',
|
|
@@ -1,29 +1,28 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* A one-line startup hint in the TUI, and the whole widget lifetime around it.
|
|
3
3
|
*
|
|
4
|
-
* WHY IT IS ONE MODULE.
|
|
5
|
-
*
|
|
6
|
-
* TUI gate, the `setWidget` in a try/catch, the `onTerminalInput` that clears
|
|
7
|
-
* the first keystroke, the unsubscribe, and the swallow for a stale ctx
|
|
8
|
-
*
|
|
9
|
-
* here once and each hint supplies only its `compose`.
|
|
4
|
+
* WHY IT IS ONE MODULE. Its two callers — brave-warning and reasoning-warning —
|
|
5
|
+
* would otherwise each write the same ritual: the `session_start` subscription,
|
|
6
|
+
* the TUI gate, the `setWidget` in a try/catch, the `onTerminalInput` that clears
|
|
7
|
+
* on the first keystroke, the unsubscribe, and the swallow for a stale ctx. Here
|
|
8
|
+
* the ritual lives once and each hint supplies only its `compose`.
|
|
10
9
|
*
|
|
11
10
|
* The REFINE half is why this is not just deduplication. A hint may learn
|
|
12
|
-
* something after it has painted
|
|
11
|
+
* something after it has painted — the reasoning hint probes the model's server —
|
|
13
12
|
* and the rule that a refinement must never repaint a widget the user already
|
|
14
|
-
* dismissed
|
|
15
|
-
*
|
|
13
|
+
* dismissed is a property of this module rather than a closure variable in one of
|
|
14
|
+
* the two files. session-hint.test.ts is where it is asserted.
|
|
16
15
|
*/
|
|
17
16
|
import type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';
|
|
18
17
|
export interface SessionHint {
|
|
19
18
|
/** The line to paint now. */
|
|
20
19
|
text: string;
|
|
21
20
|
/**
|
|
22
|
-
* A later refinement of that line, if this hint has one. Resolving to null —
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
21
|
+
* A later refinement of that line, if this hint has one. Resolving to null — or
|
|
22
|
+
* rejecting — leaves the first line standing, so a refinement can never remove a
|
|
23
|
+
* warning it was only meant to sharpen. It is fire-and-forget: it cannot delay
|
|
24
|
+
* or prevent the first paint, and a refinement that lands AFTER the user cleared
|
|
25
|
+
* the hint repaints nothing.
|
|
27
26
|
*/
|
|
28
27
|
refine?: Promise<string | null>;
|
|
29
28
|
}
|
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* A one-line startup hint in the TUI, and the whole widget lifetime around it.
|
|
3
3
|
*
|
|
4
|
-
* WHY IT IS ONE MODULE.
|
|
5
|
-
*
|
|
6
|
-
* TUI gate, the `setWidget` in a try/catch, the `onTerminalInput` that clears
|
|
7
|
-
* the first keystroke, the unsubscribe, and the swallow for a stale ctx
|
|
8
|
-
*
|
|
9
|
-
* here once and each hint supplies only its `compose`.
|
|
4
|
+
* WHY IT IS ONE MODULE. Its two callers — brave-warning and reasoning-warning —
|
|
5
|
+
* would otherwise each write the same ritual: the `session_start` subscription,
|
|
6
|
+
* the TUI gate, the `setWidget` in a try/catch, the `onTerminalInput` that clears
|
|
7
|
+
* on the first keystroke, the unsubscribe, and the swallow for a stale ctx. Here
|
|
8
|
+
* the ritual lives once and each hint supplies only its `compose`.
|
|
10
9
|
*
|
|
11
10
|
* The REFINE half is why this is not just deduplication. A hint may learn
|
|
12
|
-
* something after it has painted
|
|
11
|
+
* something after it has painted — the reasoning hint probes the model's server —
|
|
13
12
|
* and the rule that a refinement must never repaint a widget the user already
|
|
14
|
-
* dismissed
|
|
15
|
-
*
|
|
13
|
+
* dismissed is a property of this module rather than a closure variable in one of
|
|
14
|
+
* the two files. session-hint.test.ts is where it is asserted.
|
|
16
15
|
*/
|
|
17
16
|
/**
|
|
18
17
|
* Register one startup hint.
|
package/dist/workers/shared.d.ts
CHANGED
|
@@ -19,19 +19,16 @@ export interface ChildOutcome {
|
|
|
19
19
|
* The one place worker child-failure is turned into a user-facing message.
|
|
20
20
|
* Returns `null` when the child succeeded (caller proceeds to format output).
|
|
21
21
|
*
|
|
22
|
-
* It ASKS THE LADDER
|
|
23
|
-
*
|
|
24
|
-
* `if (aborted) return abortedMessage
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* later at the only caller that had the richer result, computed the real cause
|
|
28
|
-
* and sent it to a debug trail nobody reads. That is the same shape as the bug
|
|
29
|
-
* `worker-failure.ts`'s own header records, one layer out: a second author of a
|
|
30
|
-
* taxonomy the module exists to own.
|
|
22
|
+
* It ASKS THE LADDER (`classifyWorkerFailure` -> `describeWorkerFailure`) rather
|
|
23
|
+
* than re-deriving the answer from two fields. Every kill path also sets
|
|
24
|
+
* `aborted`, so an `if (aborted) return abortedMessage` would give a wall-clock
|
|
25
|
+
* kill, a hung command, a dead backend, a loop kill and a user ESC the same four
|
|
26
|
+
* words. Through the ladder each gets its own diagnosis.
|
|
31
27
|
*
|
|
32
|
-
* A caller with only a `ChildOutcome` is unaffected
|
|
33
|
-
*
|
|
34
|
-
*
|
|
28
|
+
* A caller with only a `ChildOutcome` is unaffected: it carries no kill flags, so
|
|
29
|
+
* the ladder falls through to `aborted`/`exit` — null on a clean exit, the abort
|
|
30
|
+
* message when aborted, and `Worker exited N` plus the stderr tail otherwise.
|
|
31
|
+
* `shared.test.ts` pins those three.
|
|
35
32
|
*/
|
|
36
33
|
export declare function formatChildFailure(child: ChildOutcome | (WorkerFailureInput & {
|
|
37
34
|
stderr?: string;
|
|
@@ -39,15 +36,13 @@ export declare function formatChildFailure(child: ChildOutcome | (WorkerFailureI
|
|
|
39
36
|
/**
|
|
40
37
|
* What a worker tool PRODUCED — an answer, or a statement that it has none.
|
|
41
38
|
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
* `code
|
|
46
|
-
* exit code 0,
|
|
47
|
-
* aborted."`
|
|
48
|
-
*
|
|
49
|
-
* re-fire. `docsFailureResult`'s own contract said it recorded the code "NOT as
|
|
50
|
-
* 0"; the value it copied was 0.
|
|
39
|
+
* As a bare `{text, details}` bag, "did it succeed" gets re-derived downstream
|
|
40
|
+
* from `details.childExitCode === 0`. That derivation is wrong in the one case it
|
|
41
|
+
* most needs to be right: node reports a signal kill as `close` with
|
|
42
|
+
* `code === null`, which child-process.ts settles as `code ?? 0` — so an ABORTED
|
|
43
|
+
* lookup arrives carrying exit code 0, the cache rules say yes, and
|
|
44
|
+
* `"Docs lookup aborted."` is memoised for the whole run and re-served to every
|
|
45
|
+
* later sibling.
|
|
51
46
|
*
|
|
52
47
|
* Stating the outcome makes that unrepresentable: `makeWorkerTool` stores only an
|
|
53
48
|
* `answer`, so no cache rule has to know anything about process health, and the
|
|
@@ -92,20 +87,21 @@ export interface WorkerToolSpec<TParams extends TSchema, TDetails> {
|
|
|
92
87
|
run(params: Static<TParams>, signal: AbortSignal | undefined, ctx: ExtensionContext): Promise<WorkerOutcome<TDetails>>;
|
|
93
88
|
renderCall(args: Static<TParams>, theme: Theme): Text;
|
|
94
89
|
/**
|
|
95
|
-
* Per-run research-cache policy
|
|
90
|
+
* Per-run research-cache policy. Return a stable cache key for this call —
|
|
96
91
|
* a result keyed on it is a deterministic function of the inputs that does not
|
|
97
92
|
* change within a run, so a later sibling task can reuse it instead of re-running
|
|
98
93
|
* the network fetch + child summariser. Return `null` to opt a particular call
|
|
99
94
|
* OUT of caching (e.g. a project-source `.` lookup, whose answer the working tree
|
|
100
95
|
* mutates within a run). Omit entirely and the tool is never cached. The stored
|
|
101
|
-
* key is namespaced by tool name
|
|
96
|
+
* key is namespaced by tool name — joined with a literal NUL, which is why the
|
|
97
|
+
* separator is invisible to `grep` and to a plain editor.
|
|
102
98
|
*/
|
|
103
99
|
cacheKey?(params: Static<TParams>): string | null;
|
|
104
100
|
/**
|
|
105
101
|
* The npm package this call's answer is ABOUT, for a package-scoped tool (docs).
|
|
106
102
|
* Recorded as structured provenance on the cache entry so a resume can drop just the
|
|
107
|
-
* entries whose package moved version, instead of the whole run's cache
|
|
108
|
-
* greenfield run adds packages every few tasks, so a whole-file gate never holds
|
|
103
|
+
* entries whose package moved version, instead of the whole run's cache. A
|
|
104
|
+
* greenfield run adds packages every few tasks, so a whole-file gate never holds.
|
|
109
105
|
* Omit — or return undefined — and the entry survives every resume of its run.
|
|
110
106
|
*/
|
|
111
107
|
cachePkg?(params: Static<TParams>): string | undefined;
|
package/dist/workers/shared.js
CHANGED
|
Binary file
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import type { ExtensionAPI } from '@earendil-works/pi-coding-agent';
|
|
2
2
|
/**
|
|
3
|
-
* Loaded via `-e` into
|
|
4
|
-
*
|
|
5
|
-
* (
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
3
|
+
* Loaded via `-e` into two kinds of child, both of which have their source
|
|
4
|
+
* INLINED and so can only be thrashing when they re-read: the TOOLING research
|
|
5
|
+
* worker (phases.ts) and the planning children (auto-orchestrator.ts).
|
|
6
|
+
*
|
|
7
|
+
* Two in-run blocks. Each returns a `reason`, which pi turns into an error tool
|
|
8
|
+
* result — `agent-loop.js` does `createErrorToolResult(beforeResult.reason)` on a
|
|
9
|
+
* blocked call — so the child reads the explanation and continues instead of
|
|
10
|
+
* dying:
|
|
11
|
+
* - read: blocks a re-read of LINES already delivered; forward paging passes,
|
|
12
|
+
* and the reason names the line to resume from.
|
|
13
|
+
* - grep/find/ls: blocks a byte-identical repeat, keyed on the args; a call
|
|
14
|
+
* with any different argument passes.
|
|
15
|
+
* A tool outside this set is never touched. See single-read-guard.ts for why the
|
|
16
|
+
* read-once rule is safe only where it is armed.
|
|
10
17
|
*/
|
|
11
18
|
export default function (pi: ExtensionAPI): void;
|
|
@@ -3,13 +3,20 @@ import { RepeatedCallGuard, SingleReadGuard } from './single-read-guard.js';
|
|
|
3
3
|
/** Read-like tools whose byte-identical repeats are blocked (read is handled separately). */
|
|
4
4
|
const DEDUP_TOOLS = new Set(['grep', 'find', 'ls']);
|
|
5
5
|
/**
|
|
6
|
-
* Loaded via `-e` into
|
|
7
|
-
*
|
|
8
|
-
* (
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
6
|
+
* Loaded via `-e` into two kinds of child, both of which have their source
|
|
7
|
+
* INLINED and so can only be thrashing when they re-read: the TOOLING research
|
|
8
|
+
* worker (phases.ts) and the planning children (auto-orchestrator.ts).
|
|
9
|
+
*
|
|
10
|
+
* Two in-run blocks. Each returns a `reason`, which pi turns into an error tool
|
|
11
|
+
* result — `agent-loop.js` does `createErrorToolResult(beforeResult.reason)` on a
|
|
12
|
+
* blocked call — so the child reads the explanation and continues instead of
|
|
13
|
+
* dying:
|
|
14
|
+
* - read: blocks a re-read of LINES already delivered; forward paging passes,
|
|
15
|
+
* and the reason names the line to resume from.
|
|
16
|
+
* - grep/find/ls: blocks a byte-identical repeat, keyed on the args; a call
|
|
17
|
+
* with any different argument passes.
|
|
18
|
+
* A tool outside this set is never touched. See single-read-guard.ts for why the
|
|
19
|
+
* read-once rule is safe only where it is armed.
|
|
13
20
|
*/
|
|
14
21
|
export default function (pi) {
|
|
15
22
|
const reads = new SingleReadGuard();
|