@tea-agent/loop-agent 0.42.0-next.1 → 0.42.0-next.11
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/AGENTS.md +1 -1
- package/CHANGELOG.md +321 -1
- package/dist/application/dag/generate-task-dag.js +75 -19
- package/dist/application/dag/run-dag.js +41 -0
- package/dist/application/task-lifecycle/advance.js +24 -5
- package/dist/application/task-lifecycle/observe.js +171 -17
- package/dist/application/task-lifecycle/plan-transitions.js +42 -7
- package/dist/application/task-lifecycle/recommendations.js +13 -2
- package/dist/build-stamp.json +3 -3
- package/dist/cli/command-definitions.js +7 -0
- package/dist/cli/program.js +6 -1
- package/dist/commands/client-recovery.js +3 -0
- package/dist/commands/dag-follow-up.js +138 -0
- package/dist/commands/dag-rerun-task.js +2 -0
- package/dist/commands/init.js +27 -1
- package/dist/commands/task-advance.js +19 -0
- package/dist/executors/dag-pi-executor.js +4010 -78
- package/dist/executors/pi-executor.js +15 -4
- package/dist/executors/pi-extension-resolver.js +14 -2
- package/dist/executors/pi-read-budget-policy.js +239 -0
- package/dist/executors/shell-executor.js +978 -188
- package/dist/executors/shell-write-guard.js +7 -0
- package/dist/infrastructure/console/operation-store.js +226 -6
- package/dist/shared/dag-failure-category.js +12 -0
- package/dist/shared/openspec-spec.js +70 -4
- package/dist/shared/operator/capabilities.js +7 -0
- package/dist/task/config-types.js +105 -5
- package/dist/task/contract/adopt.js +4 -0
- package/dist/task/contract/import-revision.js +4 -0
- package/dist/task/contract/project.js +3 -0
- package/dist/task/contract/schema.js +2 -1
- package/dist/task/frontend-project-capability.js +203 -20
- package/dist/task/runtime.js +5 -2
- package/dist/task/source-prepare/build-draft.js +3 -3
- package/dist/task/source-prepare/fragment-inventory.js +64 -25
- package/dist/task/source-prepare/prepare.js +126 -21
- package/dist/task/source-prepare/semantic-intake.js +6 -2
- package/dist/task/source-references.js +22 -1
- package/dist/worker/console/chat/chat-ui-policy.js +4 -2
- package/dist/worker/console/chat/model-resolver.js +7 -4
- package/dist/worker/console/chat/pi-runtime.js +258 -11
- package/dist/worker/console/chat/repo-browser.js +10 -3
- package/dist/worker/console/chat/routes.js +165 -71
- package/dist/worker/console/chat/sdd-data-alignment.js +222 -0
- package/dist/worker/console/chat/session-catalog.js +2 -0
- package/dist/worker/console/chat/session-store.js +159 -70
- package/dist/worker/console/chat/shortcuts.js +19 -3
- package/dist/worker/console/chat/turn-process.js +111 -56
- package/dist/worker/console/frontend-human-decision-adapter.js +19 -0
- package/dist/worker/console/frontend-split-operation-adapter.js +20 -0
- package/dist/worker/console/index.js +3 -0
- package/dist/worker/console/operator-actions.js +169 -7
- package/dist/worker/console/pi-readiness.js +3 -2
- package/dist/worker/console/server.js +23 -1
- package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-DZZ8m3PO.js → abnfDiagram-N423BO3Z-CcS17TBr.js} +1 -1
- package/dist/worker/console/static/assets/{arc-D6PvaVd-.js → arc-COptKq2S.js} +1 -1
- package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-B_OTOiI8.js → architectureDiagram-T3A2C74G-h4LKMHjP.js} +1 -1
- package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-Bv6rqHBg.js → blockDiagram-VBNYF7ZC-COA1MOH0.js} +1 -1
- package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-B8eHr0oz.js → c4Diagram-5PPSVZJV-DJUf0QPm.js} +1 -1
- package/dist/worker/console/static/assets/channel-DdBCaOJ6.js +1 -0
- package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-DYwR0im2.js → chunk-2GRJ4B5K-mtWfKrUX.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-D2WPGqXt.js → chunk-2Q5K7J3B-B8pXsxDQ.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5RXB4S5H-CQISJ_I7.js → chunk-5RXB4S5H-ipKzByl1.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5VM5RSS4-C0o2Du1e.js → chunk-5VM5RSS4-DYi3Ald_.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-4f8kr-U7.js → chunk-6Q2QTUOP-DQtGYoty.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-GF5L2VYU-D_OWvXzX.js → chunk-GF5L2VYU-BU0qS2YV.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-JWPE2WC7-CasdPz5X.js → chunk-JWPE2WC7-DVH9dIGE.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-KBJHAD2P-Cj8lRrla.js → chunk-KBJHAD2P-Dt60SmgM.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-RYQCIY6F-CUvD1FSd.js → chunk-RYQCIY6F-BoaUGuEY.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-XXDRQBXY-CqLw_eqB.js → chunk-XXDRQBXY-_WHFDTp2.js} +1 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-DZFra1GO.js +1 -0
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-DZFra1GO.js +1 -0
- package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-ku-WqJPx.js → cose-bilkent-JH36ORCC-BxkbTIRd.js} +1 -1
- package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-Bq_PYDhl.js → cynefin-VYW2F7L2-Bf2UVnoG.js} +1 -1
- package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-BiGZV641.js → cynefinDiagram-MW4NZA55-Bo23q1J_.js} +1 -1
- package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-C4JRlglF.js → dagre-VZM6K2ZE-Dd_UU49i.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-7IWD3JNH-B0dNeWYG.js → diagram-7IWD3JNH-ebUa1a9y.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-Cj35YvYM.js → diagram-B4RE2ZJO-BucthU8r.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-LBJQPF4R-uzQoJ2-8.js → diagram-LBJQPF4R-BgqNpAkm.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-Q27KOJAE-D1a-Buoz.js → diagram-Q27KOJAE-DC4q5NGa.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-UB23O5K3-XjRrLRSs.js → diagram-UB23O5K3-CBqCaMeb.js} +1 -1
- package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-Da_O24cW.js → ebnfDiagram-BXEA7PRR-CGtnbQ3-.js} +1 -1
- package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-BLJ8jrYU.js → erDiagram-JOGREHBK-CG3LUao5.js} +1 -1
- package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-B9GrLjM0.js → flowDiagram-UKHOOZJN-D2ZVgoFS.js} +1 -1
- package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-CeJ0TqiK.js → ganttDiagram-PKOTCBZU-DoYFZiKt.js} +1 -1
- package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-Bm2eNNFX.js → gitGraphDiagram-DS77QQ5N-CKoP1s6j.js} +1 -1
- package/dist/worker/console/static/assets/index-CAZ2fC_X.css +1 -0
- package/dist/worker/console/static/assets/index-vbTcFnFs.js +449 -0
- package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-DB26i3d8.js → infoDiagram-6WML65LV-Duofv8p2.js} +1 -1
- package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-BOGRyeZT.js → ishikawaDiagram-WSZJBQD7-D2nlCkA1.js} +1 -1
- package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-CZRoBO_6.js → journeyDiagram-NVQOT4AX-Dd4IHdus.js} +1 -1
- package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-qlWhJyoB.js → kanban-definition-27J2QSJJ-Bi20AOdt.js} +1 -1
- package/dist/worker/console/static/assets/{linear-CfUiDDB3.js → linear-D59YJ9kB.js} +1 -1
- package/dist/worker/console/static/assets/{mermaid.core-BQe6fpqj.js → mermaid.core-Bl13LpNa.js} +5 -5
- package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-zFzWHw64.js → mindmap-definition-FAOFIHXS-C6DLP5eY.js} +1 -1
- package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-DFGUqjZO.js → pegDiagram-VL7TDLO6-BjO4cy64.js} +1 -1
- package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-BB5i0l8Z.js → pieDiagram-7S7Q4E2Y-D7i2qZTG.js} +1 -1
- package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-obbVZ_X5.js → quadrantDiagram-CIZ2JOQS-Dx8o_h0y.js} +1 -1
- package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-BwdaNzc1.js → railroadDiagram-AXF67PYL-B55orI_t.js} +1 -1
- package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-CkTJaugh.js → requirementDiagram-LRYGKXZP-zWaehp6f.js} +1 -1
- package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-BwJ-hIgq.js → sankeyDiagram-W5VNT64P-CcA-pjvD.js} +1 -1
- package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-BzSgmm7w.js → sequenceDiagram-SI44F4Z6-BOFbzNHI.js} +1 -1
- package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-Bn3oj5Q1.js → sizeCapture-X5ZJPWSS-BjAejah1.js} +1 -1
- package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-dxhGtL8K.js → stateDiagram-OKZ733FA-DXYwxJwZ.js} +1 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-Clg3V9t1.js +1 -0
- package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-BLpEInya.js → swimlanes-SLNWSIFB-OYiOch8n.js} +2 -2
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-DX1dxAAW.js +8 -0
- package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-ChJGYcXy.js → timeline-definition-Z64GVDOM-cZfH3nmU.js} +1 -1
- package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-DK-qjRer.js → vennDiagram-T6HMQDX7-BDE7b3E1.js} +1 -1
- package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-3qeaWAg-.js → wardleyDiagram-T6FBY63Y-kyyGy9WJ.js} +1 -1
- package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-CootlyP9.js → xychartDiagram-ELKLHX3M-CJj6VTog.js} +1 -1
- package/dist/worker/console/static/index.html +2 -2
- package/dist/worker/console/static-src/active-run-badge.js +17 -0
- package/dist/worker/console/static-src/app/useRecoveryConsole.js +5 -5
- package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +19 -8
- package/dist/worker/console/static-src/operator-chat/input-history.js +8 -6
- package/dist/worker/console/static-src/operator-chat/open-preview-in-browser.js +15 -7
- package/dist/worker/console/static-src/operator-chat/runtime-snapshot-store.js +10 -0
- package/dist/worker/console/static-src/operator-chat/useChatSessions.js +258 -23
- package/dist/worker/console/static-src/operator-chat/useChatThread.js +112 -4
- package/dist/worker/console/static-src/operator-chat/useComposer.js +13 -4
- package/dist/worker/console/static-src/operator-chat/useRuntimeControls.js +29 -6
- package/dist/worker/console/static-src/operator-chat/useRuntimeSnapshot.js +8 -2
- package/dist/worker/console/static-src/shell/console-update-reload.js +36 -9
- package/dist/worker/console/static-src/shell/workspace-route.js +11 -0
- package/dist/worker/console/workspace-context.js +115 -1
- package/dist/worker/materialize/frontend-split-task-materializer.js +72 -0
- package/dist/worker/observe/routes.js +4 -0
- package/dist/worker/observe/static/constants.js +22 -22
- package/dist/worker/observe/static/dag-context-reason-labels.js +19 -0
- package/dist/worker/observe/static/dag-helpers.js +4 -2
- package/dist/worker/observe/static/dag-history-labels.js +1 -0
- package/dist/worker/observe/static/dag-inspector-humanize.d.ts +16 -0
- package/dist/worker/observe/static/dag-inspector-humanize.js +339 -0
- package/dist/worker/observe/static/dag-node-purpose.js +13 -8
- package/dist/worker/observe/static/index.html +4 -4
- package/dist/worker/observe/static/inspect-workspace.js +23 -0
- package/dist/worker/observe/static/kpi.js +2 -2
- package/dist/worker/observe/static/operator-chrome.d.ts +10 -2
- package/dist/worker/observe/static/operator-chrome.js +37 -23
- package/dist/worker/observe/static/prompt-restart-candidates.js +4 -2
- package/dist/worker/observe/static/relations.js +7 -7
- package/dist/worker/observe/static/router.d.ts +12 -1
- package/dist/worker/observe/static/router.js +48 -6
- package/dist/worker/observe/static/run-processing.js +4 -2
- package/dist/worker/observe/static/shell-chrome.js +2 -2
- package/dist/worker/observe/static/state.js +5 -0
- package/dist/worker/observe/static/styles.css +231 -0
- package/dist/worker/observe/static/views/dag-graph.js +1 -1
- package/dist/worker/observe/static/views/dag-inspector.js +336 -181
- package/dist/worker/observe/static/views/dag.js +26 -14
- package/dist/worker/observe/static/views/dags.js +3 -1
- package/dist/worker/observe/static/views/dashboard.js +14 -6
- package/dist/worker/observe/static/views/pool.js +7 -2
- package/dist/worker/observe/static/views/run.js +12 -3
- package/dist/worker/observe/static/views/session-timeline.js +74 -13
- package/dist/worker/observe/static/views/task.js +7 -2
- package/dist/workflows/dag/backend-test-case-coverage-analysis.js +215 -28
- package/dist/workflows/dag/backend-test-markdown-workflow.js +13 -1
- package/dist/workflows/dag/backend-test-plan-protocol.js +210 -0
- package/dist/workflows/dag/backend-test-scenario-param.js +172 -25
- package/dist/workflows/dag/backend-test-scenario-partitions.js +62 -1
- package/dist/workflows/dag/backend-test-writer-completeness.js +104 -12
- package/dist/workflows/dag/contract-validator-registrations.js +1 -2
- package/dist/workflows/dag/dag-retry-schema.js +138 -0
- package/dist/workflows/dag/frontend-closeout.js +221 -0
- package/dist/workflows/dag/frontend-design-policy.js +400 -0
- package/dist/workflows/dag/frontend-human-decision.js +182 -0
- package/dist/workflows/dag/frontend-implementation-contract.js +1237 -192
- package/dist/workflows/dag/frontend-plan-render.js +2 -1
- package/dist/workflows/dag/frontend-prewrite-gate.js +256 -350
- package/dist/workflows/dag/frontend-provider-capability-matrix.js +159 -0
- package/dist/workflows/dag/frontend-recovery-capsule.js +455 -0
- package/dist/workflows/dag/frontend-recovery-controller.js +226 -0
- package/dist/workflows/dag/frontend-recovery-lineage.js +178 -0
- package/dist/workflows/dag/frontend-recovery-plan.js +21 -10
- package/dist/workflows/dag/frontend-recovery-run.js +166 -34
- package/dist/workflows/dag/frontend-repair.js +1 -432
- package/dist/workflows/dag/frontend-review-context.js +261 -15
- package/dist/workflows/dag/frontend-review-findings.js +270 -0
- package/dist/workflows/dag/frontend-shadow-dual-write.js +941 -0
- package/dist/workflows/dag/frontend-shape-capsule-store.js +191 -0
- package/dist/workflows/dag/frontend-shape-facts.js +419 -0
- package/dist/workflows/dag/frontend-shape.js +435 -0
- package/dist/workflows/dag/frontend-source-fidelity-ledger.js +108 -0
- package/dist/workflows/dag/frontend-split-application-service.js +203 -0
- package/dist/workflows/dag/frontend-split-orchestrator.js +899 -0
- package/dist/workflows/dag/frontend-typed-event-store.js +452 -0
- package/dist/workflows/dag/frontend-typed-event-transaction.js +180 -0
- package/dist/workflows/dag/frontend-verification-trace.js +252 -25
- package/dist/workflows/dag/frontend-worktree-diff.js +250 -17
- package/dist/workflows/dag/frontend-writer-admission.js +319 -0
- package/dist/workflows/dag/frontend-writer-status.js +256 -0
- package/dist/workflows/dag/init-hybrid.js +1031 -564
- package/dist/workflows/dag/interrupt-request.js +7 -0
- package/dist/workflows/dag/node-execution.js +854 -4
- package/dist/workflows/dag/prompt.js +70 -3
- package/dist/workflows/dag/recovery-lease.js +170 -0
- package/dist/workflows/dag/report.js +37 -1
- package/dist/workflows/dag/rerun-feedback.js +315 -1
- package/dist/workflows/dag/rerun-plan.js +17 -6
- package/dist/workflows/dag/rerun-run.js +44 -6
- package/dist/workflows/dag/rerun-task.js +251 -13
- package/dist/workflows/dag/retry-policy.js +230 -104
- package/dist/workflows/dag/runner.js +580 -124
- package/dist/workflows/dag/scheduler.js +133 -20
- package/dist/workflows/dag/types.js +244 -16
- package/dist/workflows/dag/validate.js +28 -12
- package/docs/examples/README.md +5 -0
- package/docs/init-surface.manifest.json +30 -12
- package/docs/skills/vetted-skill-registry.md +4 -2
- package/docs/templates/README.md +2 -0
- package/docs/templates/agent-dag-report.schema.json +8 -2
- package/docs/templates/agent-dag.schema.json +1 -1
- package/docs/templates/backend-test-dag.json +25 -20
- package/docs/templates/frontend-implementation-contract.schema.json +4 -1
- package/docs/templates/frontend-implementation-dag.json +89 -0
- package/docs/templates/spec-registry.schema.json +45 -0
- package/harness.json +1 -1
- package/package.json +4 -3
- package/skills/frontend-bounded-implement/SKILL.md +15 -14
- package/skills/frontend-bounded-implement/references/code-standards.md +19 -0
- package/skills/frontend-contract/SKILL.md +23 -0
- package/skills/frontend-contract/references/contract-protocol.md +34 -0
- package/skills/frontend-design-review/SKILL.md +22 -41
- package/skills/frontend-plan/SKILL.md +26 -0
- package/skills/frontend-plan/references/decision-contract.md +37 -0
- package/skills/frontend-plan/references/design-decisions.md +17 -0
- package/skills/frontend-review/SKILL.md +20 -15
- package/skills/frontend-review/references/review-findings.md +6 -7
- package/skills/frontend-scout/SKILL.md +25 -0
- package/skills/frontend-scout/references/design-evidence.md +16 -0
- package/skills/frontend-scout/references/scout-evidence.md +23 -0
- package/skills/frontend-verification/SKILL.md +1 -1
- package/skills/loop-agent/references/command-reference.md +1 -0
- package/skills/loop-agent/references/hybrid-dag.md +2 -2
- package/dist/worker/console/static/assets/channel-BU5gOilw.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-DIzKJGHr.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-DIzKJGHr.js +0 -1
- package/dist/worker/console/static/assets/index-H9rFJiGL.css +0 -1
- package/dist/worker/console/static/assets/index-xwu9GxEc.js +0 -451
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-Cld2qK9v.js +0 -1
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-TIHpiT7w.js +0 -8
- package/skills/frontend-implementation/SKILL.md +0 -52
- package/skills/frontend-implementation/references/code-standards.md +0 -33
- package/skills/frontend-implementation/references/design-spec.md +0 -56
- package/skills/frontend-implementation/references/node-contracts.md +0 -31
|
@@ -1014,17 +1014,28 @@ export function classifyPiFailure(input) {
|
|
|
1014
1014
|
if (input.outputTooLarge)
|
|
1015
1015
|
return "output-too-large";
|
|
1016
1016
|
const combined = `${input.stderr}\n${input.stdout}`.toLowerCase();
|
|
1017
|
+
// Context overflow (400 request-too-large / context window exceeded).
|
|
1018
|
+
// Must be detected BEFORE the generic rate-limit/quota phrases: an overflow
|
|
1019
|
+
// error often contains "too many tokens" / "maximum context" which would
|
|
1020
|
+
// otherwise be misread as rate-limit or quota. Kept in sync with
|
|
1021
|
+
// CONTEXT_OVERFLOW_PHRASES in commands/client-recovery.ts.
|
|
1022
|
+
if (/请求上下文过大|context_length_exceeded|context overflow|context length overflow|too many tokens|maximum context|prompt is too long|request_too_large|context window/.test(combined))
|
|
1023
|
+
return "context-overflow";
|
|
1017
1024
|
// Prefer explicit rate-limit / HTTP 429 before generic "limit" quota phrases.
|
|
1018
1025
|
// Chinese gateways often say "请求频率已达到限制" without English "rate limit".
|
|
1019
|
-
|
|
1026
|
+
// Patterns need error-shaped context: the captured stream also contains
|
|
1027
|
+
// serialized session events, where a bare "429" is an output-token counter,
|
|
1028
|
+
// bare "rpm"/"tpm" are base64 substrings of encrypted reasoning, and bare
|
|
1029
|
+
// "network" is a "no-network" UI state name.
|
|
1030
|
+
if (/rate.?limit|too many requests|(?:http|status)[^\d]{0,4}429\b|"code"\s*:\s*"?429\b|(?:^|\n)429[\s:]|请求频率|频率.*限制|\b(?:rpm|tpm)\s*(?:limit|quota|exceeded)/.test(combined))
|
|
1020
1031
|
return "rate-limit";
|
|
1021
|
-
if (/quota|usage limit|reached
|
|
1032
|
+
if (/quota|usage limit|reached[^\n.]{0,60}limit|5\s*小时|5小时|insufficient_quota|billing/.test(combined))
|
|
1022
1033
|
return "quota";
|
|
1023
1034
|
if (/\bunauthorized\b|\bhttp\s*40[13]\b|invalid api key|authentication (?:failed|required|error)|auth(?:entication)? failed/.test(combined))
|
|
1024
1035
|
return "auth";
|
|
1025
|
-
if (/unknown provider|unknown model|model
|
|
1036
|
+
if (/unknown provider|unknown model|(?:provider|model|service|gateway)\s+(?:is\s+)?unavailable|overloaded|at capacity|temporarily unavailable/.test(combined))
|
|
1026
1037
|
return "unavailable";
|
|
1027
|
-
if (/network|
|
|
1038
|
+
if (/network\s*(?:error|failure|issue|timeout|unreachable|reset|abort)|networkerror|connection (?:reset|error|refused|closed|timed\s*out)|request timed out|socket hang up|econn\w*|etimedout|fetch failed|dns (?:error|failure|lookup failed)/.test(combined))
|
|
1028
1039
|
return "network";
|
|
1029
1040
|
if (input.exitCode === 0 && !input.assistantText.trim())
|
|
1030
1041
|
return "empty-output";
|
|
@@ -62,9 +62,21 @@ function readSettingsPackages(settingsPath) {
|
|
|
62
62
|
return undefined;
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
|
-
/**
|
|
65
|
+
/**
|
|
66
|
+
* Strip an `npm:` prefix and a trailing `@<version>`/`@<dist-tag>` suffix
|
|
67
|
+
* from a settings package spec, e.g. `npm:pi-lens@3.8.72` → `pi-lens`,
|
|
68
|
+
* `npm:@scope/pkg@1.0.0` → `@scope/pkg`. The leading `@` of a scoped
|
|
69
|
+
* package name is preserved (the version separator is the LAST `@` at a
|
|
70
|
+
* positive index). Mirrors the console-side spec parsing semantics so a
|
|
71
|
+
* version-pinned install (e.g. via `pi install npm:pi-lens@3.8.72`) resolves
|
|
72
|
+
* identically in both surfaces.
|
|
73
|
+
*/
|
|
66
74
|
export function packageNameFromSpec(spec) {
|
|
67
|
-
|
|
75
|
+
const base = spec.startsWith("npm:") ? spec.slice(4) : spec;
|
|
76
|
+
const at = base.lastIndexOf("@");
|
|
77
|
+
if (at > 0)
|
|
78
|
+
return base.slice(0, at);
|
|
79
|
+
return base;
|
|
68
80
|
}
|
|
69
81
|
function loadPackageInventories(repoRoot) {
|
|
70
82
|
const agentDir = getPiAgentDir();
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { access, open, readFile, stat, } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
class PiReadBudgetSoftLimitError extends Error {
|
|
4
|
+
}
|
|
5
|
+
class PiReadAccessDeniedError extends Error {
|
|
6
|
+
}
|
|
7
|
+
class PiReadBudgetGuard {
|
|
8
|
+
budget;
|
|
9
|
+
files = new Set();
|
|
10
|
+
violations = [];
|
|
11
|
+
bytes = 0;
|
|
12
|
+
operations = 0;
|
|
13
|
+
startedAt = Date.now();
|
|
14
|
+
allowedReadPaths;
|
|
15
|
+
allowedReadRoots;
|
|
16
|
+
constructor(budget, readAccess) {
|
|
17
|
+
this.budget = budget;
|
|
18
|
+
this.allowedReadPaths = readAccess?.allowedReadPaths
|
|
19
|
+
? new Set(readAccess.allowedReadPaths.map((candidate) => path.resolve(candidate)))
|
|
20
|
+
: undefined;
|
|
21
|
+
this.allowedReadRoots = (readAccess?.allowedReadRoots ?? []).map((candidate) => path.resolve(candidate));
|
|
22
|
+
}
|
|
23
|
+
issues() {
|
|
24
|
+
return [...this.violations];
|
|
25
|
+
}
|
|
26
|
+
report(message) {
|
|
27
|
+
if (!this.violations.includes(message))
|
|
28
|
+
this.violations.push(message);
|
|
29
|
+
}
|
|
30
|
+
exhaust(message) {
|
|
31
|
+
if (this.budget.onExhaustion === "return-guidance") {
|
|
32
|
+
throw new PiReadBudgetSoftLimitError(message);
|
|
33
|
+
}
|
|
34
|
+
this.report(message);
|
|
35
|
+
throw new Error(message);
|
|
36
|
+
}
|
|
37
|
+
assertElapsed() {
|
|
38
|
+
if (this.budget.maxMs === undefined)
|
|
39
|
+
return;
|
|
40
|
+
const elapsedMs = Date.now() - this.startedAt;
|
|
41
|
+
if (elapsedMs > this.budget.maxMs) {
|
|
42
|
+
const message = `read budget exhausted: ${elapsedMs}ms (budget ${this.budget.maxMs}ms)`;
|
|
43
|
+
this.exhaust(message);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
beforeToolOperation() {
|
|
47
|
+
this.assertElapsed();
|
|
48
|
+
if (this.budget.maxOperations === undefined)
|
|
49
|
+
return true;
|
|
50
|
+
if (this.operations >= this.budget.maxOperations) {
|
|
51
|
+
const message = `read budget exhausted: operation ${this.operations + 1} would exceed ${this.budget.maxOperations} read-only tool calls`;
|
|
52
|
+
if (this.budget.onExhaustion === "return-guidance")
|
|
53
|
+
return false;
|
|
54
|
+
this.exhaust(message);
|
|
55
|
+
}
|
|
56
|
+
this.operations += 1;
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
operationLimitGuidance() {
|
|
60
|
+
return {
|
|
61
|
+
content: [
|
|
62
|
+
{
|
|
63
|
+
type: "text",
|
|
64
|
+
text: "[read limit reached: no repository data was read. Do not call discovery tools again; use injected facts, commit remaining record_* facts, then call finalize_plan exactly once.]",
|
|
65
|
+
},
|
|
66
|
+
],
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
readAccessGuidance() {
|
|
70
|
+
return {
|
|
71
|
+
content: [
|
|
72
|
+
{
|
|
73
|
+
type: "text",
|
|
74
|
+
text: "[read denied: this node may read only named upstream artifacts or Scout-confirmed paths. Do not explore a new repository path; use committed facts or record an evidence gap, then finish the required terminal protocol.]",
|
|
75
|
+
},
|
|
76
|
+
],
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
assertReadablePath(absolutePath) {
|
|
80
|
+
if (!this.allowedReadPaths)
|
|
81
|
+
return;
|
|
82
|
+
const resolved = path.resolve(absolutePath);
|
|
83
|
+
if (this.allowedReadPaths.has(resolved))
|
|
84
|
+
return;
|
|
85
|
+
if (this.allowedReadRoots.some((root) => resolved === root || resolved.startsWith(`${root}${path.sep}`)))
|
|
86
|
+
return;
|
|
87
|
+
throw new PiReadAccessDeniedError(`read access denied: ${resolved}`);
|
|
88
|
+
}
|
|
89
|
+
reserveFile(absolutePath) {
|
|
90
|
+
this.assertElapsed();
|
|
91
|
+
if (this.files.has(absolutePath))
|
|
92
|
+
return;
|
|
93
|
+
if (this.files.size >= this.budget.maxFiles) {
|
|
94
|
+
const message = `read budget exhausted: file ${absolutePath} would exceed ${this.budget.maxFiles} files`;
|
|
95
|
+
this.exhaust(message);
|
|
96
|
+
}
|
|
97
|
+
this.files.add(absolutePath);
|
|
98
|
+
}
|
|
99
|
+
reserveBytes(bytes) {
|
|
100
|
+
this.assertElapsed();
|
|
101
|
+
const remaining = Math.max(0, this.budget.maxBytes - this.bytes);
|
|
102
|
+
if (remaining === 0) {
|
|
103
|
+
const message = `read budget exhausted: ${this.bytes} bytes (budget ${this.budget.maxBytes})`;
|
|
104
|
+
this.exhaust(message);
|
|
105
|
+
}
|
|
106
|
+
const granted = Math.min(bytes, remaining);
|
|
107
|
+
if (granted < bytes && this.budget.onExhaustion === "return-guidance") {
|
|
108
|
+
this.exhaust(`read budget exhausted: ${bytes} requested bytes would exceed ${this.budget.maxBytes} bytes`);
|
|
109
|
+
}
|
|
110
|
+
this.bytes += granted;
|
|
111
|
+
if (granted < bytes) {
|
|
112
|
+
this.report(`read budget truncated: ${bytes} requested bytes at ${this.bytes}/${this.budget.maxBytes} bytes`);
|
|
113
|
+
}
|
|
114
|
+
return granted;
|
|
115
|
+
}
|
|
116
|
+
async readFile(absolutePath) {
|
|
117
|
+
this.assertReadablePath(absolutePath);
|
|
118
|
+
this.reserveFile(absolutePath);
|
|
119
|
+
const metadata = await stat(absolutePath);
|
|
120
|
+
const granted = this.reserveBytes(metadata.size);
|
|
121
|
+
if (granted === metadata.size)
|
|
122
|
+
return await readFile(absolutePath);
|
|
123
|
+
const handle = await open(absolutePath, "r");
|
|
124
|
+
try {
|
|
125
|
+
const buffer = Buffer.allocUnsafe(granted);
|
|
126
|
+
const { bytesRead } = await handle.read(buffer, 0, granted, 0);
|
|
127
|
+
return buffer.subarray(0, bytesRead);
|
|
128
|
+
}
|
|
129
|
+
finally {
|
|
130
|
+
await handle.close();
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
async access(absolutePath) {
|
|
134
|
+
this.assertReadablePath(absolutePath);
|
|
135
|
+
this.reserveFile(absolutePath);
|
|
136
|
+
await access(absolutePath);
|
|
137
|
+
}
|
|
138
|
+
limitToolResult(result) {
|
|
139
|
+
if (!result || typeof result !== "object" || !Array.isArray(result.content)) {
|
|
140
|
+
return result;
|
|
141
|
+
}
|
|
142
|
+
const content = result.content.map((item) => {
|
|
143
|
+
if (!item || item.type !== "text" || typeof item.text !== "string") {
|
|
144
|
+
this.report("read budget truncated: non-text tool result omitted");
|
|
145
|
+
return {
|
|
146
|
+
type: "text",
|
|
147
|
+
text: "[read budget reached: non-text result omitted]",
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
const granted = this.reserveBytes(Buffer.byteLength(item.text));
|
|
151
|
+
return {
|
|
152
|
+
...item,
|
|
153
|
+
text: truncateUtf8(item.text, granted),
|
|
154
|
+
};
|
|
155
|
+
});
|
|
156
|
+
return { ...result, content };
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
function truncateUtf8(text, maxBytes) {
|
|
160
|
+
if (Buffer.byteLength(text) <= maxBytes)
|
|
161
|
+
return text;
|
|
162
|
+
const marker = "\n[read result truncated by node budget]";
|
|
163
|
+
const markerBytes = Buffer.byteLength(marker);
|
|
164
|
+
if (maxBytes <= markerBytes)
|
|
165
|
+
return truncateUtf8Prefix(marker, maxBytes);
|
|
166
|
+
const contentBudget = maxBytes - markerBytes;
|
|
167
|
+
return `${truncateUtf8Prefix(text, contentBudget)}${marker}`;
|
|
168
|
+
}
|
|
169
|
+
function truncateUtf8Prefix(text, maxBytes) {
|
|
170
|
+
let result = "";
|
|
171
|
+
let bytes = 0;
|
|
172
|
+
for (const codePoint of text) {
|
|
173
|
+
const size = Buffer.byteLength(codePoint);
|
|
174
|
+
if (bytes + size > maxBytes)
|
|
175
|
+
break;
|
|
176
|
+
result += codePoint;
|
|
177
|
+
bytes += size;
|
|
178
|
+
}
|
|
179
|
+
return result;
|
|
180
|
+
}
|
|
181
|
+
function wrapTool(definition, guard, consumeResult) {
|
|
182
|
+
return {
|
|
183
|
+
...definition,
|
|
184
|
+
async execute(...args) {
|
|
185
|
+
try {
|
|
186
|
+
if (!guard.beforeToolOperation())
|
|
187
|
+
return guard.operationLimitGuidance();
|
|
188
|
+
const result = await definition.execute(...args);
|
|
189
|
+
return consumeResult ? guard.limitToolResult(result) : result;
|
|
190
|
+
}
|
|
191
|
+
catch (error) {
|
|
192
|
+
if (error instanceof PiReadBudgetSoftLimitError) {
|
|
193
|
+
return guard.operationLimitGuidance();
|
|
194
|
+
}
|
|
195
|
+
if (error instanceof PiReadAccessDeniedError) {
|
|
196
|
+
return guard.readAccessGuidance();
|
|
197
|
+
}
|
|
198
|
+
throw error;
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Override Pi's built-in read-only tools with SDK definitions that meter the
|
|
205
|
+
* content before it reaches the model. The read tool caps filesystem bytes at
|
|
206
|
+
* the operation boundary; grep/find/ls have their returned payload clipped
|
|
207
|
+
* before the agent receives it. This is SDK-only by design: the CLI backend
|
|
208
|
+
* cannot inject same-name built-in overrides safely.
|
|
209
|
+
*/
|
|
210
|
+
export async function createPiReadBudgetCustomTools(input) {
|
|
211
|
+
const sdk = (await import("@earendil-works/pi-coding-agent"));
|
|
212
|
+
const createReadToolDefinition = sdk.createReadToolDefinition;
|
|
213
|
+
const createGrepToolDefinition = sdk.createGrepToolDefinition;
|
|
214
|
+
const createFindToolDefinition = sdk.createFindToolDefinition;
|
|
215
|
+
const createLsToolDefinition = sdk.createLsToolDefinition;
|
|
216
|
+
if (typeof createReadToolDefinition !== "function" ||
|
|
217
|
+
typeof createGrepToolDefinition !== "function" ||
|
|
218
|
+
typeof createFindToolDefinition !== "function" ||
|
|
219
|
+
typeof createLsToolDefinition !== "function") {
|
|
220
|
+
throw new Error("pi read budget policy unavailable: SDK read/grep/find/ls tool factories missing");
|
|
221
|
+
}
|
|
222
|
+
const guard = new PiReadBudgetGuard(input.budget, input.readAccess);
|
|
223
|
+
const read = wrapTool(createReadToolDefinition(input.repoRoot, {
|
|
224
|
+
operations: {
|
|
225
|
+
readFile: (absolutePath) => guard.readFile(absolutePath),
|
|
226
|
+
access: (absolutePath) => guard.access(absolutePath),
|
|
227
|
+
},
|
|
228
|
+
}), guard, false);
|
|
229
|
+
const grep = wrapTool(createGrepToolDefinition(input.repoRoot), guard, true);
|
|
230
|
+
const find = wrapTool(createFindToolDefinition(input.repoRoot), guard, true);
|
|
231
|
+
const ls = wrapTool(createLsToolDefinition(input.repoRoot), guard, true);
|
|
232
|
+
if (read.name !== "read" ||
|
|
233
|
+
grep.name !== "grep" ||
|
|
234
|
+
find.name !== "find" ||
|
|
235
|
+
ls.name !== "ls") {
|
|
236
|
+
throw new Error("pi read budget policy unavailable: SDK tool name mismatch");
|
|
237
|
+
}
|
|
238
|
+
return { customTools: [read, grep, find, ls], issues: () => guard.issues() };
|
|
239
|
+
}
|