@tea-agent/loop-agent 0.39.3 → 0.40.0-beta.2
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 +135 -92
- package/dist/adapters/context-transfer/optional-pi-handoff.js +31 -0
- package/dist/adapters/context-transfer/pi-session.js +61 -0
- package/dist/build-stamp.json +3 -3
- package/dist/cli/command-definitions.js +12 -0
- package/dist/cli/program.js +23 -1
- package/dist/commands/dag-artifact.js +284 -0
- package/dist/commands/dag-context.js +184 -0
- package/dist/commands/dag-rerun.js +206 -1
- package/dist/executors/dag-pi-executor.js +108 -19
- package/dist/executors/pi-executor.js +4 -2
- package/dist/executors/pi-sdk-executor.js +49 -1
- package/dist/executors/pi-writer-tool-policy.js +57 -1
- package/dist/executors/shell-executor.js +42 -2
- package/dist/executors/workspace-write-snapshot.js +68 -0
- package/dist/{worker → infrastructure}/console/app-data.js +4 -0
- package/dist/infrastructure/console/artifact-revision-store.js +430 -0
- package/dist/infrastructure/console/context-export-store.js +160 -0
- package/dist/infrastructure/console/dir-lock.js +132 -0
- package/dist/infrastructure/harness/artifact-store.js +10 -1
- package/dist/infrastructure/harness/atomic-write.js +35 -2
- package/dist/shared/context-transfer/artifact-revision.js +172 -0
- package/dist/shared/context-transfer.js +418 -0
- package/dist/shared/operator/capabilities.js +14 -0
- package/dist/shared/operator/safe-run-summary.js +1 -0
- package/dist/shared/path-safety.js +93 -0
- package/dist/shared/preview.js +28 -4
- package/dist/task/config-types.js +12 -1
- package/dist/task/source-prepare/fragment-inventory.js +1 -14
- package/dist/task/task-demand-routing.js +3 -0
- package/dist/worker/console/chat/chat-event-store.js +77 -7
- package/dist/worker/console/chat/context-panel.js +7 -0
- package/dist/worker/console/chat/deferred-turn.js +12 -0
- package/dist/worker/console/chat/pi-runtime.js +331 -18
- package/dist/worker/console/chat/provider-error.js +98 -0
- package/dist/worker/console/chat/resource-preferences-store.js +1 -1
- package/dist/worker/console/chat/routes.js +389 -56
- package/dist/worker/console/chat/session-stats.js +179 -0
- package/dist/worker/console/chat/session-store.js +94 -64
- package/dist/worker/console/chat/todos.js +115 -0
- package/dist/worker/console/chat/tool-preview.js +42 -0
- package/dist/worker/console/chat/turn-process.js +20 -55
- package/dist/worker/console/chat/user-questions.js +266 -0
- package/dist/worker/console/chat/workspace-landing.js +79 -0
- package/dist/worker/console/console-update-runtime.js +1 -1
- package/dist/worker/console/context-transfer-diagnostics.js +198 -0
- package/dist/worker/console/dag-confirmation.js +1 -1
- package/dist/worker/console/dag-execution-receipt.js +1 -1
- package/dist/worker/console/doctor.js +1 -1
- package/dist/worker/console/draft-store.js +1 -1
- package/dist/worker/console/human-gate-token.js +1 -1
- package/dist/worker/console/index.js +3 -3
- package/dist/worker/console/interview/assessment.js +1 -1
- package/dist/worker/console/interview/session.js +1 -1
- package/dist/worker/console/native-directory-picker.js +13 -0
- package/dist/worker/console/operation-runner.js +45 -4
- package/dist/worker/console/operation-sse.js +1 -1
- package/dist/worker/console/operation-wait.js +1 -1
- package/dist/worker/console/operator-actions.js +104 -3
- package/dist/worker/console/operator-surface-health.js +1 -1
- package/dist/worker/console/operator-user-error.js +128 -0
- package/dist/worker/console/routes.js +927 -8
- package/dist/worker/console/security.js +39 -4
- package/dist/worker/console/server.js +532 -187
- package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-CTx1TrNa.js → abnfDiagram-N423BO3Z-CpWvwARc.js} +1 -1
- package/dist/worker/console/static/assets/{arc-B4i9cVxX.js → arc-DctXgO-g.js} +1 -1
- package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-BAXE8_Rl.js → architectureDiagram-T3A2C74G-D4mIkoQl.js} +1 -1
- package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-C5Xh59at.js → blockDiagram-VBNYF7ZC-ClG0--KO.js} +1 -1
- package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-B_asOzAu.js → c4Diagram-5PPSVZJV-CwdLk78T.js} +1 -1
- package/dist/worker/console/static/assets/channel-C9VQZ-ru.js +1 -0
- package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-wRO_iRNc.js → chunk-2GRJ4B5K-DKczcu-O.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-ByOaSh_G.js → chunk-2Q5K7J3B-BV6F-vBI.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5RXB4S5H-DjLzudan.js → chunk-5RXB4S5H-DtojVnvA.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5VM5RSS4-JCNGkXYT.js → chunk-5VM5RSS4-BjDQRGnO.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-BhrPXXMZ.js → chunk-6Q2QTUOP-I0fV6ngU.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-GF5L2VYU-TJ5JuEBT.js → chunk-GF5L2VYU-BM8C-mmC.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-JWPE2WC7-VVthn_mD.js → chunk-JWPE2WC7-BEK-a15e.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-KBJHAD2P-D60-Mny4.js → chunk-KBJHAD2P-CQsg_fSR.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-RYQCIY6F-zXv7aVye.js → chunk-RYQCIY6F-B-BcaUm3.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-XXDRQBXY-By9VQoi1.js → chunk-XXDRQBXY-D1Bu08fg.js} +1 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-BsCkw5MF.js +1 -0
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-BsCkw5MF.js +1 -0
- package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-C4zQLe-M.js → cose-bilkent-JH36ORCC-q8nwtxBR.js} +1 -1
- package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-wh5N2ReN.js → cynefin-VYW2F7L2-CruhpURw.js} +1 -1
- package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-Dlu5wIqs.js → cynefinDiagram-MW4NZA55-CJne6iYF.js} +1 -1
- package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-CrDgthc6.js → dagre-VZM6K2ZE-CbeLvBU5.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-7IWD3JNH-zN1clg27.js → diagram-7IWD3JNH-DmCxH1Pe.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-BN-o7J7-.js → diagram-B4RE2ZJO-DJ5OYhtC.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-LBJQPF4R-C8SuPt0d.js → diagram-LBJQPF4R-B-UN-hln.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-Q27KOJAE-BoizuHbZ.js → diagram-Q27KOJAE-CcEro8Ey.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-UB23O5K3-BzUzXixG.js → diagram-UB23O5K3-BBBzDden.js} +1 -1
- package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-Ev3lA4Cf.js → ebnfDiagram-BXEA7PRR-xKEyH-oo.js} +1 -1
- package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-GALUzRbs.js → erDiagram-JOGREHBK-C7xl63VC.js} +1 -1
- package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-CZJN65Sb.js → flowDiagram-UKHOOZJN-nthQQ9nR.js} +1 -1
- package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-JLB9OESl.js → ganttDiagram-PKOTCBZU-CWN5mE33.js} +1 -1
- package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-CcvCr4GD.js → gitGraphDiagram-DS77QQ5N-Wn86tQ6N.js} +1 -1
- package/dist/worker/console/static/assets/index-D-0NVyMk.css +1 -0
- package/dist/worker/console/static/assets/index-gwyOxQiS.js +407 -0
- package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-HG5z7aVg.js → infoDiagram-6WML65LV-_WQymGtW.js} +1 -1
- package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-BHEu9chR.js → ishikawaDiagram-WSZJBQD7-COBeivBm.js} +1 -1
- package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-Cp_Up8-a.js → journeyDiagram-NVQOT4AX-CwGOJl3Q.js} +1 -1
- package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-DvVeY-em.js → kanban-definition-27J2QSJJ-Ci0CJ5Vi.js} +1 -1
- package/dist/worker/console/static/assets/{linear-aGmcjgTn.js → linear-CPjMq6vN.js} +1 -1
- package/dist/worker/console/static/assets/{mermaid.core-Biyo-tqA.js → mermaid.core-Z0wGoe0b.js} +5 -5
- package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-DyxY2pIb.js → mindmap-definition-FAOFIHXS-dISked0d.js} +1 -1
- package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-CkdGuc50.js → pegDiagram-VL7TDLO6-BJxgof7Y.js} +1 -1
- package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-NNQI9xVR.js → pieDiagram-7S7Q4E2Y-CIblU8eW.js} +1 -1
- package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-PAJkuz_G.js → quadrantDiagram-CIZ2JOQS-vwYiqh8E.js} +1 -1
- package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-ZwrQod0O.js → railroadDiagram-AXF67PYL-_iOsVeFm.js} +1 -1
- package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-D3ZfrzM2.js → requirementDiagram-LRYGKXZP-Dk0MLxO_.js} +1 -1
- package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-DDGFmWk5.js → sankeyDiagram-W5VNT64P-Dx7HtLVW.js} +1 -1
- package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-DO6mmXTA.js → sequenceDiagram-SI44F4Z6-DRuWjlpL.js} +1 -1
- package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-DMbCQiJt.js → sizeCapture-X5ZJPWSS-Bhy9DQAA.js} +1 -1
- package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-Di_YUEfC.js → stateDiagram-OKZ733FA-DAx9twnU.js} +1 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-Dmdf8cGy.js +1 -0
- package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-Bn2PphNJ.js → swimlanes-SLNWSIFB-okMlvVrM.js} +2 -2
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-W1IcAFff.js +8 -0
- package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-DPh8pRsp.js → timeline-definition-Z64GVDOM-DXqCKe37.js} +1 -1
- package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-GMfl26pW.js → vennDiagram-T6HMQDX7-CeIUkwBh.js} +1 -1
- package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-DTlmVrmF.js → wardleyDiagram-T6FBY63Y-BP76BKTN.js} +1 -1
- package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-YGBjKAS5.js → xychartDiagram-ELKLHX3M-BpVI0OpF.js} +1 -1
- package/dist/worker/console/static/index.html +7 -2
- package/dist/worker/console/static-src/app/console-types.js +29 -4
- package/dist/worker/console/static-src/app/useConsoleShell.js +30 -12
- package/dist/worker/console/static-src/app/useOperatorActions.js +36 -6
- package/dist/worker/console/static-src/app/useRecoveryConsole.js +10 -11
- package/dist/worker/console/static-src/app/useRunProgress.js +2 -1
- package/dist/worker/console/static-src/app/useTaskWizard.js +2 -2
- package/dist/worker/console/static-src/night/useNightBoard.js +8 -5
- package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +141 -8
- package/dist/worker/console/static-src/operator-chat/compaction-message.js +79 -0
- package/dist/worker/console/static-src/operator-chat/details-dag-actions.js +122 -0
- package/dist/worker/console/static-src/operator-chat/refs.js +3 -0
- package/dist/worker/console/static-src/operator-chat/runtime-selection-labels.js +27 -0
- package/dist/worker/console/static-src/operator-chat/spatial-overlay.js +1 -2
- package/dist/worker/console/static-src/operator-chat/turn-stream-controller.js +25 -0
- package/dist/worker/console/static-src/operator-chat/turn-submission.js +3 -2
- package/dist/worker/console/static-src/operator-chat/useChatSessions.js +181 -87
- package/dist/worker/console/static-src/operator-chat/useChatStream.js +159 -44
- package/dist/worker/console/static-src/operator-chat/useChatThread.js +177 -8
- package/dist/worker/console/static-src/operator-chat/useRepoBrowser.js +63 -9
- package/dist/worker/console/static-src/operator-chat/useWorkspaceBrowserGate.js +4 -0
- package/dist/worker/console/static-src/operator-chat/workspace-layout-mode.js +3 -3
- package/dist/worker/console/static-src/shell/useWorkspaces.js +299 -0
- package/dist/worker/console/static-src/shell/workspace-route.js +339 -0
- package/dist/worker/console/workspace-context.js +260 -0
- package/dist/worker/console/workspace-registry.js +214 -0
- package/dist/worker/continuation/worker-continuation.js +278 -0
- package/dist/worker/observe/health.js +1 -1
- package/dist/worker/observe/node-transparency.js +572 -0
- package/dist/worker/observe/routes.js +51 -1
- package/dist/worker/observe/server.js +4 -0
- package/dist/worker/observe/static/api.js +94 -10
- package/dist/worker/observe/static/app.js +18 -70
- package/dist/worker/observe/static/dag-context-reason-labels.d.ts +9 -0
- package/dist/worker/observe/static/dag-context-reason-labels.js +120 -0
- package/dist/worker/observe/static/index.html +1 -1
- package/dist/worker/observe/static/inspect-workspace.js +307 -0
- package/dist/worker/observe/static/operator-chrome.css +145 -20
- package/dist/worker/observe/static/operator-chrome.d.ts +20 -3
- package/dist/worker/observe/static/operator-chrome.js +330 -100
- package/dist/worker/observe/static/router.d.ts +46 -0
- package/dist/worker/observe/static/router.js +25 -1
- package/dist/worker/observe/static/state.d.ts +50 -0
- package/dist/worker/observe/static/state.js +175 -1
- package/dist/worker/observe/static/styles.css +1039 -128
- package/dist/worker/observe/static/views/dag-inspector.js +1218 -60
- package/dist/worker/observe/static/views/dag.js +2 -1
- package/dist/worker/observe/static/views/dashboard.js +6 -4
- package/dist/worker/observe/static/views/night.js +2 -2
- package/dist/worker/observe/static/views/pool.js +1 -0
- package/dist/worker/observe/static/views/run.js +3 -1
- package/dist/worker/observe/static/views/session-timeline.js +75 -10
- package/dist/worker/observe/static/views/task.js +1 -1
- package/dist/worker/outcomes/adapters.js +19 -0
- package/dist/worker/outcomes/types.js +1 -0
- package/dist/worker/pool/attempt-lease.js +97 -66
- package/dist/worker/pool/begin-attempt-with-lease.js +1 -0
- package/dist/worker/pool/reconcile.js +46 -1
- package/dist/worker/pool/run-store.js +2 -0
- package/dist/worker/pool/state-projection.js +2 -0
- package/dist/worker/task-spec/workflow-routing.js +8 -3
- package/dist/workflows/dag/artifact-bindings.js +149 -0
- package/dist/workflows/dag/artifact-revision-schema-registry.js +31 -0
- package/dist/workflows/dag/backend-test-pytest-collection.js +11 -10
- package/dist/workflows/dag/backend-test-writer-completeness.js +7 -12
- package/dist/workflows/dag/context-receipt.js +305 -0
- package/dist/workflows/dag/context-transfer/context-bundle.js +423 -0
- package/dist/workflows/dag/context-transfer/operator-actions.js +61 -0
- package/dist/workflows/dag/context-transfer/renderers.js +93 -0
- package/dist/workflows/dag/dynamic-runtime/map.js +1 -0
- package/dist/workflows/dag/frontend-implementation-contract.js +1 -89
- package/dist/workflows/dag/init-hybrid.js +259 -47
- package/dist/workflows/dag/interrupt-request.js +3 -3
- package/dist/workflows/dag/lifecycle.js +3 -3
- package/dist/workflows/dag/node-execution.js +112 -27
- package/dist/workflows/dag/path-safety.js +1 -0
- package/dist/workflows/dag/prompt.js +29 -4
- package/dist/workflows/dag/rerun-plan.js +272 -0
- package/dist/workflows/dag/rerun-run.js +390 -12
- package/dist/workflows/dag/skill-snapshot.js +1 -0
- package/dist/workflows/dag/types.js +203 -8
- package/docs/README.md +1 -0
- package/docs/architecture/runtime-boundaries.md +6 -6
- package/docs/architecture/worker-and-feature.md +1 -1
- package/docs/operations/local-development-environment.md +21 -0
- package/docs/templates/agent-dag.schema.json +50 -0
- package/docs/templates/backend-test-dag.json +265 -237
- package/docs/templates/product-line/task.yaml +1 -1
- package/harness.json +3 -3
- package/package.json +5 -1
- package/skills/loop-agent/references/command-reference.md +6 -0
- package/dist/worker/console/static/assets/channel-Dj_4Moei.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-C0YYAyCa.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-C0YYAyCa.js +0 -1
- package/dist/worker/console/static/assets/index-CW88Fjbw.js +0 -406
- package/dist/worker/console/static/assets/index-DP0ZJl39.css +0 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-DrdDvela.js +0 -1
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-DPkEAULl.js +0 -8
- package/dist/worker/console/static-src/operator-chat/activity-rail-presentation.js +0 -73
- package/dist/worker/console/static-src/operator-chat/useActivityRailTransition.js +0 -59
- /package/dist/{worker → infrastructure}/console/operation-store.js +0 -0
- /package/dist/{worker → infrastructure}/console/repo-fingerprint.js +0 -0
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
import { createHash } from "node:crypto";
|
|
20
20
|
import { existsSync, readFileSync, rmSync } from "node:fs";
|
|
21
21
|
import path from "node:path";
|
|
22
|
-
import { ensureSecureDir, writeSecureJsonSync, } from "
|
|
23
|
-
import { isTerminalOperationState, } from "
|
|
22
|
+
import { ensureSecureDir, writeSecureJsonSync, } from "../../../infrastructure/console/app-data.js";
|
|
23
|
+
import { isTerminalOperationState, } from "../../../infrastructure/console/operation-store.js";
|
|
24
24
|
import { scrubSecrets } from "./explore-tools.js";
|
|
25
25
|
const OPERATION_PREVIEW_MAX_CHARS = 1200;
|
|
26
26
|
function boundedRedactedText(value, maxChars = OPERATION_PREVIEW_MAX_CHARS) {
|
|
@@ -231,6 +231,10 @@ export function projectCompactSnapshot(value) {
|
|
|
231
231
|
Number.isFinite(record.tokensBefore)
|
|
232
232
|
? Math.max(0, Math.floor(record.tokensBefore))
|
|
233
233
|
: undefined;
|
|
234
|
+
const estimatedTokensAfter = typeof record.estimatedTokensAfter === "number" &&
|
|
235
|
+
Number.isFinite(record.estimatedTokensAfter)
|
|
236
|
+
? Math.max(0, Math.floor(record.estimatedTokensAfter))
|
|
237
|
+
: undefined;
|
|
234
238
|
const details = record.details === undefined
|
|
235
239
|
? undefined
|
|
236
240
|
: boundedRedactedJson(record.details).preview;
|
|
@@ -239,9 +243,16 @@ export function projectCompactSnapshot(value) {
|
|
|
239
243
|
summary,
|
|
240
244
|
...(firstKeptEntryId ? { firstKeptEntryId } : {}),
|
|
241
245
|
...(tokensBefore !== undefined ? { tokensBefore } : {}),
|
|
246
|
+
...(estimatedTokensAfter !== undefined ? { estimatedTokensAfter } : {}),
|
|
242
247
|
...(details ? { details } : {}),
|
|
243
248
|
previewHash: createHash("sha256")
|
|
244
|
-
.update(JSON.stringify({
|
|
249
|
+
.update(JSON.stringify({
|
|
250
|
+
summary,
|
|
251
|
+
firstKeptEntryId,
|
|
252
|
+
tokensBefore,
|
|
253
|
+
estimatedTokensAfter,
|
|
254
|
+
details,
|
|
255
|
+
}))
|
|
245
256
|
.digest("hex"),
|
|
246
257
|
};
|
|
247
258
|
}
|
|
@@ -433,6 +444,20 @@ function safeSessionId(sessionId) {
|
|
|
433
444
|
* Link durable Chat refs to the existing canonical operation store/event ring.
|
|
434
445
|
* This owns no operation state and schedules no work; it only projects facts.
|
|
435
446
|
*/
|
|
447
|
+
/** R8 AC-R8-001: operationIds whose operation-ref has been overshadowed by
|
|
448
|
+
* a later operation-unlinked tombstone in the same ring. A tombstoned
|
|
449
|
+
* association must never be restored by recoverSession / replay / fork. */
|
|
450
|
+
function tombstonedOperationIds(events) {
|
|
451
|
+
const tombstones = new Set();
|
|
452
|
+
for (const event of events) {
|
|
453
|
+
if (event.kind !== "operation-unlinked")
|
|
454
|
+
continue;
|
|
455
|
+
const operationId = event.data.operationId;
|
|
456
|
+
if (typeof operationId === "string" && operationId)
|
|
457
|
+
tombstones.add(operationId);
|
|
458
|
+
}
|
|
459
|
+
return tombstones;
|
|
460
|
+
}
|
|
436
461
|
export function createChatOperationLinker(options) {
|
|
437
462
|
const followers = new Map();
|
|
438
463
|
const keyFor = (sessionId, operationId) => `${sessionId}\u0000${operationId}`;
|
|
@@ -535,14 +560,37 @@ export function createChatOperationLinker(options) {
|
|
|
535
560
|
}
|
|
536
561
|
return {
|
|
537
562
|
link,
|
|
563
|
+
async unlink(input) {
|
|
564
|
+
// Idempotent removal (AC-R7-001): drop the live follower and the
|
|
565
|
+
// persisted operation-ref event so the association is truly gone.
|
|
566
|
+
const key = keyFor(input.sessionId, input.operationId);
|
|
567
|
+
followers.get(key)?.();
|
|
568
|
+
followers.delete(key);
|
|
569
|
+
const ring = options.chatEvents.snapshot(input.sessionId);
|
|
570
|
+
const refs = ring.filter((event) => event.kind === "operation-ref" &&
|
|
571
|
+
event.data.operationId ===
|
|
572
|
+
input.operationId);
|
|
573
|
+
for (const event of refs) {
|
|
574
|
+
options.chatEvents.append(input.sessionId, event.turnId, {
|
|
575
|
+
kind: "operation-unlinked",
|
|
576
|
+
data: { operationId: input.operationId, unlinkedAt: new Date().toISOString() },
|
|
577
|
+
});
|
|
578
|
+
}
|
|
579
|
+
return refs.length > 0;
|
|
580
|
+
},
|
|
538
581
|
async recoverSession(sessionId) {
|
|
539
|
-
const
|
|
540
|
-
|
|
541
|
-
|
|
582
|
+
const snapshot = options.chatEvents.snapshot(sessionId);
|
|
583
|
+
// R8 AC-R8-001: a tombstoned (unlinked) operationId must NOT be
|
|
584
|
+
// re-linked on recovery — the persisted operation-unlinked event
|
|
585
|
+
// overshadows any earlier operation-ref in the same ring.
|
|
586
|
+
const tombstones = tombstonedOperationIds(snapshot);
|
|
587
|
+
const refs = snapshot.filter((event) => event.kind === "operation-ref");
|
|
542
588
|
for (const event of refs) {
|
|
543
589
|
const data = event.data;
|
|
544
590
|
if (!data.operationId || !data.toolCallId)
|
|
545
591
|
continue;
|
|
592
|
+
if (tombstones.has(data.operationId))
|
|
593
|
+
continue;
|
|
546
594
|
await link({
|
|
547
595
|
sessionId,
|
|
548
596
|
turnId: event.turnId,
|
|
@@ -566,6 +614,19 @@ export function createChatOperationLinker(options) {
|
|
|
566
614
|
},
|
|
567
615
|
};
|
|
568
616
|
}
|
|
617
|
+
/** R8 AC-R8-001 (fork): same tombstone scan as the linker — kept local to
|
|
618
|
+
* the store so forkContextRefs needs no linker dependency. */
|
|
619
|
+
function forkTombstonedOperationIds(events) {
|
|
620
|
+
const tombstones = new Set();
|
|
621
|
+
for (const event of events) {
|
|
622
|
+
if (event.kind !== "operation-unlinked")
|
|
623
|
+
continue;
|
|
624
|
+
const operationId = event.data.operationId;
|
|
625
|
+
if (typeof operationId === "string" && operationId)
|
|
626
|
+
tombstones.add(operationId);
|
|
627
|
+
}
|
|
628
|
+
return tombstones;
|
|
629
|
+
}
|
|
569
630
|
export function createChatEventStore(options) {
|
|
570
631
|
const maxEvents = options?.maxEventsPerSession ?? DEFAULT_MAX_EVENTS;
|
|
571
632
|
const maxBytes = options?.maxBytesPerSession ?? DEFAULT_MAX_BYTES;
|
|
@@ -735,13 +796,22 @@ export function createChatEventStore(options) {
|
|
|
735
796
|
"assessment",
|
|
736
797
|
"taskKind-confirmed",
|
|
737
798
|
"human-gate-card",
|
|
799
|
+
"compaction_end",
|
|
738
800
|
"compact",
|
|
739
801
|
"artifact-ref",
|
|
740
802
|
]);
|
|
741
803
|
let copiedCount = 0;
|
|
742
|
-
|
|
804
|
+
const source = this.snapshot(input.sourceSessionId);
|
|
805
|
+
// R8 AC-R8-001: fork excludes tombstoned associations — an unlinked
|
|
806
|
+
// operationId must not leak its operation-ref into a forked session.
|
|
807
|
+
const tombstones = forkTombstonedOperationIds(source);
|
|
808
|
+
for (const event of source) {
|
|
743
809
|
if (!allowed.has(event.kind))
|
|
744
810
|
continue;
|
|
811
|
+
if ((event.kind === "operation-ref" ||
|
|
812
|
+
event.kind === "operation-status") &&
|
|
813
|
+
tombstones.has(event.data.operationId ?? ""))
|
|
814
|
+
continue;
|
|
745
815
|
const data = structuredClone(event.data);
|
|
746
816
|
if (event.kind === "human-gate-card") {
|
|
747
817
|
delete data.humanGateToken;
|
|
@@ -38,6 +38,13 @@ export function projectTaskContext(input) {
|
|
|
38
38
|
const previous = gates.get(card.cardId);
|
|
39
39
|
gates.set(card.cardId, safeGate({ ...card, ...(previous?.dagSpine && !card.dagSpine ? { dagSpine: previous.dagSpine } : {}) }));
|
|
40
40
|
}
|
|
41
|
+
else if (event.kind === "operation-unlinked") {
|
|
42
|
+
// R8 AC-001/AC-R8-001: tombstone — an operation-unlinked event appended
|
|
43
|
+
// after its operation-ref removes the card from the projection for good.
|
|
44
|
+
const operationId = typeof data.operationId === "string" ? data.operationId : "";
|
|
45
|
+
if (operationId)
|
|
46
|
+
view.operations = view.operations.filter((operation) => operation.operationId !== operationId);
|
|
47
|
+
}
|
|
41
48
|
else if (event.kind === "operation-ref" || event.kind === "operation-status") {
|
|
42
49
|
const operation = operationFromEventPayload(data);
|
|
43
50
|
if (operation && (!activeTaskId || !operation.taskId || operation.taskId === activeTaskId))
|
|
@@ -81,11 +81,23 @@ export function projectDeferredTurnSummary(deferredTurn) {
|
|
|
81
81
|
blockedByTurnId: deferredTurn.blockedByTurnId,
|
|
82
82
|
state: deferredTurn.state,
|
|
83
83
|
updatedAt: deferredTurn.updatedAt,
|
|
84
|
+
text: deferredTurn.text,
|
|
84
85
|
textPreview: deferredTurn.text.replace(/\s+/g, " ").trim().slice(0, 120),
|
|
85
86
|
imageCount: deferredTurn.images.length,
|
|
87
|
+
images: structuredClone(deferredTurn.images),
|
|
86
88
|
...(deferredTurn.acceptedTurnId
|
|
87
89
|
? { acceptedTurnId: deferredTurn.acceptedTurnId }
|
|
88
90
|
: {}),
|
|
89
91
|
...(deferredTurn.lastError ? { lastError: deferredTurn.lastError } : {}),
|
|
90
92
|
};
|
|
91
93
|
}
|
|
94
|
+
export function parseDeferredTurns(value) {
|
|
95
|
+
if (!Array.isArray(value))
|
|
96
|
+
return [];
|
|
97
|
+
return value
|
|
98
|
+
.map((item) => parseDeferredTurn(item))
|
|
99
|
+
.filter((item) => item !== undefined);
|
|
100
|
+
}
|
|
101
|
+
export function projectDeferredTurnSummaries(deferredTurns) {
|
|
102
|
+
return deferredTurns.map((item) => projectDeferredTurnSummary(item));
|
|
103
|
+
}
|