agent-worker 0.10.0 → 0.12.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.
@@ -1,16 +1,15 @@
1
- import { T as parseModel, a as createMockBackend, k as createModelAsync, n as createBackend } from "./backends-BOAkfYyL.mjs";
2
- import { c as CONTEXT_DEFAULTS, i as resolveContextDir, n as createFileContextProvider, t as FileContextProvider } from "./cli/index.mjs";
3
- import { a as createMemoryContextProvider, t as createContextMCPServer } from "./mcp-server-BQCQxv2v.mjs";
4
- import { createChannelLogger, createSilentLogger } from "./logger-C3ekEOzi.mjs";
1
+ import { A as createModelAsync, E as parseModel, a as createMockBackend, n as createBackend } from "./backends-DLaP0rMW.mjs";
2
+ import { T as EventLog, n as createFileContextProvider, t as FileContextProvider, v as createContextMCPServer } from "./cli/index.mjs";
3
+ import { n as createMemoryContextProvider } from "./memory-provider-BtLYtdQH.mjs";
4
+ import { createChannelLogger, createSilentLogger } from "./logger-Bfdo83xL.mjs";
5
5
  import { generateText, jsonSchema, stepCountIs, tool } from "ai";
6
- import { existsSync, mkdirSync, readFileSync } from "node:fs";
7
- import { basename, dirname, join, resolve } from "node:path";
8
- import { parse } from "yaml";
6
+ import { existsSync, mkdirSync } from "node:fs";
7
+ import { join } from "node:path";
9
8
  import { tmpdir } from "node:os";
10
9
  import { exec, execSync } from "node:child_process";
10
+ import { randomUUID } from "node:crypto";
11
11
  import { promisify } from "node:util";
12
12
  import { createServer } from "node:http";
13
- import { randomUUID } from "node:crypto";
14
13
  import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
15
14
  import { MockLanguageModelV3, mockValues } from "ai/test";
16
15
  import { Client } from "@modelcontextprotocol/sdk/client/index.js";
@@ -19,243 +18,6 @@ import stringWidth from "string-width";
19
18
  import chalk from "chalk";
20
19
  import wrapAnsi from "wrap-ansi";
21
20
 
22
- //#region src/workflow/parser.ts
23
- /**
24
- * Workflow file parser
25
- */
26
- /**
27
- * Parse a workflow file
28
- */
29
- async function parseWorkflowFile(filePath, options) {
30
- const absolutePath = resolve(filePath);
31
- const workflow = options?.workflow ?? options?.instance ?? "global";
32
- const tag = options?.tag ?? "main";
33
- if (!existsSync(absolutePath)) throw new Error(`Workflow file not found: ${absolutePath}`);
34
- const content = readFileSync(absolutePath, "utf-8");
35
- const workflowDir = dirname(absolutePath);
36
- let raw;
37
- try {
38
- raw = parse(content);
39
- } catch (error) {
40
- throw new Error(`Failed to parse YAML: ${error instanceof Error ? error.message : String(error)}`);
41
- }
42
- const validation = validateWorkflow(raw);
43
- if (!validation.valid) {
44
- const messages = validation.errors.map((e) => ` - ${e.path}: ${e.message}`).join("\n");
45
- throw new Error(`Invalid workflow file:\n${messages}`);
46
- }
47
- const name = raw.name || basename(absolutePath, ".yml").replace(".yaml", "");
48
- const agents = {};
49
- for (const [agentName, agentDef] of Object.entries(raw.agents)) agents[agentName] = await resolveAgent(agentDef, workflowDir);
50
- return {
51
- name,
52
- filePath: absolutePath,
53
- agents,
54
- context: resolveContext(raw.context, workflowDir, name, workflow, tag),
55
- setup: raw.setup || [],
56
- kickoff: raw.kickoff
57
- };
58
- }
59
- /**
60
- * Resolve context configuration
61
- *
62
- * - undefined (not set): default file provider enabled
63
- * - null: default file provider enabled (YAML `context:` syntax)
64
- * - false: explicitly disabled
65
- * - { provider: 'file', config?: { dir | bind } }: file provider (ephemeral or persistent)
66
- * - { provider: 'memory' }: memory provider (for testing)
67
- */
68
- function resolveContext(config, workflowDir, workflowName, workflow, tag) {
69
- const resolve = (template) => resolveContextDir(template, {
70
- workflowName,
71
- workflow,
72
- tag,
73
- instance: workflow,
74
- baseDir: workflowDir
75
- });
76
- if (config === false) return;
77
- if (config === void 0 || config === null) return {
78
- provider: "file",
79
- dir: resolve(CONTEXT_DEFAULTS.dir)
80
- };
81
- if (config.provider === "memory") return {
82
- provider: "memory",
83
- documentOwner: config.documentOwner
84
- };
85
- const bindPath = config.config?.bind;
86
- if (bindPath) return {
87
- provider: "file",
88
- dir: resolve(bindPath),
89
- persistent: true,
90
- documentOwner: config.documentOwner
91
- };
92
- return {
93
- provider: "file",
94
- dir: resolve(config.config?.dir || CONTEXT_DEFAULTS.dir),
95
- documentOwner: config.documentOwner
96
- };
97
- }
98
- /**
99
- * Resolve agent definition (load system prompt from file if needed)
100
- */
101
- async function resolveAgent(agent, workflowDir) {
102
- let resolvedSystemPrompt = agent.system_prompt;
103
- if (resolvedSystemPrompt?.endsWith(".txt") || resolvedSystemPrompt?.endsWith(".md")) {
104
- const promptPath = resolvedSystemPrompt.startsWith("/") ? resolvedSystemPrompt : join(workflowDir, resolvedSystemPrompt);
105
- if (existsSync(promptPath)) resolvedSystemPrompt = readFileSync(promptPath, "utf-8");
106
- }
107
- return {
108
- ...agent,
109
- resolvedSystemPrompt
110
- };
111
- }
112
- /**
113
- * Validate workflow structure
114
- */
115
- function validateWorkflow(workflow) {
116
- const errors = [];
117
- if (!workflow || typeof workflow !== "object") {
118
- errors.push({
119
- path: "",
120
- message: "Workflow must be an object"
121
- });
122
- return {
123
- valid: false,
124
- errors
125
- };
126
- }
127
- const w = workflow;
128
- if (!w.agents || typeof w.agents !== "object") errors.push({
129
- path: "agents",
130
- message: "Required field \"agents\" must be an object"
131
- });
132
- else {
133
- const agents = w.agents;
134
- for (const [name, agent] of Object.entries(agents)) validateAgent(name, agent, errors);
135
- }
136
- if (w.context !== void 0 && w.context !== null && w.context !== false) validateContext(w.context, errors);
137
- if (w.setup !== void 0) if (!Array.isArray(w.setup)) errors.push({
138
- path: "setup",
139
- message: "Setup must be an array"
140
- });
141
- else for (let i = 0; i < w.setup.length; i++) validateSetupTask(`setup[${i}]`, w.setup[i], errors);
142
- if (w.kickoff !== void 0 && typeof w.kickoff !== "string") errors.push({
143
- path: "kickoff",
144
- message: "Kickoff must be a string"
145
- });
146
- return {
147
- valid: errors.length === 0,
148
- errors
149
- };
150
- }
151
- function validateContext(context, errors) {
152
- if (typeof context !== "object" || context === null) {
153
- errors.push({
154
- path: "context",
155
- message: "Context must be an object or false"
156
- });
157
- return;
158
- }
159
- const c = context;
160
- if (!c.provider || typeof c.provider !== "string") {
161
- errors.push({
162
- path: "context.provider",
163
- message: "Context requires \"provider\" field (file or memory)"
164
- });
165
- return;
166
- }
167
- if (c.provider !== "file" && c.provider !== "memory") {
168
- errors.push({
169
- path: "context.provider",
170
- message: "Context provider must be \"file\" or \"memory\""
171
- });
172
- return;
173
- }
174
- if (c.documentOwner !== void 0 && typeof c.documentOwner !== "string") errors.push({
175
- path: "context.documentOwner",
176
- message: "Context documentOwner must be a string"
177
- });
178
- if (c.provider === "file" && c.config !== void 0) {
179
- if (typeof c.config !== "object" || c.config === null) {
180
- errors.push({
181
- path: "context.config",
182
- message: "Context config must be an object"
183
- });
184
- return;
185
- }
186
- const cfg = c.config;
187
- if (cfg.dir !== void 0 && cfg.bind !== void 0) {
188
- errors.push({
189
- path: "context.config",
190
- message: "\"dir\" and \"bind\" are mutually exclusive — use one or the other"
191
- });
192
- return;
193
- }
194
- if (cfg.dir !== void 0 && typeof cfg.dir !== "string") errors.push({
195
- path: "context.config.dir",
196
- message: "Context config dir must be a string"
197
- });
198
- if (cfg.bind !== void 0 && typeof cfg.bind !== "string") errors.push({
199
- path: "context.config.bind",
200
- message: "Context config bind must be a string path"
201
- });
202
- }
203
- }
204
- function validateSetupTask(path, task, errors) {
205
- if (!task || typeof task !== "object") {
206
- errors.push({
207
- path,
208
- message: "Setup task must be an object"
209
- });
210
- return;
211
- }
212
- const t = task;
213
- if (!t.shell || typeof t.shell !== "string") errors.push({
214
- path: `${path}.shell`,
215
- message: "Setup task requires \"shell\" field as string"
216
- });
217
- if (t.as !== void 0 && typeof t.as !== "string") errors.push({
218
- path: `${path}.as`,
219
- message: "Setup task \"as\" field must be a string"
220
- });
221
- }
222
- /** Backends that don't require an explicit model field */
223
- const CLI_BACKENDS = [
224
- "claude",
225
- "cursor",
226
- "codex",
227
- "mock"
228
- ];
229
- function validateAgent(name, agent, errors) {
230
- const path = `agents.${name}`;
231
- if (!agent || typeof agent !== "object") {
232
- errors.push({
233
- path,
234
- message: "Agent must be an object"
235
- });
236
- return;
237
- }
238
- const a = agent;
239
- const backend = typeof a.backend === "string" ? a.backend : "sdk";
240
- if (a.model !== void 0 && typeof a.model !== "string") errors.push({
241
- path: `${path}.model`,
242
- message: "Field \"model\" must be a string"
243
- });
244
- else if (!a.model && !CLI_BACKENDS.includes(backend)) errors.push({
245
- path: `${path}.model`,
246
- message: "Required field \"model\" must be a string (required for sdk backend)"
247
- });
248
- if (a.system_prompt !== void 0 && typeof a.system_prompt !== "string") errors.push({
249
- path: `${path}.system_prompt`,
250
- message: "Optional field \"system_prompt\" must be a string"
251
- });
252
- if (a.tools !== void 0 && !Array.isArray(a.tools)) errors.push({
253
- path: `${path}.tools`,
254
- message: "Optional field \"tools\" must be an array"
255
- });
256
- }
257
-
258
- //#endregion
259
21
  //#region src/workflow/interpolate.ts
260
22
  const VARIABLE_PATTERN = /\$\{\{\s*([^}]+)\s*\}\}/g;
261
23
  /**
@@ -779,7 +541,7 @@ function createBashTool() {
779
541
  /**
780
542
  * Run an SDK agent with real model + MCP tools + bash.
781
543
  *
782
- * Used by the controller when backend.type === 'sdk'.
544
+ * Used by the controller when backend.type === 'default'.
783
545
  * Unlike the simple SdkBackend.send() (text-only), this runner:
784
546
  * 1. Connects to MCP server for context tools (channel, document)
785
547
  * 2. Adds bash tool for shell access
@@ -813,17 +575,8 @@ async function runSdkAgent(ctx, debugLog) {
813
575
  stopWhen: stepCountIs(ctx.agent.max_steps ?? 200),
814
576
  onStepFinish: (step) => {
815
577
  _stepNum++;
816
- if (step.toolCalls?.length) {
817
- for (const tc of step.toolCalls) if (tc.toolName === "bash") {
818
- const args = formatToolCall(tc);
819
- ctx.provider.appendChannel(ctx.name, args, {
820
- kind: "tool_call",
821
- toolCall: {
822
- name: tc.toolName,
823
- args
824
- }
825
- }).catch(() => {});
826
- }
578
+ if (step.toolCalls?.length && ctx.eventLog) {
579
+ for (const tc of step.toolCalls) if (tc.toolName === "bash") ctx.eventLog.toolCall(ctx.name, tc.toolName, formatToolCall(tc), "sdk");
827
580
  }
828
581
  }
829
582
  });
@@ -832,7 +585,7 @@ async function runSdkAgent(ctx, debugLog) {
832
585
  if (ctx.agent.max_steps && result.steps.length >= ctx.agent.max_steps && (lastStep?.toolCalls?.length ?? 0) > 0) {
833
586
  const warning = `⚠️ Agent reached max_steps limit (${ctx.agent.max_steps}) but wanted to continue. Consider increasing max_steps or removing the limit.`;
834
587
  log(warning);
835
- await ctx.provider.appendChannel(ctx.name, warning, { kind: "log" }).catch(() => {});
588
+ await ctx.provider.appendChannel(ctx.name, warning, { kind: "system" }).catch(() => {});
836
589
  }
837
590
  await mcp.close();
838
591
  return {
@@ -868,7 +621,7 @@ function shouldContinue(state) {
868
621
  * 5. Can be woken early via wake()
869
622
  */
870
623
  function createAgentController(config) {
871
- const { name, agent, contextProvider, mcpUrl, workspaceDir, projectDir, backend, onRunComplete, log = () => {}, feedback } = config;
624
+ const { name, agent, contextProvider, eventLog, mcpUrl, workspaceDir, projectDir, backend, onRunComplete, log = () => {}, feedback } = config;
872
625
  const infoLog = config.infoLog ?? log;
873
626
  const errorLog = config.errorLog ?? log;
874
627
  const pollInterval = config.pollInterval ?? CONTROLLER_DEFAULTS.pollInterval;
@@ -934,6 +687,7 @@ function createAgentController(config) {
934
687
  projectDir,
935
688
  retryAttempt: attempt,
936
689
  provider: contextProvider,
690
+ eventLog,
937
691
  feedback
938
692
  }, log, infoLog);
939
693
  if (lastResult.success) {
@@ -1016,7 +770,7 @@ function createAgentController(config) {
1016
770
  async function runAgent(backend, ctx, log, infoLog) {
1017
771
  const info = infoLog ?? log;
1018
772
  if (backend.type === "mock") return runMockAgent(ctx, (msg) => log(msg));
1019
- if (backend.type === "sdk") return runSdkAgent(ctx, (msg) => log(msg));
773
+ if (backend.type === "default") return runSdkAgent(ctx, (msg) => log(msg));
1020
774
  const startTime = Date.now();
1021
775
  try {
1022
776
  if (backend.setWorkspace) {
@@ -1067,8 +821,7 @@ function getBackendByType(backendType, options) {
1067
821
  if (backendType === "mock") return createMockBackend(options?.debugLog);
1068
822
  const backendOptions = {};
1069
823
  if (options?.timeout) backendOptions.timeout = options.timeout;
1070
- if (options?.debugLog) backendOptions.debugLog = options.debugLog;
1071
- if (options?.messageLog) backendOptions.messageLog = options.messageLog;
824
+ if (options?.streamCallbacks) backendOptions.streamCallbacks = options.streamCallbacks;
1072
825
  return createBackend({
1073
826
  type: backendType,
1074
827
  model: options?.model,
@@ -1084,7 +837,7 @@ function getBackendByType(backendType, options) {
1084
837
  function getBackendForModel(model, options) {
1085
838
  const { provider } = parseModel(model);
1086
839
  switch (provider) {
1087
- case "anthropic": return getBackendByType("sdk", {
840
+ case "anthropic": return getBackendByType("default", {
1088
841
  ...options,
1089
842
  model
1090
843
  });
@@ -1354,9 +1107,11 @@ function startChannelWatcher(config) {
1354
1107
  * Workflow Runner
1355
1108
  *
1356
1109
  * All output flows through the channel:
1357
- * - Operational events (init, setup, connect) → kind="log" (always visible)
1110
+ * - Operational events (init, setup, connect) → kind="system" (always visible)
1358
1111
  * - Debug details (MCP traces, idle checks) → kind="debug" (visible with --debug)
1359
- * - Agent messages → kind=undefined (always visible)
1112
+ * - Agent messages → kind="message" or undefined (always visible)
1113
+ * - Tool calls → kind="tool_call" with structured metadata
1114
+ * - Backend text output → kind="output" (always visible)
1360
1115
  *
1361
1116
  * The display layer (display.ts) handles filtering and formatting.
1362
1117
  */
@@ -1421,6 +1176,8 @@ async function initWorkflow(config) {
1421
1176
  }
1422
1177
  const projectDir = process.cwd();
1423
1178
  let mcpGetFeedback;
1179
+ let mcpToolNames = /* @__PURE__ */ new Set();
1180
+ const eventLog = new EventLog(contextProvider);
1424
1181
  const createMCPServerInstance = () => {
1425
1182
  const mcp = createContextMCPServer({
1426
1183
  provider: contextProvider,
@@ -1432,6 +1189,7 @@ async function initWorkflow(config) {
1432
1189
  debugLog
1433
1190
  });
1434
1191
  mcpGetFeedback = mcp.getFeedback;
1192
+ mcpToolNames = mcp.mcpToolNames;
1435
1193
  return mcp.server;
1436
1194
  };
1437
1195
  const httpMcpServer = await runWithHttp({
@@ -1468,9 +1226,11 @@ async function initWorkflow(config) {
1468
1226
  contextDir,
1469
1227
  projectDir,
1470
1228
  contextProvider,
1229
+ eventLog,
1471
1230
  httpMcpServer,
1472
1231
  mcpUrl: httpMcpServer.url,
1473
1232
  agentNames,
1233
+ mcpToolNames,
1474
1234
  setupResults,
1475
1235
  async sendKickoff() {
1476
1236
  if (!interpolatedKickoff) {
@@ -1574,23 +1334,23 @@ async function runWorkflowWithControllers(config) {
1574
1334
  model: agentDef.model
1575
1335
  });
1576
1336
  const agentLogger = logger.child(agentName);
1577
- const backendDebugLog = (msg) => {
1578
- agentLogger.debug(msg);
1579
- };
1580
- const backendMessageLog = (msg) => {
1581
- runtime.contextProvider.appendChannel(agentName, msg, { kind: "stream" }).catch(() => {});
1337
+ const streamCallbacks = {
1338
+ debugLog: (msg) => agentLogger.debug(msg),
1339
+ outputLog: (msg) => runtime.eventLog.output(agentName, msg),
1340
+ toolCallLog: (name, args) => runtime.eventLog.toolCall(agentName, name, args, "backend"),
1341
+ mcpToolNames: runtime.mcpToolNames
1582
1342
  };
1583
1343
  let backend;
1584
1344
  if (createBackend) backend = createBackend(agentName, agentDef);
1585
1345
  else if (agentDef.backend) backend = getBackendByType(agentDef.backend, {
1586
1346
  model: agentDef.model,
1587
- debugLog: backendDebugLog,
1588
- messageLog: backendMessageLog,
1347
+ debugLog: (msg) => agentLogger.debug(msg),
1348
+ streamCallbacks,
1589
1349
  timeout: agentDef.timeout
1590
1350
  });
1591
1351
  else if (agentDef.model) backend = getBackendForModel(agentDef.model, {
1592
- debugLog: backendDebugLog,
1593
- messageLog: backendMessageLog
1352
+ debugLog: (msg) => agentLogger.debug(msg),
1353
+ streamCallbacks
1594
1354
  });
1595
1355
  else throw new Error(`Agent "${agentName}" requires either a backend or model field`);
1596
1356
  logger.debug(`Using backend: ${backend.type} for ${agentName}`);
@@ -1601,6 +1361,7 @@ async function runWorkflowWithControllers(config) {
1601
1361
  name: agentName,
1602
1362
  agent: agentDef,
1603
1363
  contextProvider: runtime.contextProvider,
1364
+ eventLog: runtime.eventLog,
1604
1365
  mcpUrl: runtime.mcpUrl,
1605
1366
  workspaceDir,
1606
1367
  projectDir: runtime.projectDir,
@@ -1619,8 +1380,8 @@ async function runWorkflowWithControllers(config) {
1619
1380
  await runtime.sendKickoff();
1620
1381
  logger.debug("Kickoff sent");
1621
1382
  let channelWatcher;
1622
- if (config.prettyDisplay) {
1623
- const { startPrettyDisplay } = await import("./display-pretty-CWoRE9FY.mjs");
1383
+ if (!config.headless) if (config.prettyDisplay) {
1384
+ const { startPrettyDisplay } = await import("./display-pretty-BCJq5v9d.mjs");
1624
1385
  channelWatcher = startPrettyDisplay({
1625
1386
  contextProvider: runtime.contextProvider,
1626
1387
  agentNames: runtime.agentNames,
@@ -1725,4 +1486,4 @@ function sleep(ms) {
1725
1486
  }
1726
1487
 
1727
1488
  //#endregion
1728
- export { parseWorkflowFile, runWorkflowWithControllers, shutdownControllers };
1489
+ export { runSdkAgent as a, buildAgentPrompt as c, createWorkflowProvider, createContext as d, interpolate as f, createAgentController as i, initWorkflow, formatInbox as l, getBackendForModel as n, runMockAgent as o, checkWorkflowIdle as r, runWorkflowWithControllers, generateWorkflowMCPConfig as s, shutdownControllers, getBackendByType as t, CONTROLLER_DEFAULTS as u };