@tea-agent/loop-agent 0.39.0-beta.0 → 0.39.0-beta.10
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 +4 -1
- package/CHANGELOG.md +248 -95
- package/README.md +9 -5
- package/bin/loop-agent.js +7 -3
- package/dist/application/task-lifecycle/advance.js +12 -0
- package/dist/application/task-lifecycle/recommendations.js +13 -2
- package/dist/build-stamp.json +3 -3
- package/dist/cli/command-definitions.js +23 -5
- package/dist/cli/program.js +21 -2
- package/dist/cli/update/notifier.js +2 -2
- package/dist/cli/update/runtime-activity.js +1 -29
- package/dist/cli.js +2 -1
- package/dist/commands/client-recovery.js +3 -0
- package/dist/commands/dag-follow-up.js +138 -0
- package/dist/commands/dag-rerun.js +55 -1
- package/dist/commands/init-model-catalog.js +464 -0
- package/dist/commands/init-upgrade.js +265 -97
- package/dist/commands/init.js +455 -28
- package/dist/commands/inspect-next.js +8 -0
- package/dist/commands/task-advance.js +19 -0
- package/dist/executors/dag-pi-executor.js +2306 -61
- package/dist/executors/pi-executor.js +7 -0
- package/dist/executors/pi-extension-resolver.js +233 -0
- package/dist/executors/pi-playwright-cli-tool.js +74 -28
- package/dist/executors/pi-read-budget-policy.js +239 -0
- package/dist/executors/pi-sdk-executor.js +180 -33
- package/dist/executors/shell-executor.js +1249 -224
- package/dist/executors/shell-write-guard.js +14 -0
- package/dist/executors/workspace-write-snapshot.js +68 -0
- package/dist/infrastructure/harness/atomic-write.js +23 -0
- package/dist/shared/dag-failure-category.js +150 -0
- package/dist/shared/dag-prompt-override.js +27 -0
- package/dist/shared/openspec-spec.js +70 -4
- package/dist/shared/operator/capabilities.js +39 -0
- package/dist/shared/playwright-cli-command-policy.js +15 -0
- package/dist/shared/update/console-notifier.js +100 -0
- package/dist/{cli → shared}/update/npm-client.js +70 -15
- package/dist/{cli → shared}/update/state.js +41 -13
- package/dist/task/config-types.js +50 -5
- package/dist/task/contract/apply.js +11 -1
- package/dist/task/contract/constants.js +2 -0
- package/dist/task/contract/hash.js +3 -0
- package/dist/task/contract/observe.js +25 -4
- package/dist/task/contract/paths.js +2 -1
- package/dist/task/contract/project.js +18 -1
- package/dist/task/contract/schema.js +4 -1
- package/dist/task/contract/transaction.js +12 -0
- package/dist/task/frontend-project-capability.js +199 -18
- package/dist/task/source-prepare/completeness.js +188 -0
- package/dist/task/source-prepare/fragment-inventory.js +477 -0
- package/dist/task/source-prepare/index.js +3 -0
- package/dist/task/source-prepare/ledger-reconciliation.js +127 -0
- package/dist/task/source-prepare/ledger-review.js +214 -0
- package/dist/task/source-prepare/ledger.js +545 -0
- package/dist/task/source-prepare/parse-intent.js +24 -4
- package/dist/task/source-prepare/prepare.js +298 -1
- package/dist/task/source-prepare/semantic-intake.js +25 -5
- package/dist/task/source-prepare/source-fidelity-pi.js +384 -0
- package/dist/task/source-prepare/types.js +22 -0
- package/dist/task/source-references.js +22 -1
- package/dist/worker/cli.js +18 -2
- package/dist/worker/console/chat/chat-event-store.js +62 -4
- package/dist/worker/console/chat/context-panel.js +7 -0
- package/dist/worker/console/chat/deferred-turn.js +12 -0
- package/dist/worker/console/chat/operation-card.js +8 -1
- package/dist/worker/console/chat/pi-console-config.js +81 -10
- package/dist/worker/console/chat/pi-runtime.js +264 -16
- package/dist/worker/console/chat/provider-error.js +98 -0
- package/dist/worker/console/chat/routes.js +298 -32
- package/dist/worker/console/chat/session-stats.js +179 -0
- package/dist/worker/console/chat/session-store.js +93 -63
- package/dist/worker/console/chat/todos.js +115 -0
- package/dist/worker/console/chat/tool-preview.js +42 -0
- package/dist/worker/console/chat/turn-process.js +20 -55
- package/dist/worker/console/chat/user-questions.js +266 -0
- package/dist/worker/console/chat/workspace-landing.js +14 -0
- package/dist/worker/console/console-handoff.js +82 -0
- package/dist/worker/console/console-update-and-init.js +115 -0
- package/dist/worker/console/console-update-runtime.js +84 -0
- package/dist/worker/console/dag-execution-receipt.js +33 -0
- package/dist/worker/console/draft-store.js +49 -0
- 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/inspect-split.js +18 -0
- package/dist/worker/console/native-directory-picker.js +13 -0
- package/dist/worker/console/operation-run-facts.js +19 -3
- package/dist/worker/console/operation-store.js +227 -7
- package/dist/worker/console/operator-actions.js +388 -0
- package/dist/worker/console/operator-surface-health.js +1 -0
- package/dist/worker/console/operator-user-error.js +2 -2
- package/dist/worker/console/prd-intake-bridge.js +13 -0
- package/dist/worker/console/routes.js +355 -3
- package/dist/worker/console/security.js +67 -13
- package/dist/worker/console/server.js +609 -164
- package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-C4kVYweA.js → abnfDiagram-N423BO3Z-BAsjg7ew.js} +1 -1
- package/dist/worker/console/static/assets/{arc-Bj2M8iO5.js → arc-CyIlrwZw.js} +1 -1
- package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-CLlXe4-6.js → architectureDiagram-T3A2C74G-Bo4tobhH.js} +1 -1
- package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-psEp5xH0.js → blockDiagram-VBNYF7ZC-Dfpow9gu.js} +1 -1
- package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-DeKcOCGJ.js → c4Diagram-5PPSVZJV-DPmzG_B4.js} +1 -1
- package/dist/worker/console/static/assets/channel-DSrJAn0-.js +1 -0
- package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-K0C744p1.js → chunk-2GRJ4B5K-pKQpB1UW.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-xbNw4J9-.js → chunk-2Q5K7J3B-5n9YYquZ.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5RXB4S5H-DjLaSDUO.js → chunk-5RXB4S5H-DP3CtA2a.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5VM5RSS4-CtiPlKel.js → chunk-5VM5RSS4-DYxMJPUy.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-DZtolir7.js → chunk-6Q2QTUOP-CS3D50Io.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-GF5L2VYU-CPcdNeew.js → chunk-GF5L2VYU-gSdDfo5_.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-JWPE2WC7-NgHc6V37.js → chunk-JWPE2WC7-A48q0ZNt.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-KBJHAD2P-DQ_T-hg8.js → chunk-KBJHAD2P-ow8Mm3DY.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-RYQCIY6F-DgLsxcVP.js → chunk-RYQCIY6F-CMKfLWYE.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-XXDRQBXY-UrVoM9z1.js → chunk-XXDRQBXY-BiTBdQPX.js} +1 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-DeMmPl0_.js +1 -0
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-DeMmPl0_.js +1 -0
- package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-CLkYvTb3.js → cose-bilkent-JH36ORCC-Cm7exRz_.js} +1 -1
- package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-BwT_xKrE.js → cynefin-VYW2F7L2-D9O5qGOu.js} +1 -1
- package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-Bi9tuzif.js → cynefinDiagram-MW4NZA55-CkvQnako.js} +1 -1
- package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-BCIqkWBV.js → dagre-VZM6K2ZE-B1rzp7CB.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-7IWD3JNH-Dip6l9_Z.js → diagram-7IWD3JNH-BP07Ipcc.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-B-xkh_wK.js → diagram-B4RE2ZJO-BlPzweQb.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-LBJQPF4R-DZO0kTt_.js → diagram-LBJQPF4R-CxPa7n0S.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-Q27KOJAE-D6ZplNbZ.js → diagram-Q27KOJAE-CMTZs53A.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-UB23O5K3-BPekbhoS.js → diagram-UB23O5K3-CxG_X52r.js} +1 -1
- package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-BtmaJpK5.js → ebnfDiagram-BXEA7PRR-D8axtJM0.js} +1 -1
- package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-6DS0Xc44.js → erDiagram-JOGREHBK-DIsGzn7b.js} +1 -1
- package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-CihnROSm.js → flowDiagram-UKHOOZJN-CU9zkDG0.js} +1 -1
- package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-CZC4zOE2.js → ganttDiagram-PKOTCBZU-DCjTmz5P.js} +1 -1
- package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-Dq1fhzGN.js → gitGraphDiagram-DS77QQ5N-BksdmFzg.js} +1 -1
- package/dist/worker/console/static/assets/index-B-O5ChYq.css +1 -0
- package/dist/worker/console/static/assets/index-CfnY8AQx.js +407 -0
- package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-DlSl4BGx.js → infoDiagram-6WML65LV-CGzzzJtL.js} +1 -1
- package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-snnzFl_U.js → ishikawaDiagram-WSZJBQD7-BdseB80N.js} +1 -1
- package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-BDE7qpMx.js → journeyDiagram-NVQOT4AX-DM9gsgha.js} +1 -1
- package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-CD2Ci04G.js → kanban-definition-27J2QSJJ-3q-_9R2b.js} +1 -1
- package/dist/worker/console/static/assets/{linear-DdnapKIH.js → linear-B8N-Mxsd.js} +1 -1
- package/dist/worker/console/static/assets/{mermaid.core-BVjAT9b8.js → mermaid.core-EPIHUUsu.js} +5 -5
- package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-D0yJk-zA.js → mindmap-definition-FAOFIHXS-CxwO12aa.js} +1 -1
- package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-BVo9tFP-.js → pegDiagram-VL7TDLO6-bPqbVX6Y.js} +1 -1
- package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-DnOV-mZ_.js → pieDiagram-7S7Q4E2Y-KzqIvzeX.js} +1 -1
- package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-CzUJo58i.js → quadrantDiagram-CIZ2JOQS-CyofpWiV.js} +1 -1
- package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-Bvikrolh.js → railroadDiagram-AXF67PYL-cTWJvLTP.js} +1 -1
- package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-DtaSVCap.js → requirementDiagram-LRYGKXZP-BK--q27B.js} +1 -1
- package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-C2c9A0wW.js → sankeyDiagram-W5VNT64P-C0SDOHXK.js} +1 -1
- package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-DmXJcU7r.js → sequenceDiagram-SI44F4Z6-Cong6YIo.js} +1 -1
- package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-B4GUFW92.js → sizeCapture-X5ZJPWSS-DUVkgZx8.js} +1 -1
- package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-Dsad2MXf.js → stateDiagram-OKZ733FA-C7XgxuZg.js} +1 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-Dzbnd5oX.js +1 -0
- package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-DGq48Fbi.js → swimlanes-SLNWSIFB-D9Ayvwcy.js} +2 -2
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-BY0hHk6G.js +8 -0
- package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-CSSi6OFf.js → timeline-definition-Z64GVDOM-Byb000cH.js} +1 -1
- package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-BqyzPrWv.js → vennDiagram-T6HMQDX7-DMLegPt4.js} +1 -1
- package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-DlznVb6S.js → wardleyDiagram-T6FBY63Y-ChMMeOsP.js} +1 -1
- package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-CfBcgJ_K.js → xychartDiagram-ELKLHX3M-bEMEPisW.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/console-types.js +68 -4
- package/dist/worker/console/static-src/app/useConsoleShell.js +30 -12
- package/dist/worker/console/static-src/app/useOperatorActions.js +41 -6
- package/dist/worker/console/static-src/app/useRecoveryConsole.js +45 -10
- package/dist/worker/console/static-src/app/useRunProgress.js +47 -0
- package/dist/worker/console/static-src/app/useTaskWizard.js +74 -2
- package/dist/worker/console/static-src/night/useNightBoard.js +8 -5
- package/dist/worker/console/static-src/operator-chat/cards/failure-category-advice.js +25 -0
- package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +140 -8
- package/dist/worker/console/static-src/operator-chat/details-dag-actions.js +122 -0
- package/dist/worker/console/static-src/operator-chat/input-history.js +76 -0
- package/dist/worker/console/static-src/operator-chat/mutation-gate.js +1 -1
- package/dist/worker/console/static-src/operator-chat/refs.js +3 -0
- package/dist/worker/console/static-src/operator-chat/runtime-selection-labels.js +27 -0
- package/dist/worker/console/static-src/operator-chat/turn-submission.js +16 -3
- package/dist/worker/console/static-src/operator-chat/useChatSessions.js +168 -72
- package/dist/worker/console/static-src/operator-chat/useChatStream.js +102 -21
- package/dist/worker/console/static-src/operator-chat/useChatThread.js +184 -4
- package/dist/worker/console/static-src/operator-chat/useComposer.js +32 -0
- package/dist/worker/console/static-src/operator-chat/useRepoBrowser.js +63 -9
- package/dist/worker/console/static-src/operator-chat/useWorkspaceBrowserGate.js +4 -0
- package/dist/worker/console/static-src/operator-chat/workspace-layout-mode.js +3 -3
- package/dist/worker/console/static-src/pages/tasks/run-id-resolution.js +79 -0
- package/dist/worker/console/static-src/pages/tasks/run-ownership-verify.js +23 -0
- package/dist/worker/console/static-src/pages/tasks/run-panel-progress.js +110 -0
- package/dist/worker/console/static-src/shell/useWorkspaces.js +299 -0
- package/dist/worker/console/static-src/shell/workspace-route.js +337 -0
- package/dist/worker/console/workspace-context.js +344 -0
- package/dist/worker/console/workspace-registry.js +214 -0
- package/dist/worker/loop-agent/loop-agent-client.js +7 -3
- package/dist/worker/materialize/frontend-split-task-materializer.js +72 -0
- package/dist/worker/materialize/harness-task-lineage.js +5 -2
- package/dist/worker/observability/init-runtime-activity.js +26 -0
- package/dist/worker/observability/read-model.js +22 -0
- package/dist/worker/observe/node-input.js +160 -3
- package/dist/worker/observe/node-process.js +377 -0
- package/dist/worker/observe/routes.js +224 -3
- package/dist/worker/observe/server.js +4 -0
- package/dist/worker/observe/shell-handler-keys.js +34 -0
- package/dist/worker/observe/static/api.js +90 -4
- package/dist/worker/observe/static/app.js +18 -70
- package/dist/worker/observe/static/constants.js +8 -1
- package/dist/worker/observe/static/dag-history-labels.js +4 -0
- package/dist/worker/observe/static/dag-node-purpose.d.ts +6 -0
- package/dist/worker/observe/static/dag-node-purpose.js +208 -0
- package/dist/worker/observe/static/format.js +60 -0
- package/dist/worker/observe/static/index.html +6 -1
- package/dist/worker/observe/static/inspect-workspace.js +307 -0
- package/dist/worker/observe/static/markdown-render.js +20 -1
- package/dist/worker/observe/static/operator-chrome.css +145 -20
- package/dist/worker/observe/static/operator-chrome.d.ts +20 -3
- package/dist/worker/observe/static/operator-chrome.js +330 -96
- package/dist/worker/observe/static/prompt-restart-candidates.d.ts +18 -0
- package/dist/worker/observe/static/prompt-restart-candidates.js +36 -0
- package/dist/worker/observe/static/router.d.ts +46 -0
- package/dist/worker/observe/static/router.js +25 -1
- package/dist/worker/observe/static/state.d.ts +50 -0
- package/dist/worker/observe/static/state.js +184 -1
- package/dist/worker/observe/static/styles.css +395 -0
- package/dist/worker/observe/static/views/dag-graph.js +4 -2
- package/dist/worker/observe/static/views/dag-inspector.js +1067 -9
- package/dist/worker/observe/static/views/dag.d.ts +13 -0
- package/dist/worker/observe/static/views/dag.js +14 -5
- package/dist/worker/observe/static/views/dashboard.js +6 -4
- package/dist/worker/observe/static/views/failures.js +5 -2
- package/dist/worker/observe/static/views/night.js +2 -2
- package/dist/worker/observe/static/views/pool.js +1 -0
- package/dist/worker/observe/static/views/run.js +3 -1
- package/dist/worker/observe/static/views/session-timeline.js +78 -9
- package/dist/worker/observe/static/views/task.js +56 -1
- package/dist/workflows/dag/backend-test-case-coverage-analysis.js +49 -3
- package/dist/workflows/dag/backend-test-markdown-workflow.js +176 -1
- package/dist/workflows/dag/backend-test-pytest-collection.js +98 -14
- package/dist/workflows/dag/backend-test-writer-completeness.js +10 -5
- package/dist/workflows/dag/contract-output-registry.js +15 -0
- package/dist/workflows/dag/contract-validator-registrations.js +1 -2
- package/dist/workflows/dag/dynamic-runtime/loop-until.js +1 -1
- package/dist/workflows/dag/dynamic-runtime/map.js +1 -1
- package/dist/workflows/dag/failure-category.js +7 -116
- 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 +534 -178
- package/dist/workflows/dag/frontend-plan-render.js +24 -0
- package/dist/workflows/dag/frontend-prewrite-gate.js +371 -393
- 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 +202 -0
- package/dist/workflows/dag/frontend-recovery-lineage.js +178 -0
- package/dist/workflows/dag/frontend-recovery-plan.js +17 -10
- package/dist/workflows/dag/frontend-recovery-run.js +33 -20
- package/dist/workflows/dag/frontend-repair.js +7 -424
- package/dist/workflows/dag/frontend-review-context.js +288 -14
- package/dist/workflows/dag/frontend-review-findings.js +270 -0
- package/dist/workflows/dag/frontend-risk.js +15 -2
- package/dist/workflows/dag/frontend-shadow-dual-write.js +814 -0
- package/dist/workflows/dag/frontend-shape-capsule-store.js +191 -0
- package/dist/workflows/dag/frontend-shape-facts.js +409 -0
- package/dist/workflows/dag/frontend-shape.js +427 -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-test-case-checklist.js +30 -4
- package/dist/workflows/dag/frontend-test-case-manifest.js +11 -4
- package/dist/workflows/dag/frontend-test-case-quality.js +11 -16
- package/dist/workflows/dag/frontend-test-environment-probe.js +230 -0
- package/dist/workflows/dag/frontend-test-html-report.js +3 -1
- package/dist/workflows/dag/frontend-test-l5-report.js +3 -1
- package/dist/workflows/dag/frontend-test-layout.js +159 -0
- package/dist/workflows/dag/frontend-test-markdown.js +61 -0
- package/dist/workflows/dag/frontend-test-result-contract.js +188 -42
- package/dist/workflows/dag/frontend-test-standard-scenarios.js +70 -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 +52 -17
- package/dist/workflows/dag/frontend-worktree-diff.js +250 -17
- package/dist/workflows/dag/frontend-writer-admission.js +272 -0
- package/dist/workflows/dag/frontend-writer-status.js +244 -0
- package/dist/workflows/dag/init-hybrid.js +984 -618
- package/dist/workflows/dag/interrupt-request.js +10 -3
- package/dist/workflows/dag/lifecycle.js +3 -3
- package/dist/workflows/dag/node-execution.js +468 -34
- package/dist/workflows/dag/prompt.js +44 -19
- package/dist/workflows/dag/recovery-lease.js +80 -0
- package/dist/workflows/dag/report.js +37 -1
- package/dist/workflows/dag/rerun-feedback.js +124 -1
- package/dist/workflows/dag/rerun-plan.js +144 -5
- package/dist/workflows/dag/rerun-run.js +81 -6
- package/dist/workflows/dag/rerun-task.js +29 -0
- package/dist/workflows/dag/retry-policy.js +318 -8
- package/dist/workflows/dag/runner.js +429 -122
- package/dist/workflows/dag/scheduler.js +114 -16
- package/dist/workflows/dag/structured-output-repair.js +712 -0
- package/dist/workflows/dag/types.js +321 -31
- package/dist/workflows/dag/upstream-artifacts.js +0 -4
- package/dist/workflows/dag/validate.js +92 -32
- package/docs/README.md +2 -0
- package/docs/architecture/evolution.md +45 -0
- package/docs/init-surface.manifest.json +9 -0
- package/docs/operations/README.md +1 -1
- package/docs/operations/local-development-environment.md +21 -0
- package/docs/templates/README.md +2 -1
- package/docs/templates/agent-dag-report.schema.json +8 -2
- package/docs/templates/agent-dag.schema.json +45 -1
- package/docs/templates/frontend-implementation-contract.schema.json +684 -24
- package/docs/templates/frontend-test-case-checklist.md +2 -2
- package/docs/templates/frontend-test-dag.json +8 -10
- package/docs/templates/frontend-test-dag.retrieve-context.prompt.md +1 -1
- package/docs/templates/init-managed-agents.md +13 -3
- package/docs/templates/spec-registry.schema.json +45 -0
- package/harness.json +3 -3
- package/package.json +7 -1
- package/scripts/next-info.mjs +356 -0
- package/scripts/next-publish-gate.mjs +238 -0
- package/scripts/release-source-binding.mjs +251 -0
- package/skills/codebase-scout/SKILL.md +1 -1
- package/skills/fe-test-ui-scout/SKILL.md +65 -0
- package/skills/fe-test-ui-scout/references/ledger-schema.md +62 -0
- package/skills/fe-test-ui-scout/references/recon-protocol.md +54 -0
- package/skills/frontend-bounded-implement/SKILL.md +8 -14
- package/skills/frontend-design-review/SKILL.md +20 -41
- package/skills/frontend-implementation/SKILL.md +3 -4
- package/skills/frontend-implementation/references/design-spec.md +15 -10
- package/skills/frontend-implementation/references/node-contracts.md +23 -13
- package/skills/frontend-review/SKILL.md +22 -14
- package/skills/frontend-review/references/review-findings.md +6 -7
- package/skills/loop-agent/references/command-reference.md +12 -4
- package/skills/loop-agent/references/hybrid-dag.md +8 -1
- package/skills/playwright-cli/SKILL.md +23 -1
- package/skills/playwright-cli-case-generator/SKILL.md +29 -8
- package/dist/worker/console/static/assets/channel-CPF4N7pf.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-C2DwA_Y1.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-C2DwA_Y1.js +0 -1
- package/dist/worker/console/static/assets/index-DTZOKgAn.js +0 -404
- package/dist/worker/console/static/assets/index-Ya5FE7cD.css +0 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-B8FB_cNk.js +0 -1
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-CrZYaWfx.js +0 -8
|
@@ -2,6 +2,7 @@ import { createHash } from "node:crypto";
|
|
|
2
2
|
import { access, copyFile, mkdir, readdir, readFile } from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { writeJsonAtomic } from "../../infrastructure/harness/atomic-write.js";
|
|
5
|
+
import { composeDagPromptOverridePrompt, isDagRerunPromptOverrideEnabled, } from "../../shared/dag-prompt-override.js";
|
|
5
6
|
import { resolveRunningControllerIdentity } from "../../shared/package-metadata.js";
|
|
6
7
|
import { readControllerIdentityArtifact, captureControllerIdentity } from "./controller-identity.js";
|
|
7
8
|
import { DAG_RUNS_DIR, getDagRunDir, isDagNonExecutionLifecycle, locateDagRun, readDagRunSpec, readDagRunState, } from "./lifecycle.js";
|
|
@@ -11,6 +12,7 @@ import { prepareActiveRunDir, writeNodeRecord, writeRunSpec, writeRunState, } fr
|
|
|
11
12
|
import { cloneParentSkillSnapshotForContinuation, readSkillSnapshot, } from "./skill-snapshot.js";
|
|
12
13
|
import { topoSortToRanks } from "./topo.js";
|
|
13
14
|
import { captureWorkspaceCheckpoint, readWorkspaceCheckpoint, WORKSPACE_CHECKPOINT_START_REL, WORKSPACE_CHECKPOINT_TERMINAL_REL, writeWorkspaceCheckpoint, } from "./workspace-checkpoint.js";
|
|
15
|
+
import { acquireDagRecoveryLease, bindDagRecoveryLeaseExecution, } from "./recovery-lease.js";
|
|
14
16
|
export const RERUN_PLAN_REL_PATH = ".runtime/rerun-plan.json";
|
|
15
17
|
export const IMPORT_MANIFEST_REL_PATH = ".runtime/import-manifest.json";
|
|
16
18
|
export const WORKER_ASSOCIATION_REL_PATH = ".runtime/worker-association.json";
|
|
@@ -190,6 +192,8 @@ export async function planDagRerun(input) {
|
|
|
190
192
|
parentSpec: nonCompletedSpec,
|
|
191
193
|
parentState: nonCompletedState,
|
|
192
194
|
parentLifecycle,
|
|
195
|
+
promptOverrides: input.promptOverrides,
|
|
196
|
+
promptOverrideEnabled: isDagRerunPromptOverrideEnabled(),
|
|
193
197
|
workerManaged: nonCompletedWorkerHints.workerManaged,
|
|
194
198
|
workerAssociation: nonCompletedWorkerHints.workerManaged
|
|
195
199
|
? {
|
|
@@ -229,6 +233,8 @@ export async function planDagRerun(input) {
|
|
|
229
233
|
parentTerminalWorkspace,
|
|
230
234
|
currentWorkspace,
|
|
231
235
|
skillSnapshotOk,
|
|
236
|
+
promptOverrides: input.promptOverrides,
|
|
237
|
+
promptOverrideEnabled: isDagRerunPromptOverrideEnabled(),
|
|
232
238
|
workerManaged: workerHints.workerManaged,
|
|
233
239
|
workerAssociation: workerHints.workerManaged
|
|
234
240
|
? {
|
|
@@ -384,15 +390,57 @@ function buildPendingNodeRecord(task) {
|
|
|
384
390
|
...(task.outputMode ? { outputMode: task.outputMode } : {}),
|
|
385
391
|
};
|
|
386
392
|
}
|
|
393
|
+
/**
|
|
394
|
+
* Stage the continuation spec with operator prompt overrides applied. The
|
|
395
|
+
* parent spec stays frozen; every override must match the plan entry (sha256
|
|
396
|
+
* of the composed final prompt and of the parent base prompt) so the
|
|
397
|
+
* two-phase planHash remains the single source of truth for what changed.
|
|
398
|
+
* "append" entries keep the frozen base and append the operator addendum in a
|
|
399
|
+
* marked block; "replace" entries swap the whole prompt.
|
|
400
|
+
*/
|
|
401
|
+
function applyPromptOverridesToSpec(input) {
|
|
402
|
+
const planned = new Map((input.plan.promptOverrides ?? []).map((entry) => [entry.nodeId, entry]));
|
|
403
|
+
const spec = structuredClone(input.spec);
|
|
404
|
+
for (const override of input.overrides) {
|
|
405
|
+
const entry = planned.get(override.nodeId);
|
|
406
|
+
if (!entry) {
|
|
407
|
+
throw new Error(`prompt override is not present in the rerun plan: ${override.nodeId}`);
|
|
408
|
+
}
|
|
409
|
+
const task = spec.tasks.find((candidate) => candidate.id === override.nodeId);
|
|
410
|
+
if (!task) {
|
|
411
|
+
throw new Error(`prompt override node missing from spec: ${override.nodeId}`);
|
|
412
|
+
}
|
|
413
|
+
if (sha256Hex(task.subtask_prompt) !== entry.basePromptSha256) {
|
|
414
|
+
throw new Error(`prompt override base prompt drifted from plan: ${override.nodeId}`);
|
|
415
|
+
}
|
|
416
|
+
const finalPrompt = composeDagPromptOverridePrompt({
|
|
417
|
+
basePrompt: task.subtask_prompt,
|
|
418
|
+
text: override.prompt,
|
|
419
|
+
mode: override.mode === "append" ? "append" : "replace",
|
|
420
|
+
});
|
|
421
|
+
if (sha256Hex(finalPrompt) !== entry.promptSha256) {
|
|
422
|
+
throw new Error(`prompt override text does not match the planned sha256: ${override.nodeId}`);
|
|
423
|
+
}
|
|
424
|
+
task.subtask_prompt = finalPrompt;
|
|
425
|
+
}
|
|
426
|
+
return spec;
|
|
427
|
+
}
|
|
387
428
|
async function stageContinuationRun(input) {
|
|
388
|
-
const
|
|
389
|
-
|
|
429
|
+
const specForRun = input.promptOverrides !== undefined && input.promptOverrides.length > 0
|
|
430
|
+
? applyPromptOverridesToSpec({
|
|
431
|
+
spec: input.parentSpec,
|
|
432
|
+
plan: input.plan,
|
|
433
|
+
overrides: input.promptOverrides,
|
|
434
|
+
})
|
|
435
|
+
: input.parentSpec;
|
|
436
|
+
const { ranks } = topoSortToRanks(specForRun);
|
|
437
|
+
const runId = await buildDagRunId(specForRun, { cwd: input.cwd });
|
|
390
438
|
const runDir = getDagRunDir(input.cwd, "active", runId);
|
|
391
439
|
await prepareActiveRunDir(runDir);
|
|
392
|
-
await writeRunSpec(runDir,
|
|
440
|
+
await writeRunSpec(runDir, specForRun);
|
|
393
441
|
const resetSet = new Set(input.plan.resetNodeIds);
|
|
394
442
|
const importedSet = new Set(input.plan.importedNodeIds);
|
|
395
|
-
const tasksById = new Map(
|
|
443
|
+
const tasksById = new Map(specForRun.tasks.map((task) => [task.id, task]));
|
|
396
444
|
const importManifestNodes = [];
|
|
397
445
|
const nodes = {};
|
|
398
446
|
for (const nodeId of input.plan.importedNodeIds) {
|
|
@@ -433,6 +481,9 @@ async function stageContinuationRun(input) {
|
|
|
433
481
|
reason: input.reason,
|
|
434
482
|
requestId: input.requestId,
|
|
435
483
|
planHash: input.plan.planHash,
|
|
484
|
+
...(input.plan.promptOverrides
|
|
485
|
+
? { promptOverrides: input.plan.promptOverrides }
|
|
486
|
+
: {}),
|
|
436
487
|
createdAt,
|
|
437
488
|
};
|
|
438
489
|
const state = {
|
|
@@ -482,7 +533,7 @@ async function stageContinuationRun(input) {
|
|
|
482
533
|
await writeJsonAtomic(path.join(runDir, IMPORT_MANIFEST_REL_PATH), importManifest);
|
|
483
534
|
await writeJsonAtomic(path.join(runDir, RERUN_PLAN_REL_PATH), input.plan);
|
|
484
535
|
await writeRunState(runDir, state);
|
|
485
|
-
return { runId, runDir, state };
|
|
536
|
+
return { runId, runDir, state, spec: specForRun };
|
|
486
537
|
}
|
|
487
538
|
export async function executeDagRerun(input) {
|
|
488
539
|
const existing = await readExistingOperatorRequest(input.cwd, input.requestId);
|
|
@@ -493,6 +544,7 @@ export async function executeDagRerun(input) {
|
|
|
493
544
|
cwd: input.cwd,
|
|
494
545
|
parentRunId: input.parentRunId,
|
|
495
546
|
selectedNodeId: input.selectedNodeId,
|
|
547
|
+
promptOverrides: input.promptOverrides,
|
|
496
548
|
});
|
|
497
549
|
if (plan.planHash !== input.planHash) {
|
|
498
550
|
return {
|
|
@@ -521,6 +573,20 @@ export async function executeDagRerun(input) {
|
|
|
521
573
|
}
|
|
522
574
|
const parentSpec = await readDagRunSpec(located.runDir);
|
|
523
575
|
const parentState = await readDagRunState(located.runDir);
|
|
576
|
+
const recoveryLease = await acquireDagRecoveryLease({
|
|
577
|
+
cwd: input.cwd,
|
|
578
|
+
parentRunId: input.parentRunId,
|
|
579
|
+
requestId: input.requestId,
|
|
580
|
+
kind: "rerun-from-node",
|
|
581
|
+
});
|
|
582
|
+
if (recoveryLease.kind === "held") {
|
|
583
|
+
return {
|
|
584
|
+
ok: false,
|
|
585
|
+
plan,
|
|
586
|
+
errorCode: "RECOVERY_LEASE_HELD",
|
|
587
|
+
message: `parent run recovery is already claimed by ${recoveryLease.lease.kind} request ${recoveryLease.lease.requestId}`,
|
|
588
|
+
};
|
|
589
|
+
}
|
|
524
590
|
const staged = await stageContinuationRun({
|
|
525
591
|
cwd: input.cwd,
|
|
526
592
|
parentRunDir: located.runDir,
|
|
@@ -530,10 +596,19 @@ export async function executeDagRerun(input) {
|
|
|
530
596
|
plan,
|
|
531
597
|
reason: input.reason,
|
|
532
598
|
requestId: input.requestId,
|
|
599
|
+
promptOverrides: input.promptOverrides,
|
|
600
|
+
});
|
|
601
|
+
// Stage is non-executing; bind the child identity immediately before handing
|
|
602
|
+
// it to the runner so no recovery DAG can start without durable parent
|
|
603
|
+
// lineage ownership.
|
|
604
|
+
await bindDagRecoveryLeaseExecution({
|
|
605
|
+
leasePath: recoveryLease.leasePath,
|
|
606
|
+
lease: recoveryLease.lease,
|
|
607
|
+
executionRef: staged.state.runId,
|
|
533
608
|
});
|
|
534
609
|
const continuationOptions = {
|
|
535
610
|
cwd: input.cwd,
|
|
536
|
-
spec:
|
|
611
|
+
spec: staged.spec,
|
|
537
612
|
state: staged.state,
|
|
538
613
|
runDir: staged.runDir,
|
|
539
614
|
...(input.maxConcurrent !== undefined
|
|
@@ -4,6 +4,7 @@ import { generateTaskDagUseCase } from "../../application/dag/generate-task-dag.
|
|
|
4
4
|
import { writeJsonAtomic } from "../../infrastructure/harness/atomic-write.js";
|
|
5
5
|
import { DAG_RUNS_DIR, isTerminalDagRunStatus, locateDagRun, readDagRunSpec, readDagRunState, } from "./lifecycle.js";
|
|
6
6
|
import { deriveDagRerunFeedback } from "./rerun-feedback.js";
|
|
7
|
+
import { acquireDagRecoveryLease, bindDagRecoveryLeaseExecution, } from "./recovery-lease.js";
|
|
7
8
|
import { parseDagSpec, } from "./types.js";
|
|
8
9
|
export const RERUN_TASK_LINEAGE_REL_PATH = ".runtime/rerun-task-lineage.json";
|
|
9
10
|
export function parseDagRerunTaskArgs(args) {
|
|
@@ -369,6 +370,34 @@ export async function rerunStandaloneTask(input) {
|
|
|
369
370
|
}
|
|
370
371
|
}
|
|
371
372
|
}
|
|
373
|
+
const recoveryLease = execute
|
|
374
|
+
? await acquireDagRecoveryLease({
|
|
375
|
+
cwd: input.cwd,
|
|
376
|
+
parentRunId: input.parentRunId,
|
|
377
|
+
requestId: input.requestId,
|
|
378
|
+
kind: "standalone-task-rerun",
|
|
379
|
+
})
|
|
380
|
+
: undefined;
|
|
381
|
+
if (recoveryLease?.kind === "held") {
|
|
382
|
+
return blockedResult({
|
|
383
|
+
parentRunId: input.parentRunId,
|
|
384
|
+
reason: input.reason,
|
|
385
|
+
requestId: input.requestId,
|
|
386
|
+
blockedReason: "recovery-lease-held",
|
|
387
|
+
note: `parent run recovery is already claimed by ${recoveryLease.lease.kind} request ${recoveryLease.lease.requestId}`,
|
|
388
|
+
taskId: taskResolution.taskId,
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
if (recoveryLease?.kind === "acquired") {
|
|
392
|
+
// Persist a non-empty execution identity before generateTaskDagUseCase can
|
|
393
|
+
// execute its new DAG. The generated run id is not available yet, so the
|
|
394
|
+
// request id is the stable lineage handle for this entry point.
|
|
395
|
+
await bindDagRecoveryLeaseExecution({
|
|
396
|
+
leasePath: recoveryLease.leasePath,
|
|
397
|
+
lease: recoveryLease.lease,
|
|
398
|
+
executionRef: `standalone-task-rerun:${input.requestId}`,
|
|
399
|
+
});
|
|
400
|
+
}
|
|
372
401
|
const generateResult = await generateTaskDagUseCase({
|
|
373
402
|
repoRoot: input.cwd,
|
|
374
403
|
taskId: taskResolution.taskId,
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { projectProtocolFailureReason, } from "./frontend-recovery-capsule.js";
|
|
3
|
+
import { TYPED_EVENT_FACT_KINDS } from "./frontend-typed-event-store.js";
|
|
2
4
|
/**
|
|
3
5
|
* Failure categories that are safe to auto-retry for read-only Pi nodes.
|
|
4
6
|
*
|
|
@@ -23,6 +25,29 @@ export const PROTOCOL_INVALID_RETRY_CATEGORY = "protocol-invalid";
|
|
|
23
25
|
export const STRUCTURED_ARTIFACT_INVALID_RETRY_CATEGORY = "invalid-output";
|
|
24
26
|
/** Provider stopReason=length truncated the response before the JSON contract completed. */
|
|
25
27
|
export const STRUCTURED_OUTPUT_TRUNCATED_RETRY_CATEGORY = "structured-output-truncated";
|
|
28
|
+
/**
|
|
29
|
+
* The review node emitted a verdict in response text (e.g. "VERDICT: pass")
|
|
30
|
+
* but never committed the authoritative typed terminal tool call
|
|
31
|
+
* (approve_review / request_review_changes). Read-only and safe to retry with
|
|
32
|
+
* a corrected instruction; the typed terminal is the only authority.
|
|
33
|
+
*/
|
|
34
|
+
export const REVIEW_TERMINAL_MISSING_RETRY_CATEGORY = "review-terminal-missing";
|
|
35
|
+
/**
|
|
36
|
+
* The plan node issued too many read-only tool calls (read/grep/ls/find),
|
|
37
|
+
* blowing up the context window and eventually a 400 request-too-large. The
|
|
38
|
+
* plan should trust upstream typed facts instead of re-reading contract/scout
|
|
39
|
+
* outputs and source files repeatedly. Read-only and safe to retry with a
|
|
40
|
+
* reduced-reading instruction.
|
|
41
|
+
*/
|
|
42
|
+
export const READ_BURST_RETRY_CATEGORY = "read-burst";
|
|
43
|
+
/**
|
|
44
|
+
* Provider returned a context-overflow error (400 request-too-large / context
|
|
45
|
+
* window exceeded). The SDK compacts and auto-retries once internally; when it
|
|
46
|
+
* still surfaces, the executor classifies this so retry policies and reports
|
|
47
|
+
* treat it as overflow (not empty-output) and can retry with a compacted
|
|
48
|
+
* session / fresh context.
|
|
49
|
+
*/
|
|
50
|
+
export const CONTEXT_OVERFLOW_RETRY_CATEGORY = "context-overflow";
|
|
26
51
|
/** Retry only a proven no-op from an explicitly opt-in bounded Pi writer. */
|
|
27
52
|
export const WRITER_EMPTY_DIFF_RETRY_CATEGORY = "writer-empty-diff";
|
|
28
53
|
/** Retry when a backend-test writer finished but Completeness Gate found missing/broken targets. */
|
|
@@ -55,6 +80,9 @@ export const ALL_DAG_RETRY_CATEGORIES = [
|
|
|
55
80
|
WRITER_EMPTY_DIFF_RETRY_CATEGORY,
|
|
56
81
|
INCOMPLETE_WRITE_SET_RETRY_CATEGORY,
|
|
57
82
|
WRITER_CLEAN_TIMEOUT_RETRY_CATEGORY,
|
|
83
|
+
REVIEW_TERMINAL_MISSING_RETRY_CATEGORY,
|
|
84
|
+
READ_BURST_RETRY_CATEGORY,
|
|
85
|
+
CONTEXT_OVERFLOW_RETRY_CATEGORY,
|
|
58
86
|
];
|
|
59
87
|
const RETRY_SAFE_PI_ROLES = new Set([
|
|
60
88
|
"planner",
|
|
@@ -104,13 +132,35 @@ export const dagRetryPolicySchema = z
|
|
|
104
132
|
/**
|
|
105
133
|
* The default retry policy applied to safe generated read-only Pi nodes.
|
|
106
134
|
* Total attempts: 3, exponential backoff with cap.
|
|
135
|
+
*
|
|
136
|
+
* Includes `context-overflow`: a read-only node that blew the context window
|
|
137
|
+
* (400 request too large, e.g. a review node accumulating too many reads) is a
|
|
138
|
+
* transient, safe-to-retry failure — the retry re-runs the node with a
|
|
139
|
+
* compact-context instruction instead of failing the whole run. Previously
|
|
140
|
+
* only writer transport policies had context-overflow; contract/scout/
|
|
141
|
+
* design-review/review fell straight to ERROR without a retry attempt.
|
|
107
142
|
*/
|
|
108
143
|
export const DEFAULT_READ_ONLY_PI_RETRY_POLICY = {
|
|
109
144
|
maxAttempts: 3,
|
|
110
145
|
backoff: "exponential",
|
|
111
146
|
initialDelayMs: 2000,
|
|
112
147
|
maxDelayMs: 30000,
|
|
113
|
-
retryCategories: [
|
|
148
|
+
retryCategories: [
|
|
149
|
+
...DEFAULT_DAG_RETRY_CATEGORIES,
|
|
150
|
+
READ_BURST_RETRY_CATEGORY,
|
|
151
|
+
CONTEXT_OVERFLOW_RETRY_CATEGORY,
|
|
152
|
+
],
|
|
153
|
+
};
|
|
154
|
+
/** Scout is the discovery authority. A missing/incomplete typed target surface
|
|
155
|
+
* is safe to retry in-node, rather than making Plan rediscover the repository. */
|
|
156
|
+
export const FRONTEND_SCOUT_COMPLETENESS_RETRY_POLICY = {
|
|
157
|
+
...DEFAULT_READ_ONLY_PI_RETRY_POLICY,
|
|
158
|
+
retryCategories: [
|
|
159
|
+
...DEFAULT_DAG_RETRY_CATEGORIES,
|
|
160
|
+
STRUCTURED_ARTIFACT_INVALID_RETRY_CATEGORY,
|
|
161
|
+
READ_BURST_RETRY_CATEGORY,
|
|
162
|
+
CONTEXT_OVERFLOW_RETRY_CATEGORY,
|
|
163
|
+
],
|
|
114
164
|
};
|
|
115
165
|
/**
|
|
116
166
|
* Structured planner nodes may retry with a compact-output instruction
|
|
@@ -120,7 +170,11 @@ export const DEFAULT_READ_ONLY_PI_RETRY_POLICY = {
|
|
|
120
170
|
*/
|
|
121
171
|
export const STRUCTURED_REQUIRED_PI_RETRY_POLICY = {
|
|
122
172
|
...DEFAULT_READ_ONLY_PI_RETRY_POLICY,
|
|
123
|
-
retryCategories: [
|
|
173
|
+
retryCategories: [
|
|
174
|
+
...STRUCTURED_REQUIRED_DAG_RETRY_CATEGORIES,
|
|
175
|
+
READ_BURST_RETRY_CATEGORY,
|
|
176
|
+
CONTEXT_OVERFLOW_RETRY_CATEGORY,
|
|
177
|
+
],
|
|
124
178
|
};
|
|
125
179
|
/**
|
|
126
180
|
* Planner read-only nodes (standard DAG contract-pi / plan-pi) may retry with
|
|
@@ -131,7 +185,12 @@ export const STRUCTURED_REQUIRED_PI_RETRY_POLICY = {
|
|
|
131
185
|
*/
|
|
132
186
|
export const PLANNER_OUTPUT_LIMIT_RETRY_POLICY = {
|
|
133
187
|
...DEFAULT_READ_ONLY_PI_RETRY_POLICY,
|
|
134
|
-
retryCategories: [
|
|
188
|
+
retryCategories: [
|
|
189
|
+
...DEFAULT_DAG_RETRY_CATEGORIES,
|
|
190
|
+
STRUCTURED_OUTPUT_RETRY_CATEGORY,
|
|
191
|
+
READ_BURST_RETRY_CATEGORY,
|
|
192
|
+
CONTEXT_OVERFLOW_RETRY_CATEGORY,
|
|
193
|
+
],
|
|
135
194
|
};
|
|
136
195
|
/**
|
|
137
196
|
* Default retry for reviewer / recovery nodes that declare outputProtocol.
|
|
@@ -141,6 +200,22 @@ export const PROTOCOL_AWARE_PI_RETRY_POLICY = {
|
|
|
141
200
|
...DEFAULT_READ_ONLY_PI_RETRY_POLICY,
|
|
142
201
|
retryCategories: [...PROTOCOL_AWARE_DAG_RETRY_CATEGORIES],
|
|
143
202
|
};
|
|
203
|
+
/**
|
|
204
|
+
* frontend-review-pi retry policy. The review verdict must be committed
|
|
205
|
+
* through the typed terminal tools (approve_review / request_review_changes);
|
|
206
|
+
* a model that only echoes "VERDICT: pass" text fails as
|
|
207
|
+
* review-terminal-missing. That is read-only and safe to retry with a
|
|
208
|
+
* corrected instruction so a single model slip does not burn the whole run.
|
|
209
|
+
*/
|
|
210
|
+
export const FRONTEND_REVIEW_TERMINAL_RETRY_POLICY = {
|
|
211
|
+
...DEFAULT_READ_ONLY_PI_RETRY_POLICY,
|
|
212
|
+
retryCategories: [
|
|
213
|
+
...DEFAULT_DAG_RETRY_CATEGORIES,
|
|
214
|
+
READ_BURST_RETRY_CATEGORY,
|
|
215
|
+
CONTEXT_OVERFLOW_RETRY_CATEGORY,
|
|
216
|
+
REVIEW_TERMINAL_MISSING_RETRY_CATEGORY,
|
|
217
|
+
],
|
|
218
|
+
};
|
|
144
219
|
/**
|
|
145
220
|
* The sole writer retry policy for requireChangedFiles writers. It is
|
|
146
221
|
* intentionally not included in any read-only default: a writer may retry only
|
|
@@ -163,7 +238,46 @@ export const WRITER_TRANSPORT_RETRY_POLICY = {
|
|
|
163
238
|
backoff: "exponential",
|
|
164
239
|
initialDelayMs: 5000,
|
|
165
240
|
maxDelayMs: 30000,
|
|
166
|
-
retryCategories: [
|
|
241
|
+
retryCategories: [
|
|
242
|
+
WRITER_CLEAN_TIMEOUT_RETRY_CATEGORY,
|
|
243
|
+
CONTEXT_OVERFLOW_RETRY_CATEGORY,
|
|
244
|
+
],
|
|
245
|
+
};
|
|
246
|
+
/**
|
|
247
|
+
* Implicit runtime retry for canonical final verify shells. Not a DagRetryPolicy:
|
|
248
|
+
* `spawn-error` / `test-timeout` are runtime command categories and must not enter
|
|
249
|
+
* `dagRetryPolicySchema` / `ALL_DAG_RETRY_CATEGORIES`.
|
|
250
|
+
*/
|
|
251
|
+
export const VERIFY_SHELL_RETRY_CATEGORIES = [
|
|
252
|
+
"timeout",
|
|
253
|
+
"spawn-error",
|
|
254
|
+
"test-timeout",
|
|
255
|
+
];
|
|
256
|
+
export const VERIFY_SHELL_RETRY_POLICY = {
|
|
257
|
+
maxAttempts: 2,
|
|
258
|
+
backoff: "exponential",
|
|
259
|
+
initialDelayMs: 2000,
|
|
260
|
+
maxDelayMs: 30000,
|
|
261
|
+
retryCategories: VERIFY_SHELL_RETRY_CATEGORIES,
|
|
262
|
+
};
|
|
263
|
+
export const TARGET_TEMPLATE_TRANSIENT_RETRY_PROFILE = "standard-reviewed-supervised-v1";
|
|
264
|
+
/**
|
|
265
|
+
* Target-template exclusive implement-pi transport retry. Same schema category
|
|
266
|
+
* as frontend (`writer-clean-timeout`) so DagSpec validation stays unchanged;
|
|
267
|
+
* only the delay cap is wider. Context overflow is added so a writer whose
|
|
268
|
+
* session hit the context window (compact+retry inside the SDK) can retry once
|
|
269
|
+
* more at the DAG level with a fresh attempt. Do not mutate
|
|
270
|
+
* {@link WRITER_TRANSPORT_RETRY_POLICY}.
|
|
271
|
+
*/
|
|
272
|
+
export const TARGET_TEMPLATE_WRITER_TRANSPORT_RETRY_POLICY = {
|
|
273
|
+
maxAttempts: 2,
|
|
274
|
+
backoff: "exponential",
|
|
275
|
+
initialDelayMs: 5000,
|
|
276
|
+
maxDelayMs: 60000,
|
|
277
|
+
retryCategories: [
|
|
278
|
+
WRITER_CLEAN_TIMEOUT_RETRY_CATEGORY,
|
|
279
|
+
CONTEXT_OVERFLOW_RETRY_CATEGORY,
|
|
280
|
+
],
|
|
167
281
|
};
|
|
168
282
|
/**
|
|
169
283
|
* Backend-test generation writers: empty-diff once, plus bounded incomplete-write-set
|
|
@@ -229,15 +343,77 @@ export function isWriterEmptyDiffRetryCandidate(task) {
|
|
|
229
343
|
task.writerOutcomePolicy?.requireChangedFiles === true);
|
|
230
344
|
}
|
|
231
345
|
/**
|
|
232
|
-
* Standard exclusive implementers (implementation-outcome
|
|
233
|
-
* single clean-timeout transport retry. Backend
|
|
234
|
-
* have their own policy and are excluded here.
|
|
346
|
+
* Standard exclusive implementers (implementation-outcome and frontend-facts
|
|
347
|
+
* writers) may take a single clean-timeout transport retry. Backend
|
|
348
|
+
* completeness writers already have their own policy and are excluded here.
|
|
235
349
|
*/
|
|
236
350
|
export function isWriterTransportRetryCandidate(task) {
|
|
237
351
|
return (isExclusivePiImplementer(task) &&
|
|
238
|
-
task.writerOutcomePolicy?.type === "implementation-outcome-v1"
|
|
352
|
+
(task.writerOutcomePolicy?.type === "implementation-outcome-v1" ||
|
|
353
|
+
task.writerOutcomePolicy?.type === "frontend-facts-v1") &&
|
|
239
354
|
task.writerOutcomePolicy.requireChangedFiles !== true);
|
|
240
355
|
}
|
|
356
|
+
/**
|
|
357
|
+
* Canonical standard exclusive `implement-pi` only. Frontend designers and
|
|
358
|
+
* completeness writers stay on the existing timeout-only transport candidate.
|
|
359
|
+
*/
|
|
360
|
+
export function isTargetTemplateImplementPi(task) {
|
|
361
|
+
return isWriterTransportRetryCandidate(task) && task.id === "implement-pi";
|
|
362
|
+
}
|
|
363
|
+
export function hasTargetTemplateTransientRetryProfile(task) {
|
|
364
|
+
return (task?.transientRetryProfile === TARGET_TEMPLATE_TRANSIENT_RETRY_PROFILE);
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Dual-condition eligibility: canonical shape AND generated-path stamp.
|
|
368
|
+
* Custom / other-template nodes that only match id or shape stay ineligible.
|
|
369
|
+
*/
|
|
370
|
+
export function isTargetTemplateTransientRetryNode(task) {
|
|
371
|
+
if (!hasTargetTemplateTransientRetryProfile(task))
|
|
372
|
+
return false;
|
|
373
|
+
return (isCanonicalFinalVerifyShellRetryCandidate(task) ||
|
|
374
|
+
isTargetTemplateImplementPi(task));
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Shape-based eligibility for implicit canonical final verify-shell retry.
|
|
378
|
+
* Does not consult node id or a template field.
|
|
379
|
+
*/
|
|
380
|
+
export function isCanonicalFinalVerifyShellRetryCandidate(task) {
|
|
381
|
+
if (task.executor !== "shell")
|
|
382
|
+
return false;
|
|
383
|
+
if (task.role !== "verifier")
|
|
384
|
+
return false;
|
|
385
|
+
if (task.writePolicy !== undefined &&
|
|
386
|
+
task.writePolicy !== "read-only" &&
|
|
387
|
+
task.writePolicy !== "none") {
|
|
388
|
+
return false;
|
|
389
|
+
}
|
|
390
|
+
if ((task.writeSet?.length ?? 0) > 0)
|
|
391
|
+
return false;
|
|
392
|
+
const shell = task.shell;
|
|
393
|
+
if (!shell || (shell.commands?.length ?? 0) === 0)
|
|
394
|
+
return false;
|
|
395
|
+
const evidence = shell.verifyEvidence;
|
|
396
|
+
if (!evidence)
|
|
397
|
+
return false;
|
|
398
|
+
if (evidence.phase !== "final")
|
|
399
|
+
return false;
|
|
400
|
+
if (evidence.quota !== "full")
|
|
401
|
+
return false;
|
|
402
|
+
if (evidence.commandSource !== "adapter")
|
|
403
|
+
return false;
|
|
404
|
+
if (evidence.finalFullRequired !== true)
|
|
405
|
+
return false;
|
|
406
|
+
if (shell.frontendPrewriteGate ||
|
|
407
|
+
shell.frontendVerificationBundle ||
|
|
408
|
+
shell.frontendBrowserToolPreflight ||
|
|
409
|
+
shell.backendTestPipeline ||
|
|
410
|
+
shell.jacocoCoverage ||
|
|
411
|
+
shell.repairArtifactGate ||
|
|
412
|
+
shell.verdictGate) {
|
|
413
|
+
return false;
|
|
414
|
+
}
|
|
415
|
+
return true;
|
|
416
|
+
}
|
|
241
417
|
export function isSafeReadOnlyPiRetryCandidate(task) {
|
|
242
418
|
if (task.executor !== "pi")
|
|
243
419
|
return false;
|
|
@@ -279,3 +455,137 @@ export function computeBackoffDelayMs(attemptNumber, policy) {
|
|
|
279
455
|
const raw = policy.initialDelayMs * 2 ** exponent;
|
|
280
456
|
return Math.min(raw, policy.maxDelayMs);
|
|
281
457
|
}
|
|
458
|
+
/**
|
|
459
|
+
* A+B (AC-001/AC-005): project raw executor signals to the canonical 7-value
|
|
460
|
+
* protocol failure reason. Specific signals win first, then the existing
|
|
461
|
+
* alias/enum passthrough; unknown signals fail closed to `undefined`.
|
|
462
|
+
*/
|
|
463
|
+
export function projectFrontendNodeProtocolFailureReason(input) {
|
|
464
|
+
// 1. length stop reason without a terminal → length-before-terminal.
|
|
465
|
+
if (input.stopReason === "length" && input.hasTerminalFact === false) {
|
|
466
|
+
return "length-before-terminal";
|
|
467
|
+
}
|
|
468
|
+
// 2. timeout with reasoning-side evidence → reasoning-timeout.
|
|
469
|
+
if (input.failureCategory === "timeout" &&
|
|
470
|
+
/(?:reasoning|thinking|thought)/i.test(input.assistantText ?? "")) {
|
|
471
|
+
return "reasoning-timeout";
|
|
472
|
+
}
|
|
473
|
+
// 3. empty output without a terminal → provider-ended-without-terminal.
|
|
474
|
+
if (input.failureCategory === "empty-output" &&
|
|
475
|
+
input.hasTerminalFact === false) {
|
|
476
|
+
return "provider-ended-without-terminal";
|
|
477
|
+
}
|
|
478
|
+
// 4. Alias/enum passthrough; unknown fails closed to undefined.
|
|
479
|
+
return projectProtocolFailureReason(input.failureCategory ?? "");
|
|
480
|
+
}
|
|
481
|
+
export const FRONTEND_PLAN_LADDER = [
|
|
482
|
+
"normal",
|
|
483
|
+
"compact-terminal-first",
|
|
484
|
+
"bounded-tool-only",
|
|
485
|
+
"backup-model",
|
|
486
|
+
];
|
|
487
|
+
/**
|
|
488
|
+
* Map a 7-value protocol failure reason to the closest provider capability
|
|
489
|
+
* fact kind for backup-model routing. `unsupported-tool-capability` is a
|
|
490
|
+
* protocol reason, not a provider capability kind, so it is deliberately NOT
|
|
491
|
+
* a valid route (fail-closed to `unsupported-provider-capability`).
|
|
492
|
+
*/
|
|
493
|
+
export function frontendPlanProtocolReasonToCapabilityKind(reason) {
|
|
494
|
+
switch (reason) {
|
|
495
|
+
case "length-before-terminal":
|
|
496
|
+
return "length-before-terminal";
|
|
497
|
+
case "reasoning-timeout":
|
|
498
|
+
return "reasoning-timeout";
|
|
499
|
+
case "provider-ended-without-terminal":
|
|
500
|
+
return "provider-ended-without-terminal";
|
|
501
|
+
case "terminal-event-missing":
|
|
502
|
+
case "terminal-conflict":
|
|
503
|
+
return "terminal-commit";
|
|
504
|
+
case "typed-fact-invalid":
|
|
505
|
+
return "read-only-fact-channel";
|
|
506
|
+
case "unsupported-tool-capability":
|
|
507
|
+
return "unsupported-tool-capability";
|
|
508
|
+
default:
|
|
509
|
+
return undefined;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
/**
|
|
513
|
+
* A+B (AC-003): resolve a backup-model route against the frozen seven-kind
|
|
514
|
+
* provider capability catalog (the exact set `routeFrontendProviderCapability`
|
|
515
|
+
* consults). `unsupported-tool-capability` is a protocol reason, not a
|
|
516
|
+
* provider capability kind, so it (and any unmapped reason) fails closed to
|
|
517
|
+
* `unsupported-provider-capability` — never swapped for the 7-value reason.
|
|
518
|
+
*/
|
|
519
|
+
export function resolveFrontendPlanBackupRoute(reason) {
|
|
520
|
+
const factKind = frontendPlanProtocolReasonToCapabilityKind(reason);
|
|
521
|
+
if (!factKind) {
|
|
522
|
+
return { ok: false, reason: "unsupported-provider-capability" };
|
|
523
|
+
}
|
|
524
|
+
return TYPED_EVENT_FACT_KINDS.includes(factKind)
|
|
525
|
+
? { ok: true, factKind }
|
|
526
|
+
: { ok: false, reason: "unsupported-provider-capability" };
|
|
527
|
+
}
|
|
528
|
+
/**
|
|
529
|
+
* A+B (AC-002): deterministic ladder resolution. Reason-mandated upgrades
|
|
530
|
+
* (length → compact-terminal-first; terminal/timeout/empty → bounded-tool-only)
|
|
531
|
+
* never regress below the current rung. A repeated failure fingerprint with no
|
|
532
|
+
* new committed fact escalates one rung instead of re-running the same step;
|
|
533
|
+
* at `backup-model` that becomes `non-converging`, and an unavailable backup
|
|
534
|
+
* provider route fails closed to `unsupported-provider-capability`.
|
|
535
|
+
*/
|
|
536
|
+
export function resolveFrontendPlanRetryStep(input) {
|
|
537
|
+
if (input.currentStep === "non-converging" ||
|
|
538
|
+
input.currentStep === "unsupported-provider-capability") {
|
|
539
|
+
return input.currentStep;
|
|
540
|
+
}
|
|
541
|
+
const currentIndex = FRONTEND_PLAN_LADDER.indexOf(input.currentStep);
|
|
542
|
+
const reasonStep = reasonMandatedFrontendPlanRetryStep(input.protocolFailureReason);
|
|
543
|
+
const reasonIndex = reasonStep
|
|
544
|
+
? FRONTEND_PLAN_LADDER.indexOf(reasonStep)
|
|
545
|
+
: -1;
|
|
546
|
+
let nextIndex = Math.max(currentIndex, reasonIndex);
|
|
547
|
+
const repeated = input.priorFingerprints.includes(input.fingerprint);
|
|
548
|
+
if (repeated && !input.hasNewCommittedFact) {
|
|
549
|
+
nextIndex = Math.max(nextIndex, currentIndex + 1);
|
|
550
|
+
}
|
|
551
|
+
const nextStep = nextIndex >= FRONTEND_PLAN_LADDER.length
|
|
552
|
+
? "non-converging"
|
|
553
|
+
: (FRONTEND_PLAN_LADDER[nextIndex] ?? "non-converging");
|
|
554
|
+
if (nextStep === "backup-model" && input.backupRouteAvailable === false) {
|
|
555
|
+
return "unsupported-provider-capability";
|
|
556
|
+
}
|
|
557
|
+
return nextStep;
|
|
558
|
+
}
|
|
559
|
+
function reasonMandatedFrontendPlanRetryStep(reason) {
|
|
560
|
+
switch (reason) {
|
|
561
|
+
case "length-before-terminal":
|
|
562
|
+
return "compact-terminal-first";
|
|
563
|
+
case "terminal-event-missing":
|
|
564
|
+
case "reasoning-timeout":
|
|
565
|
+
case "provider-ended-without-terminal":
|
|
566
|
+
return "bounded-tool-only";
|
|
567
|
+
default:
|
|
568
|
+
return undefined;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
/**
|
|
572
|
+
* Opt-in retry policy mounted on the frontend-plan-pi node. maxAttempts=3
|
|
573
|
+
* bounds plan retry cost: the four-rung ladder is only partially traversable
|
|
574
|
+
* before the run fails non-converging (rungs: normal → bounded-tool-only →
|
|
575
|
+
* compact-terminal-first → backup-model). `invalid-output` (typed-fact schema
|
|
576
|
+
* violations, e.g. verification targets referencing undeclared UI states)
|
|
577
|
+
* retries at the `normal` rung with the contractCheck reason injected via
|
|
578
|
+
* `<retry_instruction>` (§5.1 ladder).
|
|
579
|
+
*/
|
|
580
|
+
export const FRONTEND_PLAN_LADDER_RETRY_POLICY = {
|
|
581
|
+
maxAttempts: 3,
|
|
582
|
+
backoff: "exponential",
|
|
583
|
+
initialDelayMs: 2000,
|
|
584
|
+
maxDelayMs: 30000,
|
|
585
|
+
retryCategories: [
|
|
586
|
+
...DEFAULT_DAG_RETRY_CATEGORIES,
|
|
587
|
+
STRUCTURED_ARTIFACT_INVALID_RETRY_CATEGORY,
|
|
588
|
+
READ_BURST_RETRY_CATEGORY,
|
|
589
|
+
CONTEXT_OVERFLOW_RETRY_CATEGORY,
|
|
590
|
+
],
|
|
591
|
+
};
|