@n8n/agents 0.6.0 → 0.8.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 (148) hide show
  1. package/dist/build.tsbuildinfo +1 -1
  2. package/dist/index.d.ts +18 -11
  3. package/dist/index.js +37 -10
  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 +30 -19
  9. package/dist/runtime/agent-runtime.js +616 -280
  10. package/dist/runtime/agent-runtime.js.map +1 -1
  11. package/dist/runtime/background-task-tracker.d.ts +6 -0
  12. package/dist/runtime/background-task-tracker.js +26 -0
  13. package/dist/runtime/background-task-tracker.js.map +1 -0
  14. package/dist/runtime/deferred-tool-manager.d.ts +28 -0
  15. package/dist/runtime/deferred-tool-manager.js +205 -0
  16. package/dist/runtime/deferred-tool-manager.js.map +1 -0
  17. package/dist/runtime/event-bus.d.ts +1 -0
  18. package/dist/runtime/event-bus.js +3 -0
  19. package/dist/runtime/event-bus.js.map +1 -1
  20. package/dist/runtime/json-value.d.ts +2 -0
  21. package/dist/runtime/json-value.js +43 -0
  22. package/dist/runtime/json-value.js.map +1 -0
  23. package/dist/runtime/memory-store.d.ts +34 -11
  24. package/dist/runtime/memory-store.js +210 -8
  25. package/dist/runtime/memory-store.js.map +1 -1
  26. package/dist/runtime/message-list.d.ts +6 -7
  27. package/dist/runtime/message-list.js +50 -6
  28. package/dist/runtime/message-list.js.map +1 -1
  29. package/dist/runtime/messages.d.ts +0 -2
  30. package/dist/runtime/messages.js +127 -101
  31. package/dist/runtime/messages.js.map +1 -1
  32. package/dist/runtime/model-factory.js +117 -34
  33. package/dist/runtime/model-factory.js.map +1 -1
  34. package/dist/runtime/observation-log-defaults.d.ts +20 -0
  35. package/dist/runtime/observation-log-defaults.js +523 -0
  36. package/dist/runtime/observation-log-defaults.js.map +1 -0
  37. package/dist/runtime/observation-log-observer.d.ts +64 -0
  38. package/dist/runtime/observation-log-observer.js +235 -0
  39. package/dist/runtime/observation-log-observer.js.map +1 -0
  40. package/dist/runtime/observation-log-reflector.d.ts +36 -0
  41. package/dist/runtime/observation-log-reflector.js +292 -0
  42. package/dist/runtime/observation-log-reflector.js.map +1 -0
  43. package/dist/runtime/observation-log-renderer.d.ts +6 -0
  44. package/dist/runtime/observation-log-renderer.js +73 -0
  45. package/dist/runtime/observation-log-renderer.js.map +1 -0
  46. package/dist/runtime/observation-log-store.d.ts +3 -0
  47. package/dist/runtime/observation-log-store.js +26 -0
  48. package/dist/runtime/observation-log-store.js.map +1 -0
  49. package/dist/runtime/provider-credentials.d.ts +167 -0
  50. package/dist/runtime/provider-credentials.js +34 -0
  51. package/dist/runtime/provider-credentials.js.map +1 -0
  52. package/dist/runtime/runtime-helpers.d.ts +3 -4
  53. package/dist/runtime/runtime-helpers.js +6 -32
  54. package/dist/runtime/runtime-helpers.js.map +1 -1
  55. package/dist/runtime/scoped-memory-task-runner.d.ts +79 -0
  56. package/dist/runtime/scoped-memory-task-runner.js +134 -0
  57. package/dist/runtime/scoped-memory-task-runner.js.map +1 -0
  58. package/dist/runtime/stream.js +25 -43
  59. package/dist/runtime/stream.js.map +1 -1
  60. package/dist/runtime/strip-orphaned-tool-messages.js +1 -25
  61. package/dist/runtime/strip-orphaned-tool-messages.js.map +1 -1
  62. package/dist/runtime/title-generation.d.ts +12 -3
  63. package/dist/runtime/title-generation.js +72 -3
  64. package/dist/runtime/title-generation.js.map +1 -1
  65. package/dist/runtime/tool-adapter.d.ts +1 -1
  66. package/dist/runtime/tool-adapter.js +3 -2
  67. package/dist/runtime/tool-adapter.js.map +1 -1
  68. package/dist/sdk/agent.d.ts +35 -22
  69. package/dist/sdk/agent.js +106 -331
  70. package/dist/sdk/agent.js.map +1 -1
  71. package/dist/sdk/catalog.d.ts +1 -0
  72. package/dist/sdk/catalog.js +1 -0
  73. package/dist/sdk/catalog.js.map +1 -1
  74. package/dist/sdk/eval.d.ts +0 -3
  75. package/dist/sdk/eval.js +4 -9
  76. package/dist/sdk/eval.js.map +1 -1
  77. package/dist/sdk/memory.d.ts +12 -12
  78. package/dist/sdk/memory.js +71 -51
  79. package/dist/sdk/memory.js.map +1 -1
  80. package/dist/sdk/provider-capabilities.js +4 -2
  81. package/dist/sdk/provider-capabilities.js.map +1 -1
  82. package/dist/sdk/provider-tools.d.ts +17 -2
  83. package/dist/sdk/provider-tools.js +19 -0
  84. package/dist/sdk/provider-tools.js.map +1 -1
  85. package/dist/sdk/telemetry.d.ts +2 -0
  86. package/dist/sdk/telemetry.js +6 -0
  87. package/dist/sdk/telemetry.js.map +1 -1
  88. package/dist/sdk/tool.d.ts +17 -10
  89. package/dist/sdk/tool.js +34 -0
  90. package/dist/sdk/tool.js.map +1 -1
  91. package/dist/sdk/verify.js +1 -4
  92. package/dist/sdk/verify.js.map +1 -1
  93. package/dist/storage/base-memory.d.ts +54 -0
  94. package/dist/storage/base-memory.js +48 -0
  95. package/dist/storage/base-memory.js.map +1 -0
  96. package/dist/types/index.d.ts +6 -3
  97. package/dist/types/index.js +7 -1
  98. package/dist/types/index.js.map +1 -1
  99. package/dist/types/runtime/event.d.ts +4 -9
  100. package/dist/types/runtime/event.js.map +1 -1
  101. package/dist/types/sdk/agent-builder.d.ts +5 -3
  102. package/dist/types/sdk/agent.d.ts +70 -27
  103. package/dist/types/sdk/credential-provider.d.ts +2 -3
  104. package/dist/types/sdk/memory.d.ts +33 -20
  105. package/dist/types/sdk/message.d.ts +11 -10
  106. package/dist/types/sdk/observation-log.d.ts +99 -0
  107. package/dist/types/sdk/observation-log.js +17 -0
  108. package/dist/types/sdk/observation-log.js.map +1 -0
  109. package/dist/types/sdk/observation.d.ts +9 -0
  110. package/dist/types/sdk/{schema.js → observation.js} +1 -1
  111. package/dist/types/sdk/observation.js.map +1 -0
  112. package/dist/types/sdk/provider.d.ts +5 -2
  113. package/dist/types/sdk/tool-descriptor.d.ts +13 -0
  114. package/dist/types/sdk/tool-descriptor.js +3 -0
  115. package/dist/types/sdk/tool-descriptor.js.map +1 -0
  116. package/dist/types/sdk/tool.d.ts +8 -3
  117. package/dist/types/telemetry.d.ts +1 -0
  118. package/dist/utils/parse.d.ts +10 -0
  119. package/dist/utils/parse.js +26 -0
  120. package/dist/utils/parse.js.map +1 -0
  121. package/dist/utils/zod.d.ts +1 -1
  122. package/dist/utils/zod.js.map +1 -1
  123. package/dist/workspace/tools/batch-str-replace-file.d.ts +3 -0
  124. package/dist/workspace/tools/batch-str-replace-file.js +67 -0
  125. package/dist/workspace/tools/batch-str-replace-file.js.map +1 -0
  126. package/dist/workspace/tools/str-replace-file.d.ts +3 -0
  127. package/dist/workspace/tools/str-replace-file.js +51 -0
  128. package/dist/workspace/tools/str-replace-file.js.map +1 -0
  129. package/dist/workspace/tools/workspace-tools.js +4 -0
  130. package/dist/workspace/tools/workspace-tools.js.map +1 -1
  131. package/package.json +16 -11
  132. package/dist/codegen/generate-agent-code.d.ts +0 -2
  133. package/dist/codegen/generate-agent-code.js +0 -197
  134. package/dist/codegen/generate-agent-code.js.map +0 -1
  135. package/dist/runtime/working-memory.d.ts +0 -14
  136. package/dist/runtime/working-memory.js +0 -69
  137. package/dist/runtime/working-memory.js.map +0 -1
  138. package/dist/sdk/from-schema.d.ts +0 -15
  139. package/dist/sdk/from-schema.js +0 -218
  140. package/dist/sdk/from-schema.js.map +0 -1
  141. package/dist/storage/postgres-memory.d.ts +0 -79
  142. package/dist/storage/postgres-memory.js +0 -410
  143. package/dist/storage/postgres-memory.js.map +0 -1
  144. package/dist/storage/sqlite-memory.d.ts +0 -60
  145. package/dist/storage/sqlite-memory.js +0 -348
  146. package/dist/storage/sqlite-memory.js.map +0 -1
  147. package/dist/types/sdk/schema.d.ts +0 -99
  148. package/dist/types/sdk/schema.js.map +0 -1
@@ -32,44 +32,119 @@ 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");
41
+ const background_task_tracker_1 = require("./background-task-tracker");
42
+ const deferred_tool_manager_1 = require("./deferred-tool-manager");
45
43
  const event_bus_1 = require("./event-bus");
44
+ const json_value_1 = require("./json-value");
45
+ const logger_1 = require("./logger");
46
46
  const memory_store_1 = require("./memory-store");
47
47
  const message_list_1 = require("./message-list");
48
48
  const messages_1 = require("./messages");
49
49
  const model_factory_1 = require("./model-factory");
50
+ const observation_log_observer_1 = require("./observation-log-observer");
51
+ const observation_log_reflector_1 = require("./observation-log-reflector");
52
+ const observation_log_renderer_1 = require("./observation-log-renderer");
53
+ const observation_log_store_1 = require("./observation-log-store");
50
54
  const run_state_1 = require("./run-state");
51
55
  const runtime_helpers_1 = require("./runtime-helpers");
56
+ const scoped_memory_task_runner_1 = require("./scoped-memory-task-runner");
52
57
  const stream_1 = require("./stream");
53
58
  const strip_orphaned_tool_messages_1 = require("./strip-orphaned-tool-messages");
54
59
  const title_generation_1 = require("./title-generation");
55
60
  const tool_adapter_1 = require("./tool-adapter");
56
- const working_memory_1 = require("./working-memory");
61
+ const observation_log_1 = require("../types/sdk/observation-log");
62
+ const parse_1 = require("../utils/parse");
57
63
  const zod_1 = require("../utils/zod");
64
+ function isActiveSpanTracer(value) {
65
+ return (value !== null &&
66
+ typeof value === 'object' &&
67
+ typeof Reflect.get(value, 'startActiveSpan') === 'function');
68
+ }
69
+ function stringifyTelemetryValue(value) {
70
+ try {
71
+ return JSON.stringify(value);
72
+ }
73
+ catch {
74
+ return undefined;
75
+ }
76
+ }
77
+ function getToolInputSchema(tool) {
78
+ if (!tool.inputSchema) {
79
+ return undefined;
80
+ }
81
+ return (0, zod_1.isZodSchema)(tool.inputSchema) ? (0, zod_to_json_schema_1.zodToJsonSchema)(tool.inputSchema) : tool.inputSchema;
82
+ }
83
+ function summarizeToolForTelemetry(tool) {
84
+ return {
85
+ name: tool.name,
86
+ description: tool.description,
87
+ type: tool.mcpTool ? 'mcp' : 'local',
88
+ ...(tool.mcpServerName ? { mcp_server: tool.mcpServerName } : {}),
89
+ ...(tool.suspendSchema || tool.resumeSchema || tool.withDefaultApproval
90
+ ? { approval: true }
91
+ : {}),
92
+ ...(tool.inputSchema ? { input_schema: getToolInputSchema(tool) } : {}),
93
+ };
94
+ }
95
+ function summarizeProviderToolForTelemetry(tool) {
96
+ const [provider] = tool.name.split('.');
97
+ return {
98
+ name: tool.name,
99
+ provider,
100
+ type: 'provider',
101
+ args: tool.args,
102
+ ...(tool.inputSchema ? { input_schema: getToolInputSchema(tool) } : {}),
103
+ };
104
+ }
105
+ function buildAgentRootInputAttributes(config) {
106
+ const localTools = (config.tools ?? []).map(summarizeToolForTelemetry);
107
+ const providerTools = (config.providerTools ?? []).map(summarizeProviderToolForTelemetry);
108
+ const tools = [...localTools, ...providerTools];
109
+ const toolNames = tools
110
+ .map((tool) => (typeof tool.name === 'string' ? tool.name : undefined))
111
+ .filter((name) => name !== undefined);
112
+ const serialized = stringifyTelemetryValue({
113
+ agent: config.name,
114
+ tool_count: tools.length,
115
+ tools,
116
+ });
117
+ return {
118
+ ...(toolNames.length > 0 ? { 'langsmith.metadata.available_tools': toolNames } : {}),
119
+ ...(serialized ? { 'gen_ai.prompt': serialized } : {}),
120
+ };
121
+ }
58
122
  const MAX_LOOP_ITERATIONS = 20;
59
- const ajv = new ajv_1.default({ strict: false });
123
+ const logger = (0, logger_1.createFilteredLogger)();
60
124
  const EMPTY_MESSAGE_LIST = {
61
125
  messages: [],
62
126
  historyIds: [],
63
127
  inputIds: [],
64
128
  responseIds: [],
65
129
  };
130
+ function hasFunctionProperty(value, property) {
131
+ return property in value && typeof Reflect.get(value, property) === 'function';
132
+ }
133
+ function hasObservationLogObserverMemory(memory) {
134
+ return ((0, observation_log_store_1.hasObservationLogStore)(memory) &&
135
+ hasFunctionProperty(memory, 'getMessagesForScope') &&
136
+ hasFunctionProperty(memory, 'getCursor') &&
137
+ hasFunctionProperty(memory, 'setCursor'));
138
+ }
66
139
  class AgentRuntime {
67
140
  constructor(config) {
68
- this.runId = '';
141
+ this.backgroundTasks = new background_task_tracker_1.BackgroundTaskTracker();
69
142
  this.config = config;
70
- this.runState = config.runState ?? new run_state_1.RunStateManager(config.checkpointStorage);
143
+ if (config.deferredTools && config.deferredTools.length > 0) {
144
+ this.deferredToolManager = new deferred_tool_manager_1.DeferredToolManager(config.deferredTools, config.toolSearch);
145
+ }
146
+ this.runState = new run_state_1.RunStateManager(config.checkpointStorage);
71
147
  this.eventBus = config.eventBus ?? new event_bus_1.AgentEventBus();
72
- this.modelCost = config.modelCost;
73
148
  this.currentState = {
74
149
  persistence: undefined,
75
150
  status: 'idle',
@@ -77,6 +152,9 @@ class AgentRuntime {
77
152
  pendingToolCalls: {},
78
153
  };
79
154
  }
155
+ async dispose() {
156
+ await this.backgroundTasks.flush();
157
+ }
80
158
  getState() {
81
159
  return { ...this.currentState };
82
160
  }
@@ -84,83 +162,72 @@ class AgentRuntime {
84
162
  this.eventBus.abort();
85
163
  }
86
164
  async generate(input, options) {
87
- this.runId = (0, run_state_1.generateRunId)();
88
- this.executionOptions = options;
89
- this.updateState({ persistence: options?.persistence });
165
+ const runId = (0, run_state_1.generateRunId)();
90
166
  let list = undefined;
91
167
  try {
92
- list = await this.initRun(input);
93
- const rawResult = await this.runGenerateLoop(list);
94
- return this.finalizeGenerate(rawResult, list);
168
+ const initializedList = await this.initRun(input, options);
169
+ list = initializedList;
170
+ const rawResult = await this.withTelemetryRootSpan('generate', options, runId, async () => await this.runGenerateLoop({ list: initializedList, options, runId }));
171
+ return this.finalizeGenerate(rawResult, list, runId);
95
172
  }
96
173
  catch (error) {
97
- await this.flushTelemetry();
174
+ await this.flushTelemetry(options);
98
175
  const isAbort = this.eventBus.isAborted;
99
176
  this.updateState({ status: isAbort ? 'cancelled' : 'failed' });
100
177
  if (!isAbort) {
101
- this.emitEvent({ type: "error", message: String(error), error });
178
+ this.eventBus.emit({ type: "error", message: String(error), error });
102
179
  }
103
- return {
104
- runId: this.runId,
105
- messages: list?.responseDelta() ?? [],
106
- finishReason: 'error',
107
- error,
108
- getState: () => this.getState(),
109
- };
180
+ return { runId, messages: list?.responseDelta() ?? [], finishReason: 'error', error };
110
181
  }
111
182
  }
112
183
  async stream(input, options) {
113
- this.runId = (0, run_state_1.generateRunId)();
114
- this.executionOptions = options;
115
- this.updateState({ persistence: options?.persistence });
184
+ const runId = (0, run_state_1.generateRunId)();
116
185
  let list;
117
186
  try {
118
- list = await this.initRun(input);
187
+ list = await this.initRun(input, options);
119
188
  }
120
189
  catch (error) {
121
190
  const isAbort = this.eventBus.isAborted;
122
191
  this.updateState({ status: isAbort ? 'cancelled' : 'failed' });
123
192
  if (!isAbort) {
124
- this.emitEvent({ type: "error", message: String(error), error });
193
+ this.eventBus.emit({ type: "error", message: String(error), error });
125
194
  }
126
- return { runId: this.runId, stream: (0, runtime_helpers_1.makeErrorStream)(error), getState: () => this.getState() };
195
+ return { runId, stream: (0, runtime_helpers_1.makeErrorStream)(error) };
127
196
  }
128
- return {
129
- runId: this.runId,
130
- stream: this.startStreamLoop(list),
131
- getState: () => this.getState(),
132
- };
197
+ return { runId, stream: this.startStreamLoop({ list, options, runId }) };
133
198
  }
134
199
  async resume(method, data, options) {
135
- this.runId = options.runId;
136
- const state = await this.runState.resume(this.runId);
200
+ const state = await this.runState.resume(options.runId);
137
201
  if (!state)
138
- throw new Error(`No suspended run found for runId: ${this.runId}`);
202
+ throw new Error(`No suspended run found for runId: ${options.runId}`);
139
203
  const toolCall = state.pendingToolCalls[options.toolCallId];
140
204
  if (!toolCall)
141
205
  throw new Error(`No tool call found for toolCallId: ${options.toolCallId}`);
142
- const tool = this.config.tools?.find((t) => t.name === toolCall.toolName);
206
+ const list = message_list_1.AgentMessageList.deserialize(state.messageList);
207
+ this.hydrateDeferredToolsFromList(list);
208
+ const tool = this.getCurrentTools().find((t) => t.name === toolCall.toolName);
143
209
  if (!tool)
144
210
  throw new Error(`Tool ${toolCall.toolName} not found`);
145
211
  let resumeData = data;
146
212
  if (tool.resumeSchema) {
147
- const parseResult = await tool.resumeSchema.safeParseAsync(data);
213
+ const parseResult = await (0, parse_1.parseWithSchema)(tool.resumeSchema, data);
148
214
  if (!parseResult.success) {
149
- throw new Error(`Invalid resume payload: ${parseResult.error.message}`);
215
+ throw new Error(`Invalid resume payload: ${parseResult.error}`);
150
216
  }
151
217
  resumeData = parseResult.data;
152
218
  }
153
219
  try {
154
- const list = message_list_1.AgentMessageList.deserialize(state.messageList);
155
220
  const { runId: _rid, toolCallId: _tcid, ...callerExecOptions } = options;
156
221
  const persisted = state.executionOptions ?? {};
157
222
  const mergedExecOptions = {
158
223
  ...persisted,
159
224
  ...callerExecOptions,
160
225
  };
161
- this.executionOptions = mergedExecOptions;
162
- this.updateState({ persistence: state.persistence });
163
- this.eventBus.resetAbort(this.executionOptions?.abortSignal);
226
+ const resumeOptions = {
227
+ persistence: state.persistence,
228
+ ...mergedExecOptions,
229
+ };
230
+ this.eventBus.resetAbort(resumeOptions.abortSignal);
164
231
  const pendingResume = {
165
232
  pendingToolCalls: state.pendingToolCalls,
166
233
  resumeToolCallId: options.toolCallId,
@@ -168,53 +235,61 @@ class AgentRuntime {
168
235
  messages: state.messageList.messages,
169
236
  };
170
237
  await this.ensureModelCost();
171
- await this.setListWorkingMemoryConfig(list, state.persistence);
238
+ await this.setListObservationLogMemory(list, state.persistence);
172
239
  if (method === 'generate') {
173
- const rawResult = await this.runGenerateLoop(list, pendingResume);
240
+ const rawResult = await this.withTelemetryRootSpan('generate', resumeOptions, options.runId, async () => await this.runGenerateLoop({
241
+ list,
242
+ options: resumeOptions,
243
+ runId: options.runId,
244
+ pendingResume,
245
+ }));
174
246
  if (!rawResult.pendingSuspend) {
175
- await this.cleanupRun();
247
+ await this.cleanupRun(options.runId);
176
248
  }
177
- return this.finalizeGenerate(rawResult, list);
249
+ return this.finalizeGenerate(rawResult, list, options.runId);
178
250
  }
179
251
  return {
180
- runId: this.runId,
181
- stream: this.startStreamLoop(list, pendingResume),
182
- getState: () => this.getState(),
252
+ runId: options.runId,
253
+ stream: this.startStreamLoop({
254
+ list,
255
+ options: resumeOptions,
256
+ runId: options.runId,
257
+ pendingResume,
258
+ }),
183
259
  };
184
260
  }
185
261
  catch (error) {
186
262
  const isAbort = this.eventBus.isAborted;
187
263
  this.updateState({ status: isAbort ? 'cancelled' : 'failed' });
188
264
  if (!isAbort) {
189
- this.emitEvent({ type: "error", message: String(error), error });
265
+ this.eventBus.emit({ type: "error", message: String(error), error });
190
266
  }
191
267
  if (method === 'generate') {
192
268
  return {
193
- runId: this.runId,
269
+ runId: options.runId,
194
270
  messages: [],
195
271
  finishReason: 'error',
196
272
  error,
197
- getState: () => this.getState(),
198
273
  };
199
274
  }
200
- return { runId: this.runId, stream: (0, runtime_helpers_1.makeErrorStream)(error), getState: () => this.getState() };
275
+ return { runId: options.runId, stream: (0, runtime_helpers_1.makeErrorStream)(error) };
201
276
  }
202
277
  }
203
- async buildMessageList(input) {
278
+ async buildMessageList(input, options) {
204
279
  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, {
280
+ if (this.config.memory && options?.persistence?.threadId) {
281
+ const memMessages = await this.config.memory.getMessages(options.persistence.threadId, {
208
282
  limit: this.config.lastMessages ?? 10,
283
+ resourceId: options.persistence.resourceId,
209
284
  });
210
285
  if (memMessages.length > 0) {
211
286
  list.addHistory((0, strip_orphaned_tool_messages_1.stripOrphanedToolMessages)(memMessages));
212
287
  }
213
288
  }
214
- if (this.config.semanticRecall && persistence?.threadId) {
215
- await this.performSemanticRecall(list, input, persistence.threadId, persistence.resourceId);
289
+ if (this.config.semanticRecall && options?.persistence?.threadId) {
290
+ await this.performSemanticRecall(list, input, options.persistence.threadId, options.persistence.resourceId);
216
291
  }
217
- await this.setListWorkingMemoryConfig(list, persistence);
292
+ await this.setListObservationLogMemory(list, options?.persistence);
218
293
  list.addInput(input);
219
294
  return list;
220
295
  }
@@ -296,34 +371,38 @@ class AgentRuntime {
296
371
  return mid && expandedIds.has(mid);
297
372
  });
298
373
  }
299
- async initRun(input) {
300
- this.eventBus.resetAbort(this.executionOptions?.abortSignal);
301
- this.updateState({ status: 'running' });
302
- this.emitEvent({ type: "agent_start" });
374
+ async initRun(input, options) {
375
+ this.eventBus.resetAbort(options?.abortSignal);
376
+ this.updateState({
377
+ status: 'running',
378
+ persistence: options?.persistence,
379
+ });
380
+ this.eventBus.emit({ type: "agent_start" });
303
381
  await this.ensureModelCost();
304
382
  const normalizedInput = (0, runtime_helpers_1.normalizeInput)(input);
305
- return await this.buildMessageList(normalizedInput);
383
+ this.incrementMessageCount(options?.executionCounter);
384
+ return await this.buildMessageList(normalizedInput, options);
306
385
  }
307
- finalizeGenerate(result, list) {
308
- result.runId = this.runId;
386
+ finalizeGenerate(result, list, runId) {
387
+ result.runId = runId;
309
388
  result.usage = this.applyCost(result.usage);
310
389
  result.model = this.modelIdString;
311
390
  const finalized = (0, runtime_helpers_1.applySubAgentUsage)(result);
312
391
  this.updateState({ status: 'success', messageList: list.serialize() });
313
- this.emitEvent({ type: "agent_end", messages: finalized.messages });
314
- return { ...finalized, getState: () => this.getState() };
392
+ this.eventBus.emit({ type: "agent_end", messages: finalized.messages });
393
+ return finalized;
315
394
  }
316
- resolveTelemetry() {
395
+ resolveTelemetry(options) {
317
396
  if (this.config.telemetry)
318
397
  return this.config.telemetry;
319
- const inherited = this.executionOptions?.telemetry;
398
+ const inherited = options?.telemetry;
320
399
  if (!inherited)
321
400
  return undefined;
322
401
  return { ...inherited, functionId: this.config.name };
323
402
  }
324
- async flushTelemetry() {
403
+ async flushTelemetry(options) {
325
404
  try {
326
- const resolved = this.resolveTelemetry();
405
+ const resolved = this.resolveTelemetry(options);
327
406
  if (resolved?.provider) {
328
407
  await resolved.provider.forceFlush();
329
408
  }
@@ -331,8 +410,8 @@ class AgentRuntime {
331
410
  catch {
332
411
  }
333
412
  }
334
- buildTelemetryOptions() {
335
- const t = this.resolveTelemetry();
413
+ buildTelemetryOptions(options) {
414
+ const t = this.resolveTelemetry(options);
336
415
  if (!t?.enabled)
337
416
  return {};
338
417
  return {
@@ -347,23 +426,142 @@ class AgentRuntime {
347
426
  },
348
427
  };
349
428
  }
350
- async runGenerateLoop(list, pendingResume) {
351
- const { model, toolMap, aiTools, providerOptions, hasTools, outputSpec } = this.buildLoopContext();
429
+ buildTelemetryRootAttributes(t, spanName, runId) {
430
+ const metadataAttributes = this.buildTelemetryMetadataAttributes(t, 'langsmith.metadata');
431
+ return {
432
+ 'langsmith.traceable': 'true',
433
+ 'langsmith.trace.name': spanName,
434
+ 'langsmith.span.kind': 'chain',
435
+ 'langsmith.metadata.agent_name': this.config.name,
436
+ 'langsmith.metadata.agent_run_id': runId,
437
+ ...metadataAttributes,
438
+ ...buildAgentRootInputAttributes(this.config),
439
+ };
440
+ }
441
+ buildTelemetryMetadataAttributes(t, prefix) {
442
+ return Object.fromEntries(Object.entries(t.metadata ?? {}).map(([key, value]) => [`${prefix}.${key}`, value]));
443
+ }
444
+ buildAiSdkOperationAttributes(operationId, t) {
445
+ const functionId = t.functionId ?? this.config.name;
446
+ return {
447
+ 'operation.name': `${operationId} ${functionId}`,
448
+ 'resource.name': functionId,
449
+ 'ai.operationId': operationId,
450
+ 'ai.telemetry.functionId': functionId,
451
+ ...this.buildTelemetryMetadataAttributes(t, 'ai.telemetry.metadata'),
452
+ };
453
+ }
454
+ recordExecutionCounter(fn) {
455
+ try {
456
+ fn();
457
+ }
458
+ catch {
459
+ }
460
+ }
461
+ incrementMessageCount(counter) {
462
+ if (!counter)
463
+ return;
464
+ this.recordExecutionCounter(() => counter.incrementMessageCount());
465
+ }
466
+ incrementToolCallCount(counter) {
467
+ if (!counter)
468
+ return;
469
+ this.recordExecutionCounter(() => counter.incrementToolCallCount());
470
+ }
471
+ incrementTokenCount(counter, usage) {
472
+ if (!counter || !usage)
473
+ return;
474
+ const tokenCount = usage.totalTokens ?? (usage.inputTokens ?? 0) + (usage.outputTokens ?? 0);
475
+ if (tokenCount <= 0)
476
+ return;
477
+ this.recordExecutionCounter(() => counter.incrementTokenCount(tokenCount));
478
+ }
479
+ async withTelemetryRootSpan(operation, options, runId, fn) {
480
+ const t = this.resolveTelemetry(options);
481
+ if (!t?.enabled || t.runtimeRootSpanEnabled === false || !isActiveSpanTracer(t.tracer)) {
482
+ return await fn();
483
+ }
484
+ const spanName = `${t.functionId ?? this.config.name}.${operation}`;
485
+ return await t.tracer.startActiveSpan(spanName, { attributes: this.buildTelemetryRootAttributes(t, spanName, runId) }, async (span) => {
486
+ try {
487
+ return await fn();
488
+ }
489
+ catch (error) {
490
+ span.recordException?.(error);
491
+ span.setStatus?.({ code: 2, message: String(error) });
492
+ throw error;
493
+ }
494
+ finally {
495
+ span.end();
496
+ }
497
+ });
498
+ }
499
+ async withTelemetryToolSpan(toolCallId, toolName, input, t, fn) {
500
+ if (!t?.enabled || !isActiveSpanTracer(t.tracer)) {
501
+ return await fn();
502
+ }
503
+ const shouldRecordInputs = t.recordInputs ?? true;
504
+ const inputValue = shouldRecordInputs ? stringifyTelemetryValue(input) : undefined;
505
+ return await t.tracer.startActiveSpan('ai.toolCall', {
506
+ attributes: {
507
+ ...this.buildAiSdkOperationAttributes('ai.toolCall', t),
508
+ 'ai.toolCall.name': toolName,
509
+ 'ai.toolCall.id': toolCallId,
510
+ ...(inputValue !== undefined ? { 'ai.toolCall.args': inputValue } : {}),
511
+ },
512
+ }, async (span) => {
513
+ try {
514
+ const result = await fn();
515
+ const shouldRecordOutputs = t.recordOutputs ?? true;
516
+ const outputValue = shouldRecordOutputs ? stringifyTelemetryValue(result) : undefined;
517
+ if (outputValue !== undefined) {
518
+ span.setAttributes?.({ 'ai.toolCall.result': outputValue });
519
+ }
520
+ return result;
521
+ }
522
+ catch (error) {
523
+ span.recordException?.(error);
524
+ span.setStatus?.({ code: 2, message: String(error) });
525
+ throw error;
526
+ }
527
+ finally {
528
+ span.end();
529
+ }
530
+ });
531
+ }
532
+ async runGenerateLoop(ctx) {
533
+ const { list, options, runId, pendingResume } = ctx;
534
+ this.hydrateDeferredToolsFromList(list);
352
535
  let totalUsage;
353
536
  let lastFinishReason = 'stop';
354
537
  let structuredOutput;
355
538
  const toolCallSummary = [];
356
539
  const collectedSubAgentUsage = [];
357
- const runTelemetry = this.resolveTelemetry();
540
+ const runTelemetry = this.resolveTelemetry(options);
541
+ const staticLoopContext = this.buildStaticLoopContext({
542
+ ...options,
543
+ persistence: options?.persistence,
544
+ });
545
+ const pendingLoopContext = this.buildToolLoopContext(staticLoopContext.aiProviderTools);
546
+ const pendingToolCtx = {
547
+ toolMap: pendingLoopContext.toolMap,
548
+ list,
549
+ runId,
550
+ telemetry: runTelemetry,
551
+ executionCounter: options?.executionCounter,
552
+ };
358
553
  if (pendingResume) {
359
- const batch = await this.iteratePendingToolCallsConcurrent(pendingResume, toolMap, list, runTelemetry);
554
+ const batch = await this.iteratePendingToolCallsConcurrent({
555
+ ...pendingToolCtx,
556
+ pendingResume,
557
+ });
360
558
  for (const r of batch.results) {
361
559
  toolCallSummary.push(r.toolEntry);
362
560
  if (r.subAgentUsage)
363
561
  collectedSubAgentUsage.push(...r.subAgentUsage);
364
562
  }
365
563
  if (Object.keys(batch.pending).length > 0) {
366
- const suspendRunId = await this.persistSuspension(batch.pending, list, totalUsage);
564
+ const suspendRunId = await this.persistSuspension(batch.pending, options, list, totalUsage, runId);
367
565
  return {
368
566
  runId: suspendRunId,
369
567
  messages: list.responseDelta(),
@@ -377,49 +575,57 @@ class AgentRuntime {
377
575
  suspendPayload: s.payload,
378
576
  resumeSchema: s.resumeSchema,
379
577
  })),
380
- getState: () => this.getState(),
381
578
  };
382
579
  }
383
580
  }
384
- const maxIterations = this.executionOptions?.maxIterations ?? MAX_LOOP_ITERATIONS;
581
+ const maxIterations = options?.maxIterations ?? MAX_LOOP_ITERATIONS;
385
582
  for (let i = 0; i < maxIterations; i++) {
386
583
  if (this.eventBus.isAborted) {
387
584
  this.updateState({ status: 'cancelled' });
388
585
  throw new Error('Agent run was aborted');
389
586
  }
390
- this.emitEvent({ type: "turn_start" });
587
+ this.eventBus.emit({ type: "turn_start" });
588
+ const { toolMap, aiTools, hasTools, effectiveInstructions } = this.buildToolLoopContext(staticLoopContext.aiProviderTools);
391
589
  const result = await (0, ai_1.generateText)({
392
- model,
393
- messages: list.forLlm(this.config.instructions, this.config.instructionProviderOptions),
590
+ model: staticLoopContext.model,
591
+ messages: list.forLlm(effectiveInstructions, this.config.instructionProviderOptions),
394
592
  abortSignal: this.eventBus.signal,
395
593
  ...(hasTools ? { tools: aiTools } : {}),
396
- ...(providerOptions
397
- ? { providerOptions: providerOptions }
594
+ ...(staticLoopContext.providerOptions
595
+ ? { providerOptions: staticLoopContext.providerOptions }
398
596
  : {}),
399
- ...(outputSpec ? { output: outputSpec } : {}),
400
- ...this.buildTelemetryOptions(),
597
+ ...(staticLoopContext.outputSpec ? { output: staticLoopContext.outputSpec } : {}),
598
+ ...this.buildTelemetryOptions(options),
401
599
  });
402
600
  const aiFinishReason = result.finishReason;
403
601
  lastFinishReason = (0, messages_1.fromAiFinishReason)(aiFinishReason);
404
602
  totalUsage = (0, runtime_helpers_1.accumulateUsage)(totalUsage, result.usage);
603
+ this.incrementTokenCount(options?.executionCounter, result.usage);
405
604
  const responseMessages = result.response.messages;
406
605
  const newMessages = (0, messages_1.fromAiMessages)(responseMessages);
407
606
  list.addResponse(newMessages);
408
607
  if (aiFinishReason !== 'tool-calls') {
409
- if (outputSpec) {
608
+ if (staticLoopContext.outputSpec) {
410
609
  structuredOutput = result.output;
411
610
  }
412
- this.emitTurnEnd(newMessages, (0, runtime_helpers_1.extractToolResults)(newMessages));
611
+ this.emitTurnEnd(newMessages, (0, runtime_helpers_1.extractSettledToolCalls)(newMessages));
413
612
  break;
414
613
  }
415
- const batch = await this.iterateToolCallsConcurrent(result.toolCalls, toolMap, list, runTelemetry);
614
+ const batch = await this.iterateToolCallsConcurrent({
615
+ toolMap,
616
+ list,
617
+ runId,
618
+ telemetry: runTelemetry,
619
+ executionCounter: options?.executionCounter,
620
+ toolCalls: result.toolCalls,
621
+ });
416
622
  for (const r of batch.results) {
417
623
  toolCallSummary.push(r.toolEntry);
418
624
  if (r.subAgentUsage)
419
625
  collectedSubAgentUsage.push(...r.subAgentUsage);
420
626
  }
421
627
  if (Object.keys(batch.pending).length > 0) {
422
- const suspendRunId = await this.persistSuspension(batch.pending, list, totalUsage);
628
+ const suspendRunId = await this.persistSuspension(batch.pending, options, list, totalUsage, runId);
423
629
  return {
424
630
  runId: suspendRunId,
425
631
  messages: list.responseDelta(),
@@ -433,44 +639,59 @@ class AgentRuntime {
433
639
  suspendPayload: s.payload,
434
640
  resumeSchema: s.resumeSchema,
435
641
  })),
436
- getState: () => this.getState(),
437
642
  };
438
643
  }
439
- this.emitTurnEnd(newMessages, (0, runtime_helpers_1.extractToolResults)(list.responseDelta()));
644
+ this.emitTurnEnd(newMessages, (0, runtime_helpers_1.extractSettledToolCalls)(list.responseDelta()));
440
645
  }
441
646
  if (lastFinishReason === 'tool-calls') {
442
647
  throw new Error(`Agent loop exceeded ${maxIterations} iterations without reaching a stop condition`);
443
648
  }
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)({
649
+ await this.saveToMemory(list, options);
650
+ await this.flushTelemetry(options);
651
+ if (this.config.titleGeneration && options?.persistence?.threadId && this.config.memory) {
652
+ const titlePromise = (0, title_generation_1.generateThreadTitle)({
449
653
  memory: this.config.memory,
450
- threadId: persistence.threadId,
451
- resourceId: persistence.resourceId,
654
+ threadId: options.persistence.threadId,
655
+ resourceId: options.persistence.resourceId,
452
656
  titleConfig: this.config.titleGeneration,
453
657
  agentModel: this.config.model,
454
658
  turnDelta: list.turnDelta(),
455
659
  });
660
+ this.backgroundTasks.track(titlePromise);
661
+ if (this.config.titleGeneration.sync) {
662
+ await titlePromise;
663
+ }
456
664
  }
457
665
  return {
458
- runId: this.runId,
666
+ runId: runId ?? '',
459
667
  messages: list.responseDelta(),
460
668
  finishReason: lastFinishReason,
461
669
  usage: totalUsage,
462
670
  ...(structuredOutput !== undefined && { structuredOutput }),
463
671
  ...(toolCallSummary.length > 0 && { toolCalls: toolCallSummary }),
464
672
  ...(collectedSubAgentUsage.length > 0 && { subAgentUsage: collectedSubAgentUsage }),
465
- getState: () => this.getState(),
466
673
  };
467
674
  }
468
- startStreamLoop(list, pendingResume) {
675
+ startStreamLoop(ctx) {
676
+ const { options, runId } = ctx;
469
677
  const { readable, writable } = new TransformStream();
470
678
  const writer = writable.getWriter();
471
- this.runStreamLoop(list, writer, pendingResume).catch(async (error) => {
472
- await this.flushTelemetry();
473
- await this.cleanupRun();
679
+ const onToolExecutionStart = (data) => {
680
+ if (data.type !== "tool_execution_start")
681
+ return;
682
+ writer
683
+ .write({
684
+ type: 'tool-execution-start',
685
+ toolCallId: data.toolCallId,
686
+ toolName: data.toolName,
687
+ })
688
+ .catch(() => { });
689
+ };
690
+ this.eventBus.on("tool_execution_start", onToolExecutionStart);
691
+ this.withTelemetryRootSpan('stream', options, runId, async () => await this.runStreamLoop({ ...ctx, writer }))
692
+ .catch(async (error) => {
693
+ await this.flushTelemetry(options);
694
+ await this.cleanupRun(runId);
474
695
  try {
475
696
  await writer.write({ type: 'error', error });
476
697
  await writer.write({ type: 'finish', finishReason: 'error' });
@@ -479,11 +700,15 @@ class AgentRuntime {
479
700
  catch {
480
701
  writer.abort(error).catch(() => { });
481
702
  }
703
+ })
704
+ .finally(() => {
705
+ this.eventBus.off("tool_execution_start", onToolExecutionStart);
482
706
  });
483
707
  return readable;
484
708
  }
485
- async runStreamLoop(list, writer, pendingResume) {
486
- const { model, toolMap, aiTools, providerOptions, hasTools, outputSpec } = this.buildLoopContext();
709
+ async runStreamLoop(ctx) {
710
+ const { list, options, runId, pendingResume, writer } = ctx;
711
+ this.hydrateDeferredToolsFromList(list);
487
712
  const writeChunk = async (chunk) => {
488
713
  await writer.write(chunk);
489
714
  };
@@ -491,9 +716,9 @@ class AgentRuntime {
491
716
  let lastFinishReason = 'stop';
492
717
  let structuredOutput;
493
718
  const collectedSubAgentUsage = [];
494
- const maxIterations = this.executionOptions?.maxIterations ?? MAX_LOOP_ITERATIONS;
719
+ const maxIterations = options?.maxIterations ?? MAX_LOOP_ITERATIONS;
495
720
  const closeStreamWithError = async (error, status) => {
496
- await this.cleanupRun();
721
+ await this.cleanupRun(runId);
497
722
  this.updateState({ status });
498
723
  await writer.write({ type: 'error', error });
499
724
  await writer.write({ type: 'finish', finishReason: 'error' });
@@ -505,16 +730,33 @@ class AgentRuntime {
505
730
  await closeStreamWithError(new Error('Agent run was aborted'), 'cancelled');
506
731
  return true;
507
732
  };
508
- const runTelemetry = this.resolveTelemetry();
733
+ const runTelemetry = this.resolveTelemetry(options);
734
+ const staticLoopContext = this.buildStaticLoopContext({
735
+ ...options,
736
+ persistence: options?.persistence,
737
+ });
738
+ const pendingLoopContext = this.buildToolLoopContext(staticLoopContext.aiProviderTools);
739
+ const pendingToolCtx = {
740
+ toolMap: pendingLoopContext.toolMap,
741
+ list,
742
+ runId,
743
+ telemetry: runTelemetry,
744
+ executionCounter: options?.executionCounter,
745
+ };
509
746
  if (pendingResume) {
510
747
  try {
511
- const batch = await this.iteratePendingToolCallsConcurrent(pendingResume, toolMap, list, runTelemetry);
748
+ const batch = await this.iteratePendingToolCallsConcurrent({
749
+ ...pendingToolCtx,
750
+ pendingResume,
751
+ });
512
752
  for (const r of batch.results) {
513
753
  if (r.subAgentUsage)
514
754
  collectedSubAgentUsage.push(...r.subAgentUsage);
515
755
  await writer.write({
516
- type: 'message',
517
- message: r.message,
756
+ type: 'tool-result',
757
+ toolCallId: r.toolCallId,
758
+ toolName: r.toolName,
759
+ output: r.modelOutput,
518
760
  });
519
761
  if (r.customMessage) {
520
762
  await writer.write({ type: 'message', message: r.customMessage });
@@ -522,12 +764,15 @@ class AgentRuntime {
522
764
  }
523
765
  for (const e of batch.errors) {
524
766
  await writer.write({
525
- type: 'message',
526
- message: e.message,
767
+ type: 'tool-result',
768
+ toolCallId: e.toolCallId,
769
+ toolName: e.toolName,
770
+ output: e.error,
771
+ isError: true,
527
772
  });
528
773
  }
529
774
  if (Object.keys(batch.pending).length > 0) {
530
- const suspendRunId = await this.persistSuspension(batch.pending, list, totalUsage);
775
+ const suspendRunId = await this.persistSuspension(batch.pending, options, list, totalUsage, runId);
531
776
  for (const s of batch.suspensions) {
532
777
  await writer.write({
533
778
  type: 'tool-call-suspended',
@@ -545,7 +790,7 @@ class AgentRuntime {
545
790
  }
546
791
  }
547
792
  catch (error) {
548
- this.emitEvent({ type: "error", message: String(error), error });
793
+ this.eventBus.emit({ type: "error", message: String(error), error });
549
794
  await closeStreamWithError(error, 'failed');
550
795
  return;
551
796
  }
@@ -553,21 +798,23 @@ class AgentRuntime {
553
798
  for (let i = 0; i < maxIterations; i++) {
554
799
  if (await handleAbort())
555
800
  return;
556
- this.emitEvent({ type: "turn_start" });
801
+ this.eventBus.emit({ type: "turn_start" });
802
+ const { toolMap, aiTools, hasTools, effectiveInstructions } = this.buildToolLoopContext(staticLoopContext.aiProviderTools);
803
+ const messages = list.forLlm(effectiveInstructions, this.config.instructionProviderOptions);
557
804
  const result = (0, ai_1.streamText)({
558
- model,
559
- messages: list.forLlm(this.config.instructions, this.config.instructionProviderOptions),
805
+ model: staticLoopContext.model,
806
+ messages,
560
807
  abortSignal: this.eventBus.signal,
561
808
  ...(hasTools ? { tools: aiTools } : {}),
562
- ...(providerOptions
563
- ? { providerOptions: providerOptions }
809
+ ...(staticLoopContext.providerOptions
810
+ ? { providerOptions: staticLoopContext.providerOptions }
564
811
  : {}),
565
- ...(outputSpec ? { output: outputSpec } : {}),
566
- ...this.buildTelemetryOptions(),
812
+ ...(staticLoopContext.outputSpec ? { output: staticLoopContext.outputSpec } : {}),
813
+ ...this.buildTelemetryOptions(options),
567
814
  });
568
815
  try {
569
816
  for await (const chunk of result.fullStream) {
570
- if (chunk.type === 'finish' || chunk.type === 'finish-step')
817
+ if (chunk.type === 'finish')
571
818
  continue;
572
819
  const converted = (0, stream_1.convertChunk)(chunk);
573
820
  if (converted)
@@ -577,7 +824,7 @@ class AgentRuntime {
577
824
  catch (streamError) {
578
825
  if (await handleAbort())
579
826
  return;
580
- this.emitEvent({
827
+ this.eventBus.emit({
581
828
  type: "error",
582
829
  message: String(streamError),
583
830
  error: streamError,
@@ -592,27 +839,37 @@ class AgentRuntime {
592
839
  const response = await result.response;
593
840
  lastFinishReason = (0, messages_1.fromAiFinishReason)(aiFinishReason);
594
841
  totalUsage = (0, runtime_helpers_1.accumulateUsage)(totalUsage, usage);
842
+ this.incrementTokenCount(options?.executionCounter, usage);
595
843
  const responseMessages = response.messages;
596
844
  const newMessages = (0, messages_1.fromAiMessages)(responseMessages);
597
845
  list.addResponse(newMessages);
598
846
  if (aiFinishReason !== 'tool-calls') {
599
- if (outputSpec) {
847
+ if (staticLoopContext.outputSpec) {
600
848
  structuredOutput = await result.output;
601
849
  }
602
- this.emitTurnEnd(newMessages, (0, runtime_helpers_1.extractToolResults)(newMessages));
850
+ this.emitTurnEnd(newMessages, (0, runtime_helpers_1.extractSettledToolCalls)(newMessages));
603
851
  break;
604
852
  }
605
853
  const toolCalls = await result.toolCalls;
606
854
  try {
607
- const batch = await this.iterateToolCallsConcurrent(toolCalls, toolMap, list, runTelemetry);
855
+ const batch = await this.iterateToolCallsConcurrent({
856
+ toolMap,
857
+ list,
858
+ runId,
859
+ telemetry: runTelemetry,
860
+ executionCounter: options?.executionCounter,
861
+ toolCalls,
862
+ });
608
863
  if (await handleAbort())
609
864
  return;
610
865
  for (const r of batch.results) {
611
866
  if (r.subAgentUsage)
612
867
  collectedSubAgentUsage.push(...r.subAgentUsage);
613
868
  await writer.write({
614
- type: 'message',
615
- message: r.message,
869
+ type: 'tool-result',
870
+ toolCallId: r.toolCallId,
871
+ toolName: r.toolName,
872
+ output: r.modelOutput,
616
873
  });
617
874
  if (r.customMessage) {
618
875
  await writer.write({ type: 'message', message: r.customMessage });
@@ -620,12 +877,15 @@ class AgentRuntime {
620
877
  }
621
878
  for (const e of batch.errors) {
622
879
  await writer.write({
623
- type: 'message',
624
- message: e.message,
880
+ type: 'tool-result',
881
+ toolCallId: e.toolCallId,
882
+ toolName: e.toolName,
883
+ output: e.error,
884
+ isError: true,
625
885
  });
626
886
  }
627
887
  if (Object.keys(batch.pending).length > 0) {
628
- const suspendRunId = await this.persistSuspension(batch.pending, list, totalUsage);
888
+ const suspendRunId = await this.persistSuspension(batch.pending, options, list, totalUsage, runId);
629
889
  for (const s of batch.suspensions) {
630
890
  await writer.write({
631
891
  type: 'tool-call-suspended',
@@ -643,11 +903,11 @@ class AgentRuntime {
643
903
  }
644
904
  }
645
905
  catch (error) {
646
- this.emitEvent({ type: "error", message: String(error), error });
906
+ this.eventBus.emit({ type: "error", message: String(error), error });
647
907
  await closeStreamWithError(error, 'failed');
648
908
  return;
649
909
  }
650
- this.emitTurnEnd(newMessages, (0, runtime_helpers_1.extractToolResults)(list.responseDelta()));
910
+ this.emitTurnEnd(newMessages, (0, runtime_helpers_1.extractSettledToolCalls)(list.responseDelta()));
651
911
  }
652
912
  const costUsage = this.applyCost(totalUsage);
653
913
  const parentCost = costUsage?.cost ?? 0;
@@ -664,38 +924,101 @@ class AgentRuntime {
664
924
  }),
665
925
  });
666
926
  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)({
927
+ await this.saveToMemory(list, options);
928
+ if (this.config.titleGeneration && options?.persistence && this.config.memory) {
929
+ const titlePromise = (0, title_generation_1.generateThreadTitle)({
671
930
  memory: this.config.memory,
672
- threadId: persistence.threadId,
673
- resourceId: persistence.resourceId,
931
+ threadId: options.persistence.threadId,
932
+ resourceId: options.persistence.resourceId,
674
933
  titleConfig: this.config.titleGeneration,
675
934
  agentModel: this.config.model,
676
935
  turnDelta: list.turnDelta(),
677
936
  });
937
+ this.backgroundTasks.track(titlePromise);
938
+ if (this.config.titleGeneration.sync) {
939
+ await titlePromise;
940
+ }
678
941
  }
679
- await this.cleanupRun();
680
- await this.flushTelemetry();
942
+ await this.cleanupRun(runId);
943
+ await this.flushTelemetry(options);
681
944
  this.updateState({ status: 'success', messageList: list.serialize() });
682
- this.emitEvent({ type: "agent_end", messages: list.responseDelta() });
945
+ this.eventBus.emit({ type: "agent_end", messages: list.responseDelta() });
683
946
  }
684
947
  finally {
685
948
  await writer.close();
686
949
  }
687
950
  }
688
- async saveToMemory(list) {
689
- const persistence = this.currentState.persistence;
690
- if (!this.config.memory || !persistence)
951
+ async saveToMemory(list, options) {
952
+ if (!this.config.memory || !options?.persistence)
691
953
  return;
692
954
  const delta = list.turnDelta();
693
955
  if (delta.length === 0)
694
956
  return;
695
- await (0, memory_store_1.saveMessagesToThread)(this.config.memory, persistence.threadId, persistence.resourceId, delta);
957
+ await (0, memory_store_1.saveMessagesToThread)(this.config.memory, options.persistence.threadId, options.persistence.resourceId, delta);
696
958
  if (this.config.semanticRecall?.embedder && this.config.memory.saveEmbeddings) {
697
- await this.saveEmbeddingsForMessages(persistence.threadId, persistence.resourceId, delta);
959
+ await this.saveEmbeddingsForMessages(options.persistence.threadId, options.persistence.resourceId, delta);
698
960
  }
961
+ this.scheduleObservationLogJobs(options.persistence);
962
+ }
963
+ scheduleObservationLogJobs(persistence) {
964
+ const { memory, observationalMemory } = this.config;
965
+ if (!memory || !observationalMemory || !(0, observation_log_store_1.hasObservationLogStore)(memory))
966
+ return;
967
+ const scope = this.getObservationLogScope(persistence);
968
+ const runner = this.getMemoryTaskRunner(memory, observationalMemory);
969
+ const observe = observationalMemory.observe;
970
+ const observerThresholdTokens = observationalMemory.observerThresholdTokens;
971
+ if (observe &&
972
+ observerThresholdTokens !== undefined &&
973
+ hasObservationLogObserverMemory(memory)) {
974
+ runner.schedule({ ...scope, taskKind: 'observer' }, async () => await (0, observation_log_observer_1.runObservationLogObserver)({
975
+ memory,
976
+ ...scope,
977
+ observerThresholdTokens,
978
+ observationLogTailLimit: observationalMemory.observationLogTailLimit ?? 0,
979
+ observe,
980
+ messageSource: {
981
+ threadId: persistence.threadId,
982
+ resourceId: persistence.resourceId,
983
+ },
984
+ }));
985
+ }
986
+ const reflect = observationalMemory.reflect;
987
+ const reflectorThresholdTokens = observationalMemory.reflectorThresholdTokens;
988
+ if (reflect && reflectorThresholdTokens !== undefined) {
989
+ runner.schedule({ ...scope, taskKind: 'reflector' }, async () => await (0, observation_log_reflector_1.runObservationLogReflector)({
990
+ memory,
991
+ ...scope,
992
+ reflectorThresholdTokens,
993
+ reflect,
994
+ }));
995
+ }
996
+ }
997
+ getMemoryTaskRunner(memory, observationalMemory) {
998
+ this.memoryTasks ??= new scoped_memory_task_runner_1.ScopedMemoryTaskRunner({
999
+ tracker: this.backgroundTasks,
1000
+ lockStore: (0, observation_log_store_1.hasObservationLogTaskLockStore)(memory) ? memory : undefined,
1001
+ lockTtlMs: observationalMemory.lockTtlMs,
1002
+ onEvent: (event) => {
1003
+ if (event.type !== 'failed')
1004
+ return;
1005
+ const source = event.task.taskKind;
1006
+ const message = `Observation log ${source} task failed`;
1007
+ logger.warn(message, {
1008
+ error: event.error,
1009
+ scopeKind: event.task.scopeKind,
1010
+ scopeId: event.task.scopeId,
1011
+ });
1012
+ this.eventBus.emit({ type: "error", message, error: event.error, source });
1013
+ },
1014
+ });
1015
+ return this.memoryTasks;
1016
+ }
1017
+ getObservationLogScope(persistence) {
1018
+ return {
1019
+ scopeKind: 'thread',
1020
+ scopeId: (0, observation_log_1.createObservationLogThreadScopeId)(persistence.threadId, persistence.resourceId),
1021
+ };
699
1022
  }
700
1023
  async saveEmbeddingsForMessages(threadId, resourceId, messages) {
701
1024
  const embeddable = [];
@@ -741,12 +1064,12 @@ class AgentRuntime {
741
1064
  switch (provider) {
742
1065
  case 'anthropic': {
743
1066
  const cfg = thinking;
1067
+ if (cfg.mode === 'adaptive') {
1068
+ return { anthropic: { thinking: { type: 'adaptive' } } };
1069
+ }
744
1070
  return {
745
1071
  anthropic: {
746
- thinking: {
747
- type: 'enabled',
748
- budgetTokens: cfg.budgetTokens ?? 10000,
749
- },
1072
+ thinking: { type: 'enabled', budgetTokens: cfg.budgetTokens ?? 10000 },
750
1073
  },
751
1074
  };
752
1075
  }
@@ -792,8 +1115,13 @@ class AgentRuntime {
792
1115
  }
793
1116
  return merged;
794
1117
  }
795
- async iterateToolCallsConcurrent(toolCalls, toolMap, list, resolvedTelemetry) {
1118
+ async iterateToolCallsConcurrent(ctx) {
1119
+ const { toolCalls, toolMap, list, runId, telemetry: resolvedTelemetry, executionCounter } = ctx;
796
1120
  const executableCalls = toolCalls.filter((tc) => !tc.providerExecuted);
1121
+ const providerExecutedCount = toolCalls.length - executableCalls.length;
1122
+ for (let i = 0; i < providerExecutedCount; i++) {
1123
+ this.incrementToolCallCount(executionCounter);
1124
+ }
797
1125
  const executableCallsById = new Map(executableCalls.map((tc) => [tc.toolCallId, tc]));
798
1126
  const unexecutedIds = new Set(executableCalls.map((tc) => tc.toolCallId));
799
1127
  const batchSize = this.concurrency;
@@ -807,7 +1135,7 @@ class AgentRuntime {
807
1135
  throw new Error('Agent run was aborted');
808
1136
  }
809
1137
  const batch = executableCalls.slice(batchStart, batchStart + batchSize);
810
- const settledResults = await Promise.allSettled(batch.map(async (tc) => await this.processToolCall(tc.toolCallId, tc.toolName, tc.input, toolMap, list, undefined, resolvedTelemetry)));
1138
+ const settledResults = await Promise.allSettled(batch.map(async (tc) => await this.processToolCall(tc.toolCallId, tc.toolName, tc.input, toolMap, list, undefined, resolvedTelemetry, executionCounter, true)));
811
1139
  for (const tc of batch) {
812
1140
  unexecutedIds.delete(tc.toolCallId);
813
1141
  }
@@ -817,12 +1145,12 @@ class AgentRuntime {
817
1145
  const tc = batch[i];
818
1146
  const toolInput = tc.input;
819
1147
  if (result.status === 'rejected') {
1148
+ list.setToolCallError(tc.toolCallId, result.reason);
820
1149
  errors.push({
821
1150
  toolCallId: tc.toolCallId,
822
1151
  toolName: tc.toolName,
823
1152
  input: toolInput,
824
1153
  error: result.reason,
825
- message: (0, runtime_helpers_1.makeErrorToolResultMessage)(tc.toolCallId, tc.toolName, result.reason),
826
1154
  });
827
1155
  }
828
1156
  else if (result.value.outcome === 'suspended') {
@@ -841,6 +1169,7 @@ class AgentRuntime {
841
1169
  input: toolInput,
842
1170
  suspendPayload: result.value.payload,
843
1171
  resumeSchema: result.value.resumeSchema,
1172
+ runId,
844
1173
  };
845
1174
  }
846
1175
  else if (result.value.outcome === 'success') {
@@ -849,9 +1178,9 @@ class AgentRuntime {
849
1178
  toolName: tc.toolName,
850
1179
  input: toolInput,
851
1180
  toolEntry: result.value.toolEntry,
1181
+ modelOutput: result.value.modelOutput,
852
1182
  subAgentUsage: result.value.subAgentUsage,
853
1183
  customMessage: result.value.customMessage,
854
- message: result.value.message,
855
1184
  });
856
1185
  }
857
1186
  else if (result.value.outcome === 'error') {
@@ -860,7 +1189,6 @@ class AgentRuntime {
860
1189
  toolName: tc.toolName,
861
1190
  input: toolInput,
862
1191
  error: result.value.error,
863
- message: result.value.message,
864
1192
  });
865
1193
  }
866
1194
  else if (result.value.outcome === 'noop') {
@@ -881,7 +1209,8 @@ class AgentRuntime {
881
1209
  }
882
1210
  return { results, suspensions, errors, pending };
883
1211
  }
884
- async iteratePendingToolCallsConcurrent(pendingResume, toolMap, list, resolvedTelemetry) {
1212
+ async iteratePendingToolCallsConcurrent(ctx) {
1213
+ const { pendingResume, toolMap, list, runId, telemetry: resolvedTelemetry, executionCounter, } = ctx;
885
1214
  const resumedId = pendingResume.resumeToolCallId;
886
1215
  const resumedEntry = pendingResume.pendingToolCalls[resumedId];
887
1216
  if (!resumedEntry) {
@@ -892,13 +1221,14 @@ class AgentRuntime {
892
1221
  const suspensions = [];
893
1222
  const errors = [];
894
1223
  const pending = {};
895
- const processResult = await this.processToolCall(resumedEntry.toolCallId, resumedToolName, resumedEntry.input, toolMap, list, pendingResume.resumeData, resolvedTelemetry);
1224
+ const processResult = await this.processToolCall(resumedEntry.toolCallId, resumedToolName, resumedEntry.input, toolMap, list, pendingResume.resumeData, resolvedTelemetry, executionCounter, false);
896
1225
  if (processResult.outcome === 'suspended') {
897
1226
  pending[resumedId] = {
898
1227
  ...resumedEntry,
899
1228
  suspended: true,
900
1229
  suspendPayload: processResult.payload,
901
1230
  resumeSchema: processResult.resumeSchema,
1231
+ runId,
902
1232
  };
903
1233
  suspensions.push({
904
1234
  toolCallId: resumedId,
@@ -914,9 +1244,9 @@ class AgentRuntime {
914
1244
  toolName: resumedToolName,
915
1245
  input: resumedEntry.input,
916
1246
  toolEntry: processResult.toolEntry,
1247
+ modelOutput: processResult.modelOutput,
917
1248
  subAgentUsage: processResult.subAgentUsage,
918
1249
  customMessage: processResult.customMessage,
919
- message: processResult.message,
920
1250
  });
921
1251
  }
922
1252
  else if (processResult.outcome === 'error') {
@@ -925,7 +1255,6 @@ class AgentRuntime {
925
1255
  toolName: resumedToolName,
926
1256
  input: resumedEntry.input,
927
1257
  error: processResult.error,
928
- message: processResult.message,
929
1258
  });
930
1259
  }
931
1260
  else if (processResult.outcome === 'noop') {
@@ -954,7 +1283,14 @@ class AgentRuntime {
954
1283
  }
955
1284
  }
956
1285
  if (unexecuted.length > 0) {
957
- const batch = await this.iterateToolCallsConcurrent(unexecuted, toolMap, list, resolvedTelemetry);
1286
+ const batch = await this.iterateToolCallsConcurrent({
1287
+ toolCalls: unexecuted,
1288
+ toolMap,
1289
+ list,
1290
+ runId,
1291
+ telemetry: resolvedTelemetry,
1292
+ executionCounter,
1293
+ });
958
1294
  results.push(...batch.results);
959
1295
  suspensions.push(...batch.suspensions);
960
1296
  errors.push(...batch.errors);
@@ -962,73 +1298,71 @@ class AgentRuntime {
962
1298
  }
963
1299
  return { results, suspensions, errors, pending };
964
1300
  }
965
- async processToolCall(toolCallId, toolName, toolInput, toolMap, list, resumeData, resolvedTelemetry) {
1301
+ async processToolCall(toolCallId, toolName, toolInput, toolMap, list, resumeData, resolvedTelemetry, executionCounter, countToolCall = true) {
966
1302
  const builtTool = toolMap.get(toolName);
967
- this.emitEvent({
1303
+ this.eventBus.emit({
968
1304
  type: "tool_execution_start",
969
1305
  toolCallId,
970
1306
  toolName,
971
1307
  args: toolInput,
972
1308
  });
973
1309
  const makeToolError = (error) => {
974
- this.emitEvent({
1310
+ this.eventBus.emit({
975
1311
  type: "tool_execution_end",
976
1312
  toolCallId,
977
1313
  toolName,
978
1314
  result: error,
979
1315
  isError: true,
980
1316
  });
981
- const errorMsg = (0, runtime_helpers_1.makeErrorToolResultMessage)(toolCallId, toolName, error);
982
- list.addResponse([errorMsg]);
983
- return { outcome: 'error', error, message: errorMsg };
1317
+ list.setToolCallError(toolCallId, error);
1318
+ return { outcome: 'error', error };
984
1319
  };
985
1320
  if (!builtTool) {
986
1321
  return makeToolError(new Error(`Tool ${toolName} not found`));
987
1322
  }
988
- const existingToolResults = list
1323
+ const settledBlock = list
989
1324
  .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({
1325
+ .flatMap((m) => ((0, message_1.isLlmMessage)(m) && 'content' in m ? m.content : []))
1326
+ .find((c) => c.type === 'tool-call' && c.toolCallId === toolCallId && c.state !== 'pending');
1327
+ if (settledBlock) {
1328
+ let settledResult;
1329
+ if (settledBlock.state === 'resolved') {
1330
+ settledResult = settledBlock.output;
1331
+ }
1332
+ else {
1333
+ settledResult = settledBlock.error;
1334
+ }
1335
+ this.eventBus.emit({
995
1336
  type: "tool_execution_end",
996
1337
  toolCallId,
997
1338
  toolName,
998
- result: existingToolResult.result,
999
- isError: !!existingToolResult.isError,
1339
+ result: settledResult,
1340
+ isError: settledBlock.state === 'rejected',
1000
1341
  });
1001
1342
  return { outcome: 'noop' };
1002
1343
  }
1344
+ if (countToolCall) {
1345
+ this.incrementToolCallCount(executionCounter);
1346
+ }
1003
1347
  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
- }
1348
+ const result = await (0, parse_1.parseWithSchema)(builtTool.inputSchema, toolInput);
1349
+ if (!result.success) {
1350
+ return makeToolError(new Error(`Invalid tool input: ${result.error}`));
1018
1351
  }
1352
+ toolInput = result.data;
1019
1353
  }
1020
1354
  let toolResult;
1021
1355
  try {
1022
- toolResult = await (0, tool_adapter_1.executeTool)(toolInput, builtTool, resumeData, resolvedTelemetry);
1356
+ toolResult = await this.withTelemetryToolSpan(toolCallId, toolName, toolInput, resolvedTelemetry, async () => await (0, tool_adapter_1.executeTool)(toolInput, builtTool, resumeData, resolvedTelemetry, toolCallId));
1023
1357
  }
1024
1358
  catch (error) {
1025
1359
  return makeToolError(error);
1026
1360
  }
1027
1361
  if ((0, tool_adapter_1.isSuspendedToolResult)(toolResult)) {
1028
1362
  if (builtTool?.suspendSchema) {
1029
- const parseResult = await builtTool.suspendSchema.safeParseAsync(toolResult.payload);
1363
+ const parseResult = await (0, parse_1.parseWithSchema)(builtTool.suspendSchema, toolResult.payload);
1030
1364
  if (!parseResult.success) {
1031
- return makeToolError(new Error(`Invalid suspend payload: ${parseResult.error.message}`));
1365
+ return makeToolError(new Error(`Invalid suspend payload: ${parseResult.error}`));
1032
1366
  }
1033
1367
  toolResult.payload = parseResult.data;
1034
1368
  }
@@ -1036,8 +1370,17 @@ class AgentRuntime {
1036
1370
  const error = new Error(`Tool ${toolName} has no resume schema`);
1037
1371
  return makeToolError(error);
1038
1372
  }
1039
- const resumeSchema = (0, zod_to_json_schema_1.zodToJsonSchema)(builtTool.resumeSchema);
1040
- return { outcome: 'suspended', payload: toolResult.payload, resumeSchema };
1373
+ const resumeSchema = (0, zod_1.isZodSchema)(builtTool.resumeSchema)
1374
+ ? (0, zod_to_json_schema_1.zodToJsonSchema)(builtTool.resumeSchema)
1375
+ : builtTool.resumeSchema;
1376
+ if (!resumeSchema) {
1377
+ return makeToolError(new Error('Invalid resume schema'));
1378
+ }
1379
+ return {
1380
+ outcome: 'suspended',
1381
+ payload: toolResult.payload,
1382
+ resumeSchema,
1383
+ };
1041
1384
  }
1042
1385
  let actualResult = toolResult;
1043
1386
  let extractedSubAgentUsage;
@@ -1045,7 +1388,7 @@ class AgentRuntime {
1045
1388
  actualResult = toolResult.output;
1046
1389
  extractedSubAgentUsage = toolResult.subAgentUsage;
1047
1390
  }
1048
- this.emitEvent({
1391
+ this.eventBus.emit({
1049
1392
  type: "tool_execution_end",
1050
1393
  toolCallId,
1051
1394
  toolName,
@@ -1055,8 +1398,7 @@ class AgentRuntime {
1055
1398
  const modelResult = builtTool.toModelOutput
1056
1399
  ? builtTool.toModelOutput(actualResult)
1057
1400
  : actualResult;
1058
- const toolResultMsg = (0, runtime_helpers_1.makeToolResultMessage)(toolCallId, toolName, modelResult);
1059
- list.addResponse([toolResultMsg]);
1401
+ list.setToolCallResult(toolCallId, (0, json_value_1.toJsonValue)(modelResult));
1060
1402
  const customMessage = builtTool?.toMessage?.(actualResult);
1061
1403
  if (customMessage) {
1062
1404
  list.addResponse([customMessage]);
@@ -1069,65 +1411,86 @@ class AgentRuntime {
1069
1411
  output: actualResult,
1070
1412
  transformed: !!builtTool.toModelOutput,
1071
1413
  },
1414
+ modelOutput: modelResult,
1072
1415
  subAgentUsage: extractedSubAgentUsage,
1073
1416
  customMessage,
1074
- message: toolResultMsg,
1075
1417
  };
1076
1418
  }
1077
- buildLoopContext() {
1078
- const wmTool = this.buildWorkingMemoryToolForRun(this.currentState.persistence);
1079
- const allUserTools = wmTool
1080
- ? [...(this.config.tools ?? []), wmTool]
1081
- : (this.config.tools ?? []);
1082
- const aiTools = (0, tool_adapter_1.toAiSdkTools)(allUserTools);
1419
+ buildStaticLoopContext(execOptions) {
1083
1420
  const aiProviderTools = (0, tool_adapter_1.toAiSdkProviderTools)(this.config.providerTools);
1084
- const allTools = { ...aiTools, ...aiProviderTools };
1421
+ const model = (0, model_factory_1.createModel)(this.config.model);
1085
1422
  return {
1086
- model: (0, model_factory_1.createModel)(this.config.model),
1087
- toolMap: (0, tool_adapter_1.buildToolMap)(allUserTools),
1088
- aiTools: allTools,
1089
- providerOptions: this.buildCallProviderOptions(this.executionOptions?.providerOptions),
1090
- hasTools: Object.keys(allTools).length > 0,
1423
+ model,
1424
+ aiProviderTools,
1425
+ providerOptions: this.buildCallProviderOptions(execOptions?.providerOptions),
1091
1426
  outputSpec: this.config.structuredOutput
1092
1427
  ? ai_1.Output.object({ schema: this.config.structuredOutput })
1093
1428
  : undefined,
1094
1429
  };
1095
1430
  }
1096
- buildWorkingMemoryToolForRun(persistence) {
1097
- const wmParams = this.resolveWorkingMemoryParams(persistence);
1098
- if (!wmParams)
1099
- return undefined;
1100
- return (0, working_memory_1.buildWorkingMemoryTool)({
1101
- structured: wmParams.structured,
1102
- schema: wmParams.schema,
1103
- persist: wmParams.persistFn,
1104
- });
1431
+ buildToolLoopContext(aiProviderTools) {
1432
+ const allUserTools = this.getCurrentTools();
1433
+ const aiTools = (0, tool_adapter_1.toAiSdkTools)(allUserTools);
1434
+ const allTools = { ...aiTools, ...aiProviderTools };
1435
+ const aiToolCount = Object.keys(allTools).length;
1436
+ const toolMap = (0, tool_adapter_1.buildToolMap)(allUserTools);
1437
+ const effectiveInstructions = this.composeEffectiveInstructions(allUserTools);
1438
+ return {
1439
+ toolMap,
1440
+ aiTools: allTools,
1441
+ hasTools: aiToolCount > 0,
1442
+ effectiveInstructions,
1443
+ };
1444
+ }
1445
+ getCurrentTools() {
1446
+ const baseTools = this.config.tools ?? [];
1447
+ if (!this.deferredToolManager?.hasTools)
1448
+ return baseTools;
1449
+ return [
1450
+ ...baseTools,
1451
+ ...this.deferredToolManager.getControllerTools(),
1452
+ ...this.deferredToolManager.getLoadedTools(),
1453
+ ];
1454
+ }
1455
+ hydrateDeferredToolsFromList(list) {
1456
+ if (!this.deferredToolManager?.hasTools)
1457
+ return;
1458
+ this.deferredToolManager.hydrateLoadedToolsFromMessages(list.serialize().messages);
1459
+ }
1460
+ composeEffectiveInstructions(tools) {
1461
+ const fragments = tools
1462
+ .map((t) => t.systemInstruction)
1463
+ .filter((s) => typeof s === 'string' && s.trim().length > 0);
1464
+ const userInstructions = this.config.instructions;
1465
+ if (fragments.length === 0)
1466
+ return userInstructions;
1467
+ const block = `<built_in_rules>\n${fragments.map((f) => `- ${f}`).join('\n')}\n</built_in_rules>`;
1468
+ return userInstructions ? `${block}\n\n${userInstructions}` : block;
1105
1469
  }
1106
- async persistSuspension(pendingToolCalls, list, totalUsage) {
1107
- const executionOptions = this.executionOptions?.maxIterations !== undefined
1108
- ? { maxIterations: this.executionOptions.maxIterations }
1109
- : undefined;
1470
+ async persistSuspension(pendingToolCalls, options, list, totalUsage, existingRunId) {
1471
+ const runId = existingRunId ?? (0, run_state_1.generateRunId)();
1472
+ const executionOptions = options?.maxIterations !== undefined ? { maxIterations: options.maxIterations } : undefined;
1110
1473
  const state = {
1111
- persistence: this.currentState.persistence,
1474
+ persistence: options?.persistence,
1112
1475
  status: 'suspended',
1113
1476
  messageList: list.serialize(),
1114
1477
  pendingToolCalls,
1115
1478
  usage: totalUsage,
1116
1479
  executionOptions,
1117
1480
  };
1118
- await this.runState.suspend(this.runId, state);
1481
+ await this.runState.suspend(runId, state);
1119
1482
  this.updateState({ status: 'suspended', pendingToolCalls, messageList: list.serialize() });
1120
- return this.runId;
1483
+ return runId;
1121
1484
  }
1122
- async cleanupRun() {
1123
- if (this.runId) {
1124
- await this.runState.complete(this.runId);
1485
+ async cleanupRun(runId) {
1486
+ if (runId) {
1487
+ await this.runState.complete(runId);
1125
1488
  }
1126
1489
  }
1127
1490
  emitTurnEnd(newMessages, toolResults) {
1128
1491
  const assistantMsg = newMessages.find((m) => 'role' in m && m.role === 'assistant');
1129
1492
  if (assistantMsg) {
1130
- this.emitEvent({ type: "turn_end", message: assistantMsg, toolResults });
1493
+ this.eventBus.emit({ type: "turn_end", message: assistantMsg, toolResults });
1131
1494
  }
1132
1495
  }
1133
1496
  updateState(patch) {
@@ -1163,49 +1526,22 @@ class AgentRuntime {
1163
1526
  return usage;
1164
1527
  return { ...usage, cost: (0, catalog_1.computeCost)(usage, this.modelCost) };
1165
1528
  }
1166
- async setListWorkingMemoryConfig(list, options) {
1167
- const wmParams = this.resolveWorkingMemoryParams(options);
1168
- if (!wmParams || !this.config.memory?.getWorkingMemory)
1529
+ async setListObservationLogMemory(list, options) {
1530
+ const memory = this.config.memory;
1531
+ if (!memory || !options?.threadId || !(0, observation_log_store_1.hasObservationLogStore)(memory))
1169
1532
  return;
1170
- const wmState = await this.config.memory.getWorkingMemory(wmParams.memoryParams);
1171
- list.workingMemory = {
1172
- template: wmParams.template,
1173
- structured: wmParams.structured,
1174
- state: wmState,
1175
- ...(wmParams.instruction !== undefined && { instruction: wmParams.instruction }),
1176
- };
1177
- }
1178
- emitEvent(data) {
1179
- this.eventBus.emit({ ...data, runId: this.runId });
1533
+ const scope = this.getObservationLogScope(options);
1534
+ const observations = await memory.getActiveObservationLog({
1535
+ ...scope,
1536
+ order: 'asc',
1537
+ });
1538
+ list.observationLogMemory =
1539
+ (0, observation_log_renderer_1.renderObservationLog)(observations, {
1540
+ renderTokenBudget: this.config.observationLog?.renderTokenBudget,
1541
+ }) ?? undefined;
1180
1542
  }
1181
- resolveWorkingMemoryParams(options) {
1182
- if (!options)
1183
- return null;
1184
- if (!this.config.workingMemory)
1185
- return null;
1186
- const scope = this.config.workingMemory?.scope ?? 'resource';
1187
- if (scope === 'resource' && !options.resourceId) {
1188
- throw new Error('Working memory scope is "resource" but no resourceId was provided. ' +
1189
- 'Pass a resourceId in RunOptions or change the scope to "thread".');
1190
- }
1191
- if (!options)
1192
- return null;
1193
- const memoryParams = { ...options, scope };
1194
- const persistFn = this.config.workingMemory && this.config.memory?.saveWorkingMemory && options
1195
- ? async (content) => {
1196
- await this.config.memory.saveWorkingMemory(memoryParams, content);
1197
- }
1198
- : undefined;
1199
- if (!persistFn)
1200
- return null;
1201
- return {
1202
- persistFn,
1203
- memoryParams,
1204
- template: this.config.workingMemory.template,
1205
- structured: this.config.workingMemory.structured,
1206
- schema: this.config.workingMemory.schema,
1207
- instruction: this.config.workingMemory.instruction,
1208
- };
1543
+ getConfiguredTelemetry() {
1544
+ return this.config.telemetry;
1209
1545
  }
1210
1546
  }
1211
1547
  exports.AgentRuntime = AgentRuntime;