@stigmer/runner 3.15.0 → 3.15.2-dev.20260913223433
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/README.md +2 -4
- package/dist/.build-fingerprint +1 -1
- package/dist/__test-utils__/execution-record-fixture.d.ts +14 -0
- package/dist/__test-utils__/execution-record-fixture.js +4 -0
- package/dist/__test-utils__/execution-record-fixture.js.map +1 -1
- package/dist/__test-utils__/file-review-projection.d.ts +40 -0
- package/dist/__test-utils__/file-review-projection.js +136 -0
- package/dist/__test-utils__/file-review-projection.js.map +1 -0
- package/dist/__test-utils__/harness-contract/types.d.ts +23 -1
- package/dist/__test-utils__/harness-contract/types.js +15 -0
- package/dist/__test-utils__/harness-contract/types.js.map +1 -1
- package/dist/__test-utils__/hermetic-activity.d.ts +44 -12
- package/dist/__test-utils__/hermetic-activity.js +52 -14
- package/dist/__test-utils__/hermetic-activity.js.map +1 -1
- package/dist/__test-utils__/model-registry-fixture.d.ts +32 -7
- package/dist/__test-utils__/model-registry-fixture.js +31 -7
- package/dist/__test-utils__/model-registry-fixture.js.map +1 -1
- package/dist/__test-utils__/turn-input-fixture.d.ts +1 -1
- package/dist/__test-utils__/turn-input-fixture.js +1 -1
- package/dist/__test-utils__/turn-input-fixture.js.map +1 -1
- package/dist/activities/call-agent.js +2 -2
- package/dist/activities/call-agent.js.map +1 -1
- package/dist/activities/execute-cursor/__test-utils__/contract-subject.js +45 -3
- package/dist/activities/execute-cursor/__test-utils__/contract-subject.js.map +1 -1
- package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.d.ts +0 -9
- package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.js +2 -41
- package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.js.map +1 -1
- package/dist/activities/execute-cursor/adapter.d.ts +7 -5
- package/dist/activities/execute-cursor/adapter.js +7 -5
- package/dist/activities/execute-cursor/adapter.js.map +1 -1
- package/dist/activities/execute-cursor/approval-policy.d.ts +5 -2
- package/dist/activities/execute-cursor/approval-policy.js +5 -2
- package/dist/activities/execute-cursor/approval-policy.js.map +1 -1
- package/dist/activities/execute-cursor/approval-state.d.ts +16 -8
- package/dist/activities/execute-cursor/approval-state.js +6 -3
- package/dist/activities/execute-cursor/approval-state.js.map +1 -1
- package/dist/activities/execute-cursor/cas-observations.d.ts +14 -2
- package/dist/activities/execute-cursor/cas-observations.js +19 -2
- package/dist/activities/execute-cursor/cas-observations.js.map +1 -1
- package/dist/activities/execute-cursor/cursor-capabilities.d.ts +8 -4
- package/dist/activities/execute-cursor/cursor-capabilities.js +21 -4
- package/dist/activities/execute-cursor/cursor-capabilities.js.map +1 -1
- package/dist/activities/execute-cursor/message-translator.d.ts +12 -20
- package/dist/activities/execute-cursor/message-translator.js +19 -32
- package/dist/activities/execute-cursor/message-translator.js.map +1 -1
- package/dist/activities/execute-cursor/prompt-builder.d.ts +48 -58
- package/dist/activities/execute-cursor/prompt-builder.js +76 -95
- package/dist/activities/execute-cursor/prompt-builder.js.map +1 -1
- package/dist/activities/execute-cursor/turn-boundary.d.ts +27 -55
- package/dist/activities/execute-cursor/turn-boundary.js +30 -90
- package/dist/activities/execute-cursor/turn-boundary.js.map +1 -1
- package/dist/activities/execute-cursor/turn-settle.d.ts +11 -7
- package/dist/activities/execute-cursor/turn-settle.js +37 -49
- package/dist/activities/execute-cursor/turn-settle.js.map +1 -1
- package/dist/activities/execute-cursor/turn-setup.d.ts +16 -24
- package/dist/activities/execute-cursor/turn-setup.js +29 -59
- package/dist/activities/execute-cursor/turn-setup.js.map +1 -1
- package/dist/activities/execute-cursor/turn-stream.d.ts +3 -8
- package/dist/activities/execute-cursor/turn-stream.js +9 -22
- package/dist/activities/execute-cursor/turn-stream.js.map +1 -1
- package/dist/activities/execute-cursor/turn.js +5 -1
- package/dist/activities/execute-cursor/turn.js.map +1 -1
- package/dist/activities/execute-deep-agent/__test-utils__/contract-subject.d.ts +93 -0
- package/dist/activities/execute-deep-agent/__test-utils__/contract-subject.js +348 -0
- package/dist/activities/execute-deep-agent/__test-utils__/contract-subject.js.map +1 -0
- package/dist/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.d.ts +170 -0
- package/dist/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.js +225 -0
- package/dist/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.js.map +1 -0
- package/dist/activities/execute-deep-agent/__test-utils__/hitl-script.d.ts +24 -0
- package/dist/activities/execute-deep-agent/__test-utils__/hitl-script.js +41 -0
- package/dist/activities/execute-deep-agent/__test-utils__/hitl-script.js.map +1 -0
- package/dist/activities/execute-deep-agent/__test-utils__/scripted-model-module.d.ts +54 -0
- package/dist/activities/execute-deep-agent/__test-utils__/scripted-model-module.js +72 -0
- package/dist/activities/execute-deep-agent/__test-utils__/scripted-model-module.js.map +1 -0
- package/dist/activities/execute-deep-agent/__test-utils__/scripted-model.d.ts +187 -23
- package/dist/activities/execute-deep-agent/__test-utils__/scripted-model.js +238 -27
- package/dist/activities/execute-deep-agent/__test-utils__/scripted-model.js.map +1 -1
- package/dist/activities/execute-deep-agent/adapter.d.ts +41 -0
- package/dist/activities/execute-deep-agent/adapter.js +78 -0
- package/dist/activities/execute-deep-agent/adapter.js.map +1 -0
- package/dist/activities/execute-deep-agent/cas-capture-observer.d.ts +8 -0
- package/dist/activities/execute-deep-agent/cas-capture-observer.js +9 -0
- package/dist/activities/execute-deep-agent/cas-capture-observer.js.map +1 -1
- package/dist/activities/execute-deep-agent/deep-agent-capabilities.d.ts +31 -0
- package/dist/activities/execute-deep-agent/deep-agent-capabilities.js +40 -0
- package/dist/activities/execute-deep-agent/deep-agent-capabilities.js.map +1 -0
- package/dist/activities/execute-deep-agent/execution-state.d.ts +4 -11
- package/dist/activities/execute-deep-agent/execution-state.js +4 -12
- package/dist/activities/execute-deep-agent/execution-state.js.map +1 -1
- package/dist/activities/execute-deep-agent/hitl.d.ts +49 -47
- package/dist/activities/execute-deep-agent/hitl.js +77 -103
- package/dist/activities/execute-deep-agent/hitl.js.map +1 -1
- package/dist/activities/execute-deep-agent/prompt-builder.d.ts +51 -23
- package/dist/activities/execute-deep-agent/prompt-builder.js +115 -76
- package/dist/activities/execute-deep-agent/prompt-builder.js.map +1 -1
- package/dist/activities/execute-deep-agent/status-builder-shared.d.ts +18 -32
- package/dist/activities/execute-deep-agent/status-builder-shared.js +10 -65
- package/dist/activities/execute-deep-agent/status-builder-shared.js.map +1 -1
- package/dist/activities/execute-deep-agent/streaming-side-effects.d.ts +10 -8
- package/dist/activities/execute-deep-agent/streaming-side-effects.js +12 -14
- package/dist/activities/execute-deep-agent/streaming-side-effects.js.map +1 -1
- package/dist/activities/execute-deep-agent/subagent-tracker.d.ts +36 -13
- package/dist/activities/execute-deep-agent/subagent-tracker.js +76 -39
- package/dist/activities/execute-deep-agent/subagent-tracker.js.map +1 -1
- package/dist/activities/execute-deep-agent/subagent-transformer.d.ts +25 -28
- package/dist/activities/execute-deep-agent/subagent-transformer.js +29 -82
- package/dist/activities/execute-deep-agent/subagent-transformer.js.map +1 -1
- package/dist/activities/execute-deep-agent/subagent-wiring.d.ts +3 -2
- package/dist/activities/execute-deep-agent/subagent-wiring.js +2 -2
- package/dist/activities/execute-deep-agent/subagent-wiring.js.map +1 -1
- package/dist/activities/execute-deep-agent/turn-settle.d.ts +42 -0
- package/dist/activities/execute-deep-agent/turn-settle.js +146 -0
- package/dist/activities/execute-deep-agent/turn-settle.js.map +1 -0
- package/dist/activities/execute-deep-agent/turn-setup.d.ts +212 -0
- package/dist/activities/execute-deep-agent/turn-setup.js +430 -0
- package/dist/activities/execute-deep-agent/turn-setup.js.map +1 -0
- package/dist/activities/execute-deep-agent/turn-stream.d.ts +97 -0
- package/dist/activities/execute-deep-agent/turn-stream.js +242 -0
- package/dist/activities/execute-deep-agent/turn-stream.js.map +1 -0
- package/dist/activities/execute-deep-agent/turn.d.ts +42 -0
- package/dist/activities/execute-deep-agent/turn.js +116 -0
- package/dist/activities/execute-deep-agent/turn.js.map +1 -0
- package/dist/activities/execute-deep-agent/v3-event-recorder.d.ts +6 -5
- package/dist/activities/execute-deep-agent/v3-event-recorder.js +6 -5
- package/dist/activities/execute-deep-agent/v3-event-recorder.js.map +1 -1
- package/dist/activities/execute-deep-agent/v3-events.d.ts +1 -1
- package/dist/activities/execute-deep-agent/v3-events.js +1 -1
- package/dist/activities/execute-deep-agent/v3-status-builder.d.ts +60 -17
- package/dist/activities/execute-deep-agent/v3-status-builder.js +72 -57
- package/dist/activities/execute-deep-agent/v3-status-builder.js.map +1 -1
- package/dist/harness/approval-decisions.d.ts +61 -0
- package/dist/harness/approval-decisions.js +102 -0
- package/dist/harness/approval-decisions.js.map +1 -0
- package/dist/harness/capabilities.d.ts +16 -5
- package/dist/harness/capabilities.js +9 -0
- package/dist/harness/capabilities.js.map +1 -1
- package/dist/harness/capture.d.ts +144 -0
- package/dist/harness/capture.js +219 -0
- package/dist/harness/capture.js.map +1 -0
- package/dist/harness/persist-chokepoint.d.ts +19 -4
- package/dist/harness/persist-chokepoint.js +17 -4
- package/dist/harness/persist-chokepoint.js.map +1 -1
- package/dist/harness/run-turn.js +115 -29
- package/dist/harness/run-turn.js.map +1 -1
- package/dist/harness/terminal-table.d.ts +40 -11
- package/dist/harness/terminal-table.js +58 -19
- package/dist/harness/terminal-table.js.map +1 -1
- package/dist/harness/turn-context.d.ts +141 -76
- package/dist/harness/turn-context.js +194 -99
- package/dist/harness/turn-context.js.map +1 -1
- package/dist/harness/types.d.ts +65 -12
- package/dist/harness/types.js +8 -2
- package/dist/harness/types.js.map +1 -1
- package/dist/harness-adapters.d.ts +12 -8
- package/dist/harness-adapters.js +17 -9
- package/dist/harness-adapters.js.map +1 -1
- package/dist/middleware/approval-gate.d.ts +1 -1
- package/dist/middleware/approval-gate.js +1 -1
- package/dist/middleware/approval-gate.js.map +1 -1
- package/dist/middleware/cost-advisory.d.ts +39 -0
- package/dist/middleware/{cost-cap.js → cost-advisory.js} +37 -55
- package/dist/middleware/cost-advisory.js.map +1 -0
- package/dist/middleware/index.d.ts +23 -12
- package/dist/middleware/index.js +26 -18
- package/dist/middleware/index.js.map +1 -1
- package/dist/middleware/types.d.ts +3 -2
- package/dist/runner-manager.js +1 -5
- package/dist/runner-manager.js.map +1 -1
- package/dist/runner.js +1 -5
- package/dist/runner.js.map +1 -1
- package/dist/shared/attachment-resolver.d.ts +41 -18
- package/dist/shared/attachment-resolver.js +178 -46
- package/dist/shared/attachment-resolver.js.map +1 -1
- package/dist/shared/attachment-zip.d.ts +85 -0
- package/dist/shared/attachment-zip.js +185 -0
- package/dist/shared/attachment-zip.js.map +1 -0
- package/dist/shared/connect-backfill.js +5 -4
- package/dist/shared/connect-backfill.js.map +1 -1
- package/dist/shared/cost-guard.d.ts +3 -3
- package/dist/shared/cost-guard.js +3 -3
- package/dist/shared/execution-status-writer.d.ts +5 -5
- package/dist/shared/execution-status-writer.js +5 -5
- package/dist/shared/extract-structured-output.d.ts +8 -7
- package/dist/shared/extract-structured-output.js +8 -7
- package/dist/shared/extract-structured-output.js.map +1 -1
- package/dist/shared/filereview/cas-progress.d.ts +1 -18
- package/dist/shared/filereview/cas-progress.js +4 -0
- package/dist/shared/filereview/cas-progress.js.map +1 -1
- package/dist/shared/filereview/cas-touched.d.ts +56 -0
- package/dist/shared/filereview/cas-touched.js +63 -0
- package/dist/shared/filereview/cas-touched.js.map +1 -0
- package/dist/shared/filereview/index.d.ts +2 -1
- package/dist/shared/filereview/index.js +2 -1
- package/dist/shared/filereview/index.js.map +1 -1
- package/dist/shared/mcp-resolver.d.ts +4 -5
- package/dist/shared/mcp-resolver.js +4 -5
- package/dist/shared/mcp-resolver.js.map +1 -1
- package/dist/shared/persist-decision.d.ts +3 -4
- package/dist/shared/persist-decision.js +3 -4
- package/dist/shared/persist-decision.js.map +1 -1
- package/dist/shared/plan-mode-permissions.d.ts +2 -2
- package/dist/shared/plan-mode-permissions.js +2 -2
- package/dist/shared/plan-mode-prompt.d.ts +1 -1
- package/dist/shared/plan-mode-prompt.js +1 -1
- package/dist/shared/prompt-sections.d.ts +163 -0
- package/dist/shared/prompt-sections.js +164 -0
- package/dist/shared/prompt-sections.js.map +1 -0
- package/dist/shared/skill-resolver.d.ts +4 -2
- package/dist/shared/skill-resolver.js +4 -2
- package/dist/shared/skill-resolver.js.map +1 -1
- package/dist/shared/tool-rounds.d.ts +32 -0
- package/dist/shared/tool-rounds.js +43 -0
- package/dist/shared/tool-rounds.js.map +1 -1
- package/dist/shared/tool-row.d.ts +34 -0
- package/dist/shared/tool-row.js +52 -0
- package/dist/shared/tool-row.js.map +1 -1
- package/dist/shared/workspace/session-provision.d.ts +3 -3
- package/dist/shared/workspace/session-provision.js +3 -3
- package/dist/shared/workspace/stigmer-link.d.ts +3 -3
- package/dist/shared/workspace/stigmer-link.js +3 -3
- package/dist/shared/workspace/writeback-coordinator.d.ts +15 -22
- package/dist/shared/workspace/writeback-coordinator.js +16 -53
- package/dist/shared/workspace/writeback-coordinator.js.map +1 -1
- package/dist/tools/index.d.ts +1 -1
- package/dist/tools/index.js +1 -1
- package/package.json +4 -4
- package/src/__test-utils__/__tests__/harness-contract-self-check.test.ts +1 -0
- package/src/__test-utils__/execution-record-fixture.ts +18 -2
- package/src/__test-utils__/file-review-projection.ts +156 -0
- package/src/__test-utils__/git-workspace-fixture.ts +58 -0
- package/src/__test-utils__/harness-boot-order-child.ts +7 -2
- package/src/__test-utils__/harness-contract/contract.ts +33 -20
- package/src/__test-utils__/harness-contract/recording-sink.ts +11 -1
- package/src/__test-utils__/harness-contract/runtime-contract.ts +328 -10
- package/src/__test-utils__/harness-contract/scripted-adapter.ts +38 -6
- package/src/__test-utils__/harness-contract/types.ts +27 -3
- package/src/__test-utils__/hermetic-activity.ts +52 -14
- package/src/__test-utils__/model-registry-fixture.ts +32 -7
- package/src/__test-utils__/module-specifiers.ts +24 -0
- package/src/__test-utils__/turn-input-fixture.ts +2 -2
- package/src/__tests__/harness-boot-order.test.ts +9 -2
- package/src/activities/call-agent.ts +2 -2
- package/src/activities/execute-cursor/__test-utils__/contract-subject.ts +47 -3
- package/src/activities/execute-cursor/__test-utils__/hermetic-cursor.ts +2 -48
- package/src/activities/execute-cursor/__tests__/approval-decisions-agree.test.ts +1 -1
- package/src/activities/execute-cursor/__tests__/approval-gate.test.ts +6 -1
- package/src/activities/execute-cursor/__tests__/build-prompt.test.ts +52 -27
- package/src/activities/execute-cursor/__tests__/cas-observations.test.ts +25 -0
- package/src/activities/execute-cursor/__tests__/goldens/prompt.enhanced.everything.prompt.md +166 -0
- package/src/activities/execute-cursor/__tests__/goldens/prompt.enhanced.plan-mode.prompt.md +186 -0
- package/src/activities/execute-cursor/__tests__/goldens/prompt.hitl.recovery.prompt.md +191 -0
- package/src/activities/execute-cursor/__tests__/goldens/prompt.hitl.reinvocation.prompt.md +13 -0
- package/src/activities/execute-cursor/__tests__/goldens/prompt.resumed.prefixed.prompt.md +32 -0
- package/src/activities/execute-cursor/__tests__/goldens/prompt.resumed.raw.prompt.md +1 -0
- package/src/activities/execute-cursor/__tests__/hermetic/file-review-capture.test.ts +1 -2
- package/src/activities/execute-cursor/__tests__/hermetic/goldens/sdk-error-at-create.status.json +4 -0
- package/src/activities/execute-cursor/__tests__/hermetic/harness-contract.test.ts +24 -4
- package/src/activities/execute-cursor/__tests__/hermetic/stream-self-stop-arms.test.ts +6 -5
- package/src/activities/execute-cursor/__tests__/hermetic/thrown-error-arms.test.ts +9 -0
- package/src/activities/execute-cursor/__tests__/hitl-resume-history.test.ts +11 -8
- package/src/activities/execute-cursor/__tests__/prompt-goldens.test.ts +229 -0
- package/src/activities/execute-cursor/__tests__/same-identity-reproposal.test.ts +3 -3
- package/src/activities/execute-cursor/__tests__/sequential-gate-resume.test.ts +2 -2
- package/src/activities/execute-cursor/__tests__/turn-boundary.test.ts +78 -234
- package/src/activities/execute-cursor/__tests__/turn-stream.test.ts +1 -26
- package/src/activities/execute-cursor/adapter.ts +7 -5
- package/src/activities/execute-cursor/approval-policy.ts +5 -2
- package/src/activities/execute-cursor/approval-state.ts +16 -8
- package/src/activities/execute-cursor/cas-observations.ts +20 -2
- package/src/activities/execute-cursor/cursor-capabilities.ts +24 -5
- package/src/activities/execute-cursor/message-translator.ts +29 -41
- package/src/activities/execute-cursor/prompt-builder.ts +99 -157
- package/src/activities/execute-cursor/turn-boundary.ts +34 -140
- package/src/activities/execute-cursor/turn-settle.ts +37 -51
- package/src/activities/execute-cursor/turn-setup.ts +30 -70
- package/src/activities/execute-cursor/turn-stream.ts +8 -31
- package/src/activities/execute-cursor/turn.ts +5 -1
- package/src/activities/execute-deep-agent/__test-utils__/contract-subject.ts +391 -0
- package/src/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.ts +313 -0
- package/src/activities/execute-deep-agent/__test-utils__/hitl-script.ts +48 -0
- package/src/activities/execute-deep-agent/__test-utils__/scripted-model-module.ts +85 -0
- package/src/activities/execute-deep-agent/__test-utils__/scripted-model.ts +383 -36
- package/src/activities/execute-deep-agent/__tests__/adapter-graph-is-sdk-free.test.ts +76 -0
- package/src/activities/execute-deep-agent/__tests__/adapter-is-temporal-free.test.ts +47 -0
- package/src/activities/execute-deep-agent/__tests__/adapter.test.ts +80 -0
- package/src/activities/execute-deep-agent/__tests__/cas-capture-backend.test.ts +1 -1
- package/src/activities/execute-deep-agent/__tests__/execution-state-extended.test.ts +0 -2
- package/src/activities/execute-deep-agent/__tests__/execution-state.test.ts +0 -3
- package/src/activities/execute-deep-agent/__tests__/goldens/system-prompt.build-from-plan.prompt.md +172 -0
- package/src/activities/execute-deep-agent/__tests__/goldens/system-prompt.everything.prompt.md +167 -0
- package/src/activities/execute-deep-agent/__tests__/goldens/system-prompt.minimal.prompt.md +36 -0
- package/src/activities/execute-deep-agent/__tests__/goldens/system-prompt.plan-mode.prompt.md +178 -0
- package/src/activities/execute-deep-agent/__tests__/goldens/system-prompt.skills-below-threshold.prompt.md +158 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/file-review-capture.test.ts +210 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/approve-all-lease.turn1.status.json +74 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/approve-all-lease.turn2.status.json +104 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/approve.turn2.status.json +78 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/file-review-capture.status.json +138 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/gate.turn1.status.json +68 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/inline-artifact.turn1.status.json +154 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/inline-artifact.turn2.status.json +116 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/pause.loop.after-tool.status.json +69 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/pause.loop.mid-tool.status.json +67 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/plain-turn.status.json +47 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/platform-stop.status.json +68 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/recursion-limit.persisted.status.json +280 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/reject.turn2.status.json +77 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/resolution-error.status.json +18 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/sequential-gates.turn2.status.json +99 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/sequential-gates.turn3.status.json +109 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/skip.turn2.status.json +76 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/structured-output.text-fallback.status.json +51 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/structured-output.tier2.status.json +51 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/structured-output.tool-strategy.status.json +56 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/sub-agent-delegation.status.json +90 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/tool-call.status.json +70 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/worker-shutdown.status.json +71 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/harness-contract.test.ts +144 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/hitl-approve-all-lease.test.ts +184 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/hitl-round-trips.test.ts +203 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/hitl-sequential-gates.test.ts +170 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/inline-artifact-across-gate.test.ts +175 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/pause-vs-shutdown.test.ts +206 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/plain-turn.test.ts +142 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/platform-stop.test.ts +126 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/recursion-limit.test.ts +139 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/resolution-error.test.ts +122 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/structured-output.test.ts +236 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/sub-agent-delegation.test.ts +161 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/tool-call.test.ts +157 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/workspace-lock-timeout.test.ts +152 -0
- package/src/activities/execute-deep-agent/__tests__/hitl.test.ts +50 -122
- package/src/activities/execute-deep-agent/__tests__/inline-publisher.test.ts +8 -6
- package/src/activities/execute-deep-agent/__tests__/plan-mode-path-normalization.test.ts +2 -2
- package/src/activities/execute-deep-agent/__tests__/prompt-builder.test.ts +35 -35
- package/src/activities/execute-deep-agent/__tests__/prompt-goldens.test.ts +247 -0
- package/src/activities/execute-deep-agent/__tests__/scripted-model.test.ts +329 -0
- package/src/activities/execute-deep-agent/__tests__/status-builder-shared.test.ts +1 -20
- package/src/activities/execute-deep-agent/__tests__/streaming-side-effects.test.ts +78 -0
- package/src/activities/execute-deep-agent/__tests__/subagent-gitignored-capture.test.ts +1 -1
- package/src/activities/execute-deep-agent/__tests__/subagent-plan-mode-permissions.test.ts +2 -2
- package/src/activities/execute-deep-agent/__tests__/subagent-tracker.test.ts +57 -31
- package/src/activities/execute-deep-agent/__tests__/subagent-transformer.test.ts +19 -79
- package/src/activities/execute-deep-agent/__tests__/subagent-wiring.test.ts +15 -15
- package/src/activities/execute-deep-agent/__tests__/summarization-verification.test.ts +1 -1
- package/src/activities/execute-deep-agent/__tests__/turn-stream.test.ts +391 -0
- package/src/activities/execute-deep-agent/__tests__/v3-status-builder.test.ts +343 -38
- package/src/activities/execute-deep-agent/__tests__/vision-input.test.ts +5 -5
- package/src/activities/execute-deep-agent/adapter.ts +94 -0
- package/src/activities/execute-deep-agent/cas-capture-observer.ts +11 -0
- package/src/activities/execute-deep-agent/deep-agent-capabilities.ts +43 -0
- package/src/activities/execute-deep-agent/execution-state.ts +4 -13
- package/src/activities/execute-deep-agent/hitl.ts +100 -123
- package/src/activities/execute-deep-agent/prompt-builder.ts +141 -115
- package/src/activities/execute-deep-agent/status-builder-shared.ts +21 -84
- package/src/activities/execute-deep-agent/streaming-side-effects.ts +13 -19
- package/src/activities/execute-deep-agent/subagent-tracker.ts +77 -42
- package/src/activities/execute-deep-agent/subagent-transformer.ts +46 -105
- package/src/activities/execute-deep-agent/subagent-wiring.ts +5 -4
- package/src/activities/execute-deep-agent/turn-settle.ts +164 -0
- package/src/activities/execute-deep-agent/turn-setup.ts +541 -0
- package/src/activities/execute-deep-agent/turn-stream.ts +313 -0
- package/src/activities/execute-deep-agent/turn.ts +131 -0
- package/src/activities/execute-deep-agent/v3-event-recorder.ts +6 -5
- package/src/activities/execute-deep-agent/v3-events.ts +1 -1
- package/src/activities/execute-deep-agent/v3-status-builder.ts +84 -63
- package/src/harness/__tests__/approval-decisions.test.ts +116 -0
- package/src/harness/__tests__/capture.test.ts +268 -0
- package/src/harness/__tests__/mount-skills.test.ts +169 -0
- package/src/harness/__tests__/persist-chokepoint.test.ts +38 -2
- package/src/harness/__tests__/run-turn-deterministic.test.ts +94 -0
- package/src/harness/__tests__/run-turn.test.ts +39 -23
- package/src/harness/__tests__/turn-attachments-vision.test.ts +80 -0
- package/src/harness/__tests__/turn-context.test.ts +73 -26
- package/src/harness/approval-decisions.ts +104 -0
- package/src/harness/capabilities.ts +16 -5
- package/src/harness/capture.ts +301 -0
- package/src/harness/persist-chokepoint.ts +24 -4
- package/src/harness/run-turn.ts +120 -29
- package/src/harness/terminal-table.ts +61 -20
- package/src/harness/turn-context.ts +208 -111
- package/src/harness/types.ts +66 -12
- package/src/harness-adapters.ts +17 -9
- package/src/middleware/__tests__/approval-gate.test.ts +1 -1
- package/src/middleware/__tests__/cost-advisory.test.ts +113 -0
- package/src/middleware/approval-gate.ts +2 -2
- package/src/middleware/{cost-cap.ts → cost-advisory.ts} +40 -70
- package/src/middleware/index.ts +29 -29
- package/src/middleware/types.ts +3 -2
- package/src/runner-manager.ts +0 -8
- package/src/runner.ts +0 -8
- package/src/shared/__tests__/attachment-naming.test.ts +6 -19
- package/src/shared/__tests__/attachment-resolver.test.ts +158 -8
- package/src/shared/__tests__/attachment-zip.test.ts +236 -0
- package/src/shared/__tests__/bedrock-adapter.test.ts +1 -1
- package/src/shared/__tests__/blueprint-resolver.test.ts +43 -0
- package/src/shared/__tests__/cost-guard.test.ts +3 -3
- package/src/shared/__tests__/prompt-sections.test.ts +167 -0
- package/src/shared/__tests__/secret-leak-scan.test.ts +2 -2
- package/src/{activities/execute-deep-agent → shared}/__tests__/stamp-flowed-rows.test.ts +33 -10
- package/src/shared/__tests__/vertex-adapter.test.ts +1 -1
- package/src/shared/attachment-resolver.ts +218 -55
- package/src/shared/attachment-zip.ts +281 -0
- package/src/shared/connect-backfill.ts +9 -11
- package/src/shared/cost-guard.ts +3 -3
- package/src/shared/execution-status-writer.ts +5 -5
- package/src/shared/extract-structured-output.ts +8 -7
- package/src/shared/filereview/__tests__/capture.test.ts +86 -4
- package/src/shared/filereview/__tests__/cas-progress.test.ts +2 -1
- package/src/shared/filereview/cas-progress.ts +5 -19
- package/src/shared/filereview/cas-touched.ts +89 -0
- package/src/shared/filereview/index.ts +4 -2
- package/src/shared/mcp-resolver.ts +4 -5
- package/src/shared/persist-decision.ts +3 -4
- package/src/shared/plan-mode-permissions.ts +2 -2
- package/src/shared/plan-mode-prompt.ts +1 -1
- package/src/shared/prompt-sections.ts +256 -0
- package/src/shared/skill-resolver.ts +4 -2
- package/src/shared/tool-rounds.ts +48 -0
- package/src/shared/tool-row.ts +61 -0
- package/src/shared/workspace/__tests__/stigmer-link.test.ts +7 -22
- package/src/shared/workspace/__tests__/writeback-coordinator.test.ts +20 -61
- package/src/shared/workspace/session-provision.ts +3 -3
- package/src/shared/workspace/stigmer-link.ts +3 -3
- package/src/shared/workspace/writeback-coordinator.ts +16 -64
- package/src/tools/index.ts +1 -1
- package/dist/activities/execute-cursor/capture-flow.d.ts +0 -142
- package/dist/activities/execute-cursor/capture-flow.js +0 -285
- package/dist/activities/execute-cursor/capture-flow.js.map +0 -1
- package/dist/activities/execute-cursor/command-provenance.d.ts +0 -48
- package/dist/activities/execute-cursor/command-provenance.js +0 -38
- package/dist/activities/execute-cursor/command-provenance.js.map +0 -1
- package/dist/activities/execute-deep-agent/attachment-injector.d.ts +0 -134
- package/dist/activities/execute-deep-agent/attachment-injector.js +0 -386
- package/dist/activities/execute-deep-agent/attachment-injector.js.map +0 -1
- package/dist/activities/execute-deep-agent/command-provenance.d.ts +0 -61
- package/dist/activities/execute-deep-agent/command-provenance.js +0 -72
- package/dist/activities/execute-deep-agent/command-provenance.js.map +0 -1
- package/dist/activities/execute-deep-agent/environment.d.ts +0 -24
- package/dist/activities/execute-deep-agent/environment.js +0 -58
- package/dist/activities/execute-deep-agent/environment.js.map +0 -1
- package/dist/activities/execute-deep-agent/event-recorder.d.ts +0 -21
- package/dist/activities/execute-deep-agent/event-recorder.js +0 -67
- package/dist/activities/execute-deep-agent/event-recorder.js.map +0 -1
- package/dist/activities/execute-deep-agent/index.d.ts +0 -15
- package/dist/activities/execute-deep-agent/index.js +0 -918
- package/dist/activities/execute-deep-agent/index.js.map +0 -1
- package/dist/activities/execute-deep-agent/mcp-gate.d.ts +0 -28
- package/dist/activities/execute-deep-agent/mcp-gate.js +0 -22
- package/dist/activities/execute-deep-agent/mcp-gate.js.map +0 -1
- package/dist/activities/execute-deep-agent/post-stream.d.ts +0 -23
- package/dist/activities/execute-deep-agent/post-stream.js +0 -71
- package/dist/activities/execute-deep-agent/post-stream.js.map +0 -1
- package/dist/activities/execute-deep-agent/setup.d.ts +0 -136
- package/dist/activities/execute-deep-agent/setup.js +0 -767
- package/dist/activities/execute-deep-agent/setup.js.map +0 -1
- package/dist/activities/execute-deep-agent/stamp-flowed-rows.d.ts +0 -36
- package/dist/activities/execute-deep-agent/stamp-flowed-rows.js +0 -56
- package/dist/activities/execute-deep-agent/stamp-flowed-rows.js.map +0 -1
- package/dist/activities/execute-deep-agent/status-builder.d.ts +0 -93
- package/dist/activities/execute-deep-agent/status-builder.js +0 -365
- package/dist/activities/execute-deep-agent/status-builder.js.map +0 -1
- package/dist/activities/execute-deep-agent/streaming-terminal.d.ts +0 -21
- package/dist/activities/execute-deep-agent/streaming-terminal.js +0 -80
- package/dist/activities/execute-deep-agent/streaming-terminal.js.map +0 -1
- package/dist/activities/execute-deep-agent/streaming-v3.d.ts +0 -13
- package/dist/activities/execute-deep-agent/streaming-v3.js +0 -174
- package/dist/activities/execute-deep-agent/streaming-v3.js.map +0 -1
- package/dist/activities/execute-deep-agent/streaming.d.ts +0 -81
- package/dist/activities/execute-deep-agent/streaming.js +0 -160
- package/dist/activities/execute-deep-agent/streaming.js.map +0 -1
- package/dist/middleware/cost-cap.d.ts +0 -22
- package/dist/middleware/cost-cap.js.map +0 -1
- package/dist/middleware/graceful-stop.d.ts +0 -17
- package/dist/middleware/graceful-stop.js +0 -63
- package/dist/middleware/graceful-stop.js.map +0 -1
- package/dist/shared/skill-writer.d.ts +0 -75
- package/dist/shared/skill-writer.js +0 -207
- package/dist/shared/skill-writer.js.map +0 -1
- package/src/activities/execute-cursor/__tests__/capture-flow.test.ts +0 -1032
- package/src/activities/execute-cursor/__tests__/command-provenance.test.ts +0 -240
- package/src/activities/execute-cursor/__tests__/progress-substrate.test.ts +0 -169
- package/src/activities/execute-cursor/capture-flow.ts +0 -379
- package/src/activities/execute-cursor/command-provenance.ts +0 -73
- package/src/activities/execute-deep-agent/__tests__/attachment-injector.test.ts +0 -1161
- package/src/activities/execute-deep-agent/__tests__/command-provenance.test.ts +0 -252
- package/src/activities/execute-deep-agent/__tests__/environment.test.ts +0 -108
- package/src/activities/execute-deep-agent/__tests__/event-recorder.test.ts +0 -150
- package/src/activities/execute-deep-agent/__tests__/hitl-integration.test.ts +0 -226
- package/src/activities/execute-deep-agent/__tests__/hitl-reject.test.ts +0 -318
- package/src/activities/execute-deep-agent/__tests__/hitl-resume-approve-all.test.ts +0 -351
- package/src/activities/execute-deep-agent/__tests__/hitl-resume-history.test.ts +0 -293
- package/src/activities/execute-deep-agent/__tests__/index.test.ts +0 -99
- package/src/activities/execute-deep-agent/__tests__/mcp-gate.test.ts +0 -44
- package/src/activities/execute-deep-agent/__tests__/post-stream.test.ts +0 -112
- package/src/activities/execute-deep-agent/__tests__/sequential-gate-resume.test.ts +0 -358
- package/src/activities/execute-deep-agent/__tests__/status-builder.test.ts +0 -1933
- package/src/activities/execute-deep-agent/__tests__/streaming-terminal.test.ts +0 -40
- package/src/activities/execute-deep-agent/__tests__/streaming-v3.test.ts +0 -597
- package/src/activities/execute-deep-agent/__tests__/streaming.test.ts +0 -508
- package/src/activities/execute-deep-agent/attachment-injector.ts +0 -627
- package/src/activities/execute-deep-agent/command-provenance.ts +0 -102
- package/src/activities/execute-deep-agent/environment.ts +0 -76
- package/src/activities/execute-deep-agent/event-recorder.ts +0 -95
- package/src/activities/execute-deep-agent/index.ts +0 -1072
- package/src/activities/execute-deep-agent/mcp-gate.ts +0 -37
- package/src/activities/execute-deep-agent/post-stream.ts +0 -109
- package/src/activities/execute-deep-agent/setup.ts +0 -1081
- package/src/activities/execute-deep-agent/stamp-flowed-rows.ts +0 -64
- package/src/activities/execute-deep-agent/status-builder.ts +0 -481
- package/src/activities/execute-deep-agent/streaming-terminal.ts +0 -106
- package/src/activities/execute-deep-agent/streaming-v3.ts +0 -277
- package/src/activities/execute-deep-agent/streaming.ts +0 -313
- package/src/middleware/__tests__/cost-cap.test.ts +0 -192
- package/src/middleware/__tests__/graceful-stop.test.ts +0 -105
- package/src/middleware/graceful-stop.ts +0 -86
- package/src/shared/__tests__/skill-writer.test.ts +0 -372
- package/src/shared/skill-writer.ts +0 -266
|
@@ -1,918 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ExecuteDeepAgent activity — runs a Stigmer deep agent via LangGraph.
|
|
3
|
-
*
|
|
4
|
-
* Signature matches ExecuteGraphton (Python): (executionId, threadId) → status.
|
|
5
|
-
* The slim-payload pattern is preserved: input is just IDs, output is a slim
|
|
6
|
-
* AgentExecutionStatus proto.
|
|
7
|
-
*
|
|
8
|
-
* Phase 3b-iii: full middleware stack + artifact storage, inline publishing,
|
|
9
|
-
* incremental git writeback, and post-stream safety net.
|
|
10
|
-
*/
|
|
11
|
-
import { readFile } from "node:fs/promises";
|
|
12
|
-
import { join } from "node:path";
|
|
13
|
-
import { Context, CancelledFailure } from "@temporalio/activity";
|
|
14
|
-
import { create, clone } from "@bufbuild/protobuf";
|
|
15
|
-
import { AgentExecutionStatusSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
|
|
16
|
-
import { AgentMessageSchema, ToolCallSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/message_pb";
|
|
17
|
-
import { ExecutionPhase, FileCaptureClass, FileChangeSetStatus, InteractionMode, MessageType, ToolCallStatus } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
|
|
18
|
-
import { activityStarted, activityFinished } from "../../idle-watchdog.js";
|
|
19
|
-
import { normalizeActivityInput } from "../../shared/activity-input.js";
|
|
20
|
-
import { persistStatus, reportSetupProgress, slimStatus, utcTimestamp } from "../../shared/status.js";
|
|
21
|
-
import { acquireWorkspaceLock, WorkspaceLockCancelledError, WorkspaceLockTimeoutError, } from "../../shared/workspace/workspace-lock.js";
|
|
22
|
-
import { ensureStigmerSymlink, removeStigmerSymlink, } from "../../shared/workspace/stigmer-link.js";
|
|
23
|
-
import { publishPlanArtifact } from "../../shared/plan-artifact.js";
|
|
24
|
-
import { classifyTool } from "../../shared/tool-kind.js";
|
|
25
|
-
import { POLICY_ENGINE_VERSION, toProtoPolicySource, } from "../../shared/approval-policy.js";
|
|
26
|
-
import { StigmerClient } from "../../client/stigmer-client.js";
|
|
27
|
-
import { performSetup } from "./setup.js";
|
|
28
|
-
import { streamExecution } from "./streaming.js";
|
|
29
|
-
import { loadStreamingConfig } from "../../shared/streaming-scheduler.js";
|
|
30
|
-
import { StatusBuilder } from "./status-builder.js";
|
|
31
|
-
import { InlinePublisher } from "./inline-publisher.js";
|
|
32
|
-
import { WriteBackCoordinator } from "../../shared/workspace/writeback-coordinator.js";
|
|
33
|
-
import { processPostStream } from "./post-stream.js";
|
|
34
|
-
import { resolveResumeInput, reconcileNonExecutingDecisions, reconcileUnattendedSkips } from "./hitl.js";
|
|
35
|
-
import { captureApprovalArtifacts } from "./approval-file-change.js";
|
|
36
|
-
import { applyCaptureDecisions, captureBaselineToLedger, captureCandidateToLedger, } from "../../shared/filereview/capture.js";
|
|
37
|
-
import { captureFileChangeProgress, createGitProgressSubstrate, createHybridProgressSubstrate, newProgressCaptureState, } from "../../shared/filereview/progress.js";
|
|
38
|
-
import { createCasProgressSubstrate, } from "../../shared/filereview/cas-progress.js";
|
|
39
|
-
import { hasCandidateCaptured } from "../../shared/filereview/events.js";
|
|
40
|
-
import { casBlobReader } from "../../shared/filereview/cas-substrate.js";
|
|
41
|
-
import { partitionIgnoredPathsBySecret } from "../../shared/filereview/secret-paths.js";
|
|
42
|
-
import { collectSettledToolCallIds, collectSubAgentToolCallIds, withholdSecretContentFromMessages, } from "../../shared/tool-row.js";
|
|
43
|
-
import { stampFlowedFileEditRows, stampFlowedSubAgentFileEditRows } from "./stamp-flowed-rows.js";
|
|
44
|
-
import { deriveTurnCommandProvenance } from "./command-provenance.js";
|
|
45
|
-
import { describeExecutionError } from "../../shared/model-error.js";
|
|
46
|
-
import { inferProvider } from "../../shared/llm-proxy.js";
|
|
47
|
-
import { getShutdownSignalForQueue } from "../../shared/worker-shutdown.js";
|
|
48
|
-
/** The harness id stamped on the deep-agent's file-review ledger events. */
|
|
49
|
-
const DEEP_AGENT_HARNESS_ID = "deep-agent";
|
|
50
|
-
/**
|
|
51
|
-
* The worker-shutdown terminal status (#776). A shutdown is not a pause: the
|
|
52
|
-
* execution will not resume on this worker, so persisting PAUSED would strand
|
|
53
|
-
* the user with a lie. The copy is byte-identical to the Cursor harness's
|
|
54
|
-
* worker-shutdown branch so every downstream status.error consumer (the Go and
|
|
55
|
-
* Java workflow fallbacks, the cloud channel decision table) keys on ONE shape.
|
|
56
|
-
*/
|
|
57
|
-
function buildWorkerShutdownStatus() {
|
|
58
|
-
return create(AgentExecutionStatusSchema, {
|
|
59
|
-
phase: ExecutionPhase.EXECUTION_FAILED,
|
|
60
|
-
error: "Execution interrupted: runner worker was shut down. Retry or resume.",
|
|
61
|
-
completedAt: utcTimestamp(),
|
|
62
|
-
messages: [
|
|
63
|
-
create(AgentMessageSchema, {
|
|
64
|
-
type: MessageType.MESSAGE_SYSTEM,
|
|
65
|
-
content: "Execution interrupted: the runner worker was shut down while the agent was still running. You can retry or resume.",
|
|
66
|
-
timestamp: utcTimestamp(),
|
|
67
|
-
}),
|
|
68
|
-
],
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* Best-effort provider inference for error-message wording. inferProvider
|
|
73
|
-
* throws on unrecognized names; an error path must never throw over a label.
|
|
74
|
-
*/
|
|
75
|
-
function tryInferProvider(modelName) {
|
|
76
|
-
try {
|
|
77
|
-
return inferProvider(modelName);
|
|
78
|
-
}
|
|
79
|
-
catch {
|
|
80
|
-
return undefined;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
export function createDeepAgentActivities(config) {
|
|
84
|
-
const client = new StigmerClient({
|
|
85
|
-
endpoint: config.stigmerBackendEndpoint,
|
|
86
|
-
token: config.stigmerToken,
|
|
87
|
-
tokenRef: config.stigmerTokenRef,
|
|
88
|
-
runnerTokenRef: config.stigmerRunnerTokenRef,
|
|
89
|
-
});
|
|
90
|
-
const streamingConfig = loadStreamingConfig();
|
|
91
|
-
return {
|
|
92
|
-
// Accepts the new typed object OR the legacy positional args (transitional
|
|
93
|
-
// dual-shape so the runner can deploy before the control planes — see
|
|
94
|
-
// shared/activity-input.ts). Drop the positional arm once both control
|
|
95
|
-
// planes send the object.
|
|
96
|
-
ExecuteDeepAgent: async (arg0, arg1) => {
|
|
97
|
-
const { executionId, threadId, turnSeq } = normalizeActivityInput(arg0, arg1);
|
|
98
|
-
activityStarted();
|
|
99
|
-
// Worker-shutdown classification channel (#776): the pause paths below
|
|
100
|
-
// consult this signal to distinguish "my worker is draining" (SIGTERM,
|
|
101
|
-
// desktop quit) from "the orchestrator cancelled me" (a real user
|
|
102
|
-
// pause). See shared/worker-shutdown.ts for the ownership contract.
|
|
103
|
-
const shutdownSignal = getShutdownSignalForQueue(Context.current().info.taskQueue);
|
|
104
|
-
let setup = null;
|
|
105
|
-
// Exclusive turn lock on the workspace working tree — held across the
|
|
106
|
-
// entire tree-mutating window (decision reconcile, agent writes,
|
|
107
|
-
// candidate capture, write-back) and released in the finally. Mirrors
|
|
108
|
-
// the Cursor harness; see shared/workspace/workspace-lock.ts.
|
|
109
|
-
let releaseWorkspaceLock;
|
|
110
|
-
try {
|
|
111
|
-
console.log(`[ExecuteDeepAgent] Started for execution ${executionId}`);
|
|
112
|
-
setup = await performSetup({ config, client, executionId, threadId });
|
|
113
|
-
// Single offload context for every persist in this execution: spill
|
|
114
|
-
// oversized tool outputs (e.g. computer-use screenshots) to artifact
|
|
115
|
-
// storage so the UI can render them, and keep the status under the
|
|
116
|
-
// gRPC cap. Threaded into the streaming loop and reused for the
|
|
117
|
-
// terminal persists below so the guard is never skipped. Undefined when
|
|
118
|
-
// there is no artifact store (proxy misconfig): offload is then disabled,
|
|
119
|
-
// but persistStatus still enforces the aggregate size cap, so persistence
|
|
120
|
-
// can never silently blow past the gRPC limit.
|
|
121
|
-
const statusOffload = setup.artifactStorage
|
|
122
|
-
? { artifactStorage: setup.artifactStorage, executionId }
|
|
123
|
-
: undefined;
|
|
124
|
-
// Read the graph checkpoint once, to resolve how a pending approval
|
|
125
|
-
// interrupt continues (Command(resume) vs a fresh replay). Reading once
|
|
126
|
-
// avoids a redundant round-trip on the durable (http) saver.
|
|
127
|
-
const graphState = await setup.agentGraph.getState(setup.langgraphConfig);
|
|
128
|
-
// Seed from the persisted transcript whenever the execution already has
|
|
129
|
-
// committed history, so streamed deltas append onto it instead of
|
|
130
|
-
// replacing it. This holds for every re-invocation — durable resume and
|
|
131
|
-
// memory-checkpointer replay alike — and is a no-op on a first run.
|
|
132
|
-
const initialStatus = shouldSeedFromPersistedTranscript(setup.execution)
|
|
133
|
-
? seedStatusFromExecution(setup.execution)
|
|
134
|
-
: create(AgentExecutionStatusSchema, {});
|
|
135
|
-
// The semantic retriever's injection outcome (DD-008 D5), computed at
|
|
136
|
-
// prompt build in setup Step 8. Stamped here — before the first
|
|
137
|
-
// persist — because setup predates this status object; the server's
|
|
138
|
-
// presence-guarded merge preserves it across report-less writes. On a
|
|
139
|
-
// re-invocation the seeded status already carries the (replayed)
|
|
140
|
-
// report, so this stamp is idempotent by construction.
|
|
141
|
-
if (setup.recalledMemoriesReport !== undefined) {
|
|
142
|
-
initialStatus.recalledMemoriesReport = setup.recalledMemoriesReport;
|
|
143
|
-
}
|
|
144
|
-
const statusBuilder = new StatusBuilder(executionId, initialStatus);
|
|
145
|
-
statusBuilder.setApprovalProvider({
|
|
146
|
-
policies: setup.approvalPolicies,
|
|
147
|
-
toolServerMap: setup.toolServerMap,
|
|
148
|
-
leasedCategories: setup.leasedCategories,
|
|
149
|
-
globalBypass: setup.globalBypass,
|
|
150
|
-
unattended: setup.unattended,
|
|
151
|
-
});
|
|
152
|
-
const resume = resolveResumeInput(setup.execution, graphState);
|
|
153
|
-
// Not an approval resume -> setup.langgraphInput, the single
|
|
154
|
-
// construction site of the turn's user message (string or multimodal
|
|
155
|
-
// content blocks when the turn carries inline images).
|
|
156
|
-
const effectiveInput = resume.isResumeFromApproval
|
|
157
|
-
? resume.graphInput
|
|
158
|
-
: setup.langgraphInput;
|
|
159
|
-
const inlinePublisher = new InlinePublisher({
|
|
160
|
-
workspaceBackend: setup.workspaceBackend,
|
|
161
|
-
artifactStorage: setup.artifactStorage,
|
|
162
|
-
statusWriter: statusBuilder,
|
|
163
|
-
executionId,
|
|
164
|
-
});
|
|
165
|
-
const workspaceEntries = setup.session.spec?.workspaceEntries ?? [];
|
|
166
|
-
const writebackCoordinator = setup.provisionResults.length > 0
|
|
167
|
-
? new WriteBackCoordinator({
|
|
168
|
-
statusWriter: statusBuilder,
|
|
169
|
-
executionId,
|
|
170
|
-
// Branch/PR are session-scoped: every turn of this session
|
|
171
|
-
// appends commits to the same stigmer/<session-id> branch.
|
|
172
|
-
sessionId: setup.session.metadata?.id ?? "",
|
|
173
|
-
// The PR API token, plumbed from the resolved execution env —
|
|
174
|
-
// gitMetadata.repoUrl is token-stripped by construction, so the
|
|
175
|
-
// coordinator can never recover it from provisioning state.
|
|
176
|
-
githubToken: setup.mergedEnvVars.GITHUB_TOKEN ?? "",
|
|
177
|
-
provisionResults: setup.provisionResults,
|
|
178
|
-
workspaceEntries: workspaceEntries,
|
|
179
|
-
workspaceBackend: setup.workspaceBackend,
|
|
180
|
-
})
|
|
181
|
-
: null;
|
|
182
|
-
// Apply-then-review capture identity + substrate root for this turn.
|
|
183
|
-
const gitRoot = setup.workspaceBackend.rootDir;
|
|
184
|
-
const changeSetId = `${executionId}:${turnSeq}`;
|
|
185
|
-
// Serialize this turn against every other execution sharing this
|
|
186
|
-
// working tree — an unserialized concurrent write lands inside this
|
|
187
|
-
// turn's baseline→candidate window and gets misattributed to this
|
|
188
|
-
// turn's review. Acquired before ANY tree mutation below (decision
|
|
189
|
-
// reconcile, agent writes, candidate capture, write-back); waiting
|
|
190
|
-
// surfaces a visible state and heartbeats, and a cancel aborts the
|
|
191
|
-
// wait immediately. Mirrors the Cursor harness wiring exactly.
|
|
192
|
-
try {
|
|
193
|
-
releaseWorkspaceLock = await acquireWorkspaceLock(gitRoot, {
|
|
194
|
-
onWaiting: () => reportSetupProgress(client, executionId, "Waiting for workspace — in use by another session"),
|
|
195
|
-
heartbeat: () => Context.current().heartbeat(),
|
|
196
|
-
signal: Context.current().cancellationSignal,
|
|
197
|
-
timeoutMs: config.workspaceLockTimeoutMs,
|
|
198
|
-
});
|
|
199
|
-
}
|
|
200
|
-
catch (lockErr) {
|
|
201
|
-
if (lockErr instanceof WorkspaceLockCancelledError) {
|
|
202
|
-
throw new CancelledFailure("Activity cancelled while waiting for the workspace lock");
|
|
203
|
-
}
|
|
204
|
-
if (lockErr instanceof WorkspaceLockTimeoutError) {
|
|
205
|
-
const failedStatus = create(AgentExecutionStatusSchema, {
|
|
206
|
-
phase: ExecutionPhase.EXECUTION_FAILED,
|
|
207
|
-
error: lockErr.message,
|
|
208
|
-
completedAt: utcTimestamp(),
|
|
209
|
-
messages: [
|
|
210
|
-
create(AgentMessageSchema, {
|
|
211
|
-
type: MessageType.MESSAGE_SYSTEM,
|
|
212
|
-
content: `Execution failed: ${lockErr.message}`,
|
|
213
|
-
timestamp: utcTimestamp(),
|
|
214
|
-
}),
|
|
215
|
-
],
|
|
216
|
-
});
|
|
217
|
-
await persistStatus(client, executionId, failedStatus, { offload: statusOffload });
|
|
218
|
-
return slimStatus(failedStatus);
|
|
219
|
-
}
|
|
220
|
-
throw lockErr;
|
|
221
|
-
}
|
|
222
|
-
// Bridge the workspace to the session's platform dir so the agent's
|
|
223
|
-
// file tools can read platform-mounted content (`.stigmer/inputs/…`
|
|
224
|
-
// attachments incl. the approved plan, `.stigmer/skills/…`) — the
|
|
225
|
-
// deepagents FilesystemBackend resolves paths against the workspace
|
|
226
|
-
// root and knows nothing of the LocalWorkspaceBackend's `.stigmer`
|
|
227
|
-
// routing. Two ordering invariants (see shared/workspace/stigmer-link.ts):
|
|
228
|
-
// - AFTER the lock: the link is a tree mutation; sessions sharing one
|
|
229
|
-
// attached directory must not re-point it under a running turn.
|
|
230
|
-
// - BEFORE the baseline capture below: present in both the baseline
|
|
231
|
-
// and candidate trees, the link cancels out of the file-review diff
|
|
232
|
-
// even when the workspace's git excludes do not list `.stigmer`.
|
|
233
|
-
// Removed in cleanup() (the finally below), before the lock releases.
|
|
234
|
-
if (setup.workspaceBackend.platformDir) {
|
|
235
|
-
await ensureStigmerSymlink(gitRoot, setup.workspaceBackend.platformDir);
|
|
236
|
-
}
|
|
237
|
-
// (1) Capture-mode resume — reconcile any DECIDED change set FIRST (this
|
|
238
|
-
// drops the per-execution refs), before the next baseline re-pins them
|
|
239
|
-
// (refs are executionId-keyed). Then (2) short-circuit a pure file-review
|
|
240
|
-
// resume — the agent already finished in a prior segment, so finalize with
|
|
241
|
-
// NO model re-invocation. A mixed turn (a tool gate is also pending) falls
|
|
242
|
-
// through to resume the graph for the gated tool.
|
|
243
|
-
if (setup.captureMode) {
|
|
244
|
-
const decidedSets = (setup.execution.status?.fileChangeSets ?? []).filter((cs) => cs.status === FileChangeSetStatus.DECIDED);
|
|
245
|
-
let reconciledAny = false;
|
|
246
|
-
let reconcileFailed = false;
|
|
247
|
-
let reconcileFailureDetail = "";
|
|
248
|
-
// The CAS blob reader reconciles ignored-file decisions from the durable
|
|
249
|
-
// manifest (git-only turns have no manifest, so the CAS branch no-ops).
|
|
250
|
-
// Undefined with no store: this block still runs for a git workspace
|
|
251
|
-
// whose captureMode is true without storage, but such a turn captures no
|
|
252
|
-
// CAS files (captureIgnored is off), so its change set carries no CAS ref
|
|
253
|
-
// and applyCaptureDecisions never needs the reader.
|
|
254
|
-
const casReadBlob = setup.artifactStorage
|
|
255
|
-
? casBlobReader(setup.artifactStorage)
|
|
256
|
-
: undefined;
|
|
257
|
-
for (const changeSet of decidedSets) {
|
|
258
|
-
const capResult = await applyCaptureDecisions({
|
|
259
|
-
status: initialStatus,
|
|
260
|
-
gitRoot,
|
|
261
|
-
executionId,
|
|
262
|
-
changeSet,
|
|
263
|
-
harnessId: DEEP_AGENT_HARNESS_ID,
|
|
264
|
-
storage: setup.artifactStorage,
|
|
265
|
-
readBlob: casReadBlob,
|
|
266
|
-
gitWorkspace: setup.gitWorkspace,
|
|
267
|
-
});
|
|
268
|
-
if (!capResult.isCaptureTurn)
|
|
269
|
-
continue;
|
|
270
|
-
reconciledAny = true;
|
|
271
|
-
if (capResult.failed) {
|
|
272
|
-
reconcileFailed = true;
|
|
273
|
-
reconcileFailureDetail =
|
|
274
|
-
capResult.failureDetail ?? "file review reconcile failed";
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
if (reconciledAny) {
|
|
278
|
-
if (reconcileFailed) {
|
|
279
|
-
// What-you-approve-is-what-applies failed: nothing was applied.
|
|
280
|
-
initialStatus.phase = ExecutionPhase.EXECUTION_FAILED;
|
|
281
|
-
initialStatus.error = `File review reconcile failed: ${reconcileFailureDetail}`;
|
|
282
|
-
initialStatus.completedAt = utcTimestamp();
|
|
283
|
-
await persistStatus(client, executionId, initialStatus, { offload: statusOffload });
|
|
284
|
-
return slimStatus(initialStatus);
|
|
285
|
-
}
|
|
286
|
-
if (!hasPendingToolApprovals(setup.execution)) {
|
|
287
|
-
// Pure file review: the agent's final answer + outputs already rode
|
|
288
|
-
// the prior segment's persisted status (seeded into initialStatus).
|
|
289
|
-
// Complete now and push only the approved tree — NO model re-run.
|
|
290
|
-
//
|
|
291
|
-
// The discriminator is the PERSISTED transcript, not the live graph
|
|
292
|
-
// checkpoint: it must behave identically across checkpointer
|
|
293
|
-
// backends, but the live checkpoint does not — the memory backend
|
|
294
|
-
// (opt-in, tests) recreates it empty each invocation while the
|
|
295
|
-
// durable backends (sqlite local / http cloud) preserve it, so a
|
|
296
|
-
// graphState-based check would diverge and could wrongly fire for a
|
|
297
|
-
// mixed turn. A mixed turn leaves WAITING_APPROVAL tool rows in the
|
|
298
|
-
// transcript; a pure file-review turn leaves none.
|
|
299
|
-
initialStatus.phase = ExecutionPhase.EXECUTION_COMPLETED;
|
|
300
|
-
initialStatus.completedAt = utcTimestamp();
|
|
301
|
-
if (writebackCoordinator) {
|
|
302
|
-
await processCaptureWriteback(writebackCoordinator, executionId);
|
|
303
|
-
}
|
|
304
|
-
await persistStatus(client, executionId, initialStatus, { offload: statusOffload });
|
|
305
|
-
// Surface the agent's final outputs (computed in the prior segment,
|
|
306
|
-
// carried on the seeded status) the same way a normal completion does.
|
|
307
|
-
const slim = slimStatus(initialStatus);
|
|
308
|
-
const lastAi = [...initialStatus.messages]
|
|
309
|
-
.reverse()
|
|
310
|
-
.find((m) => m.type === MessageType.MESSAGE_AI);
|
|
311
|
-
if (lastAi?.content)
|
|
312
|
-
slim.final_text = lastAi.content;
|
|
313
|
-
if (initialStatus.structuredOutput !== undefined) {
|
|
314
|
-
slim.structured = initialStatus.structuredOutput;
|
|
315
|
-
}
|
|
316
|
-
return slim;
|
|
317
|
-
}
|
|
318
|
-
// else: mixed turn — fall through; the graph resumes for the gated
|
|
319
|
-
// tool and a new baseline is taken below for the continuation segment.
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
// Turn start (capture mode): pin the pre-turn tree + author BASELINE. Taken
|
|
323
|
-
// AFTER any reconcile above and AFTER performSetup's workspace writes and
|
|
324
|
-
// the `.stigmer` symlink above, so the baseline absorbs the reconciled
|
|
325
|
-
// state and the runner-owned files (the symlink then cancels out of the
|
|
326
|
-
// baseline→candidate diff).
|
|
327
|
-
let captureBaselineTree = "";
|
|
328
|
-
// Snapshot the sub-agent tool-call ids that exist BEFORE this turn's
|
|
329
|
-
// stream, so the turn-boundary stamp scopes itself to sub-agent rows
|
|
330
|
-
// created this turn (empty here by construction — this harness never
|
|
331
|
-
// seeds prior sub-agents — but computed, not assumed, so it stays correct
|
|
332
|
-
// if that ever changes; see collectSubAgentToolCallIds).
|
|
333
|
-
const priorSubAgentToolCallIds = collectSubAgentToolCallIds(initialStatus.subAgentExecutions);
|
|
334
|
-
// Snapshot the top-level tool-call ids already SETTLED before this turn's
|
|
335
|
-
// stream, so the approved-command provenance (DD-28) scopes itself to THIS
|
|
336
|
-
// turn's executed commands by identity. The deep-agent's approved shell
|
|
337
|
-
// executes in place at its seeded position, so the Cursor positional scope
|
|
338
|
-
// would miss it — see execute-deep-agent/command-provenance.ts.
|
|
339
|
-
const priorSettledToolCallIds = collectSettledToolCallIds(initialStatus.messages);
|
|
340
|
-
if (setup.captureMode) {
|
|
341
|
-
captureBaselineTree = await captureBaselineToLedger({
|
|
342
|
-
status: initialStatus,
|
|
343
|
-
gitRoot,
|
|
344
|
-
executionId,
|
|
345
|
-
changeSetId,
|
|
346
|
-
harnessId: DEEP_AGENT_HARNESS_ID,
|
|
347
|
-
gitWorkspace: setup.gitWorkspace,
|
|
348
|
-
});
|
|
349
|
-
}
|
|
350
|
-
// Per-turn state + substrate for mid-run live capture (DD-32 / DD-33). The
|
|
351
|
-
// floor lives in progressState; the substrate is chosen for this turn's
|
|
352
|
-
// workspace shape and owns its own short-circuit cache. An atomic snapshot
|
|
353
|
-
// of the shared observer feeds the CAS/HYBRID substrates — copied
|
|
354
|
-
// synchronously so a concurrent sub-agent write cannot mutate it mid-read.
|
|
355
|
-
const progressState = newProgressCaptureState();
|
|
356
|
-
const casObserver = setup.casObserver;
|
|
357
|
-
const readObserverTouched = () => ({
|
|
358
|
-
before: new Map(casObserver.before),
|
|
359
|
-
blockedSecretPaths: new Set(casObserver.blockedSecretPaths),
|
|
360
|
-
});
|
|
361
|
-
// Git tree -> hybrid (numstat for tracked + observer for gitignored);
|
|
362
|
-
// non-git -> cas over the observer (no baseline tree needed). Undefined
|
|
363
|
-
// outside capture mode (writes are deny-gated, nothing is captured).
|
|
364
|
-
const progressSubstrate = !setup.captureMode
|
|
365
|
-
? undefined
|
|
366
|
-
: setup.gitWorkspace
|
|
367
|
-
? captureBaselineTree
|
|
368
|
-
? createHybridProgressSubstrate(createGitProgressSubstrate({
|
|
369
|
-
workspaceRoot: gitRoot,
|
|
370
|
-
executionId,
|
|
371
|
-
baselineTree: captureBaselineTree,
|
|
372
|
-
}), createCasProgressSubstrate({ workspaceRoot: gitRoot, read: readObserverTouched }))
|
|
373
|
-
: undefined
|
|
374
|
-
: createCasProgressSubstrate({ workspaceRoot: gitRoot, read: readObserverTouched });
|
|
375
|
-
const cancellationSignal = Context.current().cancellationSignal;
|
|
376
|
-
const result = await streamExecution({
|
|
377
|
-
agentGraph: setup.agentGraph,
|
|
378
|
-
langgraphInput: effectiveInput,
|
|
379
|
-
langgraphConfig: setup.langgraphConfig,
|
|
380
|
-
executionId,
|
|
381
|
-
client,
|
|
382
|
-
initialStatus,
|
|
383
|
-
streamingConfig,
|
|
384
|
-
offload: statusOffload,
|
|
385
|
-
gracefulStop: setup.gracefulStop,
|
|
386
|
-
inlinePublisher,
|
|
387
|
-
// Capture mode: never push speculative edits during the turn. Writeback
|
|
388
|
-
// is deferred until the approved tree is reconciled (post-decision).
|
|
389
|
-
writebackCoordinator: setup.captureMode ? undefined : (writebackCoordinator ?? undefined),
|
|
390
|
-
heartbeatFn: (details) => Context.current().heartbeat(details),
|
|
391
|
-
isCancelledFn: () => cancellationSignal.aborted,
|
|
392
|
-
approvalProvider: {
|
|
393
|
-
policies: setup.approvalPolicies,
|
|
394
|
-
toolServerMap: setup.toolServerMap,
|
|
395
|
-
leasedCategories: setup.leasedCategories,
|
|
396
|
-
globalBypass: setup.globalBypass,
|
|
397
|
-
unattended: setup.unattended,
|
|
398
|
-
},
|
|
399
|
-
streamVersion: setup.streamVersion,
|
|
400
|
-
// Mid-run live capture (DD-32 / DD-33): attach file_change_progress
|
|
401
|
-
// before each scheduled persist, throttled by the floor inside
|
|
402
|
-
// captureFileChangeProgress. The substrate (git / non-git CAS / hybrid)
|
|
403
|
-
// was chosen for this turn above; the deep-agent's only runner-owned
|
|
404
|
-
// tree entry is the `.stigmer` symlink, created before the baseline
|
|
405
|
-
// so it appears identically in every capture and cancels out of the
|
|
406
|
-
// diff — the git slice therefore needs no excludePaths, matching its
|
|
407
|
-
// turn-boundary candidate capture.
|
|
408
|
-
beforePersist: async (status) => {
|
|
409
|
-
if (!progressSubstrate)
|
|
410
|
-
return;
|
|
411
|
-
await captureFileChangeProgress({
|
|
412
|
-
status,
|
|
413
|
-
changeSetId,
|
|
414
|
-
substrate: progressSubstrate,
|
|
415
|
-
state: progressState,
|
|
416
|
-
});
|
|
417
|
-
},
|
|
418
|
-
});
|
|
419
|
-
await processPostStream({
|
|
420
|
-
status: initialStatus,
|
|
421
|
-
inlinePublisher,
|
|
422
|
-
// Capture mode: suppress the post-stream writeback finalize — the edits
|
|
423
|
-
// on disk are still speculative until reviewed. Writeback runs only on
|
|
424
|
-
// the approved tree (processCaptureWriteback, after reconcile).
|
|
425
|
-
writebackCoordinator: setup.captureMode ? null : writebackCoordinator,
|
|
426
|
-
pendingPublishPromises: result.pendingPublishPromises,
|
|
427
|
-
pendingWritebackPromises: result.pendingWritebackPromises,
|
|
428
|
-
executionId,
|
|
429
|
-
});
|
|
430
|
-
// Never-persist-secret backstop (DD-26 #2): withhold content from any
|
|
431
|
-
// built-in write row targeting a secret-like path, across the top-level
|
|
432
|
-
// and sub-agent transcripts, before ANY persist below. On the deny-gate a
|
|
433
|
-
// secret write is hard-blocked (a COMPLETED row) or — under
|
|
434
|
-
// auto_approve_all, where no gate is installed — flowed; either way the
|
|
435
|
-
// streamed row still carries `args` from handleToolStarted, and the
|
|
436
|
-
// capture-mode stamping pass (which performs the same scrub) does not run
|
|
437
|
-
// here. Idempotent / a no-op in capture mode. This single post-stream
|
|
438
|
-
// sweep is the one choke point that precedes every downstream persist.
|
|
439
|
-
withholdSecretContentFromMessages(initialStatus.messages, initialStatus.subAgentExecutions);
|
|
440
|
-
// Terminalize any tool call the user SKIPPED or REJECTED at the gate.
|
|
441
|
-
// These decisions never run the tool, so the resumed stream leaves the
|
|
442
|
-
// seeded WAITING_APPROVAL row untouched (the gate returns a ToolMessage
|
|
443
|
-
// with no on_tool_start on http; the memory replay never re-drives the
|
|
444
|
-
// gate). Folding the recorded decision into a terminal status here makes
|
|
445
|
-
// reject/skip resolve identically on both checkpointers — see
|
|
446
|
-
// reconcileNonExecutingDecisions. Runs before the WAITING-detection and
|
|
447
|
-
// completion persists below so the terminal status is what is persisted.
|
|
448
|
-
reconcileNonExecutingDecisions(initialStatus);
|
|
449
|
-
// Terminalize every tool call the gate auto-skipped under UNATTENDED
|
|
450
|
-
// approval mode (DD-014): the skip has no human decision behind it, so
|
|
451
|
-
// reconcileNonExecutingDecisions cannot see it — this sibling folds the
|
|
452
|
-
// gate's registry into terminal SKIPPED rows with UNATTENDED_SKIP
|
|
453
|
-
// provenance, whatever transient status the stream left behind. No-op
|
|
454
|
-
// for interactive executions (empty registry).
|
|
455
|
-
reconcileUnattendedSkips(initialStatus, setup.unattendedSkips);
|
|
456
|
-
// Turn boundary (capture mode): capture the candidate change set from the
|
|
457
|
-
// git diff and author CANDIDATE_CAPTURED, then stamp the flowed file-edit
|
|
458
|
-
// rows with the change set id — they stay visible in place as
|
|
459
|
-
// observational records while file_change_sets remains the single
|
|
460
|
-
// decision surface. Skipped on an abnormal terminal (pause / stop /
|
|
461
|
-
// recursion limit) — there is no review to open. `fileReviewPending`
|
|
462
|
-
// then composes with any tool gate below.
|
|
463
|
-
let fileReviewPending = false;
|
|
464
|
-
const abnormalTerminal = !!result.terminalStatus &&
|
|
465
|
-
initialStatus.phase !== ExecutionPhase.EXECUTION_WAITING_FOR_APPROVAL;
|
|
466
|
-
if (setup.captureMode && !abnormalTerminal) {
|
|
467
|
-
// Compose the CAS-captured paths (before-bytes from the observer,
|
|
468
|
-
// after-bytes re-read from disk) and the secret-blocked paths into the
|
|
469
|
-
// change set. The substrate class labels their provenance:
|
|
470
|
-
// GIT_IGNORED_CAPTURED for a git tree's ignored paths, NON_GIT_CAS for a
|
|
471
|
-
// non-git workspace (where these ARE the whole change set). In a git turn
|
|
472
|
-
// they compose with the git-tracked diff into one hybrid set; in a non-git
|
|
473
|
-
// turn they are the entire (CAS-only) set.
|
|
474
|
-
const casCaptureClass = setup.gitWorkspace
|
|
475
|
-
? FileCaptureClass.GIT_IGNORED_CAPTURED
|
|
476
|
-
: FileCaptureClass.NON_GIT_CAS;
|
|
477
|
-
const { casCaptures, unreviewablePaths } = await buildCasTurnCaptures(setup.casObserver, gitRoot, casCaptureClass);
|
|
478
|
-
// Approved-command turn facts (DD-28): when every mutation-capable call
|
|
479
|
-
// this turn was a consented shell command, attach the provenance so the
|
|
480
|
-
// backend can verify the cited consent rows and auto-keep the set
|
|
481
|
-
// instead of arming a second review gate. Fail-closed: any non-qualifying
|
|
482
|
-
// turn attaches nothing and reviews manually exactly as before. Attached
|
|
483
|
-
// only when captureCandidateToLedger actually authors a CANDIDATE.
|
|
484
|
-
const commandProvenance = deriveTurnCommandProvenance({
|
|
485
|
-
status: initialStatus,
|
|
486
|
-
priorSettledToolCallIds,
|
|
487
|
-
priorSubAgentToolCallIds,
|
|
488
|
-
globalBypass: setup.globalBypass,
|
|
489
|
-
});
|
|
490
|
-
if (commandProvenance) {
|
|
491
|
-
console.log(`[ExecuteDeepAgent] capture: turn qualifies for approved-command auto-keep ` +
|
|
492
|
-
`(consent rows: ${commandProvenance.consentToolCallIds.join(",") || "(auto_approve_all)"}); ` +
|
|
493
|
-
`attaching provenance to candidate (execution=${executionId})`);
|
|
494
|
-
}
|
|
495
|
-
await captureCandidateToLedger({
|
|
496
|
-
status: initialStatus,
|
|
497
|
-
gitRoot,
|
|
498
|
-
executionId,
|
|
499
|
-
changeSetId,
|
|
500
|
-
baselineTree: captureBaselineTree,
|
|
501
|
-
harnessId: DEEP_AGENT_HARNESS_ID,
|
|
502
|
-
casCaptures,
|
|
503
|
-
storage: setup.artifactStorage,
|
|
504
|
-
unreviewablePaths,
|
|
505
|
-
unreviewableCaptureClass: casCaptureClass,
|
|
506
|
-
gitWorkspace: setup.gitWorkspace,
|
|
507
|
-
commandProvenance,
|
|
508
|
-
});
|
|
509
|
-
// Review is pending iff a CANDIDATE was actually authored (the seam
|
|
510
|
-
// drops no-op captures), so a turn that only touched-then-unchanged an
|
|
511
|
-
// ignored file does not open an empty review. Stamping is gated on the
|
|
512
|
-
// same signal: a row must never reference a change set that does not
|
|
513
|
-
// exist.
|
|
514
|
-
fileReviewPending = hasCandidateCaptured(initialStatus, changeSetId);
|
|
515
|
-
if (fileReviewPending) {
|
|
516
|
-
stampFlowedFileEditRows(initialStatus.messages, changeSetId);
|
|
517
|
-
stampFlowedSubAgentFileEditRows(initialStatus.subAgentExecutions, changeSetId, priorSubAgentToolCallIds);
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
if (result.terminalStatus) {
|
|
521
|
-
if (initialStatus.phase === ExecutionPhase.EXECUTION_PAUSED) {
|
|
522
|
-
// The stream loop marks PAUSED for ANY platform cancellation; a
|
|
523
|
-
// worker shutdown is not a pause and must not persist as one (#776).
|
|
524
|
-
if (shutdownSignal?.aborted) {
|
|
525
|
-
console.log(`[ExecuteDeepAgent] Cancelled (worker shutdown) for execution ${executionId}: events=${result.eventsProcessed}`);
|
|
526
|
-
await persistStatus(client, executionId, buildWorkerShutdownStatus(), { offload: statusOffload }).catch(() => { });
|
|
527
|
-
throw new CancelledFailure("Activity cancelled (worker shutdown, not user pause)");
|
|
528
|
-
}
|
|
529
|
-
await persistStatus(client, executionId, initialStatus, { offload: statusOffload });
|
|
530
|
-
console.log(`[ExecuteDeepAgent] Paused for execution ${executionId}: events=${result.eventsProcessed}`);
|
|
531
|
-
throw new CancelledFailure("Activity paused by orchestrator");
|
|
532
|
-
}
|
|
533
|
-
// Capture mode: a tool gate set WAITING during the stream while file
|
|
534
|
-
// edits also flowed this turn. The CANDIDATE event + stamped file-edit
|
|
535
|
-
// rows post-date the stream's slim, so persist + return the current
|
|
536
|
-
// status (both review surfaces — the file change set and the tool gate —
|
|
537
|
-
// are now pending). `!abnormalTerminal` means the capture block ran.
|
|
538
|
-
if (setup.captureMode && !abnormalTerminal) {
|
|
539
|
-
await persistStatus(client, executionId, initialStatus, { offload: statusOffload });
|
|
540
|
-
return slimStatus(initialStatus);
|
|
541
|
-
}
|
|
542
|
-
return result.terminalStatus;
|
|
543
|
-
}
|
|
544
|
-
if (!setup.globalBypass) {
|
|
545
|
-
const postStreamGraphState = await setup.agentGraph.getState(setup.langgraphConfig);
|
|
546
|
-
const graphMessages = postStreamGraphState.values.messages;
|
|
547
|
-
const aiMessages = Array.isArray(graphMessages) ? graphMessages : [];
|
|
548
|
-
const pendingInterrupts = detectPendingInterrupts(postStreamGraphState);
|
|
549
|
-
if (pendingInterrupts.length > 0) {
|
|
550
|
-
console.log(`[ExecuteDeepAgent] Detected ${pendingInterrupts.length} pending interrupt(s) ` +
|
|
551
|
-
`for execution ${executionId} — setting WAITING_FOR_APPROVAL`);
|
|
552
|
-
initialStatus.phase = ExecutionPhase.EXECUTION_WAITING_FOR_APPROVAL;
|
|
553
|
-
const aiMsg = create(AgentMessageSchema, {
|
|
554
|
-
type: MessageType.MESSAGE_AI,
|
|
555
|
-
content: "",
|
|
556
|
-
timestamp: utcTimestamp(),
|
|
557
|
-
isStreaming: false,
|
|
558
|
-
});
|
|
559
|
-
for (const intr of pendingInterrupts) {
|
|
560
|
-
const toolCall = create(ToolCallSchema, {
|
|
561
|
-
id: intr.toolCallId,
|
|
562
|
-
name: intr.toolName,
|
|
563
|
-
status: ToolCallStatus.TOOL_CALL_WAITING_APPROVAL,
|
|
564
|
-
requiresApproval: true,
|
|
565
|
-
approvalMessage: intr.message,
|
|
566
|
-
approvalRequestedAt: utcTimestamp(),
|
|
567
|
-
mcpServerSlug: intr.mcpServerSlug,
|
|
568
|
-
startedAt: utcTimestamp(),
|
|
569
|
-
toolKind: classifyTool(intr.toolName, intr.mcpServerSlug),
|
|
570
|
-
approvalPolicySource: toProtoPolicySource(intr.policySource),
|
|
571
|
-
policyEngineVersion: intr.policySource ? POLICY_ENGINE_VERSION : "",
|
|
572
|
-
});
|
|
573
|
-
// Capture a sanitized args preview AND the redacted args object
|
|
574
|
-
// while the graph is paused, so the approval UI renders the
|
|
575
|
-
// proposed change before the tool runs — and the row header can
|
|
576
|
-
// extract its filename-first path from `args` like every other
|
|
577
|
-
// row (issue #754: a placeholder without args rendered a
|
|
578
|
-
// pathless "Write" header). Args are correlated from the
|
|
579
|
-
// AI-message tool call in graph state (the single source of
|
|
580
|
-
// truth).
|
|
581
|
-
const { argsPreview, args } = captureApprovalArtifacts({
|
|
582
|
-
toolCallId: intr.toolCallId,
|
|
583
|
-
messages: aiMessages,
|
|
584
|
-
});
|
|
585
|
-
if (argsPreview)
|
|
586
|
-
toolCall.argsPreview = argsPreview;
|
|
587
|
-
if (args)
|
|
588
|
-
toolCall.args = args;
|
|
589
|
-
aiMsg.toolCalls.push(toolCall);
|
|
590
|
-
}
|
|
591
|
-
initialStatus.messages.push(aiMsg);
|
|
592
|
-
await persistStatus(client, executionId, initialStatus, { offload: statusOffload });
|
|
593
|
-
return slimStatus(initialStatus);
|
|
594
|
-
}
|
|
595
|
-
}
|
|
596
|
-
// Capture mode: file edits flowed but no tool gate fired — open file
|
|
597
|
-
// review instead of completing. The agent's final answer + outputs are
|
|
598
|
-
// still computed and persisted below, so the pure-file-review resume can
|
|
599
|
-
// complete from the seeded status with no model re-invocation.
|
|
600
|
-
const completeNow = !fileReviewPending;
|
|
601
|
-
initialStatus.phase = completeNow
|
|
602
|
-
? ExecutionPhase.EXECUTION_COMPLETED
|
|
603
|
-
: ExecutionPhase.EXECUTION_WAITING_FOR_APPROVAL;
|
|
604
|
-
if (completeNow) {
|
|
605
|
-
initialStatus.completedAt = utcTimestamp();
|
|
606
|
-
}
|
|
607
|
-
let structuredOutput;
|
|
608
|
-
let finalText;
|
|
609
|
-
const lastAiMsg = [...initialStatus.messages]
|
|
610
|
-
.reverse()
|
|
611
|
-
.find(m => m.type === MessageType.MESSAGE_AI);
|
|
612
|
-
if (lastAiMsg) {
|
|
613
|
-
finalText = lastAiMsg.content;
|
|
614
|
-
}
|
|
615
|
-
if (setup.hasStructuredOutput) {
|
|
616
|
-
// Primary source: deepagents' structuredResponse surfaced via the v3
|
|
617
|
-
// run.output. This is the reliable path when the graph populates it.
|
|
618
|
-
const sr = result.runOutput?.structuredResponse;
|
|
619
|
-
if (sr != null && typeof sr === "object" && !Array.isArray(sr)) {
|
|
620
|
-
structuredOutput = sr;
|
|
621
|
-
}
|
|
622
|
-
else if (sr !== undefined) {
|
|
623
|
-
console.warn(`[ExecuteDeepAgent] structuredResponse is not a plain object ` +
|
|
624
|
-
`for execution ${executionId}: type=${typeof sr}`);
|
|
625
|
-
}
|
|
626
|
-
// Fallback: extract JSON from the agent's final text message. The v3
|
|
627
|
-
// streaming path does not surface deepagents' structuredResponse
|
|
628
|
-
// (hasStructuredResponse=false), so we recover structured output by
|
|
629
|
-
// parsing the agent's final response (JSON / code-fence / last-brace).
|
|
630
|
-
if (structuredOutput === undefined && finalText) {
|
|
631
|
-
const { extractJsonFromText } = await import("../../shared/extract-json.js");
|
|
632
|
-
const extracted = extractJsonFromText(finalText);
|
|
633
|
-
if (extracted != null && typeof extracted === "object" && !Array.isArray(extracted)) {
|
|
634
|
-
structuredOutput = extracted;
|
|
635
|
-
console.log(`[ExecuteDeepAgent] structured output extracted from final text ` +
|
|
636
|
-
`for execution ${executionId}: finalTextLength=${finalText.length}`);
|
|
637
|
-
}
|
|
638
|
-
}
|
|
639
|
-
if (structuredOutput !== undefined) {
|
|
640
|
-
initialStatus.structuredOutput = structuredOutput;
|
|
641
|
-
}
|
|
642
|
-
}
|
|
643
|
-
// Plan mode: the agent's final message is the plan. Publish it as a
|
|
644
|
-
// first-class plan artifact (named from the plan's title) so the UI can
|
|
645
|
-
// render a reviewable Plan card and a follow-up Implement run can
|
|
646
|
-
// reference it. Read-only mode produces no file to auto-publish, so
|
|
647
|
-
// this is the only artifact path.
|
|
648
|
-
// Requires artifact storage; with none (proxy misconfig) the plan text
|
|
649
|
-
// still lives in the final message — only the reviewable artifact is
|
|
650
|
-
// skipped (mirrors Cursor's storage-guarded plan publish).
|
|
651
|
-
if (setup.execution.spec?.executionConfig?.interactionMode === InteractionMode.PLAN &&
|
|
652
|
-
finalText &&
|
|
653
|
-
setup.artifactStorage) {
|
|
654
|
-
await publishPlanArtifact({
|
|
655
|
-
status: initialStatus,
|
|
656
|
-
executionId,
|
|
657
|
-
planText: finalText,
|
|
658
|
-
artifactStorage: setup.artifactStorage,
|
|
659
|
-
});
|
|
660
|
-
}
|
|
661
|
-
// Capture mode: push the approved tree exactly once, on terminal
|
|
662
|
-
// completion — never the speculative mid-turn edits.
|
|
663
|
-
if (setup.captureMode && completeNow && writebackCoordinator) {
|
|
664
|
-
await processCaptureWriteback(writebackCoordinator, executionId);
|
|
665
|
-
}
|
|
666
|
-
await persistStatus(client, executionId, initialStatus, { offload: statusOffload });
|
|
667
|
-
console.log(`[ExecuteDeepAgent] ${completeNow ? "Completed" : "Awaiting file review for"} ` +
|
|
668
|
-
`execution ${executionId}: ` +
|
|
669
|
-
`events=${result.eventsProcessed}, ` +
|
|
670
|
-
`messages=${initialStatus.messages.length}, ` +
|
|
671
|
-
`artifacts=${initialStatus.artifacts.length}, ` +
|
|
672
|
-
`writebacks=${initialStatus.workspaceWriteBacks.length}, ` +
|
|
673
|
-
`hasStructuredOutput=${structuredOutput !== undefined}`);
|
|
674
|
-
// A WAITING (file-review) return carries no final outputs yet — those are
|
|
675
|
-
// surfaced when the pure-file-review resume completes from this persisted
|
|
676
|
-
// status. The COMPLETED return enriches the slim with final text/outputs.
|
|
677
|
-
if (!completeNow) {
|
|
678
|
-
return slimStatus(initialStatus);
|
|
679
|
-
}
|
|
680
|
-
const slim = slimStatus(initialStatus);
|
|
681
|
-
if (finalText !== undefined) {
|
|
682
|
-
slim.final_text = finalText;
|
|
683
|
-
}
|
|
684
|
-
if (structuredOutput !== undefined) {
|
|
685
|
-
slim.structured = structuredOutput;
|
|
686
|
-
}
|
|
687
|
-
return slim;
|
|
688
|
-
}
|
|
689
|
-
catch (err) {
|
|
690
|
-
if (err instanceof CancelledFailure) {
|
|
691
|
-
// Worker shutdown is infrastructure failure, not pause — the caught
|
|
692
|
-
// CancelledFailure is itself the interruption evidence (#776).
|
|
693
|
-
if (shutdownSignal?.aborted) {
|
|
694
|
-
console.log(`[ExecuteDeepAgent] Cancelled (worker shutdown) for execution ${executionId}`);
|
|
695
|
-
await persistStatus(client, executionId, buildWorkerShutdownStatus()).catch(() => { });
|
|
696
|
-
throw err;
|
|
697
|
-
}
|
|
698
|
-
console.log(`[ExecuteDeepAgent] Cancelled (pause) for execution ${executionId}`);
|
|
699
|
-
const pausedStatus = create(AgentExecutionStatusSchema, {
|
|
700
|
-
phase: ExecutionPhase.EXECUTION_PAUSED,
|
|
701
|
-
});
|
|
702
|
-
await persistStatus(client, executionId, pausedStatus).catch(() => { });
|
|
703
|
-
throw err;
|
|
704
|
-
}
|
|
705
|
-
if (Context.current().cancellationSignal.aborted) {
|
|
706
|
-
if (shutdownSignal?.aborted) {
|
|
707
|
-
console.log(`[ExecuteDeepAgent] Error during worker-shutdown cancellation for ${executionId}: ${err}`);
|
|
708
|
-
await persistStatus(client, executionId, buildWorkerShutdownStatus()).catch(() => { });
|
|
709
|
-
throw new CancelledFailure("Activity cancelled (worker shutdown, not user pause)");
|
|
710
|
-
}
|
|
711
|
-
console.log(`[ExecuteDeepAgent] Error during cancellation for ${executionId}, treating as pause: ${err}`);
|
|
712
|
-
const pausedStatus = create(AgentExecutionStatusSchema, {
|
|
713
|
-
phase: ExecutionPhase.EXECUTION_PAUSED,
|
|
714
|
-
});
|
|
715
|
-
await persistStatus(client, executionId, pausedStatus).catch(() => { });
|
|
716
|
-
throw new CancelledFailure("Activity paused by orchestrator (error during cancellation)");
|
|
717
|
-
}
|
|
718
|
-
// Classify before formatting: model-call failures get stable codes
|
|
719
|
-
// and platform-vs-user attribution (LangChain's MiddlewareError
|
|
720
|
-
// wrapper is unwrapped to the root SDK error); non-model failures
|
|
721
|
-
// keep the root error's own identity. See shared/model-error.ts.
|
|
722
|
-
const { errorType, errorMessage } = describeExecutionError(err, {
|
|
723
|
-
proxyMode: !!config.proxyEndpoint,
|
|
724
|
-
modelId: setup?.modelName,
|
|
725
|
-
provider: setup ? tryInferProvider(setup.modelName) : undefined,
|
|
726
|
-
});
|
|
727
|
-
console.error(`[ExecuteDeepAgent] Failed for execution ${executionId}: ` +
|
|
728
|
-
`[${errorType}] ${errorMessage}`);
|
|
729
|
-
const failedStatus = create(AgentExecutionStatusSchema, {
|
|
730
|
-
phase: ExecutionPhase.EXECUTION_FAILED,
|
|
731
|
-
error: `Execution failed: [${errorType}] ${errorMessage}`,
|
|
732
|
-
completedAt: utcTimestamp(),
|
|
733
|
-
messages: [
|
|
734
|
-
create(AgentMessageSchema, {
|
|
735
|
-
type: MessageType.MESSAGE_SYSTEM,
|
|
736
|
-
content: `Error: [${errorType}] ${errorMessage}`,
|
|
737
|
-
timestamp: utcTimestamp(),
|
|
738
|
-
}),
|
|
739
|
-
],
|
|
740
|
-
});
|
|
741
|
-
await persistStatus(client, executionId, failedStatus);
|
|
742
|
-
return slimStatus(failedStatus);
|
|
743
|
-
}
|
|
744
|
-
finally {
|
|
745
|
-
await cleanup(setup);
|
|
746
|
-
// Release the workspace turn lock LAST — the next queued turn must
|
|
747
|
-
// not baseline until every mutation of this one has landed.
|
|
748
|
-
// Idempotent and non-throwing (see workspace-lock.ts).
|
|
749
|
-
await releaseWorkspaceLock?.();
|
|
750
|
-
activityFinished();
|
|
751
|
-
}
|
|
752
|
-
},
|
|
753
|
-
};
|
|
754
|
-
}
|
|
755
|
-
/**
|
|
756
|
-
* Normalize the graph checkpoint's un-resumed interrupts into pending approvals.
|
|
757
|
-
* Used both before streaming (to detect whether a resume is a pure file review)
|
|
758
|
-
* and after (to seed the WAITING_FOR_APPROVAL tool rows).
|
|
759
|
-
*/
|
|
760
|
-
function detectPendingInterrupts(graphState) {
|
|
761
|
-
const tasks = graphState.tasks;
|
|
762
|
-
return (tasks?.flatMap((task) => (task.interrupts ?? [])
|
|
763
|
-
.filter((intr) => intr.resumeValue === undefined)
|
|
764
|
-
.map((intr) => {
|
|
765
|
-
const val = intr.value;
|
|
766
|
-
return {
|
|
767
|
-
toolCallId: val?.tool_call_id ?? "",
|
|
768
|
-
toolName: val?.tool_name ?? "",
|
|
769
|
-
mcpServerSlug: val?.mcp_server_slug ?? "",
|
|
770
|
-
message: val?.message ?? "",
|
|
771
|
-
policySource: val?.policy_source || undefined,
|
|
772
|
-
};
|
|
773
|
-
})) ?? []);
|
|
774
|
-
}
|
|
775
|
-
/**
|
|
776
|
-
* Whether the persisted transcript holds any tool call awaiting approval — the
|
|
777
|
-
* checkpointer-independent signal that a resume must drive a tool gate (resume
|
|
778
|
-
* the graph), not just a file review. Scans root + sub-agent messages. A tool
|
|
779
|
-
* keeps `WAITING_APPROVAL` after the user decides (the decision rides
|
|
780
|
-
* `approval_action`) until the runner reconciles it, so this is true for a mixed
|
|
781
|
-
* turn's resume and false for a pure file-review turn.
|
|
782
|
-
*/
|
|
783
|
-
function hasPendingToolApprovals(execution) {
|
|
784
|
-
const status = execution.status;
|
|
785
|
-
if (!status)
|
|
786
|
-
return false;
|
|
787
|
-
const anyWaiting = (msgs) => msgs.some((m) => m.toolCalls.some((tc) => tc.status === ToolCallStatus.TOOL_CALL_WAITING_APPROVAL));
|
|
788
|
-
if (anyWaiting(status.messages))
|
|
789
|
-
return true;
|
|
790
|
-
return status.subAgentExecutions.some((sa) => anyWaiting(sa.messages));
|
|
791
|
-
}
|
|
792
|
-
/**
|
|
793
|
-
* Assemble the turn's CAS captures and secret-blocked paths from the shared
|
|
794
|
-
* observer (the pre-turn bytes recorded by the parent AND every sub-agent CAS
|
|
795
|
-
* backend, plus the gate's secret-blocked set).
|
|
796
|
-
*
|
|
797
|
-
* For each observed CAS-owned path the after-bytes are re-read from disk (the
|
|
798
|
-
* authoritative net result of the turn; `null` when the file is gone). A path
|
|
799
|
-
* that is secret-like is diverted to `unreviewablePaths` and its before-bytes are
|
|
800
|
-
* dropped — the fail-closed backstop that holds even under the global bypass,
|
|
801
|
-
* where the gate did not run to block it up front. The result composes into the
|
|
802
|
-
* change set in {@link captureCandidateToLedger}.
|
|
803
|
-
*
|
|
804
|
-
* `captureClass` is the turn's CAS substrate class — GIT_IGNORED_CAPTURED for a
|
|
805
|
-
* git work tree's ignored paths, NON_GIT_CAS for a non-git workspace (where these
|
|
806
|
-
* ARE the whole change set) — so each captured path carries its true provenance.
|
|
807
|
-
*/
|
|
808
|
-
async function buildCasTurnCaptures(observer, workspaceRoot, captureClass) {
|
|
809
|
-
// The secret partition (pure, corpus-lockable) decides what may be captured;
|
|
810
|
-
// this shell only performs the IO for the capturable set. The backstop that
|
|
811
|
-
// withholds a secret observed under the global bypass lives in the partition.
|
|
812
|
-
const { capturablePaths, unreviewablePaths } = partitionIgnoredPathsBySecret(observer.before.keys(), observer.blockedSecretPaths);
|
|
813
|
-
const casCaptures = [];
|
|
814
|
-
for (const relPath of capturablePaths) {
|
|
815
|
-
const after = await readFileOrNull(join(workspaceRoot, relPath));
|
|
816
|
-
casCaptures.push({
|
|
817
|
-
path: relPath,
|
|
818
|
-
before: observer.before.get(relPath) ?? null,
|
|
819
|
-
after,
|
|
820
|
-
captureClass,
|
|
821
|
-
});
|
|
822
|
-
}
|
|
823
|
-
return { casCaptures, unreviewablePaths: [...unreviewablePaths] };
|
|
824
|
-
}
|
|
825
|
-
/** Raw bytes of a file, or `null` when it does not exist (a DELETE). */
|
|
826
|
-
async function readFileOrNull(absolutePath) {
|
|
827
|
-
try {
|
|
828
|
-
return await readFile(absolutePath);
|
|
829
|
-
}
|
|
830
|
-
catch {
|
|
831
|
-
return null;
|
|
832
|
-
}
|
|
833
|
-
}
|
|
834
|
-
/**
|
|
835
|
-
* Push the reconciled (approved) tree exactly once, on terminal completion in
|
|
836
|
-
* capture mode. The coordinator's {@link WriteBackCoordinator.finalize} commits +
|
|
837
|
-
* pushes whatever uncommitted changes remain — which, post-reconcile, is exactly
|
|
838
|
-
* the approved content (rejected files were already snapped back to baseline).
|
|
839
|
-
* Speculative mid-turn edits never reach here (writeback is suppressed during the
|
|
840
|
-
* turn). Fire-and-forget by the coordinator's own contract (errors logged).
|
|
841
|
-
*/
|
|
842
|
-
async function processCaptureWriteback(writebackCoordinator, executionId) {
|
|
843
|
-
await writebackCoordinator.finalize();
|
|
844
|
-
console.log(`[ExecuteDeepAgent] capture writeback finalized for execution ${executionId}`);
|
|
845
|
-
}
|
|
846
|
-
/**
|
|
847
|
-
* Whether to seed the initial status from the persisted execution transcript.
|
|
848
|
-
*
|
|
849
|
-
* The Temporal workflow re-invokes ExecuteDeepAgent with the same thread_id on
|
|
850
|
-
* every continuation — HITL approval, pause/resume, and transient recovery. The
|
|
851
|
-
* runner owns the transcript and the server enforces it as append-only at
|
|
852
|
-
* identity, so any continuation must build ON the committed history rather than
|
|
853
|
-
* rebuilding from an empty proto and replacing it.
|
|
854
|
-
*
|
|
855
|
-
* The decision is therefore driven solely by whether the server already holds
|
|
856
|
-
* committed history for this execution — NOT by the live graph checkpoint, which
|
|
857
|
-
* the checkpointer backends leave in different states for the same continuation:
|
|
858
|
-
* - durable (sqlite, the OSS local / desktop default; and http in cloud): the
|
|
859
|
-
* checkpoint survives, the graph resumes via Command(resume), and
|
|
860
|
-
* streamEvents re-emits only post-checkpoint events;
|
|
861
|
-
* - memory (ephemeral, opt-in — used by tests): the checkpoint is recreated
|
|
862
|
-
* empty every invocation, so the graph REPLAYS from scratch and the blind
|
|
863
|
-
* FIFO turns advance one gate at a time.
|
|
864
|
-
* Keying on the live checkpoint skipped seeding on that memory-replay path, so a
|
|
865
|
-
* second sequential gate emitted a transcript holding only the new gate, dropped
|
|
866
|
-
* the first gate's committed tool-call id, and tripped the server's append-only
|
|
867
|
-
* guard — the silent sequential-gate skip. Seeding whenever persisted history
|
|
868
|
-
* exists covers both paths; a re-emitted prior turn reconciles in place by
|
|
869
|
-
* tool-call id (StatusBuilder.rebuildToolCallIndex), so seeding never
|
|
870
|
-
* duplicates. False on a first run (no persisted messages), preserving the
|
|
871
|
-
* original start-from-empty behavior.
|
|
872
|
-
*/
|
|
873
|
-
function shouldSeedFromPersistedTranscript(execution) {
|
|
874
|
-
return (execution.status?.messages.length ?? 0) > 0;
|
|
875
|
-
}
|
|
876
|
-
/**
|
|
877
|
-
* Seed a fresh status from the persisted execution transcript so streamed
|
|
878
|
-
* deltas append onto existing history rather than replacing it. The clone keeps
|
|
879
|
-
* the persisted proto immutable. Terminal fields are cleared because the resumed
|
|
880
|
-
* run is in progress again; the StatusBuilder constructor re-sets the phase.
|
|
881
|
-
*/
|
|
882
|
-
function seedStatusFromExecution(execution) {
|
|
883
|
-
const seeded = clone(AgentExecutionStatusSchema, execution.status);
|
|
884
|
-
seeded.completedAt = "";
|
|
885
|
-
seeded.error = "";
|
|
886
|
-
return seeded;
|
|
887
|
-
}
|
|
888
|
-
async function cleanup(setup) {
|
|
889
|
-
if (!setup)
|
|
890
|
-
return;
|
|
891
|
-
if (setup.mcpConnection) {
|
|
892
|
-
try {
|
|
893
|
-
await setup.mcpConnection.client.close();
|
|
894
|
-
}
|
|
895
|
-
catch (err) {
|
|
896
|
-
console.warn("[ExecuteDeepAgent] MCP connection cleanup failed:", err);
|
|
897
|
-
}
|
|
898
|
-
}
|
|
899
|
-
// Close the checkpointer's backing resources. Only the durable sqlite saver
|
|
900
|
-
// holds an OS handle (an open DB file); memory/http savers have no close(),
|
|
901
|
-
// so this is duck-typed and best-effort.
|
|
902
|
-
const closable = setup.checkpointer;
|
|
903
|
-
if (closable && typeof closable.close === "function") {
|
|
904
|
-
try {
|
|
905
|
-
closable.close();
|
|
906
|
-
}
|
|
907
|
-
catch (err) {
|
|
908
|
-
console.warn("[ExecuteDeepAgent] Checkpointer cleanup failed:", err);
|
|
909
|
-
}
|
|
910
|
-
}
|
|
911
|
-
// Drop the workspace→platform `.stigmer` symlink so an attached repo is
|
|
912
|
-
// left untouched between turns (issue #173 semantics; a multi-turn session
|
|
913
|
-
// recreates it next turn). Runs in the activity finally, BEFORE the
|
|
914
|
-
// workspace lock releases, so the next queued turn baselines a clean tree.
|
|
915
|
-
// Best-effort and symlink-only: a real `.stigmer` directory is never removed.
|
|
916
|
-
await removeStigmerSymlink(setup.workspaceBackend.rootDir);
|
|
917
|
-
}
|
|
918
|
-
//# sourceMappingURL=index.js.map
|