@tea-agent/loop-agent 0.43.0-next.8 → 0.43.0
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 +41 -2312
- package/README.md +7 -0
- package/dist/application/dag/args.js +8 -0
- package/dist/application/task-lifecycle/advance.js +38 -7
- package/dist/build-stamp.json +3 -3
- package/dist/cli/command-definitions.js +2 -0
- package/dist/cli/program.js +3 -1
- package/dist/cli/update/init-surface-notifier.js +2 -0
- package/dist/cli/update/policy.js +2 -0
- package/dist/commands/client-recovery.js +20 -55
- package/dist/commands/cursor-prompt.js +2 -0
- package/dist/commands/dag-approve.js +2 -0
- package/dist/commands/dag-final-verification.js +2 -0
- package/dist/commands/dag-init-hybrid.js +2 -0
- package/dist/commands/dag-reconcile-tasks.js +2 -0
- package/dist/commands/dag-reject.js +2 -0
- package/dist/commands/dag-report.js +2 -0
- package/dist/commands/dag-rerun.js +2 -0
- package/dist/commands/dag-resume.js +2 -0
- package/dist/commands/dag-workflow-compile.js +2 -0
- package/dist/commands/dag-workflow-plan.js +2 -0
- package/dist/commands/dag-workflow-validate.js +2 -0
- package/dist/commands/delegate.js +2 -0
- package/dist/commands/examples.js +2 -0
- package/dist/commands/import-prd.js +2 -0
- package/dist/commands/init-model-catalog.js +2 -0
- package/dist/commands/init.js +19 -13
- package/dist/commands/instructions.js +2 -0
- package/dist/commands/knowledge.js +2 -0
- package/dist/commands/loop-benchmark.js +2 -0
- package/dist/commands/pi-prompt.js +2 -0
- package/dist/commands/pi-reuse-benchmark.js +2 -0
- package/dist/commands/promote-run.js +2 -0
- package/dist/commands/stats.js +1 -1
- package/dist/commands/study-init.js +2 -0
- package/dist/commands/task-advance.js +34 -0
- package/dist/commands/task-source-prepare.js +2 -0
- package/dist/commands/worktree-create.js +2 -0
- package/dist/commands/worktree-remove.js +2 -0
- package/dist/executors/dag-pi-executor.js +1650 -198
- package/dist/executors/pi-executor.js +85 -3
- package/dist/executors/pi-sdk-executor.js +18 -0
- package/dist/executors/shell-executor.js +93 -7
- package/dist/executors/shell-verification.js +3 -0
- package/dist/executors/shell-write-guard.js +27 -32
- package/dist/governance/exec-plans.js +6 -3
- package/dist/infrastructure/console/app-data.js +6 -0
- package/dist/shared/artifacts-core.js +2 -0
- package/dist/shared/backend-dogfood-preflight.js +47 -0
- package/dist/shared/dag-failure-category.js +3 -0
- package/dist/shared/git-progress.js +2 -0
- package/dist/shared/one-shot-prompt-args.js +2 -0
- package/dist/shared/operator/capabilities.js +180 -0
- package/dist/shared/package-metadata.js +6 -4
- package/dist/shared/pi-context-pressure/extension.js +26 -16
- package/dist/shared/pi-context-pressure/sift-bridge.js +1 -1
- package/dist/shared/pi-provider-recovery.js +182 -0
- package/dist/shared/pi-retry-settings.js +40 -0
- package/dist/shared/reference-context.js +2 -0
- package/dist/task/config-types.js +29 -0
- package/dist/task/contract/project.js +9 -0
- package/dist/task/contract/recover.js +6 -0
- package/dist/task/contract/schema.js +17 -0
- package/dist/task/source-prepare/artifact-meta.js +9 -2
- package/dist/task/source-prepare/build-draft.js +60 -0
- package/dist/task/source-prepare/fragment-inventory.js +4 -1
- package/dist/task/source-prepare/parse-intent.js +36 -11
- package/dist/task/task-demand-routing.js +5 -2
- package/dist/worker/console/chat/browser-automation.js +523 -0
- package/dist/worker/console/chat/browser-policy.js +6 -36
- package/dist/worker/console/chat/browser-routes.js +188 -56
- package/dist/worker/console/chat/explore-tools.js +5 -2
- package/dist/worker/console/chat/pi-mode-loop-isolation.js +155 -0
- package/dist/worker/console/chat/pi-runtime/custom-tools/ask-user-question.js +44 -0
- package/dist/worker/console/chat/pi-runtime/custom-tools/browser-tools.js +184 -0
- package/dist/worker/console/chat/pi-runtime/custom-tools/explore-tools.js +202 -0
- package/dist/worker/console/chat/pi-runtime/custom-tools/goal-tools.js +79 -0
- package/dist/worker/console/chat/pi-runtime/custom-tools/operator-tools.js +94 -0
- package/dist/worker/console/chat/pi-runtime/custom-tools/scheduled-goal-tools.js +22 -0
- package/dist/worker/console/chat/pi-runtime/custom-tools/todo-write.js +38 -0
- package/dist/worker/console/chat/pi-runtime/inspection-types.js +28 -0
- package/dist/worker/console/chat/pi-runtime/inspection.js +439 -0
- package/dist/worker/console/chat/pi-runtime/progressive-tools.js +195 -0
- package/dist/worker/console/chat/pi-runtime/sdk-bindings.js +153 -0
- package/dist/worker/console/chat/pi-runtime/sdk-session.js +5 -0
- package/dist/worker/console/chat/pi-runtime.js +208 -1138
- package/dist/worker/console/chat/routes.js +59 -24
- package/dist/worker/console/chat/scheduled-goal-booking.js +59 -0
- package/dist/worker/console/chat/scheduled-goal-delivery.js +27 -0
- package/dist/worker/console/chat/scheduled-goal-request.js +190 -0
- package/dist/worker/console/chat/sdd-data-alignment.js +1 -1
- package/dist/worker/console/chat/session-mode-view.js +5 -4
- package/dist/worker/console/chat/session-mode.js +18 -12
- package/dist/worker/console/chat/session-store.js +42 -9
- package/dist/worker/console/chat/terminal-sessions.js +65 -1
- package/dist/worker/console/chat/terminal-tools.js +17 -5
- package/dist/worker/console/chat/tool-preview.js +115 -0
- package/dist/worker/console/chat/tools.js +10 -0
- package/dist/worker/console/chat/turn-order.js +13 -0
- package/dist/worker/console/chat/turn-process.js +32 -30
- package/dist/worker/console/console-update-and-init.js +1 -19
- package/dist/worker/console/console-update-runtime.js +5 -20
- package/dist/worker/console/operator-actions.js +63 -1
- package/dist/worker/console/prd-intake-bridge.js +54 -1
- package/dist/worker/console/routes.js +8 -0
- package/dist/worker/console/scheduled-goal-host.js +98 -0
- package/dist/worker/console/scheduled-goal-operation-adapter.js +127 -0
- package/dist/worker/console/server.js +24 -1
- package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-CwAxHSAM.js → abnfDiagram-N423BO3Z-8-j6y-sd.js} +1 -1
- package/dist/worker/console/static/assets/{arc-Bozf-oeF.js → arc-eoQiMvuk.js} +1 -1
- package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-DEypbEQv.js → architectureDiagram-T3A2C74G-C4A3uMcI.js} +1 -1
- package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-B1BQWCbE.js → blockDiagram-VBNYF7ZC-D4zD2F-Q.js} +1 -1
- package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-B3u5-yZz.js → c4Diagram-5PPSVZJV-j1RkJziL.js} +1 -1
- package/dist/worker/console/static/assets/channel-ChE7y-cx.js +1 -0
- package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-DSUc2NTh.js → chunk-2GRJ4B5K-YBHmhik1.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-DZouMIvT.js → chunk-2Q5K7J3B-COfWyo9P.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5RXB4S5H-B3bhB5hh.js → chunk-5RXB4S5H-I99OUkHY.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5VM5RSS4-CZFP_BOz.js → chunk-5VM5RSS4-XKxoJNJ4.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-DnE_wb-X.js → chunk-6Q2QTUOP-DLT_cYx1.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-GF5L2VYU-C2OfoiWm.js → chunk-GF5L2VYU-CxcKZ9mV.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-JWPE2WC7-BKUTL8mm.js → chunk-JWPE2WC7-V1EqXdjY.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-KBJHAD2P-BT5oz0tg.js → chunk-KBJHAD2P-DebTtdFp.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-RYQCIY6F-D8vk-GJi.js → chunk-RYQCIY6F-B-ivNRDf.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-XXDRQBXY-CkUIm3zu.js → chunk-XXDRQBXY-DC_Ds11b.js} +1 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-C01TCf2X.js +1 -0
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-C01TCf2X.js +1 -0
- package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-CO9QNHmR.js → cose-bilkent-JH36ORCC-sWEqKwIb.js} +1 -1
- package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-s52EPl2Z.js → cynefin-VYW2F7L2-BXa_dcu4.js} +1 -1
- package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-BHaseJfW.js → cynefinDiagram-MW4NZA55-C-Mle84F.js} +1 -1
- package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-CTVhRG_R.js → dagre-VZM6K2ZE-CXPDBITe.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-7IWD3JNH-B6pYeOMR.js → diagram-7IWD3JNH-CC-WJQfa.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-CXXRzw5j.js → diagram-B4RE2ZJO-CDAV5Vs4.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-LBJQPF4R-BOeJHiLA.js → diagram-LBJQPF4R-CmFiAcNz.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-Q27KOJAE-DbEg6h_l.js → diagram-Q27KOJAE-DPBZHuyn.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-UB23O5K3-CjlEcbX6.js → diagram-UB23O5K3-jUlm_Ds3.js} +1 -1
- package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-BcqMPbD_.js → ebnfDiagram-BXEA7PRR-DWhQ3mfY.js} +1 -1
- package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-DWfRyHe5.js → erDiagram-JOGREHBK-Tr2gMqet.js} +1 -1
- package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-Bz7TeIc8.js → flowDiagram-UKHOOZJN-DJjVQHPA.js} +1 -1
- package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-BD-JxYjU.js → ganttDiagram-PKOTCBZU-D74dQ4u0.js} +1 -1
- package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-Cv16vMHK.js → gitGraphDiagram-DS77QQ5N-DwW0tZ0X.js} +1 -1
- package/dist/worker/console/static/assets/index-BWkIfcrK.css +1 -0
- package/dist/worker/console/static/assets/index-Cdkvw_H6.js +469 -0
- package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-BlWO0HQQ.js → infoDiagram-6WML65LV-ILCbxJyb.js} +1 -1
- package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-C4mbsn97.js → ishikawaDiagram-WSZJBQD7-DeuWBQ89.js} +1 -1
- package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-CBPvVKjw.js → journeyDiagram-NVQOT4AX-CF5ih8Fk.js} +1 -1
- package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-DPHLp54K.js → kanban-definition-27J2QSJJ-C7yOSuRO.js} +1 -1
- package/dist/worker/console/static/assets/{linear-CXx_9o6k.js → linear-BDZ9riWi.js} +1 -1
- package/dist/worker/console/static/assets/{mermaid.core-DU3IxMq9.js → mermaid.core-7pKqYtpZ.js} +5 -5
- package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-COm4a2ud.js → mindmap-definition-FAOFIHXS-LeJDybSU.js} +1 -1
- package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-Cbt7OA5d.js → pegDiagram-VL7TDLO6-BJvT3pMD.js} +1 -1
- package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-BiYV_4Wl.js → pieDiagram-7S7Q4E2Y-_rGqpMan.js} +1 -1
- package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-lg2zhvbp.js → quadrantDiagram-CIZ2JOQS-DPcSv5aA.js} +1 -1
- package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-cBLvtf0p.js → railroadDiagram-AXF67PYL-Drxx4hkJ.js} +1 -1
- package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-BoekU3Bg.js → requirementDiagram-LRYGKXZP-BCTUdU4z.js} +1 -1
- package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-D_DMZYga.js → sankeyDiagram-W5VNT64P-B6wzbZmB.js} +1 -1
- package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-Lzmzn8lz.js → sequenceDiagram-SI44F4Z6-BGt8d3QQ.js} +1 -1
- package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-Cos3HpIe.js → sizeCapture-X5ZJPWSS-7nlhJKo7.js} +1 -1
- package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-D-hFBGsx.js → stateDiagram-OKZ733FA-Cv2stqMA.js} +1 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-DC7V5vcq.js +1 -0
- package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-BY95sCVI.js → swimlanes-SLNWSIFB-qDAo4Yc1.js} +2 -2
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-Bwy4QUTO.js +8 -0
- package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-D1iCgWHS.js → timeline-definition-Z64GVDOM-CKbDNKTr.js} +1 -1
- package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-D9IYy4WK.js → vennDiagram-T6HMQDX7-DI-9EHic.js} +1 -1
- package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-C9yJwO-R.js → wardleyDiagram-T6FBY63Y-BrzzRDpX.js} +1 -1
- package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-CC2llyou.js → xychartDiagram-ELKLHX3M-BclH5hGh.js} +1 -1
- package/dist/worker/console/static/index.html +2 -2
- package/dist/worker/console/static-src/operator-chat/active-turn-tail.js +10 -0
- package/dist/worker/console/static-src/operator-chat/chat-scroll-position.js +24 -0
- package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +41 -11
- package/dist/worker/console/static-src/operator-chat/compaction-message.js +10 -17
- package/dist/worker/console/static-src/operator-chat/composer-session-ledger.js +192 -0
- package/dist/worker/console/static-src/operator-chat/pending-user-message.js +9 -1
- package/dist/worker/console/static-src/operator-chat/slash-palette-nav.js +15 -5
- package/dist/worker/console/static-src/operator-chat/timeline-merge.js +29 -0
- package/dist/worker/console/static-src/operator-chat/turn-process-disclosure.js +10 -0
- package/dist/worker/console/static-src/operator-chat/useChatSessions.js +105 -44
- package/dist/worker/console/static-src/operator-chat/useChatStream.js +145 -70
- package/dist/worker/console/static-src/operator-chat/useChatThread.js +38 -57
- package/dist/worker/console/static-src/operator-chat/useComposer.js +195 -73
- package/dist/worker/console/static-src/operator-chat/useRepoBrowser.js +2 -0
- package/dist/worker/console/static-src/prd-file-import.js +3 -1
- package/dist/worker/console/workspace-context.js +22 -0
- package/dist/worker/console/workspace-initialization.js +209 -0
- package/dist/worker/delivery/git-transaction.js +2 -0
- package/dist/worker/feature/fullstack-validate.js +2 -0
- package/dist/worker/loop-agent/loop-agent-client.js +8 -2
- package/dist/worker/materialize/harness-task-materializer.js +4 -1
- package/dist/worker/metrics/projector.js +1 -1
- package/dist/worker/observability/event-store.js +4 -1
- package/dist/worker/observability/read-model.js +4 -1
- package/dist/worker/observe/node-transparency.js +23 -1
- package/dist/worker/observe/routes.js +4 -0
- package/dist/worker/observe/static/operator-chrome.js +3 -1
- package/dist/worker/observe/static/styles.css +7 -4
- package/dist/worker/observe/static/views/dag-inspector.js +5 -19
- package/dist/worker/outcomes/declared-artifacts.js +2 -0
- package/dist/worker/preflight.js +3 -0
- package/dist/worker/scheduler/scheduled-goal-dispatch.js +117 -0
- package/dist/worker/scheduler/scheduled-goal-evidence.js +167 -0
- package/dist/worker/scheduler/scheduled-goal-recovery.js +62 -0
- package/dist/worker/scheduler/scheduled-goal-store.js +699 -0
- package/dist/worker/scheduler/scheduled-goal-supervisor.js +132 -0
- package/dist/worker/scheduler/scheduled-goal-time.js +102 -0
- package/dist/worker/scheduler/scheduled-goal-types.js +95 -0
- package/dist/worker/task-spec/validate.js +4 -1
- package/dist/workflows/dag/backend-test-markdown-workflow.js +6 -24
- package/dist/workflows/dag/backend-test-plan-protocol.js +82 -5
- package/dist/workflows/dag/dag-retry-schema.js +11 -0
- package/dist/workflows/dag/decision-envelope.js +2 -0
- package/dist/workflows/dag/dynamic-runtime/shared.js +2 -2
- package/dist/workflows/dag/frontend-closeout.js +3 -1
- package/dist/workflows/dag/frontend-committed-facts.js +461 -0
- package/dist/workflows/dag/frontend-durable-tools.js +15 -3
- package/dist/workflows/dag/frontend-implementation-contract.js +369 -12
- package/dist/workflows/dag/frontend-plan-canary.js +53 -0
- package/dist/workflows/dag/frontend-plan-decision-contract.js +803 -0
- package/dist/workflows/dag/frontend-plan-render.js +0 -2
- package/dist/workflows/dag/frontend-provider-capability-matrix.js +8 -61
- package/dist/workflows/dag/frontend-recovery-run.js +57 -0
- package/dist/workflows/dag/frontend-repair.js +55 -76
- package/dist/workflows/dag/frontend-review-context.js +42 -68
- package/dist/workflows/dag/frontend-review-scopes.js +2 -2
- package/dist/workflows/dag/frontend-risk.js +92 -10
- package/dist/workflows/dag/frontend-session-budget.js +117 -3
- package/dist/workflows/dag/frontend-shape.js +11 -55
- package/dist/workflows/dag/frontend-test-execution-evidence.js +35 -10
- package/dist/workflows/dag/frontend-typed-event-store.js +32 -25
- package/dist/workflows/dag/frontend-verification-trace.js +33 -54
- package/dist/workflows/dag/frontend-writer-admission.js +3 -47
- package/dist/workflows/dag/frontend-writer-status.js +0 -23
- package/dist/workflows/dag/init-hybrid.js +47 -19
- package/dist/workflows/dag/interrupt-request.js +2 -0
- package/dist/workflows/dag/lifecycle.js +11 -2
- package/dist/workflows/dag/node-execution.js +50 -13
- package/dist/workflows/dag/reconcile-run.js +2 -0
- package/dist/workflows/dag/repair-artifact.js +3 -1
- package/dist/workflows/dag/report.js +2 -0
- package/dist/workflows/dag/rerun-plan.js +10 -0
- package/dist/workflows/dag/rerun-task.js +79 -1
- package/dist/workflows/dag/retry-policy.js +18 -0
- package/dist/workflows/dag/scheduler.js +2 -4
- package/dist/workflows/dag/types.js +44 -6
- package/dist/workflows/dag/validate.js +4 -0
- package/docs/README.md +1 -0
- package/docs/architecture/runtime-boundaries.md +3 -3
- package/docs/governance/README.md +1 -0
- package/docs/init-surface.manifest.json +1 -0
- package/docs/operations/README.md +2 -0
- package/docs/templates/README.md +1 -1
- package/docs/templates/agent-dag.schema.json +2 -2
- package/docs/templates/backend-test-dag.json +14 -10
- package/docs/templates/frontend-implementation-contract.schema.json +0 -7
- package/package.json +9 -3
- package/skills/frontend-bounded-implement/references/code-standards.md +3 -3
- package/skills/frontend-contract/references/contract-protocol.md +3 -1
- package/skills/frontend-plan/SKILL.md +8 -6
- package/skills/frontend-plan/references/decision-contract.md +3 -3
- package/skills/frontend-review/SKILL.md +18 -28
- package/skills/frontend-review/references/review-findings.md +8 -3
- package/dist/commands/new-task.js +0 -5
- package/dist/commands/status.js +0 -57
- package/dist/commands/task-contract.js +0 -269
- package/dist/shared/prompts.js +0 -26
- package/dist/task/config.js +0 -2
- package/dist/task/contract/validate-draft.js +0 -106
- package/dist/task/goal.js +0 -3
- package/dist/task/index.js +0 -12
- package/dist/task/lifecycle.js +0 -1
- package/dist/task/operator/capabilities.js +0 -6
- package/dist/task/operator/envelope.js +0 -2
- package/dist/task/operator/index.js +0 -5
- package/dist/task/operator/registry.js +0 -2
- package/dist/task/operator/types.js +0 -1
- package/dist/task/paths.js +0 -1
- package/dist/task/source-state.js +0 -1
- package/dist/task/subagent-guidance.js +0 -1
- package/dist/worker/console/chat/sift-bridge.js +0 -1
- package/dist/worker/console/index.js +0 -20
- package/dist/worker/console/static/assets/channel-JM-I_b0s.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-DuQQAYEg.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-DuQQAYEg.js +0 -1
- package/dist/worker/console/static/assets/index-B5H-giS2.js +0 -468
- package/dist/worker/console/static/assets/index-Bf7dxfm-.css +0 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-img0hVJ4.js +0 -1
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-B4acZJvk.js +0 -8
- package/dist/worker/scheduler/index.js +0 -25
- package/dist/workflows/dag/facts.js +0 -4
- package/dist/workflows/dag/frontend-shadow-dual-write.js +0 -975
- package/dist/workflows/dag/index.js +0 -6
- package/dist/workflows/dynamic/index.js +0 -7
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
import { spawn as ptySpawn } from "node-pty";
|
|
17
17
|
import { existsSync } from "node:fs";
|
|
18
18
|
import { randomBytes } from "node:crypto";
|
|
19
|
+
import { release as osRelease } from "node:os";
|
|
19
20
|
/** Bounded ring buffer of raw output chunks (bytes preserved as utf8 text). */
|
|
20
21
|
const MAX_BUFFER_CHARS = 200_000;
|
|
21
22
|
export class TerminalSessionError extends Error {
|
|
@@ -97,6 +98,51 @@ function resolveZsh() {
|
|
|
97
98
|
const file = firstExisting(["/bin/zsh", "/usr/bin/zsh", "/usr/local/bin/zsh", "/opt/homebrew/bin/zsh"]);
|
|
98
99
|
return file ? { file, args: ["-i"] } : undefined;
|
|
99
100
|
}
|
|
101
|
+
/** Windows `cmd.exe`. Always present on Windows; offered alongside
|
|
102
|
+
* PowerShell so users can use native Windows tooling (`dir`, `where`,
|
|
103
|
+
* `mklink`, `net user`, etc.) without leaving the terminal panel.
|
|
104
|
+
* - `/Q` turns off command echo (otherwise cmd echoes every input line,
|
|
105
|
+
* doubling every prompt in PTY output).
|
|
106
|
+
* - `/D` disables AutoRun execution from the registry (avoid running the
|
|
107
|
+
* user's HKCU\...\RunOnce / autorun scripts on every fresh shell).
|
|
108
|
+
* - `/K "prompt $P$G"` keeps the shell alive across tool calls (cwd/env
|
|
109
|
+
* survive) and uses the classic cmd prompt `C:\path>` instead of the
|
|
110
|
+
* bare `>`, so the user can see the working directory at a glance —
|
|
111
|
+
* matching the default `cmd.exe` window. */
|
|
112
|
+
function resolveCmd() {
|
|
113
|
+
if (!IS_WINDOWS)
|
|
114
|
+
return undefined;
|
|
115
|
+
const file = firstExisting([
|
|
116
|
+
"C:\\Windows\\System32\\cmd.exe",
|
|
117
|
+
// Wine / uncommon layouts
|
|
118
|
+
"C:\\Windows\\Sysnative\\cmd.exe",
|
|
119
|
+
]);
|
|
120
|
+
if (!file)
|
|
121
|
+
return undefined;
|
|
122
|
+
return {
|
|
123
|
+
file,
|
|
124
|
+
args: ["/Q", "/D", "/K", "prompt $P$G"],
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
/** Synthesize the cmd.exe startup banner that node-pty drops. cmd prints
|
|
128
|
+
* `Microsoft Windows [版本 10.0.26200]\n(c) Microsoft Corporation。保留所有权利。`
|
|
129
|
+
* via `WriteConsole` BEFORE ConPTY attaches to its stdio handles, so
|
|
130
|
+
* node-pty / ConPTY never sees those writes. We re-emit an equivalent
|
|
131
|
+
* banner using `os.release()` (kernel build, e.g. "10.0.26200") so the
|
|
132
|
+
* console terminal looks like a real cmd window. The leading \r\n avoids
|
|
133
|
+
* the banner colliding with whatever ANSI preamble ConPTY already sent.
|
|
134
|
+
*
|
|
135
|
+
* Only meaningful for the cmd shell — bash and PowerShell on Windows have
|
|
136
|
+
* their own startup output that we must NOT paper over with a Windows
|
|
137
|
+
* banner they don't print. */
|
|
138
|
+
function makeCmdBanner(shell) {
|
|
139
|
+
if (!IS_WINDOWS)
|
|
140
|
+
return undefined;
|
|
141
|
+
if (shell !== "cmd")
|
|
142
|
+
return undefined;
|
|
143
|
+
const build = osRelease();
|
|
144
|
+
return `\r\nMicrosoft Windows [版本 ${build}]\r\n(c) Microsoft Corporation。保留所有权利。\r\n\r\n`;
|
|
145
|
+
}
|
|
100
146
|
let cachedCatalog;
|
|
101
147
|
/** Platform shell catalog, computed once per process. Drives both the UI
|
|
102
148
|
* button set and the model tool's shell parameter enum. */
|
|
@@ -113,6 +159,9 @@ export function availableShellKinds() {
|
|
|
113
159
|
const zsh = resolveZsh();
|
|
114
160
|
if (zsh)
|
|
115
161
|
resolved.set("zsh", zsh);
|
|
162
|
+
const cmd = resolveCmd();
|
|
163
|
+
if (cmd)
|
|
164
|
+
resolved.set("cmd", cmd);
|
|
116
165
|
cachedCatalog = { kinds: [...resolved.keys()], resolved };
|
|
117
166
|
return cachedCatalog;
|
|
118
167
|
}
|
|
@@ -165,10 +214,18 @@ export class TerminalSessionRegistry {
|
|
|
165
214
|
bufferChars: 0,
|
|
166
215
|
subscribers: new Set(),
|
|
167
216
|
disposing: undefined,
|
|
217
|
+
pendingBanner: makeCmdBanner(options.shell) ?? undefined,
|
|
168
218
|
};
|
|
169
219
|
this.entries.set(sessionId, entry);
|
|
170
220
|
pty.onData((chunk) => {
|
|
171
221
|
entry.info.totalOutputChars += chunk.length;
|
|
222
|
+
// Inject the synthesized cmd banner into the FIRST chunk the
|
|
223
|
+
// subscribers see, so SSE/streaming attaches still see it even
|
|
224
|
+
// though node-pty already missed cmd's real banner.
|
|
225
|
+
if (entry.pendingBanner !== undefined) {
|
|
226
|
+
chunk = entry.pendingBanner + chunk;
|
|
227
|
+
entry.pendingBanner = undefined;
|
|
228
|
+
}
|
|
172
229
|
entry.buffer.push(chunk);
|
|
173
230
|
entry.bufferChars += chunk.length;
|
|
174
231
|
while (entry.bufferChars > MAX_BUFFER_CHARS && entry.buffer.length > 1) {
|
|
@@ -219,8 +276,15 @@ export class TerminalSessionRegistry {
|
|
|
219
276
|
/** Full buffered output (post-trim prefix may be incomplete). */
|
|
220
277
|
readAll(sessionId) {
|
|
221
278
|
const entry = this.mustGet(sessionId);
|
|
279
|
+
let text = entry.buffer.join("");
|
|
280
|
+
// If the caller reads before any real PTY output has arrived, the
|
|
281
|
+
// banner injection in onData hasn't fired yet — fold it in here.
|
|
282
|
+
if (entry.pendingBanner !== undefined) {
|
|
283
|
+
text = entry.pendingBanner + text;
|
|
284
|
+
entry.pendingBanner = undefined;
|
|
285
|
+
}
|
|
222
286
|
return {
|
|
223
|
-
text
|
|
287
|
+
text,
|
|
224
288
|
truncated: entry.info.totalOutputChars > entry.bufferChars,
|
|
225
289
|
totalOutputChars: entry.info.totalOutputChars,
|
|
226
290
|
};
|
|
@@ -48,10 +48,16 @@ export async function buildPersistentTerminalTools(deps) {
|
|
|
48
48
|
const marker = `${MARKER_PREFIX}${Date.now().toString(36)}${Math.random()
|
|
49
49
|
.toString(36)
|
|
50
50
|
.slice(2, 8)}`;
|
|
51
|
-
// Exit-code echo
|
|
51
|
+
// Exit-code echo per shell:
|
|
52
|
+
// - PowerShell: $LASTEXITCODE
|
|
53
|
+
// - bash / zsh: $?
|
|
54
|
+
// - cmd.exe: %ERRORLEVEL% (interpolation happens before echo runs,
|
|
55
|
+
// so we use `prompt` substitution style `echo MARKER:%ERRORLEVEL%`).
|
|
52
56
|
const exitEcho = kind === "powershell"
|
|
53
57
|
? `Write-Host "${marker}:$LASTEXITCODE"`
|
|
54
|
-
:
|
|
58
|
+
: kind === "cmd"
|
|
59
|
+
? `echo ${marker}:%ERRORLEVEL%`
|
|
60
|
+
: `echo "${marker}:$?"`;
|
|
55
61
|
const wrapped = `${command}\n${exitEcho}\n`;
|
|
56
62
|
// Capture output from the moment of send until the marker line shows up.
|
|
57
63
|
const pending = [];
|
|
@@ -122,15 +128,21 @@ export async function buildPersistentTerminalTools(deps) {
|
|
|
122
128
|
});
|
|
123
129
|
};
|
|
124
130
|
const kinds = availableShellKinds().kinds;
|
|
131
|
+
// Default precedence: bash (most posix-feel for cross-platform models) →
|
|
132
|
+
// cmd (native Windows shell, offered when bash is absent) → zsh (macOS
|
|
133
|
+
// default on some dev boxes) → powershell (universal Windows fallback).
|
|
125
134
|
const defaultKind = kinds.includes("bash")
|
|
126
135
|
? "bash"
|
|
127
|
-
: kinds.includes("
|
|
128
|
-
? "
|
|
129
|
-
: "
|
|
136
|
+
: kinds.includes("cmd")
|
|
137
|
+
? "cmd"
|
|
138
|
+
: kinds.includes("zsh")
|
|
139
|
+
? "zsh"
|
|
140
|
+
: "powershell";
|
|
130
141
|
const kindLabels = {
|
|
131
142
|
powershell: "PowerShell",
|
|
132
143
|
bash: "bash",
|
|
133
144
|
zsh: "zsh",
|
|
145
|
+
cmd: "cmd",
|
|
134
146
|
};
|
|
135
147
|
const tool = defineTool({
|
|
136
148
|
name: "terminal",
|
|
@@ -148,6 +148,115 @@ export function getToolPreview(args, options) {
|
|
|
148
148
|
return "";
|
|
149
149
|
return s.length > maxLen ? `${s.slice(0, maxLen)}…` : s;
|
|
150
150
|
}
|
|
151
|
+
/** DSH-style human-readable ask_user_question row (rowTitle「提问」). */
|
|
152
|
+
export function isAskUserQuestionTool(toolName) {
|
|
153
|
+
return (toolName ?? "").trim().toLowerCase() === "ask_user_question";
|
|
154
|
+
}
|
|
155
|
+
function normalizeOptionLabel(value) {
|
|
156
|
+
const record = asRecord(value);
|
|
157
|
+
if (!record)
|
|
158
|
+
return undefined;
|
|
159
|
+
const label = typeof record.label === "string" ? record.label.trim() : "";
|
|
160
|
+
return label || undefined;
|
|
161
|
+
}
|
|
162
|
+
function normalizeAskQuestion(value) {
|
|
163
|
+
const record = asRecord(value);
|
|
164
|
+
if (!record)
|
|
165
|
+
return undefined;
|
|
166
|
+
const id = typeof record.id === "string" ? record.id.trim() : "";
|
|
167
|
+
const question = typeof record.question === "string" ? record.question.trim() : "";
|
|
168
|
+
if (!id || !question)
|
|
169
|
+
return undefined;
|
|
170
|
+
const options = Array.isArray(record.options)
|
|
171
|
+
? record.options
|
|
172
|
+
.map((item) => {
|
|
173
|
+
const label = normalizeOptionLabel(item);
|
|
174
|
+
if (!label)
|
|
175
|
+
return undefined;
|
|
176
|
+
const description = typeof item === "object" && item !== null &&
|
|
177
|
+
"description" in item && typeof item.description === "string"
|
|
178
|
+
? item.description
|
|
179
|
+
: undefined;
|
|
180
|
+
return { label, ...(description && description.trim() ? { description: description.trim() } : {}) };
|
|
181
|
+
})
|
|
182
|
+
.filter((item) => Boolean(item))
|
|
183
|
+
: undefined;
|
|
184
|
+
return {
|
|
185
|
+
id,
|
|
186
|
+
question,
|
|
187
|
+
...(typeof record.header === "string" && record.header.trim()
|
|
188
|
+
? { header: record.header.trim() }
|
|
189
|
+
: {}),
|
|
190
|
+
...(typeof record.detail === "string" && record.detail.trim()
|
|
191
|
+
? { detail: record.detail.trim() }
|
|
192
|
+
: {}),
|
|
193
|
+
...(options && options.length > 0 ? { options } : {}),
|
|
194
|
+
...(record.multi_select === true || record.multiSelect === true
|
|
195
|
+
? { multiSelect: true }
|
|
196
|
+
: {}),
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
/** Project ask_user_question args (questions array) into readable views. */
|
|
200
|
+
export function parseAskUserQuestions(args) {
|
|
201
|
+
const input = parseArgs(args);
|
|
202
|
+
if (!input)
|
|
203
|
+
return [];
|
|
204
|
+
const raw = Array.isArray(input)
|
|
205
|
+
? input
|
|
206
|
+
: Array.isArray(input.questions)
|
|
207
|
+
? input.questions
|
|
208
|
+
: [];
|
|
209
|
+
return raw
|
|
210
|
+
.map(normalizeAskQuestion)
|
|
211
|
+
.filter((item) => Boolean(item));
|
|
212
|
+
}
|
|
213
|
+
/** Project ask_user_question ToolResult into answer views keyed by question id. */
|
|
214
|
+
export function parseAskUserAnswers(result) {
|
|
215
|
+
if (result === undefined || result === null)
|
|
216
|
+
return [];
|
|
217
|
+
const text = extractToolResultText(result);
|
|
218
|
+
if (!text)
|
|
219
|
+
return [];
|
|
220
|
+
let parsed;
|
|
221
|
+
try {
|
|
222
|
+
parsed = JSON.parse(text);
|
|
223
|
+
}
|
|
224
|
+
catch {
|
|
225
|
+
return [];
|
|
226
|
+
}
|
|
227
|
+
const record = asRecord(parsed);
|
|
228
|
+
const raw = record && Array.isArray(record.answers) ? record.answers : undefined;
|
|
229
|
+
if (!raw)
|
|
230
|
+
return [];
|
|
231
|
+
const out = [];
|
|
232
|
+
for (const entry of raw) {
|
|
233
|
+
const rec = entry && typeof entry === "object" && !Array.isArray(entry)
|
|
234
|
+
? entry
|
|
235
|
+
: undefined;
|
|
236
|
+
if (!rec || typeof rec.id !== "string")
|
|
237
|
+
continue;
|
|
238
|
+
const selected = Array.isArray(rec.selected)
|
|
239
|
+
? rec.selected.filter((item) => typeof item === "string").map((item) => item.trim()).filter(Boolean)
|
|
240
|
+
: [];
|
|
241
|
+
const custom = typeof rec.custom === "string" ? rec.custom.trim() : "";
|
|
242
|
+
out.push({ id: rec.id, selected, ...(custom ? { custom } : {}) });
|
|
243
|
+
}
|
|
244
|
+
return out;
|
|
245
|
+
}
|
|
246
|
+
/** "{answered}/{total} 已回答" summary; total from args questions, answered from result answers. */
|
|
247
|
+
export function getAskUserQuestionSummary(args, result) {
|
|
248
|
+
const questions = parseAskUserQuestions(args);
|
|
249
|
+
if (questions.length === 0)
|
|
250
|
+
return null;
|
|
251
|
+
const answers = parseAskUserAnswers(result);
|
|
252
|
+
let answered = 0;
|
|
253
|
+
for (const question of questions) {
|
|
254
|
+
const answer = answers.find((item) => item.id === question.id);
|
|
255
|
+
if (answer && (answer.selected.length > 0 || answer.custom))
|
|
256
|
+
answered += 1;
|
|
257
|
+
}
|
|
258
|
+
return { answered, total: questions.length };
|
|
259
|
+
}
|
|
151
260
|
/** Stable DSH-style tool row identity; unknown tools keep their real name. */
|
|
152
261
|
export function getToolPresentation(toolName) {
|
|
153
262
|
const raw = toolName?.trim() || "Tool";
|
|
@@ -191,6 +300,9 @@ export function getToolPresentation(toolName) {
|
|
|
191
300
|
if (name === "agent") {
|
|
192
301
|
return { kind: "search", label: "Explore" };
|
|
193
302
|
}
|
|
303
|
+
if (isAskUserQuestionTool(toolName)) {
|
|
304
|
+
return { kind: "tool", label: "提问" };
|
|
305
|
+
}
|
|
194
306
|
return { kind: "tool", label: raw };
|
|
195
307
|
}
|
|
196
308
|
/** A tool call that failed on its own. A call interrupted by Stop carries
|
|
@@ -213,6 +325,9 @@ export function getToolSectionLabels(toolName) {
|
|
|
213
325
|
if (name === "mcp" || name.startsWith("mcp_")) {
|
|
214
326
|
return { argsLabel: "参数", resultLabel: "结果" };
|
|
215
327
|
}
|
|
328
|
+
if (isAskUserQuestionTool(toolName)) {
|
|
329
|
+
return { argsLabel: "提问", resultLabel: "您的回答" };
|
|
330
|
+
}
|
|
216
331
|
return { argsLabel: "入参", resultLabel: "结果" };
|
|
217
332
|
}
|
|
218
333
|
/**
|
|
@@ -25,6 +25,16 @@ export const OPERATOR_CHAT_BUILTIN_CUSTOM_TOOLS = Object.freeze([
|
|
|
25
25
|
OPERATOR_CHAT_AGENT_TOOL_NAME,
|
|
26
26
|
"terminal",
|
|
27
27
|
"scm",
|
|
28
|
+
"browser_navigate",
|
|
29
|
+
"browser_search",
|
|
30
|
+
"browser_snapshot",
|
|
31
|
+
"browser_act",
|
|
32
|
+
"browser_tabs",
|
|
33
|
+
"browser_scroll",
|
|
34
|
+
"browser_press",
|
|
35
|
+
"browser_dialog",
|
|
36
|
+
"browser_wait",
|
|
37
|
+
"browser_screenshot",
|
|
28
38
|
]);
|
|
29
39
|
/**
|
|
30
40
|
* Actions the model MAY invoke. Derived from the registry but filtered by the
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export function compareChatOrder(a, b) {
|
|
2
|
+
if (a.eventSeq !== undefined &&
|
|
3
|
+
b.eventSeq !== undefined &&
|
|
4
|
+
a.eventSeq !== b.eventSeq) {
|
|
5
|
+
return a.eventSeq - b.eventSeq;
|
|
6
|
+
}
|
|
7
|
+
if (a.createdAt !== b.createdAt)
|
|
8
|
+
return a.createdAt - b.createdAt;
|
|
9
|
+
// Same timestamp with mismatched sequence presence: keep the original
|
|
10
|
+
// insertion order (stable sort). Deciding here would re-order live SSE
|
|
11
|
+
// frames that happen to share a millisecond with a tool row.
|
|
12
|
+
return 0;
|
|
13
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Turn grouping for Operator Chat inline process UX (pi-web ProcessDetails mind).
|
|
3
3
|
*/
|
|
4
|
+
import { compareChatOrder } from "./turn-order.js";
|
|
4
5
|
import { getDisplayableAssistantBlocks, joinAssistantText, parseAssistantContent, splitFinalAssistantBlocks, } from "./assistant-content.js";
|
|
5
6
|
import { dagProgressActivityForTool, semanticActivityForTool, } from "./semantic-activity.js";
|
|
6
7
|
function emptyGroup(key) {
|
|
@@ -264,13 +265,14 @@ function fillProcessDetails(group) {
|
|
|
264
265
|
items,
|
|
265
266
|
});
|
|
266
267
|
}
|
|
267
|
-
|
|
268
|
+
// Unified order (DSH rule): server seq is the single authoritative key,
|
|
269
|
+
// createdAt falls back, insertion order breaks remaining ties. No
|
|
270
|
+
// "fullySequenced" switch — a partially-sequenced group must not
|
|
271
|
+
// silently re-sort its peers by wall clock when most nodes carry seq.
|
|
268
272
|
nodes.sort((a, b) => {
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
if (a.createdAt !== b.createdAt)
|
|
273
|
-
return a.createdAt - b.createdAt;
|
|
273
|
+
const byOrder = compareChatOrder(a, b);
|
|
274
|
+
if (byOrder !== 0)
|
|
275
|
+
return byOrder;
|
|
274
276
|
return a.insertionOrder - b.insertionOrder;
|
|
275
277
|
});
|
|
276
278
|
const processItems = nodes.flatMap((node) => node.items);
|
|
@@ -301,20 +303,7 @@ function fillProcessDetails(group) {
|
|
|
301
303
|
export function buildTurnProcessGroups(input) {
|
|
302
304
|
const visible = input.messages
|
|
303
305
|
.filter((m) => m.role === "user" || m.role === "assistant")
|
|
304
|
-
.sort(
|
|
305
|
-
if (a.eventSeq !== undefined &&
|
|
306
|
-
b.eventSeq !== undefined &&
|
|
307
|
-
a.eventSeq !== b.eventSeq) {
|
|
308
|
-
return a.eventSeq - b.eventSeq;
|
|
309
|
-
}
|
|
310
|
-
if (a.createdAt !== b.createdAt)
|
|
311
|
-
return a.createdAt - b.createdAt;
|
|
312
|
-
if (a.eventSeq !== undefined && b.eventSeq === undefined)
|
|
313
|
-
return 1;
|
|
314
|
-
if (a.eventSeq === undefined && b.eventSeq !== undefined)
|
|
315
|
-
return -1;
|
|
316
|
-
return 0;
|
|
317
|
-
});
|
|
306
|
+
.sort(compareChatOrder);
|
|
318
307
|
const groups = [];
|
|
319
308
|
let current = null;
|
|
320
309
|
const startGroup = (key) => {
|
|
@@ -326,6 +315,8 @@ export function buildTurnProcessGroups(input) {
|
|
|
326
315
|
if (message.role === "user") {
|
|
327
316
|
current = startGroup(`user-${message.id}`);
|
|
328
317
|
current.user = message;
|
|
318
|
+
if (message.turnId)
|
|
319
|
+
current.turnId = message.turnId;
|
|
329
320
|
continue;
|
|
330
321
|
}
|
|
331
322
|
if (message.kind === "compaction") {
|
|
@@ -333,12 +324,16 @@ export function buildTurnProcessGroups(input) {
|
|
|
333
324
|
// prevents it from replacing the previous turn's assistant answer.
|
|
334
325
|
current = startGroup(`compaction-${message.id}`);
|
|
335
326
|
current.assistants.push(message);
|
|
327
|
+
if (message.turnId)
|
|
328
|
+
current.turnId = message.turnId;
|
|
336
329
|
current = null;
|
|
337
330
|
continue;
|
|
338
331
|
}
|
|
339
332
|
if (!current)
|
|
340
333
|
current = startGroup(`assistant-${message.id}`);
|
|
341
334
|
current.assistants.push(message);
|
|
335
|
+
if (current.turnId === undefined && message.turnId)
|
|
336
|
+
current.turnId = message.turnId;
|
|
342
337
|
}
|
|
343
338
|
const assigned = new Set();
|
|
344
339
|
const assistantToGroup = new Map();
|
|
@@ -360,10 +355,10 @@ export function buildTurnProcessGroups(input) {
|
|
|
360
355
|
if (assigned.has(tool.id))
|
|
361
356
|
continue;
|
|
362
357
|
if (tool.turnId) {
|
|
363
|
-
const byTurn = groups.find((group) => group.
|
|
358
|
+
const byTurn = groups.find((group) => group.turnId === tool.turnId ||
|
|
359
|
+
group.user?.turnId === tool.turnId ||
|
|
364
360
|
group.assistants.some((assistant) => assistant.turnId === tool.turnId) ||
|
|
365
361
|
group.tools.some((t) => t.turnId === tool.turnId) ||
|
|
366
|
-
group.key === `turn-${tool.turnId}` ||
|
|
367
362
|
(group.user && `restored-${group.user.id}` === tool.turnId));
|
|
368
363
|
if (byTurn) {
|
|
369
364
|
byTurn.tools.push(tool);
|
|
@@ -379,13 +374,25 @@ export function buildTurnProcessGroups(input) {
|
|
|
379
374
|
}
|
|
380
375
|
}
|
|
381
376
|
}
|
|
377
|
+
// Time-window fallback for legacy rows with neither assistantMessageId nor
|
|
378
|
+
// turnId. The window ends at the NEXT group's first anchor (user OR first
|
|
379
|
+
// assistant) — using POSITIVE_INFINITY would swallow every later group's
|
|
380
|
+
// tools when the very next group has no user message (e.g. compaction or a
|
|
381
|
+
// stand-alone assistant row), dumping one turn's bash cards into another.
|
|
382
382
|
for (const tool of input.toolCalls) {
|
|
383
383
|
if (assigned.has(tool.id))
|
|
384
384
|
continue;
|
|
385
385
|
const windowGroup = groups.find((group, index) => {
|
|
386
386
|
const start = group.user?.createdAt ?? group.assistants[0]?.createdAt ?? 0;
|
|
387
|
-
|
|
388
|
-
|
|
387
|
+
let end = Number.POSITIVE_INFINITY;
|
|
388
|
+
for (let i = index + 1; i < groups.length; i += 1) {
|
|
389
|
+
const next = groups[i];
|
|
390
|
+
const nextAnchor = next?.user?.createdAt ?? next?.assistants[0]?.createdAt;
|
|
391
|
+
if (nextAnchor !== undefined) {
|
|
392
|
+
end = nextAnchor;
|
|
393
|
+
break;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
389
396
|
return tool.createdAt >= start && tool.createdAt < end;
|
|
390
397
|
});
|
|
391
398
|
// Time window only. Never dump unmatched tools onto the latest group:
|
|
@@ -396,12 +403,7 @@ export function buildTurnProcessGroups(input) {
|
|
|
396
403
|
}
|
|
397
404
|
}
|
|
398
405
|
for (const group of groups) {
|
|
399
|
-
group.tools.sort(
|
|
400
|
-
if (a.eventSeq !== undefined && b.eventSeq !== undefined) {
|
|
401
|
-
return a.eventSeq - b.eventSeq;
|
|
402
|
-
}
|
|
403
|
-
return a.createdAt - b.createdAt;
|
|
404
|
-
});
|
|
406
|
+
group.tools.sort(compareChatOrder);
|
|
405
407
|
group.live =
|
|
406
408
|
input.streaming &&
|
|
407
409
|
input.activeAssistantId !== null &&
|
|
@@ -67,29 +67,11 @@ export async function performConsoleUpdateAndInit(deps, channel = "latest") {
|
|
|
67
67
|
return failed("INSTALL_VERIFICATION_FAILED", verified.reason, maintenance);
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
|
-
const initResult = await deps.applySafeInit();
|
|
71
|
-
maintenance.initialization = initResult.ok
|
|
72
|
-
? { status: "clean", pendingPaths: initResult.pendingPaths }
|
|
73
|
-
: {
|
|
74
|
-
status: "needs-reconcile",
|
|
75
|
-
pendingPaths: initResult.pendingPaths,
|
|
76
|
-
message: initResult.message,
|
|
77
|
-
};
|
|
78
70
|
if (!packageChanged) {
|
|
79
|
-
return {
|
|
80
|
-
state: initResult.ok ? "succeeded" : "needs-reconcile",
|
|
81
|
-
maintenance,
|
|
82
|
-
...(initResult.ok
|
|
83
|
-
? {}
|
|
84
|
-
: {
|
|
85
|
-
errorCode: "INIT_NEEDS_RECONCILE",
|
|
86
|
-
errorMessage: initResult.message,
|
|
87
|
-
}),
|
|
88
|
-
};
|
|
71
|
+
return { state: "succeeded", maintenance };
|
|
89
72
|
}
|
|
90
73
|
const handoff = await deps.requestHandoff({
|
|
91
74
|
targetVersion: target.version,
|
|
92
|
-
initResult,
|
|
93
75
|
});
|
|
94
76
|
if (!handoff.ok) {
|
|
95
77
|
maintenance.handoff = {
|
|
@@ -28,14 +28,13 @@ export function createConsoleUpdateExecutor(input) {
|
|
|
28
28
|
return performConsoleUpdateAndInit({
|
|
29
29
|
currentVersion,
|
|
30
30
|
preflight: async () => {
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
if (activity.workerProjectionError ||
|
|
31
|
+
const scopes = await input.workspaceActivity?.() ?? [input];
|
|
32
|
+
const activities = await Promise.all(scopes.map(scope => readInitRuntimeActivity(scope.repoRoot)));
|
|
33
|
+
const operations = (await Promise.all(scopes.map(scope => scope.operations.list()))).flat();
|
|
34
|
+
if (activities.some(activity => activity.workerProjectionError ||
|
|
36
35
|
activity.activeDagRunIds.length > 0 ||
|
|
37
36
|
activity.activeWorkerTasks > 0 ||
|
|
38
|
-
activity.activeWorkerBatches > 0) {
|
|
37
|
+
activity.activeWorkerBatches > 0)) {
|
|
39
38
|
return {
|
|
40
39
|
ok: false,
|
|
41
40
|
code: "ACTIVE_RUNTIME",
|
|
@@ -64,20 +63,6 @@ export function createConsoleUpdateExecutor(input) {
|
|
|
64
63
|
canAutoInstall: () => npm.canAutoInstall(),
|
|
65
64
|
installExact: (version, selectedChannel) => npm.installExact(version, selectedChannel),
|
|
66
65
|
verifyInstalled: (version) => npm.verifyInstalled(version),
|
|
67
|
-
applySafeInit: async () => {
|
|
68
|
-
const result = await input.client.runExternal("loop-agent", ["init", "update", "--apply-safe", "--repo-root", input.repoRoot], {
|
|
69
|
-
cwd: input.repoRoot,
|
|
70
|
-
artifactName: "console-update-safe-init",
|
|
71
|
-
timeoutMs: 120_000,
|
|
72
|
-
});
|
|
73
|
-
return result.ok
|
|
74
|
-
? { ok: true, pendingPaths: [] }
|
|
75
|
-
: {
|
|
76
|
-
ok: false,
|
|
77
|
-
message: result.stderr || result.stdout || "safe initialization failed",
|
|
78
|
-
pendingPaths: [],
|
|
79
|
-
};
|
|
80
|
-
},
|
|
81
66
|
requestHandoff: async ({ targetVersion }) => input.requestHandoff(targetVersion),
|
|
82
67
|
}, channel);
|
|
83
68
|
};
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { prepareScheduledTask } from "./chat/scheduled-goal-request.js";
|
|
2
|
+
import { ScheduledGoalStore } from "../scheduler/scheduled-goal-store.js";
|
|
3
|
+
import { prepareScheduledGoalBooking, confirmScheduledGoalBooking, getScheduledGoalBooking } from "./chat/scheduled-goal-booking.js";
|
|
1
4
|
import { access, readFile } from "node:fs/promises";
|
|
2
5
|
import { buildOperatorCapabilitiesDocument, OFFICIAL_TAIL_ACTION_IDS, } from "../../shared/operator/capabilities.js";
|
|
3
6
|
import { DAG_RERUN_PROMPT_OVERRIDE_ENV, isDagRerunPromptOverrideEnabled, MAX_DAG_RERUN_PROMPT_OVERRIDE_CHARS, } from "../../shared/dag-prompt-override.js";
|
|
@@ -772,7 +775,7 @@ async function acceptConsoleUpdateAndInit(ctx, clientRequestId, channel) {
|
|
|
772
775
|
at: new Date().toISOString(),
|
|
773
776
|
kind: "state",
|
|
774
777
|
state: "running",
|
|
775
|
-
message: `checking runtime
|
|
778
|
+
message: `checking runtime and npm ${channel}`,
|
|
776
779
|
});
|
|
777
780
|
try {
|
|
778
781
|
const result = await ctx.consoleUpdateExecutor(channel);
|
|
@@ -849,6 +852,18 @@ export async function dispatchOperatorAction(ctx, req) {
|
|
|
849
852
|
};
|
|
850
853
|
}
|
|
851
854
|
const p = paramsOf(req);
|
|
855
|
+
if (action === "workspaceInitialize") {
|
|
856
|
+
if (req.source !== "human-ui")
|
|
857
|
+
return { kind: "error", status: 403, body: operatorFailed({ command: action, outcome: "blocked", code: "HUMAN_UI_REQUIRED", message: "工作区初始化需要从界面显式发起" }) };
|
|
858
|
+
if (!req.clientRequestId?.trim() || Object.keys(p).some(key => key !== "model") || (p.model !== undefined && (typeof p.model !== "string" || p.model.length > 300)))
|
|
859
|
+
return invalid(action, "只接受 clientRequestId 和可选模型引用");
|
|
860
|
+
if (!ctx.workspaceInitialization)
|
|
861
|
+
return invalid(action, "工作区初始化服务不可用");
|
|
862
|
+
const created = await ctx.workspaceInitialization.start(req.clientRequestId, p.model);
|
|
863
|
+
if (created.kind === "conflict")
|
|
864
|
+
return { kind: "error", status: 409, body: operatorFailed({ command: action, outcome: "conflict", code: "REQUEST_ID_REUSE_CONFLICT", message: created.message }) };
|
|
865
|
+
return { kind: "accepted", status: 202, body: { operationId: created.operation.operationId, state: created.operation.state, clientRequestId: created.operation.clientRequestId, action } };
|
|
866
|
+
}
|
|
852
867
|
if (action === "consoleUpdateAndInit") {
|
|
853
868
|
if (req.source !== "human-ui") {
|
|
854
869
|
return {
|
|
@@ -874,6 +889,52 @@ export async function dispatchOperatorAction(ctx, req) {
|
|
|
874
889
|
}
|
|
875
890
|
return acceptConsoleUpdateAndInit(ctx, req.clientRequestId, channel);
|
|
876
891
|
}
|
|
892
|
+
if (["prepareScheduledTask", "prepareScheduledGoal", "confirmScheduledGoal", "scheduledGoalGet", "scheduledGoalList", "cancelScheduledGoal"].includes(action)) {
|
|
893
|
+
try {
|
|
894
|
+
const goals = new ScheduledGoalStore(ctx.repoRoot);
|
|
895
|
+
const { ChatSessionStore } = await import("./chat/session-store.js");
|
|
896
|
+
const deps = { goals, client: ctx.client, sessions: new ChatSessionStore(ctx.appData) };
|
|
897
|
+
let result;
|
|
898
|
+
if (action === "prepareScheduledTask") {
|
|
899
|
+
if (!ctx.chatSessionRef || Object.keys(p).some((key) => key !== "request"))
|
|
900
|
+
return invalid(action, "requires a host-bound Chat session and request only");
|
|
901
|
+
result = await prepareScheduledTask(p.request, { repoRoot: ctx.repoRoot, preparationRoot: nodePath.join(ctx.appData.staged, "scheduled-tasks"),
|
|
902
|
+
sessionId: ctx.chatSessionRef, client: ctx.client, sessions: deps.sessions });
|
|
903
|
+
}
|
|
904
|
+
else if (action === "prepareScheduledGoal") {
|
|
905
|
+
if (Object.keys(p).some((key) => key !== "booking"))
|
|
906
|
+
return invalid(action, "only booking may be provided");
|
|
907
|
+
result = await prepareScheduledGoalBooking(p.booking, deps);
|
|
908
|
+
}
|
|
909
|
+
else if (action === "confirmScheduledGoal") {
|
|
910
|
+
result = await confirmScheduledGoalBooking(p, deps, { source: req.source, requestId: req.clientRequestId });
|
|
911
|
+
}
|
|
912
|
+
else if (action === "cancelScheduledGoal") {
|
|
913
|
+
if (req.source !== "human-ui" || !req.clientRequestId?.trim())
|
|
914
|
+
return invalid(action, "human cancellation required");
|
|
915
|
+
if (Object.keys(p).some((key) => !["goalId", "stateVersion", "reason"].includes(key)) ||
|
|
916
|
+
typeof p.goalId !== "string" || !Number.isSafeInteger(p.stateVersion) || typeof p.reason !== "string")
|
|
917
|
+
return invalid(action, "goalId, stateVersion and reason required");
|
|
918
|
+
await goals.cancel(p.goalId, p.stateVersion, req.clientRequestId, p.reason);
|
|
919
|
+
result = await getScheduledGoalBooking(p.goalId, goals);
|
|
920
|
+
}
|
|
921
|
+
else if (action === "scheduledGoalGet") {
|
|
922
|
+
if (Object.keys(p).some((key) => key !== "goalId") || typeof p.goalId !== "string")
|
|
923
|
+
return invalid(action, "goalId required");
|
|
924
|
+
result = await getScheduledGoalBooking(p.goalId, goals);
|
|
925
|
+
}
|
|
926
|
+
else {
|
|
927
|
+
if (Object.keys(p).some((key) => key !== "chatSessionRef") || (p.chatSessionRef !== undefined && typeof p.chatSessionRef !== "string"))
|
|
928
|
+
return invalid(action, "only optional chatSessionRef may be provided");
|
|
929
|
+
const records = (await goals.list()).filter((goal) => !p.chatSessionRef || goal.frozen.chatSessionRef === p.chatSessionRef);
|
|
930
|
+
result = await Promise.all(records.map((goal) => getScheduledGoalBooking(goal.goalId, goals)));
|
|
931
|
+
}
|
|
932
|
+
return { kind: "sync", status: 200, body: operatorSucceeded(action, result) };
|
|
933
|
+
}
|
|
934
|
+
catch (error) {
|
|
935
|
+
return invalid(action, error instanceof Error ? error.message : String(error));
|
|
936
|
+
}
|
|
937
|
+
}
|
|
877
938
|
switch (action) {
|
|
878
939
|
case "operatorCapabilities": {
|
|
879
940
|
const doc = buildOperatorCapabilitiesDocument();
|
|
@@ -1065,6 +1126,7 @@ export async function dispatchOperatorAction(ctx, req) {
|
|
|
1065
1126
|
const args = ["dag", "doctor"];
|
|
1066
1127
|
if (runId)
|
|
1067
1128
|
args.push("--run-id", runId);
|
|
1129
|
+
args.push("--json");
|
|
1068
1130
|
const body = await runReadCli(ctx, args, "dag doctor");
|
|
1069
1131
|
return { kind: "sync", status: body.ok ? 200 : 400, body };
|
|
1070
1132
|
}
|