@stigmer/runner 3.14.1 → 3.15.0
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/dist/.build-fingerprint +1 -1
- package/dist/__test-utils__/execution-record-fixture.d.ts +47 -0
- package/dist/__test-utils__/execution-record-fixture.js +68 -0
- package/dist/__test-utils__/execution-record-fixture.js.map +1 -0
- package/dist/__test-utils__/harness-contract/types.d.ts +166 -0
- package/dist/__test-utils__/harness-contract/types.js +49 -0
- package/dist/__test-utils__/harness-contract/types.js.map +1 -0
- package/dist/__test-utils__/hermetic-activity.d.ts +28 -5
- package/dist/__test-utils__/hermetic-activity.js +23 -7
- package/dist/__test-utils__/hermetic-activity.js.map +1 -1
- package/dist/__test-utils__/mock-workspace.d.ts +15 -0
- package/dist/__test-utils__/mock-workspace.js +21 -0
- package/dist/__test-utils__/mock-workspace.js.map +1 -0
- package/dist/__test-utils__/model-registry-fixture.d.ts +56 -0
- package/dist/__test-utils__/model-registry-fixture.js +66 -0
- package/dist/__test-utils__/model-registry-fixture.js.map +1 -0
- package/dist/__test-utils__/turn-input-fixture.d.ts +60 -0
- package/dist/__test-utils__/turn-input-fixture.js +118 -0
- package/dist/__test-utils__/turn-input-fixture.js.map +1 -0
- package/dist/activities/execute-cursor/__test-utils__/contract-subject.d.ts +107 -0
- package/dist/activities/execute-cursor/__test-utils__/contract-subject.js +344 -0
- package/dist/activities/execute-cursor/__test-utils__/contract-subject.js.map +1 -0
- package/dist/activities/execute-cursor/__test-utils__/cursor-hook-harness.d.ts +20 -0
- package/dist/activities/execute-cursor/__test-utils__/cursor-hook-harness.js +58 -0
- package/dist/activities/execute-cursor/__test-utils__/cursor-hook-harness.js.map +1 -1
- package/dist/activities/execute-cursor/__test-utils__/gateway-substrate.js +2 -32
- package/dist/activities/execute-cursor/__test-utils__/gateway-substrate.js.map +1 -1
- package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.d.ts +38 -62
- package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.js +47 -121
- package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.js.map +1 -1
- package/dist/activities/execute-cursor/__test-utils__/scripted-agent.d.ts +17 -1
- package/dist/activities/execute-cursor/__test-utils__/scripted-agent.js +27 -4
- package/dist/activities/execute-cursor/__test-utils__/scripted-agent.js.map +1 -1
- package/dist/activities/execute-cursor/__test-utils__/scripted-sdk.d.ts +52 -11
- package/dist/activities/execute-cursor/__test-utils__/scripted-sdk.js +66 -7
- package/dist/activities/execute-cursor/__test-utils__/scripted-sdk.js.map +1 -1
- package/dist/activities/execute-cursor/adapter.d.ts +55 -0
- package/dist/activities/execute-cursor/adapter.js +119 -0
- package/dist/activities/execute-cursor/adapter.js.map +1 -0
- package/dist/activities/execute-cursor/approval-state.d.ts +2 -2
- package/dist/activities/execute-cursor/approval-state.js.map +1 -1
- package/dist/activities/execute-cursor/capture-flow.d.ts +15 -30
- package/dist/activities/execute-cursor/capture-flow.js +17 -26
- package/dist/activities/execute-cursor/capture-flow.js.map +1 -1
- package/dist/activities/execute-cursor/cursor-capabilities.d.ts +23 -0
- package/dist/activities/execute-cursor/cursor-capabilities.js +33 -0
- package/dist/activities/execute-cursor/cursor-capabilities.js.map +1 -0
- package/dist/activities/execute-cursor/cursor-mcp-config.d.ts +2 -2
- package/dist/activities/execute-cursor/cursor-mcp-config.js.map +1 -1
- package/dist/activities/execute-cursor/fetch-interceptor.d.ts +15 -25
- package/dist/activities/execute-cursor/fetch-interceptor.js +39 -33
- package/dist/activities/execute-cursor/fetch-interceptor.js.map +1 -1
- package/dist/activities/execute-cursor/http2-interceptor.d.ts +21 -17
- package/dist/activities/execute-cursor/http2-interceptor.js +38 -31
- package/dist/activities/execute-cursor/http2-interceptor.js.map +1 -1
- package/dist/activities/execute-cursor/message-translator.d.ts +28 -19
- package/dist/activities/execute-cursor/message-translator.js +76 -27
- package/dist/activities/execute-cursor/message-translator.js.map +1 -1
- package/dist/activities/execute-cursor/prompt-builder.d.ts +180 -11
- package/dist/activities/execute-cursor/prompt-builder.js +171 -0
- package/dist/activities/execute-cursor/prompt-builder.js.map +1 -1
- package/dist/activities/execute-cursor/rejection-capture.d.ts +3 -6
- package/dist/activities/execute-cursor/rejection-capture.js +5 -7
- package/dist/activities/execute-cursor/rejection-capture.js.map +1 -1
- package/dist/activities/execute-cursor/session-lifecycle.d.ts +1 -4
- package/dist/activities/execute-cursor/session-lifecycle.js.map +1 -1
- package/dist/activities/execute-cursor/turn-boundary.d.ts +1 -1
- package/dist/activities/execute-cursor/turn-settle.d.ts +49 -0
- package/dist/activities/execute-cursor/turn-settle.js +507 -0
- package/dist/activities/execute-cursor/turn-settle.js.map +1 -0
- package/dist/activities/execute-cursor/turn-setup.d.ts +173 -0
- package/dist/activities/execute-cursor/turn-setup.js +496 -0
- package/dist/activities/execute-cursor/turn-setup.js.map +1 -0
- package/dist/activities/execute-cursor/turn-stream.d.ts +41 -71
- package/dist/activities/execute-cursor/turn-stream.js +70 -135
- package/dist/activities/execute-cursor/turn-stream.js.map +1 -1
- package/dist/activities/execute-cursor/turn.d.ts +43 -0
- package/dist/activities/execute-cursor/turn.js +222 -0
- package/dist/activities/execute-cursor/turn.js.map +1 -0
- package/dist/activities/execute-cursor/usage-pricing.d.ts +38 -0
- package/dist/activities/execute-cursor/usage-pricing.js +50 -0
- package/dist/activities/execute-cursor/usage-pricing.js.map +1 -0
- package/dist/activities/execute-deep-agent/approval-file-change.d.ts +1 -1
- package/dist/activities/execute-deep-agent/approval-file-change.js +1 -1
- package/dist/activities/execute-deep-agent/environment.js +1 -1
- package/dist/activities/execute-deep-agent/environment.js.map +1 -1
- package/dist/activities/execute-deep-agent/setup.js +3 -2
- package/dist/activities/execute-deep-agent/setup.js.map +1 -1
- package/dist/activities/hydrate-workflow-execution.js +1 -1
- package/dist/activities/hydrate-workflow-execution.js.map +1 -1
- package/dist/config.d.ts +15 -0
- package/dist/config.js.map +1 -1
- package/dist/harness/capabilities.d.ts +16 -0
- package/dist/harness/capabilities.js +1 -0
- package/dist/harness/capabilities.js.map +1 -1
- package/dist/harness/persist-chokepoint.d.ts +74 -0
- package/dist/harness/persist-chokepoint.js +88 -0
- package/dist/harness/persist-chokepoint.js.map +1 -0
- package/dist/harness/registry.d.ts +44 -5
- package/dist/harness/registry.js +61 -5
- package/dist/harness/registry.js.map +1 -1
- package/dist/harness/run-turn.d.ts +53 -0
- package/dist/harness/run-turn.js +528 -0
- package/dist/harness/run-turn.js.map +1 -0
- package/dist/harness/stop-controller.d.ts +50 -0
- package/dist/harness/stop-controller.js +62 -0
- package/dist/harness/stop-controller.js.map +1 -0
- package/dist/harness/terminal-table.d.ts +141 -0
- package/dist/harness/terminal-table.js +239 -0
- package/dist/harness/terminal-table.js.map +1 -0
- package/dist/harness/turn-context.d.ts +523 -0
- package/dist/harness/turn-context.js +739 -0
- package/dist/harness/turn-context.js.map +1 -0
- package/dist/harness/types.d.ts +232 -52
- package/dist/harness/types.js +17 -8
- package/dist/harness/types.js.map +1 -1
- package/dist/harness/usage-accumulator.d.ts +68 -0
- package/dist/harness/usage-accumulator.js +101 -0
- package/dist/harness/usage-accumulator.js.map +1 -0
- package/dist/harness-adapters.d.ts +27 -0
- package/dist/harness-adapters.js +28 -0
- package/dist/harness-adapters.js.map +1 -0
- package/dist/main.js.map +1 -1
- package/dist/runner-manager.js +64 -48
- package/dist/runner-manager.js.map +1 -1
- package/dist/runner.d.ts +5 -4
- package/dist/runner.js +65 -64
- package/dist/runner.js.map +1 -1
- package/dist/shared/approval-policy.d.ts +1 -1
- package/dist/shared/approval-policy.js.map +1 -1
- package/dist/{activities/execute-cursor → shared}/attachment-resolver.d.ts +2 -2
- package/dist/{activities/execute-cursor → shared}/attachment-resolver.js +5 -5
- package/dist/shared/attachment-resolver.js.map +1 -0
- package/dist/{activities/execute-cursor → shared}/blueprint-resolver.d.ts +7 -5
- package/dist/{activities/execute-cursor → shared}/blueprint-resolver.js +3 -63
- package/dist/shared/blueprint-resolver.js.map +1 -0
- package/dist/shared/channel-attachment.d.ts +1 -1
- package/dist/shared/channel-attachment.js.map +1 -1
- package/dist/{activities/execute-cursor → shared}/cost-guard.d.ts +5 -1
- package/dist/{activities/execute-cursor → shared}/cost-guard.js +5 -1
- package/dist/shared/cost-guard.js.map +1 -0
- package/dist/{activities/execute-cursor → shared}/env-resolver.d.ts +1 -1
- package/dist/shared/env-resolver.js.map +1 -0
- package/dist/{activities/execute-cursor → shared}/exact-apply.d.ts +1 -1
- package/dist/{activities/execute-cursor → shared}/exact-apply.js +6 -6
- package/dist/shared/exact-apply.js.map +1 -0
- package/dist/shared/execution-context.d.ts +35 -0
- package/dist/shared/execution-context.js +38 -0
- package/dist/shared/execution-context.js.map +1 -0
- package/dist/{activities/execute-cursor → shared}/extract-structured-output.d.ts +5 -2
- package/dist/{activities/execute-cursor → shared}/extract-structured-output.js +9 -6
- package/dist/shared/extract-structured-output.js.map +1 -0
- package/dist/shared/filereview/capture.d.ts +1 -1
- package/dist/shared/filereview/capture.js +1 -1
- package/dist/shared/heartbeat.d.ts +13 -11
- package/dist/shared/heartbeat.js +14 -29
- package/dist/shared/heartbeat.js.map +1 -1
- package/dist/{activities/execute-cursor → shared}/persist-decision.d.ts +5 -2
- package/dist/{activities/execute-cursor → shared}/persist-decision.js +4 -1
- package/dist/shared/persist-decision.js.map +1 -0
- package/dist/{activities/execute-cursor → shared}/skill-resolver.d.ts +16 -3
- package/dist/{activities/execute-cursor → shared}/skill-resolver.js +12 -4
- package/dist/shared/skill-resolver.js.map +1 -0
- package/dist/shared/subagent-rows.d.ts +21 -0
- package/dist/shared/subagent-rows.js +34 -0
- package/dist/shared/subagent-rows.js.map +1 -0
- package/dist/shared/worker-shutdown.d.ts +43 -16
- package/dist/shared/worker-shutdown.js +28 -13
- package/dist/shared/worker-shutdown.js.map +1 -1
- package/dist/shared/workspace/platform-dir.d.ts +1 -1
- package/dist/shared/workspace/platform-dir.js +1 -1
- package/dist/shared/workspace/session-provision.d.ts +54 -0
- package/dist/{activities/execute-cursor/workspace-provision.js → shared/workspace/session-provision.js} +15 -12
- package/dist/shared/workspace/session-provision.js.map +1 -0
- package/package.json +4 -4
- package/src/__test-utils__/__tests__/harness-contract-self-check.test.ts +110 -14
- package/src/__test-utils__/execution-record-fixture.ts +104 -0
- package/src/__test-utils__/harness-boot-order-child.ts +58 -0
- package/src/__test-utils__/harness-contract/contract.ts +128 -83
- package/src/__test-utils__/harness-contract/recording-sink.ts +15 -4
- package/src/__test-utils__/harness-contract/runtime-contract.ts +666 -0
- package/src/__test-utils__/harness-contract/scripted-adapter.ts +92 -32
- package/src/__test-utils__/harness-contract/types.ts +85 -9
- package/src/__test-utils__/hermetic-activity.ts +33 -8
- package/src/__test-utils__/model-registry-fixture.ts +72 -0
- package/src/__test-utils__/module-specifiers.ts +82 -0
- package/src/__test-utils__/turn-input-fixture.ts +155 -0
- package/src/__tests__/harness-boot-order.test.ts +77 -0
- package/src/__tests__/harness-contract.test.ts +7 -5
- package/src/__tests__/runner-manager.test.ts +18 -0
- package/src/activities/execute-cursor/__test-utils__/__tests__/scripted-double.test.ts +102 -0
- package/src/activities/execute-cursor/__test-utils__/contract-subject.ts +396 -0
- package/src/activities/execute-cursor/__test-utils__/cursor-hook-harness.ts +66 -0
- package/src/activities/execute-cursor/__test-utils__/gateway-substrate.ts +2 -43
- package/src/activities/execute-cursor/__test-utils__/hermetic-cursor.ts +65 -145
- package/src/activities/execute-cursor/__test-utils__/scripted-agent.ts +30 -4
- package/src/activities/execute-cursor/__test-utils__/scripted-sdk.ts +96 -8
- package/src/activities/execute-cursor/__tests__/adapter-is-temporal-free.test.ts +45 -0
- package/src/activities/execute-cursor/__tests__/approval-decisions-agree.test.ts +90 -0
- package/src/activities/execute-cursor/__tests__/build-prompt.test.ts +7 -8
- package/src/activities/execute-cursor/__tests__/capture-flow.test.ts +28 -1
- package/src/activities/execute-cursor/__tests__/deny-gate-exact-apply.test.ts +1 -1
- package/src/activities/execute-cursor/__tests__/fetch-interceptor.test.ts +64 -6
- package/src/activities/execute-cursor/__tests__/hermetic/deny-and-retry.test.ts +1 -1
- package/src/activities/execute-cursor/__tests__/hermetic/file-review-capture.test.ts +1 -1
- package/src/activities/execute-cursor/__tests__/hermetic/goldens/cost-cap.status.json +53 -0
- package/src/activities/execute-cursor/__tests__/hermetic/goldens/pause.status.json +1 -6
- package/src/activities/execute-cursor/__tests__/hermetic/goldens/platform-stop.status.json +56 -0
- package/src/activities/execute-cursor/__tests__/hermetic/goldens/recovery-transport-timeout.status.json +48 -0
- package/src/activities/execute-cursor/__tests__/hermetic/goldens/resolution-error.status.json +18 -0
- package/src/activities/execute-cursor/__tests__/hermetic/goldens/run-cancelled.status.json +36 -0
- package/src/activities/execute-cursor/__tests__/hermetic/goldens/run-error-non-retryable.status.json +37 -0
- package/src/activities/execute-cursor/__tests__/hermetic/goldens/sdk-error-at-create.status.json +38 -0
- package/src/activities/execute-cursor/__tests__/hermetic/goldens/stall.status.json +59 -0
- package/src/activities/execute-cursor/__tests__/hermetic/goldens/unattributed-hook-block.status.json +79 -0
- package/src/activities/execute-cursor/__tests__/hermetic/goldens/worker-shutdown.status.json +2 -7
- package/src/activities/execute-cursor/__tests__/hermetic/harness-contract.test.ts +170 -0
- package/src/activities/execute-cursor/__tests__/hermetic/pause-vs-shutdown.test.ts +22 -18
- package/src/activities/execute-cursor/__tests__/hermetic/plain-turn.test.ts +1 -1
- package/src/activities/execute-cursor/__tests__/hermetic/recovery-fresh-agent.test.ts +1 -1
- package/src/activities/execute-cursor/__tests__/hermetic/run-wait-arms.test.ts +286 -0
- package/src/activities/execute-cursor/__tests__/hermetic/stream-self-stop-arms.test.ts +332 -0
- package/src/activities/execute-cursor/__tests__/hermetic/thrown-error-arms.test.ts +193 -0
- package/src/activities/execute-cursor/__tests__/hermetic/tool-call.test.ts +1 -1
- package/src/activities/execute-cursor/__tests__/hermetic/unattributed-hook-block.test.ts +185 -0
- package/src/activities/execute-cursor/__tests__/hermetic/workspace-lock-timeout.test.ts +151 -0
- package/src/activities/execute-cursor/__tests__/http2-interceptor.test.ts +65 -35
- package/src/activities/execute-cursor/__tests__/message-translator.test.ts +0 -40
- package/src/activities/execute-cursor/__tests__/same-identity-reproposal.test.ts +171 -0
- package/src/activities/execute-cursor/__tests__/turn-stream.test.ts +118 -243
- package/src/activities/execute-cursor/__tests__/usage-pricing.test.ts +84 -0
- package/src/activities/execute-cursor/adapter.ts +138 -0
- package/src/activities/execute-cursor/approval-state.ts +2 -2
- package/src/activities/execute-cursor/capture-flow.ts +18 -41
- package/src/activities/execute-cursor/cursor-capabilities.ts +35 -0
- package/src/activities/execute-cursor/cursor-mcp-config.ts +2 -2
- package/src/activities/execute-cursor/fetch-interceptor.ts +48 -45
- package/src/activities/execute-cursor/http2-interceptor.ts +47 -34
- package/src/activities/execute-cursor/message-translator.ts +90 -45
- package/src/activities/execute-cursor/prompt-builder.ts +327 -12
- package/src/activities/execute-cursor/rejection-capture.ts +5 -12
- package/src/activities/execute-cursor/session-lifecycle.ts +1 -5
- package/src/activities/execute-cursor/turn-boundary.ts +1 -1
- package/src/activities/execute-cursor/turn-settle.ts +601 -0
- package/src/activities/execute-cursor/turn-setup.ts +645 -0
- package/src/activities/execute-cursor/turn-stream.ts +84 -210
- package/src/activities/execute-cursor/turn.ts +240 -0
- package/src/activities/execute-cursor/usage-pricing.ts +67 -0
- package/src/activities/execute-deep-agent/approval-file-change.ts +1 -1
- package/src/activities/execute-deep-agent/environment.ts +1 -1
- package/src/activities/execute-deep-agent/setup.ts +3 -2
- package/src/activities/hydrate-workflow-execution.ts +1 -1
- package/src/config.ts +13 -0
- package/src/harness/__tests__/import-direction.test.ts +168 -0
- package/src/harness/__tests__/persist-chokepoint.test.ts +146 -0
- package/src/harness/__tests__/registry.test.ts +1 -0
- package/src/harness/__tests__/run-turn.test.ts +165 -0
- package/src/harness/__tests__/stop-controller.test.ts +49 -0
- package/src/harness/__tests__/turn-context.test.ts +178 -0
- package/src/harness/__tests__/usage-accumulator.test.ts +83 -0
- package/src/harness/capabilities.ts +17 -0
- package/src/harness/persist-chokepoint.ts +112 -0
- package/src/harness/registry.ts +79 -5
- package/src/harness/run-turn.ts +618 -0
- package/src/harness/stop-controller.ts +83 -0
- package/src/harness/terminal-table.ts +276 -0
- package/src/harness/turn-context.ts +1028 -0
- package/src/harness/types.ts +248 -53
- package/src/harness/usage-accumulator.ts +122 -0
- package/src/harness-adapters.ts +30 -0
- package/src/main.ts +1 -1
- package/src/runner-manager.ts +68 -61
- package/src/runner.ts +67 -78
- package/src/shared/__tests__/attachment-naming.test.ts +1 -1
- package/src/{activities/execute-cursor → shared}/__tests__/attachment-resolver.test.ts +6 -4
- package/src/{activities/execute-cursor → shared}/__tests__/cost-guard.test.ts +2 -1
- package/src/{activities/execute-cursor → shared}/__tests__/exact-apply.test.ts +3 -3
- package/src/{activities/execute-cursor → shared}/__tests__/extract-structured-output.test.ts +8 -8
- package/src/{activities/execute-cursor → shared}/__tests__/persist-decision.test.ts +4 -2
- package/src/{activities/execute-cursor → shared}/__tests__/skill-resolver.test.ts +1 -1
- package/src/shared/__tests__/subagent-rows.test.ts +34 -0
- package/src/shared/__tests__/worker-shutdown.test.ts +44 -39
- package/src/shared/approval-policy.ts +1 -1
- package/src/{activities/execute-cursor → shared}/attachment-resolver.ts +6 -6
- package/src/{activities/execute-cursor → shared}/blueprint-resolver.ts +7 -78
- package/src/shared/channel-attachment.ts +1 -1
- package/src/{activities/execute-cursor → shared}/cost-guard.ts +5 -1
- package/src/{activities/execute-cursor → shared}/env-resolver.ts +1 -1
- package/src/{activities/execute-cursor → shared}/exact-apply.ts +7 -7
- package/src/shared/execution-context.ts +45 -0
- package/src/{activities/execute-cursor → shared}/extract-structured-output.ts +10 -7
- package/src/shared/filereview/capture.ts +1 -1
- package/src/shared/heartbeat.ts +13 -33
- package/src/{activities/execute-cursor → shared}/persist-decision.ts +5 -2
- package/src/{activities/execute-cursor → shared}/skill-resolver.ts +20 -6
- package/src/shared/subagent-rows.ts +39 -0
- package/src/shared/worker-shutdown.ts +55 -25
- package/src/{activities/execute-cursor/__tests__/workspace-provision.test.ts → shared/workspace/__tests__/session-provision.test.ts} +25 -28
- package/src/shared/workspace/platform-dir.ts +1 -1
- package/src/{activities/execute-cursor/workspace-provision.ts → shared/workspace/session-provision.ts} +29 -16
- package/dist/activities/execute-cursor/attachment-resolver.js.map +0 -1
- package/dist/activities/execute-cursor/blueprint-resolver.js.map +0 -1
- package/dist/activities/execute-cursor/cost-guard.js.map +0 -1
- package/dist/activities/execute-cursor/env-resolver.js.map +0 -1
- package/dist/activities/execute-cursor/exact-apply.js.map +0 -1
- package/dist/activities/execute-cursor/extract-structured-output.js.map +0 -1
- package/dist/activities/execute-cursor/index.d.ts +0 -209
- package/dist/activities/execute-cursor/index.js +0 -2345
- package/dist/activities/execute-cursor/index.js.map +0 -1
- package/dist/activities/execute-cursor/persist-decision.js.map +0 -1
- package/dist/activities/execute-cursor/skill-resolver.js.map +0 -1
- package/dist/activities/execute-cursor/usage-accumulator.d.ts +0 -89
- package/dist/activities/execute-cursor/usage-accumulator.js +0 -121
- package/dist/activities/execute-cursor/usage-accumulator.js.map +0 -1
- package/dist/activities/execute-cursor/workspace-provision.d.ts +0 -42
- package/dist/activities/execute-cursor/workspace-provision.js.map +0 -1
- package/src/activities/execute-cursor/__tests__/usage-accumulator.test.ts +0 -164
- package/src/activities/execute-cursor/index.ts +0 -2876
- package/src/activities/execute-cursor/usage-accumulator.ts +0 -169
- /package/dist/{activities/execute-cursor → shared}/env-resolver.js +0 -0
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* path is written into the workspace itself.
|
|
13
13
|
*
|
|
14
14
|
* This module replaces the duplicated `getPlatformDir` helpers in
|
|
15
|
-
* execute-cursor/skill-resolver.ts and
|
|
15
|
+
* execute-cursor/skill-resolver.ts and shared/attachment-resolver.ts.
|
|
16
16
|
*/
|
|
17
17
|
/**
|
|
18
18
|
* Compute the WORKSPACE-scoped HITL gate directory — the home for the STABLE
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* path is written into the workspace itself.
|
|
13
13
|
*
|
|
14
14
|
* This module replaces the duplicated `getPlatformDir` helpers in
|
|
15
|
-
* execute-cursor/skill-resolver.ts and
|
|
15
|
+
* execute-cursor/skill-resolver.ts and shared/attachment-resolver.ts.
|
|
16
16
|
*/
|
|
17
17
|
import { join } from "node:path";
|
|
18
18
|
import { mkdir } from "node:fs/promises";
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local workspace provisioning for a harness turn.
|
|
3
|
+
*
|
|
4
|
+
* Harness-agnostic: the Cursor activity is today's only caller, the turn
|
|
5
|
+
* runtime takes it over in S2 M3, and S3 retires the native twin
|
|
6
|
+
* (execute-deep-agent/setup.ts `provisionWorkspace`). Agents run LOCAL
|
|
7
|
+
* (cloud is disabled — see execute-cursor/cursor-mode.ts), so the runner
|
|
8
|
+
* must clone git-repo workspace entries itself and mount local-path entries
|
|
9
|
+
* before the agent runs. Cloud agents previously cloned git repos
|
|
10
|
+
* server-side; that path is no longer used.
|
|
11
|
+
*/
|
|
12
|
+
import type { Config } from "../../config.js";
|
|
13
|
+
import type { Session } from "@stigmer/protos/ai/stigmer/agentic/session/v1/api_pb";
|
|
14
|
+
import type { ProvisionResult, WorkspaceBackend } from "./types.js";
|
|
15
|
+
/**
|
|
16
|
+
* The two runner settings provisioning reads. A `Pick` over `Config` rather
|
|
17
|
+
* than a fresh options type so a caller holding the whole `Config` (the turn
|
|
18
|
+
* orchestrator, and the runtime that replaces it) passes it unchanged, while
|
|
19
|
+
* the signature states exactly what is consumed: the root every workspace
|
|
20
|
+
* resolves under, and the mode that decides whether git entries are cloned
|
|
21
|
+
* or expected in place. A test constructs the two fields and nothing else.
|
|
22
|
+
*/
|
|
23
|
+
export type SessionProvisionConfig = Pick<Config, "workspaceRootDir" | "mode">;
|
|
24
|
+
/** What {@link provisionSessionWorkspace} hands back to the harness. */
|
|
25
|
+
export interface SessionWorkspaceProvision {
|
|
26
|
+
/** The directories the agent should operate in (never empty). */
|
|
27
|
+
readonly workspaceDirs: string[];
|
|
28
|
+
/**
|
|
29
|
+
* Per-entry provision outcomes — carries the git metadata (repo URL, base
|
|
30
|
+
* branch, credential state) the write-back coordinator needs. Empty for a
|
|
31
|
+
* session with no workspace entries.
|
|
32
|
+
*/
|
|
33
|
+
readonly provisionResults: ProvisionResult[];
|
|
34
|
+
/**
|
|
35
|
+
* The backend the entries were provisioned through — the write-back
|
|
36
|
+
* coordinator executes its git commands through it.
|
|
37
|
+
*/
|
|
38
|
+
readonly workspaceBackend: WorkspaceBackend;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Provision the session's workspace entries for a LOCAL agent.
|
|
42
|
+
*
|
|
43
|
+
* Clones git-repo entries (using the user's GITHUB_TOKEN from the resolved
|
|
44
|
+
* execution environment) and mounts local-path entries, then returns the
|
|
45
|
+
* directories the agent should operate in — along with the provision results
|
|
46
|
+
* and backend the git write-back coordinator needs. A session with no
|
|
47
|
+
* workspace entries gets its own empty per-session directory (see
|
|
48
|
+
* session-root.ts) — never the shared root, which would leak other sessions'
|
|
49
|
+
* files into it.
|
|
50
|
+
*
|
|
51
|
+
* provisionGit is idempotent (it reuses an existing clone), so this is safe
|
|
52
|
+
* to call on every execution, including multi-turn and HITL reinvocations.
|
|
53
|
+
*/
|
|
54
|
+
export declare function provisionSessionWorkspace(config: SessionProvisionConfig, session: Session, envVars: Record<string, string>, sessionId: string): Promise<SessionWorkspaceProvision>;
|
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Local workspace provisioning for
|
|
2
|
+
* Local workspace provisioning for a harness turn.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* Harness-agnostic: the Cursor activity is today's only caller, the turn
|
|
5
|
+
* runtime takes it over in S2 M3, and S3 retires the native twin
|
|
6
|
+
* (execute-deep-agent/setup.ts `provisionWorkspace`). Agents run LOCAL
|
|
7
|
+
* (cloud is disabled — see execute-cursor/cursor-mode.ts), so the runner
|
|
8
|
+
* must clone git-repo workspace entries itself and mount local-path entries
|
|
9
|
+
* before the agent runs. Cloud agents previously cloned git repos
|
|
10
|
+
* server-side; that path is no longer used.
|
|
8
11
|
*/
|
|
9
|
-
import { WorkspaceProvisioner } from "
|
|
10
|
-
import { LocalWorkspaceBackend } from "
|
|
11
|
-
import { ensurePlatformDir } from "
|
|
12
|
-
import { resolveSessionWorkspaceRoot } from "
|
|
12
|
+
import { WorkspaceProvisioner } from "./provisioner.js";
|
|
13
|
+
import { LocalWorkspaceBackend } from "./local-backend.js";
|
|
14
|
+
import { ensurePlatformDir } from "./platform-dir.js";
|
|
15
|
+
import { resolveSessionWorkspaceRoot } from "./session-root.js";
|
|
13
16
|
/**
|
|
14
|
-
* Provision the session's workspace entries for a LOCAL
|
|
17
|
+
* Provision the session's workspace entries for a LOCAL agent.
|
|
15
18
|
*
|
|
16
19
|
* Clones git-repo entries (using the user's GITHUB_TOKEN from the resolved
|
|
17
20
|
* execution environment) and mounts local-path entries, then returns the
|
|
@@ -24,7 +27,7 @@ import { resolveSessionWorkspaceRoot } from "../../shared/workspace/session-root
|
|
|
24
27
|
* provisionGit is idempotent (it reuses an existing clone), so this is safe
|
|
25
28
|
* to call on every execution, including multi-turn and HITL reinvocations.
|
|
26
29
|
*/
|
|
27
|
-
export async function
|
|
30
|
+
export async function provisionSessionWorkspace(config, session, envVars, sessionId) {
|
|
28
31
|
const entries = session.spec?.workspaceEntries ?? [];
|
|
29
32
|
const platformDir = await ensurePlatformDir(sessionId);
|
|
30
33
|
if (entries.length === 0) {
|
|
@@ -47,4 +50,4 @@ export async function provisionCursorWorkspace(config, session, envVars, session
|
|
|
47
50
|
workspaceBackend: backend,
|
|
48
51
|
};
|
|
49
52
|
}
|
|
50
|
-
//# sourceMappingURL=
|
|
53
|
+
//# sourceMappingURL=session-provision.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-provision.js","sourceRoot":"","sources":["../../../src/shared/workspace/session-provision.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAExD,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,2BAA2B,EAAE,MAAM,mBAAmB,CAAC;AA6BhE;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,MAA8B,EAC9B,OAAgB,EAChB,OAA+B,EAC/B,SAAiB;IAEjB,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,gBAAgB,IAAI,EAAE,CAAC;IACrD,MAAM,WAAW,GAAG,MAAM,iBAAiB,CAAC,SAAS,CAAC,CAAC;IAEvD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,WAAW,GAAG,MAAM,2BAA2B,CACnD,MAAM,CAAC,gBAAgB,EAAE,OAAO,EAAE,SAAS,CAC5C,CAAC;QACF,OAAO;YACL,aAAa,EAAE,CAAC,WAAW,CAAC;YAC5B,gBAAgB,EAAE,EAAE;YACpB,gBAAgB,EAAE,IAAI,qBAAqB,CAAC,WAAW,EAAE,WAAW,CAAC;SACtE,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,qBAAqB,CAAC,MAAM,CAAC,gBAAgB,EAAE,WAAW,CAAC,CAAC;IAEhF,MAAM,WAAW,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC/C,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,YAAY,CAC5C,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,EACpE,OAAO,EACP,OAAO,EACP,MAAM,CAAC,IAAI,KAAK,OAAO,EACvB,MAAM,CAAC,IAAI,KAAK,OAAO,CACxB,CAAC;IAEF,MAAM,IAAI,GAAG,OAAO;SACjB,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC;SAC/B,MAAM,CAAC,CAAC,GAAG,EAAiB,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;IAEhD,OAAO;QACL,aAAa,EAAE,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,gBAAgB,CAAC;QACjE,gBAAgB,EAAE,OAAO;QACzB,gBAAgB,EAAE,OAAO;KAC1B,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stigmer/runner",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.15.0",
|
|
4
4
|
"description": "Embeddable Temporal worker for the Stigmer AI agent platform — handles agent execution, workflow orchestration, and MCP server management",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -104,9 +104,9 @@
|
|
|
104
104
|
"@opentelemetry/sdk-metrics": "^2.0.0",
|
|
105
105
|
"@opentelemetry/sdk-trace-base": "^2.0.0",
|
|
106
106
|
"@opentelemetry/sdk-trace-node": "^2.0.0",
|
|
107
|
-
"@stigmer/protos": "3.
|
|
108
|
-
"@stigmer/temporal-codecs": "3.
|
|
109
|
-
"@stigmer/zip-structure": "3.
|
|
107
|
+
"@stigmer/protos": "3.15.0",
|
|
108
|
+
"@stigmer/temporal-codecs": "3.15.0",
|
|
109
|
+
"@stigmer/zip-structure": "3.15.0",
|
|
110
110
|
"@temporalio/activity": "1.16.2",
|
|
111
111
|
"@temporalio/common": "1.16.2",
|
|
112
112
|
"@temporalio/interceptors-opentelemetry": "1.16.2",
|
|
@@ -13,7 +13,16 @@
|
|
|
13
13
|
* so a rejection here is attributable to the kit's assertion and not to some
|
|
14
14
|
* other defect of the double. Where an invariant races a hang against the
|
|
15
15
|
* interrupt bound, the bound is shortened through the assertion's parameter;
|
|
16
|
-
* the production bound stays what `contract.ts` declares.
|
|
16
|
+
* the production bound stays what `contract.ts` declares. Every subject is
|
|
17
|
+
* booted first, as the kit's `describeHarnessContract` boots the adapters it
|
|
18
|
+
* runs (the assertion functions require it).
|
|
19
|
+
*
|
|
20
|
+
* The second half checks the kit's own driver — the runtime stand-in — for
|
|
21
|
+
* the facts a real adapter depends on and the fake never notices: the record
|
|
22
|
+
* carries the persisted status (an adapter may read its grants from
|
|
23
|
+
* `execution.status`, as the runtime guarantees), the engine's view carries
|
|
24
|
+
* the driver's ids and decisions, and a stop lands only once the engine
|
|
25
|
+
* reports it is parked.
|
|
17
26
|
*/
|
|
18
27
|
|
|
19
28
|
import { describe, it, expect } from "vitest";
|
|
@@ -22,6 +31,7 @@ import { ApprovalAction, ToolCallStatus } from "@stigmer/protos/ai/stigmer/agent
|
|
|
22
31
|
|
|
23
32
|
import type { HarnessAdapter, TurnInput, TurnOutcome, TurnSink } from "../../harness/types.js";
|
|
24
33
|
import {
|
|
34
|
+
ExecutionDriver,
|
|
25
35
|
assertConcurrentTurnsAreIndependent,
|
|
26
36
|
assertDecisionsExecuteExactlyOnce,
|
|
27
37
|
assertEveryExitIsAnOutcome,
|
|
@@ -33,13 +43,21 @@ import {
|
|
|
33
43
|
} from "../harness-contract/contract.js";
|
|
34
44
|
import { scriptedSubject } from "../harness-contract/scripted-adapter.js";
|
|
35
45
|
import type { ScriptedSubject } from "../harness-contract/scripted-adapter.js";
|
|
36
|
-
import
|
|
46
|
+
import { scenario } from "../harness-contract/types.js";
|
|
47
|
+
import type { EngineView, HarnessContractSubject, TurnScenario } from "../harness-contract/types.js";
|
|
48
|
+
import { findToolCallRow } from "../proto-helpers.js";
|
|
37
49
|
|
|
38
50
|
/** Short enough to keep this file fast; long enough that an honest microtask settle never trips it. */
|
|
39
51
|
const SHORT_BOUND_MS = 100;
|
|
40
52
|
|
|
41
53
|
// ── Wrapping helpers ────────────────────────────────────────────────────────
|
|
42
54
|
|
|
55
|
+
/** The kit boots before it asserts; so does every arm here. */
|
|
56
|
+
async function booted<S extends HarnessContractSubject>(subject: S): Promise<S> {
|
|
57
|
+
await subject.adapter.boot(subject.config);
|
|
58
|
+
return subject;
|
|
59
|
+
}
|
|
60
|
+
|
|
43
61
|
/** The honest fake's adapter with the named members replaced. */
|
|
44
62
|
function adapterOver(inner: HarnessAdapter, name: string, patch: Partial<HarnessAdapter>): HarnessAdapter {
|
|
45
63
|
return {
|
|
@@ -58,9 +76,11 @@ function sinkOver(inner: TurnSink, patch: Partial<TurnSink>): TurnSink {
|
|
|
58
76
|
return {
|
|
59
77
|
status: inner.status,
|
|
60
78
|
stopSignal: inner.stopSignal,
|
|
79
|
+
setupTiming: inner.setupTiming,
|
|
61
80
|
requestPersist: () => inner.requestPersist(),
|
|
62
|
-
recordActivity: () => inner.recordActivity(),
|
|
81
|
+
recordActivity: (detail) => inner.recordActivity(detail),
|
|
63
82
|
reportUsage: (delta) => inner.reportUsage(delta),
|
|
83
|
+
reportProgress: (label) => inner.reportProgress(label),
|
|
64
84
|
bindHarnessState: (id) => inner.bindHarnessState(id),
|
|
65
85
|
...patch,
|
|
66
86
|
};
|
|
@@ -70,9 +90,11 @@ function sinkOver(inner: TurnSink, patch: Partial<TurnSink>): TurnSink {
|
|
|
70
90
|
function subjectOver(inner: ScriptedSubject, adapter: HarnessAdapter): HarnessContractSubject {
|
|
71
91
|
return {
|
|
72
92
|
name: adapter.name,
|
|
93
|
+
harness: inner.harness,
|
|
73
94
|
adapter,
|
|
74
95
|
config: inner.config,
|
|
75
|
-
arrange: (turn) => inner.arrange(turn),
|
|
96
|
+
arrange: (turn, view) => inner.arrange(turn, view),
|
|
97
|
+
whenHanging: () => inner.whenHanging(),
|
|
76
98
|
executionCount: (toolCallId) => inner.executionCount(toolCallId),
|
|
77
99
|
};
|
|
78
100
|
}
|
|
@@ -106,9 +128,9 @@ function executesUndecidedProposals(): HarnessContractSubject {
|
|
|
106
128
|
});
|
|
107
129
|
return {
|
|
108
130
|
...subjectOver(inner, adapter),
|
|
109
|
-
arrange: (turn: TurnScenario) => {
|
|
131
|
+
arrange: (turn: TurnScenario, view: EngineView) => {
|
|
110
132
|
proposedIds = turn.flatMap((step) => (step.kind === "propose" ? [step.toolCallId] : []));
|
|
111
|
-
inner.arrange(turn);
|
|
133
|
+
inner.arrange(turn, view);
|
|
112
134
|
},
|
|
113
135
|
};
|
|
114
136
|
}
|
|
@@ -196,34 +218,108 @@ function serializesTurns(): HarnessContractSubject {
|
|
|
196
218
|
|
|
197
219
|
describe("harness contract kit self-check — every invariant can fail", () => {
|
|
198
220
|
it("invariant 1 fires when runTurn throws a CancelledFailure", async () => {
|
|
199
|
-
await expect(assertEveryExitIsAnOutcome(throwsCancelledFailure(), SHORT_BOUND_MS)).rejects.toThrow(/broken:throws-CancelledFailure: runTurn rejected with a CancelledFailure/);
|
|
221
|
+
await expect(assertEveryExitIsAnOutcome(await booted(throwsCancelledFailure()), SHORT_BOUND_MS)).rejects.toThrow(/broken:throws-CancelledFailure: runTurn rejected with a CancelledFailure/);
|
|
200
222
|
});
|
|
201
223
|
|
|
202
224
|
it("invariant 2 fires when an undecided proposal executes", async () => {
|
|
203
|
-
await expect(assertProposalIsWaitingAndUnexecuted(executesUndecidedProposals())).rejects.toThrow(/broken:executes-undecided: .*awaiting_approval/);
|
|
225
|
+
await expect(assertProposalIsWaitingAndUnexecuted(await booted(executesUndecidedProposals()))).rejects.toThrow(/broken:executes-undecided: .*awaiting_approval/);
|
|
204
226
|
});
|
|
205
227
|
|
|
206
228
|
it("invariant 3 fires when a settled row is re-gated on a later invocation", async () => {
|
|
207
|
-
await expect(assertDecisionsExecuteExactlyOnce(reGatesSettledRows())).rejects.toThrow(/broken:re-gates-settled: .*must not re-gate/);
|
|
229
|
+
await expect(assertDecisionsExecuteExactlyOnce(await booted(reGatesSettledRows()))).rejects.toThrow(/broken:re-gates-settled: .*must not re-gate/);
|
|
208
230
|
});
|
|
209
231
|
|
|
210
232
|
it("invariant 4 fires when the adapter ignores stopSignal", async () => {
|
|
211
|
-
await expect(assertStopSignalInterrupts(ignoresStopSignal(), SHORT_BOUND_MS)).rejects.toThrow(/broken:ignores-stopSignal: runTurn did not settle within 100ms/);
|
|
233
|
+
await expect(assertStopSignalInterrupts(await booted(ignoresStopSignal()), SHORT_BOUND_MS)).rejects.toThrow(/broken:ignores-stopSignal: runTurn did not settle within 100ms/);
|
|
212
234
|
});
|
|
213
235
|
|
|
214
236
|
it("invariant 5 fires when usage is reported as running totals", async () => {
|
|
215
|
-
await expect(assertUsageReachesSinkAsDeltas(reportsCumulativeUsage())).rejects.toThrow(/broken:cumulative-usage: .*must sum to what the engine emitted/);
|
|
237
|
+
await expect(assertUsageReachesSinkAsDeltas(await booted(reportsCumulativeUsage()))).rejects.toThrow(/broken:cumulative-usage: .*must sum to what the engine emitted/);
|
|
216
238
|
});
|
|
217
239
|
|
|
218
240
|
it("invariant 6 fires when an adapter claims engine-minted and never binds", async () => {
|
|
219
|
-
await expect(assertStateIdCapabilityAgrees(claimsEngineMintedNeverBinds())).rejects.toThrow(/broken:claims-engine-minted: .*must bind its state id/);
|
|
241
|
+
await expect(assertStateIdCapabilityAgrees(await booted(claimsEngineMintedNeverBinds()))).rejects.toThrow(/broken:claims-engine-minted: .*must bind its state id/);
|
|
220
242
|
});
|
|
221
243
|
|
|
222
244
|
it("invariant 7 fires when releaseSession rejects an unknown session", async () => {
|
|
223
|
-
await expect(assertLifetimesResolve(refusesUnknownRelease())).rejects.toThrow(/broken:refuses-unknown-release: releaseSession for an unknown session rejected/);
|
|
245
|
+
await expect(assertLifetimesResolve(await booted(refusesUnknownRelease()))).rejects.toThrow(/broken:refuses-unknown-release: releaseSession for an unknown session rejected/);
|
|
224
246
|
});
|
|
225
247
|
|
|
226
248
|
it("invariant 8 fires when the adapter serializes turns through shared state", async () => {
|
|
227
|
-
await expect(assertConcurrentTurnsAreIndependent(serializesTurns(), SHORT_BOUND_MS)).rejects.toThrow(/broken:serializes-turns: runTurn did not settle within 100ms/);
|
|
249
|
+
await expect(assertConcurrentTurnsAreIndependent(await booted(serializesTurns()), SHORT_BOUND_MS)).rejects.toThrow(/broken:serializes-turns: runTurn did not settle within 100ms/);
|
|
250
|
+
});
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
// ── The driver: the runtime stand-in's own guarantees ───────────────────────
|
|
254
|
+
|
|
255
|
+
const WRITE_BETA = { kind: "write", resource: "/work/beta.txt" } as const;
|
|
256
|
+
|
|
257
|
+
describe("harness contract kit self-check — the driver stands in for the runtime faithfully", () => {
|
|
258
|
+
it("hands the adapter the persisted status on the record AND the sink, as two clones", async () => {
|
|
259
|
+
const subject = await booted(honest());
|
|
260
|
+
const driver = new ExecutionDriver(subject, "driver-record");
|
|
261
|
+
const id = "driver-record-write";
|
|
262
|
+
|
|
263
|
+
const first = await driver.turn([scenario.propose(id, WRITE_BETA)]);
|
|
264
|
+
expect(first.outcome.kind).toBe("awaiting_approval");
|
|
265
|
+
expect(first.input.execution.status?.messages ?? [], "a first turn's record carries no persisted status").toHaveLength(0);
|
|
266
|
+
driver.decide(id, ApprovalAction.APPROVE);
|
|
267
|
+
|
|
268
|
+
const second = driver.begin([scenario.propose(id, WRITE_BETA)]);
|
|
269
|
+
const onRecord = second.input.execution.status;
|
|
270
|
+
expect(onRecord, "the reinvocation's record must carry what the previous turn persisted").toBeDefined();
|
|
271
|
+
expect(findToolCallRow(onRecord!, id)?.approvalAction, "the decision is on the record's row").toBe(ApprovalAction.APPROVE);
|
|
272
|
+
expect(findToolCallRow(second.sink.status, id)?.approvalAction, "and on the sink's row").toBe(ApprovalAction.APPROVE);
|
|
273
|
+
expect(onRecord, "the record's copy and the sink's copy are distinct objects, as after a real persist and read-back").not.toBe(second.sink.status);
|
|
274
|
+
expect(second.input.approvalDecisions.get(id), "the decisions map is the runtime's reader over the same rows").toBe(ApprovalAction.APPROVE);
|
|
275
|
+
await second.settled;
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
it("arranges the engine with the driver's ids and the decisions the prompt will carry", async () => {
|
|
279
|
+
const inner = await booted(honest());
|
|
280
|
+
const views: EngineView[] = [];
|
|
281
|
+
const subject: HarnessContractSubject = {
|
|
282
|
+
...inner,
|
|
283
|
+
arrange: (turn, view) => {
|
|
284
|
+
views.push(view);
|
|
285
|
+
inner.arrange(turn, view);
|
|
286
|
+
},
|
|
287
|
+
};
|
|
288
|
+
const driver = new ExecutionDriver(subject, "driver-view");
|
|
289
|
+
const id = "driver-view-write";
|
|
290
|
+
|
|
291
|
+
await driver.turn([scenario.propose(id, WRITE_BETA)]);
|
|
292
|
+
driver.decide(id, ApprovalAction.SKIP);
|
|
293
|
+
await driver.turn([scenario.propose(id, WRITE_BETA), scenario.say("on")]);
|
|
294
|
+
|
|
295
|
+
expect(views.map((v) => v.executionId)).toEqual([driver.executionId, driver.executionId]);
|
|
296
|
+
expect(views.map((v) => v.sessionId)).toEqual([driver.sessionId, driver.sessionId]);
|
|
297
|
+
expect(views[0]!.approvalDecisions.size, "nothing decided before the first turn").toBe(0);
|
|
298
|
+
expect(views[1]!.approvalDecisions.get(id), "the reinvocation's view carries the decision").toBe(ApprovalAction.SKIP);
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
it("stops a turn only once the engine reports it is parked, never during setup", async () => {
|
|
302
|
+
const inner = await booted(honest());
|
|
303
|
+
let sinkInFlight: TurnSink | undefined;
|
|
304
|
+
let abortedWhenParked: boolean | undefined;
|
|
305
|
+
// Observes the signal at the instant the engine reports the hang; the
|
|
306
|
+
// driver's own abort is chained after this observer.
|
|
307
|
+
const subject: HarnessContractSubject = {
|
|
308
|
+
...inner,
|
|
309
|
+
whenHanging: () =>
|
|
310
|
+
inner.whenHanging().then(() => {
|
|
311
|
+
abortedWhenParked = sinkInFlight?.stopSignal.aborted;
|
|
312
|
+
}),
|
|
313
|
+
};
|
|
314
|
+
const driver = new ExecutionDriver(subject, "driver-stop");
|
|
315
|
+
|
|
316
|
+
const turn = driver.begin([scenario.say("setting up"), scenario.hang(), scenario.say("never")], { stopWhenHanging: "kit: stop" });
|
|
317
|
+
sinkInFlight = turn.sink;
|
|
318
|
+
const outcome = await turn.settled;
|
|
319
|
+
|
|
320
|
+
expect(outcome.kind).toBe("interrupted");
|
|
321
|
+
expect(abortedWhenParked, "at the moment the engine reported the hang the signal was still live").toBe(false);
|
|
322
|
+
expect(turn.sink.stopSignal.aborted, "and it was aborted after").toBe(true);
|
|
323
|
+
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"]);
|
|
228
324
|
});
|
|
229
325
|
});
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The four resources of one execution, wired by id into the chain the turn
|
|
3
|
+
* runtime resolves (`execution.spec.sessionId` → `session.spec.
|
|
4
|
+
* agentInstanceId` → `agentInstance.spec.agentId` → the agent), as an
|
|
5
|
+
* `ExecutionRecord` the hermetic client answers from.
|
|
6
|
+
*
|
|
7
|
+
* Harness-agnostic: the record is the control plane's, and the runtime's
|
|
8
|
+
* phases read it the same way whatever engine runs the turn. A harness's
|
|
9
|
+
* driver supplies its own fixture ids and model (`execute-cursor/__test-
|
|
10
|
+
* utils__/hermetic-cursor.ts` `cursorExecutionRecord`); the runtime's own
|
|
11
|
+
* tests use the defaults. Ids are fixed so goldens are readable and
|
|
12
|
+
* byte-stable.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { create } from "@bufbuild/protobuf";
|
|
16
|
+
import { AgentExecutionSchema, type AgentExecution } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
|
|
17
|
+
import { AgentExecutionSpecSchema, ExecutionConfigSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/spec_pb";
|
|
18
|
+
import { SessionSchema, type Session } from "@stigmer/protos/ai/stigmer/agentic/session/v1/api_pb";
|
|
19
|
+
import { SessionSpecSchema } from "@stigmer/protos/ai/stigmer/agentic/session/v1/spec_pb";
|
|
20
|
+
import type { WorkspaceEntry } from "@stigmer/protos/ai/stigmer/agentic/session/v1/workspace_pb";
|
|
21
|
+
import { AgentSchema, type Agent } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/api_pb";
|
|
22
|
+
import { AgentSpecSchema } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/spec_pb";
|
|
23
|
+
import { AgentInstanceSchema, type AgentInstance } from "@stigmer/protos/ai/stigmer/agentic/agentinstance/v1/api_pb";
|
|
24
|
+
import { AgentInstanceSpecSchema } from "@stigmer/protos/ai/stigmer/agentic/agentinstance/v1/spec_pb";
|
|
25
|
+
import { ApiResourceMetadataSchema } from "@stigmer/protos/ai/stigmer/commons/apiresource/metadata_pb";
|
|
26
|
+
|
|
27
|
+
import { ExecutionRecord, type ExecutionRecordInput } from "./hermetic-activity.js";
|
|
28
|
+
import { FIXTURE_MODEL } from "./model-registry-fixture.js";
|
|
29
|
+
|
|
30
|
+
/** The ids a record's four resources carry. */
|
|
31
|
+
export interface ExecutionRecordIds {
|
|
32
|
+
readonly org: string;
|
|
33
|
+
readonly executionId: string;
|
|
34
|
+
readonly sessionId: string;
|
|
35
|
+
readonly agentInstanceId: string;
|
|
36
|
+
readonly agentId: string;
|
|
37
|
+
readonly agentName: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export const DEFAULT_RECORD_IDS: ExecutionRecordIds = {
|
|
41
|
+
org: "hermetic-org",
|
|
42
|
+
executionId: "aex_hermetic_0001",
|
|
43
|
+
sessionId: "ses_hermetic_0001",
|
|
44
|
+
agentInstanceId: "ain_hermetic_0001",
|
|
45
|
+
agentId: "agt_hermetic_0001",
|
|
46
|
+
agentName: "hermetic-agent",
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export interface ExecutionRecordOptions {
|
|
50
|
+
/** The user's message for this execution. */
|
|
51
|
+
readonly message: string;
|
|
52
|
+
/** The agent's instructions (system prompt body). */
|
|
53
|
+
readonly instructions?: string;
|
|
54
|
+
/** Session workspace entries (a `local_path` entry turns on capture mode). */
|
|
55
|
+
readonly workspaceEntries?: WorkspaceEntry[];
|
|
56
|
+
/** The requested model; the pinned fixture model when omitted. */
|
|
57
|
+
readonly modelName?: string;
|
|
58
|
+
readonly autoApproveAll?: boolean;
|
|
59
|
+
/**
|
|
60
|
+
* `ExecutionConfig.max_cost_usd`: the per-message cost budget the runtime
|
|
61
|
+
* enforces as a hard stop (cost-guard.ts). Omitted or 0 = no cap, the
|
|
62
|
+
* proto's default. Priced against the registry fixture's round numbers, so
|
|
63
|
+
* a scenario can state its overrun exactly (600 000 input tokens = $0.60).
|
|
64
|
+
*/
|
|
65
|
+
readonly maxCostUsd?: number;
|
|
66
|
+
/** The control plane's STOP lever; see `ExecutionRecordInput.controlSignal`. */
|
|
67
|
+
readonly controlSignal?: ExecutionRecordInput["controlSignal"];
|
|
68
|
+
readonly ids?: ExecutionRecordIds;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function executionRecordFixture(options: ExecutionRecordOptions): ExecutionRecord {
|
|
72
|
+
const ids = options.ids ?? DEFAULT_RECORD_IDS;
|
|
73
|
+
const execution: AgentExecution = create(AgentExecutionSchema, {
|
|
74
|
+
metadata: create(ApiResourceMetadataSchema, { id: ids.executionId, org: ids.org, name: ids.executionId }),
|
|
75
|
+
spec: create(AgentExecutionSpecSchema, {
|
|
76
|
+
sessionId: ids.sessionId,
|
|
77
|
+
message: options.message,
|
|
78
|
+
autoApproveAll: options.autoApproveAll ?? false,
|
|
79
|
+
executionConfig: create(ExecutionConfigSchema, {
|
|
80
|
+
modelName: options.modelName ?? FIXTURE_MODEL,
|
|
81
|
+
maxCostUsd: options.maxCostUsd ?? 0,
|
|
82
|
+
}),
|
|
83
|
+
}),
|
|
84
|
+
});
|
|
85
|
+
const session: Session = create(SessionSchema, {
|
|
86
|
+
metadata: create(ApiResourceMetadataSchema, { id: ids.sessionId, org: ids.org, name: ids.sessionId }),
|
|
87
|
+
spec: create(SessionSpecSchema, {
|
|
88
|
+
agentInstanceId: ids.agentInstanceId,
|
|
89
|
+
workspaceEntries: options.workspaceEntries ?? [],
|
|
90
|
+
}),
|
|
91
|
+
});
|
|
92
|
+
const agentInstance: AgentInstance = create(AgentInstanceSchema, {
|
|
93
|
+
metadata: create(ApiResourceMetadataSchema, { id: ids.agentInstanceId, org: ids.org, name: ids.agentInstanceId }),
|
|
94
|
+
spec: create(AgentInstanceSpecSchema, { agentId: ids.agentId }),
|
|
95
|
+
});
|
|
96
|
+
const agent: Agent = create(AgentSchema, {
|
|
97
|
+
metadata: create(ApiResourceMetadataSchema, { id: ids.agentId, org: ids.org, name: ids.agentName }),
|
|
98
|
+
spec: create(AgentSpecSchema, {
|
|
99
|
+
description: "Hermetic fixture agent",
|
|
100
|
+
instructions: options.instructions ?? "You are the hermetic fixture agent. Answer briefly.",
|
|
101
|
+
}),
|
|
102
|
+
});
|
|
103
|
+
return new ExecutionRecord({ execution, session, agentInstance, agent, controlSignal: options.controlSignal });
|
|
104
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The child entry `__tests__/harness-boot-order.test.ts` spawns: one FRESH
|
|
3
|
+
* Node process that does exactly what the composition roots do before
|
|
4
|
+
* bootstrap — import `harness-adapters.js` and `harness/registry.js`, then
|
|
5
|
+
* `bootHarnesses` on a proxy-mode config — and reports how it went.
|
|
6
|
+
*
|
|
7
|
+
* Why a child process: the `node:http2` ESM facade is snapshotted once per
|
|
8
|
+
* process at its first import, so the positive load-order contract ("the
|
|
9
|
+
* patch reached the facade") cannot be observed inside a shared vitest
|
|
10
|
+
* worker that has already imported half the runner. A fresh process is the
|
|
11
|
+
* only honest instrument (`http2-interceptor.test.ts` says as much).
|
|
12
|
+
*
|
|
13
|
+
* Arms (argv[2]):
|
|
14
|
+
* - `boot`: import the two pre-boot modules, boot with a proxy endpoint and
|
|
15
|
+
* a bound token ref. Success means the pre-boot graph was connect-free,
|
|
16
|
+
* both interceptors installed, `assertHttp2ConnectPatched` passed, and the
|
|
17
|
+
* SDK slice loaded from inside `boot`.
|
|
18
|
+
* - `boot-after-connect-node`: the same, after importing the Stigmer client
|
|
19
|
+
* (connect-node) FIRST. Must fail with the facade sentence: proves the
|
|
20
|
+
* guard is live inside `boot`, so a future regression is loud.
|
|
21
|
+
*
|
|
22
|
+
* Output: one line, `harness-boot-order: ok` or `harness-boot-order: <message>`,
|
|
23
|
+
* then exit 0 on success and 1 on a rejection. The proxy endpoint is an inert
|
|
24
|
+
* loopback nothing listens on; boot dials nothing.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import { testConfig } from "./config-fixture.js";
|
|
28
|
+
|
|
29
|
+
const arm = process.argv[2];
|
|
30
|
+
|
|
31
|
+
async function main(): Promise<void> {
|
|
32
|
+
if (arm === "boot-after-connect-node") {
|
|
33
|
+
await import("../client/stigmer-client.js");
|
|
34
|
+
} else if (arm !== "boot") {
|
|
35
|
+
throw new Error(`harness-boot-order-child: unknown arm '${String(arm)}' (expected 'boot' or 'boot-after-connect-node')`);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const [{ HARNESS_ADAPTERS }, { adaptersOf, bootHarnesses }] = await Promise.all([
|
|
39
|
+
import("../harness-adapters.js"),
|
|
40
|
+
import("../harness/registry.js"),
|
|
41
|
+
]);
|
|
42
|
+
const config = testConfig({
|
|
43
|
+
proxyEndpoint: "http://127.0.0.1:1",
|
|
44
|
+
proxyTokenRef: { current: "boot-order-test-token" },
|
|
45
|
+
});
|
|
46
|
+
await bootHarnesses(adaptersOf(HARNESS_ADAPTERS), config);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
main().then(
|
|
50
|
+
() => {
|
|
51
|
+
process.stdout.write("harness-boot-order: ok\n");
|
|
52
|
+
process.exit(0);
|
|
53
|
+
},
|
|
54
|
+
(err: unknown) => {
|
|
55
|
+
process.stdout.write(`harness-boot-order: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
56
|
+
process.exit(1);
|
|
57
|
+
},
|
|
58
|
+
);
|