@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.
Files changed (114) hide show
  1. package/dist/build.tsbuildinfo +1 -1
  2. package/dist/index.d.ts +12 -8
  3. package/dist/index.js +10 -3
  4. package/dist/index.js.map +1 -1
  5. package/dist/integrations/langsmith.d.ts +2 -0
  6. package/dist/integrations/langsmith.js +117 -2
  7. package/dist/integrations/langsmith.js.map +1 -1
  8. package/dist/runtime/agent-runtime.d.ts +6 -7
  9. package/dist/runtime/agent-runtime.js +390 -204
  10. package/dist/runtime/agent-runtime.js.map +1 -1
  11. package/dist/runtime/event-bus.d.ts +1 -0
  12. package/dist/runtime/event-bus.js +3 -0
  13. package/dist/runtime/event-bus.js.map +1 -1
  14. package/dist/runtime/json-value.d.ts +2 -0
  15. package/dist/runtime/json-value.js +43 -0
  16. package/dist/runtime/json-value.js.map +1 -0
  17. package/dist/runtime/memory-store.d.ts +40 -2
  18. package/dist/runtime/memory-store.js +138 -3
  19. package/dist/runtime/memory-store.js.map +1 -1
  20. package/dist/runtime/message-list.d.ts +5 -0
  21. package/dist/runtime/message-list.js +47 -0
  22. package/dist/runtime/message-list.js.map +1 -1
  23. package/dist/runtime/messages.d.ts +0 -2
  24. package/dist/runtime/messages.js +127 -101
  25. package/dist/runtime/messages.js.map +1 -1
  26. package/dist/runtime/model-factory.js +117 -34
  27. package/dist/runtime/model-factory.js.map +1 -1
  28. package/dist/runtime/provider-credentials.d.ts +167 -0
  29. package/dist/runtime/provider-credentials.js +34 -0
  30. package/dist/runtime/provider-credentials.js.map +1 -0
  31. package/dist/runtime/runtime-helpers.d.ts +3 -4
  32. package/dist/runtime/runtime-helpers.js +6 -32
  33. package/dist/runtime/runtime-helpers.js.map +1 -1
  34. package/dist/runtime/stream.js +25 -43
  35. package/dist/runtime/stream.js.map +1 -1
  36. package/dist/runtime/strip-orphaned-tool-messages.js +1 -25
  37. package/dist/runtime/strip-orphaned-tool-messages.js.map +1 -1
  38. package/dist/runtime/title-generation.d.ts +12 -3
  39. package/dist/runtime/title-generation.js +72 -3
  40. package/dist/runtime/title-generation.js.map +1 -1
  41. package/dist/runtime/tool-adapter.d.ts +1 -1
  42. package/dist/runtime/tool-adapter.js +3 -2
  43. package/dist/runtime/tool-adapter.js.map +1 -1
  44. package/dist/runtime/working-memory.d.ts +1 -1
  45. package/dist/runtime/working-memory.js +1 -1
  46. package/dist/runtime/working-memory.js.map +1 -1
  47. package/dist/sdk/agent.d.ts +24 -23
  48. package/dist/sdk/agent.js +50 -324
  49. package/dist/sdk/agent.js.map +1 -1
  50. package/dist/sdk/eval.d.ts +0 -3
  51. package/dist/sdk/eval.js +4 -9
  52. package/dist/sdk/eval.js.map +1 -1
  53. package/dist/sdk/provider-capabilities.js +4 -2
  54. package/dist/sdk/provider-capabilities.js.map +1 -1
  55. package/dist/sdk/provider-tools.d.ts +17 -2
  56. package/dist/sdk/provider-tools.js +19 -0
  57. package/dist/sdk/provider-tools.js.map +1 -1
  58. package/dist/sdk/telemetry.d.ts +2 -0
  59. package/dist/sdk/telemetry.js +6 -0
  60. package/dist/sdk/telemetry.js.map +1 -1
  61. package/dist/sdk/tool.d.ts +17 -10
  62. package/dist/sdk/tool.js +34 -0
  63. package/dist/sdk/tool.js.map +1 -1
  64. package/dist/sdk/verify.js +1 -4
  65. package/dist/sdk/verify.js.map +1 -1
  66. package/dist/storage/base-memory.d.ts +64 -0
  67. package/dist/storage/base-memory.js +54 -0
  68. package/dist/storage/base-memory.js.map +1 -0
  69. package/dist/storage/postgres-memory.d.ts +33 -16
  70. package/dist/storage/postgres-memory.js +46 -25
  71. package/dist/storage/postgres-memory.js.map +1 -1
  72. package/dist/storage/sqlite-memory.d.ts +16 -6
  73. package/dist/storage/sqlite-memory.js +16 -10
  74. package/dist/storage/sqlite-memory.js.map +1 -1
  75. package/dist/types/index.d.ts +4 -2
  76. package/dist/types/index.js +3 -1
  77. package/dist/types/index.js.map +1 -1
  78. package/dist/types/runtime/event.d.ts +3 -9
  79. package/dist/types/runtime/event.js.map +1 -1
  80. package/dist/types/sdk/agent-builder.d.ts +0 -3
  81. package/dist/types/sdk/agent.d.ts +64 -27
  82. package/dist/types/sdk/credential-provider.d.ts +2 -3
  83. package/dist/types/sdk/memory.d.ts +23 -2
  84. package/dist/types/sdk/message.d.ts +11 -10
  85. package/dist/types/sdk/observation.d.ts +100 -0
  86. package/dist/types/sdk/observation.js +5 -0
  87. package/dist/types/sdk/observation.js.map +1 -0
  88. package/dist/types/sdk/tool-descriptor.d.ts +13 -0
  89. package/dist/types/sdk/{schema.js → tool-descriptor.js} +1 -1
  90. package/dist/types/sdk/tool-descriptor.js.map +1 -0
  91. package/dist/types/sdk/tool.d.ts +8 -3
  92. package/dist/types/telemetry.d.ts +1 -0
  93. package/dist/utils/parse.d.ts +10 -0
  94. package/dist/utils/parse.js +26 -0
  95. package/dist/utils/parse.js.map +1 -0
  96. package/dist/utils/zod.d.ts +1 -1
  97. package/dist/utils/zod.js.map +1 -1
  98. package/dist/workspace/tools/batch-str-replace-file.d.ts +3 -0
  99. package/dist/workspace/tools/batch-str-replace-file.js +67 -0
  100. package/dist/workspace/tools/batch-str-replace-file.js.map +1 -0
  101. package/dist/workspace/tools/str-replace-file.d.ts +3 -0
  102. package/dist/workspace/tools/str-replace-file.js +51 -0
  103. package/dist/workspace/tools/str-replace-file.js.map +1 -0
  104. package/dist/workspace/tools/workspace-tools.js +4 -0
  105. package/dist/workspace/tools/workspace-tools.js.map +1 -1
  106. package/package.json +17 -8
  107. package/dist/codegen/generate-agent-code.d.ts +0 -2
  108. package/dist/codegen/generate-agent-code.js +0 -197
  109. package/dist/codegen/generate-agent-code.js.map +0 -1
  110. package/dist/sdk/from-schema.d.ts +0 -15
  111. package/dist/sdk/from-schema.js +0 -218
  112. package/dist/sdk/from-schema.js.map +0 -1
  113. package/dist/types/sdk/schema.d.ts +0 -99
  114. 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 = config.runState ?? new run_state_1.RunStateManager(config.checkpointStorage);
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
- this.runId = (0, run_state_1.generateRunId)();
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
- list = await this.initRun(input);
93
- const rawResult = await this.runGenerateLoop(list);
94
- return this.finalizeGenerate(rawResult, list);
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.emitEvent({ type: "error", message: String(error), error });
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
- this.runId = (0, run_state_1.generateRunId)();
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.emitEvent({ type: "error", message: String(error), error });
168
+ this.eventBus.emit({ type: "error", message: String(error), error });
125
169
  }
126
- return { runId: this.runId, stream: (0, runtime_helpers_1.makeErrorStream)(error), getState: () => this.getState() };
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
- this.runId = options.runId;
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: ${this.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.safeParseAsync(data);
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.message}`);
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
- this.executionOptions = mergedExecOptions;
162
- this.updateState({ persistence: state.persistence });
163
- this.eventBus.resetAbort(this.executionOptions?.abortSignal);
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.runGenerateLoop(list, pendingResume);
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: this.runId,
181
- stream: this.startStreamLoop(list, pendingResume),
182
- getState: () => this.getState(),
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.emitEvent({ type: "error", message: String(error), error });
239
+ this.eventBus.emit({ type: "error", message: String(error), error });
190
240
  }
191
241
  if (method === 'generate') {
192
242
  return {
193
- runId: this.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: this.runId, stream: (0, runtime_helpers_1.makeErrorStream)(error), getState: () => this.getState() };
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
- const persistence = this.currentState.persistence;
206
- if (this.config.memory && persistence?.threadId) {
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(this.executionOptions?.abortSignal);
301
- this.updateState({ status: 'running' });
302
- this.emitEvent({ type: "agent_start" });
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 = this.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.emitEvent({ type: "agent_end", messages: finalized.messages });
314
- return { ...finalized, getState: () => this.getState() };
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 = this.executionOptions?.telemetry;
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
- async runGenerateLoop(list, pendingResume) {
351
- const { model, toolMap, aiTools, providerOptions, hasTools, outputSpec } = this.buildLoopContext();
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(pendingResume, toolMap, list, runTelemetry);
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 = this.executionOptions?.maxIterations ?? MAX_LOOP_ITERATIONS;
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.emitEvent({ type: "turn_start" });
520
+ this.eventBus.emit({ type: "turn_start" });
391
521
  const result = await (0, ai_1.generateText)({
392
522
  model,
393
- messages: list.forLlm(this.config.instructions, this.config.instructionProviderOptions),
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.extractToolResults)(newMessages));
542
+ this.emitTurnEnd(newMessages, (0, runtime_helpers_1.extractSettledToolCalls)(newMessages));
413
543
  break;
414
544
  }
415
- const batch = await this.iterateToolCallsConcurrent(result.toolCalls, toolMap, list, runTelemetry);
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.extractToolResults)(list.responseDelta()));
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
- const persistence = this.currentState.persistence;
447
- if (this.config.titleGeneration && persistence?.threadId && this.config.memory) {
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: this.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(list, pendingResume) {
601
+ startStreamLoop(ctx) {
602
+ const { options, runId } = ctx;
469
603
  const { readable, writable } = new TransformStream();
470
604
  const writer = writable.getWriter();
471
- this.runStreamLoop(list, writer, pendingResume).catch(async (error) => {
472
- await this.flushTelemetry();
473
- await this.cleanupRun();
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(list, writer, pendingResume) {
486
- const { model, toolMap, aiTools, providerOptions, hasTools, outputSpec } = this.buildLoopContext();
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 = this.executionOptions?.maxIterations ?? MAX_LOOP_ITERATIONS;
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(pendingResume, toolMap, list, runTelemetry);
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: 'message',
517
- message: r.message,
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: 'message',
526
- message: e.message,
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.emitEvent({ type: "error", message: String(error), error });
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.emitEvent({ type: "turn_start" });
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: list.forLlm(this.config.instructions, this.config.instructionProviderOptions),
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' || chunk.type === 'finish-step')
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.emitEvent({
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.extractToolResults)(newMessages));
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(toolCalls, toolMap, list, runTelemetry);
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: 'message',
615
- message: r.message,
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: 'message',
624
- message: e.message,
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.emitEvent({ type: "error", message: String(error), error });
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.extractToolResults)(list.responseDelta()));
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
- const persistence = this.currentState.persistence;
669
- if (this.config.titleGeneration && persistence && this.config.memory) {
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.emitEvent({ type: "agent_end", messages: list.responseDelta() });
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
- const persistence = this.currentState.persistence;
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(toolCalls, toolMap, list, resolvedTelemetry) {
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(pendingResume, toolMap, list, resolvedTelemetry) {
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(unexecuted, toolMap, list, resolvedTelemetry);
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.emitEvent({
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.emitEvent({
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
- const errorMsg = (0, runtime_helpers_1.makeErrorToolResultMessage)(toolCallId, toolName, error);
982
- list.addResponse([errorMsg]);
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 existingToolResults = list
1162
+ const settledBlock = list
989
1163
  .responseDelta()
990
- .filter((m) => (0, message_1.isLlmMessage)(m) && m.role === 'tool')
991
- .flatMap((m) => m.content.filter((content) => content.type === 'tool-result'));
992
- const existingToolResult = existingToolResults.find((r) => r.toolCallId === toolCallId);
993
- if (existingToolResult) {
994
- this.emitEvent({
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: existingToolResult.result,
999
- isError: !!existingToolResult.isError,
1178
+ result: settledResult,
1179
+ isError: settledBlock.state === 'rejected',
1000
1180
  });
1001
1181
  return { outcome: 'noop' };
1002
1182
  }
1003
1183
  if (builtTool.inputSchema) {
1004
- if ((0, zod_1.isZodSchema)(builtTool.inputSchema)) {
1005
- const result = await builtTool.inputSchema.safeParseAsync(toolInput);
1006
- if (!result.success) {
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.safeParseAsync(toolResult.payload);
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.message}`));
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, zod_to_json_schema_1.zodToJsonSchema)(builtTool.resumeSchema);
1040
- return { outcome: 'suspended', payload: toolResult.payload, resumeSchema };
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.emitEvent({
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
- const toolResultMsg = (0, runtime_helpers_1.makeToolResultMessage)(toolCallId, toolName, modelResult);
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(this.currentState.persistence);
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: (0, model_factory_1.createModel)(this.config.model),
1265
+ model,
1087
1266
  toolMap: (0, tool_adapter_1.buildToolMap)(allUserTools),
1088
1267
  aiTools: allTools,
1089
- providerOptions: this.buildCallProviderOptions(this.executionOptions?.providerOptions),
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 executionOptions = this.executionOptions?.maxIterations !== undefined
1108
- ? { maxIterations: this.executionOptions.maxIterations }
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: this.currentState.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(this.runId, state);
1307
+ await this.runState.suspend(runId, state);
1119
1308
  this.updateState({ status: 'suspended', pendingToolCalls, messageList: list.serialize() });
1120
- return this.runId;
1309
+ return runId;
1121
1310
  }
1122
- async cleanupRun() {
1123
- if (this.runId) {
1124
- await this.runState.complete(this.runId);
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.emitEvent({ type: "turn_end", message: assistantMsg, toolResults });
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;