@stigmer/runner 3.10.0 → 3.11.1-dev.20260812192248
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 +14 -1
- package/dist/.build-fingerprint +1 -1
- package/dist/activities/call-llm.js +9 -10
- package/dist/activities/call-llm.js.map +1 -1
- package/dist/activities/classify-tool-approvals.d.ts +2 -1
- package/dist/activities/classify-tool-approvals.js +28 -2
- package/dist/activities/classify-tool-approvals.js.map +1 -1
- package/dist/activities/discover-mcp-server.d.ts +39 -0
- package/dist/activities/discover-mcp-server.js +165 -28
- package/dist/activities/discover-mcp-server.js.map +1 -1
- package/dist/activities/emit-event.d.ts +14 -2
- package/dist/activities/emit-event.js +52 -17
- package/dist/activities/emit-event.js.map +1 -1
- package/dist/activities/execute-cursor/__test-utils__/cursor-hook-harness.d.ts +8 -0
- package/dist/activities/execute-cursor/__test-utils__/cursor-hook-harness.js +1 -1
- package/dist/activities/execute-cursor/__test-utils__/cursor-hook-harness.js.map +1 -1
- package/dist/activities/execute-cursor/approval-state.d.ts +28 -2
- package/dist/activities/execute-cursor/approval-state.js +7 -1
- package/dist/activities/execute-cursor/approval-state.js.map +1 -1
- package/dist/activities/execute-cursor/attachment-resolver.d.ts +14 -0
- package/dist/activities/execute-cursor/attachment-resolver.js +18 -4
- package/dist/activities/execute-cursor/attachment-resolver.js.map +1 -1
- package/dist/activities/execute-cursor/blueprint-resolver.d.ts +1 -9
- package/dist/activities/execute-cursor/blueprint-resolver.js +6 -22
- package/dist/activities/execute-cursor/blueprint-resolver.js.map +1 -1
- package/dist/activities/execute-cursor/env-resolver.js +3 -1
- package/dist/activities/execute-cursor/env-resolver.js.map +1 -1
- package/dist/activities/execute-cursor/error-classifier.d.ts +59 -3
- package/dist/activities/execute-cursor/error-classifier.js +115 -6
- package/dist/activities/execute-cursor/error-classifier.js.map +1 -1
- package/dist/activities/execute-cursor/extract-structured-output.d.ts +29 -0
- package/dist/activities/execute-cursor/extract-structured-output.js +58 -0
- package/dist/activities/execute-cursor/extract-structured-output.js.map +1 -0
- package/dist/activities/execute-cursor/hook-script.d.ts +14 -3
- package/dist/activities/execute-cursor/hook-script.js +72 -10
- package/dist/activities/execute-cursor/hook-script.js.map +1 -1
- package/dist/activities/execute-cursor/index.d.ts +51 -11
- package/dist/activities/execute-cursor/index.js +177 -93
- package/dist/activities/execute-cursor/index.js.map +1 -1
- package/dist/activities/execute-cursor/mcp-resolver.d.ts +24 -1
- package/dist/activities/execute-cursor/mcp-resolver.js +5 -2
- package/dist/activities/execute-cursor/mcp-resolver.js.map +1 -1
- package/dist/activities/execute-cursor/model-pricing-data.d.ts +2 -0
- package/dist/activities/execute-cursor/model-pricing-data.js +13 -3
- package/dist/activities/execute-cursor/model-pricing-data.js.map +1 -1
- package/dist/activities/execute-cursor/prompt-builder.d.ts +51 -4
- package/dist/activities/execute-cursor/prompt-builder.js +49 -7
- package/dist/activities/execute-cursor/prompt-builder.js.map +1 -1
- package/dist/activities/execute-cursor/turn-recovery.d.ts +52 -0
- package/dist/activities/execute-cursor/turn-recovery.js +193 -0
- package/dist/activities/execute-cursor/turn-recovery.js.map +1 -0
- package/dist/activities/execute-cursor/turn-stream.js +4 -1
- package/dist/activities/execute-cursor/turn-stream.js.map +1 -1
- package/dist/activities/execute-deep-agent/attachment-injector.d.ts +18 -1
- package/dist/activities/execute-deep-agent/attachment-injector.js +68 -23
- package/dist/activities/execute-deep-agent/attachment-injector.js.map +1 -1
- package/dist/activities/execute-deep-agent/environment.js +3 -1
- package/dist/activities/execute-deep-agent/environment.js.map +1 -1
- package/dist/activities/execute-deep-agent/index.js +15 -0
- package/dist/activities/execute-deep-agent/index.js.map +1 -1
- package/dist/activities/execute-deep-agent/prompt-builder.d.ts +7 -7
- package/dist/activities/execute-deep-agent/prompt-builder.js +8 -2
- package/dist/activities/execute-deep-agent/prompt-builder.js.map +1 -1
- package/dist/activities/execute-deep-agent/setup.d.ts +10 -0
- package/dist/activities/execute-deep-agent/setup.js +65 -24
- package/dist/activities/execute-deep-agent/setup.js.map +1 -1
- package/dist/activities/execute-deep-agent/shell-env.d.ts +5 -1
- package/dist/activities/execute-deep-agent/shell-env.js +7 -9
- package/dist/activities/execute-deep-agent/shell-env.js.map +1 -1
- package/dist/activities/execute-deep-agent/subagent-transformer.d.ts +18 -1
- package/dist/activities/execute-deep-agent/subagent-transformer.js +15 -2
- package/dist/activities/execute-deep-agent/subagent-transformer.js.map +1 -1
- package/dist/activities/execute-deep-agent/subagent-wiring.d.ts +27 -6
- package/dist/activities/execute-deep-agent/subagent-wiring.js +26 -5
- package/dist/activities/execute-deep-agent/subagent-wiring.js.map +1 -1
- package/dist/activities/hydrate-workflow-execution.js +8 -3
- package/dist/activities/hydrate-workflow-execution.js.map +1 -1
- package/dist/activities/run-command.d.ts +5 -2
- package/dist/activities/run-command.js +22 -10
- package/dist/activities/run-command.js.map +1 -1
- package/dist/activities/run-env.d.ts +40 -0
- package/dist/activities/run-env.js +66 -0
- package/dist/activities/run-env.js.map +1 -0
- package/dist/activities/workflow-event-activities.d.ts +28 -10
- package/dist/activities/workflow-event-activities.js +87 -58
- package/dist/activities/workflow-event-activities.js.map +1 -1
- package/dist/bootstrap.js +5 -0
- package/dist/bootstrap.js.map +1 -1
- package/dist/claimcheck/payload-codec.js +21 -1
- package/dist/claimcheck/payload-codec.js.map +1 -1
- package/dist/client/stigmer-client.d.ts +83 -21
- package/dist/client/stigmer-client.js +106 -29
- package/dist/client/stigmer-client.js.map +1 -1
- package/dist/encryption/config.d.ts +64 -0
- package/dist/encryption/config.js +108 -0
- package/dist/encryption/config.js.map +1 -0
- package/dist/encryption/index.d.ts +3 -0
- package/dist/encryption/index.js +3 -0
- package/dist/encryption/index.js.map +1 -0
- package/dist/encryption/payload-codec.d.ts +41 -0
- package/dist/encryption/payload-codec.js +130 -0
- package/dist/encryption/payload-codec.js.map +1 -0
- package/dist/middleware/index.d.ts +3 -0
- package/dist/middleware/index.js +7 -0
- package/dist/middleware/index.js.map +1 -1
- package/dist/middleware/path-normalization.d.ts +57 -0
- package/dist/middleware/path-normalization.js +109 -0
- package/dist/middleware/path-normalization.js.map +1 -0
- package/dist/middleware/types.d.ts +8 -0
- package/dist/payload-codecs.d.ts +17 -0
- package/dist/payload-codecs.js +42 -0
- package/dist/payload-codecs.js.map +1 -0
- package/dist/preflight.d.ts +31 -0
- package/dist/preflight.js +43 -0
- package/dist/preflight.js.map +1 -1
- package/dist/runner-manager.js +21 -17
- package/dist/runner-manager.js.map +1 -1
- package/dist/runner.js +11 -18
- package/dist/runner.js.map +1 -1
- package/dist/shared/approval-policy.d.ts +9 -3
- package/dist/shared/approval-policy.js +15 -6
- package/dist/shared/approval-policy.js.map +1 -1
- package/dist/shared/artifact-storage.d.ts +23 -1
- package/dist/shared/artifact-storage.js +51 -10
- package/dist/shared/artifact-storage.js.map +1 -1
- package/dist/shared/attachment-naming.d.ts +53 -0
- package/dist/shared/attachment-naming.js +59 -0
- package/dist/shared/attachment-naming.js.map +1 -0
- package/dist/shared/caller-identity.d.ts +23 -2
- package/dist/shared/caller-identity.js +36 -5
- package/dist/shared/caller-identity.js.map +1 -1
- package/dist/shared/channel-attachment.js +1 -0
- package/dist/shared/channel-attachment.js.map +1 -1
- package/dist/shared/checkpointer/http-saver.d.ts +26 -1
- package/dist/shared/checkpointer/http-saver.js +54 -8
- package/dist/shared/checkpointer/http-saver.js.map +1 -1
- package/dist/shared/conversation-attachment.js +1 -0
- package/dist/shared/conversation-attachment.js.map +1 -1
- package/dist/shared/conversation-catchup.d.ts +9 -2
- package/dist/shared/conversation-catchup.js +39 -6
- package/dist/shared/conversation-catchup.js.map +1 -1
- package/dist/shared/datastore-attachment.d.ts +50 -7
- package/dist/shared/datastore-attachment.js +93 -11
- package/dist/shared/datastore-attachment.js.map +1 -1
- package/dist/shared/grpc-retry.d.ts +5 -1
- package/dist/shared/grpc-retry.js +5 -1
- package/dist/shared/grpc-retry.js.map +1 -1
- package/dist/shared/http-retry.d.ts +85 -0
- package/dist/shared/http-retry.js +101 -0
- package/dist/shared/http-retry.js.map +1 -0
- package/dist/shared/llm-backend.d.ts +275 -0
- package/dist/shared/llm-backend.js +425 -0
- package/dist/shared/llm-backend.js.map +1 -0
- package/dist/shared/llm-proxy.d.ts +8 -0
- package/dist/shared/llm-proxy.js +15 -0
- package/dist/shared/llm-proxy.js.map +1 -1
- package/dist/shared/mcp-enabled-tools.d.ts +57 -0
- package/dist/shared/mcp-enabled-tools.js +86 -0
- package/dist/shared/mcp-enabled-tools.js.map +1 -0
- package/dist/shared/mcp-manager.d.ts +11 -5
- package/dist/shared/mcp-manager.js +47 -8
- package/dist/shared/mcp-manager.js.map +1 -1
- package/dist/shared/mcp-resolver.d.ts +39 -2
- package/dist/shared/mcp-resolver.js +38 -2
- package/dist/shared/mcp-resolver.js.map +1 -1
- package/dist/shared/mcp-schema-sanitizer.d.ts +70 -0
- package/dist/shared/mcp-schema-sanitizer.js +197 -0
- package/dist/shared/mcp-schema-sanitizer.js.map +1 -0
- package/dist/shared/model-client.d.ts +18 -5
- package/dist/shared/model-client.js +149 -18
- package/dist/shared/model-client.js.map +1 -1
- package/dist/shared/model-error.js +198 -5
- package/dist/shared/model-error.js.map +1 -1
- package/dist/shared/model-pricing-data.d.ts +2 -0
- package/dist/shared/model-pricing-data.js +13 -3
- package/dist/shared/model-pricing-data.js.map +1 -1
- package/dist/shared/model-registry.js +3 -2
- package/dist/shared/model-registry.js.map +1 -1
- package/dist/shared/plan-mode-permissions.d.ts +33 -0
- package/dist/shared/plan-mode-permissions.js +35 -0
- package/dist/shared/plan-mode-permissions.js.map +1 -0
- package/dist/shared/registry-endpoint.d.ts +20 -0
- package/dist/shared/registry-endpoint.js +25 -0
- package/dist/shared/registry-endpoint.js.map +1 -1
- package/dist/shared/runner-credential-keys.d.ts +24 -0
- package/dist/shared/runner-credential-keys.js +47 -0
- package/dist/shared/runner-credential-keys.js.map +1 -0
- package/dist/worker.d.ts +2 -1
- package/dist/worker.js +2 -4
- package/dist/worker.js.map +1 -1
- package/dist/workflow-engine/resolve.d.ts +19 -1
- package/dist/workflow-engine/resolve.js +37 -2
- package/dist/workflow-engine/resolve.js.map +1 -1
- package/dist/workflow-engine/types.d.ts +18 -0
- package/dist/workflow-engine/types.js.map +1 -1
- package/dist/workflows/call-agent-orchestrator.d.ts +9 -0
- package/dist/workflows/call-agent-orchestrator.js +1 -0
- package/dist/workflows/call-agent-orchestrator.js.map +1 -1
- package/dist/workflows/connect-mcp-server.js +9 -0
- package/dist/workflows/connect-mcp-server.js.map +1 -1
- package/dist/workflows/engine-core.js +23 -2
- package/dist/workflows/engine-core.js.map +1 -1
- package/dist/workflows/execute-from-execution.d.ts +1 -1
- package/dist/workflows/execute-from-execution.js +11 -1
- package/dist/workflows/execute-from-execution.js.map +1 -1
- package/dist/workflows/types.d.ts +8 -0
- package/package.json +9 -4
- package/src/__test-utils__/__tests__/vitest-global-setup.test.ts +37 -0
- package/src/__test-utils__/vitest-global-setup.ts +50 -0
- package/src/__tests__/bootstrap.test.ts +43 -0
- package/src/__tests__/claimcheck-codec.test.ts +36 -0
- package/src/__tests__/encryption-codec.test.ts +287 -0
- package/src/__tests__/fixtures/encrypted-payload-fixture.json +15 -0
- package/src/__tests__/history-encryption-e2e.test.ts +243 -0
- package/src/__tests__/preflight.test.ts +65 -2
- package/src/activities/__tests__/call-llm.test.ts +75 -0
- package/src/activities/__tests__/classify-tool-approvals.test.ts +117 -1
- package/src/activities/__tests__/discover-mcp-server.hang.test.ts +103 -0
- package/src/activities/__tests__/discover-mcp-server.test.ts +242 -1
- package/src/activities/__tests__/error-classifier.test.ts +94 -2
- package/src/activities/__tests__/run-command.test.ts +221 -0
- package/src/activities/__tests__/workflow-event-activities.test.ts +107 -8
- package/src/activities/call-llm.ts +9 -16
- package/src/activities/classify-tool-approvals.ts +34 -4
- package/src/activities/discover-mcp-server.ts +203 -31
- package/src/activities/emit-event.ts +65 -21
- package/src/activities/execute-cursor/__test-utils__/cursor-hook-harness.ts +9 -0
- package/src/activities/execute-cursor/__tests__/approval-gate.test.ts +14 -0
- package/src/activities/execute-cursor/__tests__/attachment-resolver.test.ts +53 -0
- package/src/activities/execute-cursor/__tests__/build-prompt.test.ts +151 -16
- package/src/activities/execute-cursor/__tests__/error-classifier-extraction.test.ts +208 -0
- package/src/activities/execute-cursor/__tests__/extract-structured-output.test.ts +120 -0
- package/src/activities/execute-cursor/__tests__/hook-script.test.ts +93 -0
- package/src/activities/execute-cursor/__tests__/mcp-resolver.test.ts +125 -0
- package/src/activities/execute-cursor/__tests__/model-pricing.test.ts +62 -1
- package/src/activities/execute-cursor/__tests__/prompt-builder-delegation.test.ts +1 -1
- package/src/activities/execute-cursor/__tests__/turn-recovery.test.ts +160 -0
- package/src/activities/execute-cursor/__tests__/turn-stream.test.ts +13 -0
- package/src/activities/execute-cursor/approval-state.ts +30 -1
- package/src/activities/execute-cursor/attachment-resolver.ts +31 -3
- package/src/activities/execute-cursor/blueprint-resolver.ts +7 -27
- package/src/activities/execute-cursor/env-resolver.ts +3 -1
- package/src/activities/execute-cursor/error-classifier.ts +131 -7
- package/src/activities/execute-cursor/extract-structured-output.ts +72 -0
- package/src/activities/execute-cursor/hook-script.ts +74 -10
- package/src/activities/execute-cursor/index.ts +209 -109
- package/src/activities/execute-cursor/mcp-resolver.ts +36 -2
- package/src/activities/execute-cursor/model-pricing-data.ts +22 -3
- package/src/activities/execute-cursor/prompt-builder.ts +85 -9
- package/src/activities/execute-cursor/turn-recovery.ts +208 -0
- package/src/activities/execute-cursor/turn-stream.ts +5 -2
- package/src/activities/execute-deep-agent/__tests__/attachment-injector.test.ts +110 -8
- package/src/activities/execute-deep-agent/__tests__/datastore-degradation.test.ts +104 -0
- package/src/activities/execute-deep-agent/__tests__/hitl-reject.test.ts +2 -0
- package/src/activities/execute-deep-agent/__tests__/hitl-resume-approve-all.test.ts +1 -0
- package/src/activities/execute-deep-agent/__tests__/hitl-resume-history.test.ts +1 -0
- package/src/activities/execute-deep-agent/__tests__/plan-mode-path-normalization.test.ts +174 -0
- package/src/activities/execute-deep-agent/__tests__/prompt-builder.test.ts +34 -5
- package/src/activities/execute-deep-agent/__tests__/sequential-gate-resume.test.ts +1 -0
- package/src/activities/execute-deep-agent/__tests__/shell-env.test.ts +24 -10
- package/src/activities/execute-deep-agent/__tests__/subagent-plan-mode-permissions.test.ts +178 -0
- package/src/activities/execute-deep-agent/__tests__/subagent-wiring.test.ts +12 -7
- package/src/activities/execute-deep-agent/attachment-injector.ts +94 -30
- package/src/activities/execute-deep-agent/environment.ts +3 -1
- package/src/activities/execute-deep-agent/index.ts +20 -0
- package/src/activities/execute-deep-agent/prompt-builder.ts +20 -10
- package/src/activities/execute-deep-agent/setup.ts +85 -29
- package/src/activities/execute-deep-agent/shell-env.ts +8 -9
- package/src/activities/execute-deep-agent/subagent-transformer.ts +30 -2
- package/src/activities/execute-deep-agent/subagent-wiring.ts +39 -6
- package/src/activities/hydrate-workflow-execution.ts +8 -3
- package/src/activities/run-command.ts +25 -12
- package/src/activities/run-env.ts +79 -0
- package/src/activities/workflow-event-activities.ts +96 -69
- package/src/bootstrap.ts +5 -0
- package/src/claimcheck/payload-codec.ts +33 -1
- package/src/client/__tests__/stigmer-client.test.ts +110 -11
- package/src/client/stigmer-client.ts +150 -37
- package/src/encryption/config.ts +155 -0
- package/src/encryption/index.ts +3 -0
- package/src/encryption/payload-codec.ts +152 -0
- package/src/middleware/__tests__/path-normalization.test.ts +140 -0
- package/src/middleware/index.ts +8 -0
- package/src/middleware/path-normalization.ts +125 -0
- package/src/middleware/types.ts +11 -0
- package/src/payload-codecs.ts +62 -0
- package/src/preflight.ts +45 -0
- package/src/runner-manager.ts +26 -26
- package/src/runner.ts +12 -27
- package/src/shared/__tests__/approval-policy.test.ts +82 -39
- package/src/shared/__tests__/artifact-storage.test.ts +145 -2
- package/src/shared/__tests__/attachment-naming.test.ts +159 -0
- package/src/shared/__tests__/bedrock-adapter.test.ts +213 -0
- package/src/shared/__tests__/bedrock-seam.test.ts +390 -0
- package/src/shared/__tests__/caller-identity.test.ts +25 -0
- package/src/shared/__tests__/channel-attachment.test.ts +1 -1
- package/src/shared/__tests__/connect-backfill.test.ts +1 -0
- package/src/shared/__tests__/conversation-attachment.test.ts +1 -1
- package/src/shared/__tests__/conversation-catchup.test.ts +24 -0
- package/src/shared/__tests__/datastore-attachment.test.ts +129 -1
- package/src/shared/__tests__/foundry-adapter.test.ts +276 -0
- package/src/shared/__tests__/foundry-seam.test.ts +482 -0
- package/src/shared/__tests__/http-retry.test.ts +68 -0
- package/src/shared/__tests__/llm-backend.test.ts +616 -0
- package/src/shared/__tests__/mcp-enabled-tools.test.ts +86 -0
- package/src/shared/__tests__/mcp-manager.test.ts +137 -15
- package/src/shared/__tests__/mcp-resolver.test.ts +146 -3
- package/src/shared/__tests__/mcp-schema-sanitizer.test.ts +267 -0
- package/src/shared/__tests__/model-client.test.ts +200 -0
- package/src/shared/__tests__/model-error.test.ts +289 -1
- package/src/shared/__tests__/model-pricing.test.ts +62 -2
- package/src/shared/__tests__/model-registry.test.ts +22 -0
- package/src/shared/__tests__/synthesized-attachment.test.ts +1 -0
- package/src/shared/__tests__/vertex-adapter.test.ts +169 -0
- package/src/shared/__tests__/vertex-seam.test.ts +295 -0
- package/src/shared/approval-policy.ts +14 -7
- package/src/shared/artifact-storage.ts +75 -10
- package/src/shared/attachment-naming.ts +78 -0
- package/src/shared/caller-identity.ts +40 -5
- package/src/shared/channel-attachment.ts +1 -0
- package/src/shared/checkpointer/__tests__/http-saver.test.ts +196 -1
- package/src/shared/checkpointer/http-saver.ts +71 -8
- package/src/shared/conversation-attachment.ts +1 -0
- package/src/shared/conversation-catchup.ts +39 -6
- package/src/shared/datastore-attachment.ts +106 -11
- package/src/shared/grpc-retry.ts +5 -1
- package/src/shared/http-retry.ts +139 -0
- package/src/shared/llm-backend.ts +544 -0
- package/src/shared/llm-proxy.ts +15 -0
- package/src/shared/mcp-enabled-tools.ts +105 -0
- package/src/shared/mcp-manager.ts +56 -8
- package/src/shared/mcp-resolver.ts +73 -2
- package/src/shared/mcp-schema-sanitizer.ts +224 -0
- package/src/shared/model-client.ts +179 -19
- package/src/shared/model-error.ts +222 -4
- package/src/shared/model-pricing-data.ts +22 -3
- package/src/shared/model-registry.ts +7 -2
- package/src/shared/plan-mode-permissions.ts +37 -0
- package/src/shared/registry-endpoint.ts +27 -0
- package/src/shared/runner-credential-keys.ts +46 -0
- package/src/worker.ts +4 -5
- package/src/workflow-engine/__tests__/tasks/emit-event.test.ts +127 -49
- package/src/workflow-engine/resolve.ts +48 -2
- package/src/workflow-engine/types.ts +18 -0
- package/src/workflows/__tests__/connect-mcp-server.test.ts +25 -0
- package/src/workflows/__tests__/execute-serverless-workflow.test.ts +68 -2
- package/src/workflows/call-agent-orchestrator.ts +10 -0
- package/src/workflows/connect-mcp-server.ts +9 -0
- package/src/workflows/engine-core.ts +23 -2
- package/src/workflows/execute-from-execution.ts +12 -2
- package/src/workflows/types.ts +8 -0
- package/dist/activities/execute-cursor/mcp-config.d.ts +0 -30
- package/dist/activities/execute-cursor/mcp-config.js +0 -39
- package/dist/activities/execute-cursor/mcp-config.js.map +0 -1
- package/src/activities/execute-cursor/mcp-config.ts +0 -66
|
@@ -15,12 +15,15 @@
|
|
|
15
15
|
* no approval gate — see deepagents-profiles.ts for the suppression half)
|
|
16
16
|
* - Sub-agent backends are shell-capable outside plan mode (issue #248), mirroring
|
|
17
17
|
* the parent's backend selection in setup.ts
|
|
18
|
+
* - Sub-agent graphs carry the parent's filesystem permissions explicitly
|
|
19
|
+
* (issue #255): pre-built CompiledSubAgents never inherit them, so plan
|
|
20
|
+
* mode's deny-all-writes rule is baked into each graph at compile time
|
|
18
21
|
* - Invalid configurations are logged and skipped (graceful degradation)
|
|
19
22
|
* - Empty subagent list returns null (no subagents configured)
|
|
20
23
|
*/
|
|
21
24
|
|
|
22
25
|
import { createDeepAgent, FilesystemBackend, LocalShellBackend, DEFAULT_GENERAL_PURPOSE_DESCRIPTION, DEFAULT_SUBAGENT_PROMPT } from "deepagents";
|
|
23
|
-
import type { CompiledSubAgent } from "deepagents";
|
|
26
|
+
import type { CompiledSubAgent, FilesystemPermission } from "deepagents";
|
|
24
27
|
import type { StructuredTool } from "@langchain/core/tools";
|
|
25
28
|
import type { RunnableConfig } from "@langchain/core/runnables";
|
|
26
29
|
import type { BaseChatModel } from "@langchain/core/language_models/chat_models";
|
|
@@ -180,6 +183,18 @@ export interface SubagentTransformOptions {
|
|
|
180
183
|
* backends, exactly like the parent's backend selection.
|
|
181
184
|
*/
|
|
182
185
|
readonly shellEnv?: Record<string, string>;
|
|
186
|
+
/**
|
|
187
|
+
* Filesystem permission rules baked into each compiled sub-agent graph,
|
|
188
|
+
* inherited from the parent's rules in setup.ts (plan mode's deny-all-writes
|
|
189
|
+
* today). Required because deepagents' parent-permission inheritance covers
|
|
190
|
+
* only spec-style sub-agents — pre-built CompiledSubAgents bypass it, so
|
|
191
|
+
* without this a plan-mode sub-agent could still write (issue #255).
|
|
192
|
+
*
|
|
193
|
+
* Must not be combined with `shellEnv`: deepagents rejects permissions on an
|
|
194
|
+
* execution-capable backend (see the cas-capture-backend.ts header). Plan
|
|
195
|
+
* mode guarantees that by construction — it is the mode that clears shellEnv.
|
|
196
|
+
*/
|
|
197
|
+
readonly permissions?: FilesystemPermission[];
|
|
183
198
|
}
|
|
184
199
|
|
|
185
200
|
// =========================================================================
|
|
@@ -525,6 +540,8 @@ export async function compileSubagents(
|
|
|
525
540
|
readonly modelFactory?: (modelName: string) => Promise<BaseChatModel>;
|
|
526
541
|
/** Shell env for `execute`; see {@link SubagentTransformOptions.shellEnv}. */
|
|
527
542
|
readonly shellEnv?: Record<string, string>;
|
|
543
|
+
/** Per-graph filesystem rules; see {@link SubagentTransformOptions.permissions}. */
|
|
544
|
+
readonly permissions?: FilesystemPermission[];
|
|
528
545
|
},
|
|
529
546
|
): Promise<CompiledSubAgent[]> {
|
|
530
547
|
if (transformed.length === 0) return [];
|
|
@@ -537,11 +554,17 @@ export async function compileSubagents(
|
|
|
537
554
|
// Structural coupling (DD-19): a sub-agent gate flows gitignored writes into
|
|
538
555
|
// CAS iff a CAS observer backs that sub-agent's filesystem backend. Deriving
|
|
539
556
|
// both from the same `casObserver` makes "unobserved unreviewable bytes"
|
|
540
|
-
// impossible by construction.
|
|
557
|
+
// impossible by construction. Same idiom for path normalization
|
|
558
|
+
// (issue #429): derived from the same `permissions` baked into the graph
|
|
559
|
+
// below, so a rule-bearing graph always carries the shim that keeps
|
|
560
|
+
// prompt-compliant relative paths from dying in rule validation.
|
|
541
561
|
const middleware = buildSubAgentMiddleware({
|
|
542
562
|
costCap: opts.costCap,
|
|
543
563
|
approvalGate: opts.approvalGate,
|
|
544
564
|
captureIgnored: !!opts.casObserver,
|
|
565
|
+
...(opts.permissions?.length
|
|
566
|
+
? { pathNormalization: { rootDir: opts.workspaceRootDir } }
|
|
567
|
+
: {}),
|
|
545
568
|
});
|
|
546
569
|
|
|
547
570
|
const modelName = spec.model ?? opts.parentModelName;
|
|
@@ -560,6 +583,9 @@ export async function compileSubagents(
|
|
|
560
583
|
tools: spec.tools.length > 0 ? spec.tools : undefined,
|
|
561
584
|
middleware: middleware as unknown[],
|
|
562
585
|
backend,
|
|
586
|
+
// Enforced inside this graph's own filesystem tools — and inherited by
|
|
587
|
+
// any spec-style sub-agent deepagents auto-injects one level deeper.
|
|
588
|
+
...(opts.permissions ? { permissions: opts.permissions } : {}),
|
|
563
589
|
} as Parameters<typeof createDeepAgent>[0]);
|
|
564
590
|
|
|
565
591
|
const gatedRunnable = gate.wrapRunnable(
|
|
@@ -623,6 +649,7 @@ export async function transformAndCompileSubagents(
|
|
|
623
649
|
costCap,
|
|
624
650
|
modelFactory,
|
|
625
651
|
shellEnv,
|
|
652
|
+
permissions,
|
|
626
653
|
} = options;
|
|
627
654
|
|
|
628
655
|
if (subAgents.length === 0 && !workspaceBackend.rootDir) {
|
|
@@ -743,6 +770,7 @@ export async function transformAndCompileSubagents(
|
|
|
743
770
|
casObserver,
|
|
744
771
|
modelFactory,
|
|
745
772
|
shellEnv,
|
|
773
|
+
permissions,
|
|
746
774
|
});
|
|
747
775
|
|
|
748
776
|
if (compiled.length === 0) {
|
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
* Sub-agent middleware composition for ExecuteDeepAgent.
|
|
3
3
|
*
|
|
4
4
|
* Each sub-agent gets its own middleware stack with:
|
|
5
|
+
* - Path normalization (issue #429), FIRST and only on permission-rule-
|
|
6
|
+
* bearing graphs (plan mode) — workspace-relative paths are rewritten to
|
|
7
|
+
* workspace-absolute before deepagents' permission validation refuses
|
|
8
|
+
* them, exactly as on the parent. `compileSubagents` derives it from the
|
|
9
|
+
* same `permissions` option it bakes into the graph, keeping the rules
|
|
10
|
+
* and their normalization shim coupled.
|
|
5
11
|
* - Fresh loop detection (independent cycle tracking)
|
|
6
12
|
* - Fresh tool truncation (same limits as parent)
|
|
7
13
|
* - Periodic execution budget (interval=30, max=4 advisories)
|
|
@@ -9,11 +15,16 @@
|
|
|
9
15
|
* bypassed) — installed only when the parent itself is gated
|
|
10
16
|
* (`approvalGate` present; absent under auto-approve-all)
|
|
11
17
|
* - Shared cost cap view (parent's budget, no reset on sub-agent start)
|
|
18
|
+
* - Error hints (issue #255): a thrown tool error becomes a recoverable
|
|
19
|
+
* ToolMessage exactly as on the parent. Without it, any tool throw — a
|
|
20
|
+
* plan-mode permission denial, an MCP hiccup — propagated out of the
|
|
21
|
+
* sub-agent graph and killed the whole delegated task, losing all its
|
|
22
|
+
* accumulated work, where the parent's identical error is one failed
|
|
23
|
+
* tool round the model adapts to.
|
|
12
24
|
*
|
|
13
25
|
* The sub-agent middleware stack does NOT include:
|
|
14
26
|
* - Graceful stop (parent handles STOP signal propagation)
|
|
15
27
|
* - OTel spans (parent's OTel context propagates automatically)
|
|
16
|
-
* - Error hints (applied at tool level, not sub-agent level)
|
|
17
28
|
*
|
|
18
29
|
* Approval-gate note: the gate is what *creates* the LangGraph `interrupt()`.
|
|
19
30
|
* A sub-agent's interrupt does surface at the parent checkpoint and resumes
|
|
@@ -22,8 +33,13 @@
|
|
|
22
33
|
* the live HITL bypass this wiring closes.
|
|
23
34
|
*/
|
|
24
35
|
|
|
25
|
-
import type {
|
|
36
|
+
import type {
|
|
37
|
+
StigmerMiddleware,
|
|
38
|
+
ToolTruncationConfig,
|
|
39
|
+
PathNormalizationConfig,
|
|
40
|
+
} from "../../middleware/types.js";
|
|
26
41
|
import type { CostCapMiddleware } from "../../middleware/index.js";
|
|
42
|
+
import { createPathNormalizationMiddleware } from "../../middleware/path-normalization.js";
|
|
27
43
|
import { createLoopDetectionMiddleware } from "../../middleware/loop-detection.js";
|
|
28
44
|
import { createToolTruncationMiddleware } from "../../middleware/tool-truncation.js";
|
|
29
45
|
import { createExecutionBudgetMiddleware } from "../../middleware/execution-budget.js";
|
|
@@ -31,6 +47,7 @@ import {
|
|
|
31
47
|
createApprovalGateMiddleware,
|
|
32
48
|
type ApprovalGateConfig,
|
|
33
49
|
} from "../../middleware/approval-gate.js";
|
|
50
|
+
import { createErrorHintsMiddleware } from "../../middleware/error-hints.js";
|
|
34
51
|
|
|
35
52
|
const SUB_AGENT_ADVISORY_INTERVAL = 30;
|
|
36
53
|
const SUB_AGENT_MAX_ADVISORIES = 4;
|
|
@@ -53,22 +70,36 @@ export interface SubAgentMiddlewareOptions {
|
|
|
53
70
|
* unobserved backend would apply unreviewable bytes.
|
|
54
71
|
*/
|
|
55
72
|
readonly captureIgnored?: boolean;
|
|
73
|
+
/**
|
|
74
|
+
* Workspace-relative path normalization (issue #429). Present iff this
|
|
75
|
+
* sub-agent's graph carries filesystem permission rules — the caller
|
|
76
|
+
* derives it from the same `permissions` value it bakes into the graph.
|
|
77
|
+
*/
|
|
78
|
+
readonly pathNormalization?: PathNormalizationConfig;
|
|
56
79
|
}
|
|
57
80
|
|
|
58
81
|
/**
|
|
59
82
|
* Build the middleware stack for a single sub-agent.
|
|
60
83
|
*
|
|
61
84
|
* Returns an ordered array mirroring the parent composition:
|
|
62
|
-
* loop detection → execution budget (periodic) →
|
|
63
|
-
* [approval gate] → cost cap view
|
|
64
|
-
*
|
|
65
|
-
*
|
|
85
|
+
* [path normalization] → loop detection → execution budget (periodic) →
|
|
86
|
+
* tool truncation → [approval gate] → cost cap view → error hints.
|
|
87
|
+
* Normalization is outermost so everything downstream observes canonical
|
|
88
|
+
* workspace-absolute paths (matching the parent). The gate sits before the
|
|
89
|
+
* cost-cap view so an approval pause happens before budget accounting, and
|
|
90
|
+
* error hints come after the gate — both matching the parent order
|
|
91
|
+
* (…→ truncation → graceful-stop → approval gate → cost cap → error hints …),
|
|
92
|
+
* which keeps the gate's HITL interrupt outside the hints' try/catch.
|
|
66
93
|
*/
|
|
67
94
|
export function buildSubAgentMiddleware(
|
|
68
95
|
options: SubAgentMiddlewareOptions = {},
|
|
69
96
|
): StigmerMiddleware[] {
|
|
70
97
|
const stack: StigmerMiddleware[] = [];
|
|
71
98
|
|
|
99
|
+
if (options.pathNormalization) {
|
|
100
|
+
stack.push(createPathNormalizationMiddleware(options.pathNormalization));
|
|
101
|
+
}
|
|
102
|
+
|
|
72
103
|
stack.push(createLoopDetectionMiddleware({ enabled: true }));
|
|
73
104
|
|
|
74
105
|
stack.push(createExecutionBudgetMiddleware({
|
|
@@ -99,5 +130,7 @@ export function buildSubAgentMiddleware(
|
|
|
99
130
|
stack.push(options.costCap.forSubAgent());
|
|
100
131
|
}
|
|
101
132
|
|
|
133
|
+
stack.push(createErrorHintsMiddleware());
|
|
134
|
+
|
|
102
135
|
return stack;
|
|
103
136
|
}
|
|
@@ -265,9 +265,14 @@ async function fetchAndFlattenEnv(
|
|
|
265
265
|
client: StigmerClient,
|
|
266
266
|
executionId: string,
|
|
267
267
|
): Promise<Record<string, unknown>> {
|
|
268
|
-
//
|
|
269
|
-
//
|
|
270
|
-
//
|
|
268
|
+
// The runner acquires a token scoped to this workflow execution so the
|
|
269
|
+
// server's decrypt gate binds the read: a desktop runner exchanges its
|
|
270
|
+
// bootstrap credential (#156, hard error on failure — the bootstrap
|
|
271
|
+
// credential no longer decrypts since stigmer-cloud#218, so proceeding
|
|
272
|
+
// would hydrate redacted placeholders), and an OSS runner asks the
|
|
273
|
+
// credential-less best-effort exchange (oss#535 — the OSS server redacts
|
|
274
|
+
// EC reads by default and mints execution-scoped tokens). No-op for cloud
|
|
275
|
+
// sandbox runners, whose ambient credential is already scoped.
|
|
271
276
|
const scopedToken = await client.acquireScopedRunnerToken({
|
|
272
277
|
workflowExecutionId: executionId,
|
|
273
278
|
});
|
|
@@ -5,8 +5,11 @@
|
|
|
5
5
|
* - RunScript: writes inline code to a temp file, executes via node/python
|
|
6
6
|
* - RunShell: executes a shell command directly
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
8
|
+
* The child environment follows the declare-to-receive contract in
|
|
9
|
+
* run-env.ts: a minimal base plus the task's declared `environment`,
|
|
10
|
+
* with runtime placeholders (JIT secrets) resolved here in the activity
|
|
11
|
+
* so secret values never enter Temporal history. Both activities capture
|
|
12
|
+
* stdout as the activity result.
|
|
10
13
|
*/
|
|
11
14
|
|
|
12
15
|
import { execFile, exec } from "node:child_process";
|
|
@@ -16,7 +19,9 @@ import { join } from "node:path";
|
|
|
16
19
|
import { promisify } from "node:util";
|
|
17
20
|
import { ApplicationFailure } from "@temporalio/activity";
|
|
18
21
|
import type { RunCommandConfig } from "../workflow-engine/types.js";
|
|
22
|
+
import { RuntimePlaceholderResolutionError } from "../workflow-engine/resolve.js";
|
|
19
23
|
import { startHeartbeat } from "../shared/heartbeat.js";
|
|
24
|
+
import { buildRunEnv } from "./run-env.js";
|
|
20
25
|
|
|
21
26
|
const execFileAsync = promisify(execFile);
|
|
22
27
|
const execAsync = promisify(exec);
|
|
@@ -49,7 +54,7 @@ async function runScriptImpl(config: RunCommandConfig): Promise<unknown> {
|
|
|
49
54
|
|
|
50
55
|
const language = config.language!;
|
|
51
56
|
const code = config.code!;
|
|
52
|
-
const env =
|
|
57
|
+
const env = buildTaskEnv(config);
|
|
53
58
|
|
|
54
59
|
const ext = language === "js" ? ".js" : ".py";
|
|
55
60
|
const interpreter = language === "js" ? "node" : "python3";
|
|
@@ -94,7 +99,7 @@ async function runShellImpl(config: RunCommandConfig): Promise<unknown> {
|
|
|
94
99
|
const fullCommand = args.length > 0
|
|
95
100
|
? `${command} ${args.join(" ")}`
|
|
96
101
|
: command;
|
|
97
|
-
const env =
|
|
102
|
+
const env = buildTaskEnv(config);
|
|
98
103
|
|
|
99
104
|
try {
|
|
100
105
|
const { stdout } = await execAsync(fullCommand, {
|
|
@@ -116,16 +121,24 @@ async function runShellImpl(config: RunCommandConfig): Promise<unknown> {
|
|
|
116
121
|
}
|
|
117
122
|
}
|
|
118
123
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
124
|
+
/**
|
|
125
|
+
* Build the child env per the run-env.ts contract, translating a missing
|
|
126
|
+
* placeholder key into a non-retryable failure — retrying cannot conjure
|
|
127
|
+
* a variable the workflow's runtime env does not have.
|
|
128
|
+
*/
|
|
129
|
+
function buildTaskEnv(config: RunCommandConfig): Record<string, string> {
|
|
130
|
+
try {
|
|
131
|
+
return buildRunEnv(config.environment, config.runtimeEnv);
|
|
132
|
+
} catch (err: unknown) {
|
|
133
|
+
if (err instanceof RuntimePlaceholderResolutionError) {
|
|
134
|
+
throw ApplicationFailure.nonRetryable(
|
|
135
|
+
err.message,
|
|
136
|
+
"RUN_ENV_UNRESOLVED_PLACEHOLDER",
|
|
137
|
+
{ variable: err.variableName },
|
|
138
|
+
);
|
|
126
139
|
}
|
|
140
|
+
throw err;
|
|
127
141
|
}
|
|
128
|
-
return base;
|
|
129
142
|
}
|
|
130
143
|
|
|
131
144
|
function buildArgsList(args: unknown): string[] {
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Environment contract for the workflow `run` task (shell and script modes).
|
|
3
|
+
*
|
|
4
|
+
* Declare-to-receive, the same rule the stdio MCP contract adopted after
|
|
5
|
+
* #256 (PR #383): the child process sees ONLY
|
|
6
|
+
*
|
|
7
|
+
* 1. a minimal base copied from the runner process
|
|
8
|
+
* ({@link RUN_ENV_BASE_KEYS} — the six variables the MCP SDK pins),
|
|
9
|
+
* 2. the task's declared `environment` map, with `${.secrets.KEY}` /
|
|
10
|
+
* `${.env_vars.KEY}` placeholders resolved just-in-time from the
|
|
11
|
+
* workflow's runtime env. Resolution happens here in the activity,
|
|
12
|
+
* never in the deterministic workflow phase, so secret values stay
|
|
13
|
+
* out of Temporal history.
|
|
14
|
+
*
|
|
15
|
+
* Runner credentials (STIGMER_TOKEN, the HITL secret, provider keys) are
|
|
16
|
+
* structurally absent rather than denylisted — a workflow-authored
|
|
17
|
+
* `printenv` cannot read what was never passed (oss#384). A missing
|
|
18
|
+
* placeholder key fails loudly: running a command with a silently-empty
|
|
19
|
+
* credential produces cryptic downstream failures.
|
|
20
|
+
*
|
|
21
|
+
* Placeholders resolve only in declared environment VALUES, never in
|
|
22
|
+
* `command` / `code` strings — argv is visible to `ps` on the host, so
|
|
23
|
+
* the environment is the sanctioned channel for secrets.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import { resolveRuntimePlaceholdersStrict } from "../workflow-engine/resolve.js";
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Base variables copied from the runner process when present — the same
|
|
30
|
+
* six the MCP SDK provides to stdio servers, so "undeclared subprocess
|
|
31
|
+
* environment" has one platform-wide answer. `PATH` keeps interpreters
|
|
32
|
+
* and tools findable; the rest keep shells and language runtimes sane.
|
|
33
|
+
*/
|
|
34
|
+
export const RUN_ENV_BASE_KEYS: readonly string[] = [
|
|
35
|
+
"HOME",
|
|
36
|
+
"LOGNAME",
|
|
37
|
+
"PATH",
|
|
38
|
+
"SHELL",
|
|
39
|
+
"TERM",
|
|
40
|
+
"USER",
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Build the environment for a run task's child process: minimal base +
|
|
45
|
+
* declared overlay with strict placeholder resolution (declared wins on
|
|
46
|
+
* conflict with the base).
|
|
47
|
+
*
|
|
48
|
+
* @throws RuntimePlaceholderResolutionError when a declared value
|
|
49
|
+
* references a runtime key that does not exist.
|
|
50
|
+
*/
|
|
51
|
+
export function buildRunEnv(
|
|
52
|
+
declaredEnv: Readonly<Record<string, string>> | undefined,
|
|
53
|
+
runtimeEnv: Readonly<Record<string, unknown>>,
|
|
54
|
+
baseEnv: NodeJS.ProcessEnv = process.env,
|
|
55
|
+
): Record<string, string> {
|
|
56
|
+
const env: Record<string, string> = {};
|
|
57
|
+
|
|
58
|
+
for (const key of RUN_ENV_BASE_KEYS) {
|
|
59
|
+
const value = baseEnv[key];
|
|
60
|
+
if (value !== undefined) env[key] = value;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (!declaredEnv || Object.keys(declaredEnv).length === 0) {
|
|
64
|
+
// The only case whose behavior changed in oss#384 (previously the
|
|
65
|
+
// child inherited the full runner env) — leave a trace for operators.
|
|
66
|
+
console.log("run task declares no environment — child receives the minimal base env only");
|
|
67
|
+
return env;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
for (const [key, value] of Object.entries(declaredEnv)) {
|
|
71
|
+
env[key] = resolveRuntimePlaceholdersStrict(
|
|
72
|
+
value,
|
|
73
|
+
runtimeEnv,
|
|
74
|
+
`environment "${key}"`,
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return env;
|
|
79
|
+
}
|
|
@@ -3,8 +3,12 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Converts plain event descriptors (safe for the Temporal deterministic
|
|
5
5
|
* sandbox) into WorkflowExecutionEvent proto objects and sends them
|
|
6
|
-
* alongside a status update via gRPC.
|
|
7
|
-
*
|
|
6
|
+
* alongside a status update via gRPC. Failures propagate so the local
|
|
7
|
+
* activity's retry policy fires — safe because sequence numbers are
|
|
8
|
+
* workflow-assigned (stable across attempts) and the store skips
|
|
9
|
+
* already-persisted sequences, making retries idempotent. The workflow's
|
|
10
|
+
* emit wrappers catch after retries are exhausted; event emission never
|
|
11
|
+
* fails a run.
|
|
8
12
|
*
|
|
9
13
|
* Registered as proxyLocalActivities in engine-core.ts so the workflow
|
|
10
14
|
* sandbox can emit events at task boundaries and approval gates.
|
|
@@ -140,6 +144,17 @@ function buildClient(): StigmerClient {
|
|
|
140
144
|
});
|
|
141
145
|
}
|
|
142
146
|
|
|
147
|
+
/**
|
|
148
|
+
* LEGACY sequence assignment — only for descriptors that arrive without a
|
|
149
|
+
* workflow-assigned `sequenceNumber`, i.e. replays of histories recorded
|
|
150
|
+
* before the "workflow-assigned-event-sequences" patch (see
|
|
151
|
+
* engine-core.ts). This counter is process-global: it is shared across
|
|
152
|
+
* every execution on the worker and resets on worker restart, which is
|
|
153
|
+
* the root cause of oss#308's silent event loss. Deliberately NOT fixed —
|
|
154
|
+
* pre-patch executions keep their old (flawed) behavior for the
|
|
155
|
+
* migration window. Delete together with the patch gate once pre-patch
|
|
156
|
+
* executions have drained.
|
|
157
|
+
*/
|
|
143
158
|
let sequenceCounter = 0;
|
|
144
159
|
|
|
145
160
|
function nextSequence(): bigint {
|
|
@@ -148,33 +163,44 @@ function nextSequence(): bigint {
|
|
|
148
163
|
}
|
|
149
164
|
|
|
150
165
|
/**
|
|
151
|
-
*
|
|
166
|
+
* Return the persisted event-log high-water mark for the execution, and
|
|
167
|
+
* seed the legacy process-global counter from it.
|
|
152
168
|
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
169
|
+
* The workflow seeds its own sequence counter from the returned value
|
|
170
|
+
* (patched path); the legacy global seed remains for pre-patch replays,
|
|
171
|
+
* whose emit path still assigns sequences here in the activity.
|
|
155
172
|
*
|
|
156
|
-
* On
|
|
157
|
-
*
|
|
158
|
-
*
|
|
173
|
+
* On first run (no prior events) returns 0, so the first event gets
|
|
174
|
+
* sequence_number = 1. On recovery (events already persisted from a
|
|
175
|
+
* failed run) returns the highest persisted sequence_number, so new
|
|
176
|
+
* events continue from N+1.
|
|
159
177
|
*
|
|
160
178
|
* When executionId is empty (direct executeServerlessWorkflow without a
|
|
161
|
-
* persisted execution),
|
|
179
|
+
* persisted execution), returns 0 as a safe fallback.
|
|
180
|
+
*
|
|
181
|
+
* Returns a plain number — the value crosses back into the workflow
|
|
182
|
+
* through Temporal's JSON payload converter, which cannot carry BigInt.
|
|
162
183
|
*/
|
|
163
|
-
export async function initSequenceFromEventLog(executionId: string): Promise<
|
|
184
|
+
export async function initSequenceFromEventLog(executionId: string): Promise<number> {
|
|
164
185
|
if (!executionId) {
|
|
165
186
|
sequenceCounter = 0;
|
|
166
|
-
return;
|
|
187
|
+
return 0;
|
|
167
188
|
}
|
|
168
189
|
const client = buildClient();
|
|
169
190
|
const highWaterMark = await client.getEventLogHighWaterMark(executionId);
|
|
170
191
|
sequenceCounter = Number(highWaterMark);
|
|
192
|
+
return sequenceCounter;
|
|
171
193
|
}
|
|
172
194
|
|
|
173
195
|
/** @internal Exported for unit testing only. */
|
|
174
196
|
export function toProtoEvent(desc: WorkflowEventDescriptor): WorkflowExecutionEvent {
|
|
175
197
|
const base = create(WorkflowExecutionEventSchema, {
|
|
176
198
|
eventId: crypto.randomUUID(),
|
|
177
|
-
|
|
199
|
+
// Workflow-assigned sequence when present (stable across activity
|
|
200
|
+
// retries); legacy activity-side assignment only for pre-patch replays.
|
|
201
|
+
sequenceNumber: desc.sequenceNumber !== undefined
|
|
202
|
+
? BigInt(desc.sequenceNumber)
|
|
203
|
+
: nextSequence(),
|
|
178
204
|
occurredAt: desc.occurredAt,
|
|
179
205
|
taskName: desc.taskName ?? "",
|
|
180
206
|
});
|
|
@@ -382,6 +408,14 @@ export function toProtoEvent(desc: WorkflowEventDescriptor): WorkflowExecutionEv
|
|
|
382
408
|
return base;
|
|
383
409
|
}
|
|
384
410
|
|
|
411
|
+
/**
|
|
412
|
+
* Emit workflow events (with the accompanying status snapshot) to the
|
|
413
|
+
* server. Errors propagate so the local activity retry policy fires;
|
|
414
|
+
* retries are idempotent because workflow-assigned sequence numbers are
|
|
415
|
+
* stable across attempts and the store skips already-persisted ones. The
|
|
416
|
+
* workflow-side emit wrappers absorb the failure after retries are
|
|
417
|
+
* exhausted, so a broken timeline write never fails the run.
|
|
418
|
+
*/
|
|
385
419
|
export async function emitWorkflowEvents(
|
|
386
420
|
executionId: string,
|
|
387
421
|
events: WorkflowEventDescriptor[],
|
|
@@ -389,64 +423,57 @@ export async function emitWorkflowEvents(
|
|
|
389
423
|
): Promise<void> {
|
|
390
424
|
if (!executionId || events.length === 0) return;
|
|
391
425
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
statusFields.error = failedEvent.error;
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
const input = create(WorkflowExecutionUpdateStatusInputSchema, {
|
|
439
|
-
executionId,
|
|
440
|
-
status: create(WorkflowExecutionStatusSchema, statusFields as Parameters<typeof create>[1]),
|
|
441
|
-
events: protoEvents,
|
|
442
|
-
});
|
|
443
|
-
await client.workflowExecutionCommand.updateStatus(input);
|
|
444
|
-
} catch (err) {
|
|
445
|
-
console.error(
|
|
446
|
-
`Failed to emit ${events.length} workflow event(s) for ${executionId}:`,
|
|
447
|
-
err,
|
|
448
|
-
);
|
|
426
|
+
const client = buildClient();
|
|
427
|
+
const protoEvents = events.map(toProtoEvent);
|
|
428
|
+
|
|
429
|
+
const protoTasks = (taskStatuses ?? []).map(ts =>
|
|
430
|
+
create(WorkflowTaskSchema, {
|
|
431
|
+
taskId: ts.taskId ?? "",
|
|
432
|
+
taskName: ts.taskName,
|
|
433
|
+
taskType: TASK_KIND_TO_TYPE_MAP[ts.taskKind] ?? WorkflowTaskType.WORKFLOW_TASK_TYPE_UNSPECIFIED,
|
|
434
|
+
status: TASK_STATUS_MAP[ts.status],
|
|
435
|
+
startedAt: ts.startedAt ?? "",
|
|
436
|
+
completedAt: ts.completedAt ?? "",
|
|
437
|
+
error: ts.error ?? "",
|
|
438
|
+
input: toJsonObject(ts.input),
|
|
439
|
+
output: toJsonObject(ts.output),
|
|
440
|
+
metadata: toJsonObject(ts.metadata),
|
|
441
|
+
costMicros: BigInt(ts.costMicros ?? 0),
|
|
442
|
+
inputTokens: BigInt(ts.inputTokens ?? 0),
|
|
443
|
+
outputTokens: BigInt(ts.outputTokens ?? 0),
|
|
444
|
+
uiHint: ts.uiHint ?? "",
|
|
445
|
+
}),
|
|
446
|
+
);
|
|
447
|
+
|
|
448
|
+
const startedEvent = events.find(e => e.type === "execution_started");
|
|
449
|
+
const completedEvent = events.find(e => e.type === "execution_completed");
|
|
450
|
+
const failedEvent = events.find(e => e.type === "execution_failed");
|
|
451
|
+
|
|
452
|
+
const statusFields: Record<string, unknown> = { tasks: protoTasks };
|
|
453
|
+
|
|
454
|
+
if (startedEvent) {
|
|
455
|
+
statusFields.phase = ExecutionPhase.EXECUTION_IN_PROGRESS;
|
|
456
|
+
statusFields.startedAt = startedEvent.occurredAt;
|
|
457
|
+
}
|
|
458
|
+
if (completedEvent && completedEvent.type === "execution_completed") {
|
|
459
|
+
statusFields.phase = ExecutionPhase.EXECUTION_COMPLETED;
|
|
460
|
+
statusFields.completedAt = completedEvent.occurredAt;
|
|
461
|
+
statusFields.totalCostMicros = BigInt(completedEvent.totalCostMicros);
|
|
462
|
+
statusFields.totalInputTokens = BigInt(completedEvent.totalInputTokens ?? 0);
|
|
463
|
+
statusFields.totalOutputTokens = BigInt(completedEvent.totalOutputTokens ?? 0);
|
|
464
|
+
}
|
|
465
|
+
if (failedEvent && failedEvent.type === "execution_failed") {
|
|
466
|
+
statusFields.phase = ExecutionPhase.EXECUTION_FAILED;
|
|
467
|
+
statusFields.completedAt = failedEvent.occurredAt;
|
|
468
|
+
statusFields.error = failedEvent.error;
|
|
449
469
|
}
|
|
470
|
+
|
|
471
|
+
const input = create(WorkflowExecutionUpdateStatusInputSchema, {
|
|
472
|
+
executionId,
|
|
473
|
+
status: create(WorkflowExecutionStatusSchema, statusFields as Parameters<typeof create>[1]),
|
|
474
|
+
events: protoEvents,
|
|
475
|
+
});
|
|
476
|
+
await client.workflowExecutionCommand.updateStatus(input);
|
|
450
477
|
}
|
|
451
478
|
|
|
452
479
|
const PROTO_STATUS_TO_STRING: Record<number, string> = {
|
package/src/bootstrap.ts
CHANGED
|
@@ -120,6 +120,11 @@ export async function resolveRunnerBootstrap(
|
|
|
120
120
|
// (OSS / no signing key) and is handled by the runner, not treated as fatal.
|
|
121
121
|
runnerAccessToken: discovered.runnerAccessToken,
|
|
122
122
|
runnerAccessTokenExpiresInSeconds: discovered.runnerAccessTokenExpiresInSeconds,
|
|
123
|
+
// Server-managed payload-encryption keys ride the same best-effort lane:
|
|
124
|
+
// absent on OSS (env-configured keys) and on cloud servers predating key
|
|
125
|
+
// management. Note the explicit-address and localhost branches above return
|
|
126
|
+
// none by construction — key management only exists where discovery does.
|
|
127
|
+
payloadEncryption: discovered.payloadEncryption,
|
|
123
128
|
};
|
|
124
129
|
}
|
|
125
130
|
|
|
@@ -22,6 +22,14 @@ interface ClaimcheckMarker {
|
|
|
22
22
|
key: string;
|
|
23
23
|
size: number;
|
|
24
24
|
compressed: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* The relocated payload's original metadata, base64-encoded per value.
|
|
27
|
+
* Without it the restored payload would carry the marker's own
|
|
28
|
+
* "binary/claimcheck" encoding and no payload converter could interpret
|
|
29
|
+
* it. Absent on markers written before this field existed; those decode
|
|
30
|
+
* with the legacy (metadata-less) behavior.
|
|
31
|
+
*/
|
|
32
|
+
metadata?: Record<string, string>;
|
|
25
33
|
}
|
|
26
34
|
|
|
27
35
|
export class ClaimcheckPayloadCodec implements PayloadCodec {
|
|
@@ -63,6 +71,7 @@ export class ClaimcheckPayloadCodec implements PayloadCodec {
|
|
|
63
71
|
key,
|
|
64
72
|
size: data.length,
|
|
65
73
|
compressed,
|
|
74
|
+
metadata: serializeMetadata(payload.metadata),
|
|
66
75
|
};
|
|
67
76
|
|
|
68
77
|
return {
|
|
@@ -94,7 +103,9 @@ export class ClaimcheckPayloadCodec implements PayloadCodec {
|
|
|
94
103
|
const dataBuf = marker.compressed ? decompress(rawBuf) : rawBuf;
|
|
95
104
|
|
|
96
105
|
return {
|
|
97
|
-
metadata:
|
|
106
|
+
metadata: marker.metadata
|
|
107
|
+
? deserializeMetadata(marker.metadata)
|
|
108
|
+
: payload.metadata,
|
|
98
109
|
data: dataBuf,
|
|
99
110
|
};
|
|
100
111
|
}
|
|
@@ -105,3 +116,24 @@ export class ClaimcheckPayloadCodec implements PayloadCodec {
|
|
|
105
116
|
return Buffer.from(encoding).toString("utf-8") === MARKER_ENCODING_VALUE;
|
|
106
117
|
}
|
|
107
118
|
}
|
|
119
|
+
|
|
120
|
+
function serializeMetadata(
|
|
121
|
+
metadata: Payload["metadata"],
|
|
122
|
+
): Record<string, string> | undefined {
|
|
123
|
+
if (!metadata) return undefined;
|
|
124
|
+
const out: Record<string, string> = {};
|
|
125
|
+
for (const [key, value] of Object.entries(metadata)) {
|
|
126
|
+
if (value) out[key] = Buffer.from(value).toString("base64");
|
|
127
|
+
}
|
|
128
|
+
return out;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function deserializeMetadata(
|
|
132
|
+
metadata: Record<string, string>,
|
|
133
|
+
): Record<string, Uint8Array> {
|
|
134
|
+
const out: Record<string, Uint8Array> = {};
|
|
135
|
+
for (const [key, value] of Object.entries(metadata)) {
|
|
136
|
+
out[key] = Buffer.from(value, "base64");
|
|
137
|
+
}
|
|
138
|
+
return out;
|
|
139
|
+
}
|