@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
|
@@ -20,10 +20,37 @@
|
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
22
|
import { normalizeEndpoint } from "../config.js";
|
|
23
|
+
import type { FetchRetryPolicy } from "./http-retry.js";
|
|
23
24
|
|
|
24
25
|
/** Default local stigmer-server origin — mirrors config.ts's local-mode default. */
|
|
25
26
|
const DEFAULT_LOCAL_BACKEND = "http://localhost:7234";
|
|
26
27
|
|
|
28
|
+
/**
|
|
29
|
+
* Shared retry policy for the three registry fetch clients (model-registry.ts
|
|
30
|
+
* and both model-pricing-data.ts modules) — stigmer/stigmer#468.
|
|
31
|
+
*
|
|
32
|
+
* The timeout is the load-bearing half: each consumer deduplicates callers
|
|
33
|
+
* through a single in-flight promise, so one hung fetch strands every
|
|
34
|
+
* concurrent caller behind it — model-registry.ts's sits in front of every
|
|
35
|
+
* LLM client build. 10 s (not the checkpointer's 30 s) because the response
|
|
36
|
+
* is a small JSON document and the callers degrade gracefully; what they must
|
|
37
|
+
* never do is wait forever.
|
|
38
|
+
*
|
|
39
|
+
* The retry half matters because the degrade is not free: a failed registry
|
|
40
|
+
* fetch is cached (60 s empty registry → unresolved model ids that 404 at the
|
|
41
|
+
* provider; pricing falls back to defaults), so a budget spanning a
|
|
42
|
+
* pod-restart reroute converts that poisoned window into ~1.75 s of backoff.
|
|
43
|
+
* Worst case fully bounded: ~31 s of cold-cache stall when the control plane
|
|
44
|
+
* is genuinely down, versus an infinite hang before #468.
|
|
45
|
+
*/
|
|
46
|
+
export const REGISTRY_RETRY_POLICY: FetchRetryPolicy = {
|
|
47
|
+
label: "registry-endpoint",
|
|
48
|
+
baseDelayMs: 250,
|
|
49
|
+
backoffFactor: 2,
|
|
50
|
+
maxRetries: 3,
|
|
51
|
+
requestTimeoutMs: 10_000,
|
|
52
|
+
};
|
|
53
|
+
|
|
27
54
|
/**
|
|
28
55
|
* Resolve the base URL (origin, no path) for model-registry and pricing
|
|
29
56
|
* fetches. See module doc for the tier order.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Env var names of the runner's own credentials — the single source of truth
|
|
3
|
+
* for every surface that isolates agent-spawned processes from the runner's
|
|
4
|
+
* process env (issue #385).
|
|
5
|
+
*
|
|
6
|
+
* Inclusion rule: a name belongs here iff the runner reads it from its own
|
|
7
|
+
* `process.env` to authenticate the runner's own outbound calls. User-supplied
|
|
8
|
+
* credentials resolved from ExecutionContext (e.g. GITHUB_TOKEN, read only
|
|
9
|
+
* from mergedEnvVars) must NEVER be listed — the ExecutionContext overlay is
|
|
10
|
+
* their sanctioned delivery channel, and denying them here would break it.
|
|
11
|
+
*
|
|
12
|
+
* Consumers:
|
|
13
|
+
* - shell-env.ts: SHELL_ENV_DENYLIST for the native harness `execute` tool.
|
|
14
|
+
* - mcp-manager.test.ts: leak-tripwire canaries for MCP stdio subprocesses
|
|
15
|
+
* (that path passes NO runner env by construction; the test plants these
|
|
16
|
+
* names to prove none leak through).
|
|
17
|
+
*
|
|
18
|
+
* Ambient cloud-SDK chain vars (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY,
|
|
19
|
+
* GOOGLE_APPLICATION_CREDENTIALS, ...) are deliberately absent: they are
|
|
20
|
+
* dual-use on local runners (operators expect agent shells to keep their
|
|
21
|
+
* ambient aws/gcloud auth), and on a local backend the shell can read the
|
|
22
|
+
* credential files off disk regardless (owner ruling on #385).
|
|
23
|
+
*/
|
|
24
|
+
export const RUNNER_CREDENTIAL_ENV_KEYS: readonly string[] = [
|
|
25
|
+
// Derives HITL approval fingerprints (fingerprint-secret.ts) — an agent
|
|
26
|
+
// that reads this could forge approval receipts.
|
|
27
|
+
"STIGMER_RUNNER_HITL_SECRET",
|
|
28
|
+
// Stigmer control-plane auth (config.ts; rotated at runtime by
|
|
29
|
+
// runner-manager.ts). Executions receive theirs via ExecutionContext.
|
|
30
|
+
"STIGMER_TOKEN",
|
|
31
|
+
// Fallback bearer token for model-registry/pricing fetches when
|
|
32
|
+
// STIGMER_TOKEN is unset (registry-endpoint.ts).
|
|
33
|
+
"STIGMER_AUTH_TOKEN",
|
|
34
|
+
// Cursor harness credential (config.ts) — agent-spawned processes never
|
|
35
|
+
// need direct Cursor API access.
|
|
36
|
+
"CURSOR_API_KEY",
|
|
37
|
+
// Direct-mode Anthropic key for the native harness (model-client.ts).
|
|
38
|
+
"ANTHROPIC_API_KEY",
|
|
39
|
+
// Direct-mode OpenAI key for the native harness (model-client.ts).
|
|
40
|
+
"OPENAI_API_KEY",
|
|
41
|
+
// Azure AI Foundry backend key (model-client.ts).
|
|
42
|
+
"ANTHROPIC_FOUNDRY_API_KEY",
|
|
43
|
+
// Bedrock backend bearer credential, read by the AWS SDK's chain
|
|
44
|
+
// (llm-backend.ts documents it as a supported auth path).
|
|
45
|
+
"AWS_BEARER_TOKEN_BEDROCK",
|
|
46
|
+
];
|
package/src/worker.ts
CHANGED
|
@@ -27,11 +27,12 @@ export interface WorkerActivities {
|
|
|
27
27
|
export interface StartWorkerOptions {
|
|
28
28
|
config: Config;
|
|
29
29
|
activities: WorkerActivities;
|
|
30
|
-
|
|
30
|
+
/** Ordered codec chain from createPayloadCodecs (order is load-bearing). */
|
|
31
|
+
payloadCodecs?: PayloadCodec[];
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
export async function startWorker(opts: StartWorkerOptions): Promise<Worker> {
|
|
34
|
-
const { config, activities,
|
|
35
|
+
const { config, activities, payloadCodecs } = opts;
|
|
35
36
|
|
|
36
37
|
const connection = await NativeConnection.connect({
|
|
37
38
|
address: config.temporalAddress,
|
|
@@ -89,9 +90,7 @@ export async function startWorker(opts: StartWorkerOptions): Promise<Worker> {
|
|
|
89
90
|
? { workflowBundle: { codePath: workflowSource.codePath } }
|
|
90
91
|
: { workflowsPath: workflowSource.workflowsPath }),
|
|
91
92
|
maxConcurrentActivityTaskExecutions: config.maxConcurrentActivities,
|
|
92
|
-
dataConverter:
|
|
93
|
-
? { payloadCodecs: [payloadCodec] }
|
|
94
|
-
: undefined,
|
|
93
|
+
dataConverter: payloadCodecs?.length ? { payloadCodecs } : undefined,
|
|
95
94
|
sinks,
|
|
96
95
|
interceptors: {
|
|
97
96
|
...(activityInterceptors.length > 0 ? { activity: activityInterceptors } : {}),
|
|
@@ -1,32 +1,34 @@
|
|
|
1
1
|
import { describe, it, expect, vi, afterEach, beforeEach } from "vitest";
|
|
2
|
-
import { emitEventAction, type EmitEventConfig } from "../../../activities/emit-event.js";
|
|
3
|
-
|
|
4
|
-
// ───
|
|
5
|
-
// deliverSignal
|
|
6
|
-
//
|
|
7
|
-
// without a live
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
2
|
+
import { emitEventAction, type EmitEventConfig, type SignalDeliveryTarget } from "../../../activities/emit-event.js";
|
|
3
|
+
|
|
4
|
+
// ─── Server-mediated signal-delivery mocks ───────────────────────────────────
|
|
5
|
+
// deliverSignal routes through StigmerClient.sendWorkflowSignal (the server's
|
|
6
|
+
// SendSignal lane — oss#517). We mock the client so the signal path is testable
|
|
7
|
+
// without a live server, and so we can assert the addressing, the bounded call
|
|
8
|
+
// timeout, and the best-effort delivery_errors contract.
|
|
9
|
+
const mockSendWorkflowSignal = vi.fn(async (
|
|
10
|
+
_executionId: string,
|
|
11
|
+
_signalName: string,
|
|
12
|
+
_payload: unknown,
|
|
13
|
+
_options?: { timeoutMs?: number },
|
|
14
|
+
) => ({}));
|
|
15
|
+
const mockClientCtor = vi.fn((_opts: { endpoint: string; token?: string | null }) => ({
|
|
16
|
+
sendWorkflowSignal: mockSendWorkflowSignal,
|
|
13
17
|
}));
|
|
14
18
|
|
|
15
|
-
vi.mock("
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
mockClientCtor(opts),
|
|
19
|
+
vi.mock("../../../client/stigmer-client.js", () => ({
|
|
20
|
+
StigmerClient: vi.fn().mockImplementation(
|
|
21
|
+
(opts: { endpoint: string; token?: string | null }) => mockClientCtor(opts),
|
|
19
22
|
),
|
|
20
23
|
}));
|
|
21
24
|
|
|
22
|
-
// Mutable so each test can vary what config.ts resolves.
|
|
23
|
-
//
|
|
24
|
-
let
|
|
25
|
-
let mockTemporalNamespace = "default";
|
|
25
|
+
// Mutable so each test can vary what config.ts resolves. deliverSignal builds
|
|
26
|
+
// its client from the canonical stigmerBackendEndpoint resolution.
|
|
27
|
+
let mockBackendEndpoint = "http://localhost:7234";
|
|
26
28
|
vi.mock("../../../config.js", () => ({
|
|
27
29
|
loadConfig: () => ({
|
|
28
|
-
|
|
29
|
-
|
|
30
|
+
stigmerBackendEndpoint: mockBackendEndpoint,
|
|
31
|
+
stigmerToken: null,
|
|
30
32
|
}),
|
|
31
33
|
}));
|
|
32
34
|
|
|
@@ -260,63 +262,139 @@ describe("emitEventAction", () => {
|
|
|
260
262
|
});
|
|
261
263
|
});
|
|
262
264
|
|
|
263
|
-
describe("signal delivery (
|
|
265
|
+
describe("signal delivery (server-mediated SendSignal lane)", () => {
|
|
264
266
|
beforeEach(() => {
|
|
265
|
-
|
|
266
|
-
mockSignal.mockClear();
|
|
267
|
-
mockGetHandle.mockClear();
|
|
267
|
+
mockSendWorkflowSignal.mockClear();
|
|
268
268
|
mockClientCtor.mockClear();
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
mockTemporalNamespace = "default";
|
|
269
|
+
mockSendWorkflowSignal.mockResolvedValue({});
|
|
270
|
+
mockBackendEndpoint = "http://localhost:7234";
|
|
272
271
|
});
|
|
273
272
|
|
|
274
|
-
it("
|
|
275
|
-
|
|
276
|
-
// and fell back to localhost — diverging from the canonical
|
|
277
|
-
// TEMPORAL_SERVICE_ADDRESS the worker uses. It now goes through loadConfig().
|
|
278
|
-
mockTemporalAddress = "stigmer-temporal-frontend:7233";
|
|
279
|
-
mockTemporalNamespace = "stigmer-prod";
|
|
273
|
+
it("routes through the server resolved by config, addressed by execution_id", async () => {
|
|
274
|
+
mockBackendEndpoint = "https://api.stigmer.example.com";
|
|
280
275
|
|
|
281
276
|
const config: EmitEventConfig = {
|
|
282
277
|
event: { type: "approval.granted" },
|
|
283
278
|
delivery: [
|
|
284
|
-
{ signal: {
|
|
279
|
+
{ signal: { execution_id: "wfx_01ABC", signal_name: "approval_resolved" } },
|
|
285
280
|
],
|
|
286
281
|
};
|
|
287
282
|
|
|
288
283
|
const result = await emitEventAction(config, "exec-1");
|
|
289
284
|
|
|
290
|
-
expect(mockConnect).toHaveBeenCalledWith({ address: "stigmer-temporal-frontend:7233" });
|
|
291
285
|
expect(mockClientCtor).toHaveBeenCalledWith(
|
|
292
|
-
expect.objectContaining({
|
|
286
|
+
expect.objectContaining({ endpoint: "https://api.stigmer.example.com" }),
|
|
293
287
|
);
|
|
294
|
-
expect(
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
288
|
+
expect(mockSendWorkflowSignal).toHaveBeenCalledTimes(1);
|
|
289
|
+
const [executionId, signalName, envelope, options] =
|
|
290
|
+
mockSendWorkflowSignal.mock.calls[0] as unknown as [
|
|
291
|
+
string,
|
|
292
|
+
string,
|
|
293
|
+
Record<string, unknown>,
|
|
294
|
+
{ timeoutMs?: number },
|
|
295
|
+
];
|
|
296
|
+
expect(executionId).toBe("wfx_01ABC");
|
|
297
|
+
expect(signalName).toBe("approval_resolved");
|
|
301
298
|
expect(envelope.type).toBe("approval.granted");
|
|
299
|
+
expect(envelope.specversion).toBe("1.0");
|
|
302
300
|
expect(result.delivery_errors).toBeUndefined();
|
|
301
|
+
// Best-effort delivery must never consume the activity's 5m budget.
|
|
302
|
+
expect(options).toEqual({ timeoutMs: 30_000 });
|
|
303
303
|
});
|
|
304
304
|
|
|
305
|
-
it("keeps signal delivery best-effort:
|
|
306
|
-
|
|
305
|
+
it("keeps signal delivery best-effort: server refusals are collected, not thrown", async () => {
|
|
306
|
+
mockSendWorkflowSignal.mockRejectedValueOnce(
|
|
307
|
+
new Error("[failed_precondition] cannot send signal to execution in phase EXECUTION_COMPLETED"),
|
|
308
|
+
);
|
|
309
|
+
|
|
310
|
+
const config: EmitEventConfig = {
|
|
311
|
+
event: { type: "test" },
|
|
312
|
+
delivery: [
|
|
313
|
+
{ signal: { execution_id: "wfx_done", signal_name: "ping" } },
|
|
314
|
+
],
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
const result = await emitEventAction(config, "exec-1");
|
|
318
|
+
|
|
319
|
+
expect(result.delivery_errors).toHaveLength(1);
|
|
320
|
+
expect((result.delivery_errors as any)[0].target).toBe("signal:wfx_done/ping");
|
|
321
|
+
expect((result.delivery_errors as any)[0].error).toContain("failed_precondition");
|
|
322
|
+
});
|
|
307
323
|
|
|
324
|
+
it("refuses the pre-oss#517 workflow_id field by name, without calling the server", async () => {
|
|
308
325
|
const config: EmitEventConfig = {
|
|
309
326
|
event: { type: "test" },
|
|
310
327
|
delivery: [
|
|
311
|
-
{
|
|
328
|
+
{
|
|
329
|
+
signal: {
|
|
330
|
+
workflow_id: "workflow-exec-wfx_01ABC",
|
|
331
|
+
signal_name: "ping",
|
|
332
|
+
} as unknown as SignalDeliveryTarget,
|
|
333
|
+
},
|
|
312
334
|
],
|
|
313
335
|
};
|
|
314
336
|
|
|
315
337
|
const result = await emitEventAction(config, "exec-1");
|
|
316
338
|
|
|
339
|
+
expect(mockSendWorkflowSignal).not.toHaveBeenCalled();
|
|
317
340
|
expect(result.delivery_errors).toHaveLength(1);
|
|
318
|
-
expect((result.delivery_errors as any)[0].
|
|
319
|
-
expect((result.delivery_errors as any)[0].error).toContain("
|
|
341
|
+
expect((result.delivery_errors as any)[0].error).toContain("'execution_id'");
|
|
342
|
+
expect((result.delivery_errors as any)[0].error).toContain("'workflow_id' is not supported");
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
it("refuses a signal target missing signal_name", async () => {
|
|
346
|
+
const config: EmitEventConfig = {
|
|
347
|
+
event: { type: "test" },
|
|
348
|
+
delivery: [
|
|
349
|
+
{
|
|
350
|
+
signal: {
|
|
351
|
+
execution_id: "wfx_01ABC",
|
|
352
|
+
} as unknown as SignalDeliveryTarget,
|
|
353
|
+
},
|
|
354
|
+
],
|
|
355
|
+
};
|
|
356
|
+
|
|
357
|
+
const result = await emitEventAction(config, "exec-1");
|
|
358
|
+
|
|
359
|
+
expect(mockSendWorkflowSignal).not.toHaveBeenCalled();
|
|
360
|
+
expect(result.delivery_errors).toHaveLength(1);
|
|
361
|
+
expect((result.delivery_errors as any)[0].error).toContain("'signal_name'");
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
it("reuses one client across multiple signal targets", async () => {
|
|
365
|
+
const config: EmitEventConfig = {
|
|
366
|
+
event: { type: "fanout" },
|
|
367
|
+
delivery: [
|
|
368
|
+
{ signal: { execution_id: "wfx_a", signal_name: "sig_a" } },
|
|
369
|
+
{ signal: { execution_id: "wfx_b", signal_name: "sig_b" } },
|
|
370
|
+
],
|
|
371
|
+
};
|
|
372
|
+
|
|
373
|
+
const result = await emitEventAction(config, "exec-1");
|
|
374
|
+
|
|
375
|
+
expect(mockClientCtor).toHaveBeenCalledTimes(1);
|
|
376
|
+
expect(mockSendWorkflowSignal).toHaveBeenCalledTimes(2);
|
|
377
|
+
expect(result.delivery_errors).toBeUndefined();
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
it("constructs no client for webhook-only delivery", async () => {
|
|
381
|
+
const originalFetch = globalThis.fetch;
|
|
382
|
+
globalThis.fetch = vi.fn(() =>
|
|
383
|
+
Promise.resolve(new Response(null, { status: 200 })),
|
|
384
|
+
) as any;
|
|
385
|
+
|
|
386
|
+
try {
|
|
387
|
+
const config: EmitEventConfig = {
|
|
388
|
+
event: { type: "test" },
|
|
389
|
+
delivery: [{ webhook: { url: "https://events.example.com" } }],
|
|
390
|
+
};
|
|
391
|
+
|
|
392
|
+
await emitEventAction(config, "exec-1");
|
|
393
|
+
|
|
394
|
+
expect(mockClientCtor).not.toHaveBeenCalled();
|
|
395
|
+
} finally {
|
|
396
|
+
globalThis.fetch = originalFetch;
|
|
397
|
+
}
|
|
320
398
|
});
|
|
321
399
|
});
|
|
322
400
|
});
|
|
@@ -158,6 +158,9 @@ function parsePath(path: string): (string | number)[] {
|
|
|
158
158
|
|
|
159
159
|
const RUNTIME_PLACEHOLDER_RE = /\$\{\.(secrets|env_vars)\.\w+\}/;
|
|
160
160
|
|
|
161
|
+
/** Substitution form of {@link RUNTIME_PLACEHOLDER_RE} (global, capturing). */
|
|
162
|
+
const RUNTIME_PLACEHOLDER_SUB_RE = /\$\{\.(secrets|env_vars)\.(\w+)\}/g;
|
|
163
|
+
|
|
161
164
|
/**
|
|
162
165
|
* Checks whether a string contains a runtime placeholder that should
|
|
163
166
|
* NOT be evaluated in the workflow (deterministic) phase. These are
|
|
@@ -172,7 +175,9 @@ export function isRuntimePlaceholder(value: string): boolean {
|
|
|
172
175
|
|
|
173
176
|
/**
|
|
174
177
|
* Resolves runtime placeholders (`${.secrets.KEY}`, `${.env_vars.KEY}`)
|
|
175
|
-
* in a string using values from the runtime environment map.
|
|
178
|
+
* in a string using values from the runtime environment map. Missing
|
|
179
|
+
* keys resolve to `""` — callers that must fail loudly instead use
|
|
180
|
+
* {@link resolveRuntimePlaceholdersStrict}.
|
|
176
181
|
*
|
|
177
182
|
* This runs in activities only — never in the workflow sandbox.
|
|
178
183
|
*/
|
|
@@ -181,7 +186,7 @@ export function resolveRuntimePlaceholders(
|
|
|
181
186
|
runtimeEnv: Record<string, unknown>,
|
|
182
187
|
): string {
|
|
183
188
|
return value.replace(
|
|
184
|
-
|
|
189
|
+
RUNTIME_PLACEHOLDER_SUB_RE,
|
|
185
190
|
(_match, _ns: string, key: string) => {
|
|
186
191
|
const resolved = runtimeEnv[key];
|
|
187
192
|
return resolved !== undefined ? String(resolved) : "";
|
|
@@ -189,6 +194,47 @@ export function resolveRuntimePlaceholders(
|
|
|
189
194
|
);
|
|
190
195
|
}
|
|
191
196
|
|
|
197
|
+
/** Thrown by {@link resolveRuntimePlaceholdersStrict} for a missing key. */
|
|
198
|
+
export class RuntimePlaceholderResolutionError extends Error {
|
|
199
|
+
constructor(
|
|
200
|
+
public readonly variableName: string,
|
|
201
|
+
public readonly context?: string,
|
|
202
|
+
) {
|
|
203
|
+
const where = context ? ` in ${context}` : "";
|
|
204
|
+
super(
|
|
205
|
+
`Unresolved runtime placeholder for "${variableName}"${where}: ` +
|
|
206
|
+
`variable is not present in the workflow's runtime environment`,
|
|
207
|
+
);
|
|
208
|
+
this.name = "RuntimePlaceholderResolutionError";
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Strict variant of {@link resolveRuntimePlaceholders}: a placeholder
|
|
214
|
+
* whose key is missing from the runtime environment throws instead of
|
|
215
|
+
* resolving to `""` — a silently-empty credential produces cryptic
|
|
216
|
+
* downstream failures, so declared-value consumers (the run task's env
|
|
217
|
+
* contract) fail fast with the variable named.
|
|
218
|
+
*
|
|
219
|
+
* This runs in activities only — never in the workflow sandbox.
|
|
220
|
+
*/
|
|
221
|
+
export function resolveRuntimePlaceholdersStrict(
|
|
222
|
+
value: string,
|
|
223
|
+
runtimeEnv: Record<string, unknown>,
|
|
224
|
+
context?: string,
|
|
225
|
+
): string {
|
|
226
|
+
return value.replace(
|
|
227
|
+
RUNTIME_PLACEHOLDER_SUB_RE,
|
|
228
|
+
(_match, _ns: string, key: string) => {
|
|
229
|
+
const resolved = runtimeEnv[key];
|
|
230
|
+
if (resolved === undefined) {
|
|
231
|
+
throw new RuntimePlaceholderResolutionError(key, context);
|
|
232
|
+
}
|
|
233
|
+
return String(resolved);
|
|
234
|
+
},
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
|
|
192
238
|
/**
|
|
193
239
|
* Recursively resolves all runtime placeholders in a nested object.
|
|
194
240
|
* Walks maps, arrays, and strings. Non-string leaves pass through.
|
|
@@ -800,6 +800,24 @@ export type WorkflowEventDescriptor =
|
|
|
800
800
|
interface EventBase {
|
|
801
801
|
readonly taskName?: string;
|
|
802
802
|
readonly occurredAt: string;
|
|
803
|
+
/**
|
|
804
|
+
* Workflow-assigned event sequence number, stamped at the emit funnels
|
|
805
|
+
* (engine-core's emitEvents and the agent-call orchestrator's
|
|
806
|
+
* emitProgress) from the workflow-owned monotonic counter. Assigning
|
|
807
|
+
* inside the deterministic sandbox makes the number stable across
|
|
808
|
+
* activity retries and worker restarts, so persistence is idempotent
|
|
809
|
+
* (the store skips already-persisted sequences).
|
|
810
|
+
*
|
|
811
|
+
* A plain `number`, not `bigint`: descriptors cross the
|
|
812
|
+
* workflow→activity boundary through Temporal's JSON payload converter,
|
|
813
|
+
* which cannot serialize BigInt. The emit activity converts to the
|
|
814
|
+
* proto's uint64.
|
|
815
|
+
*
|
|
816
|
+
* Absent only when replaying histories recorded before the
|
|
817
|
+
* "workflow-assigned-event-sequences" patch — the emit activity then
|
|
818
|
+
* falls back to its legacy process-global counter.
|
|
819
|
+
*/
|
|
820
|
+
readonly sequenceNumber?: number;
|
|
803
821
|
}
|
|
804
822
|
|
|
805
823
|
export interface ExecutionStartedEvent extends EventBase {
|
|
@@ -63,6 +63,7 @@ describe("ConnectMcpServerWorkflow", () => {
|
|
|
63
63
|
expect(mockDiscoverActivity).toHaveBeenCalledWith({
|
|
64
64
|
mcpServerId: "mcp-123",
|
|
65
65
|
executionContextId: "ctx-abc",
|
|
66
|
+
executionContextToken: null,
|
|
66
67
|
invokerIdentityAccountId: "user-1",
|
|
67
68
|
});
|
|
68
69
|
|
|
@@ -88,6 +89,30 @@ describe("ConnectMcpServerWorkflow", () => {
|
|
|
88
89
|
expect(mockDiscoverActivity).toHaveBeenCalledWith({
|
|
89
90
|
mcpServerId: "mcp-min",
|
|
90
91
|
executionContextId: null,
|
|
92
|
+
executionContextToken: null,
|
|
93
|
+
invokerIdentityAccountId: null,
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it("forwards the payload-carried EC token to discovery (oss#535)", async () => {
|
|
98
|
+
// The OSS handler mints an execution-scoped token into the workflow
|
|
99
|
+
// input; discovery presents it on the EC read to receive decrypted
|
|
100
|
+
// credentials from the redact-by-default OSS server.
|
|
101
|
+
const { connectMcpServer } = await import("../connect-mcp-server.js");
|
|
102
|
+
|
|
103
|
+
mockDiscoverActivity.mockResolvedValue(makeDiscoveryResult({ tools: [] }));
|
|
104
|
+
mockClassifyActivity.mockResolvedValue([]);
|
|
105
|
+
|
|
106
|
+
await connectMcpServer({
|
|
107
|
+
mcp_server_id: "mcp-tok",
|
|
108
|
+
execution_context_id: "ctx-tok",
|
|
109
|
+
execution_context_token: "scoped-ec-token",
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
expect(mockDiscoverActivity).toHaveBeenCalledWith({
|
|
113
|
+
mcpServerId: "mcp-tok",
|
|
114
|
+
executionContextId: "ctx-tok",
|
|
115
|
+
executionContextToken: "scoped-ec-token",
|
|
91
116
|
invokerIdentityAccountId: null,
|
|
92
117
|
});
|
|
93
118
|
});
|
|
@@ -4,6 +4,8 @@ import type { WorkflowModel } from "../../workflow-engine/types.js";
|
|
|
4
4
|
import type { ExecuteServerlessWorkflowInput } from "../execute-serverless-workflow.js";
|
|
5
5
|
|
|
6
6
|
const mockEvaluateExpressions = vi.fn();
|
|
7
|
+
const mockResetEventSequence = vi.fn();
|
|
8
|
+
const mockEmitWorkflowEvents = vi.fn();
|
|
7
9
|
|
|
8
10
|
vi.mock("@temporalio/workflow", () => ({
|
|
9
11
|
proxyLocalActivities: vi.fn(() => ({
|
|
@@ -12,8 +14,9 @@ vi.mock("@temporalio/workflow", () => ({
|
|
|
12
14
|
input: unknown,
|
|
13
15
|
stateVars: Record<string, unknown>,
|
|
14
16
|
) => mockEvaluateExpressions(exprs, input, stateVars),
|
|
15
|
-
ResetEventSequence:
|
|
16
|
-
EmitWorkflowEvents:
|
|
17
|
+
ResetEventSequence: (executionId: string) => mockResetEventSequence(executionId),
|
|
18
|
+
EmitWorkflowEvents: (executionId: string, events: unknown[], taskStatuses: unknown[]) =>
|
|
19
|
+
mockEmitWorkflowEvents(executionId, events, taskStatuses),
|
|
17
20
|
})),
|
|
18
21
|
proxyActivities: vi.fn(() => ({
|
|
19
22
|
CallHttp: vi.fn(),
|
|
@@ -246,6 +249,69 @@ describe("executeServerlessWorkflow", () => {
|
|
|
246
249
|
});
|
|
247
250
|
});
|
|
248
251
|
|
|
252
|
+
describe("workflow-assigned event sequences", () => {
|
|
253
|
+
interface StampedEvent {
|
|
254
|
+
type: string;
|
|
255
|
+
sequenceNumber?: number;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function emittedEvents(): StampedEvent[] {
|
|
259
|
+
return mockEmitWorkflowEvents.mock.calls.flatMap(call => call[1] as StampedEvent[]);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
const model: WorkflowModel = {
|
|
263
|
+
document: { dsl: "1.0.0", name: "test-sequences" },
|
|
264
|
+
do: [
|
|
265
|
+
{ key: "step1", task: { kind: "set", set: { a: 1 } } },
|
|
266
|
+
{ key: "step2", task: { kind: "set", set: { b: 2 } } },
|
|
267
|
+
],
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
it("stamps a strictly monotonic sequence continuing from the high-water mark", async () => {
|
|
271
|
+
mockResetEventSequence.mockResolvedValue(10);
|
|
272
|
+
|
|
273
|
+
await runWorkflow({
|
|
274
|
+
model,
|
|
275
|
+
workflow_input: null,
|
|
276
|
+
env: {},
|
|
277
|
+
metadata: { execution_id: "wfx-seq-1" },
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
const events = emittedEvents();
|
|
281
|
+
expect(events.length).toBeGreaterThan(0);
|
|
282
|
+
// execution_started, task events, execution_completed — all from one
|
|
283
|
+
// counter, gapless, continuing after the persisted high-water mark.
|
|
284
|
+
const sequences = events.map(e => e.sequenceNumber);
|
|
285
|
+
const expected = Array.from({ length: events.length }, (_, i) => 11 + i);
|
|
286
|
+
expect(sequences).toEqual(expected);
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
it("starts at 1 for a fresh execution (high-water mark 0)", async () => {
|
|
290
|
+
mockResetEventSequence.mockResolvedValue(0);
|
|
291
|
+
|
|
292
|
+
await runWorkflow({
|
|
293
|
+
model,
|
|
294
|
+
workflow_input: null,
|
|
295
|
+
env: {},
|
|
296
|
+
metadata: { execution_id: "wfx-seq-2" },
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
expect(emittedEvents()[0]?.sequenceNumber).toBe(1);
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
it("emits no events without an execution_id (direct invocation, child workflows)", async () => {
|
|
303
|
+
mockResetEventSequence.mockResolvedValue(0);
|
|
304
|
+
|
|
305
|
+
await runWorkflow({
|
|
306
|
+
model,
|
|
307
|
+
workflow_input: null,
|
|
308
|
+
env: {},
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
expect(mockEmitWorkflowEvents).not.toHaveBeenCalled();
|
|
312
|
+
});
|
|
313
|
+
});
|
|
314
|
+
|
|
249
315
|
describe("switch with flow directives", () => {
|
|
250
316
|
it("handles switch-driven branching through the workflow", async () => {
|
|
251
317
|
const model: WorkflowModel = {
|
|
@@ -94,6 +94,15 @@ export interface AgentCallOrchestrationInput {
|
|
|
94
94
|
parentWorkflowId: string;
|
|
95
95
|
taskName: string;
|
|
96
96
|
workflowExecutionId: string;
|
|
97
|
+
/**
|
|
98
|
+
* Allocator for the workflow-owned event sequence counter, shared with
|
|
99
|
+
* engine-core's emit funnel so progress events and task events draw
|
|
100
|
+
* from one monotonic series. Safe to pass as a closure — the
|
|
101
|
+
* orchestrator is a plain function call inside the same workflow run,
|
|
102
|
+
* not a child workflow. Undefined when replaying pre-patch histories
|
|
103
|
+
* (the emit activity then assigns from its legacy counter).
|
|
104
|
+
*/
|
|
105
|
+
nextEventSequence?: () => number;
|
|
97
106
|
}
|
|
98
107
|
|
|
99
108
|
/**
|
|
@@ -318,6 +327,7 @@ async function emitProgress(
|
|
|
318
327
|
type: "agent_call_progress",
|
|
319
328
|
taskName: input.taskName,
|
|
320
329
|
occurredAt: new Date().toISOString(),
|
|
330
|
+
sequenceNumber: input.nextEventSequence?.(),
|
|
321
331
|
childExecutionId: childExecId,
|
|
322
332
|
agentSlug: input.config.agent ?? "",
|
|
323
333
|
agentPhase: progress?.agentPhase ?? 0,
|
|
@@ -41,6 +41,13 @@ import type {
|
|
|
41
41
|
type DiscoverActivities = ReturnType<typeof createDiscoverMcpServerActivities>;
|
|
42
42
|
type ClassifyActivities = ReturnType<typeof createClassifyToolApprovalsActivities>;
|
|
43
43
|
|
|
44
|
+
// Discovery's bounds ladder (issue #239): the activity heartbeats every 15s,
|
|
45
|
+
// so heartbeatTimeout is pure LIVENESS (dead worker/pod detection) — it no
|
|
46
|
+
// longer kills slow-but-alive discoveries. The activity bounds its own WORK
|
|
47
|
+
// with a transport-aware init timeout (30s HTTP / 270s stdio) that fails with
|
|
48
|
+
// an actionable, endpoint-naming error; startToCloseTimeout is the hard cap
|
|
49
|
+
// above both. Keep the ordering: work bound < hard cap, heartbeat interval
|
|
50
|
+
// (15s) < heartbeatTimeout.
|
|
44
51
|
const discover = proxyActivities<DiscoverActivities>({
|
|
45
52
|
startToCloseTimeout: "600s",
|
|
46
53
|
heartbeatTimeout: "60s",
|
|
@@ -194,6 +201,7 @@ export async function connectMcpServer(
|
|
|
194
201
|
const discovery = await discover.DiscoverMcpServerCapabilities({
|
|
195
202
|
mcpServerId: input.mcp_server_id,
|
|
196
203
|
executionContextId: input.execution_context_id ?? null,
|
|
204
|
+
executionContextToken: input.execution_context_token ?? null,
|
|
197
205
|
invokerIdentityAccountId: input.invoker_identity_account_id ?? null,
|
|
198
206
|
});
|
|
199
207
|
|
|
@@ -281,6 +289,7 @@ export async function discoverMcpServerLegacy(
|
|
|
281
289
|
const discovery = await discover.DiscoverMcpServerCapabilities({
|
|
282
290
|
mcpServerId: input.mcp_server_id,
|
|
283
291
|
executionContextId: input.execution_context_id ?? null,
|
|
292
|
+
executionContextToken: input.execution_context_token ?? null,
|
|
284
293
|
invokerIdentityAccountId: input.invoker_identity_account_id ?? null,
|
|
285
294
|
});
|
|
286
295
|
|