@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
|
@@ -17,7 +17,7 @@ import { OPERATOR_CHAT_ALLOWED_TOOLS, OPERATOR_CHAT_DENIED_TOOLS, OPERATOR_CHAT_
|
|
|
17
17
|
import { buildModelCallableToolSchemas } from "./tool-adapter.js";
|
|
18
18
|
import { cleanChatTitle, acceptedOperationIdFromResult } from "./session-store.js";
|
|
19
19
|
import { hashChatTurnPayload, projectChatToolEventPayload, projectCompactSnapshot, } from "./chat-event-store.js";
|
|
20
|
-
import { projectDeferredTurnSummary, } from "./deferred-turn.js";
|
|
20
|
+
import { projectDeferredTurnSummary, projectDeferredTurnSummaries, } from "./deferred-turn.js";
|
|
21
21
|
import { THINKING_LEVELS, RuntimeSnapshotUnavailableError, } from "./pi-runtime.js";
|
|
22
22
|
import { ResourcePreferencesError, setSkillAutoInvocationPreference, } from "./resource-preferences-store.js";
|
|
23
23
|
import { ComposerDraftStore } from "./composer-draft-store.js";
|
|
@@ -33,9 +33,11 @@ import { dispatchOperatorAction } from "../operator-actions.js";
|
|
|
33
33
|
import { makeHumanGateCard, } from "./human-gate-card.js";
|
|
34
34
|
import { ContractApplyReceiptStore } from "./contract-apply-receipt-store.js";
|
|
35
35
|
import { projectTaskContext } from "./context-panel.js";
|
|
36
|
+
import { deriveChatSessionTelemetry } from "./session-stats.js";
|
|
36
37
|
import { contractApplyPayloadHash, issueHumanGateToken, verifyHumanGateToken, } from "../human-gate-token.js";
|
|
37
38
|
import { sendJson } from "../routes.js";
|
|
38
39
|
import { openSseResponse, writeSseEvent } from "../operation-sse.js";
|
|
40
|
+
import { buildTodoCompactionInstructions, projectCurrentTodos } from "./todos.js";
|
|
39
41
|
function turnSummary(turn) {
|
|
40
42
|
return {
|
|
41
43
|
turnId: turn.turnId,
|
|
@@ -87,11 +89,38 @@ function turnEventToStorePartial(event) {
|
|
|
87
89
|
case "message_update":
|
|
88
90
|
case "message_end": {
|
|
89
91
|
const content = parseAssistantContent(event.content);
|
|
92
|
+
const timingSource = event.type === "message_end" &&
|
|
93
|
+
event.timing &&
|
|
94
|
+
typeof event.timing === "object"
|
|
95
|
+
? event.timing
|
|
96
|
+
: undefined;
|
|
97
|
+
const timing = timingSource &&
|
|
98
|
+
typeof timingSource.llmMs === "number" &&
|
|
99
|
+
Number.isFinite(timingSource.llmMs)
|
|
100
|
+
? {
|
|
101
|
+
llmMs: Math.max(0, timingSource.llmMs),
|
|
102
|
+
...(typeof timingSource.ttftMs === "number" &&
|
|
103
|
+
Number.isFinite(timingSource.ttftMs)
|
|
104
|
+
? { ttftMs: Math.max(0, timingSource.ttftMs) }
|
|
105
|
+
: {}),
|
|
106
|
+
...(typeof timingSource.decodeMs === "number" &&
|
|
107
|
+
Number.isFinite(timingSource.decodeMs)
|
|
108
|
+
? { decodeMs: Math.max(0, timingSource.decodeMs) }
|
|
109
|
+
: {}),
|
|
110
|
+
...(typeof timingSource.outputTokens === "number" &&
|
|
111
|
+
Number.isFinite(timingSource.outputTokens)
|
|
112
|
+
? {
|
|
113
|
+
outputTokens: Math.max(0, timingSource.outputTokens),
|
|
114
|
+
}
|
|
115
|
+
: {}),
|
|
116
|
+
}
|
|
117
|
+
: undefined;
|
|
90
118
|
return {
|
|
91
119
|
kind: event.type,
|
|
92
120
|
data: {
|
|
93
121
|
text: String(event.text ?? ""),
|
|
94
122
|
...(content ? { content } : {}),
|
|
123
|
+
...(timing ? { timing } : {}),
|
|
95
124
|
},
|
|
96
125
|
};
|
|
97
126
|
}
|
|
@@ -123,6 +152,9 @@ function turnEventToStorePartial(event) {
|
|
|
123
152
|
}),
|
|
124
153
|
};
|
|
125
154
|
}
|
|
155
|
+
case "todo_updated":
|
|
156
|
+
case "todo_cleared":
|
|
157
|
+
return { kind: event.type, data: { todos: Array.isArray(event.todos) ? event.todos : [], ...(event.toolCallId ? { toolCallId: String(event.toolCallId) } : {}) } };
|
|
126
158
|
case "agent_end":
|
|
127
159
|
return {
|
|
128
160
|
kind: "agent_end",
|
|
@@ -130,8 +162,19 @@ function turnEventToStorePartial(event) {
|
|
|
130
162
|
};
|
|
131
163
|
case "agent_settled":
|
|
132
164
|
return { kind: "agent_settled", data: {} };
|
|
133
|
-
case "error":
|
|
134
|
-
|
|
165
|
+
case "error": {
|
|
166
|
+
const content = parseAssistantContent(event.content);
|
|
167
|
+
return {
|
|
168
|
+
kind: "error",
|
|
169
|
+
data: {
|
|
170
|
+
message: String(event.message ?? ""),
|
|
171
|
+
...(content ? { content } : {}),
|
|
172
|
+
...(event.providerError && typeof event.providerError === "object"
|
|
173
|
+
? { providerError: event.providerError }
|
|
174
|
+
: {}),
|
|
175
|
+
},
|
|
176
|
+
};
|
|
177
|
+
}
|
|
135
178
|
default:
|
|
136
179
|
return undefined;
|
|
137
180
|
}
|
|
@@ -197,6 +240,13 @@ function ensureAgentEndEvent(deps, sessionId, turnId) {
|
|
|
197
240
|
}
|
|
198
241
|
}
|
|
199
242
|
async function readJsonBody(req, maxBytes = 2 * 1024 * 1024) {
|
|
243
|
+
// AC-R5-003: the multi-workspace dispatcher (server.ts readBodyOnce)
|
|
244
|
+
// pre-reads and JSON-parses the body for workspaceId resolution, stashing
|
|
245
|
+
// it on req.__preReadBody. Consume it first so the body is parsed exactly
|
|
246
|
+
// once per request; re-reading the consumed stream would yield {}.
|
|
247
|
+
const preRead = req.__preReadBody;
|
|
248
|
+
if (preRead !== undefined)
|
|
249
|
+
return preRead;
|
|
200
250
|
const chunks = [];
|
|
201
251
|
let total = 0;
|
|
202
252
|
for await (const chunk of req) {
|
|
@@ -270,6 +320,7 @@ export function parseChatImages(value) {
|
|
|
270
320
|
}
|
|
271
321
|
function gateMutation(req, deps) {
|
|
272
322
|
const failure = evaluateMutationGate(req, {
|
|
323
|
+
cookieName: deps.bootToken.cookieName,
|
|
273
324
|
bootToken: deps.bootToken.value,
|
|
274
325
|
confirmationToken: deps.bootToken.confirmationToken,
|
|
275
326
|
consoleOrigin: deps.getConsoleOrigin(),
|
|
@@ -343,7 +394,10 @@ export async function handleChatCapabilities(_req, res, deps) {
|
|
|
343
394
|
hasBash: true,
|
|
344
395
|
});
|
|
345
396
|
}
|
|
346
|
-
export async function handleCreateChatSession(req, res, deps
|
|
397
|
+
export async function handleCreateChatSession(req, res, deps,
|
|
398
|
+
/** Explicit owning workspaceId from the multi-workspace dispatcher
|
|
399
|
+
* (AC-R7-002). The body still parses exactly once via req.__preReadBody. */
|
|
400
|
+
workspaceId) {
|
|
347
401
|
const gate = gateMutation(req, deps);
|
|
348
402
|
if (!gate.ok) {
|
|
349
403
|
sendJson(res, gate.status, {
|
|
@@ -421,6 +475,10 @@ export async function handleCreateChatSession(req, res, deps) {
|
|
|
421
475
|
sessionFile: handle.sessionFile,
|
|
422
476
|
modelProvider: handle.model?.provider,
|
|
423
477
|
modelId: handle.model?.modelId,
|
|
478
|
+
// AC-R7-002: explicit parameter from the dispatcher — the runtime
|
|
479
|
+
// store.create wrapper is gone; body workspaceId (if any) only acts as
|
|
480
|
+
// a fallback for direct (non-dispatcher) handler tests.
|
|
481
|
+
workspaceId: workspaceId ?? (typeof body.workspaceId === "string" && body.workspaceId ? body.workspaceId : undefined),
|
|
424
482
|
});
|
|
425
483
|
if (snapshot)
|
|
426
484
|
deps.events.append(handle.sessionId, `${handle.sessionId}:snapshot`, {
|
|
@@ -645,8 +703,10 @@ export async function handleGetChatSession(_req, res, deps, sessionId) {
|
|
|
645
703
|
await deps.operationLinker.recoverSession(sessionId);
|
|
646
704
|
const composerDraft = await new ComposerDraftStore(deps.appData).get(sessionId);
|
|
647
705
|
const snapshot = deps.events.snapshot(sessionId);
|
|
706
|
+
const telemetry = deriveChatSessionTelemetry(snapshot);
|
|
648
707
|
const lastEvent = snapshot.at(-1);
|
|
649
708
|
const activeTurn = deps.events.getActiveTurn(sessionId);
|
|
709
|
+
const pendingQuestion = await deps.questionRegistry?.get(sessionId);
|
|
650
710
|
sendJson(res, 200, {
|
|
651
711
|
ok: true,
|
|
652
712
|
eventEpoch: deps.events.epoch(sessionId),
|
|
@@ -659,8 +719,19 @@ export async function handleGetChatSession(_req, res, deps, sessionId) {
|
|
|
659
719
|
? "stopping"
|
|
660
720
|
: "running"
|
|
661
721
|
: "idle",
|
|
722
|
+
pendingQuestion: pendingQuestion ?? null,
|
|
723
|
+
todos: projectCurrentTodos(snapshot) ?? [],
|
|
662
724
|
},
|
|
663
725
|
hasBash: true,
|
|
726
|
+
sessionStats: telemetry.stats,
|
|
727
|
+
usage: telemetry.usage,
|
|
728
|
+
compactions: snapshot
|
|
729
|
+
.filter((event) => event.kind === "compact")
|
|
730
|
+
.map((event) => ({
|
|
731
|
+
eventId: event.eventId,
|
|
732
|
+
at: event.at,
|
|
733
|
+
data: event.data,
|
|
734
|
+
})),
|
|
664
735
|
lastEventId: lastEvent?.eventId ?? null,
|
|
665
736
|
lastEventSeq: lastEvent?.seq ?? 0,
|
|
666
737
|
});
|
|
@@ -727,13 +798,15 @@ export async function handlePutDeferredTurn(req, res, deps, sessionId) {
|
|
|
727
798
|
return;
|
|
728
799
|
}
|
|
729
800
|
const active = deps.events.getActiveTurn(sessionId);
|
|
730
|
-
|
|
801
|
+
// Queueing binds to the active Turn (running OR stopping); the durable
|
|
802
|
+
// follow-up auto-dispatches when that Turn reaches a terminal state.
|
|
803
|
+
if (!active || active.turnId !== blockedByTurnId) {
|
|
731
804
|
sendJson(res, 409, {
|
|
732
805
|
ok: false,
|
|
733
806
|
accepted: false,
|
|
734
807
|
error: {
|
|
735
|
-
code: "
|
|
736
|
-
message: "
|
|
808
|
+
code: "TURN_NOT_ACTIVE",
|
|
809
|
+
message: "没有匹配的运行中 Turn,无法保存待发送消息",
|
|
737
810
|
},
|
|
738
811
|
activeTurn: active ? turnSummary(active) : null,
|
|
739
812
|
});
|
|
@@ -766,11 +839,12 @@ export async function handlePutDeferredTurn(req, res, deps, sessionId) {
|
|
|
766
839
|
: "待发送消息无效或会话不存在",
|
|
767
840
|
},
|
|
768
841
|
deferredTurn: result.deferredTurn ?? null,
|
|
842
|
+
deferredTurns: projectDeferredTurnSummaries(await deps.store.listDeferredTurns(sessionId)),
|
|
769
843
|
summary: projectDeferredTurnSummary(result.deferredTurn),
|
|
770
844
|
});
|
|
771
845
|
return;
|
|
772
846
|
}
|
|
773
|
-
emitDeferredTurnUpdate(deps, sessionId, blockedByTurnId, result.deferredTurn, result.deferredTurn.revision);
|
|
847
|
+
await emitDeferredTurnUpdate(deps, sessionId, blockedByTurnId, result.deferredTurn, result.deferredTurn.revision);
|
|
774
848
|
sendJson(res, 200, {
|
|
775
849
|
ok: true,
|
|
776
850
|
accepted: true,
|
|
@@ -778,6 +852,7 @@ export async function handlePutDeferredTurn(req, res, deps, sessionId) {
|
|
|
778
852
|
state: result.deferredTurn.state,
|
|
779
853
|
revision: result.deferredTurn.revision,
|
|
780
854
|
deferredTurn: result.deferredTurn,
|
|
855
|
+
deferredTurns: projectDeferredTurnSummaries(await deps.store.listDeferredTurns(sessionId)),
|
|
781
856
|
summary: projectDeferredTurnSummary(result.deferredTurn),
|
|
782
857
|
});
|
|
783
858
|
void dispatchDeferredTurn(deps, sessionId);
|
|
@@ -823,18 +898,90 @@ export async function handleDeleteDeferredTurn(req, res, deps, sessionId) {
|
|
|
823
898
|
: "待发送消息已变化,请刷新后重试",
|
|
824
899
|
},
|
|
825
900
|
deferredTurn: result.deferredTurn ?? null,
|
|
901
|
+
deferredTurns: projectDeferredTurnSummaries(await deps.store.listDeferredTurns(sessionId)),
|
|
826
902
|
});
|
|
827
903
|
return;
|
|
828
904
|
}
|
|
829
905
|
const clearedRevision = result.deferredTurn.revision + 1;
|
|
830
|
-
emitDeferredTurnUpdate(deps, sessionId, result.deferredTurn.blockedByTurnId, undefined, clearedRevision);
|
|
906
|
+
await emitDeferredTurnUpdate(deps, sessionId, result.deferredTurn.blockedByTurnId, undefined, clearedRevision);
|
|
831
907
|
sendJson(res, 200, {
|
|
832
908
|
ok: true,
|
|
833
909
|
cancelled: true,
|
|
834
910
|
deferredTurn: result.deferredTurn,
|
|
911
|
+
deferredTurns: projectDeferredTurnSummaries(await deps.store.listDeferredTurns(sessionId)),
|
|
835
912
|
revision: clearedRevision,
|
|
836
913
|
});
|
|
837
914
|
}
|
|
915
|
+
/** Move one addressed FIFO item into Pi's live steering queue. */
|
|
916
|
+
export async function handleSteerDeferredTurn(req, res, deps, sessionId, clientRequestId) {
|
|
917
|
+
const gate = gateMutation(req, deps);
|
|
918
|
+
if (!gate.ok) {
|
|
919
|
+
sendJson(res, gate.status, { ok: false, error: { code: gate.code, message: gate.message } });
|
|
920
|
+
return;
|
|
921
|
+
}
|
|
922
|
+
let body = {};
|
|
923
|
+
try {
|
|
924
|
+
body = await readJsonBody(req);
|
|
925
|
+
}
|
|
926
|
+
catch (error) {
|
|
927
|
+
sendJson(res, 400, { ok: false, error: { code: "INVALID_INPUT", message: error instanceof Error ? error.message : String(error) } });
|
|
928
|
+
return;
|
|
929
|
+
}
|
|
930
|
+
const expectedRevision = typeof body.expectedRevision === "number" && Number.isSafeInteger(body.expectedRevision)
|
|
931
|
+
? body.expectedRevision
|
|
932
|
+
: -1;
|
|
933
|
+
const active = deps.events.getActiveTurn(sessionId);
|
|
934
|
+
if (!active) {
|
|
935
|
+
sendJson(res, 409, { ok: false, error: { code: "TURN_NOT_ACTIVE", message: "当前没有可插话的运行中回合" } });
|
|
936
|
+
return;
|
|
937
|
+
}
|
|
938
|
+
const claim = await deps.store.claimDeferredTurn(sessionId, expectedRevision, clientRequestId);
|
|
939
|
+
if (!claim.ok) {
|
|
940
|
+
sendJson(res, claim.code === "NOT_FOUND" ? 404 : 409, {
|
|
941
|
+
ok: false,
|
|
942
|
+
error: { code: claim.code, message: "排队消息已变化,请刷新后重试" },
|
|
943
|
+
});
|
|
944
|
+
return;
|
|
945
|
+
}
|
|
946
|
+
const item = claim.deferredTurn;
|
|
947
|
+
try {
|
|
948
|
+
await deps.runtime.steer(sessionId, item.text, item.images);
|
|
949
|
+
const userMessage = await deps.store.appendMessage(sessionId, {
|
|
950
|
+
role: "user",
|
|
951
|
+
text: item.text,
|
|
952
|
+
});
|
|
953
|
+
deps.events.append(sessionId, active.turnId, {
|
|
954
|
+
kind: "user_message",
|
|
955
|
+
data: {
|
|
956
|
+
clientRequestId: item.clientRequestId,
|
|
957
|
+
message: { id: userMessage.id, text: userMessage.text, at: userMessage.at },
|
|
958
|
+
},
|
|
959
|
+
});
|
|
960
|
+
await deps.store.clearDeferredTurnForRequest(sessionId, item.clientRequestId);
|
|
961
|
+
await emitDeferredTurnUpdate(deps, sessionId, active.turnId, undefined, item.revision + 2);
|
|
962
|
+
sendJson(res, 200, {
|
|
963
|
+
ok: true,
|
|
964
|
+
accepted: true,
|
|
965
|
+
deferredTurns: projectDeferredTurnSummaries(await deps.store.listDeferredTurns(sessionId)),
|
|
966
|
+
});
|
|
967
|
+
}
|
|
968
|
+
catch (error) {
|
|
969
|
+
const restored = await deps.store.transitionDeferredTurn(sessionId, {
|
|
970
|
+
expectedRevision: item.revision,
|
|
971
|
+
clientRequestId: item.clientRequestId,
|
|
972
|
+
state: "queued",
|
|
973
|
+
});
|
|
974
|
+
if (restored)
|
|
975
|
+
await emitDeferredTurnUpdate(deps, sessionId, active.turnId, restored, restored.revision);
|
|
976
|
+
sendJson(res, 409, {
|
|
977
|
+
ok: false,
|
|
978
|
+
error: {
|
|
979
|
+
code: "STEER_FAILED",
|
|
980
|
+
message: error instanceof Error ? error.message : "插话发送失败",
|
|
981
|
+
},
|
|
982
|
+
});
|
|
983
|
+
}
|
|
984
|
+
}
|
|
838
985
|
/** Lightweight busy-truth endpoint for the client reconcile loop (pi-web
|
|
839
986
|
* get_state equivalent): exposes the active turn + the latest turn's durable
|
|
840
987
|
* outcome WITHOUT the full message payload, so the UI can poll it on an
|
|
@@ -862,6 +1009,7 @@ export async function handleGetChatSessionState(_req, res, deps, sessionId) {
|
|
|
862
1009
|
isBashRunning: false,
|
|
863
1010
|
};
|
|
864
1011
|
const runtimeBusy = Object.values(runtimeFacts).some((value) => value === true);
|
|
1012
|
+
const pendingQuestion = await deps.questionRegistry?.get(sessionId);
|
|
865
1013
|
const turnPhase = active
|
|
866
1014
|
? active.abortRequestedAt
|
|
867
1015
|
? "stopping"
|
|
@@ -881,10 +1029,60 @@ export async function handleGetChatSessionState(_req, res, deps, sessionId) {
|
|
|
881
1029
|
latestTurn: latest ? turnSummary(latest) : null,
|
|
882
1030
|
runtime: runtimeFacts,
|
|
883
1031
|
turnPhase,
|
|
884
|
-
deferredTurn: projectDeferredTurnSummary(record.
|
|
1032
|
+
deferredTurn: projectDeferredTurnSummary(record.deferredTurns?.[0]),
|
|
1033
|
+
deferredTurns: projectDeferredTurnSummaries(record.deferredTurns ?? []),
|
|
1034
|
+
pendingQuestion: pendingQuestion ?? null,
|
|
1035
|
+
todos: projectCurrentTodos(deps.events.snapshot(sessionId)) ?? [],
|
|
885
1036
|
},
|
|
886
1037
|
});
|
|
887
1038
|
}
|
|
1039
|
+
export async function handleAnswerUserQuestion(req, res, deps, sessionId, requestId) {
|
|
1040
|
+
const gate = gateMutation(req, deps);
|
|
1041
|
+
if (!gate.ok) {
|
|
1042
|
+
sendJson(res, gate.status, { ok: false, error: { code: gate.code, message: gate.message } });
|
|
1043
|
+
return;
|
|
1044
|
+
}
|
|
1045
|
+
if (!(await requireChatSession(res, deps, sessionId)))
|
|
1046
|
+
return;
|
|
1047
|
+
if (!deps.questionRegistry) {
|
|
1048
|
+
sendJson(res, 503, { ok: false, error: { code: "USER_QUESTIONS_UNAVAILABLE", message: "user question capability is unavailable" } });
|
|
1049
|
+
return;
|
|
1050
|
+
}
|
|
1051
|
+
try {
|
|
1052
|
+
const body = await readJsonBody(req);
|
|
1053
|
+
const question = await deps.questionRegistry.answer(sessionId, requestId, body);
|
|
1054
|
+
sendJson(res, 200, { ok: true, resolved: true, question });
|
|
1055
|
+
}
|
|
1056
|
+
catch (error) {
|
|
1057
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1058
|
+
const status = message === "USER_QUESTION_NOT_FOUND" ? 404 : message === "USER_QUESTION_STALE" ? 409 : 400;
|
|
1059
|
+
sendJson(res, status, { ok: false, error: { code: message, message } });
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
export async function handleCancelUserQuestion(req, res, deps, sessionId, requestId) {
|
|
1063
|
+
const gate = gateMutation(req, deps);
|
|
1064
|
+
if (!gate.ok) {
|
|
1065
|
+
sendJson(res, gate.status, { ok: false, error: { code: gate.code, message: gate.message } });
|
|
1066
|
+
return;
|
|
1067
|
+
}
|
|
1068
|
+
if (!(await requireChatSession(res, deps, sessionId)))
|
|
1069
|
+
return;
|
|
1070
|
+
if (!deps.questionRegistry) {
|
|
1071
|
+
sendJson(res, 503, { ok: false, error: { code: "USER_QUESTIONS_UNAVAILABLE", message: "user question capability is unavailable" } });
|
|
1072
|
+
return;
|
|
1073
|
+
}
|
|
1074
|
+
try {
|
|
1075
|
+
const body = await readJsonBody(req).catch(() => ({}));
|
|
1076
|
+
const reason = typeof body.reason === "string" && body.reason.trim() ? body.reason.trim().slice(0, 120) : "USER_CANCELLED";
|
|
1077
|
+
const question = await deps.questionRegistry.cancel(sessionId, requestId, reason);
|
|
1078
|
+
sendJson(res, 200, { ok: true, cancelled: true, question });
|
|
1079
|
+
}
|
|
1080
|
+
catch (error) {
|
|
1081
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1082
|
+
const status = message === "USER_QUESTION_NOT_FOUND" ? 404 : 409;
|
|
1083
|
+
sendJson(res, status, { ok: false, error: { code: message, message } });
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
888
1086
|
export async function handleListChatSessions(_req, res, deps) {
|
|
889
1087
|
const sessions = await deps.store.list({ includeArchived: true });
|
|
890
1088
|
sendJson(res, 200, {
|
|
@@ -900,7 +1098,8 @@ export async function handleListChatSessions(_req, res, deps) {
|
|
|
900
1098
|
: active
|
|
901
1099
|
? "running"
|
|
902
1100
|
: "idle",
|
|
903
|
-
deferredTurn: projectDeferredTurnSummary(session.
|
|
1101
|
+
deferredTurn: projectDeferredTurnSummary(session.deferredTurns?.[0]),
|
|
1102
|
+
deferredTurns: projectDeferredTurnSummaries(session.deferredTurns ?? []),
|
|
904
1103
|
};
|
|
905
1104
|
}),
|
|
906
1105
|
hasBash: true,
|
|
@@ -1147,6 +1346,7 @@ export async function handleChatPrompt(req, res, deps, sessionId) {
|
|
|
1147
1346
|
store: deps.store,
|
|
1148
1347
|
actionContext,
|
|
1149
1348
|
sessionId,
|
|
1349
|
+
turnId,
|
|
1150
1350
|
text,
|
|
1151
1351
|
images,
|
|
1152
1352
|
signal: ac.signal,
|
|
@@ -1442,6 +1642,7 @@ export async function handleCreateChatTurn(req, res, deps, sessionId, trustedPay
|
|
|
1442
1642
|
store: deps.store,
|
|
1443
1643
|
actionContext,
|
|
1444
1644
|
sessionId,
|
|
1645
|
+
turnId: turn.turnId,
|
|
1445
1646
|
text,
|
|
1446
1647
|
images,
|
|
1447
1648
|
signal: controller.signal,
|
|
@@ -1527,12 +1728,16 @@ export async function handleCreateChatTurn(req, res, deps, sessionId, trustedPay
|
|
|
1527
1728
|
}
|
|
1528
1729
|
})();
|
|
1529
1730
|
}
|
|
1530
|
-
function emitDeferredTurnUpdate(deps, sessionId, turnId,
|
|
1731
|
+
async function emitDeferredTurnUpdate(deps, sessionId, turnId, _deferredTurn, _revision) {
|
|
1732
|
+
const record = await deps.store.get(sessionId);
|
|
1733
|
+
if (!record)
|
|
1734
|
+
return;
|
|
1531
1735
|
deps.events.append(sessionId, turnId, {
|
|
1532
1736
|
kind: "queue_update",
|
|
1533
1737
|
data: {
|
|
1534
|
-
deferredTurn: projectDeferredTurnSummary(
|
|
1535
|
-
|
|
1738
|
+
deferredTurn: projectDeferredTurnSummary(record.deferredTurns?.[0]),
|
|
1739
|
+
deferredTurns: projectDeferredTurnSummaries(record.deferredTurns ?? []),
|
|
1740
|
+
revision: record.deferredQueueRevision ?? 0,
|
|
1536
1741
|
},
|
|
1537
1742
|
});
|
|
1538
1743
|
}
|
|
@@ -1568,7 +1773,7 @@ export async function dispatchDeferredTurn(deps, sessionId) {
|
|
|
1568
1773
|
deferredDispatchingSessions.add(sessionId);
|
|
1569
1774
|
try {
|
|
1570
1775
|
let record = await deps.store.get(sessionId);
|
|
1571
|
-
let deferred = record?.
|
|
1776
|
+
let deferred = record?.deferredTurns?.find((item) => item.state === "dispatching" || item.state === "queued");
|
|
1572
1777
|
if (!deferred)
|
|
1573
1778
|
return;
|
|
1574
1779
|
if (deferred.state === "accepted")
|
|
@@ -1580,17 +1785,19 @@ export async function dispatchDeferredTurn(deps, sessionId) {
|
|
|
1580
1785
|
if (existing) {
|
|
1581
1786
|
const accepted = await deps.store.transitionDeferredTurn(sessionId, {
|
|
1582
1787
|
expectedRevision: deferred.revision,
|
|
1788
|
+
clientRequestId: deferred.clientRequestId,
|
|
1583
1789
|
state: "accepted",
|
|
1584
1790
|
acceptedTurnId: existing.turnId,
|
|
1585
1791
|
});
|
|
1586
1792
|
if (accepted)
|
|
1587
|
-
emitDeferredTurnUpdate(deps, sessionId, existing.turnId, accepted, accepted.revision);
|
|
1793
|
+
await emitDeferredTurnUpdate(deps, sessionId, existing.turnId, accepted, accepted.revision);
|
|
1588
1794
|
return;
|
|
1589
1795
|
}
|
|
1590
1796
|
if (deps.events.getActiveTurn(sessionId))
|
|
1591
1797
|
return;
|
|
1592
1798
|
const requeued = await deps.store.transitionDeferredTurn(sessionId, {
|
|
1593
1799
|
expectedRevision: deferred.revision,
|
|
1800
|
+
clientRequestId: deferred.clientRequestId,
|
|
1594
1801
|
state: "queued",
|
|
1595
1802
|
});
|
|
1596
1803
|
if (!requeued)
|
|
@@ -1601,11 +1808,11 @@ export async function dispatchDeferredTurn(deps, sessionId) {
|
|
|
1601
1808
|
const runtimeBusy = Boolean(runtimeFacts && Object.values(runtimeFacts).some((value) => value === true));
|
|
1602
1809
|
if (deps.events.getActiveTurn(sessionId) || runtimeBusy)
|
|
1603
1810
|
return;
|
|
1604
|
-
const claim = await deps.store.claimDeferredTurn(sessionId, deferred.revision);
|
|
1811
|
+
const claim = await deps.store.claimDeferredTurn(sessionId, deferred.revision, deferred.clientRequestId);
|
|
1605
1812
|
if (!claim.ok)
|
|
1606
1813
|
return;
|
|
1607
1814
|
deferred = claim.deferredTurn;
|
|
1608
|
-
emitDeferredTurnUpdate(deps, sessionId, deferred.blockedByTurnId, deferred, deferred.revision);
|
|
1815
|
+
await emitDeferredTurnUpdate(deps, sessionId, deferred.blockedByTurnId, deferred, deferred.revision);
|
|
1609
1816
|
const started = await startTrustedChatTurn(deps, sessionId, {
|
|
1610
1817
|
clientRequestId: deferred.clientRequestId,
|
|
1611
1818
|
text: deferred.text,
|
|
@@ -1624,7 +1831,7 @@ export async function dispatchDeferredTurn(deps, sessionId) {
|
|
|
1624
1831
|
});
|
|
1625
1832
|
const cleared = await deps.store.clearDeferredTurnForRequest(sessionId, deferred.clientRequestId);
|
|
1626
1833
|
if (cleared)
|
|
1627
|
-
emitDeferredTurnUpdate(deps, sessionId, turnId, undefined, cleared.clearedRevision);
|
|
1834
|
+
await emitDeferredTurnUpdate(deps, sessionId, turnId, undefined, cleared.clearedRevision);
|
|
1628
1835
|
},
|
|
1629
1836
|
});
|
|
1630
1837
|
const accepted = started.body.accepted === true;
|
|
@@ -1634,11 +1841,12 @@ export async function dispatchDeferredTurn(deps, sessionId) {
|
|
|
1634
1841
|
if (accepted && turn?.turnId) {
|
|
1635
1842
|
const next = await deps.store.transitionDeferredTurn(sessionId, {
|
|
1636
1843
|
expectedRevision: deferred.revision,
|
|
1844
|
+
clientRequestId: deferred.clientRequestId,
|
|
1637
1845
|
state: "accepted",
|
|
1638
1846
|
acceptedTurnId: turn.turnId,
|
|
1639
1847
|
});
|
|
1640
1848
|
if (next)
|
|
1641
|
-
emitDeferredTurnUpdate(deps, sessionId, turn.turnId, next, next.revision);
|
|
1849
|
+
await emitDeferredTurnUpdate(deps, sessionId, turn.turnId, next, next.revision);
|
|
1642
1850
|
return;
|
|
1643
1851
|
}
|
|
1644
1852
|
const error = started.body.error && typeof started.body.error === "object"
|
|
@@ -1647,14 +1855,16 @@ export async function dispatchDeferredTurn(deps, sessionId) {
|
|
|
1647
1855
|
if (error.code === "TURN_ACTIVE") {
|
|
1648
1856
|
const next = await deps.store.transitionDeferredTurn(sessionId, {
|
|
1649
1857
|
expectedRevision: deferred.revision,
|
|
1858
|
+
clientRequestId: deferred.clientRequestId,
|
|
1650
1859
|
state: "queued",
|
|
1651
1860
|
});
|
|
1652
1861
|
if (next)
|
|
1653
|
-
emitDeferredTurnUpdate(deps, sessionId, deferred.blockedByTurnId, next, next.revision);
|
|
1862
|
+
await emitDeferredTurnUpdate(deps, sessionId, deferred.blockedByTurnId, next, next.revision);
|
|
1654
1863
|
return;
|
|
1655
1864
|
}
|
|
1656
1865
|
const failed = await deps.store.transitionDeferredTurn(sessionId, {
|
|
1657
1866
|
expectedRevision: deferred.revision,
|
|
1867
|
+
clientRequestId: deferred.clientRequestId,
|
|
1658
1868
|
state: "failed",
|
|
1659
1869
|
lastError: {
|
|
1660
1870
|
code: error.code ?? `HTTP_${started.status}`,
|
|
@@ -1662,17 +1872,18 @@ export async function dispatchDeferredTurn(deps, sessionId) {
|
|
|
1662
1872
|
},
|
|
1663
1873
|
});
|
|
1664
1874
|
if (failed)
|
|
1665
|
-
emitDeferredTurnUpdate(deps, sessionId, deferred.blockedByTurnId, failed, failed.revision);
|
|
1875
|
+
await emitDeferredTurnUpdate(deps, sessionId, deferred.blockedByTurnId, failed, failed.revision);
|
|
1666
1876
|
}
|
|
1667
1877
|
catch (error) {
|
|
1668
1878
|
// Keep fire-and-forget callers safe and make a dispatch failure visible and
|
|
1669
1879
|
// recoverable from the composer instead of leaving the slot indefinitely
|
|
1670
1880
|
// in an ambiguous queued/dispatching state.
|
|
1671
1881
|
try {
|
|
1672
|
-
const current = (await deps.store.get(sessionId))?.
|
|
1882
|
+
const current = (await deps.store.get(sessionId))?.deferredTurns?.find((item) => item.state === "queued" || item.state === "dispatching");
|
|
1673
1883
|
if (current && (current.state === "queued" || current.state === "dispatching")) {
|
|
1674
1884
|
const failed = await deps.store.transitionDeferredTurn(sessionId, {
|
|
1675
1885
|
expectedRevision: current.revision,
|
|
1886
|
+
clientRequestId: current.clientRequestId,
|
|
1676
1887
|
state: "failed",
|
|
1677
1888
|
lastError: {
|
|
1678
1889
|
code: "DEFERRED_TURN_DISPATCH_FAILED",
|
|
@@ -1680,7 +1891,7 @@ export async function dispatchDeferredTurn(deps, sessionId) {
|
|
|
1680
1891
|
},
|
|
1681
1892
|
});
|
|
1682
1893
|
if (failed)
|
|
1683
|
-
emitDeferredTurnUpdate(deps, sessionId, failed.blockedByTurnId, failed, failed.revision);
|
|
1894
|
+
await emitDeferredTurnUpdate(deps, sessionId, failed.blockedByTurnId, failed, failed.revision);
|
|
1684
1895
|
}
|
|
1685
1896
|
}
|
|
1686
1897
|
catch {
|
|
@@ -1695,12 +1906,9 @@ export async function dispatchDeferredTurn(deps, sessionId) {
|
|
|
1695
1906
|
export async function recoverDeferredTurns(deps) {
|
|
1696
1907
|
const sessions = await deps.store.list({ includeArchived: false });
|
|
1697
1908
|
await Promise.all(sessions
|
|
1698
|
-
.filter((session) => session.
|
|
1699
|
-
? session.deferredTurn.state === "queued" ||
|
|
1700
|
-
session.deferredTurn.state === "dispatching"
|
|
1701
|
-
: false)
|
|
1909
|
+
.filter((session) => (session.deferredTurns ?? []).some((item) => item.state === "queued" || item.state === "dispatching"))
|
|
1702
1910
|
.map(async (session) => {
|
|
1703
|
-
const deferred = session.
|
|
1911
|
+
const deferred = session.deferredTurns.find((item) => item.state === "dispatching" || item.state === "queued");
|
|
1704
1912
|
const active = deps.events.getActiveTurn(session.sessionId);
|
|
1705
1913
|
// A process restart cannot retain AbortController ownership. When the
|
|
1706
1914
|
// durable blocker was already stopping and no execution owns it now,
|
|
@@ -1768,6 +1976,7 @@ export async function handleAbortChatTurn(req, res, deps, sessionId, turnId) {
|
|
|
1768
1976
|
return;
|
|
1769
1977
|
}
|
|
1770
1978
|
deps.events.markAbortRequested?.(sessionId, turnId);
|
|
1979
|
+
await deps.questionRegistry?.cancelForSession(sessionId, "TURN_ABORTED").catch(() => undefined);
|
|
1771
1980
|
if (!execution.controller.signal.aborted)
|
|
1772
1981
|
execution.controller.abort();
|
|
1773
1982
|
const waited = await (deps.turnExecutions?.waitForCompletion(sessionId, turnId, DEFAULT_ABORT_WAIT_MS) ?? Promise.resolve({ status: "missing" }));
|
|
@@ -1918,6 +2127,8 @@ export async function handleDeleteChatSession(req, res, deps, sessionId) {
|
|
|
1918
2127
|
});
|
|
1919
2128
|
return;
|
|
1920
2129
|
}
|
|
2130
|
+
await deps.questionRegistry?.cancelForSession(sessionId, "SESSION_DELETED").catch(() => undefined);
|
|
2131
|
+
deps.todoRegistry?.clear(sessionId);
|
|
1921
2132
|
deps.runtime.dispose(sessionId);
|
|
1922
2133
|
deps.operationLinker.clearSession(sessionId);
|
|
1923
2134
|
deps.events.clear(sessionId);
|
|
@@ -2592,6 +2803,36 @@ async function handleLinkWorkspaceOperation(req, res, deps, sessionId) {
|
|
|
2592
2803
|
});
|
|
2593
2804
|
}
|
|
2594
2805
|
}
|
|
2806
|
+
async function handleUnlinkWorkspaceOperation(req, res, deps, sessionId, operationId) {
|
|
2807
|
+
const gate = gateMutation(req, deps);
|
|
2808
|
+
if (!gate.ok) {
|
|
2809
|
+
sendJson(res, gate.status, {
|
|
2810
|
+
ok: false,
|
|
2811
|
+
error: { code: gate.code, message: gate.message },
|
|
2812
|
+
});
|
|
2813
|
+
return;
|
|
2814
|
+
}
|
|
2815
|
+
if (!(await requireChatSession(res, deps, sessionId)))
|
|
2816
|
+
return;
|
|
2817
|
+
// AC-R7-001 (2026-08-23): removing a workspace-linked DAG association is
|
|
2818
|
+
// idempotent — a missing link is already-removed (200), never an error.
|
|
2819
|
+
try {
|
|
2820
|
+
const removed = await deps.operationLinker.unlink({
|
|
2821
|
+
sessionId,
|
|
2822
|
+
operationId,
|
|
2823
|
+
});
|
|
2824
|
+
sendJson(res, 200, { ok: true, removed });
|
|
2825
|
+
}
|
|
2826
|
+
catch (error) {
|
|
2827
|
+
sendJson(res, 400, {
|
|
2828
|
+
ok: false,
|
|
2829
|
+
error: {
|
|
2830
|
+
code: "INVALID_INPUT",
|
|
2831
|
+
message: error instanceof Error ? error.message : String(error),
|
|
2832
|
+
},
|
|
2833
|
+
});
|
|
2834
|
+
}
|
|
2835
|
+
}
|
|
2595
2836
|
async function handleStartInterview(req, res, deps, sessionId) {
|
|
2596
2837
|
const gate = gateMutation(req, deps);
|
|
2597
2838
|
if (!gate.ok) {
|
|
@@ -3244,7 +3485,8 @@ export async function handleChatCompact(req, res, deps, sessionId) {
|
|
|
3244
3485
|
return;
|
|
3245
3486
|
}
|
|
3246
3487
|
const rawInstructions = typeof body.instructions === "string" ? body.instructions : undefined;
|
|
3247
|
-
const
|
|
3488
|
+
const currentTodos = projectCurrentTodos(deps.events.snapshot(sessionId));
|
|
3489
|
+
const customInstructions = buildTodoCompactionInstructions(rawInstructions, currentTodos);
|
|
3248
3490
|
try {
|
|
3249
3491
|
const snapshot = await deps.runtime.compact(sessionId, customInstructions);
|
|
3250
3492
|
const event = deps.events.append(sessionId, deps.events.latestTurnId(sessionId) ?? `${sessionId}:compact`, { kind: "compact", data: snapshot });
|
|
@@ -3280,8 +3522,10 @@ export async function handleChatMessages(res, deps, sessionId, url) {
|
|
|
3280
3522
|
/**
|
|
3281
3523
|
* Dispatch a chat HTTP request. Returns true if handled.
|
|
3282
3524
|
* Mounted under /api/operator/v1/chat/*.
|
|
3525
|
+
* workspaceScope (AC-R7-002): the explicit owning workspaceId for session
|
|
3526
|
+
* create, forwarded to handleCreateChatSession → store.create.
|
|
3283
3527
|
*/
|
|
3284
|
-
export async function handleChatRequest(req, res, deps, pathname) {
|
|
3528
|
+
export async function handleChatRequest(req, res, deps, pathname, workspaceScope) {
|
|
3285
3529
|
if (!deps)
|
|
3286
3530
|
return false;
|
|
3287
3531
|
if (!pathname.startsWith("/api/operator/v1/chat/") &&
|
|
@@ -3359,6 +3603,16 @@ export async function handleChatRequest(req, res, deps, pathname) {
|
|
|
3359
3603
|
await handleStartInterview(req, res, deps, decodeURIComponent(interviewStart[1]));
|
|
3360
3604
|
return true;
|
|
3361
3605
|
}
|
|
3606
|
+
const userQuestionAnswer = pathname.match(/^\/api\/operator\/v1\/chat\/sessions\/([^/]+)\/questions\/([^/]+)\/answer$/);
|
|
3607
|
+
if (method === "POST" && userQuestionAnswer) {
|
|
3608
|
+
await handleAnswerUserQuestion(req, res, deps, decodeURIComponent(userQuestionAnswer[1]), decodeURIComponent(userQuestionAnswer[2]));
|
|
3609
|
+
return true;
|
|
3610
|
+
}
|
|
3611
|
+
const userQuestionCancel = pathname.match(/^\/api\/operator\/v1\/chat\/sessions\/([^/]+)\/questions\/([^/]+)\/cancel$/);
|
|
3612
|
+
if (method === "POST" && userQuestionCancel) {
|
|
3613
|
+
await handleCancelUserQuestion(req, res, deps, decodeURIComponent(userQuestionCancel[1]), decodeURIComponent(userQuestionCancel[2]));
|
|
3614
|
+
return true;
|
|
3615
|
+
}
|
|
3362
3616
|
const interviewAnswer = pathname.match(/^\/api\/operator\/v1\/chat\/sessions\/([^/]+)\/interviews\/([^/]+)\/answers$/);
|
|
3363
3617
|
if (method === "POST" && interviewAnswer) {
|
|
3364
3618
|
await handleAnswerInterview(req, res, deps, decodeURIComponent(interviewAnswer[1]), decodeURIComponent(interviewAnswer[2]));
|
|
@@ -3465,6 +3719,11 @@ export async function handleChatRequest(req, res, deps, pathname) {
|
|
|
3465
3719
|
await handleDeleteDeferredTurn(req, res, deps, decodeURIComponent(deferredTurn[1]));
|
|
3466
3720
|
return true;
|
|
3467
3721
|
}
|
|
3722
|
+
const deferredTurnSteer = pathname.match(/^\/api\/operator\/v1\/chat\/sessions\/([^/]+)\/deferred-turn\/([^/]+)\/steer$/);
|
|
3723
|
+
if (method === "POST" && deferredTurnSteer) {
|
|
3724
|
+
await handleSteerDeferredTurn(req, res, deps, decodeURIComponent(deferredTurnSteer[1]), decodeURIComponent(deferredTurnSteer[2]));
|
|
3725
|
+
return true;
|
|
3726
|
+
}
|
|
3468
3727
|
const sessionTurnAbort = pathname.match(/^\/api\/operator\/v1\/chat\/sessions\/([^/]+)\/turns\/([^/]+)\/abort$/);
|
|
3469
3728
|
if (method === "POST" && sessionTurnAbort) {
|
|
3470
3729
|
await handleAbortChatTurn(req, res, deps, decodeURIComponent(sessionTurnAbort[1]), decodeURIComponent(sessionTurnAbort[2]));
|
|
@@ -3480,6 +3739,13 @@ export async function handleChatRequest(req, res, deps, pathname) {
|
|
|
3480
3739
|
await handleLinkWorkspaceOperation(req, res, deps, decodeURIComponent(operationLink[1]));
|
|
3481
3740
|
return true;
|
|
3482
3741
|
}
|
|
3742
|
+
const operationLinkItem = pathname.match(/^\/api\/operator\/v1\/chat\/sessions\/([^/]+)\/operation-links\/([^/]+)$/);
|
|
3743
|
+
if (method === "DELETE" && operationLinkItem) {
|
|
3744
|
+
// AC-R7-001: Details rail DAG remove — real DELETE of the workspace
|
|
3745
|
+
// operation-link association (idempotent).
|
|
3746
|
+
await handleUnlinkWorkspaceOperation(req, res, deps, decodeURIComponent(operationLinkItem[1]), decodeURIComponent(operationLinkItem[2]));
|
|
3747
|
+
return true;
|
|
3748
|
+
}
|
|
3483
3749
|
const sessionCompact = pathname.match(/^\/api\/operator\/v1\/chat\/sessions\/([^/]+)\/compact$/);
|
|
3484
3750
|
if (method === "POST" && sessionCompact) {
|
|
3485
3751
|
await handleChatCompact(req, res, deps, decodeURIComponent(sessionCompact[1]));
|
|
@@ -3527,7 +3793,7 @@ export async function handleChatRequest(req, res, deps, pathname) {
|
|
|
3527
3793
|
}
|
|
3528
3794
|
}
|
|
3529
3795
|
if (method === "POST" && pathname === "/api/operator/v1/chat/sessions") {
|
|
3530
|
-
await handleCreateChatSession(req, res, deps);
|
|
3796
|
+
await handleCreateChatSession(req, res, deps, workspaceScope);
|
|
3531
3797
|
return true;
|
|
3532
3798
|
}
|
|
3533
3799
|
if (isMutationMethod(method)) {
|