@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
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ExecutionRecord.whenToolCallsSettled` — the barrier the hermetic scripted
|
|
3
|
+
* model waits on before it ticks (since #1097): resolves once every named row is
|
|
4
|
+
* persisted settled, across the root and the sub-agent transcripts; resolves
|
|
5
|
+
* at once when there is nothing to wait for; fails naming the open ids rather
|
|
6
|
+
* than hanging when no persist ever carries them.
|
|
7
|
+
*/
|
|
8
|
+
import { describe, expect, it } from "vitest";
|
|
9
|
+
import { create } from "@bufbuild/protobuf";
|
|
10
|
+
import { AgentExecutionStatusSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
|
|
11
|
+
import { ExecutionPhase, MessageType, ToolCallStatus } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
|
|
12
|
+
import { deepAgentExecutionRecord } from "../../activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.js";
|
|
13
|
+
|
|
14
|
+
function statusWith(rows: Array<{ id: string; status: ToolCallStatus; subAgent?: boolean }>) {
|
|
15
|
+
const message = (ids: typeof rows) => ({
|
|
16
|
+
type: MessageType.MESSAGE_AI,
|
|
17
|
+
content: "",
|
|
18
|
+
toolCalls: ids.map((r) => ({ id: r.id, name: "probe", status: r.status })),
|
|
19
|
+
});
|
|
20
|
+
return create(AgentExecutionStatusSchema, {
|
|
21
|
+
phase: ExecutionPhase.EXECUTION_IN_PROGRESS,
|
|
22
|
+
messages: [message(rows.filter((r) => !r.subAgent))],
|
|
23
|
+
subAgentExecutions: rows.some((r) => r.subAgent)
|
|
24
|
+
? [{ id: "task-1", name: "helper", messages: [message(rows.filter((r) => r.subAgent))] }]
|
|
25
|
+
: [],
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
describe("ExecutionRecord.whenToolCallsSettled", () => {
|
|
30
|
+
it("resolves at once for no ids, and for ids already persisted settled", async () => {
|
|
31
|
+
const record = deepAgentExecutionRecord({ message: "go" });
|
|
32
|
+
await expect(record.whenToolCallsSettled([])).resolves.toBeUndefined();
|
|
33
|
+
|
|
34
|
+
record.applyStatusUpdate(statusWith([{ id: "c-1", status: ToolCallStatus.TOOL_CALL_COMPLETED }]));
|
|
35
|
+
await expect(record.whenToolCallsSettled(["c-1"])).resolves.toBeUndefined();
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("waits through a RUNNING persist and releases on the persist that settles the row", async () => {
|
|
39
|
+
const record = deepAgentExecutionRecord({ message: "go" });
|
|
40
|
+
let released = false;
|
|
41
|
+
const barrier = record.whenToolCallsSettled(["c-1"]).then(() => {
|
|
42
|
+
released = true;
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
record.applyStatusUpdate(statusWith([{ id: "c-1", status: ToolCallStatus.TOOL_CALL_RUNNING }]));
|
|
46
|
+
await Promise.resolve();
|
|
47
|
+
expect(released, "a RUNNING row is not settled").toBe(false);
|
|
48
|
+
|
|
49
|
+
record.applyStatusUpdate(statusWith([{ id: "c-1", status: ToolCallStatus.TOOL_CALL_WAITING_APPROVAL }]));
|
|
50
|
+
await barrier;
|
|
51
|
+
expect(released).toBe(true);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it("finds a sub-agent's rows in its own transcript", async () => {
|
|
55
|
+
const record = deepAgentExecutionRecord({ message: "go" });
|
|
56
|
+
record.applyStatusUpdate(
|
|
57
|
+
statusWith([
|
|
58
|
+
{ id: "task-1", status: ToolCallStatus.TOOL_CALL_RUNNING },
|
|
59
|
+
{ id: "sub-1", status: ToolCallStatus.TOOL_CALL_COMPLETED, subAgent: true },
|
|
60
|
+
]),
|
|
61
|
+
);
|
|
62
|
+
await expect(record.whenToolCallsSettled(["sub-1"])).resolves.toBeUndefined();
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it("fails naming the ids still open when no persist ever settles them, instead of hanging", async () => {
|
|
66
|
+
const record = deepAgentExecutionRecord({ message: "go" });
|
|
67
|
+
record.applyStatusUpdate(statusWith([{ id: "c-1", status: ToolCallStatus.TOOL_CALL_RUNNING }]));
|
|
68
|
+
await expect(record.whenToolCallsSettled(["c-1", "c-2"], 20)).rejects.toThrow(/c-1, c-2 never settled/);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
@@ -27,7 +27,9 @@
|
|
|
27
27
|
|
|
28
28
|
import { describe, it, expect } from "vitest";
|
|
29
29
|
import { CancelledFailure } from "@temporalio/activity";
|
|
30
|
+
import { create } from "@bufbuild/protobuf";
|
|
30
31
|
import { ApprovalAction, ToolCallStatus } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
|
|
32
|
+
import { SubAgentExecutionSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/subagent_pb";
|
|
31
33
|
|
|
32
34
|
import type { HarnessAdapter, TurnInput, TurnOutcome, TurnSink } from "../../harness/types.js";
|
|
33
35
|
import {
|
|
@@ -41,11 +43,12 @@ import {
|
|
|
41
43
|
assertStopSignalInterrupts,
|
|
42
44
|
assertUsageReachesSinkAsDeltas,
|
|
43
45
|
} from "../harness-contract/contract.js";
|
|
46
|
+
import { assertTranscriptStreamsNothing } from "../harness-contract/runtime-contract.js";
|
|
44
47
|
import { scriptedSubject } from "../harness-contract/scripted-adapter.js";
|
|
45
48
|
import type { ScriptedSubject } from "../harness-contract/scripted-adapter.js";
|
|
46
49
|
import { scenario } from "../harness-contract/types.js";
|
|
47
50
|
import type { EngineView, HarnessContractSubject, TurnScenario } from "../harness-contract/types.js";
|
|
48
|
-
import { findToolCallRow } from "../proto-helpers.js";
|
|
51
|
+
import { aiMessage, emptyStatus, findToolCallRow, toolCall } from "../proto-helpers.js";
|
|
49
52
|
|
|
50
53
|
/** Short enough to keep this file fast; long enough that an honest microtask settle never trips it. */
|
|
51
54
|
const SHORT_BOUND_MS = 100;
|
|
@@ -75,6 +78,7 @@ function adapterOver(inner: HarnessAdapter, name: string, patch: Partial<Harness
|
|
|
75
78
|
function sinkOver(inner: TurnSink, patch: Partial<TurnSink>): TurnSink {
|
|
76
79
|
return {
|
|
77
80
|
status: inner.status,
|
|
81
|
+
transcript: inner.transcript,
|
|
78
82
|
stopSignal: inner.stopSignal,
|
|
79
83
|
setupTiming: inner.setupTiming,
|
|
80
84
|
requestPersist: () => inner.requestPersist(),
|
|
@@ -324,3 +328,33 @@ describe("harness contract kit self-check — the driver stands in for the runti
|
|
|
324
328
|
expect(turn.sink.status.messages.map((m) => m.content), "the stop landed in the hang, after the setup step and before the step after it").toEqual(["setting up"]);
|
|
325
329
|
});
|
|
326
330
|
});
|
|
331
|
+
|
|
332
|
+
// ── The runtime half's transcript fact ──────────────────────────────────────
|
|
333
|
+
|
|
334
|
+
describe("harness contract kit self-check — the settled-transcript assertion can fail", () => {
|
|
335
|
+
it("passes a transcript with every flag off", () => {
|
|
336
|
+
const status = emptyStatus();
|
|
337
|
+
const message = aiMessage("done");
|
|
338
|
+
message.toolCalls.push(toolCall("t-1", "read", ToolCallStatus.TOOL_CALL_COMPLETED));
|
|
339
|
+
status.messages.push(message);
|
|
340
|
+
expect(() => assertTranscriptStreamsNothing("honest", status)).not.toThrow();
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
it("names a message left streaming", () => {
|
|
344
|
+
const status = emptyStatus();
|
|
345
|
+
const message = aiMessage("still typing");
|
|
346
|
+
message.isStreaming = true;
|
|
347
|
+
status.messages.push(message);
|
|
348
|
+
expect(() => assertTranscriptStreamsNothing("broken:streams", status)).toThrow(/broken:streams: a settled turn's transcript is still streaming at messages\[0\]/);
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
it("names a tool-call row left streaming, inside a sub-agent's transcript", () => {
|
|
352
|
+
const status = emptyStatus();
|
|
353
|
+
const row = toolCall("t-2", "shell");
|
|
354
|
+
row.isStreaming = true;
|
|
355
|
+
const message = aiMessage("");
|
|
356
|
+
message.toolCalls.push(row);
|
|
357
|
+
status.subAgentExecutions.push(create(SubAgentExecutionSchema, { id: "sub-1", messages: [message] }));
|
|
358
|
+
expect(() => assertTranscriptStreamsNothing("broken:streams", status)).toThrow(/subAgentExecutions\[sub-1\]\.messages\[0\]\.toolCalls\[t-2\]/);
|
|
359
|
+
});
|
|
360
|
+
});
|
|
@@ -90,7 +90,7 @@ export function describeGatewayContract(substrate: GatewaySubstrate): void {
|
|
|
90
90
|
// effect is always auditable to the policy layer that governed it. Gated to
|
|
91
91
|
// substrates that decide the source at the gate (the deep-agent gate); the
|
|
92
92
|
// Cursor substrate projects provenance at reconstruction time and is covered
|
|
93
|
-
// by the
|
|
93
|
+
// by the translator + boundary-rows + corpus suites.
|
|
94
94
|
if (substrate.capabilities.surfacesGatePolicySource) {
|
|
95
95
|
it("tags every gated side effect with a non-UNSPECIFIED policy source", async () => {
|
|
96
96
|
for (const action of [WRITE_A, SHELL, DELETE]) {
|
|
@@ -137,7 +137,7 @@ export interface SubstrateCapabilities {
|
|
|
137
137
|
* and stamps the source at interrupt time (`true`); the Cursor substrate's
|
|
138
138
|
* provenance is a reconstruction-time projection over the persisted tool call,
|
|
139
139
|
* not a property of the hook's deny decision, so it is `false` here and is
|
|
140
|
-
* covered instead by the
|
|
140
|
+
* covered instead by the translator, boundary-rows and corpus suites.
|
|
141
141
|
*/
|
|
142
142
|
readonly surfacesGatePolicySource: boolean;
|
|
143
143
|
}
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* a bound token ref. Success means the pre-boot graph was connect-free,
|
|
16
16
|
* both interceptors installed, `assertHttp2ConnectPatched` passed, the
|
|
17
17
|
* Cursor SDK slice loaded from inside its `boot`, and the native
|
|
18
|
-
* deep-agent adapter (the table's second row since
|
|
18
|
+
* deep-agent adapter (the table's second row since #1096) registered its
|
|
19
19
|
* profiles and loaded LangChain after the patch. That neither engine is
|
|
20
20
|
* on the table's STATIC graph is each adapter's own fence
|
|
21
21
|
* (`adapter-graph-is-sdk-free.test.ts`); this child proves the boot
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
* is carried to COMPLETED; with REJECT or SKIP → never executes and the
|
|
39
39
|
* turn continues (the row's SKIPPED status is the runtime's to write,
|
|
40
40
|
* `harness/approval-decisions.ts`, proven in the runtime half — the
|
|
41
|
-
* driver stands in for that write between turns
|
|
41
|
+
* driver stands in for that write between turns); reinvoked again
|
|
42
42
|
* after the approval → still once, never re-gated.
|
|
43
43
|
* 4. Aborting `stopSignal` mid-hang settles `runTurn` as `interrupted` within
|
|
44
44
|
* {@link INTERRUPT_SETTLE_BOUND_MS} and nothing after the stop executes or
|
|
@@ -48,8 +48,8 @@
|
|
|
48
48
|
* executes on the resumed turn is the pause primitive's business — an
|
|
49
49
|
* interrupt engine completes the pending task before its model speaks,
|
|
50
50
|
* a deny-and-retry engine re-reaches it whenever its model does — so it
|
|
51
|
-
* is below the contract line (
|
|
52
|
-
*
|
|
51
|
+
* is below the contract line (each harness's own kit file observes its
|
|
52
|
+
* order).
|
|
53
53
|
* 5. Usage reaches the sink as non-negative deltas summing to what the engine
|
|
54
54
|
* emitted.
|
|
55
55
|
* 6. Capability and behaviour agree on the state id: an `engine-minted`
|
|
@@ -154,7 +154,7 @@ export class ExecutionDriver {
|
|
|
154
154
|
|
|
155
155
|
/** Start a turn without awaiting it, for invariants about turns in flight. */
|
|
156
156
|
begin(turn: TurnScenario, options: TurnOptions = {}): TurnInFlight {
|
|
157
|
-
const sink = options.sink ?? new RecordingTurnSink({ status: this.seedStatus() });
|
|
157
|
+
const sink = options.sink ?? new RecordingTurnSink({ status: this.seedStatus(), executionId: this.executionId });
|
|
158
158
|
// The engine's view and the record's copy both derive from the status
|
|
159
159
|
// this turn folds into, so a prepared sink's status is honoured too.
|
|
160
160
|
const view: EngineView = {
|
|
@@ -297,7 +297,7 @@ export async function assertEveryExitIsAnOutcome(subject: HarnessContractSubject
|
|
|
297
297
|
driver.recordTurn(sink);
|
|
298
298
|
}
|
|
299
299
|
|
|
300
|
-
const preAborted = new RecordingTurnSink({ status: driver.seedStatus() });
|
|
300
|
+
const preAborted = new RecordingTurnSink({ status: driver.seedStatus(), executionId: driver.executionId });
|
|
301
301
|
preAborted.abort("kit: aborted before the turn");
|
|
302
302
|
const { settled } = driver.begin([scenario.say("never")], { sink: preAborted });
|
|
303
303
|
await settleAsOutcome(subject, settleWithinBound(subject, settled, "under a pre-aborted signal", boundMs), "under a pre-aborted signal");
|
|
@@ -335,8 +335,8 @@ export async function assertProposalIsWaitingAndUnexecuted(subject: HarnessContr
|
|
|
335
335
|
* turn continues — the row's terminal status is NOT asserted here because
|
|
336
336
|
* it is not the adapter's to write (the decision is the server's field and
|
|
337
337
|
* the WAITING → SKIPPED transition follows from it with no engine knowledge,
|
|
338
|
-
* so it is the runtime's — `terminalizeNonExecutingDecisions`, landed
|
|
339
|
-
*
|
|
338
|
+
* so it is the runtime's — `terminalizeNonExecutingDecisions`, landed in
|
|
339
|
+
* #1096 and pinned by the runtime half's REJECT / SKIP arms).
|
|
340
340
|
* The reinvocation sees a CLONE of the persisted status, as it would from
|
|
341
341
|
* the server.
|
|
342
342
|
*/
|
|
@@ -391,7 +391,7 @@ export async function assertStopSignalInterrupts(subject: HarnessContractSubject
|
|
|
391
391
|
expect(findToolCallRow(hanging.sink.status, id), `${subject.name}: nothing after the stop may even reach the gate — the proposal after the hang has no row`).toBeUndefined();
|
|
392
392
|
driver.recordTurn(hanging.sink);
|
|
393
393
|
|
|
394
|
-
const preAborted = new RecordingTurnSink({ status: driver.seedStatus() });
|
|
394
|
+
const preAborted = new RecordingTurnSink({ status: driver.seedStatus(), executionId: driver.executionId });
|
|
395
395
|
preAborted.abort("kit: aborted before the turn");
|
|
396
396
|
const early = driver.begin([scenario.propose(id, WRITE_ALPHA)], { sink: preAborted });
|
|
397
397
|
const earlyOutcome = await settleWithinBound(subject, early.settled, "under a pre-aborted signal", boundMs);
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
|
|
21
21
|
import type { AgentExecutionStatus } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
|
|
22
22
|
|
|
23
|
+
import { TranscriptBuilder } from "../../harness/transcript/builder.js";
|
|
23
24
|
import type { TurnSink, UsageDelta } from "../../harness/types.js";
|
|
24
25
|
import type { CasTouchedReader } from "../../shared/filereview/cas-touched.js";
|
|
25
26
|
import { TimingRecorder } from "../../shared/cold-start-timing.js";
|
|
@@ -35,14 +36,22 @@ export type SinkEvent =
|
|
|
35
36
|
| { readonly kind: "cas-observations" };
|
|
36
37
|
|
|
37
38
|
export interface RecordingTurnSinkOptions {
|
|
38
|
-
/**
|
|
39
|
+
/**
|
|
40
|
+
* The status this turn folds into; a fresh empty one when omitted. A
|
|
41
|
+
* reinvocation's clone arrives already carrying last turn's rows, and the
|
|
42
|
+
* builder indexes them as the runtime's would after its seed.
|
|
43
|
+
*/
|
|
39
44
|
readonly status?: AgentExecutionStatus;
|
|
45
|
+
/** The execution the builder names in its log lines; the kit's driver passes its own. */
|
|
46
|
+
readonly executionId?: string;
|
|
40
47
|
/** When set, `bindHarnessState` rejects with this error (a failed session write). */
|
|
41
48
|
readonly bindRejectsWith?: Error;
|
|
42
49
|
}
|
|
43
50
|
|
|
44
51
|
export class RecordingTurnSink implements TurnSink {
|
|
45
52
|
readonly status: AgentExecutionStatus;
|
|
53
|
+
/** The one builder over `status`, as the runtime hands every adapter; the fake creates its rows through it. */
|
|
54
|
+
readonly transcript: TranscriptBuilder;
|
|
46
55
|
readonly stopSignal: AbortSignal;
|
|
47
56
|
readonly setupTiming = new TimingRecorder();
|
|
48
57
|
|
|
@@ -52,6 +61,7 @@ export class RecordingTurnSink implements TurnSink {
|
|
|
52
61
|
|
|
53
62
|
constructor(options: RecordingTurnSinkOptions = {}) {
|
|
54
63
|
this.status = options.status ?? emptyStatus();
|
|
64
|
+
this.transcript = new TranscriptBuilder(options.executionId ?? "kit-exec", this.status);
|
|
55
65
|
this.stopSignal = this.controller.signal;
|
|
56
66
|
this.bindRejectsWith = options.bindRejectsWith;
|
|
57
67
|
}
|
|
@@ -19,7 +19,9 @@
|
|
|
19
19
|
* the facts the runtime owes on it: the terminal phase, the copy
|
|
20
20
|
* (`terminal-table.ts` `TERMINAL_COPY`, byte-pinned), `status.error`,
|
|
21
21
|
* `completedAt`, "the step after never runs", the whole-activity heartbeat,
|
|
22
|
-
* one bind for an engine-minted harness, the slim return
|
|
22
|
+
* one bind for an engine-minted harness, the slim return, and — on every
|
|
23
|
+
* arm, whatever the outcome — a transcript that streams nothing once the
|
|
24
|
+
* turn has settled ({@link assertTranscriptStreamsNothing}). What is NOT
|
|
23
25
|
* asserted here is engine cadence — how many IN_PROGRESS persists precede
|
|
24
26
|
* the WAITING write, the exact setup labels beyond the runtime's own, the
|
|
25
27
|
* exact price a vendor's table yields — because those are a subject's facts;
|
|
@@ -216,13 +218,47 @@ export class RuntimeExecutionDriver {
|
|
|
216
218
|
}
|
|
217
219
|
}
|
|
218
220
|
|
|
219
|
-
/**
|
|
221
|
+
/**
|
|
222
|
+
* The final full status the record holds, checked for the one fact every
|
|
223
|
+
* settled turn owes its transcript before the arm reads anything else. An
|
|
224
|
+
* arm that persisted nothing is a failure, named.
|
|
225
|
+
*/
|
|
220
226
|
function finalStatusOf(harness: RuntimeContractHarness, driver: RuntimeExecutionDriver): AgentExecutionStatus {
|
|
221
227
|
const final = driver.record.lastFullStatus;
|
|
222
228
|
if (!final) throw new Error(`${harness.subject.name}: the runtime persisted no full status`);
|
|
229
|
+
assertTranscriptStreamsNothing(harness.subject.name, final);
|
|
223
230
|
return final;
|
|
224
231
|
}
|
|
225
232
|
|
|
233
|
+
/**
|
|
234
|
+
* No streaming flag survives a settled turn — on any message, any tool-call
|
|
235
|
+
* row, in the root transcript or a sub-agent's — however the turn ended. A
|
|
236
|
+
* flag left on is a spinner the console never stops. The runtime closes
|
|
237
|
+
* them once, after `runTurn` returns, on every path (`harness/run-turn.ts`),
|
|
238
|
+
* so the fact holds for every subject and every outcome, and every arm
|
|
239
|
+
* checks it through {@link finalStatusOf}. Before the runtime owned that
|
|
240
|
+
* close, this fired on both real adapters' internal-failure arm: a turn that
|
|
241
|
+
* failed before its settle left its last message streaming. Exported so the
|
|
242
|
+
* kit's self-check can hand it a status that still streams and prove it
|
|
243
|
+
* fires.
|
|
244
|
+
*/
|
|
245
|
+
export function assertTranscriptStreamsNothing(subjectName: string, status: AgentExecutionStatus): void {
|
|
246
|
+
const streaming: string[] = [];
|
|
247
|
+
const sweep = (scope: string, messages: AgentExecutionStatus["messages"]): void => {
|
|
248
|
+
messages.forEach((m, i) => {
|
|
249
|
+
if (m.isStreaming) streaming.push(`${scope}messages[${i}]`);
|
|
250
|
+
for (const tc of m.toolCalls) {
|
|
251
|
+
if (tc.isStreaming) streaming.push(`${scope}messages[${i}].toolCalls[${tc.id}]`);
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
};
|
|
255
|
+
sweep("", status.messages);
|
|
256
|
+
for (const sub of status.subAgentExecutions) sweep(`subAgentExecutions[${sub.id}].`, sub.messages);
|
|
257
|
+
if (streaming.length > 0) {
|
|
258
|
+
throw new Error(`${subjectName}: a settled turn's transcript is still streaming at ${streaming.join(", ")}`);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
226
262
|
/** What every arm hands back so a subject's file can add its own facts. */
|
|
227
263
|
export interface RuntimeArmResult {
|
|
228
264
|
readonly driver: RuntimeExecutionDriver;
|
|
@@ -357,11 +393,11 @@ export async function assertFileReviewRoundTrip(harness: RuntimeContractHarness,
|
|
|
357
393
|
expect(rows.get(keepId)?.fileChangeSetId, `${subject.name}: a flowed row is badged with the change set`).toBe(changeSetId);
|
|
358
394
|
expect(rows.get(dropId)?.fileChangeSetId).toBe(changeSetId);
|
|
359
395
|
expect(rows.get(keepId)?.status, `${subject.name}: a flowed row is COMPLETED, never gated`).toBe(ToolCallStatus.TOOL_CALL_COMPLETED);
|
|
360
|
-
// The strip is the runtime's, attached on its writes
|
|
396
|
+
// The strip is the runtime's, attached on its writes. Its COUNT is
|
|
361
397
|
// the capture floor's: a real engine's first persist precedes its first
|
|
362
398
|
// write and both writes land within one floor interval, so the pause can
|
|
363
|
-
// honestly read "0 files" beside a two-file candidate (
|
|
364
|
-
//
|
|
399
|
+
// honestly read "0 files" beside a two-file candidate (#1114: whether the
|
|
400
|
+
// terminal write should bypass the floor). The arm
|
|
365
401
|
// asserts the ownership, not the floor.
|
|
366
402
|
expect(afterCapture.fileChangeProgress?.changeSetId, `${subject.name}: the runtime carries this turn's strip`).toBe(changeSetId);
|
|
367
403
|
expect(afterCapture.completedAt, `${subject.name}: a review pause is not complete`).toBe("");
|
|
@@ -374,7 +410,7 @@ export async function assertFileReviewRoundTrip(harness: RuntimeContractHarness,
|
|
|
374
410
|
const second = await driver.turn([]);
|
|
375
411
|
expect(slimOf(subject, second).phase, `${subject.name}: a pure file-review resume completes without the engine`).toBe("EXECUTION_COMPLETED");
|
|
376
412
|
// The kept file is the engine-not-re-run witness: a subject that counts
|
|
377
|
-
// executions by reading its ledger off disk (the native one
|
|
413
|
+
// executions by reading its ledger off disk (the native one) reads
|
|
378
414
|
// the DISCARDED file's count as 0 now, because the reconcile just restored
|
|
379
415
|
// that file to its baseline — which is the reconcile working, not the
|
|
380
416
|
// engine forgetting.
|
|
@@ -398,7 +434,7 @@ export async function assertFileReviewRoundTrip(harness: RuntimeContractHarness,
|
|
|
398
434
|
* settles the row SKIPPED (a REJECT row carries `error: "Rejected by user"`),
|
|
399
435
|
* so no WAITING row survives on a finished execution. This is the proto
|
|
400
436
|
* contract as of stigmer#197 and the runtime's own write
|
|
401
|
-
* (`harness/approval-decisions.ts`); before
|
|
437
|
+
* (`harness/approval-decisions.ts`); before #1096 the runtime FAILED a
|
|
402
438
|
* REJECTed reinvocation before any engine ran.
|
|
403
439
|
*/
|
|
404
440
|
export async function assertNonExecutingDecisionSettlesSkipped(
|
|
@@ -440,14 +476,14 @@ export async function assertNonExecutingDecisionSettlesSkipped(
|
|
|
440
476
|
* the next message), `error` starting with the cross-repo prefix Stigmer
|
|
441
477
|
* Cloud's channel delivery matches on, the user copy as the one system row,
|
|
442
478
|
* `completedAt` stamped, RETURNED (a retry would spend the same budget), and
|
|
443
|
-
* the step after the limit never processed. Before
|
|
444
|
-
* RETURNED this terminal without persisting it
|
|
479
|
+
* the step after the limit never processed. Before #1096 the native harness
|
|
480
|
+
* RETURNED this terminal without persisting it; the
|
|
445
481
|
* runtime's arm is the one persisted terminal.
|
|
446
482
|
*
|
|
447
483
|
* The execution SETS the budget it exhausts: the record carries the smallest
|
|
448
484
|
* valid `max_tool_rounds` (an unbounded execution has no limit to reach — on
|
|
449
485
|
* native `resolveRecursionLimit(0)` is unlimited, and the first run of this
|
|
450
|
-
* arm against it spun until the test timed out
|
|
486
|
+
* arm against it spun until the test timed out). The fake
|
|
451
487
|
* exhausts whatever budget it is given; a real engine spins its cheapest
|
|
452
488
|
* ungated tool until the graph stops it.
|
|
453
489
|
*/
|
|
@@ -625,12 +661,12 @@ const STALL_CLOCK_INTERVAL_MS = 25;
|
|
|
625
661
|
* park is reported while the chunks the engine produced before parking are
|
|
626
662
|
* still in its event pipeline ahead of the adapter's loop, so activity marks
|
|
627
663
|
* land AFTER a single tick and a frozen clock reads idle 0 from then on
|
|
628
|
-
* (
|
|
664
|
+
* (measured on the native adapter: 35 marks at the park, 37
|
|
629
665
|
* within 10 ms). A pull-based double's park implies everything before it
|
|
630
666
|
* was seen; a real stall is wall time passing while the engine is silent,
|
|
631
667
|
* whichever shape the engine has. The interval advances a SCRIPTED clock —
|
|
632
668
|
* the kit's rule against timers is about stopping a turn on a guess, which
|
|
633
|
-
* this never does
|
|
669
|
+
* this never does.
|
|
634
670
|
*/
|
|
635
671
|
export async function assertStallFailsTheTurn(harness: RuntimeContractHarness, label = "rt-stall"): Promise<RuntimeArmResult> {
|
|
636
672
|
const { subject, clock } = harness;
|
|
@@ -692,7 +728,7 @@ export async function assertCostCapTerminates(harness: RuntimeContractHarness, l
|
|
|
692
728
|
/**
|
|
693
729
|
* A platform STOP answered to a mid-turn persist: the turn completes early
|
|
694
730
|
* with the platform-stop row and no error, and the step after the STOP never
|
|
695
|
-
* runs — the awaited `requestPersist` at work
|
|
731
|
+
* runs — the awaited `requestPersist` at work. The persist the
|
|
696
732
|
* control plane answers is the one carrying a completed `read`: the discrete
|
|
697
733
|
* event every harness flushes on (the Cursor golden's lever), where a bare
|
|
698
734
|
* assistant message may ride an engine's cadence to the settle persist, too
|
|
@@ -786,7 +822,7 @@ export async function assertFailedSurfaceWritesItsCopy(harness: RuntimeContractH
|
|
|
786
822
|
|
|
787
823
|
/**
|
|
788
824
|
* A rejected `bindHarnessState` (the session write refused) ends the turn
|
|
789
|
-
* FAILED on the internal surface with nothing executed
|
|
825
|
+
* FAILED on the internal surface with nothing executed.
|
|
790
826
|
* Engine-minted harnesses only: a deterministic one never binds.
|
|
791
827
|
*/
|
|
792
828
|
export async function assertRejectedBindFails(harness: RuntimeContractHarness, label = "rt-bind-rejects"): Promise<RuntimeArmResult> {
|
|
@@ -884,7 +920,7 @@ export interface RuntimeContractOptions {
|
|
|
884
920
|
* to wait for (`scenario.cancelled()`, an SDK-side cancel); the arm is
|
|
885
921
|
* registered SKIPPED otherwise. On by default; the native subject turns it
|
|
886
922
|
* off (no LangGraph path ends a turn `cancelled` — a stop is the runtime's
|
|
887
|
-
* and settles `interrupted
|
|
923
|
+
* and settles `interrupted`).
|
|
888
924
|
*/
|
|
889
925
|
readonly engineCancel?: boolean;
|
|
890
926
|
}
|
|
@@ -968,7 +1004,7 @@ export function describeHarnessRuntimeContract(harness: RuntimeContractHarness,
|
|
|
968
1004
|
await assertFailedSurfaceWritesItsCopy(harness, surface, FAILURE_MESSAGES[surface]);
|
|
969
1005
|
});
|
|
970
1006
|
}
|
|
971
|
-
it.skipIf(subject.adapter.capabilities.stateIdSource !== "engine-minted")("a rejected bindHarnessState ends the turn failed with nothing executed
|
|
1007
|
+
it.skipIf(subject.adapter.capabilities.stateIdSource !== "engine-minted")("a rejected bindHarnessState ends the turn failed with nothing executed", async () => {
|
|
972
1008
|
clock.reset();
|
|
973
1009
|
await assertRejectedBindFails(harness);
|
|
974
1010
|
});
|
|
@@ -22,8 +22,12 @@
|
|
|
22
22
|
*
|
|
23
23
|
* What is deliberately simple here and would be real work in an adapter:
|
|
24
24
|
* "executing" a side effect is incrementing a counter; the engine state id is
|
|
25
|
-
* a counter too;
|
|
26
|
-
*
|
|
25
|
+
* a counter too; there is no engine event to translate, so each step emits
|
|
26
|
+
* the canonical `TranscriptEvent`s a translator would (a run for a `say`, a
|
|
27
|
+
* start and a finish for a tool, a proposal for a gate) straight into
|
|
28
|
+
* `sink.transcript` — the one way any harness creates a transcript row, and
|
|
29
|
+
* the whole of what a real adapter's translator adds on top of this file.
|
|
30
|
+
* What is NOT simplified is the contract behaviour itself —
|
|
27
31
|
* settling with an outcome and never rejecting, stopping at every step
|
|
28
32
|
* boundary and inside a hang, binding before the first persist, executing an
|
|
29
33
|
* approval exactly once, refusing to resume a state it never minted — because
|
|
@@ -34,8 +38,8 @@
|
|
|
34
38
|
* is on the row (the server's field) and the transition follows from it with
|
|
35
39
|
* no engine knowledge, so it belongs to the runtime — one writer per field,
|
|
36
40
|
* as `approvalDecisionsOf` is the runtime's one reader and
|
|
37
|
-
* `terminalizeNonExecutingDecisions` its one writer (
|
|
38
|
-
*
|
|
41
|
+
* `terminalizeNonExecutingDecisions` its one writer (landed in #1096,
|
|
42
|
+
* `harness/approval-decisions.ts`). An adapter's whole duty for a
|
|
39
43
|
* non-executing decision is to not execute.
|
|
40
44
|
*
|
|
41
45
|
* Scenarios are arranged PER SESSION (the engine is per session in every real
|
|
@@ -57,7 +61,7 @@ import type { HarnessAdapter, TurnInput, TurnOutcome, TurnSink } from "../../har
|
|
|
57
61
|
import { DEEP_AGENT_VISION_PROFILE } from "../../shared/attachment-vision.js";
|
|
58
62
|
import type { ProposedAction } from "../approval-contract/types.js";
|
|
59
63
|
import { testConfig } from "../config-fixture.js";
|
|
60
|
-
import {
|
|
64
|
+
import { findToolCallRow } from "../proto-helpers.js";
|
|
61
65
|
import type { EngineView, HarnessContractSubject, ScenarioStep, TurnScenario } from "./types.js";
|
|
62
66
|
|
|
63
67
|
export interface ScriptedHarnessOptions {
|
|
@@ -101,6 +105,8 @@ export class ScriptedHarnessAdapter implements HarnessAdapter {
|
|
|
101
105
|
private readonly executions = new Map<string, number>();
|
|
102
106
|
private readonly hangWaiters: Array<() => void> = [];
|
|
103
107
|
private mintCounter = 0;
|
|
108
|
+
/** One `runId` per `say`, as an engine mints one per model run; the builder keys a message on it. */
|
|
109
|
+
private runCounter = 0;
|
|
104
110
|
|
|
105
111
|
constructor(options: ScriptedHarnessOptions) {
|
|
106
112
|
this.name = options.name ?? `scripted(${options.pausePrimitive}, ${options.stateIdSource})`;
|
|
@@ -211,7 +217,12 @@ export class ScriptedHarnessAdapter implements HarnessAdapter {
|
|
|
211
217
|
private async play(step: ScenarioStep, input: TurnInput, sink: TurnSink): Promise<TurnOutcome | undefined> {
|
|
212
218
|
switch (step.kind) {
|
|
213
219
|
case "say": {
|
|
214
|
-
|
|
220
|
+
// One model run: start, its text, finish — the shape every
|
|
221
|
+
// translator emits for an assistant message.
|
|
222
|
+
const runId = `run-${++this.runCounter}`;
|
|
223
|
+
sink.transcript.apply({ kind: "message_start", runId });
|
|
224
|
+
sink.transcript.apply({ kind: "text_delta", runId, text: step.text });
|
|
225
|
+
sink.transcript.apply({ kind: "message_finish", runId });
|
|
215
226
|
sink.recordActivity();
|
|
216
227
|
// Awaited, as the Cursor loop awaits its own: a platform STOP the
|
|
217
228
|
// runtime reads from this write aborts the signal before the next
|
|
@@ -223,14 +234,12 @@ export class ScriptedHarnessAdapter implements HarnessAdapter {
|
|
|
223
234
|
if (step.flows) return this.flowingWrite(step.toolCallId, step.action, input, sink);
|
|
224
235
|
return this.propose(step.toolCallId, step.action, input, sink);
|
|
225
236
|
case "read": {
|
|
226
|
-
// Ungated: the row
|
|
227
|
-
// and the persist is awaited like `say`'s — a real engine's tool
|
|
228
|
-
// is the discrete event its loop flushes on.
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
message.toolCalls.push(row);
|
|
233
|
-
sink.status.messages.push(message);
|
|
237
|
+
// Ungated: the row starts and finishes at once, the effect counts as
|
|
238
|
+
// run, and the persist is awaited like `say`'s — a real engine's tool
|
|
239
|
+
// call is the discrete event its loop flushes on. The builder puts
|
|
240
|
+
// the row on the message whose text preceded it.
|
|
241
|
+
sink.transcript.apply({ kind: "tool_started", callId: step.toolCallId, name: "read", input: { path: step.path }, mcpServerSlug: "" });
|
|
242
|
+
sink.transcript.apply({ kind: "tool_finished", callId: step.toolCallId, result: `contents of ${step.path}` });
|
|
234
243
|
this.executions.set(step.toolCallId, this.executionCount(step.toolCallId) + 1);
|
|
235
244
|
sink.recordActivity("read");
|
|
236
245
|
await sink.requestPersist();
|
|
@@ -279,12 +288,18 @@ export class ScriptedHarnessAdapter implements HarnessAdapter {
|
|
|
279
288
|
switch (decision) {
|
|
280
289
|
case ApprovalAction.UNSPECIFIED: {
|
|
281
290
|
// Propose: surface the gated call as a WAITING row and stop the turn.
|
|
282
|
-
//
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
291
|
+
// `approval_proposed` is an upsert by id — a resumed turn that
|
|
292
|
+
// re-proposes reopens the seeded row, never writes a second one. No
|
|
293
|
+
// `args` on purpose: a `write` carrying whole-file content would make
|
|
294
|
+
// the runtime's exact-apply eligible on APPROVE, and this fake's
|
|
295
|
+
// execution count would then measure a path the engine never ran.
|
|
296
|
+
sink.transcript.apply({
|
|
297
|
+
kind: "approval_proposed",
|
|
298
|
+
callId: toolCallId,
|
|
299
|
+
name: action.kind,
|
|
300
|
+
mcpServerSlug: "",
|
|
301
|
+
message: `Approve ${action.kind} ${action.resource}?`,
|
|
302
|
+
});
|
|
288
303
|
sink.recordActivity();
|
|
289
304
|
sink.requestPersist();
|
|
290
305
|
return { kind: "awaiting_approval" };
|
|
@@ -292,7 +307,7 @@ export class ScriptedHarnessAdapter implements HarnessAdapter {
|
|
|
292
307
|
case ApprovalAction.APPROVE:
|
|
293
308
|
case ApprovalAction.APPROVE_ALL: {
|
|
294
309
|
this.executions.set(toolCallId, this.executionCount(toolCallId) + 1);
|
|
295
|
-
this.completeRow(
|
|
310
|
+
this.completeRow(toolCallId, action, sink);
|
|
296
311
|
return undefined;
|
|
297
312
|
}
|
|
298
313
|
case ApprovalAction.SKIP:
|
|
@@ -321,11 +336,8 @@ export class ScriptedHarnessAdapter implements HarnessAdapter {
|
|
|
321
336
|
const file = join(input.workspace.primaryDir, action.resource);
|
|
322
337
|
await mkdir(dirname(file), { recursive: true });
|
|
323
338
|
await writeFile(file, `${toolCallId}\n`);
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
row.args = { path: action.resource };
|
|
327
|
-
message.toolCalls.push(row);
|
|
328
|
-
sink.status.messages.push(message);
|
|
339
|
+
sink.transcript.apply({ kind: "tool_started", callId: toolCallId, name: "write", input: { path: action.resource }, mcpServerSlug: "" });
|
|
340
|
+
sink.transcript.apply({ kind: "tool_finished", callId: toolCallId, result: "" });
|
|
329
341
|
this.executions.set(toolCallId, this.executionCount(toolCallId) + 1);
|
|
330
342
|
sink.recordActivity("write");
|
|
331
343
|
await sink.requestPersist();
|
|
@@ -333,22 +345,14 @@ export class ScriptedHarnessAdapter implements HarnessAdapter {
|
|
|
333
345
|
}
|
|
334
346
|
|
|
335
347
|
/**
|
|
336
|
-
* Report the executed action on its row, as a real engine's
|
|
337
|
-
*
|
|
338
|
-
*
|
|
339
|
-
*
|
|
340
|
-
* losing the fact.
|
|
348
|
+
* Report the executed action on its row, as a real engine's re-issue does:
|
|
349
|
+
* a start (which flips the seeded WAITING row to RUNNING — or creates the
|
|
350
|
+
* row when a runtime decided out of band and no row exists, so the fact is
|
|
351
|
+
* recorded rather than lost) and a finish.
|
|
341
352
|
*/
|
|
342
|
-
private completeRow(
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
} else {
|
|
346
|
-
const message = aiMessage("");
|
|
347
|
-
const row = waitingToolCall(toolCallId, action.kind, "");
|
|
348
|
-
row.status = ToolCallStatus.TOOL_CALL_COMPLETED;
|
|
349
|
-
message.toolCalls.push(row);
|
|
350
|
-
sink.status.messages.push(message);
|
|
351
|
-
}
|
|
353
|
+
private completeRow(toolCallId: string, action: ProposedAction, sink: TurnSink): void {
|
|
354
|
+
sink.transcript.apply({ kind: "tool_started", callId: toolCallId, name: action.kind, input: {}, mcpServerSlug: "" });
|
|
355
|
+
sink.transcript.apply({ kind: "tool_finished", callId: toolCallId, result: "" });
|
|
352
356
|
sink.recordActivity();
|
|
353
357
|
sink.requestPersist();
|
|
354
358
|
}
|
|
@@ -360,8 +364,8 @@ export interface ScriptedSubject extends HarnessContractSubject {
|
|
|
360
364
|
}
|
|
361
365
|
|
|
362
366
|
/**
|
|
363
|
-
* The fake declares the `deep-agent` row: in
|
|
364
|
-
* through this fake alone; since
|
|
367
|
+
* The fake declares the `deep-agent` row: in #1070 the runtime served that row
|
|
368
|
+
* through this fake alone; since #1096 the real native adapter takes it over
|
|
365
369
|
* in the runtime half
|
|
366
370
|
* (`execute-deep-agent/__test-utils__/contract-subject.ts`), and the fake
|
|
367
371
|
* keeps declaring it so the kit's self-check runs a full subject under both
|