@stigmer/runner 3.29.0 → 3.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/dist/.build-fingerprint +1 -1
  2. package/dist/activities/call-eval.d.ts +16 -0
  3. package/dist/activities/call-eval.js +54 -1
  4. package/dist/activities/call-eval.js.map +1 -1
  5. package/dist/activities/hydrate-workflow-execution.d.ts +1 -1
  6. package/dist/activities/workflow-event-activities.d.ts +2 -2
  7. package/dist/activities/workflow-event-activities.js +2 -2
  8. package/dist/harness/transcript/builder.d.ts +3 -2
  9. package/dist/harness/transcript/builder.js +28 -8
  10. package/dist/harness/transcript/builder.js.map +1 -1
  11. package/dist/shared/approval-policy.d.ts +5 -0
  12. package/dist/shared/approval-policy.js +8 -0
  13. package/dist/shared/approval-policy.js.map +1 -1
  14. package/dist/shared/args-preview.d.ts +12 -5
  15. package/dist/shared/args-preview.js +12 -5
  16. package/dist/shared/args-preview.js.map +1 -1
  17. package/dist/worker.d.ts +2 -4
  18. package/dist/worker.js +2 -4
  19. package/dist/worker.js.map +1 -1
  20. package/dist/workflow-engine/tasks/run.d.ts +13 -1
  21. package/dist/workflow-engine/tasks/run.js +16 -1
  22. package/dist/workflow-engine/tasks/run.js.map +1 -1
  23. package/dist/workflows/call-agent-orchestrator.d.ts +1 -1
  24. package/dist/workflows/call-agent-orchestrator.js +1 -1
  25. package/dist/workflows/engine-core.d.ts +28 -8
  26. package/dist/workflows/engine-core.js +9 -7
  27. package/dist/workflows/engine-core.js.map +1 -1
  28. package/dist/workflows/index.d.ts +22 -7
  29. package/dist/workflows/index.js +22 -7
  30. package/dist/workflows/index.js.map +1 -1
  31. package/dist/workflows/workflow-signals.d.ts +3 -3
  32. package/dist/workflows/workflow-signals.js +3 -3
  33. package/package.json +5 -5
  34. package/src/__test-utils__/workflows/index.ts +14 -0
  35. package/src/__test-utils__/workflows/inline-model.ts +32 -0
  36. package/src/__tests__/dispatch-surface-e2e.test.ts +212 -0
  37. package/src/__tests__/golden-e2e.test.ts +4 -3
  38. package/src/__tests__/history-encryption-e2e.test.ts +1 -1
  39. package/src/activities/__tests__/call-eval.test.ts +115 -0
  40. package/src/activities/call-eval.ts +59 -1
  41. package/src/activities/hydrate-workflow-execution.ts +1 -1
  42. package/src/activities/workflow-event-activities.ts +2 -2
  43. package/src/harness/transcript/__tests__/builder.test.ts +56 -1
  44. package/src/harness/transcript/builder.ts +29 -8
  45. package/src/shared/__tests__/approval-policy.test.ts +10 -0
  46. package/src/shared/__tests__/args-preview.test.ts +50 -1
  47. package/src/shared/approval-policy.ts +7 -0
  48. package/src/shared/args-preview.ts +12 -5
  49. package/src/worker.ts +2 -4
  50. package/src/workflow-engine/__tests__/tasks/run.test.ts +25 -0
  51. package/src/workflow-engine/tasks/run.ts +19 -1
  52. package/src/workflows/__tests__/barrel.test.ts +41 -0
  53. package/src/workflows/__tests__/{execute-serverless-workflow.test.ts → engine-inline-model.test.ts} +16 -4
  54. package/src/workflows/call-agent-orchestrator.ts +1 -1
  55. package/src/workflows/engine-core.ts +34 -9
  56. package/src/workflows/index.ts +22 -10
  57. package/src/workflows/workflow-signals.ts +3 -3
  58. package/dist/workflows/execute-serverless-workflow.d.ts +0 -32
  59. package/dist/workflows/execute-serverless-workflow.js +0 -36
  60. package/dist/workflows/execute-serverless-workflow.js.map +0 -1
  61. package/src/workflows/execute-serverless-workflow.ts +0 -60
@@ -0,0 +1,41 @@
1
+ /**
2
+ * The fence on what a runner registers. Every export of `workflows/index.ts`
3
+ * is a Temporal workflow type on every worker root, and anyone who can
4
+ * reach Temporal can start any of them on a runner's queue. So the set is
5
+ * pinned exactly: the three types the server starts, each by id, none of
6
+ * which takes a model to run. A new export fails here until this list, and
7
+ * the review that comes with changing it, admits it.
8
+ *
9
+ * It also pins the link to the `run.workflow` refusal
10
+ * (`workflow-engine/tasks/run.ts`): every registered type carries
11
+ * `PLATFORM_WORKFLOW_TYPE_PREFIX`, so a workflow can never name one as its
12
+ * child.
13
+ */
14
+
15
+ import { describe, expect, it } from "vitest";
16
+
17
+ import * as barrel from "../index.js";
18
+ import { EXECUTE_FROM_EXECUTION_WORKFLOW_TYPE } from "../execute-from-execution.js";
19
+ import { PLATFORM_WORKFLOW_TYPE_PREFIX } from "../../workflow-engine/tasks/run.js";
20
+
21
+ describe("the registered workflow types", () => {
22
+ it("are exactly the types the server starts", () => {
23
+ expect(Object.keys(barrel).sort()).toEqual(
24
+ [
25
+ "stigmer/mcp-server/connect",
26
+ "stigmer/mcp-server/discover",
27
+ EXECUTE_FROM_EXECUTION_WORKFLOW_TYPE,
28
+ ].sort(),
29
+ );
30
+ });
31
+
32
+ it("include no type that runs a model handed to it", () => {
33
+ expect(Object.keys(barrel)).not.toContain("stigmer/workflow/execute");
34
+ });
35
+
36
+ it("all carry the platform prefix the run.workflow refusal checks", () => {
37
+ for (const type of Object.keys(barrel)) {
38
+ expect(type.startsWith(PLATFORM_WORKFLOW_TYPE_PREFIX), type).toBe(true);
39
+ }
40
+ });
41
+ });
@@ -1,7 +1,19 @@
1
+ /**
2
+ * The workflow engine (`engine-core.ts`) driven with a materialized model,
3
+ * through the test harness's inline entry
4
+ * (`src/__test-utils__/workflows/inline-model.ts`), with the Temporal
5
+ * workflow API mocked. It pins the engine's behaviour: task output,
6
+ * workflow-level `input.from` and `output.as`, expression evaluation
7
+ * through the local activity, error handling, event sequences and flow
8
+ * directives. Production reaches the same engine only through the
9
+ * hydration workflow; `barrel.test.ts` pins that no production type takes
10
+ * a model from its caller.
11
+ */
12
+
1
13
  import { describe, it, expect, vi, beforeEach } from "vitest";
2
14
  import { evaluateExpressionBatch } from "../../workflow-engine/expression.js";
3
15
  import type { WorkflowModel } from "../../workflow-engine/types.js";
4
- import type { ExecuteServerlessWorkflowInput } from "../execute-serverless-workflow.js";
16
+ import type { ExecuteServerlessWorkflowInput } from "../engine-core.js";
5
17
 
6
18
  const mockEvaluateExpressions = vi.fn();
7
19
  const mockResetEventSequence = vi.fn();
@@ -51,7 +63,7 @@ vi.mock("@temporalio/workflow", () => ({
51
63
  isCancellation: vi.fn(() => false),
52
64
  }));
53
65
 
54
- describe("executeServerlessWorkflow", () => {
66
+ describe("the engine, on a materialized model", () => {
55
67
  beforeEach(() => {
56
68
  vi.clearAllMocks();
57
69
  mockEvaluateExpressions.mockImplementation(
@@ -60,8 +72,8 @@ describe("executeServerlessWorkflow", () => {
60
72
  });
61
73
 
62
74
  async function runWorkflow(input: ExecuteServerlessWorkflowInput) {
63
- const { executeServerlessWorkflow } = await import("../execute-serverless-workflow.js");
64
- return executeServerlessWorkflow(input);
75
+ const { executeInlineModel } = await import("../../__test-utils__/workflows/inline-model.js");
76
+ return executeInlineModel(input);
65
77
  }
66
78
 
67
79
  describe("basic workflow execution", () => {
@@ -10,7 +10,7 @@
10
10
  *
11
11
  * The workflow engine's CallAgentTaskBuilder (workflow-engine/tasks/
12
12
  * call-agent.ts) calls `ctx.callAgent()`, which is wired to
13
- * `orchestrateAgentCall()` in execute-serverless-workflow.ts.
13
+ * `orchestrateAgentCall()` in engine-core.ts.
14
14
  *
15
15
  * SANDBOX RULES: Only @temporalio/workflow imports, type-only imports,
16
16
  * and pure logic. No Node.js built-ins.
@@ -2,10 +2,13 @@
2
2
  * Shared workflow engine core — runs CNCF Serverless Workflow DSL
3
3
  * tasks inside the Temporal deterministic sandbox.
4
4
  *
5
- * Extracted from execute-serverless-workflow.ts so that both the
6
- * direct workflow ("stigmer/workflow/execute") and the hydration
7
- * wrapper ("stigmer/workflow/execute-from-execution") can share the
8
- * engine without code duplication.
5
+ * The engine runs a fully materialized {@link ExecuteServerlessWorkflowInput}
6
+ * and owns that type. Production reaches it only through the hydration
7
+ * workflow ("stigmer/workflow/execute-from-execution"), which reads the
8
+ * model, env and input back from the server by id; no registered workflow
9
+ * accepts a materialized model from its caller (see `index.ts`). The test
10
+ * harness runs goldens through an inline entry of its own
11
+ * (`src/__test-utils__/workflows/`).
9
12
  *
10
13
  * SANDBOX RULES: This file runs inside the Temporal deterministic V8
11
14
  * isolate. No Node.js built-ins (crypto, fs, net), no non-deterministic
@@ -46,10 +49,9 @@ import type {
46
49
  HumanInputExecutionConfig,
47
50
  TaskExecutionContext,
48
51
  WorkflowEventDescriptor,
52
+ WorkflowModel,
49
53
  } from "../workflow-engine/types.js";
50
54
 
51
- import type { ExecuteServerlessWorkflowInput } from "./execute-serverless-workflow.js";
52
-
53
55
  // ─────────────────────────────────────────────────────────────────────────────
54
56
  // Activity Proxies (module-level singletons — shared across all workflow
55
57
  // invocations within the same worker)
@@ -132,6 +134,30 @@ const promoteProxy = proxyLocalActivities<PromoteActivities>({
132
134
  },
133
135
  });
134
136
 
137
+ // ─────────────────────────────────────────────────────────────────────────────
138
+ // Engine Input
139
+ // ─────────────────────────────────────────────────────────────────────────────
140
+
141
+ /**
142
+ * What the engine runs: a parsed model, the merged env and the workflow
143
+ * input. Built by the hydration activity from what the server holds
144
+ * (`activities/hydrate-workflow-execution.ts`), never taken from a caller.
145
+ */
146
+ export interface ExecuteServerlessWorkflowInput {
147
+ model: WorkflowModel;
148
+ workflow_input: unknown;
149
+ env: Record<string, unknown>;
150
+ metadata?: ExecutionMetadata;
151
+ }
152
+
153
+ export interface ExecutionMetadata {
154
+ execution_id?: string;
155
+ workflow_id?: string;
156
+ workflow_instance_id?: string;
157
+ org_id?: string;
158
+ execution_target?: number;
159
+ }
160
+
135
161
  // ─────────────────────────────────────────────────────────────────────────────
136
162
  // Engine Core
137
163
  // ─────────────────────────────────────────────────────────────────────────────
@@ -149,9 +175,8 @@ export interface RunWorkflowEngineOptions {
149
175
  * executes all tasks via {@link executeDoTasks}, and returns the final
150
176
  * output.
151
177
  *
152
- * Called by both:
153
- * - `executeServerlessWorkflow` (direct invocation with pre-materialized input)
154
- * - `executeFromExecution` (wrapper that hydrates from slim IDs first)
178
+ * Called by `executeFromExecution` once it has hydrated the input from
179
+ * slim ids, and by the test harness's inline entry.
155
180
  *
156
181
  * @param options.checkPause Optional pause yield point callback. When
157
182
  * provided, the engine calls this between tasks and allows the
@@ -1,13 +1,29 @@
1
1
  /**
2
- * Workflow barrel file — the entry point for Temporal's workflow bundler.
2
+ * Workflow barrel file — the entry point for Temporal's workflow bundler,
3
+ * and the complete list of workflow types a runner registers.
3
4
  *
4
5
  * Re-exports workflow functions with the exact Temporal workflow type
5
- * names that the Java/Go backend uses to start them. The Temporal TS
6
- * SDK derives the workflow type from the export name of the module
7
- * passed to `workflowsPath`.
6
+ * names that the server uses to start them. The Temporal TS SDK derives
7
+ * the workflow type from the export name of the module passed to
8
+ * `workflowsPath`, so every export here is a registered type on every
9
+ * worker root: the static worker, the manager and pool workers, and the
10
+ * pre-built bundle (`scripts/bundle-slim.mjs`).
8
11
  *
9
- * The Java backend starts workflows via:
10
- * workflowClient.newUntypedWorkflowStub("stigmer/mcp-server/connect", ...)
12
+ * THE RULE: every export is a type the server starts, and each takes ids
13
+ * that the runner reads back from the server, never a model to run.
14
+ * Anyone who can reach Temporal can start any type registered here on a
15
+ * runner's queue, so a new export is a new door and is reviewed as a
16
+ * wire change. `__tests__/barrel.test.ts` pins the exact set. Tests that
17
+ * hand the engine a model directly use the test barrel
18
+ * (`src/__test-utils__/workflows/index.ts`).
19
+ *
20
+ * The types and their starters:
21
+ * - "stigmer/mcp-server/connect" and "stigmer/mcp-server/discover": the
22
+ * server's MCP connect lane (`temporal/mcpserver/names.ts` in the
23
+ * server), by MCP server id.
24
+ * - "stigmer/workflow/execute-from-execution": the server's workflow
25
+ * execution orchestrator (`temporal/workflowexecution/names.ts`), by
26
+ * execution id; it hydrates the model from the server.
11
27
  *
12
28
  * ES2022 arbitrary module export names (`export { fn as "..." }`) let
13
29
  * us map TypeScript function names to the slash-delimited Temporal
@@ -26,10 +42,6 @@ export {
26
42
  discoverMcpServerLegacy as "stigmer/mcp-server/discover",
27
43
  } from "./connect-mcp-server.js";
28
44
 
29
- export {
30
- executeServerlessWorkflow as "stigmer/workflow/execute",
31
- } from "./execute-serverless-workflow.js";
32
-
33
45
  export {
34
46
  executeFromExecution as "stigmer/workflow/execute-from-execution",
35
47
  } from "./execute-from-execution.js";
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * Shared pause/resume signal definitions and handler setup for
3
- * workflow execution. Used by both the hydration wrapper
4
- * ("stigmer/workflow/execute-from-execution") and the direct
5
- * invocation path ("stigmer/workflow/execute").
3
+ * workflow execution. Used by the hydration wrapper
4
+ * ("stigmer/workflow/execute-from-execution") and by the test harness's
5
+ * inline entry (`src/__test-utils__/workflows/inline-model.ts`).
6
6
  *
7
7
  * The Java/Go orchestrators forward pause and resume signals to
8
8
  * the child workflow. The engine checks a `checkPause` callback
@@ -1,32 +0,0 @@
1
- /**
2
- * Temporal workflow for executing CNCF Serverless Workflow definitions.
3
- *
4
- * Workflow type: "stigmer/workflow/execute"
5
- *
6
- * Accepts a fully materialized {@link ExecuteServerlessWorkflowInput}
7
- * (parsed WorkflowModel, merged env, workflow_input) and runs the
8
- * engine. Callers that already have the materialized input use this
9
- * workflow directly. The hydration wrapper workflow
10
- * ("stigmer/workflow/execute-from-execution") handles the case where
11
- * only slim IDs are available.
12
- *
13
- * SANDBOX RULES: This file runs inside the Temporal deterministic V8
14
- * isolate. No Node.js built-ins (crypto, fs, net), no non-deterministic
15
- * operations, no side-effecting imports. Only @temporalio/workflow APIs,
16
- * type-only imports, and pure JS/TS logic.
17
- */
18
- import type { WorkflowModel } from "../workflow-engine/types.js";
19
- export interface ExecuteServerlessWorkflowInput {
20
- model: WorkflowModel;
21
- workflow_input: unknown;
22
- env: Record<string, unknown>;
23
- metadata?: ExecutionMetadata;
24
- }
25
- export interface ExecutionMetadata {
26
- execution_id?: string;
27
- workflow_id?: string;
28
- workflow_instance_id?: string;
29
- org_id?: string;
30
- execution_target?: number;
31
- }
32
- export declare function executeServerlessWorkflow(input: ExecuteServerlessWorkflowInput): Promise<unknown>;
@@ -1,36 +0,0 @@
1
- /**
2
- * Temporal workflow for executing CNCF Serverless Workflow definitions.
3
- *
4
- * Workflow type: "stigmer/workflow/execute"
5
- *
6
- * Accepts a fully materialized {@link ExecuteServerlessWorkflowInput}
7
- * (parsed WorkflowModel, merged env, workflow_input) and runs the
8
- * engine. Callers that already have the materialized input use this
9
- * workflow directly. The hydration wrapper workflow
10
- * ("stigmer/workflow/execute-from-execution") handles the case where
11
- * only slim IDs are available.
12
- *
13
- * SANDBOX RULES: This file runs inside the Temporal deterministic V8
14
- * isolate. No Node.js built-ins (crypto, fs, net), no non-deterministic
15
- * operations, no side-effecting imports. Only @temporalio/workflow APIs,
16
- * type-only imports, and pure JS/TS logic.
17
- */
18
- import { isCancellation } from "@temporalio/workflow";
19
- import { runWorkflowEngine } from "./engine-core.js";
20
- import { setupPauseResumeHandlers } from "./workflow-signals.js";
21
- // ─────────────────────────────────────────────────────────────────────────────
22
- // Workflow Function
23
- // ─────────────────────────────────────────────────────────────────────────────
24
- export async function executeServerlessWorkflow(input) {
25
- const { checkPause } = setupPauseResumeHandlers();
26
- try {
27
- return await runWorkflowEngine(input, { checkPause });
28
- }
29
- catch (err) {
30
- if (isCancellation(err)) {
31
- // Let CancelledFailure propagate — parent handles cleanup
32
- }
33
- throw err;
34
- }
35
- }
36
- //# sourceMappingURL=execute-serverless-workflow.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"execute-serverless-workflow.js","sourceRoot":"","sources":["../../src/workflows/execute-serverless-workflow.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AAqBjE,gFAAgF;AAChF,oBAAoB;AACpB,gFAAgF;AAEhF,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,KAAqC;IAErC,MAAM,EAAE,UAAU,EAAE,GAAG,wBAAwB,EAAE,CAAC;IAElD,IAAI,CAAC;QACH,OAAO,MAAM,iBAAiB,CAAC,KAAK,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC;IACxD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC;YACxB,0DAA0D;QAC5D,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC"}
@@ -1,60 +0,0 @@
1
- /**
2
- * Temporal workflow for executing CNCF Serverless Workflow definitions.
3
- *
4
- * Workflow type: "stigmer/workflow/execute"
5
- *
6
- * Accepts a fully materialized {@link ExecuteServerlessWorkflowInput}
7
- * (parsed WorkflowModel, merged env, workflow_input) and runs the
8
- * engine. Callers that already have the materialized input use this
9
- * workflow directly. The hydration wrapper workflow
10
- * ("stigmer/workflow/execute-from-execution") handles the case where
11
- * only slim IDs are available.
12
- *
13
- * SANDBOX RULES: This file runs inside the Temporal deterministic V8
14
- * isolate. No Node.js built-ins (crypto, fs, net), no non-deterministic
15
- * operations, no side-effecting imports. Only @temporalio/workflow APIs,
16
- * type-only imports, and pure JS/TS logic.
17
- */
18
-
19
- import { isCancellation } from "@temporalio/workflow";
20
- import type { WorkflowModel } from "../workflow-engine/types.js";
21
- import { runWorkflowEngine } from "./engine-core.js";
22
- import { setupPauseResumeHandlers } from "./workflow-signals.js";
23
-
24
- // ─────────────────────────────────────────────────────────────────────────────
25
- // Workflow Input/Output Types
26
- // ─────────────────────────────────────────────────────────────────────────────
27
-
28
- export interface ExecuteServerlessWorkflowInput {
29
- model: WorkflowModel;
30
- workflow_input: unknown;
31
- env: Record<string, unknown>;
32
- metadata?: ExecutionMetadata;
33
- }
34
-
35
- export interface ExecutionMetadata {
36
- execution_id?: string;
37
- workflow_id?: string;
38
- workflow_instance_id?: string;
39
- org_id?: string;
40
- execution_target?: number;
41
- }
42
-
43
- // ─────────────────────────────────────────────────────────────────────────────
44
- // Workflow Function
45
- // ─────────────────────────────────────────────────────────────────────────────
46
-
47
- export async function executeServerlessWorkflow(
48
- input: ExecuteServerlessWorkflowInput,
49
- ): Promise<unknown> {
50
- const { checkPause } = setupPauseResumeHandlers();
51
-
52
- try {
53
- return await runWorkflowEngine(input, { checkPause });
54
- } catch (err) {
55
- if (isCancellation(err)) {
56
- // Let CancelledFailure propagate — parent handles cleanup
57
- }
58
- throw err;
59
- }
60
- }