@tea-agent/loop-agent 0.44.0-next.1 → 0.44.0-next.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/CHANGELOG.md +379 -416
- package/dist/application/evaluation/budget.js +21 -0
- package/dist/application/evaluation/corpus-hash.js +10 -15
- package/dist/application/evaluation/corpus.js +2 -1
- package/dist/application/evaluation/frontend-browser-acceptance.js +77 -0
- package/dist/application/evaluation/frontend-corpus-browser-acceptance.js +175 -0
- package/dist/application/evaluation/frontend-gateway-evidence.js +226 -0
- package/dist/application/evaluation/frontend-pair-registration.js +143 -0
- package/dist/application/evaluation/frontend-paired-summary.js +150 -0
- package/dist/application/evaluation/frontend-run-observation.js +144 -0
- package/dist/application/evaluation/frontend-shared-evidence.js +105 -0
- package/dist/application/evaluation/types.js +45 -12
- package/dist/application/task-lifecycle/observe.js +26 -1
- package/dist/build-stamp.json +3 -3
- package/dist/cli/command-definitions.js +11 -0
- package/dist/cli/program.js +4 -0
- package/dist/commands/task-advance.js +3 -5
- package/dist/commands/task-source-prepare.js +13 -1
- package/dist/executors/dag-pi/guards.js +4 -0
- package/dist/executors/dag-pi/model-config.js +30 -0
- package/dist/executors/dag-pi/plan/fact-adoption.js +55 -0
- package/dist/{workflows/dag/frontend-plan-completeness.js → executors/dag-pi/plan/facts.js} +22 -28
- package/dist/executors/dag-pi/plan/finalize-tools.js +259 -0
- package/dist/executors/dag-pi/plan/ledger-contract.js +55 -0
- package/dist/executors/dag-pi/plan/record-tools.js +861 -0
- package/dist/executors/dag-pi/plan/schema.js +129 -0
- package/dist/executors/dag-pi/plan/session.js +1 -0
- package/dist/executors/dag-pi/plan/tool-helpers.js +16 -0
- package/dist/executors/dag-pi/tools/contract-tools.js +515 -0
- package/dist/executors/dag-pi/tools/design-terminal-tools.js +159 -0
- package/dist/executors/dag-pi/tools/plan-decision-tools.js +529 -0
- package/dist/executors/dag-pi/tools/review-terminal-tools.js +159 -0
- package/dist/executors/dag-pi/tools/scout-evidence-tools.js +270 -0
- package/dist/executors/dag-pi-executor.js +398 -3384
- package/dist/executors/pi-executor.js +6 -1
- package/dist/executors/pi-sdk-executor.js +112 -19
- package/dist/executors/shell-executor.js +88 -12
- package/dist/executors/shell-presets.js +1 -1
- package/dist/executors/shell-write-guard.js +26 -3
- package/dist/infrastructure/console/operation-store.js +48 -14
- package/dist/infrastructure/evaluation/corpus-store.js +37 -12
- package/dist/shared/file-identity.js +23 -0
- package/dist/shared/git-workspace-status.js +482 -0
- package/dist/shared/operator/capabilities.js +10 -5
- package/dist/shared/path-safety.js +2 -2
- package/dist/shared/wizard-local-telemetry.js +51 -0
- package/dist/task/config-types.js +22 -8
- package/dist/task/contract/project.js +13 -0
- package/dist/task/contract/schema.js +2 -7
- package/dist/task/frontend-preflight.js +1 -1
- package/dist/task/source-prepare/parse-intent.js +124 -5
- package/dist/task/source-prepare/prepare.js +6 -1
- package/dist/task/source-prepare/semantic-intake.js +18 -3
- package/dist/task/source-prepare/source-execution.js +65 -0
- package/dist/task/source-prepare/source-fidelity-pi.js +22 -9
- package/dist/task/source-prepare/source-provider-budget.js +290 -0
- package/dist/worker/console/chat/assistant-content.js +5 -34
- package/dist/worker/console/chat/chat-event-store.js +62 -10
- package/dist/worker/console/chat/context-insights.js +723 -0
- package/dist/worker/console/chat/conversation-nodes.js +383 -0
- package/dist/worker/console/chat/db-connections.js +854 -0
- package/dist/worker/console/chat/pi-runtime/custom-tools/operator-tools.js +1 -1
- package/dist/worker/console/chat/pi-runtime/custom-tools/sql-tools.js +655 -0
- package/dist/worker/console/chat/pi-runtime.js +445 -36
- package/dist/worker/console/chat/provider-error.js +0 -12
- package/dist/worker/console/chat/repo-browser.js +52 -4
- package/dist/worker/console/chat/routes.js +577 -72
- package/dist/worker/console/chat/sdd-data-alignment.js +8 -31
- package/dist/worker/console/chat/session-store.js +147 -19
- package/dist/worker/console/chat/shortcuts.js +7 -0
- package/dist/worker/console/chat/timeline-message-order.js +22 -0
- package/dist/worker/console/chat/tools.js +34 -0
- package/dist/worker/console/chat/turn-process.js +237 -66
- package/dist/worker/console/chat/user-turn-outline.js +19 -0
- package/dist/worker/console/console-update-runtime.js +2 -2
- package/dist/worker/console/dag-confirmation.js +3 -0
- package/dist/worker/console/dag-execution-receipt.js +3 -0
- package/dist/worker/console/operator-actions.js +32 -3
- package/dist/worker/console/operator-user-error.js +28 -1
- package/dist/worker/console/pi-readiness.js +4 -4
- package/dist/worker/console/prd-intake-bridge.js +5 -12
- package/dist/worker/console/recovery-cta.js +14 -14
- package/dist/worker/console/server.js +5 -1
- package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-8-j6y-sd.js → abnfDiagram-N423BO3Z-r1NAPU_5.js} +1 -1
- package/dist/worker/console/static/assets/{arc-eoQiMvuk.js → arc-dT5T4sVL.js} +1 -1
- package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-C4A3uMcI.js → architectureDiagram-T3A2C74G-CP_cOq46.js} +1 -1
- package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-D4zD2F-Q.js → blockDiagram-VBNYF7ZC-sToEZxEf.js} +1 -1
- package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-j1RkJziL.js → c4Diagram-5PPSVZJV-DSxwwi2m.js} +1 -1
- package/dist/worker/console/static/assets/channel-CyBY_yGk.js +1 -0
- package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-YBHmhik1.js → chunk-2GRJ4B5K-B9fh0IkF.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-COfWyo9P.js → chunk-2Q5K7J3B-CAUNl-A6.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5RXB4S5H-I99OUkHY.js → chunk-5RXB4S5H-BomeqbNX.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5VM5RSS4-XKxoJNJ4.js → chunk-5VM5RSS4-BNAuTOLE.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-DLT_cYx1.js → chunk-6Q2QTUOP-DfzjRD5y.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-GF5L2VYU-CxcKZ9mV.js → chunk-GF5L2VYU-C3uE-yc2.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-JWPE2WC7-V1EqXdjY.js → chunk-JWPE2WC7-C3sQMMYr.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-KBJHAD2P-DebTtdFp.js → chunk-KBJHAD2P-D_AtEYQL.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-RYQCIY6F-B-ivNRDf.js → chunk-RYQCIY6F-DW4TwhKv.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-XXDRQBXY-DC_Ds11b.js → chunk-XXDRQBXY-CTQDmJcp.js} +1 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-D5lN4E_E.js +1 -0
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-D5lN4E_E.js +1 -0
- package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-sWEqKwIb.js → cose-bilkent-JH36ORCC-iMqPuBsL.js} +1 -1
- package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-BXa_dcu4.js → cynefin-VYW2F7L2-DktIuDWs.js} +1 -1
- package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-C-Mle84F.js → cynefinDiagram-MW4NZA55-BgVnjyEs.js} +1 -1
- package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-CXPDBITe.js → dagre-VZM6K2ZE-CR25E4bu.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-7IWD3JNH-CC-WJQfa.js → diagram-7IWD3JNH-CPM2h5HY.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-CDAV5Vs4.js → diagram-B4RE2ZJO-DqF0x2g1.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-LBJQPF4R-CmFiAcNz.js → diagram-LBJQPF4R-G8BYp2eb.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-Q27KOJAE-DPBZHuyn.js → diagram-Q27KOJAE-BbC4kT_D.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-UB23O5K3-jUlm_Ds3.js → diagram-UB23O5K3-CKZwZ-G5.js} +1 -1
- package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-DWhQ3mfY.js → ebnfDiagram-BXEA7PRR-kJDmheia.js} +1 -1
- package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-Tr2gMqet.js → erDiagram-JOGREHBK-DFTVHyxB.js} +1 -1
- package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-DJjVQHPA.js → flowDiagram-UKHOOZJN-BqdN5_os.js} +1 -1
- package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-D74dQ4u0.js → ganttDiagram-PKOTCBZU-SYDjVakh.js} +1 -1
- package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-DwW0tZ0X.js → gitGraphDiagram-DS77QQ5N-Bf8bNpGA.js} +1 -1
- package/dist/worker/console/static/assets/index-B28Onmfy.css +1 -0
- package/dist/worker/console/static/assets/index-CTMZsDmh.js +486 -0
- package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-ILCbxJyb.js → infoDiagram-6WML65LV-DIeAmJ45.js} +1 -1
- package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-DeuWBQ89.js → ishikawaDiagram-WSZJBQD7-oikqUAlo.js} +1 -1
- package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-CF5ih8Fk.js → journeyDiagram-NVQOT4AX-mKEF_xYT.js} +1 -1
- package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-C7yOSuRO.js → kanban-definition-27J2QSJJ-BdWJHPnN.js} +1 -1
- package/dist/worker/console/static/assets/{linear-BDZ9riWi.js → linear-DGRlieMH.js} +1 -1
- package/dist/worker/console/static/assets/{mermaid.core-7pKqYtpZ.js → mermaid.core-4P9yPC9c.js} +5 -5
- package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-LeJDybSU.js → mindmap-definition-FAOFIHXS-5PTSkos6.js} +1 -1
- package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-BJvT3pMD.js → pegDiagram-VL7TDLO6-DONIFpG5.js} +1 -1
- package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-_rGqpMan.js → pieDiagram-7S7Q4E2Y-D_Z4S70M.js} +1 -1
- package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-DPcSv5aA.js → quadrantDiagram-CIZ2JOQS-CAsjh8iY.js} +1 -1
- package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-Drxx4hkJ.js → railroadDiagram-AXF67PYL-Cx4Dd6ac.js} +1 -1
- package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-BCTUdU4z.js → requirementDiagram-LRYGKXZP-cQb7mwyH.js} +1 -1
- package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-B6wzbZmB.js → sankeyDiagram-W5VNT64P-Cd-DhUdf.js} +1 -1
- package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-BGt8d3QQ.js → sequenceDiagram-SI44F4Z6-AlKYRgIk.js} +1 -1
- package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-7nlhJKo7.js → sizeCapture-X5ZJPWSS-CUy_ET4e.js} +1 -1
- package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-Cv2stqMA.js → stateDiagram-OKZ733FA-CTuVe6Sa.js} +1 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-BsWhs8O7.js +1 -0
- package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-qDAo4Yc1.js → swimlanes-SLNWSIFB-ChFLJb-v.js} +2 -2
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-CJcioYGH.js +8 -0
- package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-CKbDNKTr.js → timeline-definition-Z64GVDOM-DZZeiAPr.js} +1 -1
- package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-DI-9EHic.js → vennDiagram-T6HMQDX7-t4O91cZU.js} +1 -1
- package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-BrzzRDpX.js → wardleyDiagram-T6FBY63Y-CV5qGHZu.js} +1 -1
- package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-BclH5hGh.js → xychartDiagram-ELKLHX3M-DyXbytUI.js} +1 -1
- package/dist/worker/console/static/index.html +2 -2
- package/dist/worker/console/static-src/app/console-types.js +9 -1
- package/dist/worker/console/static-src/operator-chat/animation-frame-batcher.js +38 -0
- package/dist/worker/console/static-src/operator-chat/chat-link.js +20 -0
- package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +186 -5
- package/dist/worker/console/static-src/operator-chat/chat-stream-continuity.js +101 -0
- package/dist/worker/console/static-src/operator-chat/compaction-message.js +18 -3
- package/dist/worker/console/static-src/operator-chat/context-insights-store.js +64 -0
- package/dist/worker/console/static-src/operator-chat/details-rail-surfaces.js +98 -0
- package/dist/worker/console/static-src/operator-chat/file-palette-nav.js +81 -0
- package/dist/worker/console/static-src/operator-chat/pending-user-message.js +17 -3
- package/dist/worker/console/static-src/operator-chat/process-label.js +27 -5
- package/dist/worker/console/static-src/operator-chat/tools-catalog.js +16 -7
- package/dist/worker/console/static-src/operator-chat/transcript-mode.js +21 -0
- package/dist/worker/console/static-src/operator-chat/turn-group-equality.js +4 -1
- package/dist/worker/console/static-src/operator-chat/turn-process-disclosure.js +13 -5
- package/dist/worker/console/static-src/operator-chat/turn-state-projection.js +166 -0
- package/dist/worker/console/static-src/operator-chat/turn-stream-controller.js +56 -2
- package/dist/worker/console/static-src/operator-chat/useChatSessions.js +211 -40
- package/dist/worker/console/static-src/operator-chat/useChatStream.js +124 -27
- package/dist/worker/console/static-src/operator-chat/useChatThread.js +88 -20
- package/dist/worker/console/static-src/operator-chat/useComposer.js +80 -6
- package/dist/worker/console/static-src/operator-chat/useRepoBrowser.js +13 -3
- package/dist/worker/console/static-src/operator-chat/useRuntimeControls.js +36 -17
- package/dist/worker/console/static-src/operator-chat/useRuntimeSnapshot.js +18 -0
- package/dist/worker/console/static-src/operator-chat/useWorkspaceBrowserGate.js +4 -0
- package/dist/worker/console/static-src/shell/console-update-reload.js +1 -1
- package/dist/worker/console/workspace-context.js +2 -0
- package/dist/worker/console/workspace-initialization.js +3 -3
- package/dist/worker/observability/read-model.js +23 -2
- package/dist/worker/observe/node-context-insights.js +479 -0
- package/dist/worker/observe/static/console-theme.css +174 -0
- package/dist/worker/observe/static/console-theme.js +36 -0
- package/dist/worker/observe/static/operator-chrome.css +85 -0
- package/dist/worker/observe/static/operator-chrome.js +51 -0
- package/dist/worker/scheduler/scheduled-goal-dispatch.js +3 -2
- package/dist/worker/scheduler/scheduled-goal-evidence.js +66 -3
- package/dist/worker/scheduler/scheduled-goal-store.js +10 -0
- package/dist/workflows/dag/budget-enforcement.js +31 -2
- package/dist/workflows/dag/frontend-closeout.js +3 -1
- package/dist/workflows/dag/frontend-contract-facts.js +11 -8
- package/dist/workflows/dag/frontend-design-policy.js +6 -6
- package/dist/workflows/dag/frontend-durable-tools.js +90 -70
- package/dist/workflows/dag/frontend-implementation-contract.js +146 -57
- package/dist/workflows/dag/frontend-plan-canary.js +66 -16
- package/dist/workflows/dag/frontend-plan-decision-contract.js +13 -21
- package/dist/workflows/dag/frontend-plan-progress.js +92 -0
- package/dist/workflows/dag/frontend-recovery-plan.js +10 -5
- package/dist/workflows/dag/frontend-recovery-run.js +51 -46
- package/dist/workflows/dag/frontend-repair-assertions.js +36 -0
- package/dist/workflows/dag/frontend-review-context.js +29 -1
- package/dist/workflows/dag/frontend-review-scopes.js +92 -2
- package/dist/workflows/dag/frontend-risk.js +8 -3
- package/dist/workflows/dag/frontend-root-observation.js +261 -0
- package/dist/workflows/dag/frontend-session-budget.js +52 -39
- package/dist/workflows/dag/frontend-session-context.js +10 -0
- package/dist/workflows/dag/frontend-test-execution-evidence.js +206 -48
- package/dist/workflows/dag/frontend-typed-event-store.js +11 -1
- package/dist/workflows/dag/frontend-verification-trace.js +6 -0
- package/dist/workflows/dag/frontend-writer-admission.js +3 -1
- package/dist/workflows/dag/init-hybrid.js +108 -37
- package/dist/workflows/dag/node-execution.js +11 -11
- package/dist/workflows/dag/output-protocol.js +1 -0
- package/dist/workflows/dag/rerun-feedback.js +35 -4
- package/dist/workflows/dag/rerun-task.js +62 -66
- package/dist/workflows/dag/runner.js +58 -12
- package/dist/workflows/dag/types.js +15 -8
- package/dist/workflows/loop/benchmark.js +11 -8
- package/docs/README.md +1 -1
- package/docs/architecture/runtime-boundaries.md +1 -1
- package/docs/governance/harness-methodology-verification.md +11 -0
- package/docs/templates/backend-test-dag.json +5 -4
- package/docs/templates/frontend-implementation-contract.schema.json +31 -11
- package/package.json +6 -4
- package/skills/frontend-design-review/SKILL.md +8 -11
- package/skills/frontend-design-review/references/review-checklist.md +3 -4
- package/skills/frontend-review/SKILL.md +5 -1
- package/skills/loop-agent/references/command-reference.md +8 -0
- package/skills/loop-agent/references/hybrid-dag.md +1 -1
- package/dist/worker/console/static/assets/channel-ChE7y-cx.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-C01TCf2X.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-C01TCf2X.js +0 -1
- package/dist/worker/console/static/assets/index-BWkIfcrK.css +0 -1
- package/dist/worker/console/static/assets/index-Cdkvw_H6.js +0 -469
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-DC7V5vcq.js +0 -1
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-Bwy4QUTO.js +0 -8
|
@@ -1,15 +1,113 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Turn grouping for Operator Chat inline process UX (pi-web ProcessDetails mind).
|
|
3
3
|
*/
|
|
4
|
-
import { compareChatOrder } from "./turn-order.js";
|
|
5
4
|
import { getDisplayableAssistantBlocks, joinAssistantText, parseAssistantContent, splitFinalAssistantBlocks, } from "./assistant-content.js";
|
|
6
5
|
import { dagProgressActivityForTool, semanticActivityForTool, } from "./semantic-activity.js";
|
|
7
|
-
|
|
6
|
+
import { compareChatOrder } from "./turn-order.js";
|
|
7
|
+
import { ensureLinkedSubmissionOrder } from "./timeline-message-order.js";
|
|
8
|
+
function conversationNodeOrder(node) {
|
|
9
|
+
return { eventSeq: node.anchorSeq, createdAt: node.at };
|
|
10
|
+
}
|
|
11
|
+
function processItemOrder(item, group) {
|
|
12
|
+
const createdAt = item.createdAt ??
|
|
13
|
+
(item.kind === "tool" ? item.tool.createdAt : undefined) ??
|
|
14
|
+
group.assistants[0]?.createdAt ??
|
|
15
|
+
0;
|
|
16
|
+
const eventSeq = item.eventSeq ?? (item.kind === "tool" ? item.tool.eventSeq : undefined);
|
|
17
|
+
return eventSeq === undefined ? { createdAt } : { eventSeq, createdAt };
|
|
18
|
+
}
|
|
19
|
+
function compareFlowEntries(a, b) {
|
|
20
|
+
return compareChatOrder(a.order, b.order);
|
|
21
|
+
}
|
|
22
|
+
/** Base identity for a rendered process row. Content is deliberately excluded
|
|
23
|
+
* so streaming text updates keep the same React instance. */
|
|
24
|
+
function processItemKey(item, order) {
|
|
25
|
+
if (item.kind === "tool")
|
|
26
|
+
return `tool:${item.tool.id}`;
|
|
27
|
+
if (item.kind === "activity")
|
|
28
|
+
return `activity:${item.activity.id}`;
|
|
29
|
+
if (item.kind === "dag-progress")
|
|
30
|
+
return `dag-progress:${item.progress.id}`;
|
|
31
|
+
const anchor = order.eventSeq ?? order.createdAt;
|
|
32
|
+
return `${item.kind}:${anchor}`;
|
|
33
|
+
}
|
|
34
|
+
export function turnProcessItemKey(item, occurrence = 0) {
|
|
35
|
+
const order = {
|
|
36
|
+
...(item.eventSeq === undefined ? {} : { eventSeq: item.eventSeq }),
|
|
37
|
+
createdAt: item.createdAt ?? (item.kind === "tool" ? item.tool.createdAt : 0),
|
|
38
|
+
};
|
|
39
|
+
const base = processItemKey(item, order);
|
|
40
|
+
return occurrence === 0 ? base : `${base}:${occurrence}`;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Project one turn into the same ordered buckets used by the main timeline and
|
|
44
|
+
* the trajectory view. Only existing request/running-step nodes are prelude;
|
|
45
|
+
* retry and other lifecycle nodes stay in the collapsible process window.
|
|
46
|
+
*/
|
|
47
|
+
export function projectTurnFlow(group) {
|
|
48
|
+
const conversationItems = group.conversationItems ?? [];
|
|
49
|
+
const prelude = conversationItems
|
|
50
|
+
.filter((item) => item.kind === "request" ||
|
|
51
|
+
(item.kind === "step" && item.node.status === "running"))
|
|
52
|
+
.sort((a, b) => compareChatOrder(conversationNodeOrder(a.node), conversationNodeOrder(b.node)));
|
|
53
|
+
const postAnswer = conversationItems
|
|
54
|
+
.filter((item) => item.kind === "max-tokens" || item.kind === "turn-error")
|
|
55
|
+
.sort((a, b) => compareChatOrder(conversationNodeOrder(a.node), conversationNodeOrder(b.node)));
|
|
56
|
+
const preludeKeys = new Set(prelude.map((item) => item.node.key));
|
|
57
|
+
const postAnswerKeys = new Set(postAnswer.map((item) => item.node.key));
|
|
58
|
+
const process = [];
|
|
59
|
+
for (const item of group.processItems) {
|
|
60
|
+
process.push({
|
|
61
|
+
source: "process",
|
|
62
|
+
key: "",
|
|
63
|
+
item,
|
|
64
|
+
order: processItemOrder(item, group),
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
for (const item of conversationItems) {
|
|
68
|
+
if (preludeKeys.has(item.node.key) || postAnswerKeys.has(item.node.key))
|
|
69
|
+
continue;
|
|
70
|
+
process.push({
|
|
71
|
+
source: "conversation",
|
|
72
|
+
key: `conversation:${item.node.key}`,
|
|
73
|
+
item,
|
|
74
|
+
order: conversationNodeOrder(item.node),
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
process.sort(compareFlowEntries);
|
|
78
|
+
const occurrences = new Map();
|
|
79
|
+
for (const entry of process) {
|
|
80
|
+
const base = entry.source === "conversation"
|
|
81
|
+
? entry.key
|
|
82
|
+
: processItemKey(entry.item, entry.order);
|
|
83
|
+
const occurrence = occurrences.get(base) ?? 0;
|
|
84
|
+
occurrences.set(base, occurrence + 1);
|
|
85
|
+
entry.key = occurrence === 0 ? base : `${base}:${occurrence}`;
|
|
86
|
+
}
|
|
87
|
+
return { prelude, process, postAnswer };
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Main-chat projection: request provenance and model-step bookkeeping remain
|
|
91
|
+
* available to Trajectory, but do not occupy the user-facing message stream.
|
|
92
|
+
*/
|
|
93
|
+
export function projectTimelineTurnFlow(group) {
|
|
94
|
+
const flow = projectTurnFlow(group);
|
|
95
|
+
return {
|
|
96
|
+
prelude: [],
|
|
97
|
+
process: flow.process.filter((entry) => entry.source === "process" ||
|
|
98
|
+
(entry.item.kind !== "request" && entry.item.kind !== "step")),
|
|
99
|
+
postAnswer: flow.postAnswer,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
function emptyGroup(key, turnId) {
|
|
8
103
|
return {
|
|
9
104
|
key,
|
|
105
|
+
...(turnId ? { turnId } : {}),
|
|
10
106
|
assistants: [],
|
|
11
107
|
tools: [],
|
|
12
108
|
processItems: [],
|
|
109
|
+
conversationItems: [],
|
|
110
|
+
turnClosed: false,
|
|
13
111
|
live: false,
|
|
14
112
|
};
|
|
15
113
|
}
|
|
@@ -45,6 +143,7 @@ export function hydrateSessionThread(raw) {
|
|
|
45
143
|
...(item.clientRequestId ? { clientRequestId: item.clientRequestId } : {}),
|
|
46
144
|
...(item.eventSeq === undefined ? {} : { eventSeq: item.eventSeq }),
|
|
47
145
|
...(item.turnId ? { turnId: item.turnId } : {}),
|
|
146
|
+
...(item.attachments?.length ? { attachments: item.attachments } : {}),
|
|
48
147
|
});
|
|
49
148
|
continue;
|
|
50
149
|
}
|
|
@@ -91,6 +190,10 @@ export function hydrateSessionThread(raw) {
|
|
|
91
190
|
? finishedAtMs
|
|
92
191
|
: createdAt,
|
|
93
192
|
turnId: item.turnId ?? turnId,
|
|
193
|
+
...(item.step === undefined ? {} : { step: item.step }),
|
|
194
|
+
...(item.parentToolCallId
|
|
195
|
+
? { parentToolCallId: item.parentToolCallId }
|
|
196
|
+
: {}),
|
|
94
197
|
...(item.eventSeq === undefined ? {} : { eventSeq: item.eventSeq }),
|
|
95
198
|
...(item.finishedSeq === undefined
|
|
96
199
|
? {}
|
|
@@ -131,30 +234,52 @@ function flushToolBuffer(processItems, buffer) {
|
|
|
131
234
|
return;
|
|
132
235
|
const sorted = sortToolsStable(buffer);
|
|
133
236
|
for (const tool of sorted) {
|
|
237
|
+
const order = {
|
|
238
|
+
...(tool.eventSeq === undefined ? {} : { eventSeq: tool.eventSeq }),
|
|
239
|
+
createdAt: tool.createdAt,
|
|
240
|
+
};
|
|
134
241
|
const dagProgress = dagProgressActivityForTool(tool);
|
|
135
242
|
if (dagProgress) {
|
|
136
|
-
processItems.push({
|
|
243
|
+
processItems.push({
|
|
244
|
+
kind: "dag-progress",
|
|
245
|
+
progress: dagProgress,
|
|
246
|
+
toolCallCount: 1,
|
|
247
|
+
...order,
|
|
248
|
+
});
|
|
137
249
|
continue;
|
|
138
250
|
}
|
|
139
251
|
const activity = semanticActivityForTool(tool);
|
|
140
252
|
if (activity) {
|
|
141
|
-
processItems.push({ kind: "activity", activity });
|
|
253
|
+
processItems.push({ kind: "activity", activity, toolCallCount: 1, ...order });
|
|
142
254
|
}
|
|
143
255
|
else {
|
|
144
|
-
processItems.push({ kind: "tool", tool });
|
|
256
|
+
processItems.push({ kind: "tool", tool, ...order });
|
|
145
257
|
}
|
|
146
258
|
}
|
|
147
259
|
}
|
|
148
260
|
function collapseDagProgressItems(items) {
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
261
|
+
const collapsed = [];
|
|
262
|
+
const progressIndexByRef = new Map();
|
|
263
|
+
for (const item of items) {
|
|
264
|
+
if (item.kind !== "dag-progress") {
|
|
265
|
+
collapsed.push(item);
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
const existingIndex = progressIndexByRef.get(item.progress.activityRef);
|
|
269
|
+
if (existingIndex === undefined) {
|
|
270
|
+
progressIndexByRef.set(item.progress.activityRef, collapsed.length);
|
|
271
|
+
collapsed.push(item);
|
|
272
|
+
continue;
|
|
273
|
+
}
|
|
274
|
+
const existing = collapsed[existingIndex];
|
|
275
|
+
if (existing?.kind === "dag-progress") {
|
|
276
|
+
collapsed[existingIndex] = {
|
|
277
|
+
...existing,
|
|
278
|
+
toolCallCount: (existing.toolCallCount ?? 1) + (item.toolCallCount ?? 1),
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
return collapsed;
|
|
158
283
|
}
|
|
159
284
|
function fillProcessDetails(group) {
|
|
160
285
|
const usedToolIds = new Set();
|
|
@@ -184,12 +309,24 @@ function fillProcessDetails(group) {
|
|
|
184
309
|
};
|
|
185
310
|
for (const block of blocks) {
|
|
186
311
|
if (block.type === "thinking") {
|
|
187
|
-
items.push({
|
|
312
|
+
items.push({
|
|
313
|
+
kind: "thinking",
|
|
314
|
+
thinking: block.thinking,
|
|
315
|
+
...(anchorSeq === undefined ? {} : { eventSeq: anchorSeq }),
|
|
316
|
+
createdAt: anchorAt,
|
|
317
|
+
});
|
|
188
318
|
continue;
|
|
189
319
|
}
|
|
190
320
|
if (block.type === "text") {
|
|
191
|
-
if (block.text.trim())
|
|
192
|
-
items.push({
|
|
321
|
+
if (block.text.trim()) {
|
|
322
|
+
items.push({
|
|
323
|
+
kind: "text",
|
|
324
|
+
text: block.text,
|
|
325
|
+
assistantMessageId: assistant.id,
|
|
326
|
+
...(anchorSeq === undefined ? {} : { eventSeq: anchorSeq }),
|
|
327
|
+
createdAt: anchorAt,
|
|
328
|
+
});
|
|
329
|
+
}
|
|
193
330
|
continue;
|
|
194
331
|
}
|
|
195
332
|
const tool = group.tools.find((entry) => entry.id === block.toolCallId);
|
|
@@ -212,7 +349,12 @@ function fillProcessDetails(group) {
|
|
|
212
349
|
anchorAt = tool.createdAt;
|
|
213
350
|
}
|
|
214
351
|
if (includeProviderError && assistant.providerError) {
|
|
215
|
-
items.push({
|
|
352
|
+
items.push({
|
|
353
|
+
kind: "provider-error",
|
|
354
|
+
error: assistant.providerError,
|
|
355
|
+
...(anchorSeq === undefined ? {} : { eventSeq: anchorSeq }),
|
|
356
|
+
createdAt: anchorAt,
|
|
357
|
+
});
|
|
216
358
|
}
|
|
217
359
|
flushItems();
|
|
218
360
|
// Preserve the old-data fallback after this stage. Sequenced unmatched
|
|
@@ -245,8 +387,16 @@ function fillProcessDetails(group) {
|
|
|
245
387
|
}
|
|
246
388
|
addAssistantNode(assistant, getDisplayableAssistantBlocks(assistant.content ?? []));
|
|
247
389
|
}
|
|
248
|
-
const blocks = finalAssistant?.content ??
|
|
249
|
-
|
|
390
|
+
const blocks = finalAssistant?.content ??
|
|
391
|
+
(finalAssistant?.text.trim()
|
|
392
|
+
? [{ type: "text", text: finalAssistant.text }]
|
|
393
|
+
: []);
|
|
394
|
+
// Without durable step-completion metadata, only a normally settled Turn can
|
|
395
|
+
// prove that its latest assistant generation is a final answer. Keep partial
|
|
396
|
+
// text in process for running/aborted/failed and legacy unknown states.
|
|
397
|
+
const split = splitFinalAssistantBlocks(blocks, {
|
|
398
|
+
isStreaming: group.live || group.turnState !== "settled",
|
|
399
|
+
});
|
|
250
400
|
if (finalAssistant) {
|
|
251
401
|
addAssistantNode(finalAssistant, split.processBlocks);
|
|
252
402
|
}
|
|
@@ -265,14 +415,13 @@ function fillProcessDetails(group) {
|
|
|
265
415
|
items,
|
|
266
416
|
});
|
|
267
417
|
}
|
|
268
|
-
|
|
269
|
-
// createdAt falls back, insertion order breaks remaining ties. No
|
|
270
|
-
// "fullySequenced" switch — a partially-sequenced group must not
|
|
271
|
-
// silently re-sort its peers by wall clock when most nodes carry seq.
|
|
418
|
+
const fullySequenced = nodes.every((node) => node.eventSeq !== undefined);
|
|
272
419
|
nodes.sort((a, b) => {
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
420
|
+
if (fullySequenced && a.eventSeq !== b.eventSeq) {
|
|
421
|
+
return a.eventSeq - b.eventSeq;
|
|
422
|
+
}
|
|
423
|
+
if (a.createdAt !== b.createdAt)
|
|
424
|
+
return a.createdAt - b.createdAt;
|
|
276
425
|
return a.insertionOrder - b.insertionOrder;
|
|
277
426
|
});
|
|
278
427
|
const processItems = nodes.flatMap((node) => node.items);
|
|
@@ -284,10 +433,6 @@ function fillProcessDetails(group) {
|
|
|
284
433
|
group.processItems = collapseDagProgressItems(processItems);
|
|
285
434
|
if (!finalAssistant)
|
|
286
435
|
return;
|
|
287
|
-
if (blocks.length === 0) {
|
|
288
|
-
group.answer = finalAssistant;
|
|
289
|
-
return;
|
|
290
|
-
}
|
|
291
436
|
if (split.answerBlocks.length === 0)
|
|
292
437
|
return;
|
|
293
438
|
const answerText = joinAssistantText(split.answerBlocks);
|
|
@@ -297,43 +442,49 @@ function fillProcessDetails(group) {
|
|
|
297
442
|
content: split.answerBlocks,
|
|
298
443
|
};
|
|
299
444
|
}
|
|
300
|
-
/**
|
|
301
|
-
* Build user → process → answer groups for the message timeline.
|
|
302
|
-
*/
|
|
303
445
|
export function buildTurnProcessGroups(input) {
|
|
304
|
-
const visible = input.messages
|
|
446
|
+
const visible = ensureLinkedSubmissionOrder(input.messages
|
|
305
447
|
.filter((m) => m.role === "user" || m.role === "assistant")
|
|
306
|
-
.sort(
|
|
448
|
+
.sort((a, b) => {
|
|
449
|
+
if (a.eventSeq !== undefined &&
|
|
450
|
+
b.eventSeq !== undefined &&
|
|
451
|
+
a.eventSeq !== b.eventSeq) {
|
|
452
|
+
return a.eventSeq - b.eventSeq;
|
|
453
|
+
}
|
|
454
|
+
if (a.createdAt !== b.createdAt)
|
|
455
|
+
return a.createdAt - b.createdAt;
|
|
456
|
+
if (a.eventSeq !== undefined && b.eventSeq === undefined)
|
|
457
|
+
return 1;
|
|
458
|
+
if (a.eventSeq === undefined && b.eventSeq !== undefined)
|
|
459
|
+
return -1;
|
|
460
|
+
return 0;
|
|
461
|
+
}));
|
|
307
462
|
const groups = [];
|
|
308
463
|
let current = null;
|
|
309
|
-
const startGroup = (key) => {
|
|
310
|
-
const group = emptyGroup(key);
|
|
464
|
+
const startGroup = (key, turnId) => {
|
|
465
|
+
const group = emptyGroup(key, turnId);
|
|
311
466
|
groups.push(group);
|
|
312
467
|
return group;
|
|
313
468
|
};
|
|
314
469
|
for (const message of visible) {
|
|
315
470
|
if (message.role === "user") {
|
|
316
|
-
current = startGroup(`user-${message.id}
|
|
471
|
+
current = startGroup(`user-${message.id}`, message.turnId);
|
|
317
472
|
current.user = message;
|
|
318
|
-
if (message.turnId)
|
|
319
|
-
current.turnId = message.turnId;
|
|
320
473
|
continue;
|
|
321
474
|
}
|
|
322
475
|
if (message.kind === "compaction") {
|
|
323
476
|
// Compaction is a standalone timeline event. Starting a fresh group
|
|
324
477
|
// prevents it from replacing the previous turn's assistant answer.
|
|
325
|
-
current = startGroup(`compaction-${message.id}
|
|
478
|
+
current = startGroup(`compaction-${message.id}`, message.turnId);
|
|
326
479
|
current.assistants.push(message);
|
|
327
|
-
if (message.turnId)
|
|
328
|
-
current.turnId = message.turnId;
|
|
329
480
|
current = null;
|
|
330
481
|
continue;
|
|
331
482
|
}
|
|
332
483
|
if (!current)
|
|
333
|
-
current = startGroup(`assistant-${message.id}
|
|
334
|
-
current.
|
|
335
|
-
if (current.turnId === undefined && message.turnId)
|
|
484
|
+
current = startGroup(`assistant-${message.id}`, message.turnId);
|
|
485
|
+
if (!current.turnId && message.turnId)
|
|
336
486
|
current.turnId = message.turnId;
|
|
487
|
+
current.assistants.push(message);
|
|
337
488
|
}
|
|
338
489
|
const assigned = new Set();
|
|
339
490
|
const assistantToGroup = new Map();
|
|
@@ -355,10 +506,10 @@ export function buildTurnProcessGroups(input) {
|
|
|
355
506
|
if (assigned.has(tool.id))
|
|
356
507
|
continue;
|
|
357
508
|
if (tool.turnId) {
|
|
358
|
-
const byTurn = groups.find((group) => group.turnId === tool.turnId ||
|
|
359
|
-
group.user?.turnId === tool.turnId ||
|
|
509
|
+
const byTurn = groups.find((group) => group.user?.turnId === tool.turnId ||
|
|
360
510
|
group.assistants.some((assistant) => assistant.turnId === tool.turnId) ||
|
|
361
511
|
group.tools.some((t) => t.turnId === tool.turnId) ||
|
|
512
|
+
group.key === `turn-${tool.turnId}` ||
|
|
362
513
|
(group.user && `restored-${group.user.id}` === tool.turnId));
|
|
363
514
|
if (byTurn) {
|
|
364
515
|
byTurn.tools.push(tool);
|
|
@@ -374,25 +525,15 @@ export function buildTurnProcessGroups(input) {
|
|
|
374
525
|
}
|
|
375
526
|
}
|
|
376
527
|
}
|
|
377
|
-
// Time-window fallback for legacy rows with neither assistantMessageId nor
|
|
378
|
-
// turnId. The window ends at the NEXT group's first anchor (user OR first
|
|
379
|
-
// assistant) — using POSITIVE_INFINITY would swallow every later group's
|
|
380
|
-
// tools when the very next group has no user message (e.g. compaction or a
|
|
381
|
-
// stand-alone assistant row), dumping one turn's bash cards into another.
|
|
382
528
|
for (const tool of input.toolCalls) {
|
|
383
529
|
if (assigned.has(tool.id))
|
|
384
530
|
continue;
|
|
385
531
|
const windowGroup = groups.find((group, index) => {
|
|
386
532
|
const start = group.user?.createdAt ?? group.assistants[0]?.createdAt ?? 0;
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
if (nextAnchor !== undefined) {
|
|
392
|
-
end = nextAnchor;
|
|
393
|
-
break;
|
|
394
|
-
}
|
|
395
|
-
}
|
|
533
|
+
const next = groups[index + 1];
|
|
534
|
+
const end = next?.user?.createdAt ??
|
|
535
|
+
next?.assistants[0]?.createdAt ??
|
|
536
|
+
Number.POSITIVE_INFINITY;
|
|
396
537
|
return tool.createdAt >= start && tool.createdAt < end;
|
|
397
538
|
});
|
|
398
539
|
// Time window only. Never dump unmatched tools onto the latest group:
|
|
@@ -402,13 +543,43 @@ export function buildTurnProcessGroups(input) {
|
|
|
402
543
|
assigned.add(tool.id);
|
|
403
544
|
}
|
|
404
545
|
}
|
|
546
|
+
for (const node of input.conversationNodes ?? []) {
|
|
547
|
+
if (node.location.kind === "session")
|
|
548
|
+
continue;
|
|
549
|
+
const turnId = node.location.turnId;
|
|
550
|
+
if (!groups.some((group) => group.turnId === turnId)) {
|
|
551
|
+
startGroup(`turn-${turnId}`, turnId);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
405
554
|
for (const group of groups) {
|
|
406
|
-
group.tools.sort(
|
|
555
|
+
group.tools.sort((a, b) => {
|
|
556
|
+
if (a.eventSeq !== undefined && b.eventSeq !== undefined) {
|
|
557
|
+
return a.eventSeq - b.eventSeq;
|
|
558
|
+
}
|
|
559
|
+
return a.createdAt - b.createdAt;
|
|
560
|
+
});
|
|
561
|
+
const turnState = group.turnId
|
|
562
|
+
? input.turnStatesById?.[group.turnId]
|
|
563
|
+
: undefined;
|
|
564
|
+
if (turnState !== undefined)
|
|
565
|
+
group.turnState = turnState;
|
|
566
|
+
group.turnClosed =
|
|
567
|
+
turnState === "settled" ||
|
|
568
|
+
turnState === "aborted" ||
|
|
569
|
+
turnState === "failed";
|
|
570
|
+
const targetsActiveAssistant = input.activeAssistantId !== null &&
|
|
571
|
+
group.assistants.some((assistant) => assistant.id === input.activeAssistantId);
|
|
407
572
|
group.live =
|
|
408
573
|
input.streaming &&
|
|
409
|
-
|
|
410
|
-
|
|
574
|
+
!group.turnClosed &&
|
|
575
|
+
(targetsActiveAssistant || turnState === "running");
|
|
411
576
|
fillProcessDetails(group);
|
|
577
|
+
group.conversationItems = (input.conversationNodes ?? [])
|
|
578
|
+
.filter((node) => node.location.kind !== "session" && node.location.turnId === group.turnId)
|
|
579
|
+
.map((node) => ({ kind: node.kind, node }));
|
|
580
|
+
if (group.conversationItems.some((item) => item.kind === "turn-error")) {
|
|
581
|
+
group.processItems = group.processItems.filter((item) => item.kind !== "provider-error");
|
|
582
|
+
}
|
|
412
583
|
}
|
|
413
584
|
return groups;
|
|
414
585
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const PREVIEW_LIMIT = 160;
|
|
2
|
+
/** Project the complete durable user-message index without shipping full history. */
|
|
3
|
+
export function projectUserTurnOutline(messages) {
|
|
4
|
+
let index = 0;
|
|
5
|
+
return messages.flatMap((message) => {
|
|
6
|
+
if (message.role !== "user")
|
|
7
|
+
return [];
|
|
8
|
+
index += 1;
|
|
9
|
+
const flat = message.text.trim().replace(/\s+/g, " ");
|
|
10
|
+
return [{
|
|
11
|
+
messageId: message.id,
|
|
12
|
+
index,
|
|
13
|
+
textPreview: flat.length > PREVIEW_LIMIT
|
|
14
|
+
? `${flat.slice(0, PREVIEW_LIMIT).trimEnd()}…`
|
|
15
|
+
: flat,
|
|
16
|
+
createdAt: Date.parse(message.at) || 0,
|
|
17
|
+
}];
|
|
18
|
+
});
|
|
19
|
+
}
|
|
@@ -4,7 +4,7 @@ import { createNpmUpdateClient } from "../../shared/update/npm-client.js";
|
|
|
4
4
|
import { acquireUpdateLock, updateLockPath } from "../../shared/update/state.js";
|
|
5
5
|
import { readInitRuntimeActivity } from "../observability/init-runtime-activity.js";
|
|
6
6
|
import { performConsoleUpdateAndInit, } from "./console-update-and-init.js";
|
|
7
|
-
import {
|
|
7
|
+
import { isOperationOccupied, } from "../../infrastructure/console/operation-store.js";
|
|
8
8
|
export function createConsoleUpdateExecutor(input) {
|
|
9
9
|
return async (channel) => {
|
|
10
10
|
const currentVersion = readPackageVersion(input.packageRoot);
|
|
@@ -49,7 +49,7 @@ export function createConsoleUpdateExecutor(input) {
|
|
|
49
49
|
};
|
|
50
50
|
}
|
|
51
51
|
const liveOtherOperation = operations.some((operation) => operation.action !== "consoleUpdateAndInit" &&
|
|
52
|
-
|
|
52
|
+
isOperationOccupied(operation.state));
|
|
53
53
|
return liveOtherOperation
|
|
54
54
|
? {
|
|
55
55
|
ok: false,
|
|
@@ -142,6 +142,9 @@ export class DagConfirmationStore {
|
|
|
142
142
|
preparedAt: now.toISOString(),
|
|
143
143
|
expiresAt,
|
|
144
144
|
operatorSessionId: input.operatorSessionId,
|
|
145
|
+
...(input.telemetrySessionId
|
|
146
|
+
? { telemetrySessionId: input.telemetrySessionId }
|
|
147
|
+
: {}),
|
|
145
148
|
dagHandle: input.dagHandle,
|
|
146
149
|
dagSha256,
|
|
147
150
|
dagBytesPath: input.dagBytesPath,
|
|
@@ -286,6 +286,9 @@ export class DagExecutionReceiptStore {
|
|
|
286
286
|
preparedAt: now.toISOString(),
|
|
287
287
|
expiresAt: new Date(now.getTime() + ttl).toISOString(),
|
|
288
288
|
operatorSessionId: input.operatorSessionId,
|
|
289
|
+
...(input.telemetrySessionId
|
|
290
|
+
? { telemetrySessionId: input.telemetrySessionId }
|
|
291
|
+
: {}),
|
|
289
292
|
taskId: input.taskId,
|
|
290
293
|
dagHandle: input.dagHandle,
|
|
291
294
|
dagSha256: hashDagBytes(input.dagBytes),
|
|
@@ -35,6 +35,7 @@ import { evaluateConsoleDagInterruptEligibility } from "../observability/interru
|
|
|
35
35
|
import { INTERRUPT_ERROR_MESSAGES, isInterruptReasonCode, normalizeInterruptReasonDetail, } from "../observability/interrupt-eligibility.js";
|
|
36
36
|
import { assessAutonomousExecutionEligibility, deriveEligibilityFactsFromDagSpec, } from "./dag-execution-receipt.js";
|
|
37
37
|
import { issueHumanGateToken, mutationGatePayloadHash, verifyHumanGateToken, } from "./human-gate-token.js";
|
|
38
|
+
import { DAG_TELEMETRY_SESSION_ID_ENV, isTelemetrySessionId, } from "../../shared/wizard-local-telemetry.js";
|
|
38
39
|
const MUTATION_GATE_ACTIONS = new Set([
|
|
39
40
|
// 2026-08-11: standaloneTaskRerun / workerTaskRetry are autonomous (server
|
|
40
41
|
// run-facts checks). Destructive DAG reconciliation, live cooperative
|
|
@@ -565,7 +566,11 @@ export async function acceptOperation(ctx, input) {
|
|
|
565
566
|
events: ctx.events,
|
|
566
567
|
client: ctx.client,
|
|
567
568
|
repoRoot: ctx.repoRoot,
|
|
568
|
-
env: {
|
|
569
|
+
env: {
|
|
570
|
+
...process.env,
|
|
571
|
+
LOOP_CONSOLE_APP_DATA: ctx.appData.root,
|
|
572
|
+
...input.env,
|
|
573
|
+
},
|
|
569
574
|
runCommand: ctx.runCommand,
|
|
570
575
|
beforeTerminal: input.beforeTerminal,
|
|
571
576
|
onSettled: async (operation, state, info) => {
|
|
@@ -822,6 +827,21 @@ async function acceptConsoleUpdateAndInit(ctx, clientRequestId, channel) {
|
|
|
822
827
|
},
|
|
823
828
|
};
|
|
824
829
|
}
|
|
830
|
+
async function resolvePreparedDagTelemetrySessionId(ctx) {
|
|
831
|
+
if (!ctx.chatSessionRef || !ctx.sddDataAlignment)
|
|
832
|
+
return undefined;
|
|
833
|
+
if (!(await ctx.sddDataAlignment.isEligible()))
|
|
834
|
+
return undefined;
|
|
835
|
+
return ctx.sddDataAlignment.ensureTelemetrySessionId(ctx.chatSessionRef);
|
|
836
|
+
}
|
|
837
|
+
async function resolveDagTelemetryEnv(ctx, telemetrySessionId) {
|
|
838
|
+
if (!isTelemetrySessionId(telemetrySessionId) ||
|
|
839
|
+
!ctx.sddDataAlignment ||
|
|
840
|
+
!(await ctx.sddDataAlignment.isEligible())) {
|
|
841
|
+
return undefined;
|
|
842
|
+
}
|
|
843
|
+
return { [DAG_TELEMETRY_SESSION_ID_ENV]: telemetrySessionId };
|
|
844
|
+
}
|
|
825
845
|
export async function dispatchOperatorAction(ctx, req) {
|
|
826
846
|
const action = req.action?.trim();
|
|
827
847
|
if (!action) {
|
|
@@ -1668,8 +1688,10 @@ export async function dispatchOperatorAction(ctx, req) {
|
|
|
1668
1688
|
canonicalizerVersion: ref.canonicalizerVersion,
|
|
1669
1689
|
taskConfigSchemaVersion: ref.taskConfigSchemaVersion,
|
|
1670
1690
|
};
|
|
1691
|
+
const telemetrySessionId = await resolvePreparedDagTelemetrySessionId(ctx);
|
|
1671
1692
|
const confirmation = await ctx.confirmations.prepare({
|
|
1672
1693
|
operatorSessionId: ctx.operatorSessionId,
|
|
1694
|
+
...(telemetrySessionId ? { telemetrySessionId } : {}),
|
|
1673
1695
|
dagHandle,
|
|
1674
1696
|
dagBytes: dagText,
|
|
1675
1697
|
dagBytesPath: staged.path,
|
|
@@ -1910,8 +1932,10 @@ export async function dispatchOperatorAction(ctx, req) {
|
|
|
1910
1932
|
}),
|
|
1911
1933
|
};
|
|
1912
1934
|
}
|
|
1935
|
+
const telemetrySessionId = await resolvePreparedDagTelemetrySessionId(ctx);
|
|
1913
1936
|
const prepared = await ctx.dagExecutionReceipts.prepare({
|
|
1914
1937
|
operatorSessionId: ctx.operatorSessionId,
|
|
1938
|
+
...(telemetrySessionId ? { telemetrySessionId } : {}),
|
|
1915
1939
|
taskId,
|
|
1916
1940
|
dagHandle: "staged-dag.json",
|
|
1917
1941
|
dagBytes: dagText,
|
|
@@ -2350,7 +2374,7 @@ export async function dispatchOperatorAction(ctx, req) {
|
|
|
2350
2374
|
if (!confirmationId) {
|
|
2351
2375
|
return invalid(action, "runDag requires executionId (autonomous) or confirmationId (browser Human Gate)");
|
|
2352
2376
|
}
|
|
2353
|
-
// Preserved browser Human Gate flow
|
|
2377
|
+
// Preserved browser Human Gate flow.
|
|
2354
2378
|
const conf = await ctx.confirmations.get(confirmationId);
|
|
2355
2379
|
if (!conf) {
|
|
2356
2380
|
return {
|
|
@@ -2409,12 +2433,14 @@ export async function dispatchOperatorAction(ctx, req) {
|
|
|
2409
2433
|
}
|
|
2410
2434
|
const taskId = conf.taskContractBinding.taskId;
|
|
2411
2435
|
const gateToken = readWriteSetGateToken(conf.reviewPacket);
|
|
2436
|
+
const dagTelemetryEnv = await resolveDagTelemetryEnv(ctx, conf.telemetrySessionId);
|
|
2412
2437
|
if (gateToken) {
|
|
2413
2438
|
return acceptOperation(ctx, {
|
|
2414
2439
|
action,
|
|
2415
2440
|
actionParams: { confirmationId },
|
|
2416
2441
|
clientRequestId,
|
|
2417
2442
|
taskId,
|
|
2443
|
+
env: dagTelemetryEnv,
|
|
2418
2444
|
cliArgs: [
|
|
2419
2445
|
"task",
|
|
2420
2446
|
"advance",
|
|
@@ -2430,6 +2456,7 @@ export async function dispatchOperatorAction(ctx, req) {
|
|
|
2430
2456
|
actionParams: { confirmationId },
|
|
2431
2457
|
clientRequestId,
|
|
2432
2458
|
taskId,
|
|
2459
|
+
env: dagTelemetryEnv,
|
|
2433
2460
|
cliArgs: [
|
|
2434
2461
|
"dag",
|
|
2435
2462
|
"execute",
|
|
@@ -2503,6 +2530,7 @@ export async function dispatchOperatorAction(ctx, req) {
|
|
|
2503
2530
|
};
|
|
2504
2531
|
}
|
|
2505
2532
|
const gateToken = readWriteSetGateToken(receipt.reviewPacket);
|
|
2533
|
+
const dagTelemetryEnv = await resolveDagTelemetryEnv(ctx, receipt.telemetrySessionId);
|
|
2506
2534
|
const dispatchRun = async () => {
|
|
2507
2535
|
if (gateToken) {
|
|
2508
2536
|
// Standard lifecycle path: the execution receipt replaces the
|
|
@@ -2512,6 +2540,7 @@ export async function dispatchOperatorAction(ctx, req) {
|
|
|
2512
2540
|
actionParams: { executionId },
|
|
2513
2541
|
clientRequestId,
|
|
2514
2542
|
taskId,
|
|
2543
|
+
env: dagTelemetryEnv,
|
|
2515
2544
|
cliArgs: [
|
|
2516
2545
|
"task",
|
|
2517
2546
|
"advance",
|
|
@@ -2528,6 +2557,7 @@ export async function dispatchOperatorAction(ctx, req) {
|
|
|
2528
2557
|
actionParams: { executionId },
|
|
2529
2558
|
clientRequestId,
|
|
2530
2559
|
taskId,
|
|
2560
|
+
env: dagTelemetryEnv,
|
|
2531
2561
|
cliArgs: [
|
|
2532
2562
|
"dag",
|
|
2533
2563
|
"execute",
|
|
@@ -2759,7 +2789,6 @@ export async function dispatchOperatorAction(ctx, req) {
|
|
|
2759
2789
|
reconcileAction,
|
|
2760
2790
|
"--reason",
|
|
2761
2791
|
reason,
|
|
2762
|
-
"--json",
|
|
2763
2792
|
],
|
|
2764
2793
|
});
|
|
2765
2794
|
await finalizeMutationGateReceipt(ctx, gated.receiptId, accepted);
|
|
@@ -114,7 +114,7 @@ const CONTEXT_TRANSFER_CODE_COPY = [
|
|
|
114
114
|
},
|
|
115
115
|
{
|
|
116
116
|
pattern: /\bOPERATION_NEEDS_RECONCILE\b/,
|
|
117
|
-
copy: "
|
|
117
|
+
copy: "当前操作的执行结果尚未确认,需要先核对(OPERATION_NEEDS_RECONCILE)。请查看操作记录和相关任务状态,核对实际执行结果后再决定后续操作;确认前请勿重复提交。"
|
|
118
118
|
},
|
|
119
119
|
{
|
|
120
120
|
pattern: /\bCONTEXT_EXPORT_FAILED\b/,
|
|
@@ -169,6 +169,33 @@ const CONTEXT_TRANSFER_CODE_COPY = [
|
|
|
169
169
|
pattern: /\bINVALID_VERSION\b/,
|
|
170
170
|
copy: "安装版本或渠道版本号无法解析(INVALID_VERSION),请重试;若持续出现请反馈。",
|
|
171
171
|
},
|
|
172
|
+
// 源绑定漂移(dag-confirmation.ts / dag-execution-receipt.ts 的英文原文)
|
|
173
|
+
// 与 frontend split CAS 冲突(operator-actions.ts)原本会原样透传到操作者
|
|
174
|
+
// 横幅,这里给出可执行的中文说明。
|
|
175
|
+
{
|
|
176
|
+
pattern: /\bBINDING_DRIFT\b|\bbinding drift\b|\bbinding drifted\b/i,
|
|
177
|
+
copy: "这次确认所依据的内容已经变了(任务契约、源文件、程序版本或校验结果在确认之后被修改),因此旧确认不能再使用。这是保护措施,不是故障:请回到任务页重新生成确认,然后重新开始运行。",
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
pattern: /frontend split CAS conflict/i,
|
|
181
|
+
copy: "前端拆分任务的状态在你操作期间被其他操作改过了(通常是另一个标签页或并发操作),为避免覆盖对方的结果,本次修改没有生效。请刷新页面,确认当前状态后重试。",
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
pattern: /\bCONFIRMATION_EXPIRED\b/,
|
|
185
|
+
copy: "这次确认已经超时失效。请回到任务页重新生成确认后再继续。",
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
pattern: /\bCONFIRMATION_STALE\b/,
|
|
189
|
+
copy: "这次确认对应的是改动之前的内容,已经过期作废。请回到任务页重新生成确认后再继续。",
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
pattern: /\bCONFIRMATION_CONSUMED\b/,
|
|
193
|
+
copy: "这次确认已经被使用过了,不能重复提交。如需再次执行,请重新生成确认。",
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
pattern: /\bHUMAN_CONFIRMATION_REQUIRED\b/,
|
|
197
|
+
copy: "这一步需要你先在页面上确认一次才能继续。请按提示完成确认后再重试。",
|
|
198
|
+
},
|
|
172
199
|
];
|
|
173
200
|
/** Map internal spawn/controller errors to actionable Chinese copy. */
|
|
174
201
|
export function formatOperatorUserError(message) {
|