@stigmer/runner 3.15.3-dev.20260914100347 → 3.15.3-dev.20260916211208
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 +1 -0
- package/dist/.build-fingerprint +1 -1
- package/dist/__test-utils__/approval-contract/types.d.ts +1 -1
- package/dist/__test-utils__/hermetic-activity.d.ts +61 -7
- package/dist/__test-utils__/hermetic-activity.js +100 -9
- package/dist/__test-utils__/hermetic-activity.js.map +1 -1
- package/dist/__test-utils__/model-registry-fixture.d.ts +22 -3
- package/dist/__test-utils__/model-registry-fixture.js +22 -7
- package/dist/__test-utils__/model-registry-fixture.js.map +1 -1
- package/dist/activities/execute-cursor/__test-utils__/contract-subject.d.ts +2 -2
- package/dist/activities/execute-cursor/__test-utils__/contract-subject.js +14 -11
- package/dist/activities/execute-cursor/__test-utils__/contract-subject.js.map +1 -1
- package/dist/activities/execute-cursor/__test-utils__/fold.d.ts +61 -0
- package/dist/activities/execute-cursor/__test-utils__/fold.js +94 -0
- package/dist/activities/execute-cursor/__test-utils__/fold.js.map +1 -0
- package/dist/activities/execute-cursor/__test-utils__/gateway-substrate.js +1 -1
- package/dist/activities/execute-cursor/__test-utils__/gateway-substrate.js.map +1 -1
- package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.d.ts +52 -14
- package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.js +46 -12
- package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.js.map +1 -1
- package/dist/activities/execute-cursor/__test-utils__/scripted-agent.d.ts +21 -28
- package/dist/activities/execute-cursor/__test-utils__/scripted-agent.js +27 -11
- package/dist/activities/execute-cursor/__test-utils__/scripted-agent.js.map +1 -1
- package/dist/activities/execute-cursor/__test-utils__/scripted-sdk.d.ts +70 -26
- package/dist/activities/execute-cursor/__test-utils__/scripted-sdk.js +82 -32
- package/dist/activities/execute-cursor/__test-utils__/scripted-sdk.js.map +1 -1
- package/dist/activities/execute-cursor/adapter.d.ts +8 -7
- package/dist/activities/execute-cursor/adapter.js +13 -9
- package/dist/activities/execute-cursor/adapter.js.map +1 -1
- package/dist/activities/execute-cursor/approval-policy.d.ts +10 -10
- package/dist/activities/execute-cursor/approval-policy.js +12 -23
- package/dist/activities/execute-cursor/approval-policy.js.map +1 -1
- package/dist/activities/execute-cursor/approval-state.d.ts +35 -1
- package/dist/activities/execute-cursor/approval-state.js +65 -0
- package/dist/activities/execute-cursor/approval-state.js.map +1 -1
- package/dist/activities/execute-cursor/{message-translator.d.ts → boundary-rows.d.ts} +45 -341
- package/dist/activities/execute-cursor/boundary-rows.js +1018 -0
- package/dist/activities/execute-cursor/boundary-rows.js.map +1 -0
- package/dist/activities/execute-cursor/cursor-capabilities.d.ts +1 -1
- package/dist/activities/execute-cursor/cursor-capabilities.js +1 -1
- package/dist/activities/execute-cursor/cursor-event-recorder.d.ts +33 -14
- package/dist/activities/execute-cursor/cursor-event-recorder.js +43 -21
- package/dist/activities/execute-cursor/cursor-event-recorder.js.map +1 -1
- package/dist/activities/execute-cursor/prompt-builder.d.ts +3 -3
- package/dist/activities/execute-cursor/prompt-builder.js +4 -4
- package/dist/activities/execute-cursor/prompt-builder.js.map +1 -1
- package/dist/activities/execute-cursor/sdk-warmup.d.ts +15 -6
- package/dist/activities/execute-cursor/sdk-warmup.js +15 -6
- package/dist/activities/execute-cursor/sdk-warmup.js.map +1 -1
- package/dist/activities/execute-cursor/service-tier.js +1 -2
- package/dist/activities/execute-cursor/service-tier.js.map +1 -1
- package/dist/activities/execute-cursor/session-lifecycle.d.ts +38 -59
- package/dist/activities/execute-cursor/session-lifecycle.js +59 -96
- package/dist/activities/execute-cursor/session-lifecycle.js.map +1 -1
- package/dist/activities/execute-cursor/session-store.d.ts +100 -0
- package/dist/activities/execute-cursor/session-store.js +157 -0
- package/dist/activities/execute-cursor/session-store.js.map +1 -0
- package/dist/activities/execute-cursor/sub-agent-steps.d.ts +79 -0
- package/dist/activities/execute-cursor/sub-agent-steps.js +180 -0
- package/dist/activities/execute-cursor/sub-agent-steps.js.map +1 -0
- package/dist/activities/execute-cursor/tool-result.d.ts +49 -0
- package/dist/activities/execute-cursor/tool-result.js +130 -0
- package/dist/activities/execute-cursor/tool-result.js.map +1 -0
- package/dist/activities/execute-cursor/translator.d.ts +178 -0
- package/dist/activities/execute-cursor/translator.js +485 -0
- package/dist/activities/execute-cursor/translator.js.map +1 -0
- package/dist/activities/execute-cursor/turn-boundary.d.ts +15 -5
- package/dist/activities/execute-cursor/turn-boundary.js +10 -14
- 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 +47 -34
- package/dist/activities/execute-cursor/turn-settle.js.map +1 -1
- package/dist/activities/execute-cursor/turn-setup.d.ts +2 -2
- package/dist/activities/execute-cursor/turn-setup.js +5 -5
- package/dist/activities/execute-cursor/turn-setup.js.map +1 -1
- package/dist/activities/execute-cursor/turn-stream.d.ts +23 -14
- package/dist/activities/execute-cursor/turn-stream.js +41 -28
- package/dist/activities/execute-cursor/turn-stream.js.map +1 -1
- package/dist/activities/execute-cursor/turn.d.ts +4 -4
- package/dist/activities/execute-cursor/turn.js +5 -5
- package/dist/activities/execute-cursor/usage-pricing.d.ts +2 -2
- package/dist/activities/execute-cursor/usage-pricing.js +2 -2
- package/dist/activities/execute-deep-agent/__test-utils__/contract-subject.d.ts +2 -2
- package/dist/activities/execute-deep-agent/__test-utils__/contract-subject.js +2 -2
- package/dist/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.d.ts +16 -11
- package/dist/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.js +22 -10
- package/dist/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.js.map +1 -1
- package/dist/activities/execute-deep-agent/__test-utils__/hitl-script.js +1 -1
- package/dist/activities/execute-deep-agent/__test-utils__/hitl-script.js.map +1 -1
- package/dist/activities/execute-deep-agent/__test-utils__/scripted-model-module.d.ts +2 -3
- package/dist/activities/execute-deep-agent/__test-utils__/scripted-model-module.js +2 -3
- package/dist/activities/execute-deep-agent/__test-utils__/scripted-model-module.js.map +1 -1
- package/dist/activities/execute-deep-agent/__test-utils__/scripted-model.d.ts +12 -3
- package/dist/activities/execute-deep-agent/__test-utils__/scripted-model.js +18 -4
- package/dist/activities/execute-deep-agent/__test-utils__/scripted-model.js.map +1 -1
- package/dist/activities/execute-deep-agent/__test-utils__/v3-event-fixtures.d.ts +10 -1
- package/dist/activities/execute-deep-agent/__test-utils__/v3-event-fixtures.js +24 -11
- package/dist/activities/execute-deep-agent/__test-utils__/v3-event-fixtures.js.map +1 -1
- package/dist/activities/execute-deep-agent/adapter.d.ts +1 -1
- package/dist/activities/execute-deep-agent/adapter.js +1 -1
- package/dist/activities/execute-deep-agent/approval-file-change.d.ts +19 -19
- package/dist/activities/execute-deep-agent/approval-file-change.js +16 -15
- package/dist/activities/execute-deep-agent/approval-file-change.js.map +1 -1
- package/dist/activities/execute-deep-agent/deep-agent-capabilities.d.ts +2 -2
- package/dist/activities/execute-deep-agent/deep-agent-capabilities.js +2 -2
- package/dist/activities/execute-deep-agent/hitl.d.ts +2 -2
- package/dist/activities/execute-deep-agent/hitl.js +2 -2
- package/dist/activities/execute-deep-agent/inline-publisher.d.ts +13 -3
- package/dist/activities/execute-deep-agent/inline-publisher.js +3 -3
- package/dist/activities/execute-deep-agent/inline-publisher.js.map +1 -1
- package/dist/activities/execute-deep-agent/prompt-builder.d.ts +3 -3
- package/dist/activities/execute-deep-agent/prompt-builder.js +6 -7
- package/dist/activities/execute-deep-agent/prompt-builder.js.map +1 -1
- package/dist/activities/execute-deep-agent/streaming-side-effects.d.ts +16 -8
- package/dist/activities/execute-deep-agent/streaming-side-effects.js +20 -33
- package/dist/activities/execute-deep-agent/streaming-side-effects.js.map +1 -1
- package/dist/activities/execute-deep-agent/subagent-transformer.d.ts +3 -3
- package/dist/activities/execute-deep-agent/subagent-transformer.js +1 -1
- package/dist/activities/execute-deep-agent/translator.d.ts +134 -0
- package/dist/activities/execute-deep-agent/translator.js +418 -0
- package/dist/activities/execute-deep-agent/translator.js.map +1 -0
- package/dist/activities/execute-deep-agent/turn-settle.d.ts +13 -7
- package/dist/activities/execute-deep-agent/turn-settle.js +34 -45
- package/dist/activities/execute-deep-agent/turn-settle.js.map +1 -1
- package/dist/activities/execute-deep-agent/turn-setup.d.ts +8 -8
- package/dist/activities/execute-deep-agent/turn-setup.js +7 -7
- package/dist/activities/execute-deep-agent/turn-stream.d.ts +13 -10
- package/dist/activities/execute-deep-agent/turn-stream.js +44 -41
- package/dist/activities/execute-deep-agent/turn-stream.js.map +1 -1
- package/dist/activities/execute-deep-agent/turn.d.ts +3 -3
- package/dist/activities/execute-deep-agent/turn.js +3 -3
- package/dist/config.d.ts +2 -2
- package/dist/harness/approval-decisions.d.ts +1 -1
- package/dist/harness/approval-decisions.js +1 -1
- package/dist/harness/capabilities.d.ts +21 -11
- package/dist/harness/capabilities.js +2 -2
- package/dist/harness/capture.d.ts +4 -4
- package/dist/harness/capture.js +4 -4
- package/dist/harness/persist-chokepoint.d.ts +3 -3
- package/dist/harness/persist-chokepoint.js +3 -3
- package/dist/harness/registry.d.ts +2 -2
- package/dist/harness/registry.js +2 -2
- package/dist/harness/run-turn.d.ts +6 -4
- package/dist/harness/run-turn.js +31 -9
- package/dist/harness/run-turn.js.map +1 -1
- package/dist/harness/stop-controller.d.ts +1 -1
- package/dist/harness/stop-controller.js +1 -1
- package/dist/harness/terminal-table.d.ts +7 -7
- package/dist/harness/terminal-table.js +7 -7
- package/dist/harness/transcript/builder.d.ts +182 -0
- package/dist/harness/transcript/builder.js +693 -0
- package/dist/harness/transcript/builder.js.map +1 -0
- package/dist/harness/transcript/events.d.ts +218 -0
- package/dist/harness/transcript/events.js +50 -0
- package/dist/harness/transcript/events.js.map +1 -0
- package/dist/harness/transcript/state.d.ts +110 -0
- package/dist/harness/transcript/state.js +148 -0
- package/dist/harness/transcript/state.js.map +1 -0
- package/dist/harness/turn-context.d.ts +54 -38
- package/dist/harness/turn-context.js +42 -43
- package/dist/harness/turn-context.js.map +1 -1
- package/dist/harness/types.d.ts +63 -22
- package/dist/harness/types.js +12 -11
- package/dist/harness/types.js.map +1 -1
- package/dist/harness/usage-accumulator.d.ts +2 -2
- package/dist/harness/usage-accumulator.js +2 -2
- package/dist/harness-adapters.d.ts +5 -4
- package/dist/harness-adapters.js +5 -4
- package/dist/harness-adapters.js.map +1 -1
- package/dist/middleware/approval-gate.d.ts +6 -0
- package/dist/middleware/approval-gate.js +7 -57
- package/dist/middleware/approval-gate.js.map +1 -1
- package/dist/middleware/cost-advisory.d.ts +3 -3
- package/dist/middleware/cost-advisory.js +3 -3
- package/dist/middleware/index.d.ts +1 -1
- package/dist/middleware/index.js +1 -1
- package/dist/runner-manager.js +1 -1
- package/dist/runner-manager.js.map +1 -1
- package/dist/shared/approval-policy.d.ts +53 -0
- package/dist/shared/approval-policy.js +76 -0
- package/dist/shared/approval-policy.js.map +1 -1
- package/dist/shared/args-preview.d.ts +45 -22
- package/dist/shared/args-preview.js +51 -41
- package/dist/shared/args-preview.js.map +1 -1
- package/dist/shared/attachment-resolver.d.ts +4 -4
- package/dist/shared/attachment-resolver.js +4 -4
- package/dist/shared/attachment-vision.d.ts +2 -1
- package/dist/shared/attachment-vision.js.map +1 -1
- package/dist/shared/attachment-zip.d.ts +2 -2
- package/dist/shared/attachment-zip.js +2 -2
- package/dist/shared/cost-guard.d.ts +2 -2
- package/dist/shared/cost-guard.js +2 -2
- package/dist/shared/exact-apply.d.ts +1 -1
- package/dist/shared/exact-apply.js +1 -1
- package/dist/shared/execution-context.d.ts +2 -2
- package/dist/shared/execution-context.js +2 -2
- package/dist/shared/extract-structured-output.d.ts +2 -2
- package/dist/shared/extract-structured-output.js +2 -2
- package/dist/shared/filereview/cas-touched.d.ts +2 -2
- package/dist/shared/filereview/cas-touched.js +2 -2
- package/dist/shared/heartbeat.d.ts +1 -1
- package/dist/shared/heartbeat.js +1 -1
- package/dist/shared/llm-backend.d.ts +0 -4
- package/dist/shared/llm-backend.js +0 -4
- package/dist/shared/llm-backend.js.map +1 -1
- package/dist/shared/model-error.d.ts +1 -2
- package/dist/shared/model-error.js +1 -2
- package/dist/shared/model-error.js.map +1 -1
- package/dist/shared/persist-decision.d.ts +18 -24
- package/dist/shared/persist-decision.js +19 -11
- package/dist/shared/persist-decision.js.map +1 -1
- package/dist/shared/prompt-sections.d.ts +4 -4
- package/dist/shared/prompt-sections.js +4 -4
- package/dist/shared/skill-resolver.d.ts +3 -3
- package/dist/shared/skill-resolver.js +3 -3
- package/dist/shared/status-offload.d.ts +1 -1
- package/dist/shared/status-offload.js +2 -2
- package/dist/shared/status-offload.js.map +1 -1
- package/dist/shared/streaming-scheduler.d.ts +2 -7
- package/dist/shared/streaming-scheduler.js +6 -14
- package/dist/shared/streaming-scheduler.js.map +1 -1
- package/dist/shared/subagent-rows.d.ts +2 -2
- package/dist/shared/subagent-rows.js +2 -2
- package/dist/shared/todos.d.ts +3 -3
- package/dist/shared/todos.js +3 -3
- package/dist/shared/tool-row.d.ts +19 -1
- package/dist/shared/tool-row.js +36 -2
- package/dist/shared/tool-row.js.map +1 -1
- package/dist/shared/worker-shutdown.d.ts +1 -1
- package/dist/shared/worker-shutdown.js +1 -1
- package/dist/shared/workspace/session-provision.d.ts +1 -1
- package/dist/shared/workspace/session-provision.js +1 -1
- package/dist/shared/workspace/sources/empty.d.ts +1 -1
- package/dist/shared/workspace/sources/empty.js +1 -2
- package/dist/shared/workspace/sources/empty.js.map +1 -1
- package/dist/shared/workspace/sources/git.js +4 -4
- package/dist/shared/workspace/sources/git.js.map +1 -1
- package/dist/shared/workspace/sources/local-path.js +6 -6
- package/dist/shared/workspace/sources/local-path.js.map +1 -1
- package/dist/shared/workspace/stigmer-link.d.ts +1 -1
- package/dist/shared/workspace/stigmer-link.js +1 -1
- package/dist/shared/workspace/types.d.ts +2 -5
- package/dist/shared/workspace/types.js +0 -6
- package/dist/shared/workspace/types.js.map +1 -1
- package/dist/shared/workspace/writeback-coordinator.d.ts +17 -4
- package/dist/shared/workspace/writeback-coordinator.js +7 -9
- package/dist/shared/workspace/writeback-coordinator.js.map +1 -1
- package/package.json +5 -5
- package/src/__test-utils__/__tests__/execution-record-barrier.test.ts +70 -0
- package/src/__test-utils__/__tests__/harness-contract-self-check.test.ts +35 -1
- package/src/__test-utils__/approval-contract/contract.ts +1 -1
- package/src/__test-utils__/approval-contract/types.ts +1 -1
- package/src/__test-utils__/harness-boot-order-child.ts +1 -1
- package/src/__test-utils__/harness-contract/contract.ts +8 -8
- package/src/__test-utils__/harness-contract/recording-sink.ts +11 -1
- package/src/__test-utils__/harness-contract/runtime-contract.ts +52 -16
- package/src/__test-utils__/harness-contract/scripted-adapter.ts +47 -43
- package/src/__test-utils__/hermetic-activity.ts +113 -9
- package/src/__test-utils__/model-registry-fixture.ts +31 -7
- package/src/__test-utils__/module-specifiers.ts +32 -3
- package/src/__tests__/harness-boot-order.test.ts +1 -1
- package/src/__tests__/harness-contract.test.ts +1 -1
- package/src/__tests__/runner-manager.test.ts +1 -1
- package/src/activities/execute-cursor/__test-utils__/__tests__/scripted-double.test.ts +32 -8
- package/src/activities/execute-cursor/__test-utils__/contract-subject.ts +12 -10
- package/src/activities/execute-cursor/__test-utils__/fold.ts +116 -0
- package/src/activities/execute-cursor/__test-utils__/gateway-substrate.ts +1 -1
- package/src/activities/execute-cursor/__test-utils__/hermetic-cursor.ts +72 -19
- package/src/activities/execute-cursor/__test-utils__/scripted-agent.ts +35 -29
- package/src/activities/execute-cursor/__test-utils__/scripted-sdk.ts +94 -38
- package/src/activities/execute-cursor/__tests__/approval-gate.test.ts +2 -1
- package/src/activities/execute-cursor/__tests__/approval-state.test.ts +14 -21
- package/src/activities/execute-cursor/__tests__/build-prompt.test.ts +3 -3
- package/src/activities/execute-cursor/__tests__/coarse-fingerprint.test.ts +2 -1
- package/src/activities/execute-cursor/__tests__/cursor-baseurl-routing.test.ts +10 -8
- package/src/activities/execute-cursor/__tests__/cursor-event-recorder.test.ts +142 -0
- package/src/activities/execute-cursor/__tests__/cursor-fetch-interceptor-bypass.test.ts +24 -12
- package/src/activities/execute-cursor/__tests__/cursor-generate-image-live.test.ts +7 -2
- package/src/activities/execute-cursor/__tests__/cursor-hook-protocol-live.test.ts +163 -0
- package/src/activities/execute-cursor/__tests__/cursor-sdk-auth-smoke.test.ts +23 -20
- package/src/activities/execute-cursor/__tests__/cursor-transcript-live.test.ts +298 -0
- package/src/activities/execute-cursor/__tests__/deny-gate-exact-apply.test.ts +4 -2
- package/src/activities/execute-cursor/__tests__/fetch-interceptor.test.ts +1 -1
- package/src/activities/execute-cursor/__tests__/hermetic/deny-and-retry.test.ts +5 -2
- package/src/activities/execute-cursor/__tests__/hermetic/file-review-capture.test.ts +5 -2
- package/src/activities/execute-cursor/__tests__/hermetic/goldens/mcp-tool-call.status.json +71 -0
- package/src/activities/execute-cursor/__tests__/hermetic/goldens/sdk-task-note.status.json +73 -0
- package/src/activities/execute-cursor/__tests__/hermetic/goldens/shell-output-delta.error-delta.status.json +78 -0
- package/src/activities/execute-cursor/__tests__/hermetic/goldens/shell-output-delta.output-first.status.json +72 -0
- package/src/activities/execute-cursor/__tests__/hermetic/goldens/shell-output-delta.status.json +72 -0
- package/src/activities/execute-cursor/__tests__/hermetic/goldens/sub-agent-delegation.status.json +109 -0
- package/src/activities/execute-cursor/__tests__/hermetic/goldens/thinking-turn.status.json +78 -0
- package/src/activities/execute-cursor/__tests__/hermetic/goldens/todo-write.status.json +119 -0
- package/src/activities/execute-cursor/__tests__/hermetic/goldens/tool-error.status.json +68 -0
- package/src/activities/execute-cursor/__tests__/hermetic/goldens/tool-only-step.status.json +67 -0
- package/src/activities/execute-cursor/__tests__/hermetic/goldens/unattributed-hook-block.status.json +1 -1
- package/src/activities/execute-cursor/__tests__/hermetic/harness-contract.test.ts +10 -7
- package/src/activities/execute-cursor/__tests__/hermetic/mcp-tool-call.test.ts +146 -0
- package/src/activities/execute-cursor/__tests__/hermetic/pause-vs-shutdown.test.ts +8 -5
- package/src/activities/execute-cursor/__tests__/hermetic/plain-turn.test.ts +6 -2
- package/src/activities/execute-cursor/__tests__/hermetic/recovery-fresh-agent.test.ts +4 -1
- package/src/activities/execute-cursor/__tests__/hermetic/run-wait-arms.test.ts +6 -2
- package/src/activities/execute-cursor/__tests__/hermetic/sdk-task-note.test.ts +122 -0
- package/src/activities/execute-cursor/__tests__/hermetic/shell-output-delta.test.ts +276 -0
- package/src/activities/execute-cursor/__tests__/hermetic/stream-self-stop-arms.test.ts +12 -9
- package/src/activities/execute-cursor/__tests__/hermetic/sub-agent-delegation.test.ts +196 -0
- package/src/activities/execute-cursor/__tests__/hermetic/thinking-turn.test.ts +145 -0
- package/src/activities/execute-cursor/__tests__/hermetic/thrown-error-arms.test.ts +4 -1
- package/src/activities/execute-cursor/__tests__/hermetic/todo-write.test.ts +165 -0
- package/src/activities/execute-cursor/__tests__/hermetic/tool-call.test.ts +7 -4
- package/src/activities/execute-cursor/__tests__/hermetic/tool-error.test.ts +138 -0
- package/src/activities/execute-cursor/__tests__/hermetic/tool-only-step.test.ts +130 -0
- package/src/activities/execute-cursor/__tests__/hermetic/unattributed-hook-block.test.ts +17 -2
- package/src/activities/execute-cursor/__tests__/hermetic/workspace-lock-timeout.test.ts +5 -2
- package/src/activities/execute-cursor/__tests__/hitl-ledger.test.ts +43 -60
- package/src/activities/execute-cursor/__tests__/hitl-resume-history.test.ts +23 -28
- package/src/activities/execute-cursor/__tests__/hook-script.test.ts +2 -1
- package/src/activities/execute-cursor/__tests__/http2-interceptor.test.ts +1 -1
- package/src/activities/execute-cursor/__tests__/prompt-goldens.test.ts +5 -5
- package/src/activities/execute-cursor/__tests__/same-identity-reproposal.test.ts +11 -13
- package/src/activities/execute-cursor/__tests__/sequential-gate-resume.test.ts +8 -11
- package/src/activities/execute-cursor/__tests__/session-lifecycle.test.ts +86 -58
- package/src/activities/execute-cursor/__tests__/session-store.test.ts +220 -0
- package/src/activities/execute-cursor/__tests__/tool-result-image.test.ts +8 -22
- package/src/activities/execute-cursor/__tests__/translator.test.ts +594 -0
- package/src/activities/execute-cursor/__tests__/turn-boundary.test.ts +8 -5
- package/src/activities/execute-cursor/__tests__/turn-stream.test.ts +87 -63
- package/src/activities/execute-cursor/adapter.ts +13 -9
- package/src/activities/execute-cursor/approval-policy.ts +12 -24
- package/src/activities/execute-cursor/approval-state.ts +66 -1
- package/src/activities/execute-cursor/boundary-rows.ts +1132 -0
- package/src/activities/execute-cursor/cursor-capabilities.ts +1 -1
- package/src/activities/execute-cursor/cursor-event-recorder.ts +57 -28
- package/src/activities/execute-cursor/fetch-interceptor.ts +1 -1
- package/src/activities/execute-cursor/http2-interceptor.ts +1 -1
- package/src/activities/execute-cursor/prompt-builder.ts +6 -6
- package/src/activities/execute-cursor/sdk-warmup.ts +15 -6
- package/src/activities/execute-cursor/service-tier.ts +1 -2
- package/src/activities/execute-cursor/session-lifecycle.ts +63 -109
- package/src/activities/execute-cursor/session-store.ts +187 -0
- package/src/activities/execute-cursor/sub-agent-steps.ts +188 -0
- package/src/activities/execute-cursor/tool-result.ts +128 -0
- package/src/activities/execute-cursor/translator.ts +541 -0
- package/src/activities/execute-cursor/turn-boundary.ts +21 -14
- package/src/activities/execute-cursor/turn-settle.ts +46 -34
- package/src/activities/execute-cursor/turn-setup.ts +5 -5
- package/src/activities/execute-cursor/turn-stream.ts +49 -46
- package/src/activities/execute-cursor/turn.ts +5 -5
- package/src/activities/execute-cursor/usage-pricing.ts +2 -2
- package/src/activities/execute-deep-agent/__test-utils__/contract-subject.ts +2 -2
- package/src/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.ts +23 -11
- package/src/activities/execute-deep-agent/__test-utils__/hitl-script.ts +1 -1
- package/src/activities/execute-deep-agent/__test-utils__/scripted-model-module.ts +2 -3
- package/src/activities/execute-deep-agent/__test-utils__/scripted-model.ts +25 -4
- package/src/activities/execute-deep-agent/__test-utils__/v3-event-fixtures.ts +25 -11
- package/src/activities/execute-deep-agent/__tests__/adapter-graph-is-sdk-free.test.ts +1 -1
- package/src/activities/execute-deep-agent/__tests__/adapter-is-temporal-free.test.ts +1 -1
- package/src/activities/execute-deep-agent/__tests__/approval-file-change.test.ts +6 -17
- package/src/activities/execute-deep-agent/__tests__/hermetic/file-review-capture.test.ts +25 -8
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/approve-all-lease.turn1.status.json +2 -7
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/approve-all-lease.turn2.status.json +4 -14
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/approve.turn2.status.json +1 -5
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/file-review-capture.status.json +4 -7
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/gate.turn1.status.json +1 -5
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/inline-artifact.turn1.status.json +2 -9
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/inline-artifact.turn2.status.json +2 -9
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/pause.loop.after-tool.status.json +1 -4
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/pause.loop.mid-tool.status.json +1 -4
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/platform-stop.status.json +1 -4
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/recursion-limit.persisted.status.json +109 -76
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/reject.turn2.status.json +1 -5
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/sequential-gates.turn2.status.json +2 -10
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/sequential-gates.turn3.status.json +2 -10
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/skip.turn2.status.json +1 -5
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/sub-agent-delegation.status.json +3 -6
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/tool-call.status.json +1 -4
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/worker-shutdown.status.json +1 -4
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/write-todos.status.json +92 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/harness-contract.test.ts +3 -3
- package/src/activities/execute-deep-agent/__tests__/hermetic/hitl-approve-all-lease.test.ts +9 -5
- package/src/activities/execute-deep-agent/__tests__/hermetic/hitl-round-trips.test.ts +3 -3
- package/src/activities/execute-deep-agent/__tests__/hermetic/hitl-sequential-gates.test.ts +3 -3
- package/src/activities/execute-deep-agent/__tests__/hermetic/inline-artifact-across-gate.test.ts +7 -6
- package/src/activities/execute-deep-agent/__tests__/hermetic/pause-vs-shutdown.test.ts +10 -11
- package/src/activities/execute-deep-agent/__tests__/hermetic/plain-turn.test.ts +4 -4
- package/src/activities/execute-deep-agent/__tests__/hermetic/platform-stop.test.ts +9 -8
- package/src/activities/execute-deep-agent/__tests__/hermetic/recursion-limit.test.ts +21 -13
- package/src/activities/execute-deep-agent/__tests__/hermetic/resolution-error.test.ts +2 -2
- package/src/activities/execute-deep-agent/__tests__/hermetic/structured-output.test.ts +7 -7
- package/src/activities/execute-deep-agent/__tests__/hermetic/sub-agent-delegation.test.ts +28 -12
- package/src/activities/execute-deep-agent/__tests__/hermetic/tool-call.test.ts +21 -21
- package/src/activities/execute-deep-agent/__tests__/hermetic/workspace-lock-timeout.test.ts +5 -5
- package/src/activities/execute-deep-agent/__tests__/hermetic/write-todos.test.ts +160 -0
- package/src/activities/execute-deep-agent/__tests__/inline-publisher.test.ts +35 -30
- package/src/activities/execute-deep-agent/__tests__/prompt-builder.test.ts +3 -4
- package/src/activities/execute-deep-agent/__tests__/prompt-goldens.test.ts +12 -10
- package/src/activities/execute-deep-agent/__tests__/scripted-model.test.ts +13 -3
- package/src/activities/execute-deep-agent/__tests__/streaming-side-effects.test.ts +26 -18
- package/src/activities/execute-deep-agent/__tests__/subagent-wiring.test.ts +1 -1
- package/src/activities/execute-deep-agent/__tests__/{subagent-tracker.test.ts → translator-subagents.test.ts} +76 -57
- package/src/activities/execute-deep-agent/__tests__/{v3-status-builder.test.ts → translator-through-builder.test.ts} +213 -299
- package/src/activities/execute-deep-agent/__tests__/translator.test.ts +505 -0
- package/src/activities/execute-deep-agent/__tests__/turn-stream.test.ts +11 -29
- package/src/activities/execute-deep-agent/adapter.ts +1 -1
- package/src/activities/execute-deep-agent/approval-file-change.ts +20 -22
- package/src/activities/execute-deep-agent/deep-agent-capabilities.ts +2 -2
- package/src/activities/execute-deep-agent/hitl.ts +2 -2
- package/src/activities/execute-deep-agent/inline-publisher.ts +16 -5
- package/src/activities/execute-deep-agent/prompt-builder.ts +6 -7
- package/src/activities/execute-deep-agent/streaming-side-effects.ts +22 -31
- package/src/activities/execute-deep-agent/subagent-transformer.ts +3 -3
- package/src/activities/execute-deep-agent/translator.ts +463 -0
- package/src/activities/execute-deep-agent/turn-settle.ts +35 -43
- package/src/activities/execute-deep-agent/turn-setup.ts +8 -8
- package/src/activities/execute-deep-agent/turn-stream.ts +53 -51
- package/src/activities/execute-deep-agent/turn.ts +3 -3
- package/src/config.ts +2 -2
- package/src/harness/README.md +335 -0
- package/src/harness/__tests__/approval-decisions.test.ts +2 -2
- package/src/harness/__tests__/capture.test.ts +3 -3
- package/src/harness/__tests__/import-direction.test.ts +3 -2
- package/src/harness/__tests__/mount-skills.test.ts +4 -1
- package/src/harness/__tests__/readme-index.test.ts +339 -0
- package/src/harness/__tests__/run-turn.test.ts +131 -6
- package/src/harness/__tests__/transcript-is-engine-free.test.ts +83 -0
- package/src/harness/__tests__/transcript-writers.test.ts +191 -0
- package/src/harness/__tests__/turn-attachments-vision.test.ts +5 -2
- package/src/harness/__tests__/turn-context.test.ts +5 -5
- package/src/harness/approval-decisions.ts +1 -1
- package/src/harness/capabilities.ts +21 -11
- package/src/harness/capture.ts +4 -4
- package/src/harness/persist-chokepoint.ts +3 -3
- package/src/harness/registry.ts +2 -2
- package/src/harness/run-turn.ts +33 -9
- package/src/harness/stop-controller.ts +1 -1
- package/src/harness/terminal-table.ts +7 -7
- package/src/harness/transcript/__tests__/builder.test.ts +975 -0
- package/src/harness/transcript/__tests__/state.test.ts +143 -0
- package/src/harness/transcript/builder.ts +755 -0
- package/src/harness/transcript/events.ts +262 -0
- package/src/harness/transcript/state.ts +167 -0
- package/src/harness/turn-context.ts +61 -46
- package/src/harness/types.ts +64 -22
- package/src/harness/usage-accumulator.ts +2 -2
- package/src/harness-adapters.ts +5 -4
- package/src/middleware/__tests__/cost-advisory.test.ts +2 -2
- package/src/middleware/approval-gate.ts +7 -74
- package/src/middleware/cost-advisory.ts +3 -3
- package/src/middleware/index.ts +1 -1
- package/src/runner-manager.ts +1 -1
- package/src/shared/__tests__/approval-policy.test.ts +45 -0
- package/src/shared/__tests__/args-preview.test.ts +40 -20
- package/src/shared/__tests__/attachment-naming.test.ts +1 -1
- package/src/shared/__tests__/attachment-resolver.test.ts +5 -5
- package/src/shared/__tests__/attachment-zip.test.ts +1 -1
- package/src/shared/__tests__/blueprint-resolver.test.ts +1 -1
- package/src/shared/__tests__/cost-guard.test.ts +1 -1
- package/src/shared/__tests__/exact-apply.test.ts +2 -1
- package/src/shared/__tests__/persist-decision.test.ts +19 -33
- package/src/shared/__tests__/prompt-sections.test.ts +1 -1
- package/src/shared/__tests__/stamp-flowed-rows.test.ts +1 -1
- package/src/shared/__tests__/status-offload.test.ts +1 -1
- package/src/shared/__tests__/streaming-scheduler.test.ts +8 -9
- package/src/shared/__tests__/todos.test.ts +1 -1
- package/src/shared/__tests__/tool-row.test.ts +1 -1
- package/src/shared/approval-policy.ts +95 -0
- package/src/shared/args-preview.ts +51 -42
- package/src/shared/attachment-resolver.ts +4 -4
- package/src/shared/attachment-vision.ts +2 -1
- package/src/shared/attachment-zip.ts +2 -2
- package/src/shared/cost-guard.ts +2 -2
- package/src/shared/exact-apply.ts +1 -1
- package/src/shared/execution-context.ts +2 -2
- package/src/shared/extract-structured-output.ts +2 -2
- package/src/shared/filereview/__tests__/capture.test.ts +9 -5
- package/src/shared/filereview/__tests__/git-substrate.test.ts +4 -1
- package/src/shared/filereview/__tests__/proxy-reconcile.test.ts +3 -3
- package/src/shared/filereview/cas-touched.ts +2 -2
- package/src/shared/heartbeat.ts +1 -1
- package/src/shared/llm-backend.ts +0 -4
- package/src/shared/model-error.ts +1 -2
- package/src/shared/persist-decision.ts +19 -28
- package/src/shared/prompt-sections.ts +4 -4
- package/src/shared/skill-resolver.ts +3 -3
- package/src/shared/status-offload.ts +2 -2
- package/src/shared/streaming-scheduler.ts +8 -13
- package/src/shared/subagent-rows.ts +2 -2
- package/src/shared/todos.ts +3 -3
- package/src/shared/tool-row.ts +38 -2
- package/src/shared/worker-shutdown.ts +1 -1
- package/src/shared/workspace/__tests__/git-source.test.ts +3 -3
- package/src/shared/workspace/__tests__/provisioner.test.ts +5 -5
- package/src/shared/workspace/__tests__/session-provision.test.ts +2 -2
- package/src/shared/workspace/__tests__/writeback-coordinator.integration.test.ts +8 -9
- package/src/shared/workspace/__tests__/writeback-coordinator.test.ts +25 -25
- package/src/shared/workspace/provisioner.ts +1 -1
- package/src/shared/workspace/session-provision.ts +1 -1
- package/src/shared/workspace/sources/empty.ts +2 -2
- package/src/shared/workspace/sources/git.ts +3 -4
- package/src/shared/workspace/sources/local-path.ts +5 -6
- package/src/shared/workspace/stigmer-link.ts +1 -1
- package/src/shared/workspace/types.ts +2 -5
- package/src/shared/workspace/writeback-coordinator.ts +23 -12
- package/dist/activities/execute-cursor/delta-enricher.d.ts +0 -87
- package/dist/activities/execute-cursor/delta-enricher.js +0 -265
- package/dist/activities/execute-cursor/delta-enricher.js.map +0 -1
- package/dist/activities/execute-cursor/message-translator.js +0 -2040
- package/dist/activities/execute-cursor/message-translator.js.map +0 -1
- package/dist/activities/execute-cursor/todo-tracker.d.ts +0 -40
- package/dist/activities/execute-cursor/todo-tracker.js +0 -80
- package/dist/activities/execute-cursor/todo-tracker.js.map +0 -1
- package/dist/activities/execute-deep-agent/execution-state.d.ts +0 -54
- package/dist/activities/execute-deep-agent/execution-state.js +0 -68
- package/dist/activities/execute-deep-agent/execution-state.js.map +0 -1
- package/dist/activities/execute-deep-agent/status-builder-shared.d.ts +0 -65
- package/dist/activities/execute-deep-agent/status-builder-shared.js +0 -90
- package/dist/activities/execute-deep-agent/status-builder-shared.js.map +0 -1
- package/dist/activities/execute-deep-agent/subagent-tracker.d.ts +0 -113
- package/dist/activities/execute-deep-agent/subagent-tracker.js +0 -400
- package/dist/activities/execute-deep-agent/subagent-tracker.js.map +0 -1
- package/dist/activities/execute-deep-agent/v3-events.d.ts +0 -102
- package/dist/activities/execute-deep-agent/v3-events.js +0 -35
- package/dist/activities/execute-deep-agent/v3-events.js.map +0 -1
- package/dist/activities/execute-deep-agent/v3-protocol-normalizer.d.ts +0 -15
- package/dist/activities/execute-deep-agent/v3-protocol-normalizer.js +0 -235
- package/dist/activities/execute-deep-agent/v3-protocol-normalizer.js.map +0 -1
- package/dist/activities/execute-deep-agent/v3-status-builder.d.ts +0 -111
- package/dist/activities/execute-deep-agent/v3-status-builder.js +0 -457
- package/dist/activities/execute-deep-agent/v3-status-builder.js.map +0 -1
- package/dist/shared/execution-status-writer.d.ts +0 -31
- package/dist/shared/execution-status-writer.js +0 -43
- package/dist/shared/execution-status-writer.js.map +0 -1
- package/src/activities/execute-cursor/__tests__/delta-enricher.test.ts +0 -310
- package/src/activities/execute-cursor/__tests__/message-translator.test.ts +0 -1033
- package/src/activities/execute-cursor/__tests__/todo-tracker.test.ts +0 -498
- package/src/activities/execute-cursor/delta-enricher.ts +0 -307
- package/src/activities/execute-cursor/message-translator.ts +0 -2319
- package/src/activities/execute-cursor/todo-tracker.ts +0 -91
- package/src/activities/execute-deep-agent/__tests__/execution-state-extended.test.ts +0 -148
- package/src/activities/execute-deep-agent/__tests__/execution-state.test.ts +0 -154
- package/src/activities/execute-deep-agent/__tests__/status-builder-shared.test.ts +0 -47
- package/src/activities/execute-deep-agent/__tests__/v3-protocol-normalizer.test.ts +0 -324
- package/src/activities/execute-deep-agent/execution-state.ts +0 -78
- package/src/activities/execute-deep-agent/status-builder-shared.ts +0 -142
- package/src/activities/execute-deep-agent/subagent-tracker.ts +0 -479
- package/src/activities/execute-deep-agent/v3-events.ts +0 -153
- package/src/activities/execute-deep-agent/v3-protocol-normalizer.ts +0 -264
- package/src/activities/execute-deep-agent/v3-status-builder.ts +0 -565
- package/src/shared/execution-status-writer.ts +0 -56
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* and driven by the framework's own activity environment. Both harnesses now
|
|
15
15
|
* run on it (`execute-cursor/__test-utils__/hermetic-cursor.ts`,
|
|
16
16
|
* `execute-deep-agent/__test-utils__/hermetic-deep-agent.ts`), and the earlier
|
|
17
|
-
* native tests were re-homed onto the native driver (
|
|
17
|
+
* native tests were re-homed onto the native driver (#1096), their assertions
|
|
18
18
|
* carried into `execute-deep-agent/__tests__/hermetic/`.
|
|
19
19
|
*
|
|
20
20
|
* What is generic here and what is not: everything an activity touches that is
|
|
@@ -55,11 +55,22 @@
|
|
|
55
55
|
* Determinism: the clock is faked for `Date` ONLY (`vi.useFakeTimers({ toFake:
|
|
56
56
|
* ["Date"] })`) and TICKS — the harness double advances it a fixed quantum per
|
|
57
57
|
* script step through {@link ScriptedClock}. Frozen time would make
|
|
58
|
-
*
|
|
58
|
+
* the streaming scheduler's cadence (`Date.now()` against its last send) never
|
|
59
59
|
* elapse and silently skip the mid-stream persist path production always runs;
|
|
60
60
|
* a ticking clock runs the same path and lands on the same instants every run.
|
|
61
61
|
* Timers stay real so the periodic heartbeat and the stall watchdog behave.
|
|
62
62
|
*
|
|
63
|
+
* The live posture (#1097's live-run gate): a `CURSOR_API_KEY`-gated live
|
|
64
|
+
* instrument keeps all three substitutions above — the real `Context`, the
|
|
65
|
+
* record behind the client, the temp environment — and drops only the
|
|
66
|
+
* harness's SDK double, so the REAL activity runs against the REAL vendor SDK
|
|
67
|
+
* with everything the activity persists still readable from the record.
|
|
68
|
+
* Two things differ from a hermetic run and both are the caller's explicit
|
|
69
|
+
* choice: no `ScriptedClock` is installed (the real SDK is not ticked, and a
|
|
70
|
+
* frozen clock would skip the persist cadence production runs), and the
|
|
71
|
+
* environment may name an `eventRecordingDir` so the run leaves a recording.
|
|
72
|
+
* The harness's driver names the entry (`beginLiveCursorScenario`).
|
|
73
|
+
*
|
|
63
74
|
* Not in scope: this module never edits a production module and never
|
|
64
75
|
* normalizes output. If a golden is not byte-stable, the volatile source is
|
|
65
76
|
* controlled at its origin or the surprise is escalated — never redacted here.
|
|
@@ -151,6 +162,8 @@ export class ExecutionRecord {
|
|
|
151
162
|
private readonly controlSignal: (status: AgentExecutionStatus) => ExecutionControlSignal;
|
|
152
163
|
/** Every `updateStatus` payload, in order, snapshotted at write time. */
|
|
153
164
|
readonly persisted: AgentExecutionStatus[] = [];
|
|
165
|
+
/** Fired after every full-status `applyStatusUpdate`; {@link whenToolCallsSettled} subscribes here. */
|
|
166
|
+
private readonly persistListeners = new Set<() => void>();
|
|
154
167
|
/** Setup-progress labels reported before the stream started, in order. */
|
|
155
168
|
readonly setupProgress: string[] = [];
|
|
156
169
|
/**
|
|
@@ -205,6 +218,78 @@ export class ExecutionRecord {
|
|
|
205
218
|
return this.execution.status?.messages.flatMap((m) => m.toolCalls) ?? [];
|
|
206
219
|
}
|
|
207
220
|
|
|
221
|
+
/**
|
|
222
|
+
* Resolves once every one of `ids` is a SETTLED row (not RUNNING) in a status
|
|
223
|
+
* the activity has persisted — root messages and every sub-agent's alike.
|
|
224
|
+
* Resolves at once for an empty list or when they already are.
|
|
225
|
+
*
|
|
226
|
+
* This is the barrier a real model gives the runtime for free and a
|
|
227
|
+
* scripted one does not: a model that takes 300 ms to answer never starts
|
|
228
|
+
* its next turn before the loop has folded and persisted the tool results
|
|
229
|
+
* it is answering, while `ScriptedModel` answers instantly and LangGraph's
|
|
230
|
+
* producer can run a whole turn ahead of the consumer while the consumer
|
|
231
|
+
* awaits one mid-stream persist (on a git workspace that persist shells out
|
|
232
|
+
* for `file_change_progress`). The stamps the consumer writes at apply time
|
|
233
|
+
* then land on either side of the scripted clock's next tick depending on
|
|
234
|
+
* I/O timing — a golden that flips between `:01` and `:02` on the day. The
|
|
235
|
+
* driver awaits this before it ticks (`hermetic-deep-agent.ts`), so every
|
|
236
|
+
* stamp of turn N precedes turn N+1's instant, run after run.
|
|
237
|
+
*
|
|
238
|
+
* Why "settled" and not "seen": the row's `completedAt` is stamped when the
|
|
239
|
+
* tool's end event is applied, and the producer calls the next model turn
|
|
240
|
+
* right after emitting that event, so a barrier on the row merely existing
|
|
241
|
+
* would still race the completion stamp. The persist that carries the
|
|
242
|
+
* settled row always exists: a tool's finish forces one (the builder's
|
|
243
|
+
* force flag), and a turn followed by another turn always has a tool call.
|
|
244
|
+
*
|
|
245
|
+
* Bounded by real time (timers are real under the scripted clock): a
|
|
246
|
+
* scenario that breaks the fact above — a persist that never carries the
|
|
247
|
+
* row — fails naming the ids still open, never hangs.
|
|
248
|
+
*/
|
|
249
|
+
whenToolCallsSettled(ids: readonly string[], timeoutMs = 10_000): Promise<void> {
|
|
250
|
+
const unsettled = (): string[] => {
|
|
251
|
+
const settled = this.settledToolCallIds();
|
|
252
|
+
return ids.filter((id) => !settled.has(id));
|
|
253
|
+
};
|
|
254
|
+
if (unsettled().length === 0) return Promise.resolve();
|
|
255
|
+
|
|
256
|
+
return new Promise<void>((resolve, reject) => {
|
|
257
|
+
const timer = setTimeout(() => {
|
|
258
|
+
this.persistListeners.delete(check);
|
|
259
|
+
reject(
|
|
260
|
+
new Error(
|
|
261
|
+
`ExecutionRecord: tool call(s) ${unsettled().join(", ")} never settled in a persisted status ` +
|
|
262
|
+
`within ${timeoutMs} ms (${this.persisted.length} persists seen). A model turn was asked to ` +
|
|
263
|
+
`wait for the results it answers; the loop never persisted them — a scenario or runtime bug.`,
|
|
264
|
+
),
|
|
265
|
+
);
|
|
266
|
+
}, timeoutMs);
|
|
267
|
+
const check = (): void => {
|
|
268
|
+
if (unsettled().length > 0) return;
|
|
269
|
+
clearTimeout(timer);
|
|
270
|
+
this.persistListeners.delete(check);
|
|
271
|
+
resolve();
|
|
272
|
+
};
|
|
273
|
+
this.persistListeners.add(check);
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/** The ids of every row not RUNNING in the held status, across the root and every sub-agent transcript. */
|
|
278
|
+
private settledToolCallIds(): Set<string> {
|
|
279
|
+
const out = new Set<string>();
|
|
280
|
+
const status = this.execution.status;
|
|
281
|
+
if (!status) return out;
|
|
282
|
+
const transcripts = [status.messages, ...status.subAgentExecutions.map((s) => s.messages)];
|
|
283
|
+
for (const messages of transcripts) {
|
|
284
|
+
for (const message of messages) {
|
|
285
|
+
for (const tc of message.toolCalls) {
|
|
286
|
+
if (tc.status !== ToolCallStatus.TOOL_CALL_RUNNING) out.add(tc.id);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
return out;
|
|
291
|
+
}
|
|
292
|
+
|
|
208
293
|
/** The tool calls currently paused for a decision. */
|
|
209
294
|
waitingToolCalls(): ToolCall[] {
|
|
210
295
|
return this.toolCalls().filter((tc) => tc.status === ToolCallStatus.TOOL_CALL_WAITING_APPROVAL);
|
|
@@ -254,6 +339,7 @@ export class ExecutionRecord {
|
|
|
254
339
|
return ExecutionControlSignal.UNSPECIFIED;
|
|
255
340
|
}
|
|
256
341
|
this.execution.status = clone(AgentExecutionStatusSchema, snapshot);
|
|
342
|
+
for (const listener of [...this.persistListeners]) listener();
|
|
257
343
|
return this.controlSignal(snapshot);
|
|
258
344
|
}
|
|
259
345
|
|
|
@@ -343,14 +429,30 @@ export function hermeticStigmerClientModule(): { StigmerClient: new () => Stigme
|
|
|
343
429
|
* (an absent store flips capture off — a different code path).
|
|
344
430
|
* - `STIGMER_RUNNER_HITL_SECRET`: the one randomness source on the activity
|
|
345
431
|
* path, pinned so grant tokens and fingerprints are byte-stable.
|
|
346
|
-
* - `CURSOR_EVENT_RECORD_DIR` cleared: never write recordings from a test
|
|
432
|
+
* - `CURSOR_EVENT_RECORD_DIR` cleared: never write recordings from a test —
|
|
433
|
+
* unless the caller names an `eventRecordingDir`, the live instruments'
|
|
434
|
+
* opt-in (below), in which case this environment SETS it. Either way the
|
|
435
|
+
* variable has one owner here, and dispose restores it.
|
|
347
436
|
*/
|
|
348
437
|
const PINNED_ENV = {
|
|
349
438
|
ARTIFACT_STORAGE_TYPE: "local",
|
|
350
439
|
STIGMER_RUNNER_HITL_SECRET: "hermetic-fixture-secret-do-not-use-in-production",
|
|
351
440
|
} as const;
|
|
352
441
|
|
|
353
|
-
const CLEARED_ENV = ["
|
|
442
|
+
const CLEARED_ENV = ["STIGMER_PROXY_ENDPOINT", "STIGMER_CLOUD_API_URL"] as const;
|
|
443
|
+
|
|
444
|
+
/** The one name the Cursor recorder is switched on by (`turn-settle.ts` reads it). */
|
|
445
|
+
const CURSOR_EVENT_RECORD_DIR = "CURSOR_EVENT_RECORD_DIR";
|
|
446
|
+
|
|
447
|
+
export interface HermeticEnvironmentOptions {
|
|
448
|
+
/**
|
|
449
|
+
* Where the Cursor event recorder writes this run's raw SDK recording
|
|
450
|
+
* (`<dir>/<executionId>.cursor-events.jsonl`). Named ONLY by a live
|
|
451
|
+
* instrument, whose point is a recording of the real SDK; a hermetic
|
|
452
|
+
* scenario leaves it unset and the variable is cleared for the run.
|
|
453
|
+
*/
|
|
454
|
+
readonly eventRecordingDir?: string;
|
|
455
|
+
}
|
|
354
456
|
|
|
355
457
|
export interface HermeticEnvironment {
|
|
356
458
|
/** The temp `HOME` (the runner's `~/.stigmer` lands under it). */
|
|
@@ -368,7 +470,7 @@ export interface HermeticEnvironment {
|
|
|
368
470
|
* `beforeAll`) — the fingerprint secret is memoized per process on first use,
|
|
369
471
|
* and vitest isolates files in forks, so per-file is the natural unit.
|
|
370
472
|
*/
|
|
371
|
-
export function createHermeticEnvironment(): HermeticEnvironment {
|
|
473
|
+
export function createHermeticEnvironment(options: HermeticEnvironmentOptions = {}): HermeticEnvironment {
|
|
372
474
|
const root = mkdtempSync(join(tmpdir(), "stigmer-hermetic-"));
|
|
373
475
|
const home = join(root, "home");
|
|
374
476
|
const workspaceRootDir = join(root, "workspaces");
|
|
@@ -384,6 +486,7 @@ export function createHermeticEnvironment(): HermeticEnvironment {
|
|
|
384
486
|
set("LOCAL_ARTIFACT_PATH", artifactPath);
|
|
385
487
|
for (const [k, v] of Object.entries(PINNED_ENV)) set(k, v);
|
|
386
488
|
for (const k of CLEARED_ENV) set(k, undefined);
|
|
489
|
+
set(CURSOR_EVENT_RECORD_DIR, options.eventRecordingDir);
|
|
387
490
|
|
|
388
491
|
let disposed = false;
|
|
389
492
|
return {
|
|
@@ -411,15 +514,16 @@ export function createHermeticEnvironment(): HermeticEnvironment {
|
|
|
411
514
|
* advance together; timers stay real (the periodic heartbeat, the stall
|
|
412
515
|
* watchdog, `withTimeout` all need them). The harness double calls
|
|
413
516
|
* {@link ScriptedClock.tick} once per script step, so every clock-based
|
|
414
|
-
* decision on the activity path — status timestamps, the
|
|
415
|
-
*
|
|
517
|
+
* decision on the activity path — status timestamps, the builder's row
|
|
518
|
+
* instants, cache TTLs (`Date`); the streaming scheduler's persist cadence
|
|
416
519
|
* (`performance.now()`) — sees the same instants run after run and runs the
|
|
417
520
|
* same branches production runs.
|
|
418
521
|
*
|
|
419
|
-
* Why both (
|
|
522
|
+
* Why both (since #1096): until then only `Date` was faked, so the
|
|
420
523
|
* scheduler paced persists on REAL elapsed time and `fileChangeProgress`,
|
|
421
524
|
* which rides persists, could gain or lose a capture under load — a golden
|
|
422
|
-
* flake seen twice
|
|
525
|
+
* flake seen twice while the native adapter moved onto the runtime. One clock,
|
|
526
|
+
* two faces: `tick` advances through
|
|
423
527
|
* the fake clock's own `tick` (`vi.advanceTimersByTime`), which moves both
|
|
424
528
|
* `Date` and `performance.now()`; `vi.setSystemTime` would move `Date` alone
|
|
425
529
|
* (fake-timers keeps `performance` monotonic across a system-time jump), so
|
|
@@ -23,6 +23,15 @@
|
|
|
23
23
|
* never consulted and adding an entry is byte-invisible to the other
|
|
24
24
|
* harness's goldens (verified when the native entry landed: Cursor's
|
|
25
25
|
* seventeen unchanged).
|
|
26
|
+
*
|
|
27
|
+
* The live posture (`stubRegistryFetch({ live: true })`): a live instrument
|
|
28
|
+
* runs the real activity against the REAL `@cursor/sdk`, whose cloud-api
|
|
29
|
+
* client (`Cursor.models.list`, the user-key token exchange) goes through
|
|
30
|
+
* global `fetch` — only its Connect RPC stream rides connect-node. Such a run
|
|
31
|
+
* keeps this document for the registry (pricing and tier stay pinned; nothing
|
|
32
|
+
* a live turn proves lives there) and lets every other URL reach the network
|
|
33
|
+
* through the `fetch` that was global before the stub. The refusal stays the
|
|
34
|
+
* default: a hermetic run that grows a network dependency must still fail.
|
|
26
35
|
*/
|
|
27
36
|
|
|
28
37
|
import { vi } from "vitest";
|
|
@@ -76,21 +85,36 @@ export const REGISTRY_DOCUMENT = {
|
|
|
76
85
|
],
|
|
77
86
|
} as const;
|
|
78
87
|
|
|
88
|
+
export interface StubRegistryFetchOptions {
|
|
89
|
+
/**
|
|
90
|
+
* The live posture (header): every URL that is not the registry reaches the
|
|
91
|
+
* network through the pre-stub `fetch`. Default false — refuse, and fail the
|
|
92
|
+
* run.
|
|
93
|
+
*/
|
|
94
|
+
readonly live?: boolean;
|
|
95
|
+
}
|
|
96
|
+
|
|
79
97
|
/**
|
|
80
|
-
* Stub `fetch` to answer the registry document and
|
|
81
|
-
* Returns the URLs fetched, for the "no other network"
|
|
98
|
+
* Stub `fetch` to answer the registry document and — by default — refuse
|
|
99
|
+
* everything else. Returns the URLs fetched, for the "no other network"
|
|
100
|
+
* assertion (and, in the live posture, for the record of what a real turn
|
|
101
|
+
* dialled).
|
|
82
102
|
*/
|
|
83
|
-
export function stubRegistryFetch(): { readonly urls: string[]; restore(): void } {
|
|
103
|
+
export function stubRegistryFetch(options: StubRegistryFetchOptions = {}): { readonly urls: string[]; restore(): void } {
|
|
84
104
|
const urls: string[] = [];
|
|
105
|
+
const networkFetch = globalThis.fetch;
|
|
85
106
|
vi.stubGlobal(
|
|
86
107
|
"fetch",
|
|
87
|
-
vi.fn(async (input: string | URL | Request) => {
|
|
108
|
+
vi.fn(async (input: string | URL | Request, init?: RequestInit) => {
|
|
88
109
|
const url = typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url;
|
|
89
110
|
urls.push(url);
|
|
90
|
-
if (
|
|
91
|
-
|
|
111
|
+
if (url.includes("/model-registry")) {
|
|
112
|
+
return { ok: true, status: 200, json: async () => REGISTRY_DOCUMENT } as unknown as Response;
|
|
113
|
+
}
|
|
114
|
+
if (options.live) {
|
|
115
|
+
return networkFetch(input, init);
|
|
92
116
|
}
|
|
93
|
-
|
|
117
|
+
throw new Error(`hermetic run attempted a non-registry network call: ${url}`);
|
|
94
118
|
}),
|
|
95
119
|
);
|
|
96
120
|
return { urls, restore: () => vi.unstubAllGlobals() };
|
|
@@ -2,11 +2,14 @@
|
|
|
2
2
|
* The module specifiers a TypeScript file names, read off its syntax tree —
|
|
3
3
|
* the primitive behind the runner's import fences.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
5
|
+
* Three fences stand on it: `src/harness/` and production `src/shared/` never
|
|
6
6
|
* import `src/activities/` (`harness/__tests__/import-direction.test.ts`,
|
|
7
|
-
* the rule the turn runtime is written under)
|
|
7
|
+
* the rule the turn runtime is written under); the Cursor adapter never
|
|
8
8
|
* imports `@temporalio/*` (`execute-cursor/__tests__/adapter-is-temporal-
|
|
9
|
-
* free.test.ts`, what lets the contract kit run it outside an activity)
|
|
9
|
+
* free.test.ts`, what lets the contract kit run it outside an activity); and
|
|
10
|
+
* `src/harness/transcript/` names no package outside a short allow-list
|
|
11
|
+
* (`harness/__tests__/transcript-is-engine-free.test.ts`, what keeps the one
|
|
12
|
+
* transcript builder engine-neutral).
|
|
10
13
|
*
|
|
11
14
|
* A syntax tree, not a regex, so a path quoted in a header comment cannot
|
|
12
15
|
* trip a fence, and no import form can slip past one: static, type-only,
|
|
@@ -84,6 +87,32 @@ export function packageImports(filePath: string, source: string, pkg: string): s
|
|
|
84
87
|
return moduleSpecifiers(filePath, source).filter((specifier) => specifier === pkg || specifier.startsWith(`${pkg}/`));
|
|
85
88
|
}
|
|
86
89
|
|
|
90
|
+
/**
|
|
91
|
+
* The packages `source` names — every specifier that is neither a relative
|
|
92
|
+
* path nor a `node:` builtin, reduced to its package (`@scope/name` or
|
|
93
|
+
* `name`, the subpath dropped), deduplicated, in first-appearance order.
|
|
94
|
+
*
|
|
95
|
+
* What an ALLOW-list fence compares against, where `packageImports` serves a
|
|
96
|
+
* deny: a deny-list must be extended for every SDK that does not exist yet,
|
|
97
|
+
* an allow-list refuses it on the day it is written.
|
|
98
|
+
*/
|
|
99
|
+
export function packageNames(filePath: string, source: string): string[] {
|
|
100
|
+
const names = new Set<string>();
|
|
101
|
+
for (const specifier of moduleSpecifiers(filePath, source)) {
|
|
102
|
+
if (specifier.startsWith(".") || specifier.startsWith("node:")) continue;
|
|
103
|
+
names.add(packageName(specifier));
|
|
104
|
+
}
|
|
105
|
+
return [...names];
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** `@scope/name/sub/path` → `@scope/name`; `name/sub/path` → `name`. */
|
|
109
|
+
function packageName(specifier: string): string {
|
|
110
|
+
const parts = specifier.split("/");
|
|
111
|
+
const [first, second] = parts;
|
|
112
|
+
if (first === undefined) return specifier;
|
|
113
|
+
return first.startsWith("@") && second !== undefined ? `${first}/${second}` : first;
|
|
114
|
+
}
|
|
115
|
+
|
|
87
116
|
/** Every `.ts` file under `dir`, sorted, skipping the named directories at any depth. */
|
|
88
117
|
export function typeScriptFilesUnder(dir: string, skipDirectories: ReadonlySet<string>): string[] {
|
|
89
118
|
const files: string[] = [];
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
* `adapter.ts`'s graph, or a static client import on the registry's, fails
|
|
21
21
|
* the first arm; a `boot` that stopped asserting fails the second.
|
|
22
22
|
*
|
|
23
|
-
* The table has two rows since
|
|
23
|
+
* The table has two rows since #1096 (2026-09-13): the child boots the
|
|
24
24
|
* Cursor adapter and then the native deep-agent adapter, whose `boot`
|
|
25
25
|
* registers the deepagents profiles and loads LangChain — after the patch,
|
|
26
26
|
* because it is the second row. A `boot` that reordered the rows, or a
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* halves in its own hermetic file, where the mocks its double needs can be
|
|
14
14
|
* hoisted: the Cursor adapter does so in
|
|
15
15
|
* `activities/execute-cursor/__tests__/hermetic/harness-contract.test.ts`
|
|
16
|
-
* (
|
|
16
|
+
* (since #1070), and the fake's runtime-side half runs in
|
|
17
17
|
* `harness/__tests__/run-turn.test.ts`.
|
|
18
18
|
*/
|
|
19
19
|
|
|
@@ -33,7 +33,7 @@ describe("mapManagerOptionsToConfig", () => {
|
|
|
33
33
|
expect(config.checkpointerType).toBe("http");
|
|
34
34
|
});
|
|
35
35
|
|
|
36
|
-
it("binds the proxy credential to the runner-token ref, never the control-plane ref
|
|
36
|
+
it("binds the proxy credential to the runner-token ref, never the control-plane ref", () => {
|
|
37
37
|
const tokenRef = { current: "control-plane-token" };
|
|
38
38
|
const runnerTokenRef = { current: "control-plane-token" };
|
|
39
39
|
const config = mapManagerOptionsToConfig(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The scripted `@cursor/sdk` double's own arms — the surface the harness
|
|
3
|
-
* contract kit's Cursor subject drives, added
|
|
3
|
+
* contract kit's Cursor subject drives, added in #1070 beside the golden
|
|
4
4
|
* scenarios' declared-up-front surface (which the seventeen goldens prove).
|
|
5
5
|
*
|
|
6
6
|
* - `arrangeNextTurn` writes the slot the NEXT `send()` consumes, replaces a
|
|
@@ -9,17 +9,20 @@
|
|
|
9
9
|
* - `nextRunId` names the run the next send will be given, so a script can be
|
|
10
10
|
* built with matching event ids before the send happens.
|
|
11
11
|
* - `agentForWorkspaceRef` hands `Agent.create` the agent declared for the
|
|
12
|
-
* session the create names (via `
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* list as before.
|
|
12
|
+
* session the create names (via the `workspaceRef` of the scripted store it
|
|
13
|
+
* passes as `local.store`), consulted before the ordered list and
|
|
14
|
+
* registered for `Agent.resume` by id; a create with no store, or a session
|
|
15
|
+
* the resolver does not know, falls through to the list as before.
|
|
16
|
+
* - `ScriptedLocalAgentStore.open` (the `@cursor/sdk/sqlite` double) records
|
|
17
|
+
* every open and dispose on the bound SDK, so a scenario can assert the
|
|
18
|
+
* adapter's session-store lifetime.
|
|
16
19
|
*/
|
|
17
20
|
|
|
18
21
|
import { describe, it, expect } from "vitest";
|
|
19
22
|
import type { AgentOptions, SDKMessage } from "@cursor/sdk";
|
|
20
23
|
|
|
21
24
|
import { ScriptedCursorAgent, defaultRunId, sdkEvents, step } from "../scripted-agent.js";
|
|
22
|
-
import { ScriptedCursorSdk } from "../scripted-sdk.js";
|
|
25
|
+
import { ScriptedCursorSdk, ScriptedLocalAgentStore, bindScriptedSdk } from "../scripted-sdk.js";
|
|
23
26
|
|
|
24
27
|
/** An agent whose declared turns each play the given events and finish. */
|
|
25
28
|
function agent(id: string, turns: SDKMessage[][] = []): ScriptedCursorAgent {
|
|
@@ -76,8 +79,14 @@ describe("ScriptedCursorAgent.nextRunId", () => {
|
|
|
76
79
|
});
|
|
77
80
|
|
|
78
81
|
describe("ScriptedCursorSdk.agentForWorkspaceRef", () => {
|
|
82
|
+
// The scripted store carries only the members the runner touches, not the
|
|
83
|
+
// SDK's whole `LocalAgentStore`, hence the cast — the same one the mocked
|
|
84
|
+
// module makes when it stands in for `@cursor/sdk/sqlite`.
|
|
79
85
|
const createFor = (workspaceRef: string | undefined): AgentOptions =>
|
|
80
|
-
({
|
|
86
|
+
({
|
|
87
|
+
apiKey: "k",
|
|
88
|
+
local: workspaceRef !== undefined ? { store: new ScriptedLocalAgentStore(workspaceRef, "/tmp/x") } : undefined,
|
|
89
|
+
}) as unknown as AgentOptions;
|
|
81
90
|
|
|
82
91
|
it("hands out the session's agent before the ordered list and registers it for resume", () => {
|
|
83
92
|
const forSession = agent("session-agent");
|
|
@@ -94,9 +103,24 @@ describe("ScriptedCursorSdk.agentForWorkspaceRef", () => {
|
|
|
94
103
|
expect(sdk.resolutions.map((r) => `${r.kind}:${r.agentId}`)).toEqual(["create:session-agent", "resume:session-agent", "create:listed-agent"]);
|
|
95
104
|
});
|
|
96
105
|
|
|
97
|
-
it("a create without a
|
|
106
|
+
it("a create without a store falls through to the ordered list", () => {
|
|
98
107
|
const listed = agent("listed-only");
|
|
99
108
|
const sdk = new ScriptedCursorSdk({ agents: [listed], catalog: [], agentForWorkspaceRef: () => agent("never") });
|
|
100
109
|
expect(sdk.create(createFor(undefined))).toBe(listed);
|
|
101
110
|
});
|
|
102
111
|
});
|
|
112
|
+
|
|
113
|
+
describe("ScriptedLocalAgentStore (the @cursor/sdk/sqlite double)", () => {
|
|
114
|
+
it("open hands out a store carrying the ref and root asked for, and records opens and disposes on the bound SDK", async () => {
|
|
115
|
+
const sdk = new ScriptedCursorSdk({ agents: [], catalog: [] });
|
|
116
|
+
bindScriptedSdk(sdk);
|
|
117
|
+
|
|
118
|
+
const store = await ScriptedLocalAgentStore.open({ workspaceRef: "stigmer-session:ses-9", stateRoot: "/tmp/ses-9" });
|
|
119
|
+
expect(store.workspaceRef).toBe("stigmer-session:ses-9");
|
|
120
|
+
expect(store.stateRoot).toBe("/tmp/ses-9");
|
|
121
|
+
expect(sdk.stores).toEqual([store]);
|
|
122
|
+
|
|
123
|
+
await store.dispose();
|
|
124
|
+
expect(store.disposeCalls).toBe(1);
|
|
125
|
+
});
|
|
126
|
+
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The Cursor harness as a `HarnessContractSubject` — the REAL `createCursorAdapter()`
|
|
3
3
|
* driven through the harness contract kit, with the kit's engine-neutral
|
|
4
|
-
* scenario vocabulary translated onto
|
|
4
|
+
* scenario vocabulary translated onto the scripted `@cursor/sdk` double (#1048).
|
|
5
5
|
*
|
|
6
6
|
* The sibling of `gateway-substrate.ts` (the Cursor side of the approval
|
|
7
7
|
* contract kit): the kit owns the invariants and the runtime stand-in, this
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
* Every script that does not end in `fail`, `cancelled` or `hang` closes with
|
|
60
60
|
* `finished({ result: <last say> })` so `run.wait()` has an answer.
|
|
61
61
|
*
|
|
62
|
-
* ── Two modelling decisions (
|
|
62
|
+
* ── Two modelling decisions (#1070) ─────────────────────────────────────────
|
|
63
63
|
* A `propose` for an id this subject has already seen the hook ALLOW emits
|
|
64
64
|
* nothing: the real SDK does not re-run a completed tool on resume — the parked
|
|
65
65
|
* agent's conversation already holds the tool's result. A `propose` whose id
|
|
@@ -95,7 +95,7 @@ import type {
|
|
|
95
95
|
} from "../../../__test-utils__/harness-contract/types.js";
|
|
96
96
|
import type { HermeticEnvironment } from "../../../__test-utils__/hermetic-activity.js";
|
|
97
97
|
import { createCursorAdapter } from "../adapter.js";
|
|
98
|
-
import {
|
|
98
|
+
import { resolveSessionStoreLocation } from "../session-store.js";
|
|
99
99
|
import { hookInputFor, streamArgsFor, STREAM_NAME, type GatedActionKind } from "./cursor-hook-harness.js";
|
|
100
100
|
import { FIXTURE, SDK_CATALOG, hermeticCursorConfig, runWorkspaceHook } from "./hermetic-cursor.js";
|
|
101
101
|
import { ScriptedCursorAgent, sdkEvents, step, type ScriptStep, type ScriptedRun } from "./scripted-agent.js";
|
|
@@ -216,9 +216,9 @@ class CursorSubject implements CursorContractSubject {
|
|
|
216
216
|
private mintAgent(sessionId: string): ScriptedCursorAgent {
|
|
217
217
|
const agent = new ScriptedCursorAgent({ agentId: `agent-kit-${++this.mintCounter}`, turns: [] });
|
|
218
218
|
this.agents.set(sessionId, agent);
|
|
219
|
-
// The adapter asks the SDK to create an agent for the session
|
|
220
|
-
// ref; the double answers with this agent.
|
|
221
|
-
const { workspaceRef } =
|
|
219
|
+
// The adapter asks the SDK to create an agent for the session over a store
|
|
220
|
+
// opened under this ref; the double answers with this agent.
|
|
221
|
+
const { workspaceRef } = resolveSessionStoreLocation(sessionId, this.config.workspaceRootDir);
|
|
222
222
|
this.agentsByWorkspaceRef.set(workspaceRef, agent);
|
|
223
223
|
return agent;
|
|
224
224
|
}
|
|
@@ -248,11 +248,13 @@ class CursorSubject implements CursorContractSubject {
|
|
|
248
248
|
break;
|
|
249
249
|
case "usage":
|
|
250
250
|
script.push(
|
|
251
|
+
// The kit's delta leaves a count optional; the SDK's `turn-ended`
|
|
252
|
+
// states all four, and an absent count is zero, as the pricer reads it.
|
|
251
253
|
step.turnEnded({
|
|
252
|
-
inputTokens: s.delta.inputTokens,
|
|
253
|
-
outputTokens: s.delta.outputTokens,
|
|
254
|
-
cacheReadTokens: s.delta.cacheReadTokens,
|
|
255
|
-
cacheWriteTokens: s.delta.cacheWriteTokens,
|
|
254
|
+
inputTokens: s.delta.inputTokens ?? 0,
|
|
255
|
+
outputTokens: s.delta.outputTokens ?? 0,
|
|
256
|
+
cacheReadTokens: s.delta.cacheReadTokens ?? 0,
|
|
257
|
+
cacheWriteTokens: s.delta.cacheWriteTokens ?? 0,
|
|
256
258
|
}),
|
|
257
259
|
);
|
|
258
260
|
break;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Drive Cursor SDK events through the REAL pair the harness runs in production
|
|
3
|
+
* — `CursorTranslator` into `TranscriptBuilder` over an `AgentExecutionStatus`
|
|
4
|
+
* — and hand back what they built. The unit-test seam that replaced
|
|
5
|
+
* `new <accumulator>(messages, options)` in #1097 (the accumulator folded
|
|
6
|
+
* rows itself; now the translator emits events and the shared builder folds
|
|
7
|
+
* them), so the arms that read a row's shape after a sequence of SDK events
|
|
8
|
+
* keep their shape while the module under them changed.
|
|
9
|
+
*
|
|
10
|
+
* The same shape as the native translator's local `feedAll` in
|
|
11
|
+
* `execute-deep-agent/__tests__/translator-through-builder.test.ts`, shared
|
|
12
|
+
* here because seven Cursor test files read through it.
|
|
13
|
+
*
|
|
14
|
+
* Deltas follow the loop's discipline (`turn-stream.ts`): `observeDelta`
|
|
15
|
+
* queues, and the queue is drained into the builder after the NEXT stream
|
|
16
|
+
* event — or at {@link CursorFold.drain} for a caller that wants them applied
|
|
17
|
+
* now, the settle's own last drain before `finalize()`.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { create } from "@bufbuild/protobuf";
|
|
21
|
+
import type { InteractionUpdate, SDKMessage } from "@cursor/sdk";
|
|
22
|
+
import { AgentExecutionStatusSchema, type AgentExecutionStatus } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
|
|
23
|
+
import type { AgentMessage, ToolCall } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/message_pb";
|
|
24
|
+
import { TranscriptBuilder } from "../../../harness/transcript/builder.js";
|
|
25
|
+
import { CursorTranslator, type CursorTranslatorOptions } from "../translator.js";
|
|
26
|
+
|
|
27
|
+
export interface CursorFoldOptions {
|
|
28
|
+
/** The status to build into; a fresh empty one when omitted. Its `messages` are the translator's seed. */
|
|
29
|
+
readonly status?: AgentExecutionStatus;
|
|
30
|
+
/**
|
|
31
|
+
* An existing `messages` array to build into BY REFERENCE (a test that
|
|
32
|
+
* hand-built its seeded rows and keeps asserting on the same objects). Wins
|
|
33
|
+
* over `status`'s own array.
|
|
34
|
+
*/
|
|
35
|
+
readonly messages?: AgentMessage[];
|
|
36
|
+
readonly policies?: CursorTranslatorOptions["policies"];
|
|
37
|
+
readonly leases?: CursorTranslatorOptions["leases"];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export class CursorFold {
|
|
41
|
+
readonly status: AgentExecutionStatus;
|
|
42
|
+
readonly translator: CursorTranslator;
|
|
43
|
+
readonly builder: TranscriptBuilder;
|
|
44
|
+
|
|
45
|
+
constructor(options: CursorFoldOptions = {}) {
|
|
46
|
+
this.status = options.status ?? create(AgentExecutionStatusSchema, {});
|
|
47
|
+
if (options.messages) this.status.messages = options.messages;
|
|
48
|
+
this.translator = new CursorTranslator({
|
|
49
|
+
policies: options.policies ?? new Map(),
|
|
50
|
+
leases: options.leases ?? { global: false, categories: new Set() },
|
|
51
|
+
seeded: this.status.messages,
|
|
52
|
+
});
|
|
53
|
+
this.builder = new TranscriptBuilder("exec-fold", this.status);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** One stream event, translated and folded, then the deltas queued so far — the loop's order. */
|
|
57
|
+
event(event: SDKMessage): this {
|
|
58
|
+
for (const e of this.translator.translate(event)) this.builder.apply(e);
|
|
59
|
+
this.drain();
|
|
60
|
+
return this;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
events(...events: SDKMessage[]): this {
|
|
64
|
+
for (const e of events) this.event(e);
|
|
65
|
+
return this;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** One delta, queued — applied at the next {@link event} or {@link drain}. */
|
|
69
|
+
delta(update: InteractionUpdate): this {
|
|
70
|
+
this.translator.observeDelta(update);
|
|
71
|
+
return this;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
drain(): this {
|
|
75
|
+
for (const e of this.translator.drainDeltas()) this.builder.apply(e);
|
|
76
|
+
return this;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
finalize(): this {
|
|
80
|
+
this.drain();
|
|
81
|
+
this.builder.finalize();
|
|
82
|
+
return this;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
get messages(): AgentMessage[] {
|
|
86
|
+
return this.status.messages;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** Every root row, in transcript order. */
|
|
90
|
+
rows(): ToolCall[] {
|
|
91
|
+
return this.status.messages.flatMap((m) => m.toolCalls);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
row(callId: string): ToolCall {
|
|
95
|
+
const found = this.rows().find((tc) => tc.id === callId);
|
|
96
|
+
if (!found) throw new Error(`CursorFold: no row ${callId}`);
|
|
97
|
+
return found;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** Fold a sequence of stream events into a fresh transcript; the common one-liner. */
|
|
102
|
+
export function foldCursorEvents(events: readonly SDKMessage[], options: CursorFoldOptions = {}): CursorFold {
|
|
103
|
+
return new CursorFold(options).events(...events);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* A builder over an existing `messages` array, kept BY REFERENCE (the status
|
|
108
|
+
* is given the array itself, never a copy), so a boundary test that built its
|
|
109
|
+
* rows by hand can hand them to `reconcileDeniedToolCalls` and keep asserting
|
|
110
|
+
* on the same objects.
|
|
111
|
+
*/
|
|
112
|
+
export function builderOver(messages: AgentMessage[], executionId = "exec-boundary"): TranscriptBuilder {
|
|
113
|
+
const status = create(AgentExecutionStatusSchema, {});
|
|
114
|
+
status.messages = messages;
|
|
115
|
+
return new TranscriptBuilder(executionId, status);
|
|
116
|
+
}
|
|
@@ -80,7 +80,7 @@ export function createCursorSubstrate(): GatewaySubstrate {
|
|
|
80
80
|
enforcesExactContent: true,
|
|
81
81
|
appliesRunLifetimeLease: true,
|
|
82
82
|
// The Cursor hook's deny decision does not carry approval_policy_source;
|
|
83
|
-
// provenance is projected at
|
|
83
|
+
// provenance is projected at translation time (the Cursor translator)
|
|
84
84
|
// and asserted by the corpus + resolveApprovalProvenance suites instead.
|
|
85
85
|
surfacesGatePolicySource: false,
|
|
86
86
|
},
|