@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,1081 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Execution setup pipeline for the deep agent activity.
|
|
3
|
-
*
|
|
4
|
-
* Hydrates the execution from the database, resolves the full resource
|
|
5
|
-
* chain (session -> agentInstance -> agent), provisions workspace, loads
|
|
6
|
-
* MCP servers / environment, creates the LangGraph agent graph with the
|
|
7
|
-
* full middleware stack, and returns a SetupResult containing everything
|
|
8
|
-
* the streaming phase needs.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import { createDeepAgent } from "deepagents";
|
|
12
|
-
import { InteractionMode } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
|
|
13
|
-
import type { BaseCheckpointSaver } from "@langchain/langgraph-checkpoint";
|
|
14
|
-
import { z } from "zod";
|
|
15
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
16
|
-
type AgentGraph = any;
|
|
17
|
-
|
|
18
|
-
import type { AgentExecution, RecalledMemoriesReport } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
|
|
19
|
-
import type { Agent } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/api_pb";
|
|
20
|
-
import type { Session } from "@stigmer/protos/ai/stigmer/agentic/session/v1/api_pb";
|
|
21
|
-
import type { DynamicStructuredTool } from "@langchain/core/tools";
|
|
22
|
-
|
|
23
|
-
import type { Config } from "../../config.js";
|
|
24
|
-
import type { StigmerClient } from "../../client/stigmer-client.js";
|
|
25
|
-
import { TimingRecorder, emitTimingLog } from "../../shared/cold-start-timing.js";
|
|
26
|
-
import { createCheckpointer } from "../../shared/checkpointer/factory.js";
|
|
27
|
-
import { readContextBridge } from "../../shared/context-bridge.js";
|
|
28
|
-
import { readConversationCatchup } from "../../shared/conversation-catchup.js";
|
|
29
|
-
import { readSenderIdentity } from "../../shared/sender-identity.js";
|
|
30
|
-
import {
|
|
31
|
-
injectCallerIdentityEnv,
|
|
32
|
-
resolveCallerIdentity,
|
|
33
|
-
} from "../../shared/caller-identity.js";
|
|
34
|
-
import { readSessionContext } from "../../shared/session-context.js";
|
|
35
|
-
import { readDeclaredPreferences } from "../../shared/declared-preferences.js";
|
|
36
|
-
import { selectRecalledFacts } from "../../shared/memory-retrieval.js";
|
|
37
|
-
import { connectMcpServers, type McpConnectionResult } from "../../shared/mcp-manager.js";
|
|
38
|
-
import { mergeMcpServerUsages, resolveMcpServers } from "../../shared/mcp-resolver.js";
|
|
39
|
-
import { resolveMcpTransportPosture } from "../../shared/mcp-transport-guard.js";
|
|
40
|
-
import { backfillMcpServersIfNeeded } from "../../shared/connect-backfill.js";
|
|
41
|
-
import {
|
|
42
|
-
discoverChannelMessaging,
|
|
43
|
-
formatChannelTemplatesSection,
|
|
44
|
-
synthesizeChannelAttachment,
|
|
45
|
-
} from "../../shared/channel-attachment.js";
|
|
46
|
-
import {
|
|
47
|
-
readChannelConversationId,
|
|
48
|
-
synthesizeConversationAttachment,
|
|
49
|
-
} from "../../shared/conversation-attachment.js";
|
|
50
|
-
import {
|
|
51
|
-
memoryCaptureEnabled,
|
|
52
|
-
synthesizeMemoryAttachment,
|
|
53
|
-
} from "../../shared/memory-attachment.js";
|
|
54
|
-
import { injectSynthesizedAttachment } from "../../shared/synthesized-attachment.js";
|
|
55
|
-
import { shouldConnectMcp } from "./mcp-gate.js";
|
|
56
|
-
import { WorkspaceProvisioner } from "../../shared/workspace/provisioner.js";
|
|
57
|
-
import { LocalWorkspaceBackend } from "../../shared/workspace/local-backend.js";
|
|
58
|
-
import type { WorkspaceBackend, ProvisionResult } from "../../shared/workspace/types.js";
|
|
59
|
-
import { createCasCaptureBackend } from "./cas-capture-backend.js";
|
|
60
|
-
import { buildShellEnv } from "./shell-env.js";
|
|
61
|
-
import { buildPlanModePermissions } from "../../shared/plan-mode-permissions.js";
|
|
62
|
-
import { CasCaptureObserver } from "./cas-capture-observer.js";
|
|
63
|
-
import { isGitWorkTree, isPathCapturable } from "../../shared/filereview/git-substrate.js";
|
|
64
|
-
import { deriveCaptureMode } from "../../shared/filereview/capture.js";
|
|
65
|
-
import { resolveWorkspacePath } from "../../shared/file-change.js";
|
|
66
|
-
import { ensurePlatformDir, ensureCheckpointDbPath } from "../../shared/workspace/platform-dir.js";
|
|
67
|
-
import { resolveSessionWorkspaceRoot } from "../../shared/workspace/session-root.js";
|
|
68
|
-
import { buildWorkspaceFileTree } from "../../shared/workspace/file-tree.js";
|
|
69
|
-
import { reportSetupProgress } from "../../shared/status.js";
|
|
70
|
-
import { resolveEnvironment, type EnvironmentResult } from "./environment.js";
|
|
71
|
-
import { buildEnhancedSystemPrompt, composeUserMessage } from "./prompt-builder.js";
|
|
72
|
-
import { buildMiddlewareStack } from "../../middleware/index.js";
|
|
73
|
-
import type { GracefulStopMiddleware } from "../../middleware/index.js";
|
|
74
|
-
import { createThinkTool, createWebFetchTool, resolveGuardPosture } from "../../tools/index.js";
|
|
75
|
-
import type { ApprovalGateConfig } from "../../middleware/approval-gate.js";
|
|
76
|
-
import { deriveExecutionFingerprintKey } from "../../shared/approval-fingerprint.js";
|
|
77
|
-
import { getRunnerHitlMasterSecret } from "../../shared/fingerprint-secret.js";
|
|
78
|
-
import { getModelPricing, ensureLoaded as ensurePricingLoaded } from "../../shared/model-pricing.js";
|
|
79
|
-
import { getDefaultModel, getModelVisionCapability } from "../../shared/model-registry.js";
|
|
80
|
-
import { buildChatModel } from "../../shared/model-client.js";
|
|
81
|
-
import { resolveEffectiveServiceTier } from "../../shared/service-tier.js";
|
|
82
|
-
import {
|
|
83
|
-
loadArtifactStorageConfig,
|
|
84
|
-
resolveUsableArtifactStorage,
|
|
85
|
-
type ArtifactStorage,
|
|
86
|
-
} from "../../shared/artifact-storage.js";
|
|
87
|
-
import {
|
|
88
|
-
mergeApprovalPolicies,
|
|
89
|
-
deriveActiveLeases,
|
|
90
|
-
isUnattendedApprovalMode,
|
|
91
|
-
type MergedToolPolicy,
|
|
92
|
-
} from "../../shared/approval-policy.js";
|
|
93
|
-
import type { ToolApprovalCategory } from "../../shared/tool-kind.js";
|
|
94
|
-
import {
|
|
95
|
-
mergeSkillRefs,
|
|
96
|
-
fetchSkillsByRefs,
|
|
97
|
-
mountSkills,
|
|
98
|
-
generatePromptSection,
|
|
99
|
-
generateAlsoAvailableSection,
|
|
100
|
-
} from "../../shared/skill-writer.js";
|
|
101
|
-
import { filterSkills, SKILL_COUNT_THRESHOLD } from "../../shared/skill-relevance.js";
|
|
102
|
-
import { injectAttachments } from "./attachment-injector.js";
|
|
103
|
-
import {
|
|
104
|
-
DEEP_AGENT_VISION_PROFILE,
|
|
105
|
-
VisionBudget,
|
|
106
|
-
toLangChainImageBlocks,
|
|
107
|
-
type NotViewableEntry,
|
|
108
|
-
} from "../../shared/attachment-vision.js";
|
|
109
|
-
import { transformAndCompileSubagents } from "./subagent-transformer.js";
|
|
110
|
-
import {
|
|
111
|
-
resolveRecursionLimit,
|
|
112
|
-
UNBOUNDED_ADVISORY_RECURSION_LIMIT,
|
|
113
|
-
} from "../../shared/tool-rounds.js";
|
|
114
|
-
|
|
115
|
-
export interface SetupResult {
|
|
116
|
-
readonly agentGraph: AgentGraph;
|
|
117
|
-
/**
|
|
118
|
-
* The checkpoint saver backing agentGraph. Retained so the activity can close
|
|
119
|
-
* it in cleanup — the durable sqlite saver holds an open file handle. Backends
|
|
120
|
-
* without a handle (memory/http) are duck-typed for an optional close().
|
|
121
|
-
*/
|
|
122
|
-
readonly checkpointer: BaseCheckpointSaver;
|
|
123
|
-
readonly langgraphConfig: Record<string, unknown>;
|
|
124
|
-
readonly langgraphInput: Record<string, unknown>;
|
|
125
|
-
readonly execution: AgentExecution;
|
|
126
|
-
readonly agent: Agent;
|
|
127
|
-
readonly session: Session;
|
|
128
|
-
readonly workspaceBackend: WorkspaceBackend;
|
|
129
|
-
readonly mcpConnection: McpConnectionResult | null;
|
|
130
|
-
readonly mergedEnvVars: Record<string, string>;
|
|
131
|
-
readonly secretKeys: ReadonlySet<string>;
|
|
132
|
-
readonly modelName: string;
|
|
133
|
-
readonly gracefulStop: GracefulStopMiddleware;
|
|
134
|
-
/**
|
|
135
|
-
* Artifact storage for CAS blobs, tool-output offload, and attachment/plan
|
|
136
|
-
* artifacts. `undefined` only when it cannot be built (proxy transport with a
|
|
137
|
-
* missing token/endpoint — a misconfiguration; local storage never fails). Every
|
|
138
|
-
* consumer must tolerate its absence: capture degrades to the deny-gate (see
|
|
139
|
-
* `captureMode`), offload is disabled (the aggregate size guard still applies),
|
|
140
|
-
* and attachment/plan publishing surface a clear error rather than crashing.
|
|
141
|
-
*/
|
|
142
|
-
readonly artifactStorage: ArtifactStorage | undefined;
|
|
143
|
-
readonly provisionResults: readonly ProvisionResult[];
|
|
144
|
-
readonly approvalPolicies: ReadonlyMap<string, MergedToolPolicy>;
|
|
145
|
-
readonly toolServerMap: ReadonlyMap<string, string>;
|
|
146
|
-
/**
|
|
147
|
-
* Built-in approval categories with a run-lifetime scoped lease (from an
|
|
148
|
-
* interactive APPROVE_ALL). Threaded to the StatusBuilder so a leased built-in
|
|
149
|
-
* call is attributed to its lease (approval_lease) rather than the plain
|
|
150
|
-
* category gate. Empty under a global pre-arm or when no lease is active.
|
|
151
|
-
*/
|
|
152
|
-
readonly leasedCategories: ReadonlySet<ToolApprovalCategory>;
|
|
153
|
-
/**
|
|
154
|
-
* Pre-armed spec.auto_approve_all — the one unscoped, whole-run bypass. When
|
|
155
|
-
* true the approval gate is not installed at all. Interactive "approve all"
|
|
156
|
-
* decisions are NOT folded in here; they become scoped leases applied inside
|
|
157
|
-
* the gate (see ActiveLeases / deriveActiveLeases).
|
|
158
|
-
*/
|
|
159
|
-
readonly globalBypass: boolean;
|
|
160
|
-
/**
|
|
161
|
-
* Unattended approval mode (ExecutionConfig.approval_mode = UNATTENDED,
|
|
162
|
-
* stamped by approver-less surfaces — channels, guest shares). The gate
|
|
163
|
-
* resolves gated tools as automatic skips instead of interrupting; the
|
|
164
|
-
* builders never seed WAITING_APPROVAL. See isUnattendedApprovalMode.
|
|
165
|
-
*/
|
|
166
|
-
readonly unattended: boolean;
|
|
167
|
-
/**
|
|
168
|
-
* Tool-call ids the gate auto-skipped under {@link unattended} this turn.
|
|
169
|
-
* Written ONLY by the approval gate (parent + inherited sub-agent gates
|
|
170
|
-
* share this instance); read by reconcileUnattendedSkips after the stream
|
|
171
|
-
* to stamp terminal SKIPPED rows. Empty set when not unattended.
|
|
172
|
-
*/
|
|
173
|
-
readonly unattendedSkips: Set<string>;
|
|
174
|
-
readonly hasStructuredOutput: boolean;
|
|
175
|
-
readonly streamVersion: "v2" | "v3";
|
|
176
|
-
/**
|
|
177
|
-
* The single owner of this turn's CAS-capture state (design docs 08/11/12):
|
|
178
|
-
* the pre-turn bytes of first-touched gitignored paths (recorded
|
|
179
|
-
* gate-independently by the CAS-observing backends of the parent AND every
|
|
180
|
-
* sub-agent) plus the gitignored paths the gate hard-blocked as secret-like
|
|
181
|
-
* (DD-E). The turn boundary reads both to compose the CAS change set. Empty in
|
|
182
|
-
* the legacy (non-capture) path, where no CAS-observing backend is installed.
|
|
183
|
-
*/
|
|
184
|
-
readonly casObserver: CasCaptureObserver;
|
|
185
|
-
/**
|
|
186
|
-
* Apply-then-review capture mode, decided by {@link deriveCaptureMode} (shared
|
|
187
|
-
* with the Cursor harness so both degrade identically): file edits flow during
|
|
188
|
-
* the turn and are reviewed post-hoc as a captured `FileChangeSet` (the activity
|
|
189
|
-
* authors the baseline/candidate ledger events and reconciles on resume). True
|
|
190
|
-
* whenever there is a capture substrate — a git work tree (needs no storage) OR
|
|
191
|
-
* artifact storage for the non-git CAS path. False for a non-git workspace with
|
|
192
|
-
* no artifact storage (proxy misconfig): capture has no substrate, so file writes
|
|
193
|
-
* fall back to the deny-gate (gated pre-execution) exactly like Cursor's DD-22
|
|
194
|
-
* fallback. When true, the deny-gate covers only shell/MCP/irreversible tools.
|
|
195
|
-
*/
|
|
196
|
-
readonly captureMode: boolean;
|
|
197
|
-
/**
|
|
198
|
-
* True when the workspace is a git work tree. Selects the capture SUBSTRATE for
|
|
199
|
-
* this turn: git-diff (pinned baseline/after trees) when true; content-addressed
|
|
200
|
-
* CAS manifest (path-scoped to touched paths) when false. Threaded into the
|
|
201
|
-
* baseline/candidate/reconcile seam (`capture.ts`) and the CAS capture-class.
|
|
202
|
-
*/
|
|
203
|
-
readonly gitWorkspace: boolean;
|
|
204
|
-
/**
|
|
205
|
-
* The semantic retriever's injection outcome (DD-008 D5), produced at
|
|
206
|
-
* prompt build (Step 8) — the one place selection runs. The activity
|
|
207
|
-
* stamps it onto the turn's status proto before the first persist; the
|
|
208
|
-
* server's presence-guarded merge preserves it across report-less
|
|
209
|
-
* writes. Undefined when nothing was injected (recall absent, disabled,
|
|
210
|
-
* or empty) — absent report = wholesale, true by construction.
|
|
211
|
-
*/
|
|
212
|
-
readonly recalledMemoriesReport: RecalledMemoriesReport | undefined;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
export interface SetupDependencies {
|
|
216
|
-
config: Config;
|
|
217
|
-
client: StigmerClient;
|
|
218
|
-
executionId: string;
|
|
219
|
-
threadId: string;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
/**
|
|
223
|
-
* Execute all setup phases and return resources for the streaming phase.
|
|
224
|
-
*
|
|
225
|
-
* On failure, partial resources (MCP connections, workspace backend) are
|
|
226
|
-
* cleaned up internally before re-throwing.
|
|
227
|
-
*/
|
|
228
|
-
export async function performSetup(deps: SetupDependencies): Promise<SetupResult> {
|
|
229
|
-
const { config, client, executionId, threadId } = deps;
|
|
230
|
-
let mcpConnection: McpConnectionResult | null = null;
|
|
231
|
-
// Cold-start timeline of this setup (warm-agent-surfaces Phase 0): one mark
|
|
232
|
-
// after each phase, emitted as a single structured log line before return.
|
|
233
|
-
const timing = new TimingRecorder();
|
|
234
|
-
|
|
235
|
-
try {
|
|
236
|
-
// Step 1: Hydrate execution
|
|
237
|
-
await reportSetupProgress(client, executionId, "Fetching execution…");
|
|
238
|
-
const execution = await client.getExecution(executionId);
|
|
239
|
-
console.log(`[setup] Execution fetched: agent_id=${execution.spec?.agentId}`);
|
|
240
|
-
timing.mark("fetch_execution");
|
|
241
|
-
|
|
242
|
-
// Step 2: Resolve chain — execution → session → agentInstance → agent
|
|
243
|
-
await reportSetupProgress(client, executionId, "Resolving agent…");
|
|
244
|
-
const sessionId = execution.spec!.sessionId;
|
|
245
|
-
if (!sessionId) {
|
|
246
|
-
throw new Error(
|
|
247
|
-
`Session ID is required for execution ${executionId}. ` +
|
|
248
|
-
"Execution must have a valid session_id.",
|
|
249
|
-
);
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
const session = await client.getSession(sessionId);
|
|
253
|
-
const agentInstance = await client.getAgentInstance(session.spec!.agentInstanceId);
|
|
254
|
-
const agent = await client.getAgent(agentInstance.spec!.agentId);
|
|
255
|
-
|
|
256
|
-
const instructions = agent.spec!.instructions || "You are a helpful AI assistant.";
|
|
257
|
-
console.log(
|
|
258
|
-
`[setup] Chain resolved: session=${sessionId}, ` +
|
|
259
|
-
`agent=${agent.metadata!.name}`,
|
|
260
|
-
);
|
|
261
|
-
timing.mark("resolve_chain");
|
|
262
|
-
|
|
263
|
-
// Step 3: Resolve model
|
|
264
|
-
const modelName = execution.spec!.executionConfig?.modelName
|
|
265
|
-
|| await getDefaultModel();
|
|
266
|
-
|
|
267
|
-
// Step 4: Create checkpointer. The durable local (sqlite) backend keys its
|
|
268
|
-
// file per session — a session has exactly one thread (`thread-{sessionId}`),
|
|
269
|
-
// so checkpoint lifetime tracks session lifetime. The saver is closed in the
|
|
270
|
-
// activity cleanup (see index.ts), alongside the MCP connection.
|
|
271
|
-
const checkpointer = await createCheckpointer({
|
|
272
|
-
type: config.checkpointerType,
|
|
273
|
-
proxyEndpoint: config.checkpointerProxyEndpoint ?? undefined,
|
|
274
|
-
authToken: config.stigmerToken ?? undefined,
|
|
275
|
-
sqlitePath: config.checkpointerType === "sqlite"
|
|
276
|
-
? await ensureCheckpointDbPath(sessionId)
|
|
277
|
-
: undefined,
|
|
278
|
-
});
|
|
279
|
-
timing.mark("create_checkpointer");
|
|
280
|
-
|
|
281
|
-
// Step 5: Resolve environment
|
|
282
|
-
await reportSetupProgress(client, executionId, "Resolving environment…");
|
|
283
|
-
const envResult: EnvironmentResult = await resolveEnvironment(client, executionId);
|
|
284
|
-
timing.mark("resolve_environment");
|
|
285
|
-
|
|
286
|
-
// Step 6: Resolve a usable artifact store (shared with the Cursor harness so
|
|
287
|
-
// both degrade identically). Returns `undefined` — never throws — when there
|
|
288
|
-
// is no working substrate: a proxy misconfig OR an unwritable local path
|
|
289
|
-
// (which `createArtifactStorage` cannot detect, since it just holds a path).
|
|
290
|
-
// An absent store flips capture mode off (deny-gate fallback below) and
|
|
291
|
-
// disables offload, instead of flowing writes then crashing at the boundary.
|
|
292
|
-
const artifactStorage: ArtifactStorage | undefined =
|
|
293
|
-
await resolveUsableArtifactStorage(loadArtifactStorageConfig(config), { executionId });
|
|
294
|
-
timing.mark("resolve_artifact_storage");
|
|
295
|
-
|
|
296
|
-
// Step 7: Provision workspace
|
|
297
|
-
await reportSetupProgress(client, executionId, "Initializing workspace…");
|
|
298
|
-
const { workspaceBackend, provisionResults } = await provisionWorkspace(
|
|
299
|
-
config,
|
|
300
|
-
session,
|
|
301
|
-
envResult.mergedEnvVars,
|
|
302
|
-
sessionId,
|
|
303
|
-
);
|
|
304
|
-
timing.mark("provision_workspace");
|
|
305
|
-
|
|
306
|
-
// Apply-then-review is the file-review model whenever there is a capture
|
|
307
|
-
// SUBSTRATE (DD-21 D2, Slice 2b): file edits flow during the turn and are
|
|
308
|
-
// reviewed post-hoc as a captured `FileChangeSet` (reconciled byte-exactly on
|
|
309
|
-
// resume), never gated before they run. The substrate is selected by
|
|
310
|
-
// `gitWorkspace`:
|
|
311
|
-
// - a git work tree diffs a pinned baseline -> candidate tree (git-substrate,
|
|
312
|
-
// needs no artifact storage), and routes its .gitignored edits into the
|
|
313
|
-
// path-scoped CAS observer;
|
|
314
|
-
// - a non-git workspace has no git snapshot at all, so EVERY touched path is
|
|
315
|
-
// captured into the content-addressed CAS manifest (cas-substrate), which
|
|
316
|
-
// needs artifact storage to persist blobs.
|
|
317
|
-
// So a non-git workspace with NO artifact storage has no substrate: capture
|
|
318
|
-
// degrades to the deny-gate (file writes gated pre-execution), exactly like the
|
|
319
|
-
// Cursor harness (DD-22). `deriveCaptureMode` is the shared decision so both
|
|
320
|
-
// harnesses degrade identically. When capture is on, the deny-gate survives only
|
|
321
|
-
// for shell/MCP/irreversible tools.
|
|
322
|
-
const gitWorkspace = await isGitWorkTree(workspaceBackend.rootDir);
|
|
323
|
-
const captureMode = deriveCaptureMode(
|
|
324
|
-
workspaceBackend.rootDir,
|
|
325
|
-
gitWorkspace,
|
|
326
|
-
!!artifactStorage,
|
|
327
|
-
);
|
|
328
|
-
|
|
329
|
-
// Git-tracked capturability, consulted by the gate to route a file write to
|
|
330
|
-
// disk-and-git-diff (tracked) vs into CAS (ignored). Only meaningful in a git
|
|
331
|
-
// work tree. In a non-git workspace nothing is "git-capturable" (there is no
|
|
332
|
-
// snapshot), so this resolves false for every path and the gate routes all
|
|
333
|
-
// file writes through its captureIgnored (CAS) arm.
|
|
334
|
-
const isCapturablePath = gitWorkspace
|
|
335
|
-
? (rawPath: string): Promise<boolean> =>
|
|
336
|
-
isPathCapturable(
|
|
337
|
-
workspaceBackend.rootDir,
|
|
338
|
-
resolveWorkspacePath(rawPath, workspaceBackend.rootDir, true).path,
|
|
339
|
-
)
|
|
340
|
-
: (_rawPath: string): Promise<boolean> => Promise.resolve(false);
|
|
341
|
-
|
|
342
|
-
// CAS capture (design docs 08/11/12): the content-addressed half of
|
|
343
|
-
// apply-then-review. The single per-turn observer owns the before-bytes of
|
|
344
|
-
// first-touched CAS-owned paths AND the secret-blocked paths, keyed
|
|
345
|
-
// workspace-root-relative so they align with the CAS reconcile's
|
|
346
|
-
// `join(workspaceRoot, path)`. It is shared by the parent AND every sub-agent
|
|
347
|
-
// CAS backend, giving race-free first-touch-wins across concurrent graphs.
|
|
348
|
-
// Its ownership predicate is memoized, so `git check-ignore` runs at most once
|
|
349
|
-
// per distinct path.
|
|
350
|
-
const casObserver = new CasCaptureObserver({
|
|
351
|
-
rootDir: workspaceBackend.rootDir,
|
|
352
|
-
// Which touched paths the observer owns (records pre-turn bytes for). In a
|
|
353
|
-
// git work tree that is the .gitignored set only — git captures the tracked
|
|
354
|
-
// ones. In a non-git workspace there is no git substrate, so the observer
|
|
355
|
-
// owns EVERY touched path; the CAS manifest is the sole capture surface.
|
|
356
|
-
isIgnored: gitWorkspace
|
|
357
|
-
? async (relPath) => !(await isPathCapturable(workspaceBackend.rootDir, relPath))
|
|
358
|
-
: async () => true,
|
|
359
|
-
});
|
|
360
|
-
|
|
361
|
-
// Step 7: Resolve and connect MCP servers. Session-wins-per-slug merge
|
|
362
|
-
// (the Cursor harness's blueprint semantics, shared so a duplicate slug
|
|
363
|
-
// resolves identically in both harnesses — one usage per server, whose
|
|
364
|
-
// enabled_tools is the one the connect-time filter honors).
|
|
365
|
-
const mcpServerUsages = mergeMcpServerUsages(
|
|
366
|
-
agent.spec!.mcpServerUsages || [],
|
|
367
|
-
session.spec!.mcpServerUsages || [],
|
|
368
|
-
);
|
|
369
|
-
|
|
370
|
-
// The synthesized attachments' credential story (DD-006 D4): the
|
|
371
|
-
// exchanged token authenticates the discovery reads per-call (the
|
|
372
|
-
// messaging reach refuses a desktop runner's ambient embedded_runner
|
|
373
|
-
// credential; undefined lets the ambient credential apply). The
|
|
374
|
-
// attachment header falls back to the ambient credential. Unlike the
|
|
375
|
-
// env read (which hard-fails on a broken exchange — secrets are
|
|
376
|
-
// load-bearing there), this exchange is opportunistic: every consumer
|
|
377
|
-
// below degrades to an empty answer by contract, and the server
|
|
378
|
-
// refuses the ambient fallback safely, so a failed exchange must not
|
|
379
|
-
// kill the run.
|
|
380
|
-
let exchangedRunnerToken: string | undefined;
|
|
381
|
-
try {
|
|
382
|
-
exchangedRunnerToken =
|
|
383
|
-
await client.acquireScopedRunnerToken({ agentExecutionId: executionId });
|
|
384
|
-
} catch (err) {
|
|
385
|
-
console.warn(
|
|
386
|
-
"[execute-deep-agent] Scoped-token exchange failed for attachment/discovery " +
|
|
387
|
-
`reads; degrading to the ambient credential: ${err instanceof Error ? err.message : err}`,
|
|
388
|
-
);
|
|
389
|
-
}
|
|
390
|
-
const attachmentCredential = exchangedRunnerToken
|
|
391
|
-
?? config.stigmerTokenRef?.current
|
|
392
|
-
?? config.stigmerToken;
|
|
393
|
-
|
|
394
|
-
// The channel discovery read runs BEFORE the MCP gate below: an
|
|
395
|
-
// agent whose ONLY tool source is a proactive channel would
|
|
396
|
-
// otherwise never enter MCP resolution and never connect the
|
|
397
|
-
// attachment (DD-006 D7). Every failure mode degrades to an empty
|
|
398
|
-
// answer — no tool, no section, execution unharmed.
|
|
399
|
-
const channelMessaging = await discoverChannelMessaging(client, exchangedRunnerToken);
|
|
400
|
-
|
|
401
|
-
// The conversation-attachment decision (DD-008 D-c): the channel-id
|
|
402
|
-
// session label, stamped server-side on every channel session — a
|
|
403
|
-
// free, synchronous read, so no hoisted discovery needed.
|
|
404
|
-
const conversationChannelId = readChannelConversationId(session.metadata?.labels);
|
|
405
|
-
|
|
406
|
-
// The memory-attachment decision (DD-005 D1): the recall snapshot's
|
|
407
|
-
// enabled bit, stamped server-side at execution create — like the
|
|
408
|
-
// conversation attachment, a free, synchronous spec read.
|
|
409
|
-
const captureMemories = memoryCaptureEnabled(execution.spec?.recalledMemories);
|
|
410
|
-
|
|
411
|
-
let resolvedMcpServers: Awaited<ReturnType<typeof resolveMcpServers>> | null = null;
|
|
412
|
-
if (shouldConnectMcp({
|
|
413
|
-
mcpServerUsageCount: mcpServerUsages.length,
|
|
414
|
-
channelMessagingCount: channelMessaging.length,
|
|
415
|
-
conversationChannelId,
|
|
416
|
-
memoryCaptureEnabled: captureMemories,
|
|
417
|
-
})) {
|
|
418
|
-
await reportSetupProgress(client, executionId, "Connecting tools…");
|
|
419
|
-
const transportPosture = resolveMcpTransportPosture(config.mode);
|
|
420
|
-
// The MCP-bound env map (and ONLY it) carries the reserved
|
|
421
|
-
// caller-identity keys — mirror of the Cursor harness's Phase 4
|
|
422
|
-
// injection; filterEnvToDeclaredKeys keeps undeclared servers blind.
|
|
423
|
-
const mcpEnvVars = injectCallerIdentityEnv(
|
|
424
|
-
envResult.mergedEnvVars,
|
|
425
|
-
resolveCallerIdentity(
|
|
426
|
-
session.spec!.metadata,
|
|
427
|
-
session.status?.audit?.specAudit?.createdBy,
|
|
428
|
-
),
|
|
429
|
-
sessionId,
|
|
430
|
-
);
|
|
431
|
-
resolvedMcpServers = await resolveMcpServers(
|
|
432
|
-
client, mcpServerUsages, mcpEnvVars, transportPosture,
|
|
433
|
-
);
|
|
434
|
-
timing.mark("resolve_mcp_servers");
|
|
435
|
-
|
|
436
|
-
const sessionOrg = session.metadata?.org ?? "";
|
|
437
|
-
let backfilledServers = await backfillMcpServersIfNeeded(
|
|
438
|
-
client,
|
|
439
|
-
resolvedMcpServers.resolvedServers,
|
|
440
|
-
mcpServerUsages,
|
|
441
|
-
mcpEnvVars,
|
|
442
|
-
sessionOrg,
|
|
443
|
-
transportPosture,
|
|
444
|
-
undefined,
|
|
445
|
-
envResult.secretKeys,
|
|
446
|
-
);
|
|
447
|
-
|
|
448
|
-
// The channel messaging attachment (DD-006 D7/D8) — injected AFTER
|
|
449
|
-
// resolve + backfill so the destructiveHint tightener can never gate
|
|
450
|
-
// it; empty approval maps keep it approval-free by construction.
|
|
451
|
-
if (channelMessaging.length > 0) {
|
|
452
|
-
const attachment = synthesizeChannelAttachment(channelMessaging, {
|
|
453
|
-
bridgeEndpoint: config.mcpBridgeEndpoint,
|
|
454
|
-
credential: attachmentCredential,
|
|
455
|
-
backendEndpoint: config.stigmerBackendEndpoint,
|
|
456
|
-
});
|
|
457
|
-
if (attachment) {
|
|
458
|
-
backfilledServers = injectSynthesizedAttachment(
|
|
459
|
-
backfilledServers, attachment, "channel messaging",
|
|
460
|
-
);
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
// The conversation participation attachment (DD-008 D-c) — the
|
|
465
|
-
// channel attachment's sibling, same after-backfill rule. HTTP-only:
|
|
466
|
-
// synthesize answers undefined with no bridge endpoint by design (see
|
|
467
|
-
// shared/conversation-attachment.ts).
|
|
468
|
-
const conversationAttachment = synthesizeConversationAttachment(conversationChannelId, {
|
|
469
|
-
bridgeEndpoint: config.mcpBridgeEndpoint,
|
|
470
|
-
credential: attachmentCredential,
|
|
471
|
-
backendEndpoint: config.stigmerBackendEndpoint,
|
|
472
|
-
});
|
|
473
|
-
if (conversationAttachment) {
|
|
474
|
-
backfilledServers = injectSynthesizedAttachment(
|
|
475
|
-
backfilledServers, conversationAttachment, "conversation participation",
|
|
476
|
-
);
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
// The memory capture attachment (DD-005 D1) — same after-backfill
|
|
480
|
-
// rule. The capture context is attribution the server verifies or
|
|
481
|
-
// trusts per edition (Stage 3 provenance decision); the subject is
|
|
482
|
-
// never threaded — it derives from the credential.
|
|
483
|
-
if (captureMemories) {
|
|
484
|
-
const memoryAttachment = synthesizeMemoryAttachment(
|
|
485
|
-
execution.spec?.recalledMemories,
|
|
486
|
-
{
|
|
487
|
-
org: session.metadata?.org ?? "",
|
|
488
|
-
agentId: agent.metadata?.id ?? "",
|
|
489
|
-
sessionId,
|
|
490
|
-
agentExecutionId: executionId,
|
|
491
|
-
},
|
|
492
|
-
{
|
|
493
|
-
bridgeEndpoint: config.mcpBridgeEndpoint,
|
|
494
|
-
credential: attachmentCredential,
|
|
495
|
-
backendEndpoint: config.stigmerBackendEndpoint,
|
|
496
|
-
},
|
|
497
|
-
);
|
|
498
|
-
if (memoryAttachment) {
|
|
499
|
-
backfilledServers = injectSynthesizedAttachment(
|
|
500
|
-
backfilledServers, memoryAttachment, "memory capture",
|
|
501
|
-
);
|
|
502
|
-
}
|
|
503
|
-
}
|
|
504
|
-
resolvedMcpServers = { resolvedServers: backfilledServers };
|
|
505
|
-
timing.mark("backfill_mcp");
|
|
506
|
-
|
|
507
|
-
// connect_mcp covers the whole fan-out: stdio servers spawn npx/uvx
|
|
508
|
-
// subprocesses here, so on-demand package installs land in this span.
|
|
509
|
-
mcpConnection = await connectMcpServers(resolvedMcpServers.resolvedServers);
|
|
510
|
-
timing.mark("connect_mcp");
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
// Step 7b: Resolve and write skills
|
|
514
|
-
const skillRefs = mergeSkillRefs(
|
|
515
|
-
agent.spec!.skillRefs || [],
|
|
516
|
-
session.spec!.skillRefs || [],
|
|
517
|
-
);
|
|
518
|
-
|
|
519
|
-
let skillsPromptSection = "";
|
|
520
|
-
if (skillRefs.length > 0) {
|
|
521
|
-
await reportSetupProgress(client, executionId, "Loading skills…");
|
|
522
|
-
const skills = await fetchSkillsByRefs(client, skillRefs);
|
|
523
|
-
|
|
524
|
-
if (skills.length > 0) {
|
|
525
|
-
// platformDir is an invariant of this path: provisionWorkspace below
|
|
526
|
-
// threads ensurePlatformDir into every backend it constructs.
|
|
527
|
-
const { paths: skillPaths } = await mountSkills(
|
|
528
|
-
client, skills, workspaceBackend.platformDir!,
|
|
529
|
-
);
|
|
530
|
-
|
|
531
|
-
const userMessage = execution.spec!.message || "";
|
|
532
|
-
const skillNames = skills.map(s => s.spec?.name || s.metadata?.slug || "unknown");
|
|
533
|
-
const skillDescriptions = skills.map(s => s.spec?.description || "");
|
|
534
|
-
|
|
535
|
-
if (skills.length >= SKILL_COUNT_THRESHOLD) {
|
|
536
|
-
const filterResult = filterSkills(userMessage, skillNames, skillDescriptions);
|
|
537
|
-
if (filterResult.excludedNames.length > 0) {
|
|
538
|
-
const includedSkills = filterResult.includedIndices.map(i => skills[i]);
|
|
539
|
-
console.log(
|
|
540
|
-
`[setup] Skill relevance filter: ${includedSkills.length} included, ` +
|
|
541
|
-
`${filterResult.excludedNames.length} excluded: ${filterResult.excludedNames.join(", ")}`,
|
|
542
|
-
);
|
|
543
|
-
skillsPromptSection =
|
|
544
|
-
generatePromptSection(includedSkills, skillPaths) +
|
|
545
|
-
generateAlsoAvailableSection(filterResult.excludedNames);
|
|
546
|
-
} else {
|
|
547
|
-
skillsPromptSection = generatePromptSection(skills, skillPaths);
|
|
548
|
-
}
|
|
549
|
-
} else {
|
|
550
|
-
skillsPromptSection = generatePromptSection(skills, skillPaths);
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
console.log(
|
|
554
|
-
`[setup] Skills loaded: ${skills.length} total, prompt section ${skillsPromptSection.length} chars`,
|
|
555
|
-
);
|
|
556
|
-
}
|
|
557
|
-
timing.mark("resolve_skills");
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
// Step 7c: Inject attachments. The vision budget rides along so image
|
|
561
|
-
// attachments are selected for inline delivery while their bytes are
|
|
562
|
-
// already in hand (attachment-vision.ts owns all policy). The budget
|
|
563
|
-
// also carries the root model's registry vision capability — the root
|
|
564
|
-
// model is the only one that ever receives inline image blocks
|
|
565
|
-
// (sub-agents get a fresh task description, summarization reuses this
|
|
566
|
-
// same model instance) — so a model flagged `vision: false` degrades
|
|
567
|
-
// images honestly instead of shipping a payload its provider rejects.
|
|
568
|
-
const attachments = execution.spec!.attachments || [];
|
|
569
|
-
const visionBudget = new VisionBudget(DEEP_AGENT_VISION_PROFILE, {
|
|
570
|
-
modelVision: await getModelVisionCapability(modelName),
|
|
571
|
-
});
|
|
572
|
-
const injectedFiles = await injectAttachments({
|
|
573
|
-
backend: workspaceBackend,
|
|
574
|
-
attachments,
|
|
575
|
-
storage: artifactStorage,
|
|
576
|
-
isLocalMode: config.mode === "local",
|
|
577
|
-
visionBudget,
|
|
578
|
-
});
|
|
579
|
-
// Vision facts, derived once from the single injection result: the images
|
|
580
|
-
// the model will see inline (in attachment order) and the ones that
|
|
581
|
-
// degraded to path-only, disclosed in the system prompt's Input Files
|
|
582
|
-
// section.
|
|
583
|
-
const visionImages = injectedFiles.flatMap((f) => (f.vision ? [f.vision] : []));
|
|
584
|
-
const visionNotViewable: NotViewableEntry[] = injectedFiles.flatMap((f) =>
|
|
585
|
-
f.visionDegraded ? [{ path: f.path, reason: f.visionDegraded }] : [],
|
|
586
|
-
);
|
|
587
|
-
const visionPromptInfo = visionImages.length > 0 || visionNotViewable.length > 0
|
|
588
|
-
? {
|
|
589
|
-
inlineFilenames: visionImages.map((v) => v.filename),
|
|
590
|
-
notViewable: visionNotViewable,
|
|
591
|
-
}
|
|
592
|
-
: undefined;
|
|
593
|
-
if (visionPromptInfo) {
|
|
594
|
-
console.log(
|
|
595
|
-
`[attachment-vision] execution=${executionId} inline=${visionImages.length} ` +
|
|
596
|
-
`(${visionImages.reduce((n, v) => n + v.byteSize, 0)} bytes) ` +
|
|
597
|
-
`degraded=${JSON.stringify(visionNotViewable.map((d) => `${d.path}:${d.reason}`))}`,
|
|
598
|
-
);
|
|
599
|
-
}
|
|
600
|
-
timing.mark("inject_attachments");
|
|
601
|
-
|
|
602
|
-
// Step 8: Build enhanced system prompt.
|
|
603
|
-
//
|
|
604
|
-
// Recalled memories go through the semantic retriever (DD-008), not the
|
|
605
|
-
// raw snapshot read: above the activation threshold it selects the
|
|
606
|
-
// top-k facts for THIS turn's message (one batched embeddings call);
|
|
607
|
-
// otherwise — and on any failure — it injects the full candidate set,
|
|
608
|
-
// exactly the Phase 2 behavior. A re-invocation of this execution
|
|
609
|
-
// (approval resume) replays the outcome recorded on the execution's
|
|
610
|
-
// status instead of re-selecting, so the prompt never shifts
|
|
611
|
-
// mid-execution. The report returned here is stamped onto the turn's
|
|
612
|
-
// status by the activity (index.ts) — setup has no status object yet.
|
|
613
|
-
const memorySelection = await selectRecalledFacts(
|
|
614
|
-
execution.spec!.recalledMemories,
|
|
615
|
-
execution.spec!.message,
|
|
616
|
-
{
|
|
617
|
-
proxyEndpoint: config.proxyEndpoint,
|
|
618
|
-
stigmerToken: config.stigmerToken,
|
|
619
|
-
executionId,
|
|
620
|
-
priorReport: execution.status?.recalledMemoriesReport,
|
|
621
|
-
},
|
|
622
|
-
);
|
|
623
|
-
const systemPrompt = buildEnhancedSystemPrompt({
|
|
624
|
-
instructions,
|
|
625
|
-
provisionResults,
|
|
626
|
-
containerRoot: workspaceBackend.rootDir,
|
|
627
|
-
skillsPromptSection,
|
|
628
|
-
// "" (nothing sendable) threads as undefined: the tool alone still
|
|
629
|
-
// serves text sends inside a 24-hour window (DD-006 D6).
|
|
630
|
-
channelTemplatesPromptSection: channelMessaging.length > 0
|
|
631
|
-
? formatChannelTemplatesSection(channelMessaging) || undefined
|
|
632
|
-
: undefined,
|
|
633
|
-
workspaceFileRefs: execution.spec!.workspaceFileRefs || [],
|
|
634
|
-
workspaceRoot: workspaceBackend.rootDir,
|
|
635
|
-
injectedFiles,
|
|
636
|
-
vision: visionPromptInfo,
|
|
637
|
-
downloadUrlKind: artifactStorage?.downloadUrlKind,
|
|
638
|
-
interactionMode: execution.spec!.executionConfig?.interactionMode,
|
|
639
|
-
buildFromPlan: execution.spec!.executionConfig?.buildFromPlan,
|
|
640
|
-
contextBridge: readContextBridge(session.spec!.metadata),
|
|
641
|
-
senderIdentity: readSenderIdentity(session.spec!.metadata),
|
|
642
|
-
sessionContext: readSessionContext(session.spec!.metadata),
|
|
643
|
-
declaredPreferences: readDeclaredPreferences(
|
|
644
|
-
execution.spec!.declaredPreferences,
|
|
645
|
-
),
|
|
646
|
-
recalledMemories: memorySelection.content,
|
|
647
|
-
});
|
|
648
|
-
|
|
649
|
-
// Step 9: Construct the LLM model. Resolution to the provider API id
|
|
650
|
-
// happens inside buildChatModel; modelName stays the registry id for
|
|
651
|
-
// pricing, the native-thinking heuristic, and sub-agent inheritance.
|
|
652
|
-
// The operator's STIGMER_LLM_REQUEST_TIMEOUT_MS bound is applied inside
|
|
653
|
-
// buildChatModel (#468) — the sub-agent modelFactory below silently
|
|
654
|
-
// dropped it when each caller parsed the env itself.
|
|
655
|
-
//
|
|
656
|
-
// The service tier resolves ONCE here (UNSPECIFIED → explicit
|
|
657
|
-
// STANDARD, shared/service-tier.ts) and rides every model this
|
|
658
|
-
// execution constructs — the primary below AND the sub-agent factory —
|
|
659
|
-
// so the provider account's default can never pick the price of any
|
|
660
|
-
// turn (#361, the native half of #357's contract). Sub-agents inherit
|
|
661
|
-
// it because the tier is an attribute of the EXECUTION's bill, and
|
|
662
|
-
// sub-agent calls land on the same ledger.
|
|
663
|
-
const serviceTier = resolveEffectiveServiceTier(
|
|
664
|
-
execution.spec!.executionConfig?.serviceTier);
|
|
665
|
-
const { model } = await buildChatModel({
|
|
666
|
-
modelName,
|
|
667
|
-
proxyEndpoint: config.proxyEndpoint ?? undefined,
|
|
668
|
-
stigmerToken: config.stigmerToken ?? undefined,
|
|
669
|
-
headerScope: { executionId },
|
|
670
|
-
serviceTier,
|
|
671
|
-
});
|
|
672
|
-
timing.mark("build_model");
|
|
673
|
-
|
|
674
|
-
// Step 10: Build middleware stack
|
|
675
|
-
await ensurePricingLoaded();
|
|
676
|
-
const pricing = getModelPricing(modelName);
|
|
677
|
-
const execConfig = execution.spec!.executionConfig;
|
|
678
|
-
const isPlanMode = execConfig?.interactionMode === InteractionMode.PLAN;
|
|
679
|
-
const shellEnv = isPlanMode ? undefined : buildShellEnv(envResult.mergedEnvVars);
|
|
680
|
-
// Plan mode's filesystem permission rules, hoisted once: the parent graph
|
|
681
|
-
// and every sub-agent graph carry this single value. The rules are the
|
|
682
|
-
// write-deny half of plan mode only — the read boundary is structural
|
|
683
|
-
// (virtual-rooted backends, issue #754), and the path-normalization shim
|
|
684
|
-
// is no longer tied to the rules: every native graph installs it (see
|
|
685
|
-
// buildMiddlewareStack below) so the whole harness speaks one dialect.
|
|
686
|
-
const planModePermissions = isPlanMode ? buildPlanModePermissions() : undefined;
|
|
687
|
-
|
|
688
|
-
const toolServerMap = new Map<string, string>();
|
|
689
|
-
if (mcpConnection) {
|
|
690
|
-
for (const [serverName, serverTools] of Object.entries(mcpConnection.serverToolMap)) {
|
|
691
|
-
for (const t of serverTools) {
|
|
692
|
-
toolServerMap.set(t.name, serverName);
|
|
693
|
-
}
|
|
694
|
-
}
|
|
695
|
-
}
|
|
696
|
-
|
|
697
|
-
// Step 10b: Resolve approval policies + leases.
|
|
698
|
-
//
|
|
699
|
-
// Two distinct bypasses (see ActiveLeases): the pre-armed
|
|
700
|
-
// spec.auto_approve_all is the one whole-run global bypass; an interactive
|
|
701
|
-
// APPROVE_ALL grants a run-lifetime lease scoped to that action's class (its
|
|
702
|
-
// built-in category, or its MCP server). Server leases shape the policy map
|
|
703
|
-
// (leased servers dropped); built-in category leases are applied inside the
|
|
704
|
-
// gate. Both flow into sub-agents via the shared config below.
|
|
705
|
-
const leases = deriveActiveLeases(execution);
|
|
706
|
-
const globalBypass = leases.global;
|
|
707
|
-
// Layer-3 overrides ride each resolved server from its (session-wins
|
|
708
|
-
// merged) usage — see ResolvedMcpServer.toolApprovalOverrides (issue
|
|
709
|
-
// #349) — so there is no separate override input to pass here.
|
|
710
|
-
const approvalPolicies = mergeApprovalPolicies(
|
|
711
|
-
resolvedMcpServers?.resolvedServers ?? [],
|
|
712
|
-
leases,
|
|
713
|
-
);
|
|
714
|
-
|
|
715
|
-
// Unattended approval mode (DD-014): approver-less surfaces (channels,
|
|
716
|
-
// guest shares) stamp APPROVAL_MODE_UNATTENDED, and the gate resolves
|
|
717
|
-
// gated tools as automatic skips instead of interrupting. The registry is
|
|
718
|
-
// the gate→reconciler channel for the skipped tool-call ids; one instance
|
|
719
|
-
// is shared with sub-agent gates via the inherited config.
|
|
720
|
-
const unattended = isUnattendedApprovalMode(execution);
|
|
721
|
-
const unattendedSkips = new Set<string>();
|
|
722
|
-
|
|
723
|
-
// The approval gate config is the single source of truth for HITL gating,
|
|
724
|
-
// built once and inherited verbatim by sub-agents (so a mutating tool inside
|
|
725
|
-
// a sub-agent is gated identically to one in the parent). Null under the
|
|
726
|
-
// global pre-arm, where the gate is inert; under scoped leases the gate stays
|
|
727
|
-
// active and clears only leased categories. The per-execution fingerprint key
|
|
728
|
-
// (runner master secret + execution_id) drives the shadow ExecutionReceipt.
|
|
729
|
-
const approvalGateConfig: ApprovalGateConfig | null = !globalBypass
|
|
730
|
-
? {
|
|
731
|
-
policies: approvalPolicies,
|
|
732
|
-
leasedCategories: leases.categories,
|
|
733
|
-
toolServerMap,
|
|
734
|
-
fingerprintKey: deriveExecutionFingerprintKey(
|
|
735
|
-
getRunnerHitlMasterSecret(),
|
|
736
|
-
executionId,
|
|
737
|
-
),
|
|
738
|
-
executionId,
|
|
739
|
-
// Capture mode: file edits flow and are reviewed post-hoc. In a git work
|
|
740
|
-
// tree, git-tracked edits flow to the git diff and .gitignored edits flow
|
|
741
|
-
// into CAS (captureIgnored) on THIS parent gate; in a non-git workspace
|
|
742
|
-
// isCapturablePath is always false, so ALL file writes take the CAS arm.
|
|
743
|
-
// Secret-like paths are hard-blocked (DD-E) and recorded for a
|
|
744
|
-
// DIFF_UNREVIEWABLE entry. shell/MCP stay gated. Sub-agents inherit this
|
|
745
|
-
// config; buildSubAgentMiddleware sets their captureIgnored explicitly
|
|
746
|
-
// from whether a CAS observer backs the sub-agent (Session 26, DD-19),
|
|
747
|
-
// so their captured edits flow into the SAME observer.
|
|
748
|
-
//
|
|
749
|
-
// When captureMode is false (no substrate — non-git + no storage),
|
|
750
|
-
// fileCaptureMode is false so file writes take the plain deny-gate. The
|
|
751
|
-
// CAS arm additionally requires storage: captureIgnored gates gitignored
|
|
752
|
-
// writes onto CAS only when a store exists to persist their blobs (the
|
|
753
|
-
// git+no-storage case), matching the Cursor harness's
|
|
754
|
-
// `captureMode && !!artifactStorage`.
|
|
755
|
-
fileCaptureMode: captureMode,
|
|
756
|
-
isCapturablePath,
|
|
757
|
-
captureIgnored: captureMode && !!artifactStorage,
|
|
758
|
-
recordBlockedSecret: (rawPath: string) => casObserver.recordBlockedSecret(rawPath),
|
|
759
|
-
// Pre-delete byte capture (issue #303): deepagents has no backend
|
|
760
|
-
// delete method for the CAS backend to observe, so a flowing delete's
|
|
761
|
-
// before-bytes are recorded by the gate at authorization time, through
|
|
762
|
-
// the SAME shared observer — the turn boundary then reads after=null
|
|
763
|
-
// and authors a reviewable, restorable DELETE. recordBefore's own
|
|
764
|
-
// ownership predicate (gitignored-only in a git tree, everything in
|
|
765
|
-
// non-git) agrees with the gate's not-capturable condition.
|
|
766
|
-
captureDeleteBefore: (rawPath: string) => casObserver.recordBefore(rawPath),
|
|
767
|
-
unattended,
|
|
768
|
-
unattendedSkips,
|
|
769
|
-
}
|
|
770
|
-
: null;
|
|
771
|
-
|
|
772
|
-
const maxCostUsd = execConfig?.maxCostUsd ?? 0;
|
|
773
|
-
// max_tool_rounds → recursion limit (proto contract: 0/unset = unlimited,
|
|
774
|
-
// set = clamped 10–1000 and enforced). One resolved value feeds BOTH the
|
|
775
|
-
// hard stop on the invoke config below and the budget middleware's ~80%
|
|
776
|
-
// wrap-up advisory, so the warning and the enforcement can never disagree.
|
|
777
|
-
const recursionLimit = resolveRecursionLimit(execConfig?.maxToolRounds);
|
|
778
|
-
const { middleware, gracefulStop, costCap: costCapMiddleware } = buildMiddlewareStack({
|
|
779
|
-
loopDetection: {
|
|
780
|
-
historySize: 20,
|
|
781
|
-
consecutiveThreshold: 7,
|
|
782
|
-
totalThreshold: 20,
|
|
783
|
-
},
|
|
784
|
-
executionBudget: {
|
|
785
|
-
recursionLimit: recursionLimit ?? UNBOUNDED_ADVISORY_RECURSION_LIMIT,
|
|
786
|
-
warningPct: 80,
|
|
787
|
-
},
|
|
788
|
-
toolTruncation: {
|
|
789
|
-
maxChars: execConfig?.maxToolResultChars || 30_000,
|
|
790
|
-
},
|
|
791
|
-
costCap: maxCostUsd > 0 ? {
|
|
792
|
-
maxCostUsd,
|
|
793
|
-
inputPricePerMillion: pricing.inputPricePerMillion,
|
|
794
|
-
outputPricePerMillion: pricing.outputPricePerMillion,
|
|
795
|
-
cacheReadPricePerMillion: pricing.cacheReadPricePerMillion,
|
|
796
|
-
warningPct: 80,
|
|
797
|
-
} : null,
|
|
798
|
-
otelSpans: { toolServerMap },
|
|
799
|
-
approvalGate: approvalGateConfig,
|
|
800
|
-
// Every graph, every mode (issue #754): the dialect-repair seam that
|
|
801
|
-
// keeps model-supplied paths canonical for the virtual-rooted backend
|
|
802
|
-
// and every downstream consumer (gate, capture, spans).
|
|
803
|
-
pathNormalization: { rootDir: workspaceBackend.rootDir },
|
|
804
|
-
});
|
|
805
|
-
timing.mark("build_middleware");
|
|
806
|
-
|
|
807
|
-
// Step 11: Build tools list (MCP tools + native built-in tools).
|
|
808
|
-
//
|
|
809
|
-
// web_fetch is always-on for every native run — the same posture as the
|
|
810
|
-
// Cursor harness, whose WebFetch is a CLI built-in that no configuration
|
|
811
|
-
// removes (issue #214 parity). It is auto-approved by design (see
|
|
812
|
-
// toolApprovalCategory in shared/tool-kind.ts), so its URL guard posture
|
|
813
|
-
// — strict on managed cloud runners, relaxed on user-owned machines — is
|
|
814
|
-
// the entire safety boundary. Derived from config.mode, NOT the
|
|
815
|
-
// cloudModeEnabled Cursor feature flag.
|
|
816
|
-
const webFetchPosture = resolveGuardPosture(config.mode);
|
|
817
|
-
const tools = [
|
|
818
|
-
...(mcpConnection?.tools as DynamicStructuredTool[] ?? []),
|
|
819
|
-
createThinkTool(),
|
|
820
|
-
createWebFetchTool({ posture: webFetchPosture }),
|
|
821
|
-
];
|
|
822
|
-
|
|
823
|
-
// Step 11b: Transform and compile subagents
|
|
824
|
-
const subAgentProtos = agent.spec!.subAgents || [];
|
|
825
|
-
let compiledSubagents: Awaited<ReturnType<typeof transformAndCompileSubagents>> | undefined;
|
|
826
|
-
|
|
827
|
-
if (subAgentProtos.length > 0 || workspaceBackend.rootDir) {
|
|
828
|
-
await reportSetupProgress(client, executionId, "Configuring sub-agents…");
|
|
829
|
-
|
|
830
|
-
const parentMcpServerToolMap = new Map<string, DynamicStructuredTool[]>();
|
|
831
|
-
if (mcpConnection) {
|
|
832
|
-
for (const [serverName, serverTools] of Object.entries(mcpConnection.serverToolMap)) {
|
|
833
|
-
parentMcpServerToolMap.set(serverName, serverTools as DynamicStructuredTool[]);
|
|
834
|
-
}
|
|
835
|
-
}
|
|
836
|
-
|
|
837
|
-
compiledSubagents = await transformAndCompileSubagents({
|
|
838
|
-
subAgents: subAgentProtos,
|
|
839
|
-
parentMcpTools: mcpConnection?.tools as DynamicStructuredTool[] ?? [],
|
|
840
|
-
parentMcpServerToolMap,
|
|
841
|
-
parentMcpUsages: mcpServerUsages,
|
|
842
|
-
skillClient: client,
|
|
843
|
-
workspaceBackend,
|
|
844
|
-
approvalGate: approvalGateConfig,
|
|
845
|
-
// Capture is universal (Slice 2b), so every sub-agent gets a CAS-observing
|
|
846
|
-
// backend wired to the SAME per-turn observer as the parent — their
|
|
847
|
-
// captured writes (.gitignored in a git tree, all touched paths in a
|
|
848
|
-
// non-git one) compose into the parent's change set (Session 26, DD-19).
|
|
849
|
-
casObserver,
|
|
850
|
-
parentModelName: modelName,
|
|
851
|
-
parentHasNativeThinking: _modelHasNativeThinking(modelName),
|
|
852
|
-
webFetchPosture,
|
|
853
|
-
costCap: costCapMiddleware ?? undefined,
|
|
854
|
-
modelFactory: async (m: string) =>
|
|
855
|
-
(await buildChatModel({
|
|
856
|
-
modelName: m,
|
|
857
|
-
proxyEndpoint: config.proxyEndpoint ?? undefined,
|
|
858
|
-
stigmerToken: config.stigmerToken ?? undefined,
|
|
859
|
-
headerScope: { executionId },
|
|
860
|
-
// The execution's tier, inherited: sub-agent calls bill to the
|
|
861
|
-
// same execution (#361 — see the Step 9 resolution comment).
|
|
862
|
-
serviceTier,
|
|
863
|
-
})).model,
|
|
864
|
-
// Presence of shellEnv is the shell-capability switch for sub-agent
|
|
865
|
-
// backends too (undefined in plan mode; see buildShellEnv above).
|
|
866
|
-
shellEnv,
|
|
867
|
-
// Plan mode's deny-all-writes rule, mirrored onto every sub-agent graph
|
|
868
|
-
// (issue #255) — pre-built CompiledSubAgents never inherit the parent's
|
|
869
|
-
// permissions, so read-only-by-construction must be baked in here.
|
|
870
|
-
// compileSubagents derives each sub-agent's path-normalization shim
|
|
871
|
-
// from this same value (issue #429).
|
|
872
|
-
...(planModePermissions ? { permissions: planModePermissions } : {}),
|
|
873
|
-
});
|
|
874
|
-
timing.mark("compile_subagents");
|
|
875
|
-
}
|
|
876
|
-
|
|
877
|
-
// Step 12: Create the agent graph with middleware
|
|
878
|
-
await reportSetupProgress(client, executionId, "Creating agent…");
|
|
879
|
-
|
|
880
|
-
const outputSchema = execution.spec!.executionConfig?.structuredOutputSchema;
|
|
881
|
-
let responseFormat: z.ZodType | undefined;
|
|
882
|
-
if (outputSchema) {
|
|
883
|
-
responseFormat = jsonSchemaToZod(outputSchema as unknown as Record<string, unknown>);
|
|
884
|
-
}
|
|
885
|
-
|
|
886
|
-
// File capture point. Apply-then-review is universal (Slice 2b), so the
|
|
887
|
-
// CAS-observing backend: git-tracked edits flow to disk (the turn-boundary
|
|
888
|
-
// git diff is authoritative), and the shared CAS observer records the pre-turn
|
|
889
|
-
// bytes of every CAS-owned path — .gitignored paths in a git work tree, all
|
|
890
|
-
// touched paths in a non-git one — so the boundary can capture them into CAS.
|
|
891
|
-
// It is gate-independent, so it holds even under the global bypass.
|
|
892
|
-
const fileBackend = await createCasCaptureBackend({
|
|
893
|
-
rootDir: workspaceBackend.rootDir,
|
|
894
|
-
observer: casObserver,
|
|
895
|
-
shellEnv,
|
|
896
|
-
});
|
|
897
|
-
const agentGraph = await createDeepAgent({
|
|
898
|
-
model,
|
|
899
|
-
checkpointer: checkpointer as any,
|
|
900
|
-
backend: fileBackend,
|
|
901
|
-
systemPrompt,
|
|
902
|
-
tools,
|
|
903
|
-
middleware: middleware as any,
|
|
904
|
-
subagents: compiledSubagents ?? undefined,
|
|
905
|
-
...(responseFormat ? { responseFormat } : {}),
|
|
906
|
-
...(planModePermissions ? { permissions: planModePermissions } : {}),
|
|
907
|
-
} as Parameters<typeof createDeepAgent>[0]);
|
|
908
|
-
|
|
909
|
-
// Step 11: Prepare invocation input and config. The conversation catchup
|
|
910
|
-
// (cloud DD-006) rides the USER MESSAGE, not the system prompt — see
|
|
911
|
-
// composeUserMessage for the durability rationale (A27).
|
|
912
|
-
let userMessage = composeUserMessage(
|
|
913
|
-
execution.spec!.message,
|
|
914
|
-
readConversationCatchup(execution.spec!.conversationCatchup),
|
|
915
|
-
);
|
|
916
|
-
if (outputSchema) {
|
|
917
|
-
userMessage += `\n\n---\nIMPORTANT: When your analysis is complete, provide your findings as structured output matching the required schema. The system will capture your structured response automatically.`;
|
|
918
|
-
}
|
|
919
|
-
// With inline images the user message becomes a multimodal content-block
|
|
920
|
-
// array — image blocks (with filename labels) FIRST, the composed text
|
|
921
|
-
// last, per Anthropic's images-before-text guidance. Without images the
|
|
922
|
-
// content stays a plain string, byte-identical to the pre-vision shape.
|
|
923
|
-
// The LangGraph messages reducer coerces either form into a HumanMessage
|
|
924
|
-
// untouched (verified against the installed @langchain/langgraph).
|
|
925
|
-
const langgraphInput = {
|
|
926
|
-
messages: [
|
|
927
|
-
{
|
|
928
|
-
role: "user",
|
|
929
|
-
content: visionImages.length > 0
|
|
930
|
-
? [
|
|
931
|
-
...toLangChainImageBlocks(visionImages),
|
|
932
|
-
{ type: "text", text: userMessage },
|
|
933
|
-
]
|
|
934
|
-
: userMessage,
|
|
935
|
-
},
|
|
936
|
-
],
|
|
937
|
-
};
|
|
938
|
-
|
|
939
|
-
const langgraphConfig: Record<string, unknown> = {
|
|
940
|
-
configurable: { thread_id: threadId },
|
|
941
|
-
// Hard enforcement of max_tool_rounds (null = unlimited, the default):
|
|
942
|
-
// when the graph exhausts this, the streaming loop's GraphRecursionError
|
|
943
|
-
// handler terminates gracefully with work saved ("send another message
|
|
944
|
-
// to continue"). The middleware's wrap-up advisory fires at ~80% of the
|
|
945
|
-
// same value, so a healthy run finishes normally before ever hitting it.
|
|
946
|
-
...(recursionLimit !== null ? { recursionLimit } : {}),
|
|
947
|
-
};
|
|
948
|
-
|
|
949
|
-
const streamVersion: "v2" | "v3" =
|
|
950
|
-
process.env.LANGGRAPH_STREAM_EVENTS_VERSION === "v2" ? "v2" : "v3";
|
|
951
|
-
|
|
952
|
-
console.log(
|
|
953
|
-
`[setup] Complete: model=${modelName}, ` +
|
|
954
|
-
`tools=${tools.length}, middleware=${middleware.length}, ` +
|
|
955
|
-
`thread_id=${threadId}, streamVersion=${streamVersion}`,
|
|
956
|
-
);
|
|
957
|
-
timing.mark("create_agent_graph");
|
|
958
|
-
emitTimingLog("execution_setup", {
|
|
959
|
-
execution_id: executionId,
|
|
960
|
-
session_id: sessionId,
|
|
961
|
-
harness: "native",
|
|
962
|
-
mcp_server_count: mcpServerUsages.length,
|
|
963
|
-
skill_count: skillRefs.length,
|
|
964
|
-
workspace_entry_count: session.spec!.workspaceEntries?.length ?? 0,
|
|
965
|
-
}, timing);
|
|
966
|
-
|
|
967
|
-
return {
|
|
968
|
-
agentGraph,
|
|
969
|
-
checkpointer,
|
|
970
|
-
langgraphConfig,
|
|
971
|
-
langgraphInput,
|
|
972
|
-
execution,
|
|
973
|
-
agent,
|
|
974
|
-
session,
|
|
975
|
-
workspaceBackend,
|
|
976
|
-
mcpConnection,
|
|
977
|
-
mergedEnvVars: envResult.mergedEnvVars,
|
|
978
|
-
secretKeys: envResult.secretKeys,
|
|
979
|
-
modelName,
|
|
980
|
-
gracefulStop,
|
|
981
|
-
artifactStorage,
|
|
982
|
-
provisionResults,
|
|
983
|
-
approvalPolicies,
|
|
984
|
-
toolServerMap,
|
|
985
|
-
leasedCategories: leases.categories,
|
|
986
|
-
globalBypass,
|
|
987
|
-
unattended,
|
|
988
|
-
unattendedSkips,
|
|
989
|
-
hasStructuredOutput: !!outputSchema,
|
|
990
|
-
streamVersion,
|
|
991
|
-
casObserver,
|
|
992
|
-
captureMode,
|
|
993
|
-
gitWorkspace,
|
|
994
|
-
recalledMemoriesReport: memorySelection.report,
|
|
995
|
-
};
|
|
996
|
-
} catch (err) {
|
|
997
|
-
if (mcpConnection) {
|
|
998
|
-
try { await mcpConnection.client.close(); } catch { /* swallow */ }
|
|
999
|
-
}
|
|
1000
|
-
throw err;
|
|
1001
|
-
}
|
|
1002
|
-
}
|
|
1003
|
-
|
|
1004
|
-
/**
|
|
1005
|
-
* Provision workspace from session workspace entries.
|
|
1006
|
-
*
|
|
1007
|
-
* A session with no entries gets its own empty per-session directory (see
|
|
1008
|
-
* shared/workspace/session-root.ts) — never the shared root, which would
|
|
1009
|
-
* leak other sessions' files into it. Mirrors shared/workspace/
|
|
1010
|
-
* session-provision.ts `provisionSessionWorkspace` exactly; S3 of the
|
|
1011
|
-
* harness runtime program retires this twin in favor of that one.
|
|
1012
|
-
*/
|
|
1013
|
-
async function provisionWorkspace(
|
|
1014
|
-
config: Config,
|
|
1015
|
-
session: Session,
|
|
1016
|
-
mergedEnvVars: Record<string, string>,
|
|
1017
|
-
sessionId: string,
|
|
1018
|
-
): Promise<{ workspaceBackend: WorkspaceBackend; provisionResults: ProvisionResult[] }> {
|
|
1019
|
-
const platformDir = await ensurePlatformDir(sessionId);
|
|
1020
|
-
|
|
1021
|
-
const workspaceEntries = session.spec!.workspaceEntries || [];
|
|
1022
|
-
if (workspaceEntries.length === 0) {
|
|
1023
|
-
const sessionRoot = await resolveSessionWorkspaceRoot(
|
|
1024
|
-
config.workspaceRootDir, workspaceEntries, sessionId,
|
|
1025
|
-
);
|
|
1026
|
-
return {
|
|
1027
|
-
workspaceBackend: new LocalWorkspaceBackend(sessionRoot, platformDir),
|
|
1028
|
-
provisionResults: [],
|
|
1029
|
-
};
|
|
1030
|
-
}
|
|
1031
|
-
|
|
1032
|
-
const workspaceBackend = new LocalWorkspaceBackend(config.workspaceRootDir, platformDir);
|
|
1033
|
-
const provisioner = new WorkspaceProvisioner();
|
|
1034
|
-
const provisionResults = await provisioner.provisionAll(
|
|
1035
|
-
workspaceEntries.map(entry => ({
|
|
1036
|
-
name: entry.name,
|
|
1037
|
-
source: entry.source,
|
|
1038
|
-
})),
|
|
1039
|
-
workspaceBackend,
|
|
1040
|
-
mergedEnvVars,
|
|
1041
|
-
config.mode === "local",
|
|
1042
|
-
config.mode !== "local",
|
|
1043
|
-
);
|
|
1044
|
-
|
|
1045
|
-
// If single entry changed root dir, create a new backend with the same platformDir
|
|
1046
|
-
if (
|
|
1047
|
-
provisionResults.length === 1 &&
|
|
1048
|
-
provisionResults[0].rootDir !== workspaceBackend.rootDir
|
|
1049
|
-
) {
|
|
1050
|
-
return {
|
|
1051
|
-
workspaceBackend: new LocalWorkspaceBackend(provisionResults[0].rootDir, platformDir),
|
|
1052
|
-
provisionResults,
|
|
1053
|
-
};
|
|
1054
|
-
}
|
|
1055
|
-
|
|
1056
|
-
return { workspaceBackend, provisionResults };
|
|
1057
|
-
}
|
|
1058
|
-
|
|
1059
|
-
// Shared JSON Schema → Zod converter (consolidated from 3 duplicate copies).
|
|
1060
|
-
import { jsonSchemaToZod } from "../../shared/json-schema-to-zod.js";
|
|
1061
|
-
|
|
1062
|
-
/**
|
|
1063
|
-
* Heuristic check for native extended thinking support.
|
|
1064
|
-
* Models with thinking support don't need the explicit think tool.
|
|
1065
|
-
*/
|
|
1066
|
-
function _modelHasNativeThinking(modelId: string): boolean {
|
|
1067
|
-
const lower = modelId.toLowerCase();
|
|
1068
|
-
|
|
1069
|
-
if (lower.includes("haiku")) return false;
|
|
1070
|
-
if (lower.includes("gpt-4o-mini")) return false;
|
|
1071
|
-
|
|
1072
|
-
if (lower.includes("claude") && (
|
|
1073
|
-
lower.includes("sonnet") || lower.includes("opus")
|
|
1074
|
-
)) return true;
|
|
1075
|
-
|
|
1076
|
-
if (lower.includes("o1") || lower.includes("o3") || lower.includes("o4")) {
|
|
1077
|
-
return true;
|
|
1078
|
-
}
|
|
1079
|
-
|
|
1080
|
-
return false;
|
|
1081
|
-
}
|