@automatalabs/workflows 0.6.2 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -214,6 +214,18 @@ above. `WorkflowManagerOptions` lets you set a default `agent`, `concurrency`, `
214
214
  `loadSavedWorkflow` resolver (enables nested `workflow('name')`), and per-agent timeout/retry
215
215
  defaults.
216
216
 
217
+ Manager events are Node `EventEmitter` notifications: `agentStart`, `agentEnd`, `agentHistory`,
218
+ `tokenUsage`, `log`, `phase`, `complete`, `paused`, `resumed`, `stopped`, `error`, and
219
+ `agentEvent`. `agentEvent` forwards the live ACP stream from an ACP-capable runner with `name`,
220
+ `event`, and the runner context fields (`runId`, `label`, `sessionId`, `backendId`) when the event
221
+ carries them; `backend_error` is connection-scoped and carries `backendId` only. ACP
222
+ `session/update` traffic is emitted once under its inner discriminant name, while
223
+ permission/session/raw/backend events keep their runner names.
224
+
225
+ ```ts
226
+ manager.on("agentEvent", ({ runId, label, name }) => console.error(runId, label, name));
227
+ ```
228
+
217
229
  ### d) Bring your own backend — implement the `AgentRunner` seam
218
230
 
219
231
  `AgentRunner` is the single, frozen coupling point between the engine and any backend. Implement
@@ -283,9 +295,10 @@ await runner.dispose();
283
295
  | event | payload |
284
296
  |-------|---------|
285
297
  | `session_update` | `{ update }` — catch-all for **every** update, regardless of kind |
286
- | `permission_request` | `{ request, outcome }` — a tool permission the runner auto-answered |
298
+ | `permission_pending` | `{ request }` — resolver-only; emitted after the request is parked and before the resolver is invoked |
299
+ | `permission_request` | `{ request, outcome }` — the final permission outcome returned to the agent |
287
300
  | `raw_message` | `{ method, message }` — a vendor extension notification (e.g. Claude `_claude/sdkMessage`) |
288
- | `session_open` / `session_close` | a session opened / was released on a pooled connection |
301
+ | `session_open` / `session_close` | an ACP session opened / was released |
289
302
  | `backend_error` | `{ backendId, error }` — a pooled backend process crashed |
290
303
 
291
304
  **Context envelope.** A pooled runner multiplexes many concurrent runs over one process, so every
@@ -295,10 +308,11 @@ event (except `backend_error`) carries `{ sessionId, backendId, label?, runId? }
295
308
  **Best-effort.** Listeners are observers: a throwing listener is isolated and never breaks the run,
296
309
  the update drain, or sibling listeners.
297
310
 
298
- **With `runDynamicWorkflow` / `WorkflowManager`.** Construct the runner yourself, subscribe, then
299
- inject it: `runDynamicWorkflow(script, { runner })` or `new WorkflowManager({ agent: runner })`.
300
- Every `agent()` call in the script then streams through your listeners (filter by `label` to tell
301
- agents apart).
311
+ **With `runDynamicWorkflow` / `WorkflowManager`.** Subscribe at the manager layer:
312
+ `manager.on("agentEvent", ({ runId, label, name, event }) => …)`. Every `agent()` call in the
313
+ script then streams live ACP events through the manager; ACP `session/update` traffic is forwarded
314
+ once under `name = event.sessionUpdate`, so hosts do not receive both the catch-all and the
315
+ per-discriminant runner event.
302
316
 
303
317
  ---
304
318
 
@@ -406,21 +420,30 @@ WorkflowManager, // stateful / resumable run manager
406
420
  // ── ACP backend ──
407
421
  createAcpRunner, // () => AcpAgentRunner (the default AgentRunner; has .on(...) events)
408
422
  AcpAgentRunner, // class — implements AgentRunner over ACP
423
+ InteractiveSession, // held-open multi-turn ACP session returned by openSession()
409
424
  selectBackend, // pick Claude vs Codex from a model/tier spec
410
425
  ClaudeBackend, CodexBackend, // the concrete backends
426
+ clientCapabilitiesFor, adaptPromptContent,
411
427
  toJsonSchema, toStrictJsonSchema,
412
428
  TypedEventEmitter, // the tiny typed emitter backing runner.on(...)
413
429
 
414
430
  // ── Errors ──
415
431
  WorkflowError, WorkflowErrorCode, isWorkflowError, isProviderUsageLimit,
416
432
 
433
+ // ── Persistence paths ──
434
+ AGENTPRISM_PERSISTENCE_ROOT_ENV,
435
+
417
436
  // ── Types ──
418
437
  RunDynamicWorkflowOptions, WorkflowRunOptions, AgentOptions, ExecOptions,
419
438
  WorkflowManagerOptions, CheckpointOptions, WorkflowRunResult, WorkflowSnapshot,
439
+ WorkflowPathOptions, RunPersistenceOptions,
420
440
  AcpPoolOptions, AgentRunner, RunOptions, AgentResult, AgentUsage, JournalEntry,
441
+ InteractiveSessionOptions, InteractiveTurn, PermissionResolver,
442
+ ClientHandlers, FsHandlers, TerminalHandlers, AcpSessionContext, NegotiatedCapabilities,
421
443
  // ACP events: the runner.on(...) surface
422
444
  AcpRunnerEventMap, AcpEventName, AcpEventListener, AcpEventContext,
423
- AcpSessionUpdate, AcpUpdateKind, AcpPermissionEvent, AcpRawMessageEvent, AcpBackendErrorEvent,
445
+ AcpSessionUpdate, AcpUpdateKind, AcpPermissionPendingEvent, AcpPermissionEvent,
446
+ AcpRawMessageEvent, AcpBackendErrorEvent,
424
447
  ```
425
448
 
426
449
  (The DSL globals — `agent`, `parallel`, `pipeline`, … — are **not** exported; they are realm
package/dist/index.d.ts CHANGED
@@ -1,14 +1,62 @@
1
- import type { ExecOptions } from "@automatalabs/workflow-engine";
1
+ import { WorkflowManager as EngineWorkflowManager } from "@automatalabs/workflow-engine";
2
+ import type { AcpEventName, AcpRunnerEventMap } from "@automatalabs/acp-agents";
3
+ import type { ExecOptions, WorkflowManagerOptions } from "@automatalabs/workflow-engine";
2
4
  import type { AgentRunner, WorkflowBackendConfig, WorkflowRunResult } from "@automatalabs/shared-types";
3
- export { runWorkflow, parseWorkflowScript, WorkflowManager } from "@automatalabs/workflow-engine";
4
- export type { WorkflowRunOptions, AgentOptions, ExecOptions, WorkflowManagerOptions, CheckpointOptions, WorkflowRunResult, WorkflowSnapshot, } from "@automatalabs/workflow-engine";
5
- export { WorkflowError, WorkflowErrorCode, isWorkflowError, isProviderUsageLimit, } from "@automatalabs/workflow-engine";
6
- export { createAcpRunner, AcpAgentRunner, selectBackend, ClaudeBackend, CodexBackend, CustomAcpBackend, resolveBackendRegistry, BACKENDS_ENV, toJsonSchema, toStrictJsonSchema, } from "@automatalabs/acp-agents";
7
- export type { AcpPoolOptions, AcpRunnerOptions, BackendRegistry, CustomBackendConfig, RegisteredBackend, } from "@automatalabs/acp-agents";
5
+ export { runWorkflow, parseWorkflowScript } from "@automatalabs/workflow-engine";
6
+ export type { WorkflowRunOptions, AgentOptions, ExecOptions, WorkflowManagerOptions, CheckpointOptions, WorkflowRunResult, WorkflowSnapshot, WorkflowPathOptions, RunPersistenceOptions, } from "@automatalabs/workflow-engine";
7
+ export { AGENTPRISM_PERSISTENCE_ROOT_ENV, WorkflowError, WorkflowErrorCode, isWorkflowError, isProviderUsageLimit, } from "@automatalabs/workflow-engine";
8
+ export { createAcpRunner, AcpAgentRunner, InteractiveSession, selectBackend, ClaudeBackend, CodexBackend, CustomAcpBackend, clientCapabilitiesFor, adaptPromptContent, resolveBackendRegistry, BACKENDS_ENV, toJsonSchema, toStrictJsonSchema, } from "@automatalabs/acp-agents";
9
+ export type { AcpPoolOptions, AcpRunnerOptions, InteractiveSessionOptions, InteractiveTurn, BackendRegistry, CustomBackendConfig, RegisteredBackend, ClientHandlers, FsHandlers, TerminalHandlers, AcpSessionContext, NegotiatedCapabilities, PermissionResolver, } from "@automatalabs/acp-agents";
8
10
  export { TypedEventEmitter } from "@automatalabs/acp-agents";
9
- export type { AcpRunnerEventMap, AcpEventName, AcpEventListener, AcpEventContext, AcpSessionUpdate, AcpUpdateKind, AcpPermissionEvent, AcpRawMessageEvent, AcpBackendErrorEvent, } from "@automatalabs/acp-agents";
11
+ export type { AcpRunnerEventMap, AcpEventName, AcpEventListener, AcpEventContext, AcpSessionUpdate, AcpUpdateKind, AcpPermissionPendingEvent, AcpPermissionEvent, AcpRawMessageEvent, AcpBackendErrorEvent, } from "@automatalabs/acp-agents";
10
12
  export type { AgentRunner, RunOptions, AgentResult, AgentUsage } from "@automatalabs/shared-types";
11
13
  export type { JournalEntry, WorkflowBackendConfig, WorkflowMeta } from "@automatalabs/shared-types";
14
+ type ContextProperty<T, K extends PropertyKey> = K extends keyof T ? T[K] : never;
15
+ type OptionalContextProperty<T, K extends PropertyKey> = K extends keyof T ? T[K] : undefined;
16
+ /** Payload of `WorkflowManager`'s `agentEvent` observer. `event` is the verbatim runner event
17
+ * payload; the top-level envelope repeats the ACP context fields hosts filter on. `backend_error`
18
+ * is connection-scoped in acp-agents and therefore has no session/run context to repeat. */
19
+ type AgentEventPayloadMap = {
20
+ [K in AcpEventName]: {
21
+ name: K;
22
+ event: AcpRunnerEventMap[K];
23
+ backendId: ContextProperty<AcpRunnerEventMap[K], "backendId">;
24
+ } & ("sessionId" extends keyof AcpRunnerEventMap[K] ? {
25
+ sessionId: ContextProperty<AcpRunnerEventMap[K], "sessionId">;
26
+ } : {
27
+ sessionId?: undefined;
28
+ }) & {
29
+ label?: OptionalContextProperty<AcpRunnerEventMap[K], "label">;
30
+ runId?: OptionalContextProperty<AcpRunnerEventMap[K], "runId">;
31
+ };
32
+ };
33
+ export type AgentEventPayload<K extends AcpEventName = AcpEventName> = AgentEventPayloadMap[K];
34
+ /**
35
+ * Stateful workflow manager exported by the SDK facade. It is the workflow-engine manager plus
36
+ * ONE composition-root bridge for ACP-capable runners: when the injected AgentRunner also exposes
37
+ * the acp-agents `.on(name, listener)` bus, the manager forwards that live stream as `agentEvent`.
38
+ *
39
+ * The engine package stays backend-agnostic; this facade already owns the ACP default runner and
40
+ * ACP event types, so the bridge belongs here. Forwarding is OBSERVABILITY ONLY: manager
41
+ * `agentEvent` listeners are isolated from each other and from the run, and `dispose()` removes
42
+ * only the manager's runner subscriptions (runner process ownership stays with the caller).
43
+ */
44
+ export declare class WorkflowManager extends EngineWorkflowManager {
45
+ private readonly acpBridges;
46
+ constructor(options?: WorkflowManagerOptions);
47
+ startInBackground(script: string, args?: unknown, exec?: ExecOptions): {
48
+ runId: string;
49
+ promise: Promise<WorkflowRunResult>;
50
+ };
51
+ runSync(script: string, args?: unknown, exec?: ExecOptions): Promise<WorkflowRunResult>;
52
+ resume(runId: string, exec?: ExecOptions): Promise<boolean>;
53
+ /** Detach manager-owned ACP event subscriptions. The manager does NOT dispose the runner: the
54
+ * caller may share one runner across managers or own its process lifetime explicitly. */
55
+ dispose(): void;
56
+ /** Node-style alias for hosts that tear down managers through close hooks. */
57
+ close(): void;
58
+ private acquireAcpRunnerBridge;
59
+ }
12
60
  /**
13
61
  * Approval policy for SCRIPT-DECLARED custom ACP backends (`meta.backends`). Script backends
14
62
  * spawn arbitrary commands on this machine, so they are INERT unless the embedder approves
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,KAAK,EAAE,WAAW,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAIxG,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAClG,YAAY,EACV,kBAAkB,EAClB,YAAY,EACZ,WAAW,EACX,sBAAsB,EACtB,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,eAAe,EACf,oBAAoB,GACrB,MAAM,+BAA+B,CAAC;AAOvC,OAAO,EACL,eAAe,EACf,cAAc,EACd,aAAa,EACb,aAAa,EACb,YAAY,EACZ,gBAAgB,EAChB,sBAAsB,EACtB,YAAY,EACZ,YAAY,EACZ,kBAAkB,GACnB,MAAM,0BAA0B,CAAC;AAClC,YAAY,EACV,cAAc,EACd,gBAAgB,EAChB,eAAe,EACf,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,0BAA0B,CAAC;AAMlC,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,YAAY,EACV,iBAAiB,EACjB,YAAY,EACZ,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,kBAAkB,EAClB,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,0BAA0B,CAAC;AAIlC,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACnG,YAAY,EAAE,YAAY,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAEpG;;;;;;;;GAQG;AACH,MAAM,MAAM,qBAAqB,GAC7B,OAAO,GACP,CAAC,CAAC,OAAO,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,qBAAqB,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;AAExF,8CAA8C;AAC9C,MAAM,WAAW,yBAAyB;IACxC;;;;OAIG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,+EAA+E;IAC/E,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,kGAAkG;IAClG,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,+FAA+F;IAC/F,mBAAmB,CAAC,EAAE,qBAAqB,CAAC;CAC7C;AAED;;;;;;;;;GASG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,MAAM,EACd,IAAI,GAAE,yBAA8B,GACnC,OAAO,CAAC,iBAAiB,CAAC,CAe5B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,31 +1,152 @@
1
1
  /// <reference path="./dsl.d.ts" />
2
2
  // @automatalabs/workflows — the importable SDK for the AgentPrism dynamic-workflow
3
- // orchestrator. A THIN FACADE re-export barrel: it owns NO logic of its own, it
4
- // re-exports the clean public surface of the three engine packages and adds ONE
5
- // convenience helper (`runDynamicWorkflow`) that defaults the AgentRunner seam to the
6
- // ACP backend. It is SEPARATE from @automatalabs/mcp-server (the stdio MCP server) and
7
- // stays a PURE library — it pulls in neither @modelcontextprotocol/sdk nor zod.
3
+ // orchestrator. A FACADE re-export barrel: it re-exports the clean public surface of
4
+ // the three engine packages, adds the SDK-level WorkflowManager ACP-event bridge, and
5
+ // adds ONE convenience helper (`runDynamicWorkflow`) that defaults the AgentRunner seam
6
+ // to the ACP backend. It is SEPARATE from @automatalabs/mcp-server (the stdio MCP server)
7
+ // and stays a PURE library — it pulls in neither @modelcontextprotocol/sdk nor zod.
8
8
  //
9
9
  // The DSL globals available INSIDE a workflow script (agent, parallel, pipeline, …) are
10
10
  // vm-realm globals, NOT importable symbols; they are documented for author IntelliSense
11
11
  // in ./dsl.d.ts (referenced above), not exported here.
12
- import { createAcpRunner } from "@automatalabs/acp-agents";
13
- import { parseWorkflowScript, WorkflowError, WorkflowErrorCode, WorkflowManager } from "@automatalabs/workflow-engine";
12
+ import { ACP_CROSS_CUTTING_EVENT_NAMES, createAcpRunner } from "@automatalabs/acp-agents";
13
+ import { parseWorkflowScript, WorkflowError, WorkflowErrorCode, WorkflowManager as EngineWorkflowManager, } from "@automatalabs/workflow-engine";
14
14
  // ── Engine: run entry, script parsing, the managed-run lifecycle, and the
15
15
  // option/result + error types the host composes against. ──
16
- export { runWorkflow, parseWorkflowScript, WorkflowManager } from "@automatalabs/workflow-engine";
17
- export { WorkflowError, WorkflowErrorCode, isWorkflowError, isProviderUsageLimit, } from "@automatalabs/workflow-engine";
18
- // ── ACP backend: the default AgentRunner implementation, backend selection, the
19
- // concrete backends (built-in + custom registry), the pool/runner options, and the
20
- // JSON-Schema helpers. Custom backends let ANY ACP agent serve agent() calls:
16
+ export { runWorkflow, parseWorkflowScript } from "@automatalabs/workflow-engine";
17
+ export { AGENTPRISM_PERSISTENCE_ROOT_ENV, WorkflowError, WorkflowErrorCode, isWorkflowError, isProviderUsageLimit, } from "@automatalabs/workflow-engine";
18
+ // ── ACP backend: the default AgentRunner implementation, interactive sessions, backend
19
+ // selection, the concrete backends (built-in + custom registry), the pool/runner options,
20
+ // capability helpers, client handlers, permission resolvers, and JSON-Schema helpers.
21
+ // Custom backends let ANY ACP agent serve agent() calls:
21
22
  // `createAcpRunner({ backends: { browser: { command: "…" } } })` (or the
22
23
  // AGENTPRISM_BACKENDS env var), then route with `agent(p, { model: "browser" })`. ──
23
- export { createAcpRunner, AcpAgentRunner, selectBackend, ClaudeBackend, CodexBackend, CustomAcpBackend, resolveBackendRegistry, BACKENDS_ENV, toJsonSchema, toStrictJsonSchema, } from "@automatalabs/acp-agents";
24
+ export { createAcpRunner, AcpAgentRunner, InteractiveSession, selectBackend, ClaudeBackend, CodexBackend, CustomAcpBackend, clientCapabilitiesFor, adaptPromptContent, resolveBackendRegistry, BACKENDS_ENV, toJsonSchema, toStrictJsonSchema, } from "@automatalabs/acp-agents";
24
25
  // ── Live ACP events: `createAcpRunner().on("tool_call", evt => …)` to listen in on the
25
26
  // stream of a run. The event map keys are ACP `sessionUpdate` discriminants plus a few
26
27
  // cross-cutting events; each payload carries a `{ sessionId, backendId, label?, runId? }`
27
28
  // context envelope so a pooled runner's concurrent runs are disambiguable. ──
28
29
  export { TypedEventEmitter } from "@automatalabs/acp-agents";
30
+ const MANAGER_ACP_CROSS_CUTTING_EVENT_NAMES = ACP_CROSS_CUTTING_EVENT_NAMES;
31
+ /**
32
+ * Stateful workflow manager exported by the SDK facade. It is the workflow-engine manager plus
33
+ * ONE composition-root bridge for ACP-capable runners: when the injected AgentRunner also exposes
34
+ * the acp-agents `.on(name, listener)` bus, the manager forwards that live stream as `agentEvent`.
35
+ *
36
+ * The engine package stays backend-agnostic; this facade already owns the ACP default runner and
37
+ * ACP event types, so the bridge belongs here. Forwarding is OBSERVABILITY ONLY: manager
38
+ * `agentEvent` listeners are isolated from each other and from the run, and `dispose()` removes
39
+ * only the manager's runner subscriptions (runner process ownership stays with the caller).
40
+ */
41
+ export class WorkflowManager extends EngineWorkflowManager {
42
+ acpBridges = new Map();
43
+ constructor(options = {}) {
44
+ super(options);
45
+ this.acquireAcpRunnerBridge(options.agent);
46
+ }
47
+ startInBackground(script, args, exec = {}) {
48
+ const releaseBridge = this.acquireAcpRunnerBridge(exec.agent);
49
+ try {
50
+ const started = super.startInBackground(script, args, exec);
51
+ void started.promise.then(releaseBridge, releaseBridge);
52
+ return started;
53
+ }
54
+ catch (error) {
55
+ releaseBridge();
56
+ throw error;
57
+ }
58
+ }
59
+ async runSync(script, args, exec = {}) {
60
+ const releaseBridge = this.acquireAcpRunnerBridge(exec.agent);
61
+ try {
62
+ return await super.runSync(script, args, exec);
63
+ }
64
+ finally {
65
+ releaseBridge();
66
+ }
67
+ }
68
+ async resume(runId, exec = {}) {
69
+ const releaseBridge = this.acquireAcpRunnerBridge(exec.agent);
70
+ try {
71
+ return await super.resume(runId, exec);
72
+ }
73
+ finally {
74
+ releaseBridge();
75
+ }
76
+ }
77
+ /** Detach manager-owned ACP event subscriptions. The manager does NOT dispose the runner: the
78
+ * caller may share one runner across managers or own its process lifetime explicitly. */
79
+ dispose() {
80
+ for (const bridge of this.acpBridges.values()) {
81
+ for (const unsubscribe of bridge.unsubscribers)
82
+ unsubscribe();
83
+ }
84
+ this.acpBridges.clear();
85
+ }
86
+ /** Node-style alias for hosts that tear down managers through close hooks. */
87
+ close() {
88
+ this.dispose();
89
+ }
90
+ acquireAcpRunnerBridge(agent) {
91
+ if (!isAcpEventBusRunner(agent))
92
+ return () => { };
93
+ let bridge = this.acpBridges.get(agent);
94
+ if (!bridge) {
95
+ bridge = {
96
+ refs: 0,
97
+ unsubscribers: [
98
+ agent.on("session_update", (event) => {
99
+ this.emit("agentEvent", toSessionUpdateAgentEventPayload(event));
100
+ }),
101
+ ...MANAGER_ACP_CROSS_CUTTING_EVENT_NAMES.map((name) => agent.on(name, (event) => {
102
+ this.emit("agentEvent", toAgentEventPayload(name, event));
103
+ })),
104
+ ],
105
+ };
106
+ this.acpBridges.set(agent, bridge);
107
+ }
108
+ bridge.refs++;
109
+ let active = true;
110
+ return () => {
111
+ if (!active)
112
+ return;
113
+ active = false;
114
+ const current = this.acpBridges.get(agent);
115
+ if (current !== bridge)
116
+ return;
117
+ current.refs--;
118
+ if (current.refs > 0)
119
+ return;
120
+ for (const unsubscribe of current.unsubscribers)
121
+ unsubscribe();
122
+ this.acpBridges.delete(agent);
123
+ };
124
+ }
125
+ }
126
+ function isAcpEventBusRunner(agent) {
127
+ return typeof agent?.on === "function";
128
+ }
129
+ function toSessionUpdateAgentEventPayload(event) {
130
+ const name = event.update.sessionUpdate;
131
+ return toAgentEventPayload(name, {
132
+ ...event.update,
133
+ sessionId: event.sessionId,
134
+ backendId: event.backendId,
135
+ label: event.label,
136
+ runId: event.runId,
137
+ });
138
+ }
139
+ function toAgentEventPayload(name, event) {
140
+ const context = event;
141
+ return {
142
+ name,
143
+ event,
144
+ backendId: context.backendId,
145
+ ...(context.sessionId !== undefined ? { sessionId: context.sessionId } : {}),
146
+ ...(context.label !== undefined ? { label: context.label } : {}),
147
+ ...(context.runId !== undefined ? { runId: context.runId } : {}),
148
+ };
149
+ }
29
150
  /**
30
151
  * Run a dynamic workflow script to a TERMINAL result, with the AgentRunner seam
31
152
  * defaulted to the ACP backend.
@@ -51,7 +172,13 @@ export async function runDynamicWorkflow(script, opts = {}) {
51
172
  if (declared && Object.keys(declared).length > 0) {
52
173
  exec = { ...(exec ?? {}), scriptBackends: await approveScriptBackends(declared, opts.allowScriptBackends) };
53
174
  }
54
- return new WorkflowManager({ agent: opts.runner ?? createAcpRunner() }).runSync(script, opts.args, exec);
175
+ const manager = new WorkflowManager({ agent: opts.runner ?? createAcpRunner() });
176
+ try {
177
+ return await manager.runSync(script, opts.args, exec);
178
+ }
179
+ finally {
180
+ manager.dispose();
181
+ }
55
182
  }
56
183
  /** Resolve the embedder's approval policy over the declared backends; throw with guidance when
57
184
  * approval is missing or any backend is declined (an unapproved dependency must abort, never
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automatalabs/workflows",
3
- "version": "0.6.2",
3
+ "version": "0.8.0",
4
4
  "license": "Apache-2.0",
5
5
  "repository": {
6
6
  "type": "git",
@@ -25,8 +25,8 @@
25
25
  },
26
26
  "dependencies": {
27
27
  "@automatalabs/shared-types": "0.7.0",
28
- "@automatalabs/workflow-engine": "0.3.2",
29
- "@automatalabs/acp-agents": "0.8.0"
28
+ "@automatalabs/workflow-engine": "0.4.0",
29
+ "@automatalabs/acp-agents": "0.9.0"
30
30
  },
31
31
  "scripts": {
32
32
  "build": "tsc -b",