agent-worker 0.13.0 → 0.15.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,448 +0,0 @@
1
- import { F as createModelWithProvider, P as createModelAsync } from "./backends-CziIqKRg.mjs";
2
- import { ToolLoopAgent, stepCountIs } from "ai";
3
-
4
- //#region src/agent/worker.ts
5
- /**
6
- * AgentWorker - Stateful worker for controlled agent execution
7
- *
8
- * Uses ToolLoopAgent internally for multi-step reasoning loops.
9
- * Maintains conversation state across multiple send() calls,
10
- * enabling improvisational testing where you observe responses
11
- * and decide next actions.
12
- *
13
- * Tools are AI SDK tool() objects passed as Record<name, tool()>.
14
- * Approval is configured separately via Record<name, check>.
15
- */
16
- var AgentWorker = class {
17
- id;
18
- model;
19
- system;
20
- createdAt;
21
- tools;
22
- approval;
23
- maxTokens;
24
- maxSteps;
25
- messages = [];
26
- totalUsage = {
27
- input: 0,
28
- output: 0,
29
- total: 0
30
- };
31
- pendingApprovals = [];
32
- backend;
33
- provider;
34
- cachedAgent = null;
35
- toolsChanged = false;
36
- /**
37
- * Whether this session supports tool management (SDK backend only)
38
- */
39
- get supportsTools() {
40
- return this.backend === null;
41
- }
42
- /**
43
- * Convert AgentMessage[] to ModelMessage[] for AI SDK
44
- */
45
- toModelMessages() {
46
- return this.messages.filter((m) => m.status !== "responding").map((m) => ({
47
- role: m.role,
48
- content: m.content
49
- }));
50
- }
51
- constructor(config, restore) {
52
- if (restore) {
53
- this.id = restore.id;
54
- this.createdAt = restore.createdAt;
55
- this.messages = [...restore.messages];
56
- this.totalUsage = { ...restore.totalUsage };
57
- this.pendingApprovals = [...restore.pendingApprovals ?? []];
58
- } else {
59
- this.id = crypto.randomUUID();
60
- this.createdAt = (/* @__PURE__ */ new Date()).toISOString();
61
- }
62
- this.model = config.model;
63
- this.system = config.system;
64
- this.tools = config.tools ? { ...config.tools } : {};
65
- this.approval = config.approval ? { ...config.approval } : {};
66
- this.maxTokens = config.maxTokens ?? 4096;
67
- this.maxSteps = config.maxSteps ?? 200;
68
- this.backend = config.backend ?? null;
69
- this.provider = config.provider;
70
- }
71
- /**
72
- * Check if a tool needs approval for given arguments
73
- */
74
- checkApproval(name, args) {
75
- const check = this.approval[name];
76
- if (!check) return false;
77
- if (typeof check === "function") return check(args);
78
- return check;
79
- }
80
- /**
81
- * Build tools with approval wrapping for ToolLoopAgent
82
- */
83
- buildTools(autoApprove) {
84
- if (Object.keys(this.tools).length === 0) return void 0;
85
- if (autoApprove || Object.keys(this.approval).length === 0) return this.tools;
86
- const wrapped = {};
87
- for (const [name, t] of Object.entries(this.tools)) {
88
- if (!this.approval[name]) {
89
- wrapped[name] = t;
90
- continue;
91
- }
92
- wrapped[name] = {
93
- ...t,
94
- execute: async (args, options) => {
95
- if (this.checkApproval(name, args)) {
96
- const approval = {
97
- id: crypto.randomUUID(),
98
- toolName: name,
99
- toolCallId: crypto.randomUUID(),
100
- arguments: args,
101
- requestedAt: (/* @__PURE__ */ new Date()).toISOString(),
102
- status: "pending"
103
- };
104
- this.pendingApprovals.push(approval);
105
- return {
106
- __approvalRequired: true,
107
- approvalId: approval.id
108
- };
109
- }
110
- return t.execute?.(args, options);
111
- }
112
- };
113
- }
114
- return wrapped;
115
- }
116
- /**
117
- * Get or create cached agent, rebuild if tools changed
118
- */
119
- async getAgent(autoApprove) {
120
- if (!this.cachedAgent || this.toolsChanged || !autoApprove) {
121
- this.cachedAgent = new ToolLoopAgent({
122
- model: this.provider ? await createModelWithProvider(this.model, this.provider) : await createModelAsync(this.model),
123
- instructions: this.system,
124
- tools: this.buildTools(autoApprove),
125
- maxOutputTokens: this.maxTokens,
126
- stopWhen: stepCountIs(this.maxSteps)
127
- });
128
- if (autoApprove) this.toolsChanged = false;
129
- }
130
- return this.cachedAgent;
131
- }
132
- /**
133
- * Send a message via CLI backend (non-SDK path)
134
- */
135
- async sendViaBackend(content) {
136
- const startTime = performance.now();
137
- const timestamp = (/* @__PURE__ */ new Date()).toISOString();
138
- this.messages.push({
139
- role: "user",
140
- content,
141
- status: "complete",
142
- timestamp
143
- });
144
- const result = await this.backend.send(content, { system: this.system });
145
- const latency = Math.round(performance.now() - startTime);
146
- this.messages.push({
147
- role: "assistant",
148
- content: result.content,
149
- status: "complete",
150
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
151
- });
152
- const usage = {
153
- input: result.usage?.input ?? 0,
154
- output: result.usage?.output ?? 0,
155
- total: result.usage?.total ?? 0
156
- };
157
- this.totalUsage.input += usage.input;
158
- this.totalUsage.output += usage.output;
159
- this.totalUsage.total += usage.total;
160
- const toolCalls = (result.toolCalls ?? []).map((tc) => ({
161
- name: tc.name,
162
- arguments: tc.arguments,
163
- result: tc.result,
164
- timing: 0
165
- }));
166
- return {
167
- content: result.content,
168
- toolCalls,
169
- pendingApprovals: [],
170
- usage,
171
- latency
172
- };
173
- }
174
- /**
175
- * Send a message and get the agent's response
176
- */
177
- async send(content, options = {}) {
178
- if (this.backend) return this.sendViaBackend(content);
179
- const { autoApprove = true, onStepFinish } = options;
180
- const startTime = performance.now();
181
- const timestamp = (/* @__PURE__ */ new Date()).toISOString();
182
- this.messages.push({
183
- role: "user",
184
- content,
185
- status: "complete",
186
- timestamp
187
- });
188
- const agent = await this.getAgent(autoApprove);
189
- const allToolCalls = [];
190
- let stepNumber = 0;
191
- const result = await agent.generate({
192
- messages: this.toModelMessages(),
193
- onStepFinish: async ({ usage, toolCalls, toolResults }) => {
194
- stepNumber++;
195
- const stepToolCalls = [];
196
- if (toolCalls) for (const tc of toolCalls) {
197
- const toolResult = toolResults?.find((tr) => tr.toolCallId === tc.toolCallId);
198
- const toolCall = {
199
- name: tc.toolName,
200
- arguments: tc.input,
201
- result: toolResult?.output ?? null,
202
- timing: 0
203
- };
204
- stepToolCalls.push(toolCall);
205
- allToolCalls.push(toolCall);
206
- }
207
- if (onStepFinish) {
208
- const stepUsage = {
209
- input: usage?.inputTokens ?? 0,
210
- output: usage?.outputTokens ?? 0,
211
- total: (usage?.inputTokens ?? 0) + (usage?.outputTokens ?? 0)
212
- };
213
- await onStepFinish({
214
- stepNumber,
215
- toolCalls: stepToolCalls,
216
- usage: stepUsage
217
- });
218
- }
219
- }
220
- });
221
- const latency = Math.round(performance.now() - startTime);
222
- this.messages.push({
223
- role: "assistant",
224
- content: result.text,
225
- status: "complete",
226
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
227
- });
228
- const usage = {
229
- input: result.usage?.inputTokens ?? 0,
230
- output: result.usage?.outputTokens ?? 0,
231
- total: (result.usage?.inputTokens ?? 0) + (result.usage?.outputTokens ?? 0)
232
- };
233
- this.totalUsage.input += usage.input;
234
- this.totalUsage.output += usage.output;
235
- this.totalUsage.total += usage.total;
236
- if (this.maxSteps > 0 && stepNumber >= this.maxSteps && allToolCalls.length > 0) console.warn(`⚠️ Agent reached maxSteps limit (${this.maxSteps}) but wanted to continue. Consider increasing maxSteps or removing the limit.`);
237
- const currentPending = this.pendingApprovals.filter((p) => p.status === "pending");
238
- return {
239
- content: result.text,
240
- toolCalls: allToolCalls,
241
- pendingApprovals: currentPending,
242
- usage,
243
- latency
244
- };
245
- }
246
- /**
247
- * Send a message and stream the response
248
- */
249
- async *sendStream(content, options = {}) {
250
- if (this.backend) {
251
- const response = await this.sendViaBackend(content);
252
- yield response.content;
253
- return response;
254
- }
255
- const { autoApprove = true, onStepFinish } = options;
256
- const startTime = performance.now();
257
- const timestamp = (/* @__PURE__ */ new Date()).toISOString();
258
- this.messages.push({
259
- role: "user",
260
- content,
261
- status: "complete",
262
- timestamp
263
- });
264
- const assistantMsg = {
265
- role: "assistant",
266
- content: "",
267
- status: "responding",
268
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
269
- };
270
- this.messages.push(assistantMsg);
271
- const agent = await this.getAgent(autoApprove);
272
- const allToolCalls = [];
273
- let stepNumber = 0;
274
- const result = await agent.stream({
275
- messages: this.toModelMessages(),
276
- onStepFinish: async ({ usage, toolCalls, toolResults }) => {
277
- stepNumber++;
278
- const stepToolCalls = [];
279
- if (toolCalls) for (const tc of toolCalls) {
280
- const toolResult = toolResults?.find((tr) => tr.toolCallId === tc.toolCallId);
281
- const toolCall = {
282
- name: tc.toolName,
283
- arguments: tc.input,
284
- result: toolResult?.output ?? null,
285
- timing: 0
286
- };
287
- stepToolCalls.push(toolCall);
288
- allToolCalls.push(toolCall);
289
- }
290
- if (onStepFinish) {
291
- const stepUsage = {
292
- input: usage?.inputTokens ?? 0,
293
- output: usage?.outputTokens ?? 0,
294
- total: (usage?.inputTokens ?? 0) + (usage?.outputTokens ?? 0)
295
- };
296
- await onStepFinish({
297
- stepNumber,
298
- toolCalls: stepToolCalls,
299
- usage: stepUsage
300
- });
301
- }
302
- }
303
- });
304
- for await (const chunk of result.textStream) {
305
- assistantMsg.content += chunk;
306
- yield chunk;
307
- }
308
- const latency = Math.round(performance.now() - startTime);
309
- const text = await result.text;
310
- assistantMsg.content = text;
311
- assistantMsg.status = "complete";
312
- const finalUsage = await result.usage;
313
- const usage = {
314
- input: finalUsage?.inputTokens ?? 0,
315
- output: finalUsage?.outputTokens ?? 0,
316
- total: (finalUsage?.inputTokens ?? 0) + (finalUsage?.outputTokens ?? 0)
317
- };
318
- this.totalUsage.input += usage.input;
319
- this.totalUsage.output += usage.output;
320
- this.totalUsage.total += usage.total;
321
- return {
322
- content: text,
323
- toolCalls: allToolCalls,
324
- pendingApprovals: this.pendingApprovals.filter((p) => p.status === "pending"),
325
- usage,
326
- latency
327
- };
328
- }
329
- /**
330
- * Add an AI SDK tool
331
- * Only supported for SDK backends (ToolLoopAgent)
332
- */
333
- addTool(name, t) {
334
- if (this.backend) throw new Error("Tool management not supported for CLI backends");
335
- this.tools[name] = t;
336
- this.toolsChanged = true;
337
- this.cachedAgent = null;
338
- }
339
- /**
340
- * Set approval requirement for a tool
341
- */
342
- setApproval(name, check) {
343
- this.approval[name] = check;
344
- }
345
- /**
346
- * Replace a tool's execute function (for testing)
347
- */
348
- mockTool(name, mockFn) {
349
- if (this.backend) throw new Error("Tool management not supported for CLI backends");
350
- const t = this.tools[name];
351
- if (!t) throw new Error(`Tool not found: ${name}`);
352
- this.tools[name] = {
353
- ...t,
354
- execute: mockFn
355
- };
356
- this.toolsChanged = true;
357
- this.cachedAgent = null;
358
- }
359
- /**
360
- * Set a static mock response for an existing tool
361
- */
362
- setMockResponse(name, response) {
363
- if (this.backend) throw new Error("Tool management not supported for CLI backends");
364
- const t = this.tools[name];
365
- if (!t) throw new Error(`Tool not found: ${name}`);
366
- this.tools[name] = {
367
- ...t,
368
- execute: () => response
369
- };
370
- this.toolsChanged = true;
371
- this.cachedAgent = null;
372
- }
373
- /**
374
- * Get tool info (names, descriptions, approval status)
375
- */
376
- getTools() {
377
- return Object.entries(this.tools).map(([name, t]) => {
378
- return {
379
- name,
380
- description: t?.description,
381
- needsApproval: !!this.approval[name]
382
- };
383
- });
384
- }
385
- history() {
386
- return [...this.messages];
387
- }
388
- stats() {
389
- return {
390
- messageCount: this.messages.length,
391
- usage: { ...this.totalUsage }
392
- };
393
- }
394
- export() {
395
- return {
396
- sessionId: this.id,
397
- model: this.model,
398
- system: this.system,
399
- messages: [...this.messages],
400
- totalUsage: { ...this.totalUsage },
401
- createdAt: this.createdAt
402
- };
403
- }
404
- getState() {
405
- return {
406
- id: this.id,
407
- createdAt: this.createdAt,
408
- messages: [...this.messages],
409
- totalUsage: { ...this.totalUsage },
410
- pendingApprovals: [...this.pendingApprovals]
411
- };
412
- }
413
- getPendingApprovals() {
414
- return this.pendingApprovals.filter((p) => p.status === "pending");
415
- }
416
- async approve(approvalId) {
417
- const approval = this.pendingApprovals.find((p) => p.id === approvalId);
418
- if (!approval) throw new Error(`Approval not found: ${approvalId}`);
419
- if (approval.status !== "pending") throw new Error(`Approval already ${approval.status}: ${approvalId}`);
420
- const t = this.tools[approval.toolName];
421
- if (!t) throw new Error(`Tool not found: ${approval.toolName}`);
422
- let result;
423
- const tool = t;
424
- if (typeof tool.execute === "function") result = await tool.execute(approval.arguments);
425
- else result = { error: "No implementation provided" };
426
- approval.status = "approved";
427
- return result;
428
- }
429
- deny(approvalId, reason) {
430
- const approval = this.pendingApprovals.find((p) => p.id === approvalId);
431
- if (!approval) throw new Error(`Approval not found: ${approvalId}`);
432
- if (approval.status !== "pending") throw new Error(`Approval already ${approval.status}: ${approvalId}`);
433
- approval.status = "denied";
434
- approval.denyReason = reason;
435
- }
436
- clear() {
437
- this.messages = [];
438
- this.totalUsage = {
439
- input: 0,
440
- output: 0,
441
- total: 0
442
- };
443
- this.pendingApprovals = [];
444
- }
445
- };
446
-
447
- //#endregion
448
- export { AgentWorker as t };
@@ -1,272 +0,0 @@
1
- import "./backends-CziIqKRg.mjs";
2
- import { c as CONTEXT_DEFAULTS, i as resolveContextDir } from "./cli/index.mjs";
3
- import "./memory-provider-BtLYtdQH.mjs";
4
- import { createChannelLogger, createSilentLogger } from "./logger-Bfdo83xL.mjs";
5
- import { a as runSdkAgent, c as buildAgentPrompt, createWorkflowProvider, d as createContext, f as interpolate, i as createAgentController, initWorkflow, l as formatInbox, n as getBackendForModel, o as runMockAgent, r as checkWorkflowIdle, runWorkflowWithControllers, s as generateWorkflowMCPConfig, shutdownControllers, t as getBackendByType, u as CONTROLLER_DEFAULTS } from "./runner-CnxROIev.mjs";
6
- import { existsSync, readFileSync } from "node:fs";
7
- import { basename, dirname, join, resolve } from "node:path";
8
- import { parse } from "yaml";
9
-
10
- //#region src/workflow/parser.ts
11
- /**
12
- * Workflow file parser
13
- */
14
- /**
15
- * Parse a workflow file
16
- */
17
- async function parseWorkflowFile(filePath, options) {
18
- const absolutePath = resolve(filePath);
19
- const workflow = options?.workflow ?? options?.instance ?? "global";
20
- const tag = options?.tag ?? "main";
21
- if (!existsSync(absolutePath)) throw new Error(`Workflow file not found: ${absolutePath}`);
22
- const content = readFileSync(absolutePath, "utf-8");
23
- const workflowDir = dirname(absolutePath);
24
- let raw;
25
- try {
26
- raw = parse(content);
27
- } catch (error) {
28
- throw new Error(`Failed to parse YAML: ${error instanceof Error ? error.message : String(error)}`);
29
- }
30
- const validation = validateWorkflow(raw);
31
- if (!validation.valid) {
32
- const messages = validation.errors.map((e) => ` - ${e.path}: ${e.message}`).join("\n");
33
- throw new Error(`Invalid workflow file:\n${messages}`);
34
- }
35
- const name = raw.name || basename(absolutePath, ".yml").replace(".yaml", "");
36
- const agents = {};
37
- for (const [agentName, agentDef] of Object.entries(raw.agents)) agents[agentName] = await resolveAgent(agentDef, workflowDir);
38
- return {
39
- name,
40
- filePath: absolutePath,
41
- agents,
42
- context: resolveContext(raw.context, workflowDir, name, workflow, tag),
43
- setup: raw.setup || [],
44
- kickoff: raw.kickoff
45
- };
46
- }
47
- /**
48
- * Resolve context configuration
49
- *
50
- * - undefined (not set): default file provider enabled
51
- * - null: default file provider enabled (YAML `context:` syntax)
52
- * - false: explicitly disabled
53
- * - { provider: 'file', config?: { dir | bind } }: file provider (ephemeral or persistent)
54
- * - { provider: 'memory' }: memory provider (for testing)
55
- */
56
- function resolveContext(config, workflowDir, workflowName, workflow, tag) {
57
- const resolve = (template) => resolveContextDir(template, {
58
- workflowName,
59
- workflow,
60
- tag,
61
- instance: workflow,
62
- baseDir: workflowDir
63
- });
64
- if (config === false) return;
65
- if (config === void 0 || config === null) return {
66
- provider: "file",
67
- dir: resolve(CONTEXT_DEFAULTS.dir)
68
- };
69
- if (config.provider === "memory") return {
70
- provider: "memory",
71
- documentOwner: config.documentOwner
72
- };
73
- const bindPath = config.config?.bind;
74
- if (bindPath) return {
75
- provider: "file",
76
- dir: resolve(bindPath),
77
- persistent: true,
78
- documentOwner: config.documentOwner
79
- };
80
- return {
81
- provider: "file",
82
- dir: resolve(config.config?.dir || CONTEXT_DEFAULTS.dir),
83
- documentOwner: config.documentOwner
84
- };
85
- }
86
- /**
87
- * Resolve agent definition (load system prompt from file if needed)
88
- */
89
- async function resolveAgent(agent, workflowDir) {
90
- let resolvedSystemPrompt = agent.system_prompt;
91
- if (resolvedSystemPrompt?.endsWith(".txt") || resolvedSystemPrompt?.endsWith(".md")) {
92
- const promptPath = resolvedSystemPrompt.startsWith("/") ? resolvedSystemPrompt : join(workflowDir, resolvedSystemPrompt);
93
- if (existsSync(promptPath)) resolvedSystemPrompt = readFileSync(promptPath, "utf-8");
94
- }
95
- return {
96
- ...agent,
97
- resolvedSystemPrompt
98
- };
99
- }
100
- /**
101
- * Validate workflow structure
102
- */
103
- function validateWorkflow(workflow) {
104
- const errors = [];
105
- if (!workflow || typeof workflow !== "object") {
106
- errors.push({
107
- path: "",
108
- message: "Workflow must be an object"
109
- });
110
- return {
111
- valid: false,
112
- errors
113
- };
114
- }
115
- const w = workflow;
116
- if (!w.agents || typeof w.agents !== "object") errors.push({
117
- path: "agents",
118
- message: "Required field \"agents\" must be an object"
119
- });
120
- else {
121
- const agents = w.agents;
122
- for (const [name, agent] of Object.entries(agents)) validateAgent(name, agent, errors);
123
- }
124
- if (w.context !== void 0 && w.context !== null && w.context !== false) validateContext(w.context, errors);
125
- if (w.setup !== void 0) if (!Array.isArray(w.setup)) errors.push({
126
- path: "setup",
127
- message: "Setup must be an array"
128
- });
129
- else for (let i = 0; i < w.setup.length; i++) validateSetupTask(`setup[${i}]`, w.setup[i], errors);
130
- if (w.kickoff !== void 0 && typeof w.kickoff !== "string") errors.push({
131
- path: "kickoff",
132
- message: "Kickoff must be a string"
133
- });
134
- return {
135
- valid: errors.length === 0,
136
- errors
137
- };
138
- }
139
- function validateContext(context, errors) {
140
- if (typeof context !== "object" || context === null) {
141
- errors.push({
142
- path: "context",
143
- message: "Context must be an object or false"
144
- });
145
- return;
146
- }
147
- const c = context;
148
- if (!c.provider || typeof c.provider !== "string") {
149
- errors.push({
150
- path: "context.provider",
151
- message: "Context requires \"provider\" field (file or memory)"
152
- });
153
- return;
154
- }
155
- if (c.provider !== "file" && c.provider !== "memory") {
156
- errors.push({
157
- path: "context.provider",
158
- message: "Context provider must be \"file\" or \"memory\""
159
- });
160
- return;
161
- }
162
- if (c.documentOwner !== void 0 && typeof c.documentOwner !== "string") errors.push({
163
- path: "context.documentOwner",
164
- message: "Context documentOwner must be a string"
165
- });
166
- if (c.provider === "file" && c.config !== void 0) {
167
- if (typeof c.config !== "object" || c.config === null) {
168
- errors.push({
169
- path: "context.config",
170
- message: "Context config must be an object"
171
- });
172
- return;
173
- }
174
- const cfg = c.config;
175
- if (cfg.dir !== void 0 && cfg.bind !== void 0) {
176
- errors.push({
177
- path: "context.config",
178
- message: "\"dir\" and \"bind\" are mutually exclusive — use one or the other"
179
- });
180
- return;
181
- }
182
- if (cfg.dir !== void 0 && typeof cfg.dir !== "string") errors.push({
183
- path: "context.config.dir",
184
- message: "Context config dir must be a string"
185
- });
186
- if (cfg.bind !== void 0 && typeof cfg.bind !== "string") errors.push({
187
- path: "context.config.bind",
188
- message: "Context config bind must be a string path"
189
- });
190
- }
191
- }
192
- function validateSetupTask(path, task, errors) {
193
- if (!task || typeof task !== "object") {
194
- errors.push({
195
- path,
196
- message: "Setup task must be an object"
197
- });
198
- return;
199
- }
200
- const t = task;
201
- if (!t.shell || typeof t.shell !== "string") errors.push({
202
- path: `${path}.shell`,
203
- message: "Setup task requires \"shell\" field as string"
204
- });
205
- if (t.as !== void 0 && typeof t.as !== "string") errors.push({
206
- path: `${path}.as`,
207
- message: "Setup task \"as\" field must be a string"
208
- });
209
- }
210
- /** Backends that don't require an explicit model field */
211
- const CLI_BACKENDS = [
212
- "claude",
213
- "cursor",
214
- "codex",
215
- "opencode",
216
- "mock"
217
- ];
218
- function validateAgent(name, agent, errors) {
219
- const path = `agents.${name}`;
220
- if (!agent || typeof agent !== "object") {
221
- errors.push({
222
- path,
223
- message: "Agent must be an object"
224
- });
225
- return;
226
- }
227
- const a = agent;
228
- const backend = typeof a.backend === "string" ? a.backend : "default";
229
- if (a.model !== void 0 && typeof a.model !== "string") errors.push({
230
- path: `${path}.model`,
231
- message: "Field \"model\" must be a string"
232
- });
233
- else if (!a.model && !CLI_BACKENDS.includes(backend)) errors.push({
234
- path: `${path}.model`,
235
- message: "Required field \"model\" must be a string (required for default backend)"
236
- });
237
- if (a.system_prompt !== void 0 && typeof a.system_prompt !== "string") errors.push({
238
- path: `${path}.system_prompt`,
239
- message: "Optional field \"system_prompt\" must be a string"
240
- });
241
- if (a.tools !== void 0 && !Array.isArray(a.tools)) errors.push({
242
- path: `${path}.tools`,
243
- message: "Optional field \"tools\" must be an array"
244
- });
245
- if (a.provider !== void 0) {
246
- if (typeof a.provider === "string") {} else if (typeof a.provider === "object" && a.provider !== null && !Array.isArray(a.provider)) {
247
- const p = a.provider;
248
- if (!p.name || typeof p.name !== "string") errors.push({
249
- path: `${path}.provider.name`,
250
- message: "Field \"provider.name\" is required and must be a string"
251
- });
252
- if (p.base_url !== void 0 && typeof p.base_url !== "string") errors.push({
253
- path: `${path}.provider.base_url`,
254
- message: "Field \"provider.base_url\" must be a string"
255
- });
256
- if (p.api_key !== void 0 && typeof p.api_key !== "string") errors.push({
257
- path: `${path}.provider.api_key`,
258
- message: "Field \"provider.api_key\" must be a string"
259
- });
260
- } else errors.push({
261
- path: `${path}.provider`,
262
- message: "Field \"provider\" must be a string or object with { name, base_url?, api_key? }"
263
- });
264
- if (CLI_BACKENDS.includes(backend) && backend !== "mock") errors.push({
265
- path: `${path}.provider`,
266
- message: `Field "provider" is ignored for CLI backend "${backend}" (only works with default backend)`
267
- });
268
- }
269
- }
270
-
271
- //#endregion
272
- export { parseWorkflowFile, runWorkflowWithControllers, shutdownControllers };