@n8n/agents 0.10.1 → 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.
- package/dist/build.tsbuildinfo +1 -1
- package/dist/index.d.ts +10 -2
- package/dist/index.js +36 -5
- package/dist/index.js.map +1 -1
- package/dist/runtime/agent-runtime.d.ts +14 -6
- package/dist/runtime/agent-runtime.js +359 -267
- package/dist/runtime/agent-runtime.js.map +1 -1
- package/dist/runtime/delegate-sub-agent-tool.d.ts +87 -0
- package/dist/runtime/delegate-sub-agent-tool.js +362 -0
- package/dist/runtime/delegate-sub-agent-tool.js.map +1 -0
- package/dist/runtime/event-bus.d.ts +8 -0
- package/dist/runtime/event-bus.js +48 -0
- package/dist/runtime/event-bus.js.map +1 -1
- package/dist/runtime/mcp-connection.d.ts +2 -3
- package/dist/runtime/mcp-connection.js +3 -6
- package/dist/runtime/mcp-connection.js.map +1 -1
- package/dist/runtime/message-list.d.ts +9 -3
- package/dist/runtime/message-list.js +16 -5
- package/dist/runtime/message-list.js.map +1 -1
- package/dist/runtime/messages.js +10 -2
- package/dist/runtime/messages.js.map +1 -1
- package/dist/runtime/model-factory.js +12 -0
- package/dist/runtime/model-factory.js.map +1 -1
- package/dist/runtime/provider-credentials.d.ts +13 -0
- package/dist/runtime/provider-credentials.js +1 -0
- package/dist/runtime/provider-credentials.js.map +1 -1
- package/dist/runtime/runtime-helpers.d.ts +1 -2
- package/dist/runtime/runtime-helpers.js +0 -8
- package/dist/runtime/runtime-helpers.js.map +1 -1
- package/dist/runtime/sdk-owned-tool.d.ts +4 -0
- package/dist/runtime/sdk-owned-tool.js +19 -0
- package/dist/runtime/sdk-owned-tool.js.map +1 -0
- package/dist/runtime/stream.js +8 -0
- package/dist/runtime/stream.js.map +1 -1
- package/dist/runtime/sub-agent-task-path.d.ts +10 -0
- package/dist/runtime/sub-agent-task-path.js +39 -0
- package/dist/runtime/sub-agent-task-path.js.map +1 -0
- package/dist/runtime/title-generation.js +8 -5
- package/dist/runtime/title-generation.js.map +1 -1
- package/dist/runtime/tool-adapter.d.ts +0 -9
- package/dist/runtime/tool-adapter.js +12 -21
- package/dist/runtime/tool-adapter.js.map +1 -1
- package/dist/runtime/write-todos-tool.d.ts +3 -0
- package/dist/runtime/write-todos-tool.js +95 -0
- package/dist/runtime/write-todos-tool.js.map +1 -0
- package/dist/sdk/agent.d.ts +19 -12
- package/dist/sdk/agent.js +318 -91
- package/dist/sdk/agent.js.map +1 -1
- package/dist/sdk/cancellation.d.ts +7 -0
- package/dist/sdk/cancellation.js +16 -0
- package/dist/sdk/cancellation.js.map +1 -0
- package/dist/sdk/catalog.js +40 -4
- package/dist/sdk/catalog.js.map +1 -1
- package/dist/sdk/guardrails/index.d.ts +5 -0
- package/dist/sdk/guardrails/index.js +15 -0
- package/dist/sdk/guardrails/index.js.map +1 -0
- package/dist/sdk/guardrails/patterns.d.ts +13 -0
- package/dist/sdk/guardrails/patterns.js +61 -0
- package/dist/sdk/guardrails/patterns.js.map +1 -0
- package/dist/sdk/guardrails/redactor.d.ts +24 -0
- package/dist/sdk/guardrails/redactor.js +86 -0
- package/dist/sdk/guardrails/redactor.js.map +1 -0
- package/dist/sdk/guardrails/streaming-redactor.d.ts +9 -0
- package/dist/sdk/guardrails/streaming-redactor.js +43 -0
- package/dist/sdk/guardrails/streaming-redactor.js.map +1 -0
- package/dist/sdk/mcp-client.d.ts +1 -1
- package/dist/sdk/mcp-client.js +2 -2
- package/dist/sdk/mcp-client.js.map +1 -1
- package/dist/sdk/memory.d.ts +1 -3
- package/dist/sdk/memory.js +0 -14
- package/dist/sdk/memory.js.map +1 -1
- package/dist/sdk/provider-capabilities.js +1 -0
- package/dist/sdk/provider-capabilities.js.map +1 -1
- package/dist/sdk/tool.d.ts +3 -0
- package/dist/sdk/tool.js +42 -10
- package/dist/sdk/tool.js.map +1 -1
- package/dist/storage/base-memory.d.ts +0 -31
- package/dist/storage/base-memory.js +0 -9
- package/dist/storage/base-memory.js.map +1 -1
- package/dist/types/index.d.ts +2 -2
- package/dist/types/index.js.map +1 -1
- package/dist/types/runtime/event.d.ts +31 -1
- package/dist/types/runtime/event.js +2 -0
- package/dist/types/runtime/event.js.map +1 -1
- package/dist/types/sdk/agent-builder.d.ts +0 -1
- package/dist/types/sdk/agent.d.ts +20 -15
- package/dist/types/sdk/guardrail.d.ts +1 -1
- package/dist/types/sdk/memory.d.ts +0 -42
- package/dist/types/sdk/message.d.ts +1 -0
- package/dist/types/sdk/tool.d.ts +19 -1
- package/dist/utils/json-schema.d.ts +3 -0
- package/dist/utils/json-schema.js +72 -0
- package/dist/utils/json-schema.js.map +1 -0
- package/dist/workspace/filesystem/daytona-filesystem.d.ts +25 -0
- package/dist/workspace/filesystem/daytona-filesystem.js +130 -0
- package/dist/workspace/filesystem/daytona-filesystem.js.map +1 -0
- package/dist/workspace/filesystem/n8n-sandbox-filesystem.d.ts +25 -0
- package/dist/workspace/filesystem/n8n-sandbox-filesystem.js +126 -0
- package/dist/workspace/filesystem/n8n-sandbox-filesystem.js.map +1 -0
- package/dist/workspace/sandbox/create-workspace.d.ts +4 -0
- package/dist/workspace/sandbox/create-workspace.js +68 -0
- package/dist/workspace/sandbox/create-workspace.js.map +1 -0
- package/dist/workspace/sandbox/daytona-auth-manager.d.ts +26 -0
- package/dist/workspace/sandbox/daytona-auth-manager.js +84 -0
- package/dist/workspace/sandbox/daytona-auth-manager.js.map +1 -0
- package/dist/workspace/sandbox/daytona-sandbox.d.ts +72 -0
- package/dist/workspace/sandbox/daytona-sandbox.js +357 -0
- package/dist/workspace/sandbox/daytona-sandbox.js.map +1 -0
- package/dist/workspace/sandbox/index.d.ts +7 -0
- package/dist/workspace/sandbox/index.js +22 -0
- package/dist/workspace/sandbox/index.js.map +1 -0
- package/dist/workspace/sandbox/lazy-daytona.d.ts +2 -0
- package/dist/workspace/sandbox/lazy-daytona.js +12 -0
- package/dist/workspace/sandbox/lazy-daytona.js.map +1 -0
- package/dist/workspace/sandbox/logger.d.ts +12 -0
- package/dist/workspace/sandbox/logger.js +3 -0
- package/dist/workspace/sandbox/logger.js.map +1 -0
- package/dist/workspace/sandbox/n8n-sandbox-sandbox.d.ts +35 -0
- package/dist/workspace/sandbox/n8n-sandbox-sandbox.js +138 -0
- package/dist/workspace/sandbox/n8n-sandbox-sandbox.js.map +1 -0
- package/dist/workspace/sandbox/provider.d.ts +4 -0
- package/dist/workspace/sandbox/provider.js +14 -0
- package/dist/workspace/sandbox/provider.js.map +1 -0
- package/dist/workspace/sandbox/run-in-sandbox.d.ts +26 -0
- package/dist/workspace/sandbox/run-in-sandbox.js +19 -0
- package/dist/workspace/sandbox/run-in-sandbox.js.map +1 -0
- package/dist/workspace/sandbox/types.d.ts +45 -0
- package/dist/workspace/sandbox/types.js +3 -0
- package/dist/workspace/sandbox/types.js.map +1 -0
- package/dist/workspace/sandbox/workspace-root.d.ts +16 -0
- package/dist/workspace/sandbox/workspace-root.js +69 -0
- package/dist/workspace/sandbox/workspace-root.js.map +1 -0
- package/dist/workspace/tools/batch-str-replace-file.js +2 -2
- package/dist/workspace/tools/batch-str-replace-file.js.map +1 -1
- package/dist/workspace/tools/str-replace-file.js +2 -2
- package/dist/workspace/tools/str-replace-file.js.map +1 -1
- package/package.json +29 -17
- package/dist/sdk/network.d.ts +0 -20
- package/dist/sdk/network.js +0 -46
- package/dist/sdk/network.js.map +0 -1
|
@@ -6,6 +6,7 @@ const catalog_1 = require("../sdk/catalog");
|
|
|
6
6
|
const message_1 = require("../sdk/message");
|
|
7
7
|
const background_task_tracker_1 = require("./background-task-tracker");
|
|
8
8
|
const deferred_tool_manager_1 = require("./deferred-tool-manager");
|
|
9
|
+
const delegate_sub_agent_tool_1 = require("./delegate-sub-agent-tool");
|
|
9
10
|
const episodic_memory_1 = require("./episodic-memory");
|
|
10
11
|
const event_bus_1 = require("./event-bus");
|
|
11
12
|
const execution_counter_1 = require("./execution-counter");
|
|
@@ -26,9 +27,12 @@ const runtime_helpers_1 = require("./runtime-helpers");
|
|
|
26
27
|
const scoped_memory_task_runner_1 = require("./scoped-memory-task-runner");
|
|
27
28
|
const stream_1 = require("./stream");
|
|
28
29
|
const strip_orphaned_tool_messages_1 = require("./strip-orphaned-tool-messages");
|
|
30
|
+
const sub_agent_task_path_1 = require("./sub-agent-task-path");
|
|
29
31
|
const title_generation_1 = require("./title-generation");
|
|
30
32
|
const tool_adapter_1 = require("./tool-adapter");
|
|
33
|
+
const cancellation_1 = require("../sdk/cancellation");
|
|
31
34
|
const telemetry_1 = require("../sdk/telemetry");
|
|
35
|
+
const json_schema_1 = require("../utils/json-schema");
|
|
32
36
|
const parse_1 = require("../utils/parse");
|
|
33
37
|
const zod_1 = require("../utils/zod");
|
|
34
38
|
function isActiveSpanTracer(value) {
|
|
@@ -56,9 +60,7 @@ function summarizeToolForTelemetry(tool) {
|
|
|
56
60
|
description: tool.description,
|
|
57
61
|
type: tool.mcpTool ? 'mcp' : 'local',
|
|
58
62
|
...(tool.mcpServerName ? { mcp_server: tool.mcpServerName } : {}),
|
|
59
|
-
...(tool.suspendSchema || tool.resumeSchema || tool.
|
|
60
|
-
? { approval: true }
|
|
61
|
-
: {}),
|
|
63
|
+
...(tool.suspendSchema || tool.resumeSchema || tool.approval ? { approval: true } : {}),
|
|
62
64
|
...(tool.inputSchema ? { input_schema: getToolInputSchema(tool) } : {}),
|
|
63
65
|
};
|
|
64
66
|
}
|
|
@@ -72,6 +74,23 @@ function summarizeProviderToolForTelemetry(tool) {
|
|
|
72
74
|
...(tool.inputSchema ? { input_schema: getToolInputSchema(tool) } : {}),
|
|
73
75
|
};
|
|
74
76
|
}
|
|
77
|
+
function isDeniedApprovalResumeData(value) {
|
|
78
|
+
return value !== null && typeof value === 'object' && Reflect.get(value, 'approved') === false;
|
|
79
|
+
}
|
|
80
|
+
function shouldEmitToolExecutionStart(tool, resumeData) {
|
|
81
|
+
if (!tool.approval)
|
|
82
|
+
return true;
|
|
83
|
+
if (!tool.approval.required && tool.approval.conditional !== true)
|
|
84
|
+
return true;
|
|
85
|
+
if (resumeData === undefined)
|
|
86
|
+
return false;
|
|
87
|
+
return !isDeniedApprovalResumeData(resumeData);
|
|
88
|
+
}
|
|
89
|
+
function getToolResumeJsonSchema(tool) {
|
|
90
|
+
if (!tool.resumeSchema)
|
|
91
|
+
return undefined;
|
|
92
|
+
return (0, zod_1.isZodSchema)(tool.resumeSchema) ? (0, zod_to_json_schema_1.zodToJsonSchema)(tool.resumeSchema) : tool.resumeSchema;
|
|
93
|
+
}
|
|
75
94
|
function buildAgentRootInputAttributes(config) {
|
|
76
95
|
const localTools = (config.tools ?? []).map(summarizeToolForTelemetry);
|
|
77
96
|
const providerTools = (config.providerTools ?? []).map(summarizeProviderToolForTelemetry);
|
|
@@ -115,11 +134,13 @@ class AgentRuntime {
|
|
|
115
134
|
this.backgroundTasks = new background_task_tracker_1.BackgroundTaskTracker();
|
|
116
135
|
this.episodicMemoryTasksByResource = new Map();
|
|
117
136
|
this.config = config;
|
|
137
|
+
this.runId = config.runId ?? (0, run_state_1.generateRunId)();
|
|
118
138
|
if (config.deferredTools && config.deferredTools.length > 0) {
|
|
119
139
|
this.deferredToolManager = new deferred_tool_manager_1.DeferredToolManager(config.deferredTools, config.toolSearch);
|
|
120
140
|
}
|
|
121
|
-
this.runState = new run_state_1.RunStateManager(config.checkpointStorage);
|
|
141
|
+
this.runState = config.runState ?? new run_state_1.RunStateManager(config.checkpointStorage);
|
|
122
142
|
this.eventBus = config.eventBus ?? new event_bus_1.AgentEventBus();
|
|
143
|
+
this.modelCost = config.modelCost;
|
|
123
144
|
this.currentState = {
|
|
124
145
|
persistence: undefined,
|
|
125
146
|
status: 'idle',
|
|
@@ -131,6 +152,7 @@ class AgentRuntime {
|
|
|
131
152
|
this.config.telemetry = telemetry;
|
|
132
153
|
}
|
|
133
154
|
async dispose() {
|
|
155
|
+
this.eventBus.dispose();
|
|
134
156
|
await this.backgroundTasks.flush();
|
|
135
157
|
}
|
|
136
158
|
getState() {
|
|
@@ -140,44 +162,59 @@ class AgentRuntime {
|
|
|
140
162
|
this.eventBus.abort();
|
|
141
163
|
}
|
|
142
164
|
async generate(input, options) {
|
|
143
|
-
const
|
|
165
|
+
const abortScope = this.eventBus.createAbortScope(options?.abortSignal);
|
|
144
166
|
let list = undefined;
|
|
145
167
|
try {
|
|
146
168
|
const initializedList = await this.initRun(input, options);
|
|
147
169
|
list = initializedList;
|
|
148
|
-
const rawResult = await this.withTelemetryRootSpan('generate', options, runId, async () => await this.runGenerateLoop({ list: initializedList, options,
|
|
149
|
-
return this.finalizeGenerate(rawResult, list
|
|
170
|
+
const rawResult = await this.withTelemetryRootSpan('generate', options, this.runId, async () => await this.runGenerateLoop({ list: initializedList, options, abortScope }));
|
|
171
|
+
return this.finalizeGenerate(rawResult, list);
|
|
150
172
|
}
|
|
151
173
|
catch (error) {
|
|
152
174
|
await this.flushTelemetry(options);
|
|
153
|
-
const isAbort =
|
|
175
|
+
const isAbort = abortScope.isAborted;
|
|
154
176
|
this.updateState({ status: isAbort ? 'cancelled' : 'failed' });
|
|
155
177
|
if (!isAbort) {
|
|
156
178
|
this.eventBus.emit({ type: "error", message: String(error), error });
|
|
157
179
|
}
|
|
158
|
-
return {
|
|
180
|
+
return {
|
|
181
|
+
runId: this.runId,
|
|
182
|
+
messages: list?.responseDelta() ?? [],
|
|
183
|
+
finishReason: 'error',
|
|
184
|
+
error,
|
|
185
|
+
getState: () => this.getState(),
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
finally {
|
|
189
|
+
abortScope.dispose();
|
|
159
190
|
}
|
|
160
191
|
}
|
|
161
192
|
async stream(input, options) {
|
|
162
|
-
const
|
|
193
|
+
const abortScope = this.eventBus.createAbortScope(options?.abortSignal);
|
|
163
194
|
let list;
|
|
164
195
|
try {
|
|
165
196
|
list = await this.initRun(input, options);
|
|
166
197
|
}
|
|
167
198
|
catch (error) {
|
|
168
|
-
const isAbort =
|
|
199
|
+
const isAbort = abortScope.isAborted;
|
|
169
200
|
this.updateState({ status: isAbort ? 'cancelled' : 'failed' });
|
|
170
201
|
if (!isAbort) {
|
|
171
202
|
this.eventBus.emit({ type: "error", message: String(error), error });
|
|
172
203
|
}
|
|
173
|
-
|
|
204
|
+
abortScope.dispose();
|
|
205
|
+
return { runId: this.runId, stream: (0, runtime_helpers_1.makeErrorStream)(error), getState: () => this.getState() };
|
|
174
206
|
}
|
|
175
|
-
return {
|
|
207
|
+
return {
|
|
208
|
+
runId: this.runId,
|
|
209
|
+
stream: this.startStreamLoop({ list, options, abortScope }),
|
|
210
|
+
getState: () => this.getState(),
|
|
211
|
+
};
|
|
176
212
|
}
|
|
177
213
|
async resume(method, data, options) {
|
|
178
|
-
|
|
214
|
+
this.runId = options.runId;
|
|
215
|
+
const state = await this.runState.resume(this.runId);
|
|
179
216
|
if (!state)
|
|
180
|
-
throw new Error(`No suspended run found for runId: ${
|
|
217
|
+
throw new Error(`No suspended run found for runId: ${this.runId}`);
|
|
181
218
|
const toolCall = state.pendingToolCalls[options.toolCallId];
|
|
182
219
|
if (!toolCall)
|
|
183
220
|
throw new Error(`No tool call found for toolCallId: ${options.toolCallId}`);
|
|
@@ -187,7 +224,8 @@ class AgentRuntime {
|
|
|
187
224
|
if (!toolForValidation)
|
|
188
225
|
throw new Error(`Tool ${toolCall.toolName} not found`);
|
|
189
226
|
let resumeData = data;
|
|
190
|
-
|
|
227
|
+
let abortScope;
|
|
228
|
+
if (!(0, cancellation_1.isCancellation)(resumeData) && toolForValidation.resumeSchema) {
|
|
191
229
|
const parseResult = await (0, parse_1.parseWithSchema)(toolForValidation.resumeSchema, data);
|
|
192
230
|
if (!parseResult.success) {
|
|
193
231
|
throw new Error(`Invalid resume payload: ${parseResult.error}`);
|
|
@@ -217,7 +255,8 @@ class AgentRuntime {
|
|
|
217
255
|
persistence: state.persistence,
|
|
218
256
|
...mergedExecOptions,
|
|
219
257
|
};
|
|
220
|
-
this.eventBus.
|
|
258
|
+
abortScope = this.eventBus.createAbortScope(resumeOptions.abortSignal);
|
|
259
|
+
const activeAbortScope = abortScope;
|
|
221
260
|
const pendingResume = {
|
|
222
261
|
pendingToolCalls: state.pendingToolCalls,
|
|
223
262
|
resumeToolCallId: options.toolCallId,
|
|
@@ -227,42 +266,50 @@ class AgentRuntime {
|
|
|
227
266
|
await this.ensureModelCost();
|
|
228
267
|
await this.setListObservationLogMemory(list, state.persistence);
|
|
229
268
|
if (method === 'generate') {
|
|
230
|
-
const rawResult = await this.withTelemetryRootSpan('generate', resumeOptions,
|
|
269
|
+
const rawResult = await this.withTelemetryRootSpan('generate', resumeOptions, this.runId, async () => await this.runGenerateLoop({
|
|
231
270
|
list,
|
|
232
271
|
options: resumeOptions,
|
|
233
|
-
|
|
272
|
+
abortScope: activeAbortScope,
|
|
234
273
|
pendingResume,
|
|
235
274
|
}));
|
|
236
275
|
if (!rawResult.pendingSuspend) {
|
|
237
|
-
await this.cleanupRun(
|
|
276
|
+
await this.cleanupRun();
|
|
277
|
+
}
|
|
278
|
+
try {
|
|
279
|
+
return this.finalizeGenerate(rawResult, list);
|
|
280
|
+
}
|
|
281
|
+
finally {
|
|
282
|
+
abortScope.dispose();
|
|
238
283
|
}
|
|
239
|
-
return this.finalizeGenerate(rawResult, list, options.runId);
|
|
240
284
|
}
|
|
241
285
|
return {
|
|
242
|
-
runId:
|
|
286
|
+
runId: this.runId,
|
|
243
287
|
stream: this.startStreamLoop({
|
|
244
288
|
list,
|
|
245
289
|
options: resumeOptions,
|
|
246
|
-
|
|
290
|
+
abortScope: activeAbortScope,
|
|
247
291
|
pendingResume,
|
|
248
292
|
}),
|
|
293
|
+
getState: () => this.getState(),
|
|
249
294
|
};
|
|
250
295
|
}
|
|
251
296
|
catch (error) {
|
|
252
|
-
const isAbort =
|
|
297
|
+
const isAbort = abortScope?.isAborted ?? false;
|
|
298
|
+
abortScope?.dispose();
|
|
253
299
|
this.updateState({ status: isAbort ? 'cancelled' : 'failed' });
|
|
254
300
|
if (!isAbort) {
|
|
255
301
|
this.eventBus.emit({ type: "error", message: String(error), error });
|
|
256
302
|
}
|
|
257
303
|
if (method === 'generate') {
|
|
258
304
|
return {
|
|
259
|
-
runId:
|
|
305
|
+
runId: this.runId,
|
|
260
306
|
messages: [],
|
|
261
307
|
finishReason: 'error',
|
|
262
308
|
error,
|
|
309
|
+
getState: () => this.getState(),
|
|
263
310
|
};
|
|
264
311
|
}
|
|
265
|
-
return { runId:
|
|
312
|
+
return { runId: this.runId, stream: (0, runtime_helpers_1.makeErrorStream)(error), getState: () => this.getState() };
|
|
266
313
|
}
|
|
267
314
|
}
|
|
268
315
|
async buildMessageList(input, options) {
|
|
@@ -273,9 +320,6 @@ class AgentRuntime {
|
|
|
273
320
|
list.addHistory((0, strip_orphaned_tool_messages_1.stripOrphanedToolMessages)(memMessages));
|
|
274
321
|
}
|
|
275
322
|
}
|
|
276
|
-
if (this.config.semanticRecall && options?.persistence?.threadId) {
|
|
277
|
-
await this.performSemanticRecall(list, input, options.persistence, options.executionCounter);
|
|
278
|
-
}
|
|
279
323
|
await this.setListObservationLogMemory(list, options?.persistence);
|
|
280
324
|
list.addInput(input);
|
|
281
325
|
return list;
|
|
@@ -300,87 +344,7 @@ class AgentRuntime {
|
|
|
300
344
|
resourceId,
|
|
301
345
|
});
|
|
302
346
|
}
|
|
303
|
-
async performSemanticRecall(list, input, persistence, executionCounter) {
|
|
304
|
-
if (!this.config.semanticRecall || !this.config.memory)
|
|
305
|
-
return;
|
|
306
|
-
const userText = input
|
|
307
|
-
.filter((m) => (0, message_1.isLlmMessage)(m) && m.role === 'user')
|
|
308
|
-
.flatMap((m) => ((0, message_1.isLlmMessage)(m) ? m.content : []))
|
|
309
|
-
.filter((c) => c.type === 'text')
|
|
310
|
-
.map((c) => c.text)
|
|
311
|
-
.join(' ');
|
|
312
|
-
if (!userText)
|
|
313
|
-
return;
|
|
314
|
-
let recalled = [];
|
|
315
|
-
if (this.config.memory.queryEmbeddings && this.config.semanticRecall.embedder) {
|
|
316
|
-
const { embed } = getAiSdk();
|
|
317
|
-
const embeddingModel = (0, model_factory_1.createEmbeddingModel)(this.config.semanticRecall.embedder, this.config.semanticRecall.apiKey);
|
|
318
|
-
const { embedding, usage } = await embed({ model: embeddingModel, value: userText });
|
|
319
|
-
(0, execution_counter_1.incrementTokenCountFromUsage)(executionCounter, usage);
|
|
320
|
-
const hits = await this.config.memory.queryEmbeddings({
|
|
321
|
-
scope: this.config.semanticRecall.scope ?? 'resource',
|
|
322
|
-
threadId: persistence.threadId,
|
|
323
|
-
resourceId: persistence.resourceId,
|
|
324
|
-
vector: embedding,
|
|
325
|
-
topK: this.config.semanticRecall.topK,
|
|
326
|
-
});
|
|
327
|
-
if (hits.length > 0) {
|
|
328
|
-
const hitIds = new Set(hits.map((h) => h.id));
|
|
329
|
-
const allMsgs = await this.config.memory.getMessages(persistence.threadId);
|
|
330
|
-
if (this.config.semanticRecall.messageRange) {
|
|
331
|
-
recalled = this.expandMessageRange(allMsgs, hitIds, this.config.semanticRecall.messageRange);
|
|
332
|
-
}
|
|
333
|
-
else {
|
|
334
|
-
recalled = allMsgs.filter((m) => {
|
|
335
|
-
const id = m.id;
|
|
336
|
-
return id !== undefined && hitIds.has(id);
|
|
337
|
-
});
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
else if (this.config.memory.search) {
|
|
342
|
-
recalled = await this.config.memory.search(userText, {
|
|
343
|
-
threadId: persistence.threadId,
|
|
344
|
-
resourceId: persistence.resourceId,
|
|
345
|
-
topK: this.config.semanticRecall.topK,
|
|
346
|
-
messageRange: this.config.semanticRecall.messageRange,
|
|
347
|
-
});
|
|
348
|
-
}
|
|
349
|
-
if (recalled.length === 0)
|
|
350
|
-
return;
|
|
351
|
-
const { historyIds } = list.serialize();
|
|
352
|
-
const historyIdSet = new Set(historyIds);
|
|
353
|
-
const newRecalled = recalled.filter((m) => {
|
|
354
|
-
const id = m.id;
|
|
355
|
-
return !id || !historyIdSet.has(id);
|
|
356
|
-
});
|
|
357
|
-
if (newRecalled.length > 0) {
|
|
358
|
-
list.addHistory(newRecalled);
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
expandMessageRange(allMsgs, hitIds, range) {
|
|
362
|
-
const expandedIds = new Set();
|
|
363
|
-
for (const msg of allMsgs) {
|
|
364
|
-
const id = 'id' in msg && typeof msg.id === 'string' ? msg.id : undefined;
|
|
365
|
-
if (!id || !hitIds.has(id))
|
|
366
|
-
continue;
|
|
367
|
-
const idx = allMsgs.indexOf(msg);
|
|
368
|
-
const start = Math.max(0, idx - (range.before ?? 0));
|
|
369
|
-
const end = Math.min(allMsgs.length - 1, idx + (range.after ?? 0));
|
|
370
|
-
for (let i = start; i <= end; i++) {
|
|
371
|
-
const el = allMsgs[i];
|
|
372
|
-
const mid = 'id' in el && typeof el.id === 'string' ? el.id : undefined;
|
|
373
|
-
if (mid)
|
|
374
|
-
expandedIds.add(mid);
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
return allMsgs.filter((m) => {
|
|
378
|
-
const mid = 'id' in m && typeof m.id === 'string' ? m.id : undefined;
|
|
379
|
-
return mid && expandedIds.has(mid);
|
|
380
|
-
});
|
|
381
|
-
}
|
|
382
347
|
async initRun(input, options) {
|
|
383
|
-
this.eventBus.resetAbort(options?.abortSignal);
|
|
384
348
|
this.updateState({
|
|
385
349
|
status: 'running',
|
|
386
350
|
persistence: options?.persistence,
|
|
@@ -391,14 +355,13 @@ class AgentRuntime {
|
|
|
391
355
|
this.incrementMessageCount(options?.executionCounter);
|
|
392
356
|
return await this.buildMessageList(normalizedInput, options);
|
|
393
357
|
}
|
|
394
|
-
finalizeGenerate(result, list
|
|
395
|
-
result.runId = runId;
|
|
358
|
+
finalizeGenerate(result, list) {
|
|
359
|
+
result.runId = this.runId;
|
|
396
360
|
result.usage = this.applyCost(result.usage);
|
|
397
361
|
result.model = this.modelIdString;
|
|
398
|
-
const finalized = (0, runtime_helpers_1.applySubAgentUsage)(result);
|
|
399
362
|
this.updateState({ status: 'success', messageList: list.serialize() });
|
|
400
|
-
this.eventBus.emit({ type: "agent_end", messages:
|
|
401
|
-
return
|
|
363
|
+
this.eventBus.emit({ type: "agent_end", messages: result.messages });
|
|
364
|
+
return { ...result, getState: () => this.getState() };
|
|
402
365
|
}
|
|
403
366
|
resolveTelemetry(options) {
|
|
404
367
|
if (this.config.telemetry)
|
|
@@ -422,6 +385,12 @@ class AgentRuntime {
|
|
|
422
385
|
},
|
|
423
386
|
};
|
|
424
387
|
}
|
|
388
|
+
buildSmoothStreamTransformOptions(options) {
|
|
389
|
+
if (options?.smoothStream === false)
|
|
390
|
+
return {};
|
|
391
|
+
const { smoothStream } = (0, lazy_ai_1.loadAi)();
|
|
392
|
+
return { experimental_transform: smoothStream(options?.smoothStream ?? {}) };
|
|
393
|
+
}
|
|
425
394
|
buildTelemetryOptions(options) {
|
|
426
395
|
const t = this.resolveTelemetry(options);
|
|
427
396
|
if (!t?.enabled)
|
|
@@ -537,13 +506,12 @@ class AgentRuntime {
|
|
|
537
506
|
});
|
|
538
507
|
}
|
|
539
508
|
async runGenerateLoop(ctx) {
|
|
540
|
-
const { list, options,
|
|
509
|
+
const { list, options, abortScope, pendingResume } = ctx;
|
|
541
510
|
this.hydrateDeferredToolsFromList(list);
|
|
542
511
|
let totalUsage;
|
|
543
512
|
let lastFinishReason = 'stop';
|
|
544
513
|
let structuredOutput;
|
|
545
514
|
const toolCallSummary = [];
|
|
546
|
-
const collectedSubAgentUsage = [];
|
|
547
515
|
const runTelemetry = this.resolveTelemetry(options);
|
|
548
516
|
const staticLoopContext = this.buildStaticLoopContext({
|
|
549
517
|
...options,
|
|
@@ -553,10 +521,12 @@ class AgentRuntime {
|
|
|
553
521
|
const pendingToolCtx = {
|
|
554
522
|
toolMap: pendingLoopContext.toolMap,
|
|
555
523
|
list,
|
|
556
|
-
runId,
|
|
524
|
+
runId: this.runId,
|
|
557
525
|
persistence: options?.persistence,
|
|
558
526
|
telemetry: runTelemetry,
|
|
559
527
|
executionCounter: options?.executionCounter,
|
|
528
|
+
abortSignal: abortScope.signal,
|
|
529
|
+
isAborted: () => abortScope.isAborted,
|
|
560
530
|
};
|
|
561
531
|
const maxIterations = options?.maxIterations ?? MAX_LOOP_ITERATIONS;
|
|
562
532
|
let iterationCount = options?.iterationCount ?? 0;
|
|
@@ -568,11 +538,9 @@ class AgentRuntime {
|
|
|
568
538
|
});
|
|
569
539
|
for (const r of batch.results) {
|
|
570
540
|
toolCallSummary.push(r.toolEntry);
|
|
571
|
-
if (r.subAgentUsage)
|
|
572
|
-
collectedSubAgentUsage.push(...r.subAgentUsage);
|
|
573
541
|
}
|
|
574
542
|
if (Object.keys(batch.pending).length > 0) {
|
|
575
|
-
const suspendRunId = await this.persistSuspension(batch.pending, options, list, totalUsage,
|
|
543
|
+
const suspendRunId = await this.persistSuspension(batch.pending, options, list, totalUsage, maxIterations, iterationCount);
|
|
576
544
|
return {
|
|
577
545
|
runId: suspendRunId,
|
|
578
546
|
messages: list.responseDelta(),
|
|
@@ -586,21 +554,24 @@ class AgentRuntime {
|
|
|
586
554
|
suspendPayload: s.payload,
|
|
587
555
|
resumeSchema: s.resumeSchema,
|
|
588
556
|
})),
|
|
557
|
+
getState: () => this.getState(),
|
|
589
558
|
};
|
|
590
559
|
}
|
|
591
560
|
}
|
|
592
561
|
const { generateText } = (0, lazy_ai_1.loadAi)();
|
|
593
562
|
for (; iterationCount < maxIterations; iterationCount++) {
|
|
594
|
-
if (
|
|
563
|
+
if (abortScope.isAborted) {
|
|
595
564
|
this.updateState({ status: 'cancelled' });
|
|
596
565
|
throw new Error('Agent run was aborted');
|
|
597
566
|
}
|
|
598
567
|
this.eventBus.emit({ type: "turn_start" });
|
|
599
568
|
const { toolMap, aiTools, hasTools, effectiveInstructions } = this.buildToolLoopContext(staticLoopContext.aiProviderTools, options?.persistence, options?.executionCounter);
|
|
569
|
+
const { system, messages } = list.forLlm(effectiveInstructions, this.config.instructionProviderOptions);
|
|
600
570
|
const result = await generateText({
|
|
601
571
|
model: staticLoopContext.model,
|
|
602
|
-
|
|
603
|
-
|
|
572
|
+
system,
|
|
573
|
+
messages,
|
|
574
|
+
abortSignal: abortScope.signal,
|
|
604
575
|
...(hasTools ? { tools: aiTools } : {}),
|
|
605
576
|
...(staticLoopContext.providerOptions
|
|
606
577
|
? { providerOptions: staticLoopContext.providerOptions }
|
|
@@ -626,19 +597,19 @@ class AgentRuntime {
|
|
|
626
597
|
const batch = await this.iterateToolCallsConcurrent({
|
|
627
598
|
toolMap,
|
|
628
599
|
list,
|
|
629
|
-
runId,
|
|
600
|
+
runId: this.runId,
|
|
630
601
|
persistence: options?.persistence,
|
|
631
602
|
telemetry: runTelemetry,
|
|
632
603
|
executionCounter: options?.executionCounter,
|
|
604
|
+
abortSignal: abortScope.signal,
|
|
605
|
+
isAborted: () => abortScope.isAborted,
|
|
633
606
|
toolCalls: result.toolCalls,
|
|
634
607
|
});
|
|
635
608
|
for (const r of batch.results) {
|
|
636
609
|
toolCallSummary.push(r.toolEntry);
|
|
637
|
-
if (r.subAgentUsage)
|
|
638
|
-
collectedSubAgentUsage.push(...r.subAgentUsage);
|
|
639
610
|
}
|
|
640
611
|
if (Object.keys(batch.pending).length > 0) {
|
|
641
|
-
const suspendRunId = await this.persistSuspension(batch.pending, options, list, totalUsage,
|
|
612
|
+
const suspendRunId = await this.persistSuspension(batch.pending, options, list, totalUsage, maxIterations, iterationCount + 1);
|
|
642
613
|
return {
|
|
643
614
|
runId: suspendRunId,
|
|
644
615
|
messages: list.responseDelta(),
|
|
@@ -652,6 +623,7 @@ class AgentRuntime {
|
|
|
652
623
|
suspendPayload: s.payload,
|
|
653
624
|
resumeSchema: s.resumeSchema,
|
|
654
625
|
})),
|
|
626
|
+
getState: () => this.getState(),
|
|
655
627
|
};
|
|
656
628
|
}
|
|
657
629
|
this.emitTurnEnd(newMessages, (0, runtime_helpers_1.extractSettledToolCalls)(list.responseDelta()));
|
|
@@ -677,35 +649,68 @@ class AgentRuntime {
|
|
|
677
649
|
}
|
|
678
650
|
}
|
|
679
651
|
return {
|
|
680
|
-
runId: runId
|
|
652
|
+
runId: this.runId,
|
|
681
653
|
messages: list.responseDelta(),
|
|
682
654
|
finishReason: lastFinishReason,
|
|
683
655
|
usage: totalUsage,
|
|
684
656
|
...(structuredOutput !== undefined && { structuredOutput }),
|
|
685
657
|
...(toolCallSummary.length > 0 && { toolCalls: toolCallSummary }),
|
|
686
|
-
|
|
658
|
+
getState: () => this.getState(),
|
|
687
659
|
};
|
|
688
660
|
}
|
|
689
661
|
startStreamLoop(ctx) {
|
|
690
|
-
const { options
|
|
662
|
+
const { options } = ctx;
|
|
691
663
|
const { readable, writable } = new TransformStream();
|
|
692
664
|
const writer = writable.getWriter();
|
|
665
|
+
const writeEventChunk = (chunk) => {
|
|
666
|
+
writer.write(chunk).catch(() => { });
|
|
667
|
+
};
|
|
693
668
|
const onToolExecutionStart = (data) => {
|
|
694
669
|
if (data.type !== "tool_execution_start")
|
|
695
670
|
return;
|
|
696
|
-
|
|
697
|
-
.write({
|
|
671
|
+
writeEventChunk({
|
|
698
672
|
type: 'tool-execution-start',
|
|
699
673
|
toolCallId: data.toolCallId,
|
|
700
674
|
toolName: data.toolName,
|
|
701
|
-
|
|
702
|
-
|
|
675
|
+
startTime: Date.now(),
|
|
676
|
+
});
|
|
677
|
+
};
|
|
678
|
+
const onToolExecutionEnd = (data) => {
|
|
679
|
+
if (data.type !== "tool_execution_end")
|
|
680
|
+
return;
|
|
681
|
+
writeEventChunk({
|
|
682
|
+
type: 'tool-execution-end',
|
|
683
|
+
toolCallId: data.toolCallId,
|
|
684
|
+
toolName: data.toolName,
|
|
685
|
+
isError: data.isError,
|
|
686
|
+
endTime: Date.now(),
|
|
687
|
+
});
|
|
688
|
+
};
|
|
689
|
+
const onSubAgentStarted = (data) => {
|
|
690
|
+
if (data.type !== "subagent_started")
|
|
691
|
+
return;
|
|
692
|
+
const { type: _type, ...payload } = data;
|
|
693
|
+
writeEventChunk({ type: 'subagent-started', ...payload });
|
|
694
|
+
};
|
|
695
|
+
const onSubAgentCompleted = (data) => {
|
|
696
|
+
if (data.type !== "subagent_completed")
|
|
697
|
+
return;
|
|
698
|
+
const { type: _type, ...payload } = data;
|
|
699
|
+
writeEventChunk({ type: 'subagent-completed', ...payload });
|
|
703
700
|
};
|
|
704
701
|
this.eventBus.on("tool_execution_start", onToolExecutionStart);
|
|
705
|
-
this.
|
|
702
|
+
this.eventBus.on("tool_execution_end", onToolExecutionEnd);
|
|
703
|
+
this.eventBus.on("subagent_started", onSubAgentStarted);
|
|
704
|
+
this.eventBus.on("subagent_completed", onSubAgentCompleted);
|
|
705
|
+
this.withTelemetryRootSpan('stream', options, this.runId, async () => await this.runStreamLoop({ ...ctx, writer }))
|
|
706
706
|
.catch(async (error) => {
|
|
707
707
|
await this.flushTelemetry(options);
|
|
708
|
-
await this.cleanupRun(
|
|
708
|
+
await this.cleanupRun();
|
|
709
|
+
const isAbort = ctx.abortScope.isAborted;
|
|
710
|
+
this.updateState({ status: isAbort ? 'cancelled' : 'failed' });
|
|
711
|
+
if (!isAbort) {
|
|
712
|
+
this.eventBus.emit({ type: "error", message: String(error), error });
|
|
713
|
+
}
|
|
709
714
|
try {
|
|
710
715
|
await writer.write({ type: 'error', error });
|
|
711
716
|
await writer.write({ type: 'finish', finishReason: 'error' });
|
|
@@ -715,13 +720,18 @@ class AgentRuntime {
|
|
|
715
720
|
writer.abort(error).catch(() => { });
|
|
716
721
|
}
|
|
717
722
|
})
|
|
718
|
-
.finally(() => {
|
|
723
|
+
.finally(async () => {
|
|
724
|
+
await writer.close().catch(() => { });
|
|
719
725
|
this.eventBus.off("tool_execution_start", onToolExecutionStart);
|
|
726
|
+
this.eventBus.off("tool_execution_end", onToolExecutionEnd);
|
|
727
|
+
this.eventBus.off("subagent_started", onSubAgentStarted);
|
|
728
|
+
this.eventBus.off("subagent_completed", onSubAgentCompleted);
|
|
729
|
+
ctx.abortScope.dispose();
|
|
720
730
|
});
|
|
721
731
|
return readable;
|
|
722
732
|
}
|
|
723
733
|
async runStreamLoop(ctx) {
|
|
724
|
-
const { list, options,
|
|
734
|
+
const { list, options, abortScope, pendingResume, writer } = ctx;
|
|
725
735
|
this.hydrateDeferredToolsFromList(list);
|
|
726
736
|
const writeChunk = async (chunk) => {
|
|
727
737
|
await writer.write(chunk);
|
|
@@ -729,20 +739,19 @@ class AgentRuntime {
|
|
|
729
739
|
let totalUsage;
|
|
730
740
|
let lastFinishReason = 'stop';
|
|
731
741
|
let structuredOutput;
|
|
732
|
-
const collectedSubAgentUsage = [];
|
|
733
742
|
const maxIterations = options?.maxIterations ?? MAX_LOOP_ITERATIONS;
|
|
734
743
|
let iterationCount = options?.iterationCount ?? 0;
|
|
735
744
|
let reachedStopCondition = false;
|
|
736
745
|
const { streamText } = (0, lazy_ai_1.loadAi)();
|
|
737
746
|
const closeStreamWithError = async (error, status) => {
|
|
738
|
-
await this.cleanupRun(
|
|
747
|
+
await this.cleanupRun();
|
|
739
748
|
this.updateState({ status });
|
|
740
749
|
await writer.write({ type: 'error', error });
|
|
741
750
|
await writer.write({ type: 'finish', finishReason: 'error' });
|
|
742
751
|
await writer.close();
|
|
743
752
|
};
|
|
744
753
|
const handleAbort = async () => {
|
|
745
|
-
if (!
|
|
754
|
+
if (!abortScope.isAborted)
|
|
746
755
|
return false;
|
|
747
756
|
await closeStreamWithError(new Error('Agent run was aborted'), 'cancelled');
|
|
748
757
|
return true;
|
|
@@ -756,10 +765,12 @@ class AgentRuntime {
|
|
|
756
765
|
const pendingToolCtx = {
|
|
757
766
|
toolMap: pendingLoopContext.toolMap,
|
|
758
767
|
list,
|
|
759
|
-
runId,
|
|
768
|
+
runId: this.runId,
|
|
760
769
|
persistence: options?.persistence,
|
|
761
770
|
telemetry: runTelemetry,
|
|
762
771
|
executionCounter: options?.executionCounter,
|
|
772
|
+
abortSignal: abortScope.signal,
|
|
773
|
+
isAborted: () => abortScope.isAborted,
|
|
763
774
|
};
|
|
764
775
|
if (pendingResume) {
|
|
765
776
|
try {
|
|
@@ -768,13 +779,12 @@ class AgentRuntime {
|
|
|
768
779
|
pendingResume,
|
|
769
780
|
});
|
|
770
781
|
for (const r of batch.results) {
|
|
771
|
-
if (r.subAgentUsage)
|
|
772
|
-
collectedSubAgentUsage.push(...r.subAgentUsage);
|
|
773
782
|
await writer.write({
|
|
774
783
|
type: 'tool-result',
|
|
775
784
|
toolCallId: r.toolCallId,
|
|
776
785
|
toolName: r.toolName,
|
|
777
786
|
output: r.modelOutput,
|
|
787
|
+
...(r.toolEntry.canceled ? { canceled: true } : {}),
|
|
778
788
|
});
|
|
779
789
|
if (r.customMessage) {
|
|
780
790
|
await writer.write({ type: 'message', message: r.customMessage });
|
|
@@ -790,7 +800,7 @@ class AgentRuntime {
|
|
|
790
800
|
});
|
|
791
801
|
}
|
|
792
802
|
if (Object.keys(batch.pending).length > 0) {
|
|
793
|
-
const suspendRunId = await this.persistSuspension(batch.pending, options, list, totalUsage,
|
|
803
|
+
const suspendRunId = await this.persistSuspension(batch.pending, options, list, totalUsage, maxIterations, iterationCount);
|
|
794
804
|
for (const s of batch.suspensions) {
|
|
795
805
|
await writer.write({
|
|
796
806
|
type: 'tool-call-suspended',
|
|
@@ -818,25 +828,45 @@ class AgentRuntime {
|
|
|
818
828
|
return;
|
|
819
829
|
this.eventBus.emit({ type: "turn_start" });
|
|
820
830
|
const { toolMap, aiTools, hasTools, effectiveInstructions } = this.buildToolLoopContext(staticLoopContext.aiProviderTools, options?.persistence, options?.executionCounter);
|
|
821
|
-
const messages = list.forLlm(effectiveInstructions, this.config.instructionProviderOptions);
|
|
831
|
+
const { system, messages } = list.forLlm(effectiveInstructions, this.config.instructionProviderOptions);
|
|
822
832
|
const result = streamText({
|
|
823
833
|
model: staticLoopContext.model,
|
|
834
|
+
system,
|
|
824
835
|
messages,
|
|
825
|
-
abortSignal:
|
|
836
|
+
abortSignal: abortScope.signal,
|
|
826
837
|
...(hasTools ? { tools: aiTools } : {}),
|
|
827
838
|
...(staticLoopContext.providerOptions
|
|
828
839
|
? { providerOptions: staticLoopContext.providerOptions }
|
|
829
840
|
: {}),
|
|
830
841
|
...(staticLoopContext.outputSpec ? { output: staticLoopContext.outputSpec } : {}),
|
|
831
842
|
...this.buildAiSdkOptions(toolMap, options),
|
|
843
|
+
...this.buildSmoothStreamTransformOptions(options),
|
|
832
844
|
});
|
|
833
845
|
try {
|
|
834
846
|
for await (const chunk of result.fullStream) {
|
|
835
847
|
if (chunk.type === 'finish')
|
|
836
848
|
continue;
|
|
849
|
+
if ((chunk.type === 'tool-result' || chunk.type === 'tool-error') &&
|
|
850
|
+
chunk.providerExecuted) {
|
|
851
|
+
await writeChunk({
|
|
852
|
+
type: 'tool-execution-end',
|
|
853
|
+
toolCallId: chunk.toolCallId,
|
|
854
|
+
toolName: chunk.toolName ?? '',
|
|
855
|
+
isError: chunk.type === 'tool-error',
|
|
856
|
+
endTime: Date.now(),
|
|
857
|
+
});
|
|
858
|
+
}
|
|
837
859
|
const converted = (0, stream_1.convertChunk)(chunk);
|
|
838
860
|
if (converted)
|
|
839
861
|
await writeChunk(converted);
|
|
862
|
+
if (chunk.type === 'tool-call' && chunk.providerExecuted) {
|
|
863
|
+
await writeChunk({
|
|
864
|
+
type: 'tool-execution-start',
|
|
865
|
+
toolCallId: chunk.toolCallId,
|
|
866
|
+
toolName: chunk.toolName ?? '',
|
|
867
|
+
startTime: Date.now(),
|
|
868
|
+
});
|
|
869
|
+
}
|
|
840
870
|
}
|
|
841
871
|
}
|
|
842
872
|
catch (streamError) {
|
|
@@ -874,22 +904,23 @@ class AgentRuntime {
|
|
|
874
904
|
const batch = await this.iterateToolCallsConcurrent({
|
|
875
905
|
toolMap,
|
|
876
906
|
list,
|
|
877
|
-
runId,
|
|
907
|
+
runId: this.runId,
|
|
878
908
|
persistence: options?.persistence,
|
|
879
909
|
telemetry: runTelemetry,
|
|
880
910
|
executionCounter: options?.executionCounter,
|
|
911
|
+
abortSignal: abortScope.signal,
|
|
912
|
+
isAborted: () => abortScope.isAborted,
|
|
881
913
|
toolCalls,
|
|
882
914
|
});
|
|
883
915
|
if (await handleAbort())
|
|
884
916
|
return;
|
|
885
917
|
for (const r of batch.results) {
|
|
886
|
-
if (r.subAgentUsage)
|
|
887
|
-
collectedSubAgentUsage.push(...r.subAgentUsage);
|
|
888
918
|
await writer.write({
|
|
889
919
|
type: 'tool-result',
|
|
890
920
|
toolCallId: r.toolCallId,
|
|
891
921
|
toolName: r.toolName,
|
|
892
922
|
output: r.modelOutput,
|
|
923
|
+
...(r.toolEntry.canceled ? { canceled: true } : {}),
|
|
893
924
|
});
|
|
894
925
|
if (r.customMessage) {
|
|
895
926
|
await writer.write({ type: 'message', message: r.customMessage });
|
|
@@ -905,7 +936,7 @@ class AgentRuntime {
|
|
|
905
936
|
});
|
|
906
937
|
}
|
|
907
938
|
if (Object.keys(batch.pending).length > 0) {
|
|
908
|
-
const suspendRunId = await this.persistSuspension(batch.pending, options, list, totalUsage,
|
|
939
|
+
const suspendRunId = await this.persistSuspension(batch.pending, options, list, totalUsage, maxIterations, iterationCount + 1);
|
|
909
940
|
for (const s of batch.suspensions) {
|
|
910
941
|
await writer.write({
|
|
911
942
|
type: 'tool-call-suspended',
|
|
@@ -932,45 +963,35 @@ class AgentRuntime {
|
|
|
932
963
|
if (!reachedStopCondition && iterationCount >= maxIterations) {
|
|
933
964
|
lastFinishReason = 'max-iterations';
|
|
934
965
|
}
|
|
966
|
+
await this.saveToMemory(list, options);
|
|
967
|
+
if (this.config.titleGeneration && options?.persistence && this.config.memory) {
|
|
968
|
+
const titlePromise = (0, title_generation_1.generateThreadTitle)({
|
|
969
|
+
memory: this.config.memory,
|
|
970
|
+
threadId: options.persistence.threadId,
|
|
971
|
+
resourceId: options.persistence.resourceId,
|
|
972
|
+
titleConfig: this.config.titleGeneration,
|
|
973
|
+
agentModel: this.config.model,
|
|
974
|
+
turnDelta: list.turnDelta(),
|
|
975
|
+
executionCounter: options.executionCounter,
|
|
976
|
+
});
|
|
977
|
+
this.backgroundTasks.track(titlePromise);
|
|
978
|
+
if (this.config.titleGeneration.sync) {
|
|
979
|
+
await titlePromise;
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
await this.cleanupRun();
|
|
983
|
+
await this.flushTelemetry(options);
|
|
935
984
|
const costUsage = this.applyCost(totalUsage);
|
|
936
|
-
const parentCost = costUsage?.cost ?? 0;
|
|
937
|
-
const subCost = collectedSubAgentUsage.reduce((sum, s) => sum + (s.usage.cost ?? 0), 0);
|
|
938
985
|
await writer.write({
|
|
939
986
|
type: 'finish',
|
|
940
987
|
finishReason: lastFinishReason,
|
|
941
988
|
...(costUsage && { usage: costUsage }),
|
|
942
989
|
model: this.modelIdString,
|
|
943
990
|
...(structuredOutput !== undefined && { structuredOutput }),
|
|
944
|
-
...(collectedSubAgentUsage.length > 0 && {
|
|
945
|
-
subAgentUsage: collectedSubAgentUsage,
|
|
946
|
-
totalCost: parentCost + subCost,
|
|
947
|
-
}),
|
|
948
991
|
});
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
const titlePromise = (0, title_generation_1.generateThreadTitle)({
|
|
953
|
-
memory: this.config.memory,
|
|
954
|
-
threadId: options.persistence.threadId,
|
|
955
|
-
resourceId: options.persistence.resourceId,
|
|
956
|
-
titleConfig: this.config.titleGeneration,
|
|
957
|
-
agentModel: this.config.model,
|
|
958
|
-
turnDelta: list.turnDelta(),
|
|
959
|
-
executionCounter: options.executionCounter,
|
|
960
|
-
});
|
|
961
|
-
this.backgroundTasks.track(titlePromise);
|
|
962
|
-
if (this.config.titleGeneration.sync) {
|
|
963
|
-
await titlePromise;
|
|
964
|
-
}
|
|
965
|
-
}
|
|
966
|
-
await this.cleanupRun(runId);
|
|
967
|
-
await this.flushTelemetry(options);
|
|
968
|
-
this.updateState({ status: 'success', messageList: list.serialize() });
|
|
969
|
-
this.eventBus.emit({ type: "agent_end", messages: list.responseDelta() });
|
|
970
|
-
}
|
|
971
|
-
finally {
|
|
972
|
-
await writer.close();
|
|
973
|
-
}
|
|
992
|
+
this.updateState({ status: 'success', messageList: list.serialize() });
|
|
993
|
+
this.eventBus.emit({ type: "agent_end", messages: list.responseDelta() });
|
|
994
|
+
await writer.close();
|
|
974
995
|
}
|
|
975
996
|
async saveToMemory(list, options) {
|
|
976
997
|
if (!this.config.memory || !options?.persistence)
|
|
@@ -979,9 +1000,6 @@ class AgentRuntime {
|
|
|
979
1000
|
if (delta.length === 0)
|
|
980
1001
|
return;
|
|
981
1002
|
await (0, memory_store_1.saveMessagesToThread)(this.config.memory, options.persistence.threadId, options.persistence.resourceId, delta);
|
|
982
|
-
if (this.config.semanticRecall?.embedder && this.config.memory.saveEmbeddings) {
|
|
983
|
-
await this.saveEmbeddingsForMessages(options.persistence.threadId, options.persistence.resourceId, delta, options.executionCounter);
|
|
984
|
-
}
|
|
985
1003
|
const observationTasks = this.scheduleObservationLogJobs(options.persistence, options.executionCounter);
|
|
986
1004
|
this.scheduleEpisodicMemoryJob(options.persistence, observationTasks, options.executionCounter);
|
|
987
1005
|
}
|
|
@@ -1119,43 +1137,6 @@ class AgentRuntime {
|
|
|
1119
1137
|
observationScopeId: persistence.threadId,
|
|
1120
1138
|
};
|
|
1121
1139
|
}
|
|
1122
|
-
async saveEmbeddingsForMessages(threadId, resourceId, messages, executionCounter) {
|
|
1123
|
-
const embeddable = [];
|
|
1124
|
-
for (const msg of messages) {
|
|
1125
|
-
if (!(0, message_1.isLlmMessage)(msg) || (msg.role !== 'user' && msg.role !== 'assistant'))
|
|
1126
|
-
continue;
|
|
1127
|
-
const text = msg.content
|
|
1128
|
-
.filter((c) => c.type === 'text')
|
|
1129
|
-
.map((c) => c.text)
|
|
1130
|
-
.join('\n');
|
|
1131
|
-
if (!text)
|
|
1132
|
-
continue;
|
|
1133
|
-
embeddable.push({ id: msg.id, text });
|
|
1134
|
-
}
|
|
1135
|
-
if (embeddable.length === 0)
|
|
1136
|
-
return;
|
|
1137
|
-
const embedder = this.config.semanticRecall?.embedder;
|
|
1138
|
-
if (!embedder)
|
|
1139
|
-
return;
|
|
1140
|
-
const { embedMany } = getAiSdk();
|
|
1141
|
-
const embeddingModel = (0, model_factory_1.createEmbeddingModel)(embedder, this.config.semanticRecall?.apiKey);
|
|
1142
|
-
const { embeddings, usage } = await embedMany({
|
|
1143
|
-
model: embeddingModel,
|
|
1144
|
-
values: embeddable.map((e) => e.text),
|
|
1145
|
-
});
|
|
1146
|
-
(0, execution_counter_1.incrementTokenCountFromUsage)(executionCounter, usage);
|
|
1147
|
-
await this.config.memory.saveEmbeddings({
|
|
1148
|
-
scope: this.config.semanticRecall?.scope ?? 'resource',
|
|
1149
|
-
threadId,
|
|
1150
|
-
resourceId,
|
|
1151
|
-
entries: embeddable.map((e, i) => ({
|
|
1152
|
-
id: e.id,
|
|
1153
|
-
vector: embeddings[i],
|
|
1154
|
-
text: e.text,
|
|
1155
|
-
model: embedder,
|
|
1156
|
-
})),
|
|
1157
|
-
});
|
|
1158
|
-
}
|
|
1159
1140
|
buildThinkingProviderOptions() {
|
|
1160
1141
|
if (!this.config.thinking)
|
|
1161
1142
|
return undefined;
|
|
@@ -1215,8 +1196,39 @@ class AgentRuntime {
|
|
|
1215
1196
|
}
|
|
1216
1197
|
return merged;
|
|
1217
1198
|
}
|
|
1199
|
+
isDelegateSubAgentCall(toolName) {
|
|
1200
|
+
return toolName === delegate_sub_agent_tool_1.DELEGATE_SUB_AGENT_TOOL_NAME;
|
|
1201
|
+
}
|
|
1202
|
+
getToolCallBatchSize(toolName, toolMap) {
|
|
1203
|
+
if (!this.isDelegateSubAgentCall(toolName))
|
|
1204
|
+
return this.concurrency;
|
|
1205
|
+
const tool = toolMap.get(toolName);
|
|
1206
|
+
const delegateOptions = tool ? (0, delegate_sub_agent_tool_1.getInlineDelegateSubAgentToolOptions)(tool) : undefined;
|
|
1207
|
+
return delegateOptions?.policy?.maxChildren ?? sub_agent_task_path_1.DEFAULT_SUB_AGENT_MAX_CHILDREN;
|
|
1208
|
+
}
|
|
1209
|
+
takeNextToolCallBatch(calls, start, toolMap) {
|
|
1210
|
+
const first = calls[start];
|
|
1211
|
+
if (!first) {
|
|
1212
|
+
throw new Error('Unable to build tool-call batch');
|
|
1213
|
+
}
|
|
1214
|
+
const isDelegateBatch = this.isDelegateSubAgentCall(first.toolName);
|
|
1215
|
+
const batchSize = this.getToolCallBatchSize(first.toolName, toolMap);
|
|
1216
|
+
if (batchSize < 1 ||
|
|
1217
|
+
Number.isNaN(batchSize) ||
|
|
1218
|
+
(isDelegateBatch && !Number.isFinite(batchSize))) {
|
|
1219
|
+
throw new Error(`Invalid tool-call batch size for ${first.toolName}: ${batchSize}`);
|
|
1220
|
+
}
|
|
1221
|
+
const batch = [];
|
|
1222
|
+
for (let i = start; i < calls.length && batch.length < batchSize; i++) {
|
|
1223
|
+
const candidate = calls[i];
|
|
1224
|
+
if (this.isDelegateSubAgentCall(candidate.toolName) !== isDelegateBatch)
|
|
1225
|
+
break;
|
|
1226
|
+
batch.push(candidate);
|
|
1227
|
+
}
|
|
1228
|
+
return batch;
|
|
1229
|
+
}
|
|
1218
1230
|
async iterateToolCallsConcurrent(ctx) {
|
|
1219
|
-
const { toolCalls, toolMap, list, runId, telemetry: resolvedTelemetry, executionCounter } = ctx;
|
|
1231
|
+
const { toolCalls, toolMap, list, runId, telemetry: resolvedTelemetry, executionCounter, abortSignal, } = ctx;
|
|
1220
1232
|
const executableCalls = toolCalls.filter((tc) => !tc.providerExecuted);
|
|
1221
1233
|
const providerExecutedCount = toolCalls.length - executableCalls.length;
|
|
1222
1234
|
for (let i = 0; i < providerExecutedCount; i++) {
|
|
@@ -1224,18 +1236,18 @@ class AgentRuntime {
|
|
|
1224
1236
|
}
|
|
1225
1237
|
const executableCallsById = new Map(executableCalls.map((tc) => [tc.toolCallId, tc]));
|
|
1226
1238
|
const unexecutedIds = new Set(executableCalls.map((tc) => tc.toolCallId));
|
|
1227
|
-
const batchSize = this.concurrency;
|
|
1228
1239
|
const results = [];
|
|
1229
1240
|
const suspensions = [];
|
|
1230
1241
|
const errors = [];
|
|
1231
1242
|
const pending = {};
|
|
1232
|
-
for (let batchStart = 0; batchStart < executableCalls.length;
|
|
1233
|
-
if (
|
|
1243
|
+
for (let batchStart = 0; batchStart < executableCalls.length;) {
|
|
1244
|
+
if (ctx.isAborted()) {
|
|
1234
1245
|
this.updateState({ status: 'cancelled' });
|
|
1235
1246
|
throw new Error('Agent run was aborted');
|
|
1236
1247
|
}
|
|
1237
|
-
const batch =
|
|
1238
|
-
|
|
1248
|
+
const batch = this.takeNextToolCallBatch(executableCalls, batchStart, toolMap);
|
|
1249
|
+
batchStart += batch.length;
|
|
1250
|
+
const settledResults = await Promise.allSettled(batch.map(async (tc) => await this.processToolCall(tc.toolCallId, tc.toolName, tc.input, toolMap, list, runId, ctx.persistence, undefined, resolvedTelemetry, executionCounter, abortSignal, true)));
|
|
1239
1251
|
for (const tc of batch) {
|
|
1240
1252
|
unexecutedIds.delete(tc.toolCallId);
|
|
1241
1253
|
}
|
|
@@ -1279,7 +1291,6 @@ class AgentRuntime {
|
|
|
1279
1291
|
input: toolInput,
|
|
1280
1292
|
toolEntry: result.value.toolEntry,
|
|
1281
1293
|
modelOutput: result.value.modelOutput,
|
|
1282
|
-
subAgentUsage: result.value.subAgentUsage,
|
|
1283
1294
|
customMessage: result.value.customMessage,
|
|
1284
1295
|
});
|
|
1285
1296
|
}
|
|
@@ -1310,7 +1321,7 @@ class AgentRuntime {
|
|
|
1310
1321
|
return { results, suspensions, errors, pending };
|
|
1311
1322
|
}
|
|
1312
1323
|
async iteratePendingToolCallsConcurrent(ctx) {
|
|
1313
|
-
const { pendingResume, toolMap, list, runId, persistence, telemetry: resolvedTelemetry, executionCounter, } = ctx;
|
|
1324
|
+
const { pendingResume, toolMap, list, runId, persistence, telemetry: resolvedTelemetry, executionCounter, abortSignal, } = ctx;
|
|
1314
1325
|
const resumedId = pendingResume.resumeToolCallId;
|
|
1315
1326
|
const resumedEntry = pendingResume.pendingToolCalls[resumedId];
|
|
1316
1327
|
if (!resumedEntry) {
|
|
@@ -1321,7 +1332,14 @@ class AgentRuntime {
|
|
|
1321
1332
|
const suspensions = [];
|
|
1322
1333
|
const errors = [];
|
|
1323
1334
|
const pending = {};
|
|
1324
|
-
|
|
1335
|
+
let processResult;
|
|
1336
|
+
try {
|
|
1337
|
+
processResult = await this.processToolCall(resumedEntry.toolCallId, resumedToolName, resumedEntry.input, toolMap, list, runId, persistence, pendingResume.resumeData, resolvedTelemetry, executionCounter, abortSignal, false);
|
|
1338
|
+
}
|
|
1339
|
+
catch (error) {
|
|
1340
|
+
processResult = { outcome: 'error', error };
|
|
1341
|
+
list.setToolCallError(resumedEntry.toolCallId, error);
|
|
1342
|
+
}
|
|
1325
1343
|
if (processResult.outcome === 'suspended') {
|
|
1326
1344
|
pending[resumedId] = {
|
|
1327
1345
|
...resumedEntry,
|
|
@@ -1345,10 +1363,44 @@ class AgentRuntime {
|
|
|
1345
1363
|
input: resumedEntry.input,
|
|
1346
1364
|
toolEntry: processResult.toolEntry,
|
|
1347
1365
|
modelOutput: processResult.modelOutput,
|
|
1348
|
-
subAgentUsage: processResult.subAgentUsage,
|
|
1349
1366
|
customMessage: processResult.customMessage,
|
|
1350
1367
|
});
|
|
1351
1368
|
}
|
|
1369
|
+
else if (processResult.outcome === 'cancelled') {
|
|
1370
|
+
results.push({
|
|
1371
|
+
toolCallId: resumedEntry.toolCallId,
|
|
1372
|
+
toolName: resumedToolName,
|
|
1373
|
+
input: resumedEntry.input,
|
|
1374
|
+
toolEntry: processResult.toolEntry,
|
|
1375
|
+
modelOutput: processResult.modelOutput,
|
|
1376
|
+
});
|
|
1377
|
+
list.addInput([
|
|
1378
|
+
{ role: 'user', content: [{ type: 'text', text: processResult.userMessage }] },
|
|
1379
|
+
]);
|
|
1380
|
+
for (const id of Object.keys(pendingResume.pendingToolCalls)) {
|
|
1381
|
+
if (id !== resumedId) {
|
|
1382
|
+
const siblingEntry = pendingResume.pendingToolCalls[id];
|
|
1383
|
+
const modelOutput = '[Skipped: a sibling tool call was cancelled]';
|
|
1384
|
+
list.setToolCallResult(id, modelOutput, {
|
|
1385
|
+
canceled: true,
|
|
1386
|
+
});
|
|
1387
|
+
results.push({
|
|
1388
|
+
toolCallId: siblingEntry.toolCallId,
|
|
1389
|
+
toolName: siblingEntry.toolName,
|
|
1390
|
+
input: siblingEntry.input,
|
|
1391
|
+
toolEntry: {
|
|
1392
|
+
tool: siblingEntry.toolName,
|
|
1393
|
+
input: siblingEntry.input,
|
|
1394
|
+
output: modelOutput,
|
|
1395
|
+
transformed: false,
|
|
1396
|
+
canceled: true,
|
|
1397
|
+
},
|
|
1398
|
+
modelOutput,
|
|
1399
|
+
});
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
return { results, suspensions, errors, pending };
|
|
1403
|
+
}
|
|
1352
1404
|
else if (processResult.outcome === 'error') {
|
|
1353
1405
|
errors.push({
|
|
1354
1406
|
toolCallId: resumedEntry.toolCallId,
|
|
@@ -1391,6 +1443,8 @@ class AgentRuntime {
|
|
|
1391
1443
|
persistence,
|
|
1392
1444
|
telemetry: resolvedTelemetry,
|
|
1393
1445
|
executionCounter,
|
|
1446
|
+
abortSignal,
|
|
1447
|
+
isAborted: ctx.isAborted,
|
|
1394
1448
|
});
|
|
1395
1449
|
results.push(...batch.results);
|
|
1396
1450
|
suspensions.push(...batch.suspensions);
|
|
@@ -1399,14 +1453,8 @@ class AgentRuntime {
|
|
|
1399
1453
|
}
|
|
1400
1454
|
return { results, suspensions, errors, pending };
|
|
1401
1455
|
}
|
|
1402
|
-
async processToolCall(toolCallId, toolName, toolInput, toolMap, list, runId, persistence, resumeData, resolvedTelemetry, executionCounter, countToolCall = true) {
|
|
1456
|
+
async processToolCall(toolCallId, toolName, toolInput, toolMap, list, runId, persistence, resumeData, resolvedTelemetry, executionCounter, abortSignal, countToolCall = true) {
|
|
1403
1457
|
const builtTool = toolMap.get(toolName);
|
|
1404
|
-
this.eventBus.emit({
|
|
1405
|
-
type: "tool_execution_start",
|
|
1406
|
-
toolCallId,
|
|
1407
|
-
toolName,
|
|
1408
|
-
args: toolInput,
|
|
1409
|
-
});
|
|
1410
1458
|
const makeToolError = (error) => {
|
|
1411
1459
|
this.eventBus.emit({
|
|
1412
1460
|
type: "tool_execution_end",
|
|
@@ -1442,6 +1490,30 @@ class AgentRuntime {
|
|
|
1442
1490
|
});
|
|
1443
1491
|
return { outcome: 'noop' };
|
|
1444
1492
|
}
|
|
1493
|
+
if ((0, cancellation_1.isCancellation)(resumeData) && !builtTool.handleCancellation) {
|
|
1494
|
+
const modelOutput = `[Tool call cancelled. User said: "${resumeData.message}"]`;
|
|
1495
|
+
this.eventBus.emit({
|
|
1496
|
+
type: "tool_execution_end",
|
|
1497
|
+
toolCallId,
|
|
1498
|
+
toolName,
|
|
1499
|
+
result: modelOutput,
|
|
1500
|
+
isError: false,
|
|
1501
|
+
});
|
|
1502
|
+
list.setToolCallResult(toolCallId, modelOutput, { canceled: true });
|
|
1503
|
+
return {
|
|
1504
|
+
outcome: 'cancelled',
|
|
1505
|
+
toolEntry: {
|
|
1506
|
+
tool: toolName,
|
|
1507
|
+
input: toolInput,
|
|
1508
|
+
output: modelOutput,
|
|
1509
|
+
transformed: false,
|
|
1510
|
+
canceled: true,
|
|
1511
|
+
},
|
|
1512
|
+
modelOutput,
|
|
1513
|
+
userMessage: resumeData.message,
|
|
1514
|
+
canceled: true,
|
|
1515
|
+
};
|
|
1516
|
+
}
|
|
1445
1517
|
if (countToolCall) {
|
|
1446
1518
|
this.incrementToolCallCount(executionCounter);
|
|
1447
1519
|
}
|
|
@@ -1452,11 +1524,22 @@ class AgentRuntime {
|
|
|
1452
1524
|
}
|
|
1453
1525
|
toolInput = result.data;
|
|
1454
1526
|
}
|
|
1527
|
+
if (shouldEmitToolExecutionStart(builtTool, resumeData)) {
|
|
1528
|
+
this.eventBus.emit({
|
|
1529
|
+
type: "tool_execution_start",
|
|
1530
|
+
toolCallId,
|
|
1531
|
+
toolName,
|
|
1532
|
+
args: toolInput,
|
|
1533
|
+
});
|
|
1534
|
+
}
|
|
1455
1535
|
let toolResult;
|
|
1456
1536
|
try {
|
|
1457
1537
|
toolResult = await this.withTelemetryToolSpan(toolCallId, toolName, toolInput, resolvedTelemetry, async () => await (0, tool_adapter_1.executeTool)(toolInput, builtTool, resumeData, resolvedTelemetry, toolCallId, {
|
|
1458
1538
|
runId,
|
|
1459
1539
|
persistence,
|
|
1540
|
+
emitEvent: (event) => this.eventBus.emit(event),
|
|
1541
|
+
abortSignal,
|
|
1542
|
+
executionCounter,
|
|
1460
1543
|
}));
|
|
1461
1544
|
}
|
|
1462
1545
|
catch (error) {
|
|
@@ -1474,9 +1557,7 @@ class AgentRuntime {
|
|
|
1474
1557
|
const error = new Error(`Tool ${toolName} has no resume schema`);
|
|
1475
1558
|
return makeToolError(error);
|
|
1476
1559
|
}
|
|
1477
|
-
const resumeSchema = (
|
|
1478
|
-
? (0, zod_to_json_schema_1.zodToJsonSchema)(builtTool.resumeSchema)
|
|
1479
|
-
: builtTool.resumeSchema;
|
|
1560
|
+
const resumeSchema = getToolResumeJsonSchema(builtTool);
|
|
1480
1561
|
if (!resumeSchema) {
|
|
1481
1562
|
return makeToolError(new Error('Invalid resume schema'));
|
|
1482
1563
|
}
|
|
@@ -1486,24 +1567,22 @@ class AgentRuntime {
|
|
|
1486
1567
|
resumeSchema,
|
|
1487
1568
|
};
|
|
1488
1569
|
}
|
|
1489
|
-
let
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1570
|
+
let modelResult;
|
|
1571
|
+
try {
|
|
1572
|
+
modelResult = builtTool.toModelOutput ? builtTool.toModelOutput(toolResult) : toolResult;
|
|
1573
|
+
}
|
|
1574
|
+
catch (error) {
|
|
1575
|
+
return makeToolError(error);
|
|
1494
1576
|
}
|
|
1495
1577
|
this.eventBus.emit({
|
|
1496
1578
|
type: "tool_execution_end",
|
|
1497
1579
|
toolCallId,
|
|
1498
1580
|
toolName,
|
|
1499
|
-
result:
|
|
1581
|
+
result: toolResult,
|
|
1500
1582
|
isError: false,
|
|
1501
1583
|
});
|
|
1502
|
-
const modelResult = builtTool.toModelOutput
|
|
1503
|
-
? builtTool.toModelOutput(actualResult)
|
|
1504
|
-
: actualResult;
|
|
1505
1584
|
list.setToolCallResult(toolCallId, (0, json_value_1.toJsonValue)(modelResult));
|
|
1506
|
-
const customMessage = builtTool?.toMessage?.(
|
|
1585
|
+
const customMessage = builtTool?.toMessage?.(toolResult);
|
|
1507
1586
|
if (customMessage) {
|
|
1508
1587
|
list.addResponse([customMessage]);
|
|
1509
1588
|
}
|
|
@@ -1512,27 +1591,43 @@ class AgentRuntime {
|
|
|
1512
1591
|
toolEntry: {
|
|
1513
1592
|
tool: toolName,
|
|
1514
1593
|
input: toolInput,
|
|
1515
|
-
output:
|
|
1594
|
+
output: toolResult,
|
|
1516
1595
|
transformed: !!builtTool.toModelOutput,
|
|
1517
1596
|
},
|
|
1518
1597
|
modelOutput: modelResult,
|
|
1519
|
-
subAgentUsage: extractedSubAgentUsage,
|
|
1520
1598
|
customMessage,
|
|
1521
1599
|
};
|
|
1522
1600
|
}
|
|
1523
1601
|
buildStaticLoopContext(execOptions) {
|
|
1524
|
-
const { Output } = getAiSdk();
|
|
1602
|
+
const { Output, jsonSchema } = getAiSdk();
|
|
1525
1603
|
const aiProviderTools = (0, tool_adapter_1.toAiSdkProviderTools)(this.config.providerTools);
|
|
1526
1604
|
const model = (0, model_factory_1.createModel)(this.config.model);
|
|
1605
|
+
const outputSchema = this.config.structuredOutput;
|
|
1606
|
+
const isRawJsonSchemaOutput = outputSchema !== undefined && !(0, zod_1.isZodSchema)(outputSchema);
|
|
1607
|
+
const providerOptions = this.relaxStrictJsonSchemaIfNeeded(this.buildCallProviderOptions(execOptions?.providerOptions), isRawJsonSchemaOutput);
|
|
1608
|
+
const outputSpec = outputSchema
|
|
1609
|
+
? Output.object({
|
|
1610
|
+
schema: (0, zod_1.isZodSchema)(outputSchema)
|
|
1611
|
+
? outputSchema
|
|
1612
|
+
: jsonSchema((0, json_schema_1.lockAdditionalProperties)(outputSchema)),
|
|
1613
|
+
})
|
|
1614
|
+
: undefined;
|
|
1527
1615
|
return {
|
|
1528
1616
|
model,
|
|
1529
1617
|
aiProviderTools,
|
|
1530
|
-
providerOptions
|
|
1531
|
-
outputSpec
|
|
1532
|
-
? Output.object({ schema: this.config.structuredOutput })
|
|
1533
|
-
: undefined,
|
|
1618
|
+
providerOptions,
|
|
1619
|
+
outputSpec,
|
|
1534
1620
|
};
|
|
1535
1621
|
}
|
|
1622
|
+
relaxStrictJsonSchemaIfNeeded(providerOptions, isRawJsonSchemaOutput) {
|
|
1623
|
+
if (!isRawJsonSchemaOutput)
|
|
1624
|
+
return providerOptions;
|
|
1625
|
+
const result = { ...providerOptions };
|
|
1626
|
+
for (const provider of ['openai', 'groq']) {
|
|
1627
|
+
result[provider] = { strictJsonSchema: false, ...result[provider] };
|
|
1628
|
+
}
|
|
1629
|
+
return result;
|
|
1630
|
+
}
|
|
1536
1631
|
buildToolLoopContext(aiProviderTools, persistence, executionCounter) {
|
|
1537
1632
|
const allUserTools = this.getCurrentTools(persistence, executionCounter);
|
|
1538
1633
|
const aiTools = (0, tool_adapter_1.toAiSdkTools)(allUserTools);
|
|
@@ -1592,8 +1687,7 @@ class AgentRuntime {
|
|
|
1592
1687
|
const block = `<built_in_rules>\n${fragments.map((f) => `- ${f}`).join('\n')}\n</built_in_rules>`;
|
|
1593
1688
|
return userInstructions ? `${block}\n\n${userInstructions}` : block;
|
|
1594
1689
|
}
|
|
1595
|
-
async persistSuspension(pendingToolCalls, options, list, totalUsage,
|
|
1596
|
-
const runId = existingRunId ?? (0, run_state_1.generateRunId)();
|
|
1690
|
+
async persistSuspension(pendingToolCalls, options, list, totalUsage, maxIterations, iterationCount) {
|
|
1597
1691
|
const resolvedMaxIterations = maxIterations ?? options?.maxIterations;
|
|
1598
1692
|
const resolvedIterationCount = iterationCount ?? options?.iterationCount;
|
|
1599
1693
|
const executionOptions = resolvedMaxIterations !== undefined ? { maxIterations: resolvedMaxIterations } : undefined;
|
|
@@ -1606,14 +1700,12 @@ class AgentRuntime {
|
|
|
1606
1700
|
executionOptions,
|
|
1607
1701
|
...(resolvedIterationCount !== undefined ? { iterationCount: resolvedIterationCount } : {}),
|
|
1608
1702
|
};
|
|
1609
|
-
await this.runState.suspend(runId, state);
|
|
1703
|
+
await this.runState.suspend(this.runId, state);
|
|
1610
1704
|
this.updateState({ status: 'suspended', pendingToolCalls, messageList: list.serialize() });
|
|
1611
|
-
return runId;
|
|
1705
|
+
return this.runId;
|
|
1612
1706
|
}
|
|
1613
|
-
async cleanupRun(
|
|
1614
|
-
|
|
1615
|
-
await this.runState.complete(runId);
|
|
1616
|
-
}
|
|
1707
|
+
async cleanupRun() {
|
|
1708
|
+
await this.runState.complete(this.runId);
|
|
1617
1709
|
}
|
|
1618
1710
|
emitTurnEnd(newMessages, toolResults) {
|
|
1619
1711
|
const assistantMsg = newMessages.find((m) => 'role' in m && m.role === 'assistant');
|