@n8n/agents 0.6.0 → 0.7.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 +12 -8
- package/dist/index.js +10 -3
- package/dist/index.js.map +1 -1
- package/dist/integrations/langsmith.d.ts +2 -0
- package/dist/integrations/langsmith.js +117 -2
- package/dist/integrations/langsmith.js.map +1 -1
- package/dist/runtime/agent-runtime.d.ts +6 -7
- package/dist/runtime/agent-runtime.js +390 -204
- package/dist/runtime/agent-runtime.js.map +1 -1
- package/dist/runtime/event-bus.d.ts +1 -0
- package/dist/runtime/event-bus.js +3 -0
- package/dist/runtime/event-bus.js.map +1 -1
- package/dist/runtime/json-value.d.ts +2 -0
- package/dist/runtime/json-value.js +43 -0
- package/dist/runtime/json-value.js.map +1 -0
- package/dist/runtime/memory-store.d.ts +40 -2
- package/dist/runtime/memory-store.js +138 -3
- package/dist/runtime/memory-store.js.map +1 -1
- package/dist/runtime/message-list.d.ts +5 -0
- package/dist/runtime/message-list.js +47 -0
- package/dist/runtime/message-list.js.map +1 -1
- package/dist/runtime/messages.d.ts +0 -2
- package/dist/runtime/messages.js +127 -101
- package/dist/runtime/messages.js.map +1 -1
- package/dist/runtime/model-factory.js +117 -34
- package/dist/runtime/model-factory.js.map +1 -1
- package/dist/runtime/provider-credentials.d.ts +167 -0
- package/dist/runtime/provider-credentials.js +34 -0
- package/dist/runtime/provider-credentials.js.map +1 -0
- package/dist/runtime/runtime-helpers.d.ts +3 -4
- package/dist/runtime/runtime-helpers.js +6 -32
- package/dist/runtime/runtime-helpers.js.map +1 -1
- package/dist/runtime/stream.js +25 -43
- package/dist/runtime/stream.js.map +1 -1
- package/dist/runtime/strip-orphaned-tool-messages.js +1 -25
- package/dist/runtime/strip-orphaned-tool-messages.js.map +1 -1
- package/dist/runtime/title-generation.d.ts +12 -3
- package/dist/runtime/title-generation.js +72 -3
- package/dist/runtime/title-generation.js.map +1 -1
- package/dist/runtime/tool-adapter.d.ts +1 -1
- package/dist/runtime/tool-adapter.js +3 -2
- package/dist/runtime/tool-adapter.js.map +1 -1
- package/dist/runtime/working-memory.d.ts +1 -1
- package/dist/runtime/working-memory.js +1 -1
- package/dist/runtime/working-memory.js.map +1 -1
- package/dist/sdk/agent.d.ts +24 -23
- package/dist/sdk/agent.js +50 -324
- package/dist/sdk/agent.js.map +1 -1
- package/dist/sdk/eval.d.ts +0 -3
- package/dist/sdk/eval.js +4 -9
- package/dist/sdk/eval.js.map +1 -1
- package/dist/sdk/provider-capabilities.js +4 -2
- package/dist/sdk/provider-capabilities.js.map +1 -1
- package/dist/sdk/provider-tools.d.ts +17 -2
- package/dist/sdk/provider-tools.js +19 -0
- package/dist/sdk/provider-tools.js.map +1 -1
- package/dist/sdk/telemetry.d.ts +2 -0
- package/dist/sdk/telemetry.js +6 -0
- package/dist/sdk/telemetry.js.map +1 -1
- package/dist/sdk/tool.d.ts +17 -10
- package/dist/sdk/tool.js +34 -0
- package/dist/sdk/tool.js.map +1 -1
- package/dist/sdk/verify.js +1 -4
- package/dist/sdk/verify.js.map +1 -1
- package/dist/storage/base-memory.d.ts +64 -0
- package/dist/storage/base-memory.js +54 -0
- package/dist/storage/base-memory.js.map +1 -0
- package/dist/storage/postgres-memory.d.ts +33 -16
- package/dist/storage/postgres-memory.js +46 -25
- package/dist/storage/postgres-memory.js.map +1 -1
- package/dist/storage/sqlite-memory.d.ts +16 -6
- package/dist/storage/sqlite-memory.js +16 -10
- package/dist/storage/sqlite-memory.js.map +1 -1
- package/dist/types/index.d.ts +4 -2
- package/dist/types/index.js +3 -1
- package/dist/types/index.js.map +1 -1
- package/dist/types/runtime/event.d.ts +3 -9
- package/dist/types/runtime/event.js.map +1 -1
- package/dist/types/sdk/agent-builder.d.ts +0 -3
- package/dist/types/sdk/agent.d.ts +64 -27
- package/dist/types/sdk/credential-provider.d.ts +2 -3
- package/dist/types/sdk/memory.d.ts +23 -2
- package/dist/types/sdk/message.d.ts +11 -10
- package/dist/types/sdk/observation.d.ts +100 -0
- package/dist/types/sdk/observation.js +5 -0
- package/dist/types/sdk/observation.js.map +1 -0
- package/dist/types/sdk/tool-descriptor.d.ts +13 -0
- package/dist/types/sdk/{schema.js → tool-descriptor.js} +1 -1
- package/dist/types/sdk/tool-descriptor.js.map +1 -0
- package/dist/types/sdk/tool.d.ts +8 -3
- package/dist/types/telemetry.d.ts +1 -0
- package/dist/utils/parse.d.ts +10 -0
- package/dist/utils/parse.js +26 -0
- package/dist/utils/parse.js.map +1 -0
- package/dist/utils/zod.d.ts +1 -1
- package/dist/utils/zod.js.map +1 -1
- package/dist/workspace/tools/batch-str-replace-file.d.ts +3 -0
- package/dist/workspace/tools/batch-str-replace-file.js +67 -0
- package/dist/workspace/tools/batch-str-replace-file.js.map +1 -0
- package/dist/workspace/tools/str-replace-file.d.ts +3 -0
- package/dist/workspace/tools/str-replace-file.js +51 -0
- package/dist/workspace/tools/str-replace-file.js.map +1 -0
- package/dist/workspace/tools/workspace-tools.js +4 -0
- package/dist/workspace/tools/workspace-tools.js.map +1 -1
- package/package.json +17 -8
- package/dist/codegen/generate-agent-code.d.ts +0 -2
- package/dist/codegen/generate-agent-code.js +0 -197
- package/dist/codegen/generate-agent-code.js.map +0 -1
- package/dist/sdk/from-schema.d.ts +0 -15
- package/dist/sdk/from-schema.js +0 -218
- package/dist/sdk/from-schema.js.map +0 -1
- package/dist/types/sdk/schema.d.ts +0 -99
- package/dist/types/sdk/schema.js.map +0 -1
|
@@ -32,17 +32,14 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
32
32
|
return result;
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
-
};
|
|
38
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
36
|
exports.AgentRuntime = void 0;
|
|
40
37
|
const ai_1 = require("ai");
|
|
41
|
-
const ajv_1 = __importDefault(require("ajv"));
|
|
42
38
|
const zod_to_json_schema_1 = require("zod-to-json-schema");
|
|
43
39
|
const catalog_1 = require("../sdk/catalog");
|
|
44
40
|
const message_1 = require("../sdk/message");
|
|
45
41
|
const event_bus_1 = require("./event-bus");
|
|
42
|
+
const json_value_1 = require("./json-value");
|
|
46
43
|
const memory_store_1 = require("./memory-store");
|
|
47
44
|
const message_list_1 = require("./message-list");
|
|
48
45
|
const messages_1 = require("./messages");
|
|
@@ -54,9 +51,67 @@ const strip_orphaned_tool_messages_1 = require("./strip-orphaned-tool-messages")
|
|
|
54
51
|
const title_generation_1 = require("./title-generation");
|
|
55
52
|
const tool_adapter_1 = require("./tool-adapter");
|
|
56
53
|
const working_memory_1 = require("./working-memory");
|
|
54
|
+
const parse_1 = require("../utils/parse");
|
|
57
55
|
const zod_1 = require("../utils/zod");
|
|
56
|
+
function isActiveSpanTracer(value) {
|
|
57
|
+
return (value !== null &&
|
|
58
|
+
typeof value === 'object' &&
|
|
59
|
+
typeof Reflect.get(value, 'startActiveSpan') === 'function');
|
|
60
|
+
}
|
|
61
|
+
function stringifyTelemetryValue(value) {
|
|
62
|
+
try {
|
|
63
|
+
return JSON.stringify(value);
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return undefined;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function getToolInputSchema(tool) {
|
|
70
|
+
if (!tool.inputSchema) {
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
return (0, zod_1.isZodSchema)(tool.inputSchema) ? (0, zod_to_json_schema_1.zodToJsonSchema)(tool.inputSchema) : tool.inputSchema;
|
|
74
|
+
}
|
|
75
|
+
function summarizeToolForTelemetry(tool) {
|
|
76
|
+
return {
|
|
77
|
+
name: tool.name,
|
|
78
|
+
description: tool.description,
|
|
79
|
+
type: tool.mcpTool ? 'mcp' : 'local',
|
|
80
|
+
...(tool.mcpServerName ? { mcp_server: tool.mcpServerName } : {}),
|
|
81
|
+
...(tool.suspendSchema || tool.resumeSchema || tool.withDefaultApproval
|
|
82
|
+
? { approval: true }
|
|
83
|
+
: {}),
|
|
84
|
+
...(tool.inputSchema ? { input_schema: getToolInputSchema(tool) } : {}),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function summarizeProviderToolForTelemetry(tool) {
|
|
88
|
+
const [provider] = tool.name.split('.');
|
|
89
|
+
return {
|
|
90
|
+
name: tool.name,
|
|
91
|
+
provider,
|
|
92
|
+
type: 'provider',
|
|
93
|
+
args: tool.args,
|
|
94
|
+
...(tool.inputSchema ? { input_schema: getToolInputSchema(tool) } : {}),
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
function buildAgentRootInputAttributes(config) {
|
|
98
|
+
const localTools = (config.tools ?? []).map(summarizeToolForTelemetry);
|
|
99
|
+
const providerTools = (config.providerTools ?? []).map(summarizeProviderToolForTelemetry);
|
|
100
|
+
const tools = [...localTools, ...providerTools];
|
|
101
|
+
const toolNames = tools
|
|
102
|
+
.map((tool) => (typeof tool.name === 'string' ? tool.name : undefined))
|
|
103
|
+
.filter((name) => name !== undefined);
|
|
104
|
+
const serialized = stringifyTelemetryValue({
|
|
105
|
+
agent: config.name,
|
|
106
|
+
tool_count: tools.length,
|
|
107
|
+
tools,
|
|
108
|
+
});
|
|
109
|
+
return {
|
|
110
|
+
...(toolNames.length > 0 ? { 'langsmith.metadata.available_tools': toolNames } : {}),
|
|
111
|
+
...(serialized ? { 'gen_ai.prompt': serialized } : {}),
|
|
112
|
+
};
|
|
113
|
+
}
|
|
58
114
|
const MAX_LOOP_ITERATIONS = 20;
|
|
59
|
-
const ajv = new ajv_1.default({ strict: false });
|
|
60
115
|
const EMPTY_MESSAGE_LIST = {
|
|
61
116
|
messages: [],
|
|
62
117
|
historyIds: [],
|
|
@@ -65,11 +120,9 @@ const EMPTY_MESSAGE_LIST = {
|
|
|
65
120
|
};
|
|
66
121
|
class AgentRuntime {
|
|
67
122
|
constructor(config) {
|
|
68
|
-
this.runId = '';
|
|
69
123
|
this.config = config;
|
|
70
|
-
this.runState =
|
|
124
|
+
this.runState = new run_state_1.RunStateManager(config.checkpointStorage);
|
|
71
125
|
this.eventBus = config.eventBus ?? new event_bus_1.AgentEventBus();
|
|
72
|
-
this.modelCost = config.modelCost;
|
|
73
126
|
this.currentState = {
|
|
74
127
|
persistence: undefined,
|
|
75
128
|
status: 'idle',
|
|
@@ -84,58 +137,44 @@ class AgentRuntime {
|
|
|
84
137
|
this.eventBus.abort();
|
|
85
138
|
}
|
|
86
139
|
async generate(input, options) {
|
|
87
|
-
|
|
88
|
-
this.executionOptions = options;
|
|
89
|
-
this.updateState({ persistence: options?.persistence });
|
|
140
|
+
const runId = (0, run_state_1.generateRunId)();
|
|
90
141
|
let list = undefined;
|
|
91
142
|
try {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
143
|
+
const initializedList = await this.initRun(input, options);
|
|
144
|
+
list = initializedList;
|
|
145
|
+
const rawResult = await this.withTelemetryRootSpan('generate', options, runId, async () => await this.runGenerateLoop({ list: initializedList, options, runId }));
|
|
146
|
+
return this.finalizeGenerate(rawResult, list, runId);
|
|
95
147
|
}
|
|
96
148
|
catch (error) {
|
|
97
|
-
await this.flushTelemetry();
|
|
149
|
+
await this.flushTelemetry(options);
|
|
98
150
|
const isAbort = this.eventBus.isAborted;
|
|
99
151
|
this.updateState({ status: isAbort ? 'cancelled' : 'failed' });
|
|
100
152
|
if (!isAbort) {
|
|
101
|
-
this.
|
|
153
|
+
this.eventBus.emit({ type: "error", message: String(error), error });
|
|
102
154
|
}
|
|
103
|
-
return {
|
|
104
|
-
runId: this.runId,
|
|
105
|
-
messages: list?.responseDelta() ?? [],
|
|
106
|
-
finishReason: 'error',
|
|
107
|
-
error,
|
|
108
|
-
getState: () => this.getState(),
|
|
109
|
-
};
|
|
155
|
+
return { runId, messages: list?.responseDelta() ?? [], finishReason: 'error', error };
|
|
110
156
|
}
|
|
111
157
|
}
|
|
112
158
|
async stream(input, options) {
|
|
113
|
-
|
|
114
|
-
this.executionOptions = options;
|
|
115
|
-
this.updateState({ persistence: options?.persistence });
|
|
159
|
+
const runId = (0, run_state_1.generateRunId)();
|
|
116
160
|
let list;
|
|
117
161
|
try {
|
|
118
|
-
list = await this.initRun(input);
|
|
162
|
+
list = await this.initRun(input, options);
|
|
119
163
|
}
|
|
120
164
|
catch (error) {
|
|
121
165
|
const isAbort = this.eventBus.isAborted;
|
|
122
166
|
this.updateState({ status: isAbort ? 'cancelled' : 'failed' });
|
|
123
167
|
if (!isAbort) {
|
|
124
|
-
this.
|
|
168
|
+
this.eventBus.emit({ type: "error", message: String(error), error });
|
|
125
169
|
}
|
|
126
|
-
return { runId
|
|
170
|
+
return { runId, stream: (0, runtime_helpers_1.makeErrorStream)(error) };
|
|
127
171
|
}
|
|
128
|
-
return {
|
|
129
|
-
runId: this.runId,
|
|
130
|
-
stream: this.startStreamLoop(list),
|
|
131
|
-
getState: () => this.getState(),
|
|
132
|
-
};
|
|
172
|
+
return { runId, stream: this.startStreamLoop({ list, options, runId }) };
|
|
133
173
|
}
|
|
134
174
|
async resume(method, data, options) {
|
|
135
|
-
|
|
136
|
-
const state = await this.runState.resume(this.runId);
|
|
175
|
+
const state = await this.runState.resume(options.runId);
|
|
137
176
|
if (!state)
|
|
138
|
-
throw new Error(`No suspended run found for runId: ${
|
|
177
|
+
throw new Error(`No suspended run found for runId: ${options.runId}`);
|
|
139
178
|
const toolCall = state.pendingToolCalls[options.toolCallId];
|
|
140
179
|
if (!toolCall)
|
|
141
180
|
throw new Error(`No tool call found for toolCallId: ${options.toolCallId}`);
|
|
@@ -144,9 +183,9 @@ class AgentRuntime {
|
|
|
144
183
|
throw new Error(`Tool ${toolCall.toolName} not found`);
|
|
145
184
|
let resumeData = data;
|
|
146
185
|
if (tool.resumeSchema) {
|
|
147
|
-
const parseResult = await tool.resumeSchema
|
|
186
|
+
const parseResult = await (0, parse_1.parseWithSchema)(tool.resumeSchema, data);
|
|
148
187
|
if (!parseResult.success) {
|
|
149
|
-
throw new Error(`Invalid resume payload: ${parseResult.error
|
|
188
|
+
throw new Error(`Invalid resume payload: ${parseResult.error}`);
|
|
150
189
|
}
|
|
151
190
|
resumeData = parseResult.data;
|
|
152
191
|
}
|
|
@@ -158,9 +197,11 @@ class AgentRuntime {
|
|
|
158
197
|
...persisted,
|
|
159
198
|
...callerExecOptions,
|
|
160
199
|
};
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
200
|
+
const resumeOptions = {
|
|
201
|
+
persistence: state.persistence,
|
|
202
|
+
...mergedExecOptions,
|
|
203
|
+
};
|
|
204
|
+
this.eventBus.resetAbort(resumeOptions.abortSignal);
|
|
164
205
|
const pendingResume = {
|
|
165
206
|
pendingToolCalls: state.pendingToolCalls,
|
|
166
207
|
resumeToolCallId: options.toolCallId,
|
|
@@ -170,51 +211,58 @@ class AgentRuntime {
|
|
|
170
211
|
await this.ensureModelCost();
|
|
171
212
|
await this.setListWorkingMemoryConfig(list, state.persistence);
|
|
172
213
|
if (method === 'generate') {
|
|
173
|
-
const rawResult = await this.
|
|
214
|
+
const rawResult = await this.withTelemetryRootSpan('generate', resumeOptions, options.runId, async () => await this.runGenerateLoop({
|
|
215
|
+
list,
|
|
216
|
+
options: resumeOptions,
|
|
217
|
+
runId: options.runId,
|
|
218
|
+
pendingResume,
|
|
219
|
+
}));
|
|
174
220
|
if (!rawResult.pendingSuspend) {
|
|
175
|
-
await this.cleanupRun();
|
|
221
|
+
await this.cleanupRun(options.runId);
|
|
176
222
|
}
|
|
177
|
-
return this.finalizeGenerate(rawResult, list);
|
|
223
|
+
return this.finalizeGenerate(rawResult, list, options.runId);
|
|
178
224
|
}
|
|
179
225
|
return {
|
|
180
|
-
runId:
|
|
181
|
-
stream: this.startStreamLoop(
|
|
182
|
-
|
|
226
|
+
runId: options.runId,
|
|
227
|
+
stream: this.startStreamLoop({
|
|
228
|
+
list,
|
|
229
|
+
options: resumeOptions,
|
|
230
|
+
runId: options.runId,
|
|
231
|
+
pendingResume,
|
|
232
|
+
}),
|
|
183
233
|
};
|
|
184
234
|
}
|
|
185
235
|
catch (error) {
|
|
186
236
|
const isAbort = this.eventBus.isAborted;
|
|
187
237
|
this.updateState({ status: isAbort ? 'cancelled' : 'failed' });
|
|
188
238
|
if (!isAbort) {
|
|
189
|
-
this.
|
|
239
|
+
this.eventBus.emit({ type: "error", message: String(error), error });
|
|
190
240
|
}
|
|
191
241
|
if (method === 'generate') {
|
|
192
242
|
return {
|
|
193
|
-
runId:
|
|
243
|
+
runId: options.runId,
|
|
194
244
|
messages: [],
|
|
195
245
|
finishReason: 'error',
|
|
196
246
|
error,
|
|
197
|
-
getState: () => this.getState(),
|
|
198
247
|
};
|
|
199
248
|
}
|
|
200
|
-
return { runId:
|
|
249
|
+
return { runId: options.runId, stream: (0, runtime_helpers_1.makeErrorStream)(error) };
|
|
201
250
|
}
|
|
202
251
|
}
|
|
203
|
-
async buildMessageList(input) {
|
|
252
|
+
async buildMessageList(input, options) {
|
|
204
253
|
const list = new message_list_1.AgentMessageList();
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
const memMessages = await this.config.memory.getMessages(persistence.threadId, {
|
|
254
|
+
if (this.config.memory && options?.persistence?.threadId) {
|
|
255
|
+
const memMessages = await this.config.memory.getMessages(options.persistence.threadId, {
|
|
208
256
|
limit: this.config.lastMessages ?? 10,
|
|
209
257
|
});
|
|
210
258
|
if (memMessages.length > 0) {
|
|
211
259
|
list.addHistory((0, strip_orphaned_tool_messages_1.stripOrphanedToolMessages)(memMessages));
|
|
212
260
|
}
|
|
213
261
|
}
|
|
214
|
-
if (this.config.semanticRecall && persistence?.threadId) {
|
|
215
|
-
await this.performSemanticRecall(list, input, persistence.threadId, persistence.resourceId);
|
|
262
|
+
if (this.config.semanticRecall && options?.persistence?.threadId) {
|
|
263
|
+
await this.performSemanticRecall(list, input, options.persistence.threadId, options.persistence.resourceId);
|
|
216
264
|
}
|
|
217
|
-
await this.setListWorkingMemoryConfig(list, persistence);
|
|
265
|
+
await this.setListWorkingMemoryConfig(list, options?.persistence);
|
|
218
266
|
list.addInput(input);
|
|
219
267
|
return list;
|
|
220
268
|
}
|
|
@@ -296,34 +344,37 @@ class AgentRuntime {
|
|
|
296
344
|
return mid && expandedIds.has(mid);
|
|
297
345
|
});
|
|
298
346
|
}
|
|
299
|
-
async initRun(input) {
|
|
300
|
-
this.eventBus.resetAbort(
|
|
301
|
-
this.updateState({
|
|
302
|
-
|
|
347
|
+
async initRun(input, options) {
|
|
348
|
+
this.eventBus.resetAbort(options?.abortSignal);
|
|
349
|
+
this.updateState({
|
|
350
|
+
status: 'running',
|
|
351
|
+
persistence: options?.persistence,
|
|
352
|
+
});
|
|
353
|
+
this.eventBus.emit({ type: "agent_start" });
|
|
303
354
|
await this.ensureModelCost();
|
|
304
355
|
const normalizedInput = (0, runtime_helpers_1.normalizeInput)(input);
|
|
305
|
-
return await this.buildMessageList(normalizedInput);
|
|
356
|
+
return await this.buildMessageList(normalizedInput, options);
|
|
306
357
|
}
|
|
307
|
-
finalizeGenerate(result, list) {
|
|
308
|
-
result.runId =
|
|
358
|
+
finalizeGenerate(result, list, runId) {
|
|
359
|
+
result.runId = runId;
|
|
309
360
|
result.usage = this.applyCost(result.usage);
|
|
310
361
|
result.model = this.modelIdString;
|
|
311
362
|
const finalized = (0, runtime_helpers_1.applySubAgentUsage)(result);
|
|
312
363
|
this.updateState({ status: 'success', messageList: list.serialize() });
|
|
313
|
-
this.
|
|
314
|
-
return
|
|
364
|
+
this.eventBus.emit({ type: "agent_end", messages: finalized.messages });
|
|
365
|
+
return finalized;
|
|
315
366
|
}
|
|
316
|
-
resolveTelemetry() {
|
|
367
|
+
resolveTelemetry(options) {
|
|
317
368
|
if (this.config.telemetry)
|
|
318
369
|
return this.config.telemetry;
|
|
319
|
-
const inherited =
|
|
370
|
+
const inherited = options?.telemetry;
|
|
320
371
|
if (!inherited)
|
|
321
372
|
return undefined;
|
|
322
373
|
return { ...inherited, functionId: this.config.name };
|
|
323
374
|
}
|
|
324
|
-
async flushTelemetry() {
|
|
375
|
+
async flushTelemetry(options) {
|
|
325
376
|
try {
|
|
326
|
-
const resolved = this.resolveTelemetry();
|
|
377
|
+
const resolved = this.resolveTelemetry(options);
|
|
327
378
|
if (resolved?.provider) {
|
|
328
379
|
await resolved.provider.forceFlush();
|
|
329
380
|
}
|
|
@@ -331,8 +382,8 @@ class AgentRuntime {
|
|
|
331
382
|
catch {
|
|
332
383
|
}
|
|
333
384
|
}
|
|
334
|
-
buildTelemetryOptions() {
|
|
335
|
-
const t = this.resolveTelemetry();
|
|
385
|
+
buildTelemetryOptions(options) {
|
|
386
|
+
const t = this.resolveTelemetry(options);
|
|
336
387
|
if (!t?.enabled)
|
|
337
388
|
return {};
|
|
338
389
|
return {
|
|
@@ -347,23 +398,103 @@ class AgentRuntime {
|
|
|
347
398
|
},
|
|
348
399
|
};
|
|
349
400
|
}
|
|
350
|
-
|
|
351
|
-
const
|
|
401
|
+
buildTelemetryRootAttributes(t, spanName, runId) {
|
|
402
|
+
const metadataAttributes = this.buildTelemetryMetadataAttributes(t, 'langsmith.metadata');
|
|
403
|
+
return {
|
|
404
|
+
'langsmith.traceable': 'true',
|
|
405
|
+
'langsmith.trace.name': spanName,
|
|
406
|
+
'langsmith.span.kind': 'chain',
|
|
407
|
+
'langsmith.metadata.agent_name': this.config.name,
|
|
408
|
+
'langsmith.metadata.agent_run_id': runId,
|
|
409
|
+
...metadataAttributes,
|
|
410
|
+
...buildAgentRootInputAttributes(this.config),
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
buildTelemetryMetadataAttributes(t, prefix) {
|
|
414
|
+
return Object.fromEntries(Object.entries(t.metadata ?? {}).map(([key, value]) => [`${prefix}.${key}`, value]));
|
|
415
|
+
}
|
|
416
|
+
buildAiSdkOperationAttributes(operationId, t) {
|
|
417
|
+
const functionId = t.functionId ?? this.config.name;
|
|
418
|
+
return {
|
|
419
|
+
'operation.name': `${operationId} ${functionId}`,
|
|
420
|
+
'resource.name': functionId,
|
|
421
|
+
'ai.operationId': operationId,
|
|
422
|
+
'ai.telemetry.functionId': functionId,
|
|
423
|
+
...this.buildTelemetryMetadataAttributes(t, 'ai.telemetry.metadata'),
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
async withTelemetryRootSpan(operation, options, runId, fn) {
|
|
427
|
+
const t = this.resolveTelemetry(options);
|
|
428
|
+
if (!t?.enabled || t.runtimeRootSpanEnabled === false || !isActiveSpanTracer(t.tracer)) {
|
|
429
|
+
return await fn();
|
|
430
|
+
}
|
|
431
|
+
const spanName = `${t.functionId ?? this.config.name}.${operation}`;
|
|
432
|
+
return await t.tracer.startActiveSpan(spanName, { attributes: this.buildTelemetryRootAttributes(t, spanName, runId) }, async (span) => {
|
|
433
|
+
try {
|
|
434
|
+
return await fn();
|
|
435
|
+
}
|
|
436
|
+
catch (error) {
|
|
437
|
+
span.recordException?.(error);
|
|
438
|
+
span.setStatus?.({ code: 2, message: String(error) });
|
|
439
|
+
throw error;
|
|
440
|
+
}
|
|
441
|
+
finally {
|
|
442
|
+
span.end();
|
|
443
|
+
}
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
async withTelemetryToolSpan(toolCallId, toolName, input, t, fn) {
|
|
447
|
+
if (!t?.enabled || !isActiveSpanTracer(t.tracer)) {
|
|
448
|
+
return await fn();
|
|
449
|
+
}
|
|
450
|
+
const shouldRecordInputs = t.recordInputs ?? true;
|
|
451
|
+
const inputValue = shouldRecordInputs ? stringifyTelemetryValue(input) : undefined;
|
|
452
|
+
return await t.tracer.startActiveSpan('ai.toolCall', {
|
|
453
|
+
attributes: {
|
|
454
|
+
...this.buildAiSdkOperationAttributes('ai.toolCall', t),
|
|
455
|
+
'ai.toolCall.name': toolName,
|
|
456
|
+
'ai.toolCall.id': toolCallId,
|
|
457
|
+
...(inputValue !== undefined ? { 'ai.toolCall.args': inputValue } : {}),
|
|
458
|
+
},
|
|
459
|
+
}, async (span) => {
|
|
460
|
+
try {
|
|
461
|
+
const result = await fn();
|
|
462
|
+
const shouldRecordOutputs = t.recordOutputs ?? true;
|
|
463
|
+
const outputValue = shouldRecordOutputs ? stringifyTelemetryValue(result) : undefined;
|
|
464
|
+
if (outputValue !== undefined) {
|
|
465
|
+
span.setAttributes?.({ 'ai.toolCall.result': outputValue });
|
|
466
|
+
}
|
|
467
|
+
return result;
|
|
468
|
+
}
|
|
469
|
+
catch (error) {
|
|
470
|
+
span.recordException?.(error);
|
|
471
|
+
span.setStatus?.({ code: 2, message: String(error) });
|
|
472
|
+
throw error;
|
|
473
|
+
}
|
|
474
|
+
finally {
|
|
475
|
+
span.end();
|
|
476
|
+
}
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
async runGenerateLoop(ctx) {
|
|
480
|
+
const { list, options, runId, pendingResume } = ctx;
|
|
481
|
+
const { model, toolMap, aiTools, providerOptions, hasTools, outputSpec, effectiveInstructions, } = this.buildLoopContext({ ...options, persistence: options?.persistence });
|
|
352
482
|
let totalUsage;
|
|
353
483
|
let lastFinishReason = 'stop';
|
|
354
484
|
let structuredOutput;
|
|
355
485
|
const toolCallSummary = [];
|
|
356
486
|
const collectedSubAgentUsage = [];
|
|
357
|
-
const runTelemetry = this.resolveTelemetry();
|
|
487
|
+
const runTelemetry = this.resolveTelemetry(options);
|
|
488
|
+
const toolCtx = { toolMap, list, runId, telemetry: runTelemetry };
|
|
358
489
|
if (pendingResume) {
|
|
359
|
-
const batch = await this.iteratePendingToolCallsConcurrent(
|
|
490
|
+
const batch = await this.iteratePendingToolCallsConcurrent({ ...toolCtx, pendingResume });
|
|
360
491
|
for (const r of batch.results) {
|
|
361
492
|
toolCallSummary.push(r.toolEntry);
|
|
362
493
|
if (r.subAgentUsage)
|
|
363
494
|
collectedSubAgentUsage.push(...r.subAgentUsage);
|
|
364
495
|
}
|
|
365
496
|
if (Object.keys(batch.pending).length > 0) {
|
|
366
|
-
const suspendRunId = await this.persistSuspension(batch.pending, list, totalUsage);
|
|
497
|
+
const suspendRunId = await this.persistSuspension(batch.pending, options, list, totalUsage, runId);
|
|
367
498
|
return {
|
|
368
499
|
runId: suspendRunId,
|
|
369
500
|
messages: list.responseDelta(),
|
|
@@ -377,27 +508,26 @@ class AgentRuntime {
|
|
|
377
508
|
suspendPayload: s.payload,
|
|
378
509
|
resumeSchema: s.resumeSchema,
|
|
379
510
|
})),
|
|
380
|
-
getState: () => this.getState(),
|
|
381
511
|
};
|
|
382
512
|
}
|
|
383
513
|
}
|
|
384
|
-
const maxIterations =
|
|
514
|
+
const maxIterations = options?.maxIterations ?? MAX_LOOP_ITERATIONS;
|
|
385
515
|
for (let i = 0; i < maxIterations; i++) {
|
|
386
516
|
if (this.eventBus.isAborted) {
|
|
387
517
|
this.updateState({ status: 'cancelled' });
|
|
388
518
|
throw new Error('Agent run was aborted');
|
|
389
519
|
}
|
|
390
|
-
this.
|
|
520
|
+
this.eventBus.emit({ type: "turn_start" });
|
|
391
521
|
const result = await (0, ai_1.generateText)({
|
|
392
522
|
model,
|
|
393
|
-
messages: list.forLlm(
|
|
523
|
+
messages: list.forLlm(effectiveInstructions, this.config.instructionProviderOptions),
|
|
394
524
|
abortSignal: this.eventBus.signal,
|
|
395
525
|
...(hasTools ? { tools: aiTools } : {}),
|
|
396
526
|
...(providerOptions
|
|
397
527
|
? { providerOptions: providerOptions }
|
|
398
528
|
: {}),
|
|
399
529
|
...(outputSpec ? { output: outputSpec } : {}),
|
|
400
|
-
...this.buildTelemetryOptions(),
|
|
530
|
+
...this.buildTelemetryOptions(options),
|
|
401
531
|
});
|
|
402
532
|
const aiFinishReason = result.finishReason;
|
|
403
533
|
lastFinishReason = (0, messages_1.fromAiFinishReason)(aiFinishReason);
|
|
@@ -409,17 +539,20 @@ class AgentRuntime {
|
|
|
409
539
|
if (outputSpec) {
|
|
410
540
|
structuredOutput = result.output;
|
|
411
541
|
}
|
|
412
|
-
this.emitTurnEnd(newMessages, (0, runtime_helpers_1.
|
|
542
|
+
this.emitTurnEnd(newMessages, (0, runtime_helpers_1.extractSettledToolCalls)(newMessages));
|
|
413
543
|
break;
|
|
414
544
|
}
|
|
415
|
-
const batch = await this.iterateToolCallsConcurrent(
|
|
545
|
+
const batch = await this.iterateToolCallsConcurrent({
|
|
546
|
+
...toolCtx,
|
|
547
|
+
toolCalls: result.toolCalls,
|
|
548
|
+
});
|
|
416
549
|
for (const r of batch.results) {
|
|
417
550
|
toolCallSummary.push(r.toolEntry);
|
|
418
551
|
if (r.subAgentUsage)
|
|
419
552
|
collectedSubAgentUsage.push(...r.subAgentUsage);
|
|
420
553
|
}
|
|
421
554
|
if (Object.keys(batch.pending).length > 0) {
|
|
422
|
-
const suspendRunId = await this.persistSuspension(batch.pending, list, totalUsage);
|
|
555
|
+
const suspendRunId = await this.persistSuspension(batch.pending, options, list, totalUsage, runId);
|
|
423
556
|
return {
|
|
424
557
|
runId: suspendRunId,
|
|
425
558
|
messages: list.responseDelta(),
|
|
@@ -433,44 +566,58 @@ class AgentRuntime {
|
|
|
433
566
|
suspendPayload: s.payload,
|
|
434
567
|
resumeSchema: s.resumeSchema,
|
|
435
568
|
})),
|
|
436
|
-
getState: () => this.getState(),
|
|
437
569
|
};
|
|
438
570
|
}
|
|
439
|
-
this.emitTurnEnd(newMessages, (0, runtime_helpers_1.
|
|
571
|
+
this.emitTurnEnd(newMessages, (0, runtime_helpers_1.extractSettledToolCalls)(list.responseDelta()));
|
|
440
572
|
}
|
|
441
573
|
if (lastFinishReason === 'tool-calls') {
|
|
442
574
|
throw new Error(`Agent loop exceeded ${maxIterations} iterations without reaching a stop condition`);
|
|
443
575
|
}
|
|
444
|
-
await this.saveToMemory(list);
|
|
445
|
-
await this.flushTelemetry();
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
void (0, title_generation_1.generateThreadTitle)({
|
|
576
|
+
await this.saveToMemory(list, options);
|
|
577
|
+
await this.flushTelemetry(options);
|
|
578
|
+
if (this.config.titleGeneration && options?.persistence?.threadId && this.config.memory) {
|
|
579
|
+
const titlePromise = (0, title_generation_1.generateThreadTitle)({
|
|
449
580
|
memory: this.config.memory,
|
|
450
|
-
threadId: persistence.threadId,
|
|
451
|
-
resourceId: persistence.resourceId,
|
|
581
|
+
threadId: options.persistence.threadId,
|
|
582
|
+
resourceId: options.persistence.resourceId,
|
|
452
583
|
titleConfig: this.config.titleGeneration,
|
|
453
584
|
agentModel: this.config.model,
|
|
454
585
|
turnDelta: list.turnDelta(),
|
|
455
586
|
});
|
|
587
|
+
if (this.config.titleGeneration.sync) {
|
|
588
|
+
await titlePromise;
|
|
589
|
+
}
|
|
456
590
|
}
|
|
457
591
|
return {
|
|
458
|
-
runId:
|
|
592
|
+
runId: runId ?? '',
|
|
459
593
|
messages: list.responseDelta(),
|
|
460
594
|
finishReason: lastFinishReason,
|
|
461
595
|
usage: totalUsage,
|
|
462
596
|
...(structuredOutput !== undefined && { structuredOutput }),
|
|
463
597
|
...(toolCallSummary.length > 0 && { toolCalls: toolCallSummary }),
|
|
464
598
|
...(collectedSubAgentUsage.length > 0 && { subAgentUsage: collectedSubAgentUsage }),
|
|
465
|
-
getState: () => this.getState(),
|
|
466
599
|
};
|
|
467
600
|
}
|
|
468
|
-
startStreamLoop(
|
|
601
|
+
startStreamLoop(ctx) {
|
|
602
|
+
const { options, runId } = ctx;
|
|
469
603
|
const { readable, writable } = new TransformStream();
|
|
470
604
|
const writer = writable.getWriter();
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
605
|
+
const onToolExecutionStart = (data) => {
|
|
606
|
+
if (data.type !== "tool_execution_start")
|
|
607
|
+
return;
|
|
608
|
+
writer
|
|
609
|
+
.write({
|
|
610
|
+
type: 'tool-execution-start',
|
|
611
|
+
toolCallId: data.toolCallId,
|
|
612
|
+
toolName: data.toolName,
|
|
613
|
+
})
|
|
614
|
+
.catch(() => { });
|
|
615
|
+
};
|
|
616
|
+
this.eventBus.on("tool_execution_start", onToolExecutionStart);
|
|
617
|
+
this.withTelemetryRootSpan('stream', options, runId, async () => await this.runStreamLoop({ ...ctx, writer }))
|
|
618
|
+
.catch(async (error) => {
|
|
619
|
+
await this.flushTelemetry(options);
|
|
620
|
+
await this.cleanupRun(runId);
|
|
474
621
|
try {
|
|
475
622
|
await writer.write({ type: 'error', error });
|
|
476
623
|
await writer.write({ type: 'finish', finishReason: 'error' });
|
|
@@ -479,11 +626,15 @@ class AgentRuntime {
|
|
|
479
626
|
catch {
|
|
480
627
|
writer.abort(error).catch(() => { });
|
|
481
628
|
}
|
|
629
|
+
})
|
|
630
|
+
.finally(() => {
|
|
631
|
+
this.eventBus.off("tool_execution_start", onToolExecutionStart);
|
|
482
632
|
});
|
|
483
633
|
return readable;
|
|
484
634
|
}
|
|
485
|
-
async runStreamLoop(
|
|
486
|
-
const {
|
|
635
|
+
async runStreamLoop(ctx) {
|
|
636
|
+
const { list, options, runId, pendingResume, writer } = ctx;
|
|
637
|
+
const { model, toolMap, aiTools, providerOptions, hasTools, outputSpec, effectiveInstructions, } = this.buildLoopContext({ ...options, persistence: options?.persistence });
|
|
487
638
|
const writeChunk = async (chunk) => {
|
|
488
639
|
await writer.write(chunk);
|
|
489
640
|
};
|
|
@@ -491,9 +642,9 @@ class AgentRuntime {
|
|
|
491
642
|
let lastFinishReason = 'stop';
|
|
492
643
|
let structuredOutput;
|
|
493
644
|
const collectedSubAgentUsage = [];
|
|
494
|
-
const maxIterations =
|
|
645
|
+
const maxIterations = options?.maxIterations ?? MAX_LOOP_ITERATIONS;
|
|
495
646
|
const closeStreamWithError = async (error, status) => {
|
|
496
|
-
await this.cleanupRun();
|
|
647
|
+
await this.cleanupRun(runId);
|
|
497
648
|
this.updateState({ status });
|
|
498
649
|
await writer.write({ type: 'error', error });
|
|
499
650
|
await writer.write({ type: 'finish', finishReason: 'error' });
|
|
@@ -505,16 +656,22 @@ class AgentRuntime {
|
|
|
505
656
|
await closeStreamWithError(new Error('Agent run was aborted'), 'cancelled');
|
|
506
657
|
return true;
|
|
507
658
|
};
|
|
508
|
-
const runTelemetry = this.resolveTelemetry();
|
|
659
|
+
const runTelemetry = this.resolveTelemetry(options);
|
|
660
|
+
const toolCtx = { toolMap, list, runId, telemetry: runTelemetry };
|
|
509
661
|
if (pendingResume) {
|
|
510
662
|
try {
|
|
511
|
-
const batch = await this.iteratePendingToolCallsConcurrent(
|
|
663
|
+
const batch = await this.iteratePendingToolCallsConcurrent({
|
|
664
|
+
...toolCtx,
|
|
665
|
+
pendingResume,
|
|
666
|
+
});
|
|
512
667
|
for (const r of batch.results) {
|
|
513
668
|
if (r.subAgentUsage)
|
|
514
669
|
collectedSubAgentUsage.push(...r.subAgentUsage);
|
|
515
670
|
await writer.write({
|
|
516
|
-
type: '
|
|
517
|
-
|
|
671
|
+
type: 'tool-result',
|
|
672
|
+
toolCallId: r.toolCallId,
|
|
673
|
+
toolName: r.toolName,
|
|
674
|
+
output: r.modelOutput,
|
|
518
675
|
});
|
|
519
676
|
if (r.customMessage) {
|
|
520
677
|
await writer.write({ type: 'message', message: r.customMessage });
|
|
@@ -522,12 +679,15 @@ class AgentRuntime {
|
|
|
522
679
|
}
|
|
523
680
|
for (const e of batch.errors) {
|
|
524
681
|
await writer.write({
|
|
525
|
-
type: '
|
|
526
|
-
|
|
682
|
+
type: 'tool-result',
|
|
683
|
+
toolCallId: e.toolCallId,
|
|
684
|
+
toolName: e.toolName,
|
|
685
|
+
output: e.error,
|
|
686
|
+
isError: true,
|
|
527
687
|
});
|
|
528
688
|
}
|
|
529
689
|
if (Object.keys(batch.pending).length > 0) {
|
|
530
|
-
const suspendRunId = await this.persistSuspension(batch.pending, list, totalUsage);
|
|
690
|
+
const suspendRunId = await this.persistSuspension(batch.pending, options, list, totalUsage, runId);
|
|
531
691
|
for (const s of batch.suspensions) {
|
|
532
692
|
await writer.write({
|
|
533
693
|
type: 'tool-call-suspended',
|
|
@@ -545,7 +705,7 @@ class AgentRuntime {
|
|
|
545
705
|
}
|
|
546
706
|
}
|
|
547
707
|
catch (error) {
|
|
548
|
-
this.
|
|
708
|
+
this.eventBus.emit({ type: "error", message: String(error), error });
|
|
549
709
|
await closeStreamWithError(error, 'failed');
|
|
550
710
|
return;
|
|
551
711
|
}
|
|
@@ -553,21 +713,22 @@ class AgentRuntime {
|
|
|
553
713
|
for (let i = 0; i < maxIterations; i++) {
|
|
554
714
|
if (await handleAbort())
|
|
555
715
|
return;
|
|
556
|
-
this.
|
|
716
|
+
this.eventBus.emit({ type: "turn_start" });
|
|
717
|
+
const messages = list.forLlm(effectiveInstructions, this.config.instructionProviderOptions);
|
|
557
718
|
const result = (0, ai_1.streamText)({
|
|
558
719
|
model,
|
|
559
|
-
messages
|
|
720
|
+
messages,
|
|
560
721
|
abortSignal: this.eventBus.signal,
|
|
561
722
|
...(hasTools ? { tools: aiTools } : {}),
|
|
562
723
|
...(providerOptions
|
|
563
724
|
? { providerOptions: providerOptions }
|
|
564
725
|
: {}),
|
|
565
726
|
...(outputSpec ? { output: outputSpec } : {}),
|
|
566
|
-
...this.buildTelemetryOptions(),
|
|
727
|
+
...this.buildTelemetryOptions(options),
|
|
567
728
|
});
|
|
568
729
|
try {
|
|
569
730
|
for await (const chunk of result.fullStream) {
|
|
570
|
-
if (chunk.type === 'finish'
|
|
731
|
+
if (chunk.type === 'finish')
|
|
571
732
|
continue;
|
|
572
733
|
const converted = (0, stream_1.convertChunk)(chunk);
|
|
573
734
|
if (converted)
|
|
@@ -577,7 +738,7 @@ class AgentRuntime {
|
|
|
577
738
|
catch (streamError) {
|
|
578
739
|
if (await handleAbort())
|
|
579
740
|
return;
|
|
580
|
-
this.
|
|
741
|
+
this.eventBus.emit({
|
|
581
742
|
type: "error",
|
|
582
743
|
message: String(streamError),
|
|
583
744
|
error: streamError,
|
|
@@ -599,20 +760,22 @@ class AgentRuntime {
|
|
|
599
760
|
if (outputSpec) {
|
|
600
761
|
structuredOutput = await result.output;
|
|
601
762
|
}
|
|
602
|
-
this.emitTurnEnd(newMessages, (0, runtime_helpers_1.
|
|
763
|
+
this.emitTurnEnd(newMessages, (0, runtime_helpers_1.extractSettledToolCalls)(newMessages));
|
|
603
764
|
break;
|
|
604
765
|
}
|
|
605
766
|
const toolCalls = await result.toolCalls;
|
|
606
767
|
try {
|
|
607
|
-
const batch = await this.iterateToolCallsConcurrent(
|
|
768
|
+
const batch = await this.iterateToolCallsConcurrent({ ...toolCtx, toolCalls });
|
|
608
769
|
if (await handleAbort())
|
|
609
770
|
return;
|
|
610
771
|
for (const r of batch.results) {
|
|
611
772
|
if (r.subAgentUsage)
|
|
612
773
|
collectedSubAgentUsage.push(...r.subAgentUsage);
|
|
613
774
|
await writer.write({
|
|
614
|
-
type: '
|
|
615
|
-
|
|
775
|
+
type: 'tool-result',
|
|
776
|
+
toolCallId: r.toolCallId,
|
|
777
|
+
toolName: r.toolName,
|
|
778
|
+
output: r.modelOutput,
|
|
616
779
|
});
|
|
617
780
|
if (r.customMessage) {
|
|
618
781
|
await writer.write({ type: 'message', message: r.customMessage });
|
|
@@ -620,12 +783,15 @@ class AgentRuntime {
|
|
|
620
783
|
}
|
|
621
784
|
for (const e of batch.errors) {
|
|
622
785
|
await writer.write({
|
|
623
|
-
type: '
|
|
624
|
-
|
|
786
|
+
type: 'tool-result',
|
|
787
|
+
toolCallId: e.toolCallId,
|
|
788
|
+
toolName: e.toolName,
|
|
789
|
+
output: e.error,
|
|
790
|
+
isError: true,
|
|
625
791
|
});
|
|
626
792
|
}
|
|
627
793
|
if (Object.keys(batch.pending).length > 0) {
|
|
628
|
-
const suspendRunId = await this.persistSuspension(batch.pending, list, totalUsage);
|
|
794
|
+
const suspendRunId = await this.persistSuspension(batch.pending, options, list, totalUsage, runId);
|
|
629
795
|
for (const s of batch.suspensions) {
|
|
630
796
|
await writer.write({
|
|
631
797
|
type: 'tool-call-suspended',
|
|
@@ -643,11 +809,11 @@ class AgentRuntime {
|
|
|
643
809
|
}
|
|
644
810
|
}
|
|
645
811
|
catch (error) {
|
|
646
|
-
this.
|
|
812
|
+
this.eventBus.emit({ type: "error", message: String(error), error });
|
|
647
813
|
await closeStreamWithError(error, 'failed');
|
|
648
814
|
return;
|
|
649
815
|
}
|
|
650
|
-
this.emitTurnEnd(newMessages, (0, runtime_helpers_1.
|
|
816
|
+
this.emitTurnEnd(newMessages, (0, runtime_helpers_1.extractSettledToolCalls)(list.responseDelta()));
|
|
651
817
|
}
|
|
652
818
|
const costUsage = this.applyCost(totalUsage);
|
|
653
819
|
const parentCost = costUsage?.cost ?? 0;
|
|
@@ -664,37 +830,38 @@ class AgentRuntime {
|
|
|
664
830
|
}),
|
|
665
831
|
});
|
|
666
832
|
try {
|
|
667
|
-
await this.saveToMemory(list);
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
void (0, title_generation_1.generateThreadTitle)({
|
|
833
|
+
await this.saveToMemory(list, options);
|
|
834
|
+
if (this.config.titleGeneration && options?.persistence && this.config.memory) {
|
|
835
|
+
const titlePromise = (0, title_generation_1.generateThreadTitle)({
|
|
671
836
|
memory: this.config.memory,
|
|
672
|
-
threadId: persistence.threadId,
|
|
673
|
-
resourceId: persistence.resourceId,
|
|
837
|
+
threadId: options.persistence.threadId,
|
|
838
|
+
resourceId: options.persistence.resourceId,
|
|
674
839
|
titleConfig: this.config.titleGeneration,
|
|
675
840
|
agentModel: this.config.model,
|
|
676
841
|
turnDelta: list.turnDelta(),
|
|
677
842
|
});
|
|
843
|
+
if (this.config.titleGeneration.sync) {
|
|
844
|
+
await titlePromise;
|
|
845
|
+
}
|
|
678
846
|
}
|
|
679
|
-
await this.cleanupRun();
|
|
680
|
-
await this.flushTelemetry();
|
|
847
|
+
await this.cleanupRun(runId);
|
|
848
|
+
await this.flushTelemetry(options);
|
|
681
849
|
this.updateState({ status: 'success', messageList: list.serialize() });
|
|
682
|
-
this.
|
|
850
|
+
this.eventBus.emit({ type: "agent_end", messages: list.responseDelta() });
|
|
683
851
|
}
|
|
684
852
|
finally {
|
|
685
853
|
await writer.close();
|
|
686
854
|
}
|
|
687
855
|
}
|
|
688
|
-
async saveToMemory(list) {
|
|
689
|
-
|
|
690
|
-
if (!this.config.memory || !persistence)
|
|
856
|
+
async saveToMemory(list, options) {
|
|
857
|
+
if (!this.config.memory || !options?.persistence)
|
|
691
858
|
return;
|
|
692
859
|
const delta = list.turnDelta();
|
|
693
860
|
if (delta.length === 0)
|
|
694
861
|
return;
|
|
695
|
-
await (0, memory_store_1.saveMessagesToThread)(this.config.memory, persistence.threadId, persistence.resourceId, delta);
|
|
862
|
+
await (0, memory_store_1.saveMessagesToThread)(this.config.memory, options.persistence.threadId, options.persistence.resourceId, delta);
|
|
696
863
|
if (this.config.semanticRecall?.embedder && this.config.memory.saveEmbeddings) {
|
|
697
|
-
await this.saveEmbeddingsForMessages(persistence.threadId, persistence.resourceId, delta);
|
|
864
|
+
await this.saveEmbeddingsForMessages(options.persistence.threadId, options.persistence.resourceId, delta);
|
|
698
865
|
}
|
|
699
866
|
}
|
|
700
867
|
async saveEmbeddingsForMessages(threadId, resourceId, messages) {
|
|
@@ -792,7 +959,8 @@ class AgentRuntime {
|
|
|
792
959
|
}
|
|
793
960
|
return merged;
|
|
794
961
|
}
|
|
795
|
-
async iterateToolCallsConcurrent(
|
|
962
|
+
async iterateToolCallsConcurrent(ctx) {
|
|
963
|
+
const { toolCalls, toolMap, list, runId, telemetry: resolvedTelemetry } = ctx;
|
|
796
964
|
const executableCalls = toolCalls.filter((tc) => !tc.providerExecuted);
|
|
797
965
|
const executableCallsById = new Map(executableCalls.map((tc) => [tc.toolCallId, tc]));
|
|
798
966
|
const unexecutedIds = new Set(executableCalls.map((tc) => tc.toolCallId));
|
|
@@ -817,12 +985,12 @@ class AgentRuntime {
|
|
|
817
985
|
const tc = batch[i];
|
|
818
986
|
const toolInput = tc.input;
|
|
819
987
|
if (result.status === 'rejected') {
|
|
988
|
+
list.setToolCallError(tc.toolCallId, result.reason);
|
|
820
989
|
errors.push({
|
|
821
990
|
toolCallId: tc.toolCallId,
|
|
822
991
|
toolName: tc.toolName,
|
|
823
992
|
input: toolInput,
|
|
824
993
|
error: result.reason,
|
|
825
|
-
message: (0, runtime_helpers_1.makeErrorToolResultMessage)(tc.toolCallId, tc.toolName, result.reason),
|
|
826
994
|
});
|
|
827
995
|
}
|
|
828
996
|
else if (result.value.outcome === 'suspended') {
|
|
@@ -841,6 +1009,7 @@ class AgentRuntime {
|
|
|
841
1009
|
input: toolInput,
|
|
842
1010
|
suspendPayload: result.value.payload,
|
|
843
1011
|
resumeSchema: result.value.resumeSchema,
|
|
1012
|
+
runId,
|
|
844
1013
|
};
|
|
845
1014
|
}
|
|
846
1015
|
else if (result.value.outcome === 'success') {
|
|
@@ -849,9 +1018,9 @@ class AgentRuntime {
|
|
|
849
1018
|
toolName: tc.toolName,
|
|
850
1019
|
input: toolInput,
|
|
851
1020
|
toolEntry: result.value.toolEntry,
|
|
1021
|
+
modelOutput: result.value.modelOutput,
|
|
852
1022
|
subAgentUsage: result.value.subAgentUsage,
|
|
853
1023
|
customMessage: result.value.customMessage,
|
|
854
|
-
message: result.value.message,
|
|
855
1024
|
});
|
|
856
1025
|
}
|
|
857
1026
|
else if (result.value.outcome === 'error') {
|
|
@@ -860,7 +1029,6 @@ class AgentRuntime {
|
|
|
860
1029
|
toolName: tc.toolName,
|
|
861
1030
|
input: toolInput,
|
|
862
1031
|
error: result.value.error,
|
|
863
|
-
message: result.value.message,
|
|
864
1032
|
});
|
|
865
1033
|
}
|
|
866
1034
|
else if (result.value.outcome === 'noop') {
|
|
@@ -881,7 +1049,8 @@ class AgentRuntime {
|
|
|
881
1049
|
}
|
|
882
1050
|
return { results, suspensions, errors, pending };
|
|
883
1051
|
}
|
|
884
|
-
async iteratePendingToolCallsConcurrent(
|
|
1052
|
+
async iteratePendingToolCallsConcurrent(ctx) {
|
|
1053
|
+
const { pendingResume, toolMap, list, runId, telemetry: resolvedTelemetry } = ctx;
|
|
885
1054
|
const resumedId = pendingResume.resumeToolCallId;
|
|
886
1055
|
const resumedEntry = pendingResume.pendingToolCalls[resumedId];
|
|
887
1056
|
if (!resumedEntry) {
|
|
@@ -899,6 +1068,7 @@ class AgentRuntime {
|
|
|
899
1068
|
suspended: true,
|
|
900
1069
|
suspendPayload: processResult.payload,
|
|
901
1070
|
resumeSchema: processResult.resumeSchema,
|
|
1071
|
+
runId,
|
|
902
1072
|
};
|
|
903
1073
|
suspensions.push({
|
|
904
1074
|
toolCallId: resumedId,
|
|
@@ -914,9 +1084,9 @@ class AgentRuntime {
|
|
|
914
1084
|
toolName: resumedToolName,
|
|
915
1085
|
input: resumedEntry.input,
|
|
916
1086
|
toolEntry: processResult.toolEntry,
|
|
1087
|
+
modelOutput: processResult.modelOutput,
|
|
917
1088
|
subAgentUsage: processResult.subAgentUsage,
|
|
918
1089
|
customMessage: processResult.customMessage,
|
|
919
|
-
message: processResult.message,
|
|
920
1090
|
});
|
|
921
1091
|
}
|
|
922
1092
|
else if (processResult.outcome === 'error') {
|
|
@@ -925,7 +1095,6 @@ class AgentRuntime {
|
|
|
925
1095
|
toolName: resumedToolName,
|
|
926
1096
|
input: resumedEntry.input,
|
|
927
1097
|
error: processResult.error,
|
|
928
|
-
message: processResult.message,
|
|
929
1098
|
});
|
|
930
1099
|
}
|
|
931
1100
|
else if (processResult.outcome === 'noop') {
|
|
@@ -954,7 +1123,13 @@ class AgentRuntime {
|
|
|
954
1123
|
}
|
|
955
1124
|
}
|
|
956
1125
|
if (unexecuted.length > 0) {
|
|
957
|
-
const batch = await this.iterateToolCallsConcurrent(
|
|
1126
|
+
const batch = await this.iterateToolCallsConcurrent({
|
|
1127
|
+
toolCalls: unexecuted,
|
|
1128
|
+
toolMap,
|
|
1129
|
+
list,
|
|
1130
|
+
runId,
|
|
1131
|
+
telemetry: resolvedTelemetry,
|
|
1132
|
+
});
|
|
958
1133
|
results.push(...batch.results);
|
|
959
1134
|
suspensions.push(...batch.suspensions);
|
|
960
1135
|
errors.push(...batch.errors);
|
|
@@ -964,71 +1139,66 @@ class AgentRuntime {
|
|
|
964
1139
|
}
|
|
965
1140
|
async processToolCall(toolCallId, toolName, toolInput, toolMap, list, resumeData, resolvedTelemetry) {
|
|
966
1141
|
const builtTool = toolMap.get(toolName);
|
|
967
|
-
this.
|
|
1142
|
+
this.eventBus.emit({
|
|
968
1143
|
type: "tool_execution_start",
|
|
969
1144
|
toolCallId,
|
|
970
1145
|
toolName,
|
|
971
1146
|
args: toolInput,
|
|
972
1147
|
});
|
|
973
1148
|
const makeToolError = (error) => {
|
|
974
|
-
this.
|
|
1149
|
+
this.eventBus.emit({
|
|
975
1150
|
type: "tool_execution_end",
|
|
976
1151
|
toolCallId,
|
|
977
1152
|
toolName,
|
|
978
1153
|
result: error,
|
|
979
1154
|
isError: true,
|
|
980
1155
|
});
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
return { outcome: 'error', error, message: errorMsg };
|
|
1156
|
+
list.setToolCallError(toolCallId, error);
|
|
1157
|
+
return { outcome: 'error', error };
|
|
984
1158
|
};
|
|
985
1159
|
if (!builtTool) {
|
|
986
1160
|
return makeToolError(new Error(`Tool ${toolName} not found`));
|
|
987
1161
|
}
|
|
988
|
-
const
|
|
1162
|
+
const settledBlock = list
|
|
989
1163
|
.responseDelta()
|
|
990
|
-
.
|
|
991
|
-
.
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
1164
|
+
.flatMap((m) => ((0, message_1.isLlmMessage)(m) && 'content' in m ? m.content : []))
|
|
1165
|
+
.find((c) => c.type === 'tool-call' && c.toolCallId === toolCallId && c.state !== 'pending');
|
|
1166
|
+
if (settledBlock) {
|
|
1167
|
+
let settledResult;
|
|
1168
|
+
if (settledBlock.state === 'resolved') {
|
|
1169
|
+
settledResult = settledBlock.output;
|
|
1170
|
+
}
|
|
1171
|
+
else {
|
|
1172
|
+
settledResult = settledBlock.error;
|
|
1173
|
+
}
|
|
1174
|
+
this.eventBus.emit({
|
|
995
1175
|
type: "tool_execution_end",
|
|
996
1176
|
toolCallId,
|
|
997
1177
|
toolName,
|
|
998
|
-
result:
|
|
999
|
-
isError:
|
|
1178
|
+
result: settledResult,
|
|
1179
|
+
isError: settledBlock.state === 'rejected',
|
|
1000
1180
|
});
|
|
1001
1181
|
return { outcome: 'noop' };
|
|
1002
1182
|
}
|
|
1003
1183
|
if (builtTool.inputSchema) {
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
return makeToolError(new Error(`Invalid tool input: ${result.error.message}`));
|
|
1008
|
-
}
|
|
1009
|
-
toolInput = result.data;
|
|
1010
|
-
}
|
|
1011
|
-
else {
|
|
1012
|
-
const validate = ajv.compile(builtTool.inputSchema);
|
|
1013
|
-
const valid = validate(toolInput);
|
|
1014
|
-
if (!valid) {
|
|
1015
|
-
const message = ajv.errorsText(validate.errors);
|
|
1016
|
-
return makeToolError(new Error(`Invalid tool input: ${message}`));
|
|
1017
|
-
}
|
|
1184
|
+
const result = await (0, parse_1.parseWithSchema)(builtTool.inputSchema, toolInput);
|
|
1185
|
+
if (!result.success) {
|
|
1186
|
+
return makeToolError(new Error(`Invalid tool input: ${result.error}`));
|
|
1018
1187
|
}
|
|
1188
|
+
toolInput = result.data;
|
|
1019
1189
|
}
|
|
1020
1190
|
let toolResult;
|
|
1021
1191
|
try {
|
|
1022
|
-
toolResult = await (0, tool_adapter_1.executeTool)(toolInput, builtTool, resumeData, resolvedTelemetry);
|
|
1192
|
+
toolResult = await this.withTelemetryToolSpan(toolCallId, toolName, toolInput, resolvedTelemetry, async () => await (0, tool_adapter_1.executeTool)(toolInput, builtTool, resumeData, resolvedTelemetry, toolCallId));
|
|
1023
1193
|
}
|
|
1024
1194
|
catch (error) {
|
|
1025
1195
|
return makeToolError(error);
|
|
1026
1196
|
}
|
|
1027
1197
|
if ((0, tool_adapter_1.isSuspendedToolResult)(toolResult)) {
|
|
1028
1198
|
if (builtTool?.suspendSchema) {
|
|
1029
|
-
const parseResult = await builtTool.suspendSchema
|
|
1199
|
+
const parseResult = await (0, parse_1.parseWithSchema)(builtTool.suspendSchema, toolResult.payload);
|
|
1030
1200
|
if (!parseResult.success) {
|
|
1031
|
-
return makeToolError(new Error(`Invalid suspend payload: ${parseResult.error
|
|
1201
|
+
return makeToolError(new Error(`Invalid suspend payload: ${parseResult.error}`));
|
|
1032
1202
|
}
|
|
1033
1203
|
toolResult.payload = parseResult.data;
|
|
1034
1204
|
}
|
|
@@ -1036,8 +1206,17 @@ class AgentRuntime {
|
|
|
1036
1206
|
const error = new Error(`Tool ${toolName} has no resume schema`);
|
|
1037
1207
|
return makeToolError(error);
|
|
1038
1208
|
}
|
|
1039
|
-
const resumeSchema = (0,
|
|
1040
|
-
|
|
1209
|
+
const resumeSchema = (0, zod_1.isZodSchema)(builtTool.resumeSchema)
|
|
1210
|
+
? (0, zod_to_json_schema_1.zodToJsonSchema)(builtTool.resumeSchema)
|
|
1211
|
+
: builtTool.resumeSchema;
|
|
1212
|
+
if (!resumeSchema) {
|
|
1213
|
+
return makeToolError(new Error('Invalid resume schema'));
|
|
1214
|
+
}
|
|
1215
|
+
return {
|
|
1216
|
+
outcome: 'suspended',
|
|
1217
|
+
payload: toolResult.payload,
|
|
1218
|
+
resumeSchema,
|
|
1219
|
+
};
|
|
1041
1220
|
}
|
|
1042
1221
|
let actualResult = toolResult;
|
|
1043
1222
|
let extractedSubAgentUsage;
|
|
@@ -1045,7 +1224,7 @@ class AgentRuntime {
|
|
|
1045
1224
|
actualResult = toolResult.output;
|
|
1046
1225
|
extractedSubAgentUsage = toolResult.subAgentUsage;
|
|
1047
1226
|
}
|
|
1048
|
-
this.
|
|
1227
|
+
this.eventBus.emit({
|
|
1049
1228
|
type: "tool_execution_end",
|
|
1050
1229
|
toolCallId,
|
|
1051
1230
|
toolName,
|
|
@@ -1055,8 +1234,7 @@ class AgentRuntime {
|
|
|
1055
1234
|
const modelResult = builtTool.toModelOutput
|
|
1056
1235
|
? builtTool.toModelOutput(actualResult)
|
|
1057
1236
|
: actualResult;
|
|
1058
|
-
|
|
1059
|
-
list.addResponse([toolResultMsg]);
|
|
1237
|
+
list.setToolCallResult(toolCallId, (0, json_value_1.toJsonValue)(modelResult));
|
|
1060
1238
|
const customMessage = builtTool?.toMessage?.(actualResult);
|
|
1061
1239
|
if (customMessage) {
|
|
1062
1240
|
list.addResponse([customMessage]);
|
|
@@ -1069,30 +1247,42 @@ class AgentRuntime {
|
|
|
1069
1247
|
output: actualResult,
|
|
1070
1248
|
transformed: !!builtTool.toModelOutput,
|
|
1071
1249
|
},
|
|
1250
|
+
modelOutput: modelResult,
|
|
1072
1251
|
subAgentUsage: extractedSubAgentUsage,
|
|
1073
1252
|
customMessage,
|
|
1074
|
-
message: toolResultMsg,
|
|
1075
1253
|
};
|
|
1076
1254
|
}
|
|
1077
|
-
buildLoopContext() {
|
|
1078
|
-
const wmTool = this.buildWorkingMemoryToolForRun(
|
|
1255
|
+
buildLoopContext(execOptions) {
|
|
1256
|
+
const wmTool = this.buildWorkingMemoryToolForRun(execOptions?.persistence);
|
|
1079
1257
|
const allUserTools = wmTool
|
|
1080
1258
|
? [...(this.config.tools ?? []), wmTool]
|
|
1081
1259
|
: (this.config.tools ?? []);
|
|
1082
1260
|
const aiTools = (0, tool_adapter_1.toAiSdkTools)(allUserTools);
|
|
1083
1261
|
const aiProviderTools = (0, tool_adapter_1.toAiSdkProviderTools)(this.config.providerTools);
|
|
1084
1262
|
const allTools = { ...aiTools, ...aiProviderTools };
|
|
1263
|
+
const model = (0, model_factory_1.createModel)(this.config.model);
|
|
1085
1264
|
return {
|
|
1086
|
-
model
|
|
1265
|
+
model,
|
|
1087
1266
|
toolMap: (0, tool_adapter_1.buildToolMap)(allUserTools),
|
|
1088
1267
|
aiTools: allTools,
|
|
1089
|
-
providerOptions: this.buildCallProviderOptions(
|
|
1268
|
+
providerOptions: this.buildCallProviderOptions(execOptions?.providerOptions),
|
|
1090
1269
|
hasTools: Object.keys(allTools).length > 0,
|
|
1091
1270
|
outputSpec: this.config.structuredOutput
|
|
1092
1271
|
? ai_1.Output.object({ schema: this.config.structuredOutput })
|
|
1093
1272
|
: undefined,
|
|
1273
|
+
effectiveInstructions: this.composeEffectiveInstructions(allUserTools),
|
|
1094
1274
|
};
|
|
1095
1275
|
}
|
|
1276
|
+
composeEffectiveInstructions(tools) {
|
|
1277
|
+
const fragments = tools
|
|
1278
|
+
.map((t) => t.systemInstruction)
|
|
1279
|
+
.filter((s) => typeof s === 'string' && s.trim().length > 0);
|
|
1280
|
+
const userInstructions = this.config.instructions;
|
|
1281
|
+
if (fragments.length === 0)
|
|
1282
|
+
return userInstructions;
|
|
1283
|
+
const block = `<built_in_rules>\n${fragments.map((f) => `- ${f}`).join('\n')}\n</built_in_rules>`;
|
|
1284
|
+
return userInstructions ? `${block}\n\n${userInstructions}` : block;
|
|
1285
|
+
}
|
|
1096
1286
|
buildWorkingMemoryToolForRun(persistence) {
|
|
1097
1287
|
const wmParams = this.resolveWorkingMemoryParams(persistence);
|
|
1098
1288
|
if (!wmParams)
|
|
@@ -1103,31 +1293,30 @@ class AgentRuntime {
|
|
|
1103
1293
|
persist: wmParams.persistFn,
|
|
1104
1294
|
});
|
|
1105
1295
|
}
|
|
1106
|
-
async persistSuspension(pendingToolCalls, list, totalUsage) {
|
|
1107
|
-
const
|
|
1108
|
-
|
|
1109
|
-
: undefined;
|
|
1296
|
+
async persistSuspension(pendingToolCalls, options, list, totalUsage, existingRunId) {
|
|
1297
|
+
const runId = existingRunId ?? (0, run_state_1.generateRunId)();
|
|
1298
|
+
const executionOptions = options?.maxIterations !== undefined ? { maxIterations: options.maxIterations } : undefined;
|
|
1110
1299
|
const state = {
|
|
1111
|
-
persistence:
|
|
1300
|
+
persistence: options?.persistence,
|
|
1112
1301
|
status: 'suspended',
|
|
1113
1302
|
messageList: list.serialize(),
|
|
1114
1303
|
pendingToolCalls,
|
|
1115
1304
|
usage: totalUsage,
|
|
1116
1305
|
executionOptions,
|
|
1117
1306
|
};
|
|
1118
|
-
await this.runState.suspend(
|
|
1307
|
+
await this.runState.suspend(runId, state);
|
|
1119
1308
|
this.updateState({ status: 'suspended', pendingToolCalls, messageList: list.serialize() });
|
|
1120
|
-
return
|
|
1309
|
+
return runId;
|
|
1121
1310
|
}
|
|
1122
|
-
async cleanupRun() {
|
|
1123
|
-
if (
|
|
1124
|
-
await this.runState.complete(
|
|
1311
|
+
async cleanupRun(runId) {
|
|
1312
|
+
if (runId) {
|
|
1313
|
+
await this.runState.complete(runId);
|
|
1125
1314
|
}
|
|
1126
1315
|
}
|
|
1127
1316
|
emitTurnEnd(newMessages, toolResults) {
|
|
1128
1317
|
const assistantMsg = newMessages.find((m) => 'role' in m && m.role === 'assistant');
|
|
1129
1318
|
if (assistantMsg) {
|
|
1130
|
-
this.
|
|
1319
|
+
this.eventBus.emit({ type: "turn_end", message: assistantMsg, toolResults });
|
|
1131
1320
|
}
|
|
1132
1321
|
}
|
|
1133
1322
|
updateState(patch) {
|
|
@@ -1175,9 +1364,6 @@ class AgentRuntime {
|
|
|
1175
1364
|
...(wmParams.instruction !== undefined && { instruction: wmParams.instruction }),
|
|
1176
1365
|
};
|
|
1177
1366
|
}
|
|
1178
|
-
emitEvent(data) {
|
|
1179
|
-
this.eventBus.emit({ ...data, runId: this.runId });
|
|
1180
|
-
}
|
|
1181
1367
|
resolveWorkingMemoryParams(options) {
|
|
1182
1368
|
if (!options)
|
|
1183
1369
|
return null;
|