agent-worker 0.9.0 → 0.11.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 +4 -4
- package/dist/backends-DG5igQii.mjs +3 -0
- package/dist/{backends-BOAkfYyL.mjs → backends-DLaP0rMW.mjs} +45 -30
- package/dist/cli/index.mjs +1408 -1505
- package/dist/context-CKL-RY7a.mjs +4 -0
- package/dist/{display-pretty-BL9H2ocr.mjs → display-pretty-BsCsnPqs.mjs} +35 -14
- package/dist/index.d.mts +42 -30
- package/dist/index.mjs +561 -5
- package/dist/{logger-C3ekEOzi.mjs → logger-CCFaMMV7.mjs} +2 -2
- package/dist/memory-provider-CBlKMdbJ.mjs +70 -0
- package/dist/worker-CJ5_b2_q.mjs +446 -0
- package/dist/{workflow-CoZnnJ3O.mjs → workflow-CfITD7TN.mjs} +36 -37
- package/package.json +3 -1
- package/dist/backends-e6gCxRZ9.mjs +0 -3
- package/dist/context-dgI2YCGG.mjs +0 -4
- package/dist/mcp-server-BQCQxv2v.mjs +0 -573
- package/dist/skills-xNmQZf8e.mjs +0 -1002
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
import { A as createModelAsync } from "./backends-DLaP0rMW.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
|
+
cachedAgent = null;
|
|
34
|
+
toolsChanged = false;
|
|
35
|
+
/**
|
|
36
|
+
* Whether this session supports tool management (SDK backend only)
|
|
37
|
+
*/
|
|
38
|
+
get supportsTools() {
|
|
39
|
+
return this.backend === null;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Convert AgentMessage[] to ModelMessage[] for AI SDK
|
|
43
|
+
*/
|
|
44
|
+
toModelMessages() {
|
|
45
|
+
return this.messages.filter((m) => m.status !== "responding").map((m) => ({
|
|
46
|
+
role: m.role,
|
|
47
|
+
content: m.content
|
|
48
|
+
}));
|
|
49
|
+
}
|
|
50
|
+
constructor(config, restore) {
|
|
51
|
+
if (restore) {
|
|
52
|
+
this.id = restore.id;
|
|
53
|
+
this.createdAt = restore.createdAt;
|
|
54
|
+
this.messages = [...restore.messages];
|
|
55
|
+
this.totalUsage = { ...restore.totalUsage };
|
|
56
|
+
this.pendingApprovals = [...restore.pendingApprovals ?? []];
|
|
57
|
+
} else {
|
|
58
|
+
this.id = crypto.randomUUID();
|
|
59
|
+
this.createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
60
|
+
}
|
|
61
|
+
this.model = config.model;
|
|
62
|
+
this.system = config.system;
|
|
63
|
+
this.tools = config.tools ? { ...config.tools } : {};
|
|
64
|
+
this.approval = config.approval ? { ...config.approval } : {};
|
|
65
|
+
this.maxTokens = config.maxTokens ?? 4096;
|
|
66
|
+
this.maxSteps = config.maxSteps ?? 200;
|
|
67
|
+
this.backend = config.backend ?? null;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Check if a tool needs approval for given arguments
|
|
71
|
+
*/
|
|
72
|
+
checkApproval(name, args) {
|
|
73
|
+
const check = this.approval[name];
|
|
74
|
+
if (!check) return false;
|
|
75
|
+
if (typeof check === "function") return check(args);
|
|
76
|
+
return check;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Build tools with approval wrapping for ToolLoopAgent
|
|
80
|
+
*/
|
|
81
|
+
buildTools(autoApprove) {
|
|
82
|
+
if (Object.keys(this.tools).length === 0) return void 0;
|
|
83
|
+
if (autoApprove || Object.keys(this.approval).length === 0) return this.tools;
|
|
84
|
+
const wrapped = {};
|
|
85
|
+
for (const [name, t] of Object.entries(this.tools)) {
|
|
86
|
+
if (!this.approval[name]) {
|
|
87
|
+
wrapped[name] = t;
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
wrapped[name] = {
|
|
91
|
+
...t,
|
|
92
|
+
execute: async (args, options) => {
|
|
93
|
+
if (this.checkApproval(name, args)) {
|
|
94
|
+
const approval = {
|
|
95
|
+
id: crypto.randomUUID(),
|
|
96
|
+
toolName: name,
|
|
97
|
+
toolCallId: crypto.randomUUID(),
|
|
98
|
+
arguments: args,
|
|
99
|
+
requestedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
100
|
+
status: "pending"
|
|
101
|
+
};
|
|
102
|
+
this.pendingApprovals.push(approval);
|
|
103
|
+
return {
|
|
104
|
+
__approvalRequired: true,
|
|
105
|
+
approvalId: approval.id
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
return t.execute?.(args, options);
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
return wrapped;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Get or create cached agent, rebuild if tools changed
|
|
116
|
+
*/
|
|
117
|
+
async getAgent(autoApprove) {
|
|
118
|
+
if (!this.cachedAgent || this.toolsChanged || !autoApprove) {
|
|
119
|
+
this.cachedAgent = new ToolLoopAgent({
|
|
120
|
+
model: await createModelAsync(this.model),
|
|
121
|
+
instructions: this.system,
|
|
122
|
+
tools: this.buildTools(autoApprove),
|
|
123
|
+
maxOutputTokens: this.maxTokens,
|
|
124
|
+
stopWhen: stepCountIs(this.maxSteps)
|
|
125
|
+
});
|
|
126
|
+
if (autoApprove) this.toolsChanged = false;
|
|
127
|
+
}
|
|
128
|
+
return this.cachedAgent;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Send a message via CLI backend (non-SDK path)
|
|
132
|
+
*/
|
|
133
|
+
async sendViaBackend(content) {
|
|
134
|
+
const startTime = performance.now();
|
|
135
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
136
|
+
this.messages.push({
|
|
137
|
+
role: "user",
|
|
138
|
+
content,
|
|
139
|
+
status: "complete",
|
|
140
|
+
timestamp
|
|
141
|
+
});
|
|
142
|
+
const result = await this.backend.send(content, { system: this.system });
|
|
143
|
+
const latency = Math.round(performance.now() - startTime);
|
|
144
|
+
this.messages.push({
|
|
145
|
+
role: "assistant",
|
|
146
|
+
content: result.content,
|
|
147
|
+
status: "complete",
|
|
148
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
149
|
+
});
|
|
150
|
+
const usage = {
|
|
151
|
+
input: result.usage?.input ?? 0,
|
|
152
|
+
output: result.usage?.output ?? 0,
|
|
153
|
+
total: result.usage?.total ?? 0
|
|
154
|
+
};
|
|
155
|
+
this.totalUsage.input += usage.input;
|
|
156
|
+
this.totalUsage.output += usage.output;
|
|
157
|
+
this.totalUsage.total += usage.total;
|
|
158
|
+
const toolCalls = (result.toolCalls ?? []).map((tc) => ({
|
|
159
|
+
name: tc.name,
|
|
160
|
+
arguments: tc.arguments,
|
|
161
|
+
result: tc.result,
|
|
162
|
+
timing: 0
|
|
163
|
+
}));
|
|
164
|
+
return {
|
|
165
|
+
content: result.content,
|
|
166
|
+
toolCalls,
|
|
167
|
+
pendingApprovals: [],
|
|
168
|
+
usage,
|
|
169
|
+
latency
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Send a message and get the agent's response
|
|
174
|
+
*/
|
|
175
|
+
async send(content, options = {}) {
|
|
176
|
+
if (this.backend) return this.sendViaBackend(content);
|
|
177
|
+
const { autoApprove = true, onStepFinish } = options;
|
|
178
|
+
const startTime = performance.now();
|
|
179
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
180
|
+
this.messages.push({
|
|
181
|
+
role: "user",
|
|
182
|
+
content,
|
|
183
|
+
status: "complete",
|
|
184
|
+
timestamp
|
|
185
|
+
});
|
|
186
|
+
const agent = await this.getAgent(autoApprove);
|
|
187
|
+
const allToolCalls = [];
|
|
188
|
+
let stepNumber = 0;
|
|
189
|
+
const result = await agent.generate({
|
|
190
|
+
messages: this.toModelMessages(),
|
|
191
|
+
onStepFinish: async ({ usage, toolCalls, toolResults }) => {
|
|
192
|
+
stepNumber++;
|
|
193
|
+
const stepToolCalls = [];
|
|
194
|
+
if (toolCalls) for (const tc of toolCalls) {
|
|
195
|
+
const toolResult = toolResults?.find((tr) => tr.toolCallId === tc.toolCallId);
|
|
196
|
+
const toolCall = {
|
|
197
|
+
name: tc.toolName,
|
|
198
|
+
arguments: tc.input,
|
|
199
|
+
result: toolResult?.output ?? null,
|
|
200
|
+
timing: 0
|
|
201
|
+
};
|
|
202
|
+
stepToolCalls.push(toolCall);
|
|
203
|
+
allToolCalls.push(toolCall);
|
|
204
|
+
}
|
|
205
|
+
if (onStepFinish) {
|
|
206
|
+
const stepUsage = {
|
|
207
|
+
input: usage?.inputTokens ?? 0,
|
|
208
|
+
output: usage?.outputTokens ?? 0,
|
|
209
|
+
total: (usage?.inputTokens ?? 0) + (usage?.outputTokens ?? 0)
|
|
210
|
+
};
|
|
211
|
+
await onStepFinish({
|
|
212
|
+
stepNumber,
|
|
213
|
+
toolCalls: stepToolCalls,
|
|
214
|
+
usage: stepUsage
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
const latency = Math.round(performance.now() - startTime);
|
|
220
|
+
this.messages.push({
|
|
221
|
+
role: "assistant",
|
|
222
|
+
content: result.text,
|
|
223
|
+
status: "complete",
|
|
224
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
225
|
+
});
|
|
226
|
+
const usage = {
|
|
227
|
+
input: result.usage?.inputTokens ?? 0,
|
|
228
|
+
output: result.usage?.outputTokens ?? 0,
|
|
229
|
+
total: (result.usage?.inputTokens ?? 0) + (result.usage?.outputTokens ?? 0)
|
|
230
|
+
};
|
|
231
|
+
this.totalUsage.input += usage.input;
|
|
232
|
+
this.totalUsage.output += usage.output;
|
|
233
|
+
this.totalUsage.total += usage.total;
|
|
234
|
+
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.`);
|
|
235
|
+
const currentPending = this.pendingApprovals.filter((p) => p.status === "pending");
|
|
236
|
+
return {
|
|
237
|
+
content: result.text,
|
|
238
|
+
toolCalls: allToolCalls,
|
|
239
|
+
pendingApprovals: currentPending,
|
|
240
|
+
usage,
|
|
241
|
+
latency
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Send a message and stream the response
|
|
246
|
+
*/
|
|
247
|
+
async *sendStream(content, options = {}) {
|
|
248
|
+
if (this.backend) {
|
|
249
|
+
const response = await this.sendViaBackend(content);
|
|
250
|
+
yield response.content;
|
|
251
|
+
return response;
|
|
252
|
+
}
|
|
253
|
+
const { autoApprove = true, onStepFinish } = options;
|
|
254
|
+
const startTime = performance.now();
|
|
255
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
256
|
+
this.messages.push({
|
|
257
|
+
role: "user",
|
|
258
|
+
content,
|
|
259
|
+
status: "complete",
|
|
260
|
+
timestamp
|
|
261
|
+
});
|
|
262
|
+
const assistantMsg = {
|
|
263
|
+
role: "assistant",
|
|
264
|
+
content: "",
|
|
265
|
+
status: "responding",
|
|
266
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
267
|
+
};
|
|
268
|
+
this.messages.push(assistantMsg);
|
|
269
|
+
const agent = await this.getAgent(autoApprove);
|
|
270
|
+
const allToolCalls = [];
|
|
271
|
+
let stepNumber = 0;
|
|
272
|
+
const result = await agent.stream({
|
|
273
|
+
messages: this.toModelMessages(),
|
|
274
|
+
onStepFinish: async ({ usage, toolCalls, toolResults }) => {
|
|
275
|
+
stepNumber++;
|
|
276
|
+
const stepToolCalls = [];
|
|
277
|
+
if (toolCalls) for (const tc of toolCalls) {
|
|
278
|
+
const toolResult = toolResults?.find((tr) => tr.toolCallId === tc.toolCallId);
|
|
279
|
+
const toolCall = {
|
|
280
|
+
name: tc.toolName,
|
|
281
|
+
arguments: tc.input,
|
|
282
|
+
result: toolResult?.output ?? null,
|
|
283
|
+
timing: 0
|
|
284
|
+
};
|
|
285
|
+
stepToolCalls.push(toolCall);
|
|
286
|
+
allToolCalls.push(toolCall);
|
|
287
|
+
}
|
|
288
|
+
if (onStepFinish) {
|
|
289
|
+
const stepUsage = {
|
|
290
|
+
input: usage?.inputTokens ?? 0,
|
|
291
|
+
output: usage?.outputTokens ?? 0,
|
|
292
|
+
total: (usage?.inputTokens ?? 0) + (usage?.outputTokens ?? 0)
|
|
293
|
+
};
|
|
294
|
+
await onStepFinish({
|
|
295
|
+
stepNumber,
|
|
296
|
+
toolCalls: stepToolCalls,
|
|
297
|
+
usage: stepUsage
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
for await (const chunk of result.textStream) {
|
|
303
|
+
assistantMsg.content += chunk;
|
|
304
|
+
yield chunk;
|
|
305
|
+
}
|
|
306
|
+
const latency = Math.round(performance.now() - startTime);
|
|
307
|
+
const text = await result.text;
|
|
308
|
+
assistantMsg.content = text;
|
|
309
|
+
assistantMsg.status = "complete";
|
|
310
|
+
const finalUsage = await result.usage;
|
|
311
|
+
const usage = {
|
|
312
|
+
input: finalUsage?.inputTokens ?? 0,
|
|
313
|
+
output: finalUsage?.outputTokens ?? 0,
|
|
314
|
+
total: (finalUsage?.inputTokens ?? 0) + (finalUsage?.outputTokens ?? 0)
|
|
315
|
+
};
|
|
316
|
+
this.totalUsage.input += usage.input;
|
|
317
|
+
this.totalUsage.output += usage.output;
|
|
318
|
+
this.totalUsage.total += usage.total;
|
|
319
|
+
return {
|
|
320
|
+
content: text,
|
|
321
|
+
toolCalls: allToolCalls,
|
|
322
|
+
pendingApprovals: this.pendingApprovals.filter((p) => p.status === "pending"),
|
|
323
|
+
usage,
|
|
324
|
+
latency
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Add an AI SDK tool
|
|
329
|
+
* Only supported for SDK backends (ToolLoopAgent)
|
|
330
|
+
*/
|
|
331
|
+
addTool(name, t) {
|
|
332
|
+
if (this.backend) throw new Error("Tool management not supported for CLI backends");
|
|
333
|
+
this.tools[name] = t;
|
|
334
|
+
this.toolsChanged = true;
|
|
335
|
+
this.cachedAgent = null;
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Set approval requirement for a tool
|
|
339
|
+
*/
|
|
340
|
+
setApproval(name, check) {
|
|
341
|
+
this.approval[name] = check;
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Replace a tool's execute function (for testing)
|
|
345
|
+
*/
|
|
346
|
+
mockTool(name, mockFn) {
|
|
347
|
+
if (this.backend) throw new Error("Tool management not supported for CLI backends");
|
|
348
|
+
const t = this.tools[name];
|
|
349
|
+
if (!t) throw new Error(`Tool not found: ${name}`);
|
|
350
|
+
this.tools[name] = {
|
|
351
|
+
...t,
|
|
352
|
+
execute: mockFn
|
|
353
|
+
};
|
|
354
|
+
this.toolsChanged = true;
|
|
355
|
+
this.cachedAgent = null;
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Set a static mock response for an existing tool
|
|
359
|
+
*/
|
|
360
|
+
setMockResponse(name, response) {
|
|
361
|
+
if (this.backend) throw new Error("Tool management not supported for CLI backends");
|
|
362
|
+
const t = this.tools[name];
|
|
363
|
+
if (!t) throw new Error(`Tool not found: ${name}`);
|
|
364
|
+
this.tools[name] = {
|
|
365
|
+
...t,
|
|
366
|
+
execute: () => response
|
|
367
|
+
};
|
|
368
|
+
this.toolsChanged = true;
|
|
369
|
+
this.cachedAgent = null;
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Get tool info (names, descriptions, approval status)
|
|
373
|
+
*/
|
|
374
|
+
getTools() {
|
|
375
|
+
return Object.entries(this.tools).map(([name, t]) => {
|
|
376
|
+
return {
|
|
377
|
+
name,
|
|
378
|
+
description: t?.description,
|
|
379
|
+
needsApproval: !!this.approval[name]
|
|
380
|
+
};
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
history() {
|
|
384
|
+
return [...this.messages];
|
|
385
|
+
}
|
|
386
|
+
stats() {
|
|
387
|
+
return {
|
|
388
|
+
messageCount: this.messages.length,
|
|
389
|
+
usage: { ...this.totalUsage }
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
export() {
|
|
393
|
+
return {
|
|
394
|
+
sessionId: this.id,
|
|
395
|
+
model: this.model,
|
|
396
|
+
system: this.system,
|
|
397
|
+
messages: [...this.messages],
|
|
398
|
+
totalUsage: { ...this.totalUsage },
|
|
399
|
+
createdAt: this.createdAt
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
getState() {
|
|
403
|
+
return {
|
|
404
|
+
id: this.id,
|
|
405
|
+
createdAt: this.createdAt,
|
|
406
|
+
messages: [...this.messages],
|
|
407
|
+
totalUsage: { ...this.totalUsage },
|
|
408
|
+
pendingApprovals: [...this.pendingApprovals]
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
getPendingApprovals() {
|
|
412
|
+
return this.pendingApprovals.filter((p) => p.status === "pending");
|
|
413
|
+
}
|
|
414
|
+
async approve(approvalId) {
|
|
415
|
+
const approval = this.pendingApprovals.find((p) => p.id === approvalId);
|
|
416
|
+
if (!approval) throw new Error(`Approval not found: ${approvalId}`);
|
|
417
|
+
if (approval.status !== "pending") throw new Error(`Approval already ${approval.status}: ${approvalId}`);
|
|
418
|
+
const t = this.tools[approval.toolName];
|
|
419
|
+
if (!t) throw new Error(`Tool not found: ${approval.toolName}`);
|
|
420
|
+
let result;
|
|
421
|
+
const tool = t;
|
|
422
|
+
if (typeof tool.execute === "function") result = await tool.execute(approval.arguments);
|
|
423
|
+
else result = { error: "No implementation provided" };
|
|
424
|
+
approval.status = "approved";
|
|
425
|
+
return result;
|
|
426
|
+
}
|
|
427
|
+
deny(approvalId, reason) {
|
|
428
|
+
const approval = this.pendingApprovals.find((p) => p.id === approvalId);
|
|
429
|
+
if (!approval) throw new Error(`Approval not found: ${approvalId}`);
|
|
430
|
+
if (approval.status !== "pending") throw new Error(`Approval already ${approval.status}: ${approvalId}`);
|
|
431
|
+
approval.status = "denied";
|
|
432
|
+
approval.denyReason = reason;
|
|
433
|
+
}
|
|
434
|
+
clear() {
|
|
435
|
+
this.messages = [];
|
|
436
|
+
this.totalUsage = {
|
|
437
|
+
input: 0,
|
|
438
|
+
output: 0,
|
|
439
|
+
total: 0
|
|
440
|
+
};
|
|
441
|
+
this.pendingApprovals = [];
|
|
442
|
+
}
|
|
443
|
+
};
|
|
444
|
+
|
|
445
|
+
//#endregion
|
|
446
|
+
export { AgentWorker as t };
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { c as CONTEXT_DEFAULTS, i as resolveContextDir, n as createFileContextProvider, t as FileContextProvider } from "./cli/index.mjs";
|
|
3
|
-
import {
|
|
4
|
-
import { createChannelLogger, createSilentLogger } from "./logger-
|
|
1
|
+
import { A as createModelAsync, E as parseModel, a as createMockBackend, n as createBackend } from "./backends-DLaP0rMW.mjs";
|
|
2
|
+
import { T as EventLog, c as CONTEXT_DEFAULTS, i as resolveContextDir, n as createFileContextProvider, t as FileContextProvider, v as createContextMCPServer } from "./cli/index.mjs";
|
|
3
|
+
import { n as createMemoryContextProvider } from "./memory-provider-CBlKMdbJ.mjs";
|
|
4
|
+
import { createChannelLogger, createSilentLogger } from "./logger-CCFaMMV7.mjs";
|
|
5
5
|
import { generateText, jsonSchema, stepCountIs, tool } from "ai";
|
|
6
6
|
import { existsSync, mkdirSync, readFileSync } from "node:fs";
|
|
7
7
|
import { basename, dirname, join, resolve } from "node:path";
|
|
8
8
|
import { parse } from "yaml";
|
|
9
9
|
import { tmpdir } from "node:os";
|
|
10
10
|
import { exec, execSync } from "node:child_process";
|
|
11
|
+
import { randomUUID } from "node:crypto";
|
|
11
12
|
import { promisify } from "node:util";
|
|
12
13
|
import { createServer } from "node:http";
|
|
13
|
-
import { randomUUID } from "node:crypto";
|
|
14
14
|
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
15
15
|
import { MockLanguageModelV3, mockValues } from "ai/test";
|
|
16
16
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
@@ -236,14 +236,14 @@ function validateAgent(name, agent, errors) {
|
|
|
236
236
|
return;
|
|
237
237
|
}
|
|
238
238
|
const a = agent;
|
|
239
|
-
const backend = typeof a.backend === "string" ? a.backend : "
|
|
239
|
+
const backend = typeof a.backend === "string" ? a.backend : "default";
|
|
240
240
|
if (a.model !== void 0 && typeof a.model !== "string") errors.push({
|
|
241
241
|
path: `${path}.model`,
|
|
242
242
|
message: "Field \"model\" must be a string"
|
|
243
243
|
});
|
|
244
244
|
else if (!a.model && !CLI_BACKENDS.includes(backend)) errors.push({
|
|
245
245
|
path: `${path}.model`,
|
|
246
|
-
message: "Required field \"model\" must be a string (required for
|
|
246
|
+
message: "Required field \"model\" must be a string (required for default backend)"
|
|
247
247
|
});
|
|
248
248
|
if (a.system_prompt !== void 0 && typeof a.system_prompt !== "string") errors.push({
|
|
249
249
|
path: `${path}.system_prompt`,
|
|
@@ -779,7 +779,7 @@ function createBashTool() {
|
|
|
779
779
|
/**
|
|
780
780
|
* Run an SDK agent with real model + MCP tools + bash.
|
|
781
781
|
*
|
|
782
|
-
* Used by the controller when backend.type === '
|
|
782
|
+
* Used by the controller when backend.type === 'default'.
|
|
783
783
|
* Unlike the simple SdkBackend.send() (text-only), this runner:
|
|
784
784
|
* 1. Connects to MCP server for context tools (channel, document)
|
|
785
785
|
* 2. Adds bash tool for shell access
|
|
@@ -813,17 +813,8 @@ async function runSdkAgent(ctx, debugLog) {
|
|
|
813
813
|
stopWhen: stepCountIs(ctx.agent.max_steps ?? 200),
|
|
814
814
|
onStepFinish: (step) => {
|
|
815
815
|
_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
|
-
}
|
|
816
|
+
if (step.toolCalls?.length && ctx.eventLog) {
|
|
817
|
+
for (const tc of step.toolCalls) if (tc.toolName === "bash") ctx.eventLog.toolCall(ctx.name, tc.toolName, formatToolCall(tc), "sdk");
|
|
827
818
|
}
|
|
828
819
|
}
|
|
829
820
|
});
|
|
@@ -832,7 +823,7 @@ async function runSdkAgent(ctx, debugLog) {
|
|
|
832
823
|
if (ctx.agent.max_steps && result.steps.length >= ctx.agent.max_steps && (lastStep?.toolCalls?.length ?? 0) > 0) {
|
|
833
824
|
const warning = `⚠️ Agent reached max_steps limit (${ctx.agent.max_steps}) but wanted to continue. Consider increasing max_steps or removing the limit.`;
|
|
834
825
|
log(warning);
|
|
835
|
-
await ctx.provider.appendChannel(ctx.name, warning, { kind: "
|
|
826
|
+
await ctx.provider.appendChannel(ctx.name, warning, { kind: "system" }).catch(() => {});
|
|
836
827
|
}
|
|
837
828
|
await mcp.close();
|
|
838
829
|
return {
|
|
@@ -868,7 +859,7 @@ function shouldContinue(state) {
|
|
|
868
859
|
* 5. Can be woken early via wake()
|
|
869
860
|
*/
|
|
870
861
|
function createAgentController(config) {
|
|
871
|
-
const { name, agent, contextProvider, mcpUrl, workspaceDir, projectDir, backend, onRunComplete, log = () => {}, feedback } = config;
|
|
862
|
+
const { name, agent, contextProvider, eventLog, mcpUrl, workspaceDir, projectDir, backend, onRunComplete, log = () => {}, feedback } = config;
|
|
872
863
|
const infoLog = config.infoLog ?? log;
|
|
873
864
|
const errorLog = config.errorLog ?? log;
|
|
874
865
|
const pollInterval = config.pollInterval ?? CONTROLLER_DEFAULTS.pollInterval;
|
|
@@ -934,6 +925,7 @@ function createAgentController(config) {
|
|
|
934
925
|
projectDir,
|
|
935
926
|
retryAttempt: attempt,
|
|
936
927
|
provider: contextProvider,
|
|
928
|
+
eventLog,
|
|
937
929
|
feedback
|
|
938
930
|
}, log, infoLog);
|
|
939
931
|
if (lastResult.success) {
|
|
@@ -1016,7 +1008,7 @@ function createAgentController(config) {
|
|
|
1016
1008
|
async function runAgent(backend, ctx, log, infoLog) {
|
|
1017
1009
|
const info = infoLog ?? log;
|
|
1018
1010
|
if (backend.type === "mock") return runMockAgent(ctx, (msg) => log(msg));
|
|
1019
|
-
if (backend.type === "
|
|
1011
|
+
if (backend.type === "default") return runSdkAgent(ctx, (msg) => log(msg));
|
|
1020
1012
|
const startTime = Date.now();
|
|
1021
1013
|
try {
|
|
1022
1014
|
if (backend.setWorkspace) {
|
|
@@ -1067,8 +1059,7 @@ function getBackendByType(backendType, options) {
|
|
|
1067
1059
|
if (backendType === "mock") return createMockBackend(options?.debugLog);
|
|
1068
1060
|
const backendOptions = {};
|
|
1069
1061
|
if (options?.timeout) backendOptions.timeout = options.timeout;
|
|
1070
|
-
if (options?.
|
|
1071
|
-
if (options?.messageLog) backendOptions.messageLog = options.messageLog;
|
|
1062
|
+
if (options?.streamCallbacks) backendOptions.streamCallbacks = options.streamCallbacks;
|
|
1072
1063
|
return createBackend({
|
|
1073
1064
|
type: backendType,
|
|
1074
1065
|
model: options?.model,
|
|
@@ -1084,7 +1075,7 @@ function getBackendByType(backendType, options) {
|
|
|
1084
1075
|
function getBackendForModel(model, options) {
|
|
1085
1076
|
const { provider } = parseModel(model);
|
|
1086
1077
|
switch (provider) {
|
|
1087
|
-
case "anthropic": return getBackendByType("
|
|
1078
|
+
case "anthropic": return getBackendByType("default", {
|
|
1088
1079
|
...options,
|
|
1089
1080
|
model
|
|
1090
1081
|
});
|
|
@@ -1354,9 +1345,11 @@ function startChannelWatcher(config) {
|
|
|
1354
1345
|
* Workflow Runner
|
|
1355
1346
|
*
|
|
1356
1347
|
* All output flows through the channel:
|
|
1357
|
-
* - Operational events (init, setup, connect) → kind="
|
|
1348
|
+
* - Operational events (init, setup, connect) → kind="system" (always visible)
|
|
1358
1349
|
* - Debug details (MCP traces, idle checks) → kind="debug" (visible with --debug)
|
|
1359
|
-
* - Agent messages → kind=undefined (always visible)
|
|
1350
|
+
* - Agent messages → kind="message" or undefined (always visible)
|
|
1351
|
+
* - Tool calls → kind="tool_call" with structured metadata
|
|
1352
|
+
* - Backend text output → kind="output" (always visible)
|
|
1360
1353
|
*
|
|
1361
1354
|
* The display layer (display.ts) handles filtering and formatting.
|
|
1362
1355
|
*/
|
|
@@ -1421,6 +1414,8 @@ async function initWorkflow(config) {
|
|
|
1421
1414
|
}
|
|
1422
1415
|
const projectDir = process.cwd();
|
|
1423
1416
|
let mcpGetFeedback;
|
|
1417
|
+
let mcpToolNames = /* @__PURE__ */ new Set();
|
|
1418
|
+
const eventLog = new EventLog(contextProvider);
|
|
1424
1419
|
const createMCPServerInstance = () => {
|
|
1425
1420
|
const mcp = createContextMCPServer({
|
|
1426
1421
|
provider: contextProvider,
|
|
@@ -1432,6 +1427,7 @@ async function initWorkflow(config) {
|
|
|
1432
1427
|
debugLog
|
|
1433
1428
|
});
|
|
1434
1429
|
mcpGetFeedback = mcp.getFeedback;
|
|
1430
|
+
mcpToolNames = mcp.mcpToolNames;
|
|
1435
1431
|
return mcp.server;
|
|
1436
1432
|
};
|
|
1437
1433
|
const httpMcpServer = await runWithHttp({
|
|
@@ -1468,9 +1464,11 @@ async function initWorkflow(config) {
|
|
|
1468
1464
|
contextDir,
|
|
1469
1465
|
projectDir,
|
|
1470
1466
|
contextProvider,
|
|
1467
|
+
eventLog,
|
|
1471
1468
|
httpMcpServer,
|
|
1472
1469
|
mcpUrl: httpMcpServer.url,
|
|
1473
1470
|
agentNames,
|
|
1471
|
+
mcpToolNames,
|
|
1474
1472
|
setupResults,
|
|
1475
1473
|
async sendKickoff() {
|
|
1476
1474
|
if (!interpolatedKickoff) {
|
|
@@ -1574,23 +1572,23 @@ async function runWorkflowWithControllers(config) {
|
|
|
1574
1572
|
model: agentDef.model
|
|
1575
1573
|
});
|
|
1576
1574
|
const agentLogger = logger.child(agentName);
|
|
1577
|
-
const
|
|
1578
|
-
agentLogger.debug(msg)
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1575
|
+
const streamCallbacks = {
|
|
1576
|
+
debugLog: (msg) => agentLogger.debug(msg),
|
|
1577
|
+
outputLog: (msg) => runtime.eventLog.output(agentName, msg),
|
|
1578
|
+
toolCallLog: (name, args) => runtime.eventLog.toolCall(agentName, name, args, "backend"),
|
|
1579
|
+
mcpToolNames: runtime.mcpToolNames
|
|
1582
1580
|
};
|
|
1583
1581
|
let backend;
|
|
1584
1582
|
if (createBackend) backend = createBackend(agentName, agentDef);
|
|
1585
1583
|
else if (agentDef.backend) backend = getBackendByType(agentDef.backend, {
|
|
1586
1584
|
model: agentDef.model,
|
|
1587
|
-
debugLog:
|
|
1588
|
-
|
|
1585
|
+
debugLog: (msg) => agentLogger.debug(msg),
|
|
1586
|
+
streamCallbacks,
|
|
1589
1587
|
timeout: agentDef.timeout
|
|
1590
1588
|
});
|
|
1591
1589
|
else if (agentDef.model) backend = getBackendForModel(agentDef.model, {
|
|
1592
|
-
debugLog:
|
|
1593
|
-
|
|
1590
|
+
debugLog: (msg) => agentLogger.debug(msg),
|
|
1591
|
+
streamCallbacks
|
|
1594
1592
|
});
|
|
1595
1593
|
else throw new Error(`Agent "${agentName}" requires either a backend or model field`);
|
|
1596
1594
|
logger.debug(`Using backend: ${backend.type} for ${agentName}`);
|
|
@@ -1601,6 +1599,7 @@ async function runWorkflowWithControllers(config) {
|
|
|
1601
1599
|
name: agentName,
|
|
1602
1600
|
agent: agentDef,
|
|
1603
1601
|
contextProvider: runtime.contextProvider,
|
|
1602
|
+
eventLog: runtime.eventLog,
|
|
1604
1603
|
mcpUrl: runtime.mcpUrl,
|
|
1605
1604
|
workspaceDir,
|
|
1606
1605
|
projectDir: runtime.projectDir,
|
|
@@ -1620,7 +1619,7 @@ async function runWorkflowWithControllers(config) {
|
|
|
1620
1619
|
logger.debug("Kickoff sent");
|
|
1621
1620
|
let channelWatcher;
|
|
1622
1621
|
if (config.prettyDisplay) {
|
|
1623
|
-
const { startPrettyDisplay } = await import("./display-pretty-
|
|
1622
|
+
const { startPrettyDisplay } = await import("./display-pretty-BsCsnPqs.mjs");
|
|
1624
1623
|
channelWatcher = startPrettyDisplay({
|
|
1625
1624
|
contextProvider: runtime.contextProvider,
|
|
1626
1625
|
agentNames: runtime.agentNames,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-worker",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "SDK and CLI for creating and testing agent workers with Vercel AI SDK",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.mjs",
|
|
@@ -37,6 +37,8 @@
|
|
|
37
37
|
"chalk": "^5.6.2",
|
|
38
38
|
"commander": "^14.0.3",
|
|
39
39
|
"execa": "^9.6.1",
|
|
40
|
+
"@hono/node-server": "^1.19.9",
|
|
41
|
+
"hono": "^4.11.9",
|
|
40
42
|
"just-bash": "^2.8.0",
|
|
41
43
|
"nanoid": "^5.1.6",
|
|
42
44
|
"picocolors": "^1.1.1",
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import { C as SDK_MODEL_ALIASES, S as CURSOR_MODEL_MAP, _ as execWithIdleTimeout, a as createMockBackend, b as CLAUDE_MODEL_MAP, c as CodexBackend, d as codexAdapter, f as createStreamParser, g as IdleTimeoutError, h as formatEvent, i as MockAIBackend, l as ClaudeCodeBackend, m as extractCodexResult, n as createBackend, o as SdkBackend, p as extractClaudeResult, r as listBackends, s as CursorBackend, t as checkBackends, u as claudeAdapter, v as DEFAULT_IDLE_TIMEOUT, w as getModelForBackend, x as CODEX_MODEL_MAP, y as BACKEND_DEFAULT_MODELS } from "./backends-BOAkfYyL.mjs";
|
|
2
|
-
|
|
3
|
-
export { listBackends };
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import { _ as shouldUseResource, a as FileStorage, c as CONTEXT_DEFAULTS, d as RESOURCE_PREFIX, f as RESOURCE_SCHEME, g as generateResourceId, h as extractMentions, i as resolveContextDir, l as MENTION_PATTERN, m as createResourceRef, n as createFileContextProvider, o as MemoryStorage, p as calculatePriority, r as getDefaultContextDir, s as ContextProviderImpl, t as FileContextProvider, u as MESSAGE_LENGTH_THRESHOLD } from "./cli/index.mjs";
|
|
2
|
-
import { a as createMemoryContextProvider, i as MemoryContextProvider, n as formatProposal, r as formatProposalList, t as createContextMCPServer } from "./mcp-server-BQCQxv2v.mjs";
|
|
3
|
-
|
|
4
|
-
export { createFileContextProvider };
|