@automatalabs/workflows 0.23.0 → 0.23.2

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 (2) hide show
  1. package/README.md +69 -37
  2. package/package.json +2 -2
package/README.md CHANGED
@@ -6,17 +6,19 @@ The programmatic **SDK** for AgentPrism — run dynamic, multi-agent **workflow
6
6
 
7
7
  You author a small JavaScript **script** (a string), the engine runs it in a deterministic,
8
8
  journaled, resumable realm, and every `agent()` call inside it is fanned out to a pooled ACP
9
- backend — **Claude** (`claude-agent-acp`) or **Codex** (`codex-acp`) driving the actual agent
10
- subprocess to completion.
9
+ backend — **Claude** (`claude-agent-acp`), **Codex** (`codex-acp`), **OpenCode** (`opencode acp`),
10
+ or a registered custom ACP agent — driving the actual subprocess to completion.
11
11
 
12
12
  This package is the **canonical SDK** that the stdio MCP server
13
13
  [`@automatalabs/mcp-server`](https://www.npmjs.com/package/@automatalabs/mcp-server) is built on.
14
14
  If you want to expose a `workflow` tool to an MCP host (Claude Code, Zed, …), use that package; if
15
15
  you want to embed the runner in your own program, use this one.
16
16
 
17
- It is a **pure library**: it pulls in neither `@modelcontextprotocol/sdk` nor `zod`. It is a thin
18
- facade that re-exports the clean public surface of the engine + ACP packages and adds one
19
- convenience helper, `runDynamicWorkflow`, which defaults the agent backend to ACP.
17
+ It is a **programmatic library**, not an MCP stdio server. It is a thin facade over the engine +
18
+ ACP packages and adds one convenience helper, `runDynamicWorkflow`, which defaults the agent
19
+ backend to ACP. The ACP layer does use `@modelcontextprotocol/sdk` internally when it hosts the
20
+ optional StructuredOutput tool for eligible agents; consumers still interact through this SDK's
21
+ workflow/runner APIs rather than MCP server schemas.
20
22
 
21
23
  ---
22
24
 
@@ -26,8 +28,9 @@ convenience helper, `runDynamicWorkflow`, which defaults the agent backend to AC
26
28
  pnpm add @automatalabs/workflows
27
29
  ```
28
30
 
29
- > The backend ACP servers ship as transitive dependencies and are spawned for you on demand; you
30
- > do not install or start them separately.
31
+ > The Claude and Codex ACP servers ship as transitive dependencies and are spawned on demand.
32
+ > OpenCode is host-resolved: install `opencode-ai` or make `opencode` available on `PATH` before
33
+ > routing a call to it.
31
34
 
32
35
  ---
33
36
 
@@ -39,6 +42,7 @@ pnpm add @automatalabs/workflows
39
42
  - **Claude** — a logged-in Claude Code install (`~/.claude`) **or** `ANTHROPIC_API_KEY` in the
40
43
  environment.
41
44
  - **Codex** — a logged-in Codex install (`~/.codex`).
45
+ - **OpenCode** — credentials configured for the provider OpenCode will use.
42
46
 
43
47
  You only need auth for the backend(s) your scripts actually route to. The default backend is
44
48
  Claude (override with `AGENTPRISM_DEFAULT_BACKEND`; see [Backend selection](#backend-selection)).
@@ -94,6 +98,8 @@ Options (`RunDynamicWorkflowOptions`):
94
98
  | `cwd` | `string` | Base working directory for the run (e.g. the project root): every subagent session runs here (a per-agent `agent({ cwd })` or worktree isolation overrides it), worktrees branch from it, and `agentType` definitions are scanned from it. Omitted ⇒ `process.cwd()`. |
95
99
  | `runner` | `AgentRunner` | Swap the backend (or stub it in tests). Omitted ⇒ `createAcpRunner()`. |
96
100
  | `exec` | `ExecOptions` | Per-run controls forwarded to the manager: `tokenBudget`, `agentTimeoutMs`, `concurrency`, `agentRetries`, `signal`, `onProgress`, `confirm`, … |
101
+ | `allowScriptBackends` | `boolean \| callback` | Approve the commands declared in `meta.backends`; declarations are inert without host approval. |
102
+ | `workflows` | `string \| string[] \| WorkflowDir` | Resolve the first argument and nested `workflow("name")` calls from one or more directories. |
97
103
 
98
104
  ```ts
99
105
  const run = await runDynamicWorkflow(script, {
@@ -126,7 +132,7 @@ try {
126
132
  type: "object", additionalProperties: false,
127
133
  required: ["summary"], properties: { summary: { type: "string" } },
128
134
  },
129
- model: "opus", // routes to Claude; e.g. "gpt-5-codex" routes to Codex
135
+ model: "opus", // routes to Claude; e.g. "gpt-5.5" routes to Codex
130
136
  cwd: process.cwd(), // absolute working dir for the agent's session
131
137
  });
132
138
  // data is the schema-validated object (not text)
@@ -137,13 +143,13 @@ try {
137
143
  }
138
144
  ```
139
145
 
140
- `run(prompt, options?)` accepts the seam's `RunOptions`: `schema`, `model`, `tier`, `cwd`,
141
- `instructions`, `label`, `toolNames` / `disallowedToolNames`, `signal`, `mcpServers`,
142
- `meta` / `promptMeta` (generic ACP `_meta` passthroughs merged into `session/new` /
143
- `session/prompt`), `baseInstructions` / `developerInstructions` (Codex-only), and the out-of-band
144
- telemetry callbacks `onUsage` / `onModelResolved` / `onModelFallback` / `onHistory`. Token/cost
145
- usage is delivered via `onUsage` (it may never fire — ACP usage is experimental), never via the
146
- return value.
146
+ `run(prompt, options?)` accepts the seam's `RunOptions`: `schema`, `maxSchemaRetries`, `model`, `mode`, `tier`, `cwd`,
147
+ `instructions`, `label`, `toolNames` / `disallowedToolNames`, `signal`, `mcpServers`, `images`,
148
+ `backends`, `meta` / `promptMeta` (generic ACP `_meta` passthroughs merged into `session/new` /
149
+ `session/prompt`), `baseInstructions` / `developerInstructions` (Codex-only), `keepSession`, and
150
+ the out-of-band callbacks `onUsage` / `onModelResolved` / `onModelFallback` / `onHistory` /
151
+ `onSessionOpen`. Token/cost usage is delivered via `onUsage` (it may never fire — ACP usage is
152
+ experimental), never via the return value.
147
153
 
148
154
  > **Codex session instructions.** When the run routes to the Codex backend, `baseInstructions`
149
155
  > **replaces** Codex's built-in base system prompt and `developerInstructions` adds developer-role
@@ -153,7 +159,7 @@ return value.
153
159
  >
154
160
  > ```ts
155
161
  > await runner.run("Cut the release.", {
156
- > model: "gpt-5-codex",
162
+ > model: "gpt-5.5",
157
163
  > baseInstructions: "You are a release bot. Only touch CHANGELOG.md.",
158
164
  > developerInstructions: "Prefer conventional-commit summaries.",
159
165
  > });
@@ -175,9 +181,10 @@ return value.
175
181
  >
176
182
  > `model: "browser/vision-large"` additionally selects `vision-large` from the agent's config-option
177
183
  > catalog. The same registry can be declared via `AGENTPRISM_BACKENDS` (JSON env var; the
178
- > programmatic option wins per name). A `schema` is forwarded to custom backends as turn-level
179
- > `_meta.outputSchema` and the result is JSON-parsed off the final message agents that ignore the
180
- > schema channel still work via the validate/re-prompt ladder.
184
+ > programmatic option wins per name). A `schema` is forwarded as turn-level `_meta.outputSchema`
185
+ > and embedded in the prompt. Eligible HTTP-MCP agents also receive the client-hosted
186
+ > `StructuredOutput` capture tool; otherwise the result is JSON-parsed from the final message.
187
+ > Every path still goes through the validate/re-prompt ladder.
181
188
  >
182
189
  > A workflow **script** can also declare backends itself via `meta.backends` (same config shape,
183
190
  > keyed by name). Because script-declared backends spawn commands on your machine, they are inert
@@ -187,6 +194,20 @@ return value.
187
194
  > its `agent()` calls to the default backend). Host-registered names always win over script
188
195
  > declarations. Lower-level callers can thread a pre-approved registry via `exec.scriptBackends`.
189
196
 
197
+ #### Authentication lifecycle
198
+
199
+ `createAcpRunner()` is auth-capable. It exposes `describeAuthMethods()` / `completeAuth()` and the
200
+ `runner.auth` controller (`status`, `authenticate`, `logout`) while preserving the minimal
201
+ `AgentRunner.run()` seam. Existing environment variables and backend-native credential stores are
202
+ used normally. A direct `runner.run()` throws `WorkflowError { code: "AUTH_REQUIRED" }` when no
203
+ resolver can satisfy the backend; a `WorkflowManager` catches that code and returns a resumable
204
+ `paused` result with redacted `authContext`.
205
+
206
+ Pass `onAuth` and `authCapabilities` to `createAcpRunner()` when the embedding host can collect
207
+ credentials inline. Secret env/meta resolutions live in the runner's in-memory auth store, are
208
+ redacted from events/errors, and are cleared on logout. Browser/TTY methods still require a host
209
+ that can actually complete them.
210
+
190
211
  ### c) `WorkflowManager` — stateful / resumable runs
191
212
 
192
213
  `runDynamicWorkflow` is a thin wrapper over a fresh `WorkflowManager`. Construct one yourself to
@@ -200,18 +221,18 @@ const manager = new WorkflowManager({ agent: createAcpRunner() });
200
221
  const run = await manager.runSync(script, { repo: "agentprism" }, { tokenBudget: 200_000 });
201
222
 
202
223
  if (run.status === "paused") {
203
- // A pause carries a journal of every completed agent() call. Re-hydrate it and re-run the
204
- // SAME script: the unchanged prefix is replayed from the journal, the rest runs live.
205
- const persisted = manager.getPersistence().load(run.runId);
206
- const resumeJournal = new Map(persisted?.journal?.map((e) => [e.index, e]) ?? []);
207
- const finished = await manager.runSync(script, { repo: "agentprism" }, { resumeJournal });
208
- console.log(finished.status); // "completed", typically
224
+ // resume() reloads the original script, args, cwd, and journal under the SAME runId,
225
+ // then continues in the background. Observe manager events or getRun(runId) for status.
226
+ const accepted = await manager.resume(run.runId);
227
+ console.log(accepted); // true when the paused run was accepted for resume
209
228
  }
210
229
  ```
211
230
 
212
231
  `runSync(script, args?, exec?)` always resolves to a terminal `WorkflowRunResult`. A run **pauses**
213
- (rather than fails) on a provider usage limit or a headless `checkpoint()`; both are resumable as
214
- above. `WorkflowManagerOptions` lets you set a default `agent`, `concurrency`, `cwd`, a
232
+ (rather than fails) on a provider usage limit or ACP authentication requirement; both are
233
+ resumable as above. A headless `checkpoint()` applies its configured default or abort behavior.
234
+ An auth pause carries `reason: "auth_required"` plus a non-secret `authContext`; complete auth on
235
+ an auth-capable runner before resuming. `WorkflowManagerOptions` lets you set a default `agent`, `concurrency`, `cwd`, a
215
236
  `loadSavedWorkflow` resolver (enables nested `workflow('name')`), a custom `persistence`
216
237
  implementation, and per-agent timeout/retry defaults.
217
238
 
@@ -229,6 +250,12 @@ names.
229
250
  manager.on("agentEvent", ({ runId, label, name }) => console.error(runId, label, name));
230
251
  ```
231
252
 
253
+ Every live ACP-backed `agent()` call records a non-secret re-attach handle in
254
+ `run.agentSessions`. Set `agent(..., { keepSession: true })` to skip release-time `session/close`,
255
+ then use the runner's `loadSession()` or `resumeSession()` host API with that record. Session
256
+ handles are additive and are also preserved in journals; they do not change the deterministic
257
+ resume identity.
258
+
232
259
  ### d) Bring your own backend — implement the `AgentRunner` seam
233
260
 
234
261
  `AgentRunner` is the single, frozen coupling point between the engine and any backend. Implement
@@ -434,8 +461,8 @@ report.warnings; // approval reminders, phase mismatches, headless-abo
434
461
 
435
462
  Pass a JSON Schema to `agent({ schema })` (in a script) or `runner.run(prompt, { schema })` (direct)
436
463
  and the result is a **validated object** instead of text. The backend constrains output natively
437
- (Claude `outputFormat`; Codex strict `outputSchema`), then the value is coerced and validated
438
- client-side (typebox `Convert` → `Check`); on a miss the runner re-prompts a bounded number of
464
+ (Claude `outputFormat`; Codex strict `outputSchema`; prompt/tool-assisted JSON for OpenCode and
465
+ custom agents), then the value is coerced and validated client-side (typebox `Convert` → `Check`); on a miss the runner re-prompts a bounded number of
439
466
  times before failing with a non-recoverable `SCHEMA_NONCOMPLIANCE`.
440
467
 
441
468
  A **plain JSON Schema object literal** works everywhere (this is the only option inside a script —
@@ -473,16 +500,17 @@ toStrictJsonSchema(schema); // OpenAI-strict-normalized (Codex outputSchema)
473
500
  The backend for each agent is chosen from its `model` (preferred) or `tier` string:
474
501
 
475
502
  - **Provider prefix** — `anthropic/…` or `claude/…` ⇒ Claude; `openai/…` or `codex/…` ⇒ Codex.
503
+ - **OpenCode prefix or id** — `opencode/…` or `opencode` ⇒ OpenCode.
476
504
  - **Bare id** — matched by pattern: `codex` / `gpt` / `openai` / `o<digit>` ⇒ Codex;
477
505
  `claude` / `opus` / `sonnet` / `haiku` / `anthropic` ⇒ Claude.
478
506
  - **No match / no spec** — the default backend: `AGENTPRISM_DEFAULT_BACKEND` (`claude`, `codex`,
479
- or any registered custom backend name; default `claude`).
507
+ `opencode`, or any registered custom backend name; default `claude`).
480
508
 
481
509
  ```ts
482
510
  import { selectBackend } from "@automatalabs/workflows";
483
511
 
484
512
  selectBackend({ model: "opus" }).id; // "claude"
485
- selectBackend({ model: "gpt-5-codex" }).id; // "codex"
513
+ selectBackend({ model: "gpt-5.5" }).id; // "codex"
486
514
  selectBackend({ model: "anthropic/claude-sonnet" }).id; // "claude"
487
515
  ```
488
516
 
@@ -509,14 +537,16 @@ WorkflowManager, // stateful / resumable run manager
509
537
  createAcpRunner, // () => AcpAgentRunner (the default AgentRunner; has .on(...) events)
510
538
  AcpAgentRunner, // class — implements AgentRunner over ACP
511
539
  InteractiveSession, // held-open multi-turn ACP session returned by openSession()
512
- selectBackend, // pick Claude vs Codex from a model/tier spec
513
- ClaudeBackend, CodexBackend, // the concrete backends
540
+ selectBackend, // pick a built-in/custom backend from a model/tier spec
541
+ ClaudeBackend, CodexBackend, CustomAcpBackend,
542
+ resolveBackendRegistry, BACKENDS_ENV,
543
+ AGENT_METHODS, CLIENT_METHODS, ACP_AUTH_REQUIRED_ERROR_CODE,
514
544
  clientCapabilitiesFor, adaptPromptContent,
515
545
  toJsonSchema, toStrictJsonSchema,
516
546
  TypedEventEmitter, // the tiny typed emitter backing runner.on(...)
517
547
 
518
548
  // ── Errors ──
519
- WorkflowError, WorkflowErrorCode, isWorkflowError, isProviderUsageLimit,
549
+ WorkflowError, WorkflowErrorCode, isWorkflowError, isProviderUsageLimit, isAuthRequired,
520
550
 
521
551
  // ── Persistence paths ──
522
552
  AGENTPRISM_PERSISTENCE_ROOT_ENV,
@@ -526,8 +556,10 @@ RunDynamicWorkflowOptions, WorkflowRunOptions, AgentOptions, ExecOptions,
526
556
  ValidateWorkflowOptions, ValidateWorkflowReport, ValidatedAgentCall, ValidatedCheckpoint,
527
557
  WorkflowManagerOptions, CheckpointOptions, WorkflowRunResult, WorkflowSnapshot,
528
558
  WorkflowPathOptions, RunPersistence, RunPersistenceOptions,
529
- AcpPoolOptions, AgentRunner, RunOptions, AgentResult, AgentUsage, JournalEntry,
559
+ AcpPoolOptions, AcpRunnerOptions, AgentRunner, RunOptions, AgentResult, AgentUsage, JournalEntry,
560
+ AgentSessionRef, AgentSessionRecord, WorkflowBackendConfig,
530
561
  InteractiveSessionOptions, InteractiveTurn, PermissionResolver,
562
+ AuthResolver, AuthContext, AuthResolution, AuthMethodDescriptor, AuthCapableRunner,
531
563
  ClientHandlers, FsHandlers, TerminalHandlers, McpHandlers, AcpSessionContext, NegotiatedCapabilities,
532
564
  // ACP events: the runner.on(...) surface
533
565
  AcpRunnerEventMap, AcpEventName, AcpEventListener, AcpEventContext,
@@ -563,8 +595,8 @@ the exhaustive option tables.
563
595
  ## See also
564
596
 
565
597
  - **[`@automatalabs/mcp-server`](https://www.npmjs.com/package/@automatalabs/mcp-server)** — the
566
- stdio MCP server built on this SDK. It wraps the same engine + ACP backend behind a single
567
- `workflow` tool (bin: `agentprism-workflow`) for any MCP host. Use it when you want the
598
+ stdio MCP server built on this SDK. It wraps the same engine + ACP backend behind `workflow`
599
+ and conditional auth tools (bin: `agentprism-workflow`) for any MCP host. Use it when you want the
568
600
  **MCP-tool route** instead of embedding the runner in code.
569
601
 
570
602
  ## License
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automatalabs/workflows",
3
- "version": "0.23.0",
3
+ "version": "0.23.2",
4
4
  "license": "Apache-2.0",
5
5
  "engines": {
6
6
  "node": ">=22"
@@ -32,7 +32,7 @@
32
32
  "dependencies": {
33
33
  "@automatalabs/shared-types": "0.14.0",
34
34
  "@automatalabs/workflow-engine": "0.12.0",
35
- "@automatalabs/acp-agents": "0.22.0"
35
+ "@automatalabs/acp-agents": "0.22.2"
36
36
  },
37
37
  "devDependencies": {
38
38
  "typebox": "1.3.2"