@tea-agent/loop-agent 0.42.0-next.9 → 0.42.1
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/CHANGELOG.md +111 -45
- package/dist/application/dag/run-dag.js +8 -2
- package/dist/application/evaluation/budget.js +19 -1
- package/dist/application/task-lifecycle/advance.js +26 -8
- package/dist/application/task-lifecycle/observe.js +43 -29
- package/dist/application/task-lifecycle/plan-transitions.js +5 -4
- package/dist/build-stamp.json +3 -3
- package/dist/cli/program.js +1 -1
- package/dist/commands/dag-rerun-task.js +2 -0
- package/dist/commands/task-source-prepare.js +3 -1
- package/dist/executors/dag-pi-executor.js +2584 -600
- package/dist/executors/pi-executor.js +22 -1
- package/dist/executors/pi-extension-resolver.js +14 -2
- package/dist/executors/pi-sdk-executor.js +140 -39
- package/dist/executors/shell-executor.js +135 -55
- package/dist/shared/dag-failure-category.js +6 -0
- package/dist/shared/frontend-execution-policy.js +23 -0
- package/dist/task/config-types.js +4 -0
- package/dist/task/contract/apply.js +36 -2
- package/dist/task/source-prepare/ledger-reconciliation.js +2 -2
- package/dist/task/source-prepare/ledger-review.js +6 -9
- package/dist/task/source-prepare/parse-intent.js +7 -0
- package/dist/task/source-prepare/semantic-intake.js +16 -26
- package/dist/task/source-prepare/source-fidelity-pi.js +28 -9
- package/dist/task/source-references.js +48 -23
- package/dist/worker/console/chat/assistant-content.js +23 -2
- package/dist/worker/console/chat/browser-policy.js +143 -0
- package/dist/worker/console/chat/browser-routes.js +148 -0
- package/dist/worker/console/chat/chat-event-store.js +4 -2
- package/dist/worker/console/chat/explore-tools.js +13 -0
- package/dist/worker/console/chat/pi-runtime.js +173 -94
- package/dist/worker/console/chat/resource-loader.js +4 -1
- package/dist/worker/console/chat/routes.js +208 -66
- package/dist/worker/console/chat/scm-routes.js +217 -0
- package/dist/worker/console/chat/scm-service.js +283 -0
- package/dist/worker/console/chat/scm-tools.js +111 -0
- package/dist/worker/console/chat/sdd-data-alignment.js +78 -11
- package/dist/worker/console/chat/session-catalog.js +32 -0
- package/dist/worker/console/chat/session-mode-view.js +48 -0
- package/dist/worker/console/chat/session-mode.js +218 -0
- package/dist/worker/console/chat/session-store.js +27 -7
- package/dist/worker/console/chat/shortcuts.js +6 -0
- package/dist/worker/console/chat/subagents/agent-tool.js +62 -0
- package/dist/worker/console/chat/subagents/explore-agent.js +169 -0
- package/dist/worker/console/chat/subagents/index.js +5 -0
- package/dist/worker/console/chat/subagents/orchestrator.js +273 -0
- package/dist/worker/console/chat/subagents/tool-policy.js +53 -0
- package/dist/worker/console/chat/subagents/types.js +13 -0
- package/dist/worker/console/chat/terminal-routes.js +216 -0
- package/dist/worker/console/chat/terminal-sessions.js +284 -0
- package/dist/worker/console/chat/terminal-tools.js +199 -0
- package/dist/worker/console/chat/tool-preview.js +21 -0
- package/dist/worker/console/chat/tools.js +13 -1
- package/dist/worker/console/chat/turn-process.js +1 -0
- package/dist/worker/console/interview/tools.js +1 -0
- package/dist/worker/console/server.js +2 -28
- package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-C6n9_m0P.js → abnfDiagram-N423BO3Z-C9eI7nEo.js} +1 -1
- package/dist/worker/console/static/assets/{arc-DQh-IfZ1.js → arc-VJWsxWhB.js} +1 -1
- package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-54NnrwUC.js → architectureDiagram-T3A2C74G-BGcyiMSo.js} +1 -1
- package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-pivRALGK.js → blockDiagram-VBNYF7ZC-BScnFwyi.js} +1 -1
- package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-BR7OV2NJ.js → c4Diagram-5PPSVZJV-Bl9_BsLi.js} +1 -1
- package/dist/worker/console/static/assets/channel-B6sQYuOE.js +1 -0
- package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-B1Aq6BcK.js → chunk-2GRJ4B5K-F1uKxiUt.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-CbdU0rjo.js → chunk-2Q5K7J3B-rSRMynVu.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5RXB4S5H-Dqi2GJeD.js → chunk-5RXB4S5H-DAsJm1WD.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5VM5RSS4-BYn1Hu4R.js → chunk-5VM5RSS4-DQIdVI0a.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-DRLjDL0k.js → chunk-6Q2QTUOP-4A_8rJ-Q.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-GF5L2VYU-CY9Xx2jV.js → chunk-GF5L2VYU-BHnT-vjh.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-JWPE2WC7-BNCZs7_z.js → chunk-JWPE2WC7-Rq7QKBkn.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-KBJHAD2P-DZ8AStLL.js → chunk-KBJHAD2P-BXh-AI2u.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-RYQCIY6F-DsxjYrzz.js → chunk-RYQCIY6F-BblcLy8m.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-XXDRQBXY-Ddx1KC1l.js → chunk-XXDRQBXY-zHZmVnB6.js} +1 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-Z6s5QoeI.js +1 -0
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-Z6s5QoeI.js +1 -0
- package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-W9TveCnK.js → cose-bilkent-JH36ORCC-Cmwz0Wi4.js} +1 -1
- package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-l9j_ztZH.js → cynefin-VYW2F7L2-Dq76MHQU.js} +1 -1
- package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-BMJMKi4G.js → cynefinDiagram-MW4NZA55-zPahV1fM.js} +1 -1
- package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-Bb4mG9pH.js → dagre-VZM6K2ZE-DQJ3xPc_.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-7IWD3JNH-BMgL_Qv0.js → diagram-7IWD3JNH-BwX7u6fv.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-Bvo2T4OQ.js → diagram-B4RE2ZJO-CodnDCco.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-LBJQPF4R-_5kWRN9c.js → diagram-LBJQPF4R-gAjtWkxG.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-Q27KOJAE-DqdMrltM.js → diagram-Q27KOJAE-CGCqz0cS.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-UB23O5K3-CDDYsNkp.js → diagram-UB23O5K3-RHwYEywd.js} +1 -1
- package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-c4nfnZUV.js → ebnfDiagram-BXEA7PRR-B6seb_p_.js} +1 -1
- package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-DnkUcNMs.js → erDiagram-JOGREHBK-CmwCKYe8.js} +1 -1
- package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-Dz0KGLZE.js → flowDiagram-UKHOOZJN-BfNsaZ0V.js} +1 -1
- package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-Cj1t1uka.js → ganttDiagram-PKOTCBZU-zmYgi_Z3.js} +1 -1
- package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-tp2FrBHd.js → gitGraphDiagram-DS77QQ5N-BDEzzSKF.js} +1 -1
- package/dist/worker/console/static/assets/index-DgenUAfc.js +468 -0
- package/dist/worker/console/static/assets/index-aF4u-Y__.css +1 -0
- package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-DQwJS8DH.js → infoDiagram-6WML65LV-DeSz8l42.js} +1 -1
- package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-eimCQWD4.js → ishikawaDiagram-WSZJBQD7-B1LV29aH.js} +1 -1
- package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-Dd9Gbwgv.js → journeyDiagram-NVQOT4AX-CCw4W2oU.js} +1 -1
- package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-Qve3cyft.js → kanban-definition-27J2QSJJ-BozaMoRJ.js} +1 -1
- package/dist/worker/console/static/assets/{linear-UXKSe36Z.js → linear-G1JR40SX.js} +1 -1
- package/dist/worker/console/static/assets/{mermaid.core-CWhj4JXN.js → mermaid.core-CCgPF0oA.js} +5 -5
- package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-yTcwf4SJ.js → mindmap-definition-FAOFIHXS-CEqnCHnD.js} +1 -1
- package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-_7qToaZP.js → pegDiagram-VL7TDLO6-DpmQPKuI.js} +1 -1
- package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-CXmrKmDm.js → pieDiagram-7S7Q4E2Y-BP501AxR.js} +1 -1
- package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-hMmrJyaS.js → quadrantDiagram-CIZ2JOQS-D1dBhl_A.js} +1 -1
- package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-BXw8tCBe.js → railroadDiagram-AXF67PYL-DgZDS5pY.js} +1 -1
- package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-BmjgnLZl.js → requirementDiagram-LRYGKXZP-BzB3pyIq.js} +1 -1
- package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-Bj77SPpN.js → sankeyDiagram-W5VNT64P-B9ZprFFP.js} +1 -1
- package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-B2FDVysL.js → sequenceDiagram-SI44F4Z6-CC2-_XrA.js} +1 -1
- package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-UChNY9ZZ.js → sizeCapture-X5ZJPWSS-UVtAUqgB.js} +1 -1
- package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-wbAEkbd7.js → stateDiagram-OKZ733FA-CWcS5JYG.js} +1 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-BooX8u1Q.js +1 -0
- package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-DCEkU8HR.js → swimlanes-SLNWSIFB-C4p-dn06.js} +2 -2
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-D64_eqqE.js +8 -0
- package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-BGp7H06U.js → timeline-definition-Z64GVDOM-Dnz52OHX.js} +1 -1
- package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-DsCIQuWR.js → vennDiagram-T6HMQDX7-CzTE0Nfu.js} +1 -1
- package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-cRZLP4Xe.js → wardleyDiagram-T6FBY63Y-NAR9cjQQ.js} +1 -1
- package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-CP0xLR9Y.js → xychartDiagram-ELKLHX3M-DVMk8413.js} +1 -1
- package/dist/worker/console/static/index.html +2 -2
- package/dist/worker/console/static-src/chat-view-types.js +1 -1
- package/dist/worker/console/static-src/operator-chat/chat-link.js +94 -0
- package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +142 -7
- package/dist/worker/console/static-src/operator-chat/pending-user-message.js +44 -0
- package/dist/worker/console/static-src/operator-chat/process-label.js +41 -0
- package/dist/worker/console/static-src/operator-chat/tools-catalog.js +21 -2
- package/dist/worker/console/static-src/operator-chat/turn-group-equality.js +13 -0
- package/dist/worker/console/static-src/operator-chat/turn-stream-controller.js +2 -0
- package/dist/worker/console/static-src/operator-chat/use-searchable-hidden.js +51 -0
- package/dist/worker/console/static-src/operator-chat/useChatSessions.js +33 -18
- package/dist/worker/console/static-src/operator-chat/useChatStream.js +48 -16
- package/dist/worker/console/static-src/operator-chat/useChatThread.js +170 -7
- package/dist/worker/console/static-src/operator-chat/useComposer.js +13 -7
- package/dist/worker/console/static-src/operator-chat/user-turn-anchor-equality.js +21 -0
- package/dist/worker/console/static-src/shell/workspace-route.js +4 -0
- package/dist/worker/console/workspace-context.js +15 -1
- package/dist/worker/observe/node-transparency.js +81 -72
- package/dist/worker/observe/routes.js +20 -1
- package/dist/worker/observe/static/constants.js +22 -22
- package/dist/worker/observe/static/dag-context-reason-labels.js +19 -0
- package/dist/worker/observe/static/dag-history-labels.js +1 -0
- package/dist/worker/observe/static/dag-inspector-humanize.d.ts +16 -0
- package/dist/worker/observe/static/dag-inspector-humanize.js +342 -0
- package/dist/worker/observe/static/dag-node-purpose.js +10 -10
- package/dist/worker/observe/static/dom.js +20 -1
- package/dist/worker/observe/static/format-pool.d.ts +2 -0
- package/dist/worker/observe/static/format-pool.js +6 -0
- package/dist/worker/observe/static/format.js +7 -0
- package/dist/worker/observe/static/index.html +4 -4
- package/dist/worker/observe/static/inspect-workspace.js +34 -7
- package/dist/worker/observe/static/inspector-submission.js +32 -0
- package/dist/worker/observe/static/kpi.js +1 -0
- package/dist/worker/observe/static/prompt-restart-candidates.js +4 -2
- package/dist/worker/observe/static/relations.js +7 -5
- package/dist/worker/observe/static/router.js +13 -0
- package/dist/worker/observe/static/run-processing.js +2 -0
- package/dist/worker/observe/static/shell-chrome.js +36 -3
- package/dist/worker/observe/static/state.js +35 -2
- package/dist/worker/observe/static/styles.css +431 -39
- package/dist/worker/observe/static/task-failure-labels.d.ts +4 -0
- package/dist/worker/observe/static/task-failure-labels.js +67 -0
- package/dist/worker/observe/static/task-history.js +12 -0
- package/dist/worker/observe/static/views/batch.js +6 -13
- package/dist/worker/observe/static/views/dag-graph.js +51 -4
- package/dist/worker/observe/static/views/dag-inspector.js +1069 -426
- package/dist/worker/observe/static/views/dag-trajectory.js +3 -0
- package/dist/worker/observe/static/views/dag.d.ts +6 -0
- package/dist/worker/observe/static/views/dag.js +64 -22
- package/dist/worker/observe/static/views/dags.js +2 -0
- package/dist/worker/observe/static/views/dashboard.js +21 -12
- package/dist/worker/observe/static/views/failures.js +21 -11
- package/dist/worker/observe/static/views/feature.js +11 -29
- package/dist/worker/observe/static/views/pool.js +37 -28
- package/dist/worker/observe/static/views/run.js +48 -5
- package/dist/worker/observe/static/views/session-timeline.js +194 -243
- package/dist/worker/observe/static/views/task.js +81 -62
- package/dist/workflows/dag/backend-test-plan-protocol.js +104 -0
- package/dist/workflows/dag/budget-enforcement.js +53 -3
- package/dist/workflows/dag/dag-retry-schema.js +3 -0
- package/dist/workflows/dag/frontend-capacity.js +9 -0
- package/dist/workflows/dag/frontend-contract-facts.js +130 -0
- package/dist/workflows/dag/frontend-design-policy.js +103 -17
- package/dist/workflows/dag/frontend-durable-tools.js +193 -0
- package/dist/workflows/dag/frontend-execution-groups.js +24 -0
- package/dist/workflows/dag/frontend-implementation-contract.js +423 -41
- package/dist/workflows/dag/frontend-input-projection.js +76 -0
- package/dist/workflows/dag/frontend-plan-completeness.js +186 -0
- package/dist/workflows/dag/frontend-plan-recovery-policy.js +18 -0
- package/dist/workflows/dag/frontend-plan-render.js +21 -3
- package/dist/workflows/dag/frontend-prewrite-gate.js +1 -1
- package/dist/workflows/dag/frontend-recovery-controller.js +32 -8
- package/dist/workflows/dag/frontend-recovery-lineage.js +13 -0
- package/dist/workflows/dag/frontend-recovery-plan.js +4 -1
- package/dist/workflows/dag/frontend-recovery-run.js +146 -16
- package/dist/workflows/dag/frontend-review-scopes.js +139 -0
- package/dist/workflows/dag/frontend-risk.js +2 -0
- package/dist/workflows/dag/frontend-session-budget.js +249 -0
- package/dist/workflows/dag/frontend-shadow-dual-write.js +37 -3
- package/dist/workflows/dag/frontend-shape-facts.js +12 -2
- package/dist/workflows/dag/frontend-shape.js +46 -7
- package/dist/workflows/dag/frontend-test-execution-evidence.js +49 -0
- package/dist/workflows/dag/frontend-typed-event-store.js +14 -0
- package/dist/workflows/dag/frontend-verification-trace.js +38 -4
- package/dist/workflows/dag/frontend-writer-admission.js +2 -2
- package/dist/workflows/dag/init-hybrid.js +70 -35
- package/dist/workflows/dag/node-execution.js +225 -226
- package/dist/workflows/dag/prompt.js +4 -0
- package/dist/workflows/dag/recovery-lease.js +106 -16
- package/dist/workflows/dag/rerun-feedback.js +1 -0
- package/dist/workflows/dag/rerun-plan.js +96 -4
- package/dist/workflows/dag/rerun-run.js +28 -6
- package/dist/workflows/dag/rerun-task.js +221 -18
- package/dist/workflows/dag/retry-policy.js +27 -10
- package/dist/workflows/dag/runner-exit-diagnostics.js +125 -0
- package/dist/workflows/dag/runner.js +246 -19
- package/dist/workflows/dag/structured-output-repair.js +4 -1
- package/dist/workflows/dag/types.js +10 -3
- package/dist/workflows/dag/validate.js +10 -8
- package/dist/workflows/dag/workspace-checkpoint.js +66 -0
- package/docs/operations/README.md +2 -0
- package/docs/templates/agent-dag.schema.json +2 -2
- package/docs/templates/backend-test-dag.json +6 -4
- package/docs/templates/frontend-design-contract.md +4 -4
- package/docs/templates/frontend-implementation-contract.schema.json +68 -4
- package/docs/templates/frontend-implementation-dag.json +5 -5
- package/harness.json +1 -1
- package/package.json +8 -6
- package/skills/frontend-contract/SKILL.md +2 -1
- package/skills/frontend-contract/references/contract-protocol.md +19 -3
- package/skills/frontend-design-review/SKILL.md +12 -11
- package/skills/frontend-plan/SKILL.md +22 -2
- package/skills/frontend-plan/references/decision-contract.md +114 -5
- package/skills/frontend-plan/references/design-decisions.md +32 -0
- package/skills/frontend-review/SKILL.md +10 -11
- package/skills/frontend-scout/references/scout-evidence.md +4 -0
- package/dist/worker/console/static/assets/channel-DsZxrgqe.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-CuToPeGV.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-CuToPeGV.js +0 -1
- package/dist/worker/console/static/assets/index-D9Sc0f0y.js +0 -449
- package/dist/worker/console/static/assets/index-DDQc5a50.css +0 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-yPoT19ft.js +0 -1
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-VWdarchG.js +0 -8
|
@@ -16,6 +16,7 @@ import { randomUUID } from "node:crypto";
|
|
|
16
16
|
import { access } from "node:fs/promises";
|
|
17
17
|
import { parseAssistantContent } from "./assistant-content.js";
|
|
18
18
|
import { OPERATOR_CHAT_ALLOWED_TOOLS, OPERATOR_CHAT_DENIED_TOOLS, OPERATOR_CHAT_DENIED_OPERATOR_ACTIONS, } from "./tools.js";
|
|
19
|
+
import { InvalidChatSessionModeError, SESSION_MODE_ACTION_DENIED_CODE, SESSION_MODE_ACTION_DENIED_MESSAGE, SESSION_MODE_IMMUTABLE_CODE, UnknownChatSessionModeError, isWorkflowSessionMode, parseCreateSessionMode, readStoredSessionMode, shouldAcceptOperatorSnapshot, } from "./session-mode.js";
|
|
19
20
|
import { buildModelCallableToolSchemas } from "./tool-adapter.js";
|
|
20
21
|
import { cleanChatTitle, acceptedOperationIdFromResult, isBlankChatSession } from "./session-store.js";
|
|
21
22
|
import { hashChatTurnPayload, projectChatToolEventPayload, projectCompactSnapshot, } from "./chat-event-store.js";
|
|
@@ -44,11 +45,80 @@ import { buildGoalCompactionInstructions, buildGoalContinuationContext, } from "
|
|
|
44
45
|
import { classifyGoalRoundAdmission, } from "./goal-round-driver.js";
|
|
45
46
|
import { isTerminalOperationState } from "../../../infrastructure/console/operation-store.js";
|
|
46
47
|
import { SddDataAlignmentError, } from "./sdd-data-alignment.js";
|
|
48
|
+
import { TerminalSessionRegistry } from "./terminal-sessions.js";
|
|
49
|
+
import { handleTerminalRequest } from "./terminal-routes.js";
|
|
50
|
+
import { handleScmRequest } from "./scm-routes.js";
|
|
51
|
+
import { handleBrowserRequest } from "./browser-routes.js";
|
|
47
52
|
function projectBrowserChatSession(record) {
|
|
48
53
|
const { telemetrySessionId, ...projected } = record;
|
|
49
54
|
void telemetrySessionId;
|
|
50
55
|
return projected;
|
|
51
56
|
}
|
|
57
|
+
function reopenInitFromRecord(record) {
|
|
58
|
+
return {
|
|
59
|
+
sessionId: record.sessionId,
|
|
60
|
+
sessionFile: record.sessionFile,
|
|
61
|
+
...(record.modelProvider && record.modelId
|
|
62
|
+
? { model: { provider: record.modelProvider, modelId: record.modelId } }
|
|
63
|
+
: {}),
|
|
64
|
+
sessionMode: record.sessionMode,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
async function readChatSessionMode(deps, sessionId) {
|
|
68
|
+
let record;
|
|
69
|
+
try {
|
|
70
|
+
record = await deps.store.get(sessionId);
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
if (error instanceof UnknownChatSessionModeError) {
|
|
74
|
+
return {
|
|
75
|
+
ok: false,
|
|
76
|
+
status: 409,
|
|
77
|
+
code: error.code,
|
|
78
|
+
message: error.message,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
throw error;
|
|
82
|
+
}
|
|
83
|
+
if (!record) {
|
|
84
|
+
return {
|
|
85
|
+
ok: false,
|
|
86
|
+
status: 404,
|
|
87
|
+
code: "NOT_FOUND",
|
|
88
|
+
message: `chat session not found: ${sessionId}`,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
// Normalize: the store contract always fills sessionMode, but handler-level
|
|
92
|
+
// fakes / partial records may omit it — treat missing as workflow (the
|
|
93
|
+
// stock-record read rule), while a present-but-unknown value still fails
|
|
94
|
+
// closed in the store layer.
|
|
95
|
+
return {
|
|
96
|
+
ok: true,
|
|
97
|
+
record,
|
|
98
|
+
sessionMode: readStoredSessionMode(record.sessionMode),
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
async function requireWorkflowSession(res, deps, sessionId) {
|
|
102
|
+
const resolved = await readChatSessionMode(deps, sessionId);
|
|
103
|
+
if (!resolved.ok) {
|
|
104
|
+
sendJson(res, resolved.status, {
|
|
105
|
+
ok: false,
|
|
106
|
+
error: { code: resolved.code, message: resolved.message },
|
|
107
|
+
});
|
|
108
|
+
return undefined;
|
|
109
|
+
}
|
|
110
|
+
if (!isWorkflowSessionMode(resolved.sessionMode)) {
|
|
111
|
+
sendJson(res, 409, {
|
|
112
|
+
ok: false,
|
|
113
|
+
error: {
|
|
114
|
+
code: SESSION_MODE_ACTION_DENIED_CODE,
|
|
115
|
+
message: SESSION_MODE_ACTION_DENIED_MESSAGE,
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
return undefined;
|
|
119
|
+
}
|
|
120
|
+
return resolved.record;
|
|
121
|
+
}
|
|
52
122
|
/**
|
|
53
123
|
* Reattach the durable event-ring order to session-store rows. The session
|
|
54
124
|
* store remains the content authority; the ring only supplies chronology.
|
|
@@ -517,6 +587,14 @@ export async function handleChatCapabilities(_req, res, deps) {
|
|
|
517
587
|
deniedTools: OPERATOR_CHAT_DENIED_TOOLS,
|
|
518
588
|
deniedOperatorActions: OPERATOR_CHAT_DENIED_OPERATOR_ACTIONS,
|
|
519
589
|
tools: toolSchemas,
|
|
590
|
+
builtinSubagents: [
|
|
591
|
+
{
|
|
592
|
+
toolId: "Agent",
|
|
593
|
+
agent: "Explore",
|
|
594
|
+
kind: "subagent",
|
|
595
|
+
description: "Start the built-in read-only Explore subagent for codebase search, symbol lookup, and call-chain tracing.",
|
|
596
|
+
},
|
|
597
|
+
],
|
|
520
598
|
// ADR 0011: full Pi tools including bash are default-active.
|
|
521
599
|
hasBash: true,
|
|
522
600
|
});
|
|
@@ -557,6 +635,22 @@ workspaceId) {
|
|
|
557
635
|
});
|
|
558
636
|
return;
|
|
559
637
|
}
|
|
638
|
+
let sessionMode;
|
|
639
|
+
try {
|
|
640
|
+
sessionMode = parseCreateSessionMode(body.sessionMode);
|
|
641
|
+
}
|
|
642
|
+
catch (error) {
|
|
643
|
+
sendJson(res, 400, {
|
|
644
|
+
ok: false,
|
|
645
|
+
error: {
|
|
646
|
+
code: error instanceof InvalidChatSessionModeError
|
|
647
|
+
? error.code
|
|
648
|
+
: "INVALID_SESSION_MODE",
|
|
649
|
+
message: error instanceof Error ? error.message : String(error),
|
|
650
|
+
},
|
|
651
|
+
});
|
|
652
|
+
return;
|
|
653
|
+
}
|
|
560
654
|
const provider = typeof body.modelProvider === "string" ? body.modelProvider : undefined;
|
|
561
655
|
const modelId = typeof body.modelId === "string" ? body.modelId : undefined;
|
|
562
656
|
const snapshotInput = body.snapshot;
|
|
@@ -578,6 +672,16 @@ workspaceId) {
|
|
|
578
672
|
let createdSessionId;
|
|
579
673
|
let persisted = false;
|
|
580
674
|
try {
|
|
675
|
+
if (snapshotInput !== undefined && !shouldAcceptOperatorSnapshot(sessionMode)) {
|
|
676
|
+
sendJson(res, 409, {
|
|
677
|
+
ok: false,
|
|
678
|
+
error: {
|
|
679
|
+
code: SESSION_MODE_ACTION_DENIED_CODE,
|
|
680
|
+
message: "Operator snapshots cannot be imported into Pi sessions",
|
|
681
|
+
},
|
|
682
|
+
});
|
|
683
|
+
return;
|
|
684
|
+
}
|
|
581
685
|
const snapshot = snapshotInput === undefined ? undefined : projectCompactSnapshot(snapshotInput);
|
|
582
686
|
// A Console record promises that its Pi JSONL can be reopened after a
|
|
583
687
|
// Console restart. Do not make that promise until Pi has finished
|
|
@@ -585,6 +689,7 @@ workspaceId) {
|
|
|
585
689
|
// future JSONL path, leaving an unrecoverable orphan when init failed or
|
|
586
690
|
// the process restarted in that window.
|
|
587
691
|
const handle = await deps.runtime.createSession({
|
|
692
|
+
sessionMode,
|
|
588
693
|
...(provider && modelId ? { model: { provider, modelId } } : {}),
|
|
589
694
|
...(snapshot
|
|
590
695
|
? {
|
|
@@ -611,6 +716,7 @@ workspaceId) {
|
|
|
611
716
|
sessionFile: handle.sessionFile,
|
|
612
717
|
modelProvider: selection.model?.provider ?? handle.model?.provider,
|
|
613
718
|
modelId: selection.model?.modelId ?? handle.model?.modelId,
|
|
719
|
+
sessionMode,
|
|
614
720
|
// AC-R7-002: explicit parameter from the dispatcher — the runtime
|
|
615
721
|
// store.create wrapper is gone; body workspaceId (if any) only acts as
|
|
616
722
|
// a fallback for direct (non-dispatcher) handler tests.
|
|
@@ -681,6 +787,7 @@ export async function handleForkChatSession(req, res, deps, sourceSessionId) {
|
|
|
681
787
|
try {
|
|
682
788
|
const handle = await deps.runtime.forkSession({
|
|
683
789
|
sourceSessionFile: source.sessionFile ?? "",
|
|
790
|
+
sessionMode: source.sessionMode,
|
|
684
791
|
...(source.modelProvider && source.modelId
|
|
685
792
|
? { model: { provider: source.modelProvider, modelId: source.modelId } }
|
|
686
793
|
: {}),
|
|
@@ -747,10 +854,7 @@ export async function handleBranchChatSession(req, res, deps, sessionId) {
|
|
|
747
854
|
}
|
|
748
855
|
try {
|
|
749
856
|
if (!deps.runtime.hasSession(sessionId)) {
|
|
750
|
-
const reopened = await deps.runtime.reopenSession(
|
|
751
|
-
sessionId,
|
|
752
|
-
sessionFile: record.sessionFile,
|
|
753
|
-
});
|
|
857
|
+
const reopened = await deps.runtime.reopenSession(reopenInitFromRecord(record));
|
|
754
858
|
if (!reopened.ok) {
|
|
755
859
|
const mapped = await mapFailedReopen(deps, sessionId, reopened);
|
|
756
860
|
sendJson(res, mapped.status, {
|
|
@@ -851,6 +955,7 @@ export async function handleGetChatSession(_req, res, deps, sessionId) {
|
|
|
851
955
|
}
|
|
852
956
|
}
|
|
853
957
|
await deps.operationLinker.recoverSession(sessionId);
|
|
958
|
+
const messagePage = await deps.store.listMessages(sessionId, { limit: 50 });
|
|
854
959
|
const composerDraft = await new ComposerDraftStore(deps.appData).get(sessionId);
|
|
855
960
|
const snapshot = deps.events.snapshot(sessionId);
|
|
856
961
|
const telemetry = deriveChatSessionTelemetry(snapshot);
|
|
@@ -862,7 +967,7 @@ export async function handleGetChatSession(_req, res, deps, sessionId) {
|
|
|
862
967
|
eventEpoch: deps.events.epoch(sessionId),
|
|
863
968
|
session: {
|
|
864
969
|
...projectBrowserChatSession(record),
|
|
865
|
-
messages: projectStoredMessagesWithEventOrder(
|
|
970
|
+
messages: projectStoredMessagesWithEventOrder(messagePage.messages, snapshot),
|
|
866
971
|
composerDraft,
|
|
867
972
|
activeTurnId: activeTurn?.turnId,
|
|
868
973
|
turnPhase: activeTurn
|
|
@@ -874,6 +979,10 @@ export async function handleGetChatSession(_req, res, deps, sessionId) {
|
|
|
874
979
|
todos: projectCurrentTodos(snapshot) ?? [],
|
|
875
980
|
goal: deps.goalRegistry?.get(sessionId) ?? null,
|
|
876
981
|
},
|
|
982
|
+
history: {
|
|
983
|
+
hasMore: messagePage.hasMore,
|
|
984
|
+
...(messagePage.nextCursor ? { nextCursor: messagePage.nextCursor } : {}),
|
|
985
|
+
},
|
|
877
986
|
hasBash: true,
|
|
878
987
|
sessionStats: telemetry.stats,
|
|
879
988
|
usage: telemetry.usage,
|
|
@@ -1134,19 +1243,18 @@ export async function handleSteerDeferredTurn(req, res, deps, sessionId, clientR
|
|
|
1134
1243
|
}
|
|
1135
1244
|
}
|
|
1136
1245
|
async function persistAcceptedSteering(deps, sessionId, turnId, userMessage, clientRequestId) {
|
|
1246
|
+
emitUserMessageEvent(deps, sessionId, turnId, userMessage, clientRequestId, true);
|
|
1247
|
+
await emitDeferredTurnUpdate(deps, sessionId, turnId, undefined, 0);
|
|
1248
|
+
}
|
|
1249
|
+
function emitUserMessageEvent(deps, sessionId, turnId, userMessage, clientRequestId, steering = false) {
|
|
1137
1250
|
deps.events.append(sessionId, turnId, {
|
|
1138
1251
|
kind: "user_message",
|
|
1139
1252
|
data: {
|
|
1140
|
-
clientRequestId,
|
|
1141
|
-
steering: true,
|
|
1142
|
-
message: {
|
|
1143
|
-
id: userMessage.id,
|
|
1144
|
-
text: userMessage.text,
|
|
1145
|
-
at: userMessage.at,
|
|
1146
|
-
},
|
|
1253
|
+
...(clientRequestId ? { clientRequestId } : {}),
|
|
1254
|
+
...(steering ? { steering: true } : {}),
|
|
1255
|
+
message: { id: userMessage.id, text: userMessage.text, at: userMessage.at },
|
|
1147
1256
|
},
|
|
1148
1257
|
});
|
|
1149
|
-
await emitDeferredTurnUpdate(deps, sessionId, turnId, undefined, 0);
|
|
1150
1258
|
}
|
|
1151
1259
|
/** Lightweight busy-truth endpoint for the client reconcile loop (pi-web
|
|
1152
1260
|
* get_state equivalent): exposes the active turn + the latest turn's durable
|
|
@@ -1219,13 +1327,8 @@ export async function handleChatGoal(req, res, deps, sessionId) {
|
|
|
1219
1327
|
});
|
|
1220
1328
|
return;
|
|
1221
1329
|
}
|
|
1222
|
-
if (!(await deps
|
|
1223
|
-
sendJson(res, 404, {
|
|
1224
|
-
ok: false,
|
|
1225
|
-
error: { code: "NOT_FOUND", message: `chat session not found: ${sessionId}` },
|
|
1226
|
-
});
|
|
1330
|
+
if (!(await requireWorkflowSession(res, deps, sessionId)))
|
|
1227
1331
|
return;
|
|
1228
|
-
}
|
|
1229
1332
|
if (req.method === "GET") {
|
|
1230
1333
|
sendJson(res, 200, { ok: true, goal: registry.get(sessionId) });
|
|
1231
1334
|
return;
|
|
@@ -1439,6 +1542,7 @@ export async function listChatSessionSummaries(deps, ownerWorkspaceId) {
|
|
|
1439
1542
|
...(session.thinkingLevel !== undefined
|
|
1440
1543
|
? { thinkingLevel: session.thinkingLevel }
|
|
1441
1544
|
: {}),
|
|
1545
|
+
sessionMode: session.sessionMode,
|
|
1442
1546
|
activeTurnId: active?.turnId,
|
|
1443
1547
|
turnPhase: active?.abortRequestedAt
|
|
1444
1548
|
? "stopping"
|
|
@@ -1462,6 +1566,16 @@ export async function handlePatchChatSession(req, res, deps, sessionId) {
|
|
|
1462
1566
|
}
|
|
1463
1567
|
try {
|
|
1464
1568
|
const body = await readJsonBody(req);
|
|
1569
|
+
if ("sessionMode" in body) {
|
|
1570
|
+
sendJson(res, 409, {
|
|
1571
|
+
ok: false,
|
|
1572
|
+
error: {
|
|
1573
|
+
code: SESSION_MODE_IMMUTABLE_CODE,
|
|
1574
|
+
message: "sessionMode cannot be changed after create",
|
|
1575
|
+
},
|
|
1576
|
+
});
|
|
1577
|
+
return;
|
|
1578
|
+
}
|
|
1465
1579
|
let record;
|
|
1466
1580
|
if (typeof body.title === "string")
|
|
1467
1581
|
record = await deps.store.rename(sessionId, body.title);
|
|
@@ -1520,13 +1634,7 @@ export async function handleReopenChatSession(req, res, deps, sessionId) {
|
|
|
1520
1634
|
});
|
|
1521
1635
|
return;
|
|
1522
1636
|
}
|
|
1523
|
-
const result = await deps.runtime.reopenSession(
|
|
1524
|
-
sessionId,
|
|
1525
|
-
sessionFile: record.sessionFile,
|
|
1526
|
-
...(record.modelProvider && record.modelId
|
|
1527
|
-
? { model: { provider: record.modelProvider, modelId: record.modelId } }
|
|
1528
|
-
: {}),
|
|
1529
|
-
});
|
|
1637
|
+
const result = await deps.runtime.reopenSession(reopenInitFromRecord(record));
|
|
1530
1638
|
if (!result.ok) {
|
|
1531
1639
|
const mapped = await mapFailedReopen(deps, sessionId, result);
|
|
1532
1640
|
sendJson(res, mapped.status, {
|
|
@@ -1606,13 +1714,7 @@ export async function handleChatPrompt(req, res, deps, sessionId) {
|
|
|
1606
1714
|
});
|
|
1607
1715
|
return;
|
|
1608
1716
|
}
|
|
1609
|
-
const reopen = await deps.runtime.reopenSession(
|
|
1610
|
-
sessionId,
|
|
1611
|
-
sessionFile: record.sessionFile,
|
|
1612
|
-
...(record.modelProvider && record.modelId
|
|
1613
|
-
? { model: { provider: record.modelProvider, modelId: record.modelId } }
|
|
1614
|
-
: {}),
|
|
1615
|
-
});
|
|
1717
|
+
const reopen = await deps.runtime.reopenSession(reopenInitFromRecord(record));
|
|
1616
1718
|
if (!reopen.ok) {
|
|
1617
1719
|
const mapped = await mapFailedReopen(deps, sessionId, reopen);
|
|
1618
1720
|
sendJson(res, mapped.status, {
|
|
@@ -1690,7 +1792,8 @@ export async function handleChatPrompt(req, res, deps, sessionId) {
|
|
|
1690
1792
|
text,
|
|
1691
1793
|
images,
|
|
1692
1794
|
signal: ac.signal,
|
|
1693
|
-
onUserMessagePersisted: (record) => {
|
|
1795
|
+
onUserMessagePersisted: (record, userMessage) => {
|
|
1796
|
+
emitUserMessageEvent(deps, sessionId, turnId, userMessage);
|
|
1694
1797
|
const users = record.messages.filter((message) => message.role === "user");
|
|
1695
1798
|
if (users.length !== 1)
|
|
1696
1799
|
return;
|
|
@@ -1875,13 +1978,7 @@ export async function handleCreateChatTurn(req, res, deps, sessionId, trustedPay
|
|
|
1875
1978
|
});
|
|
1876
1979
|
return;
|
|
1877
1980
|
}
|
|
1878
|
-
const reopen = await deps.runtime.reopenSession(
|
|
1879
|
-
sessionId,
|
|
1880
|
-
sessionFile: record.sessionFile,
|
|
1881
|
-
...(record.modelProvider && record.modelId
|
|
1882
|
-
? { model: { provider: record.modelProvider, modelId: record.modelId } }
|
|
1883
|
-
: {}),
|
|
1884
|
-
});
|
|
1981
|
+
const reopen = await deps.runtime.reopenSession(reopenInitFromRecord(record));
|
|
1885
1982
|
if (!reopen.ok) {
|
|
1886
1983
|
const mapped = await mapFailedReopen(deps, sessionId, reopen);
|
|
1887
1984
|
sendJson(res, mapped.status, {
|
|
@@ -2000,9 +2097,12 @@ export async function handleCreateChatTurn(req, res, deps, sessionId, trustedPay
|
|
|
2000
2097
|
sessionId,
|
|
2001
2098
|
turnId: turn.turnId,
|
|
2002
2099
|
text,
|
|
2100
|
+
clientRequestId,
|
|
2003
2101
|
images,
|
|
2004
2102
|
signal: controller.signal,
|
|
2005
2103
|
onUserMessagePersisted: async (record, userMessage) => {
|
|
2104
|
+
if (!trustedPayload)
|
|
2105
|
+
emitUserMessageEvent(deps, sessionId, turn.turnId, userMessage, clientRequestId);
|
|
2006
2106
|
await trustedPayload?.onUserMessagePersisted?.(turn.turnId, userMessage);
|
|
2007
2107
|
const users = record.messages.filter((message) => message.role === "user");
|
|
2008
2108
|
if (users.length !== 1)
|
|
@@ -2156,6 +2256,10 @@ export async function driveGoalRound(deps, sessionId) {
|
|
|
2156
2256
|
registry.disarm(sessionId);
|
|
2157
2257
|
return "idle";
|
|
2158
2258
|
}
|
|
2259
|
+
if (!isWorkflowSessionMode(readStoredSessionMode(record.sessionMode))) {
|
|
2260
|
+
registry.disarm(sessionId);
|
|
2261
|
+
return "idle";
|
|
2262
|
+
}
|
|
2159
2263
|
const runtimeFacts = deps.runtime.getSessionBusyFacts(sessionId);
|
|
2160
2264
|
const operationStore = deps.runtime.actionContext?.operations;
|
|
2161
2265
|
const linkedOperationIds = linkedOperationIdsForGoal(deps.events.snapshot(sessionId));
|
|
@@ -2804,6 +2908,7 @@ export async function handleChatCommands(res, deps, sessionId) {
|
|
|
2804
2908
|
const warning = typeof listed.warning === "string" && listed.warning.trim()
|
|
2805
2909
|
? listed.warning.trim().slice(0, 160)
|
|
2806
2910
|
: undefined;
|
|
2911
|
+
const resolvedMode = await readChatSessionMode(deps, sessionId);
|
|
2807
2912
|
res.statusCode = 200;
|
|
2808
2913
|
res.setHeader("content-type", "application/json; charset=utf-8");
|
|
2809
2914
|
res.end(JSON.stringify({
|
|
@@ -2811,18 +2916,25 @@ export async function handleChatCommands(res, deps, sessionId) {
|
|
|
2811
2916
|
commands,
|
|
2812
2917
|
capabilities: {
|
|
2813
2918
|
sddBingo: Boolean(await deps.sddDataAlignment?.isEligible()),
|
|
2919
|
+
...(resolvedMode.ok ? { sessionMode: resolvedMode.sessionMode } : {}),
|
|
2814
2920
|
},
|
|
2815
2921
|
...(warning ? { warning } : {}),
|
|
2816
2922
|
}));
|
|
2817
2923
|
}
|
|
2818
2924
|
catch (error) {
|
|
2819
2925
|
// Whole-list / readiness failures stay fail-soft with empty commands + warning.
|
|
2926
|
+
// Keep the two capability shapes symmetric: the fallback mode mirrors the
|
|
2927
|
+
// client-side prop fallback in useComposer.
|
|
2928
|
+
const fallbackMode = await readChatSessionMode(deps, sessionId).catch(() => undefined);
|
|
2820
2929
|
res.statusCode = 200;
|
|
2821
2930
|
res.setHeader("content-type", "application/json; charset=utf-8");
|
|
2822
2931
|
res.end(JSON.stringify({
|
|
2823
2932
|
ok: true,
|
|
2824
2933
|
commands: [],
|
|
2825
|
-
capabilities: {
|
|
2934
|
+
capabilities: {
|
|
2935
|
+
sddBingo: false,
|
|
2936
|
+
...(fallbackMode?.ok ? { sessionMode: fallbackMode.sessionMode } : {}),
|
|
2937
|
+
},
|
|
2826
2938
|
warning: error instanceof Error ? error.message : "commands unavailable",
|
|
2827
2939
|
}));
|
|
2828
2940
|
}
|
|
@@ -2845,8 +2957,8 @@ async function handleSddBingo(req, res, deps, sessionId) {
|
|
|
2845
2957
|
if (Object.keys(body).some((key) => key !== "skillName")) {
|
|
2846
2958
|
throw new SddDataAlignmentError("SDD_INVALID_SKILL_NAME", "请求体只允许 skillName 字段", 400);
|
|
2847
2959
|
}
|
|
2848
|
-
await deps.sddDataAlignment.report(sessionId, body.skillName);
|
|
2849
|
-
sendJson(res, 200, { ok: true });
|
|
2960
|
+
const result = await deps.sddDataAlignment.report(sessionId, body.skillName);
|
|
2961
|
+
sendJson(res, 200, { ok: true, skillName: result.skillName });
|
|
2850
2962
|
}
|
|
2851
2963
|
catch (error) {
|
|
2852
2964
|
if (error instanceof SddDataAlignmentError) {
|
|
@@ -3067,13 +3179,7 @@ export async function ensureActiveSession(deps, sessionId) {
|
|
|
3067
3179
|
message: `chat session not found: ${sessionId}`,
|
|
3068
3180
|
};
|
|
3069
3181
|
}
|
|
3070
|
-
const reopened = await deps.runtime.reopenSession(
|
|
3071
|
-
sessionId,
|
|
3072
|
-
sessionFile: record.sessionFile,
|
|
3073
|
-
...(record.modelProvider && record.modelId
|
|
3074
|
-
? { model: { provider: record.modelProvider, modelId: record.modelId } }
|
|
3075
|
-
: {}),
|
|
3076
|
-
});
|
|
3182
|
+
const reopened = await deps.runtime.reopenSession(reopenInitFromRecord(record));
|
|
3077
3183
|
if (!reopened.ok) {
|
|
3078
3184
|
return { ok: false, ...(await mapFailedReopen(deps, sessionId, reopened)) };
|
|
3079
3185
|
}
|
|
@@ -3402,7 +3508,7 @@ async function handleStartInterview(req, res, deps, sessionId) {
|
|
|
3402
3508
|
});
|
|
3403
3509
|
return;
|
|
3404
3510
|
}
|
|
3405
|
-
if (!(await
|
|
3511
|
+
if (!(await requireWorkflowSession(res, deps, sessionId)))
|
|
3406
3512
|
return;
|
|
3407
3513
|
try {
|
|
3408
3514
|
const body = await readJsonBody(req);
|
|
@@ -3444,7 +3550,7 @@ async function handleAnswerInterview(req, res, deps, sessionId, interviewSession
|
|
|
3444
3550
|
});
|
|
3445
3551
|
return;
|
|
3446
3552
|
}
|
|
3447
|
-
if (!(await
|
|
3553
|
+
if (!(await requireWorkflowSession(res, deps, sessionId)))
|
|
3448
3554
|
return;
|
|
3449
3555
|
try {
|
|
3450
3556
|
const body = await readJsonBody(req);
|
|
@@ -3480,7 +3586,7 @@ async function handleAnswerInterview(req, res, deps, sessionId, interviewSession
|
|
|
3480
3586
|
}
|
|
3481
3587
|
}
|
|
3482
3588
|
async function handleGetInterviewFact(res, deps, sessionId, interviewSessionId, fact) {
|
|
3483
|
-
if (!(await
|
|
3589
|
+
if (!(await requireWorkflowSession(res, deps, sessionId)))
|
|
3484
3590
|
return;
|
|
3485
3591
|
const state = await new ChatInterviewAdapter(deps.appData, deps.events).get(interviewSessionId);
|
|
3486
3592
|
if (!state || state.interview.operatorSessionId !== sessionId) {
|
|
@@ -3578,7 +3684,7 @@ async function handleContractApplyHumanGate(req, res, deps, sessionId, step) {
|
|
|
3578
3684
|
});
|
|
3579
3685
|
return;
|
|
3580
3686
|
}
|
|
3581
|
-
if (!(await
|
|
3687
|
+
if (!(await requireWorkflowSession(res, deps, sessionId)))
|
|
3582
3688
|
return;
|
|
3583
3689
|
const ctx = deps.runtime.actionContext;
|
|
3584
3690
|
if (!ctx) {
|
|
@@ -3760,7 +3866,7 @@ async function handleDagHumanGate(req, res, deps, sessionId, step) {
|
|
|
3760
3866
|
});
|
|
3761
3867
|
return;
|
|
3762
3868
|
}
|
|
3763
|
-
if (!(await
|
|
3869
|
+
if (!(await requireWorkflowSession(res, deps, sessionId)))
|
|
3764
3870
|
return;
|
|
3765
3871
|
const ctx = deps.runtime.actionContext;
|
|
3766
3872
|
if (!ctx) {
|
|
@@ -3869,7 +3975,7 @@ async function handleMutationHumanGate(req, res, deps, sessionId) {
|
|
|
3869
3975
|
});
|
|
3870
3976
|
return;
|
|
3871
3977
|
}
|
|
3872
|
-
if (!(await
|
|
3978
|
+
if (!(await requireWorkflowSession(res, deps, sessionId)))
|
|
3873
3979
|
return;
|
|
3874
3980
|
const ctx = deps.runtime.actionContext;
|
|
3875
3981
|
if (!ctx) {
|
|
@@ -3958,7 +4064,7 @@ async function handleConfirmTaskKind(req, res, deps, sessionId, interviewSession
|
|
|
3958
4064
|
});
|
|
3959
4065
|
return;
|
|
3960
4066
|
}
|
|
3961
|
-
if (!(await
|
|
4067
|
+
if (!(await requireWorkflowSession(res, deps, sessionId)))
|
|
3962
4068
|
return;
|
|
3963
4069
|
try {
|
|
3964
4070
|
const body = await readJsonBody(req);
|
|
@@ -4014,13 +4120,7 @@ export async function handleChatCompact(req, res, deps, sessionId) {
|
|
|
4014
4120
|
return;
|
|
4015
4121
|
}
|
|
4016
4122
|
if (!deps.runtime.hasSession(sessionId)) {
|
|
4017
|
-
const reopened = await deps.runtime.reopenSession(
|
|
4018
|
-
sessionId,
|
|
4019
|
-
sessionFile: record.sessionFile,
|
|
4020
|
-
...(record.modelProvider && record.modelId
|
|
4021
|
-
? { model: { provider: record.modelProvider, modelId: record.modelId } }
|
|
4022
|
-
: {}),
|
|
4023
|
-
});
|
|
4123
|
+
const reopened = await deps.runtime.reopenSession(reopenInitFromRecord(record));
|
|
4024
4124
|
if (!reopened.ok) {
|
|
4025
4125
|
const mapped = await mapFailedReopen(deps, sessionId, reopened);
|
|
4026
4126
|
sendJson(res, mapped.status, {
|
|
@@ -4044,7 +4144,9 @@ export async function handleChatCompact(req, res, deps, sessionId) {
|
|
|
4044
4144
|
const rawInstructions = typeof body.instructions === "string" ? body.instructions : undefined;
|
|
4045
4145
|
const currentTodos = projectCurrentTodos(deps.events.snapshot(sessionId));
|
|
4046
4146
|
const todoInstructions = buildTodoCompactionInstructions(rawInstructions, currentTodos);
|
|
4047
|
-
const customInstructions =
|
|
4147
|
+
const customInstructions = isWorkflowSessionMode(record.sessionMode)
|
|
4148
|
+
? buildGoalCompactionInstructions(todoInstructions, deps.goalRegistry?.get(sessionId) ?? null)
|
|
4149
|
+
: todoInstructions;
|
|
4048
4150
|
const turnId = deps.events.latestTurnId(sessionId) ?? `${sessionId}:compact`;
|
|
4049
4151
|
const compactionId = `${sessionId}:compaction:${randomUUID()}`;
|
|
4050
4152
|
deps.events.append(sessionId, turnId, {
|
|
@@ -4130,6 +4232,46 @@ export async function handleChatMessages(res, deps, sessionId, url) {
|
|
|
4130
4232
|
export async function handleChatRequest(req, res, deps, pathname, workspaceScope) {
|
|
4131
4233
|
if (!deps)
|
|
4132
4234
|
return false;
|
|
4235
|
+
try {
|
|
4236
|
+
return await dispatchChatRequest(req, res, deps, pathname, workspaceScope);
|
|
4237
|
+
}
|
|
4238
|
+
catch (error) {
|
|
4239
|
+
// Store-level fail-closed for corrupt sessionMode: bounded 409 instead of
|
|
4240
|
+
// a generic 500, for any handler that reads the record without its own
|
|
4241
|
+
// UnknownChatSessionModeError mapping (readChatSessionMode covers the rest).
|
|
4242
|
+
if (error instanceof UnknownChatSessionModeError) {
|
|
4243
|
+
sendJson(res, 409, {
|
|
4244
|
+
ok: false,
|
|
4245
|
+
error: { code: error.code, message: error.message },
|
|
4246
|
+
});
|
|
4247
|
+
return true;
|
|
4248
|
+
}
|
|
4249
|
+
throw error;
|
|
4250
|
+
}
|
|
4251
|
+
}
|
|
4252
|
+
async function dispatchChatRequest(req, res, deps, pathname, workspaceScope) {
|
|
4253
|
+
// Terminal management API (model + Console UI shared PTY registry).
|
|
4254
|
+
if (await handleTerminalRequest(req, res, {
|
|
4255
|
+
terminals: deps.terminals ?? new TerminalSessionRegistry(),
|
|
4256
|
+
gateMutation: (r) => gateMutation(r, deps),
|
|
4257
|
+
// Terminals open in the workspace repo root, not the Console process cwd.
|
|
4258
|
+
defaultCwd: deps.appData.repoRoot,
|
|
4259
|
+
}, pathname)) {
|
|
4260
|
+
return true;
|
|
4261
|
+
}
|
|
4262
|
+
// Source control API (model + Console UI shared workspace ScmService).
|
|
4263
|
+
if (deps.scm) {
|
|
4264
|
+
if (await handleScmRequest(req, res, {
|
|
4265
|
+
scm: deps.scm,
|
|
4266
|
+
gateMutation: (r) => gateMutation(r, deps),
|
|
4267
|
+
}, pathname)) {
|
|
4268
|
+
return true;
|
|
4269
|
+
}
|
|
4270
|
+
}
|
|
4271
|
+
// Browser probe API (read-only; explains iframe refusals to the panel).
|
|
4272
|
+
if (await handleBrowserRequest(req, res, {}, pathname)) {
|
|
4273
|
+
return true;
|
|
4274
|
+
}
|
|
4133
4275
|
if (!pathname.startsWith("/api/operator/v1/chat/") &&
|
|
4134
4276
|
!pathname.startsWith("/api/operator/v1/pi/"))
|
|
4135
4277
|
return false;
|