@n8n/agents 0.12.0 → 0.13.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 (198) hide show
  1. package/dist/build.tsbuildinfo +1 -1
  2. package/dist/index.d.ts +22 -21
  3. package/dist/index.js +13 -13
  4. package/dist/index.js.map +1 -1
  5. package/dist/runtime/{agent-runtime.d.ts → loop/agent-runtime.d.ts} +19 -51
  6. package/dist/runtime/loop/agent-runtime.js +468 -0
  7. package/dist/runtime/loop/agent-runtime.js.map +1 -0
  8. package/dist/runtime/loop/execution-counter.d.ts +12 -0
  9. package/dist/runtime/loop/execution-counter.js +36 -0
  10. package/dist/runtime/loop/execution-counter.js.map +1 -0
  11. package/dist/runtime/loop/generate-sink.d.ts +13 -0
  12. package/dist/runtime/loop/generate-sink.js +75 -0
  13. package/dist/runtime/loop/generate-sink.js.map +1 -0
  14. package/dist/runtime/loop/run-output-sink.d.ts +68 -0
  15. package/dist/runtime/loop/run-output-sink.js +3 -0
  16. package/dist/runtime/loop/run-output-sink.js.map +1 -0
  17. package/dist/runtime/loop/runtime-context.d.ts +38 -0
  18. package/dist/runtime/loop/runtime-context.js +188 -0
  19. package/dist/runtime/loop/runtime-context.js.map +1 -0
  20. package/dist/runtime/{runtime-helpers.d.ts → loop/runtime-helpers.d.ts} +3 -2
  21. package/dist/runtime/{runtime-helpers.js → loop/runtime-helpers.js} +4 -2
  22. package/dist/runtime/loop/runtime-helpers.js.map +1 -0
  23. package/dist/runtime/loop/stream-sink.d.ts +22 -0
  24. package/dist/runtime/loop/stream-sink.js +144 -0
  25. package/dist/runtime/loop/stream-sink.js.map +1 -0
  26. package/dist/runtime/{mcp-connection.d.ts → mcp/mcp-connection.d.ts} +2 -2
  27. package/dist/runtime/{mcp-connection.js → mcp/mcp-connection.js} +16 -2
  28. package/dist/runtime/mcp/mcp-connection.js.map +1 -0
  29. package/dist/runtime/{mcp-tool-resolver.d.ts → mcp/mcp-tool-resolver.d.ts} +1 -1
  30. package/dist/runtime/mcp/mcp-tool-resolver.js.map +1 -0
  31. package/dist/runtime/{episodic-memory-defaults.d.ts → memory/episodic-memory-defaults.d.ts} +1 -1
  32. package/dist/runtime/{episodic-memory-defaults.js → memory/episodic-memory-defaults.js} +2 -2
  33. package/dist/runtime/memory/episodic-memory-defaults.js.map +1 -0
  34. package/dist/runtime/{episodic-memory.d.ts → memory/episodic-memory.d.ts} +4 -4
  35. package/dist/runtime/{episodic-memory.js → memory/episodic-memory.js} +2 -2
  36. package/dist/runtime/memory/episodic-memory.js.map +1 -0
  37. package/dist/runtime/memory/memory-lifecycle.js.map +1 -0
  38. package/dist/runtime/memory/memory-orchestrator.d.ts +27 -0
  39. package/dist/runtime/memory/memory-orchestrator.js +232 -0
  40. package/dist/runtime/memory/memory-orchestrator.js.map +1 -0
  41. package/dist/runtime/{memory-store.d.ts → memory/memory-store.d.ts} +4 -4
  42. package/dist/runtime/{memory-store.js → memory/memory-store.js} +1 -1
  43. package/dist/runtime/memory/memory-store.js.map +1 -0
  44. package/dist/runtime/{observation-log-defaults.d.ts → memory/observation-log-defaults.d.ts} +2 -2
  45. package/dist/runtime/{observation-log-defaults.js → memory/observation-log-defaults.js} +6 -6
  46. package/dist/runtime/memory/observation-log-defaults.js.map +1 -0
  47. package/dist/runtime/{observation-log-observer.d.ts → memory/observation-log-observer.d.ts} +6 -5
  48. package/dist/runtime/{observation-log-observer.js → memory/observation-log-observer.js} +6 -2
  49. package/dist/runtime/memory/observation-log-observer.js.map +1 -0
  50. package/dist/runtime/{observation-log-reflector.d.ts → memory/observation-log-reflector.d.ts} +2 -2
  51. package/dist/runtime/{observation-log-reflector.js → memory/observation-log-reflector.js} +4 -6
  52. package/dist/runtime/memory/observation-log-reflector.js.map +1 -0
  53. package/dist/runtime/{observation-log-renderer.d.ts → memory/observation-log-renderer.d.ts} +1 -1
  54. package/dist/runtime/{observation-log-renderer.js → memory/observation-log-renderer.js} +1 -1
  55. package/dist/runtime/memory/observation-log-renderer.js.map +1 -0
  56. package/dist/runtime/{observation-log-store.d.ts → memory/observation-log-store.d.ts} +2 -1
  57. package/dist/runtime/{observation-log-store.js → memory/observation-log-store.js} +1 -0
  58. package/dist/runtime/memory/observation-log-store.js.map +1 -0
  59. package/dist/runtime/{scoped-memory-task-runner.d.ts → memory/scoped-memory-task-runner.d.ts} +5 -2
  60. package/dist/runtime/{scoped-memory-task-runner.js → memory/scoped-memory-task-runner.js} +2 -1
  61. package/dist/runtime/memory/scoped-memory-task-runner.js.map +1 -0
  62. package/dist/runtime/{strip-orphaned-tool-messages.d.ts → memory/strip-orphaned-tool-messages.d.ts} +1 -1
  63. package/dist/runtime/{strip-orphaned-tool-messages.js → memory/strip-orphaned-tool-messages.js} +1 -1
  64. package/dist/runtime/memory/strip-orphaned-tool-messages.js.map +1 -0
  65. package/dist/runtime/{title-generation.d.ts → memory/title-generation.d.ts} +5 -3
  66. package/dist/runtime/{title-generation.js → memory/title-generation.js} +5 -5
  67. package/dist/runtime/memory/title-generation.js.map +1 -0
  68. package/dist/runtime/model/lazy-ai.js.map +1 -0
  69. package/dist/runtime/{message-list.d.ts → model/message-list.d.ts} +3 -3
  70. package/dist/runtime/{message-list.js → model/message-list.js} +3 -3
  71. package/dist/runtime/model/message-list.js.map +1 -0
  72. package/dist/runtime/model/messages.d.ts +17 -0
  73. package/dist/runtime/{messages.js → model/messages.js} +64 -18
  74. package/dist/runtime/model/messages.js.map +1 -0
  75. package/dist/runtime/{model-factory.d.ts → model/model-factory.d.ts} +3 -2
  76. package/dist/runtime/{model-factory.js → model/model-factory.js} +3 -3
  77. package/dist/runtime/model/model-factory.js.map +1 -0
  78. package/dist/runtime/model/provider-credentials.js.map +1 -0
  79. package/dist/runtime/model/raw-usage.d.ts +11 -0
  80. package/dist/runtime/model/raw-usage.js +55 -0
  81. package/dist/runtime/model/raw-usage.js.map +1 -0
  82. package/dist/runtime/state/background-task-tracker.js.map +1 -0
  83. package/dist/runtime/{event-bus.d.ts → state/event-bus.d.ts} +2 -2
  84. package/dist/runtime/{event-bus.js → state/event-bus.js} +1 -1
  85. package/dist/runtime/state/event-bus.js.map +1 -0
  86. package/dist/runtime/{run-state.d.ts → state/run-state.d.ts} +1 -1
  87. package/dist/runtime/state/run-state.js.map +1 -0
  88. package/dist/runtime/streaming/stream-session.d.ts +21 -0
  89. package/dist/runtime/streaming/stream-session.js +67 -0
  90. package/dist/runtime/streaming/stream-session.js.map +1 -0
  91. package/dist/runtime/streaming/stream-writer-guard.d.ts +14 -0
  92. package/dist/runtime/streaming/stream-writer-guard.js +45 -0
  93. package/dist/runtime/streaming/stream-writer-guard.js.map +1 -0
  94. package/dist/runtime/{stream.d.ts → streaming/stream.d.ts} +2 -1
  95. package/dist/runtime/{stream.js → streaming/stream.js} +3 -1
  96. package/dist/runtime/streaming/stream.js.map +1 -0
  97. package/dist/runtime/telemetry/runtime-telemetry.d.ts +19 -0
  98. package/dist/runtime/telemetry/runtime-telemetry.js +174 -0
  99. package/dist/runtime/telemetry/runtime-telemetry.js.map +1 -0
  100. package/dist/runtime/{deferred-tool-manager.d.ts → tools/deferred-tool-manager.d.ts} +2 -2
  101. package/dist/runtime/{deferred-tool-manager.js → tools/deferred-tool-manager.js} +3 -5
  102. package/dist/runtime/tools/deferred-tool-manager.js.map +1 -0
  103. package/dist/runtime/{delegate-sub-agent-tool.d.ts → tools/delegate-sub-agent-tool.d.ts} +2 -2
  104. package/dist/runtime/{delegate-sub-agent-tool.js → tools/delegate-sub-agent-tool.js} +2 -2
  105. package/dist/runtime/tools/delegate-sub-agent-tool.js.map +1 -0
  106. package/dist/runtime/{fix-tool-call.d.ts → tools/fix-tool-call.d.ts} +1 -1
  107. package/dist/runtime/{fix-tool-call.js → tools/fix-tool-call.js} +1 -1
  108. package/dist/runtime/tools/fix-tool-call.js.map +1 -0
  109. package/dist/runtime/{sdk-owned-tool.d.ts → tools/sdk-owned-tool.d.ts} +1 -1
  110. package/dist/runtime/tools/sdk-owned-tool.js.map +1 -0
  111. package/dist/runtime/tools/sub-agent-task-path.js.map +1 -0
  112. package/dist/runtime/{tool-adapter.d.ts → tools/tool-adapter.d.ts} +1 -1
  113. package/dist/runtime/{tool-adapter.js → tools/tool-adapter.js} +4 -4
  114. package/dist/runtime/tools/tool-adapter.js.map +1 -0
  115. package/dist/runtime/tools/tool-call-executor.d.ts +86 -0
  116. package/dist/runtime/tools/tool-call-executor.js +498 -0
  117. package/dist/runtime/tools/tool-call-executor.js.map +1 -0
  118. package/dist/runtime/{write-todos-tool.d.ts → tools/write-todos-tool.d.ts} +1 -1
  119. package/dist/runtime/{write-todos-tool.js → tools/write-todos-tool.js} +1 -1
  120. package/dist/runtime/tools/write-todos-tool.js.map +1 -0
  121. package/dist/sdk/agent.d.ts +7 -1
  122. package/dist/sdk/agent.js +18 -8
  123. package/dist/sdk/agent.js.map +1 -1
  124. package/dist/sdk/eval.js +1 -1
  125. package/dist/sdk/eval.js.map +1 -1
  126. package/dist/sdk/guardrails/patterns.d.ts +3 -0
  127. package/dist/sdk/guardrails/patterns.js +95 -2
  128. package/dist/sdk/guardrails/patterns.js.map +1 -1
  129. package/dist/sdk/mcp-client.js +1 -1
  130. package/dist/sdk/mcp-client.js.map +1 -1
  131. package/dist/sdk/memory.d.ts +1 -1
  132. package/dist/sdk/memory.js +6 -6
  133. package/dist/sdk/memory.js.map +1 -1
  134. package/dist/skills/registry.js +2 -4
  135. package/dist/skills/registry.js.map +1 -1
  136. package/dist/skills/validator.js +4 -6
  137. package/dist/skills/validator.js.map +1 -1
  138. package/dist/types/sdk/agent-builder.d.ts +2 -0
  139. package/dist/types/sdk/agent.d.ts +6 -2
  140. package/dist/types/sdk/guardrail.d.ts +1 -1
  141. package/dist/types/sdk/provider.d.ts +1 -0
  142. package/dist/workspace/sandbox/daytona-auth-manager.d.ts +1 -1
  143. package/dist/workspace/sandbox/daytona-sandbox.d.ts +1 -1
  144. package/dist/workspace/sandbox/lazy-daytona.d.ts +1 -1
  145. package/dist/workspace/sandbox/lazy-daytona.js +1 -1
  146. package/dist/workspace/sandbox/lazy-daytona.js.map +1 -1
  147. package/dist/workspace/sandbox/types.d.ts +1 -1
  148. package/package.json +10 -10
  149. package/dist/runtime/agent-runtime.js +0 -1771
  150. package/dist/runtime/agent-runtime.js.map +0 -1
  151. package/dist/runtime/background-task-tracker.js.map +0 -1
  152. package/dist/runtime/deferred-tool-manager.js.map +0 -1
  153. package/dist/runtime/delegate-sub-agent-tool.js.map +0 -1
  154. package/dist/runtime/episodic-memory-defaults.js.map +0 -1
  155. package/dist/runtime/episodic-memory.js.map +0 -1
  156. package/dist/runtime/event-bus.js.map +0 -1
  157. package/dist/runtime/execution-counter.d.ts +0 -9
  158. package/dist/runtime/execution-counter.js +0 -16
  159. package/dist/runtime/execution-counter.js.map +0 -1
  160. package/dist/runtime/fix-tool-call.js.map +0 -1
  161. package/dist/runtime/lazy-ai.js.map +0 -1
  162. package/dist/runtime/mcp-connection.js.map +0 -1
  163. package/dist/runtime/mcp-tool-resolver.js.map +0 -1
  164. package/dist/runtime/memory-lifecycle.js.map +0 -1
  165. package/dist/runtime/memory-store.js.map +0 -1
  166. package/dist/runtime/message-list.js.map +0 -1
  167. package/dist/runtime/messages.d.ts +0 -6
  168. package/dist/runtime/messages.js.map +0 -1
  169. package/dist/runtime/model-factory.js.map +0 -1
  170. package/dist/runtime/observation-log-defaults.js.map +0 -1
  171. package/dist/runtime/observation-log-observer.js.map +0 -1
  172. package/dist/runtime/observation-log-reflector.js.map +0 -1
  173. package/dist/runtime/observation-log-renderer.js.map +0 -1
  174. package/dist/runtime/observation-log-store.js.map +0 -1
  175. package/dist/runtime/provider-credentials.js.map +0 -1
  176. package/dist/runtime/run-state.js.map +0 -1
  177. package/dist/runtime/runtime-helpers.js.map +0 -1
  178. package/dist/runtime/scoped-memory-task-runner.js.map +0 -1
  179. package/dist/runtime/sdk-owned-tool.js.map +0 -1
  180. package/dist/runtime/stream.js.map +0 -1
  181. package/dist/runtime/strip-orphaned-tool-messages.js.map +0 -1
  182. package/dist/runtime/sub-agent-task-path.js.map +0 -1
  183. package/dist/runtime/title-generation.js.map +0 -1
  184. package/dist/runtime/tool-adapter.js.map +0 -1
  185. package/dist/runtime/write-todos-tool.js.map +0 -1
  186. /package/dist/runtime/{mcp-tool-resolver.js → mcp/mcp-tool-resolver.js} +0 -0
  187. /package/dist/runtime/{memory-lifecycle.d.ts → memory/memory-lifecycle.d.ts} +0 -0
  188. /package/dist/runtime/{memory-lifecycle.js → memory/memory-lifecycle.js} +0 -0
  189. /package/dist/runtime/{lazy-ai.d.ts → model/lazy-ai.d.ts} +0 -0
  190. /package/dist/runtime/{lazy-ai.js → model/lazy-ai.js} +0 -0
  191. /package/dist/runtime/{provider-credentials.d.ts → model/provider-credentials.d.ts} +0 -0
  192. /package/dist/runtime/{provider-credentials.js → model/provider-credentials.js} +0 -0
  193. /package/dist/runtime/{background-task-tracker.d.ts → state/background-task-tracker.d.ts} +0 -0
  194. /package/dist/runtime/{background-task-tracker.js → state/background-task-tracker.js} +0 -0
  195. /package/dist/runtime/{run-state.js → state/run-state.js} +0 -0
  196. /package/dist/runtime/{sdk-owned-tool.js → tools/sdk-owned-tool.js} +0 -0
  197. /package/dist/runtime/{sub-agent-task-path.d.ts → tools/sub-agent-task-path.d.ts} +0 -0
  198. /package/dist/runtime/{sub-agent-task-path.js → tools/sub-agent-task-path.js} +0 -0
@@ -1,1771 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.AgentRuntime = void 0;
4
- const zod_to_json_schema_1 = require("zod-to-json-schema");
5
- const catalog_1 = require("../sdk/catalog");
6
- const message_1 = require("../sdk/message");
7
- const background_task_tracker_1 = require("./background-task-tracker");
8
- const deferred_tool_manager_1 = require("./deferred-tool-manager");
9
- const delegate_sub_agent_tool_1 = require("./delegate-sub-agent-tool");
10
- const episodic_memory_1 = require("./episodic-memory");
11
- const event_bus_1 = require("./event-bus");
12
- const execution_counter_1 = require("./execution-counter");
13
- const fix_tool_call_1 = require("./fix-tool-call");
14
- const json_value_1 = require("./json-value");
15
- const lazy_ai_1 = require("./lazy-ai");
16
- const logger_1 = require("./logger");
17
- const memory_store_1 = require("./memory-store");
18
- const message_list_1 = require("./message-list");
19
- const messages_1 = require("./messages");
20
- const model_factory_1 = require("./model-factory");
21
- const observation_log_observer_1 = require("./observation-log-observer");
22
- const observation_log_reflector_1 = require("./observation-log-reflector");
23
- const observation_log_renderer_1 = require("./observation-log-renderer");
24
- const observation_log_store_1 = require("./observation-log-store");
25
- const run_state_1 = require("./run-state");
26
- const runtime_helpers_1 = require("./runtime-helpers");
27
- const scoped_memory_task_runner_1 = require("./scoped-memory-task-runner");
28
- const stream_1 = require("./stream");
29
- const strip_orphaned_tool_messages_1 = require("./strip-orphaned-tool-messages");
30
- const sub_agent_task_path_1 = require("./sub-agent-task-path");
31
- const title_generation_1 = require("./title-generation");
32
- const tool_adapter_1 = require("./tool-adapter");
33
- const cancellation_1 = require("../sdk/cancellation");
34
- const telemetry_1 = require("../sdk/telemetry");
35
- const json_schema_1 = require("../utils/json-schema");
36
- const parse_1 = require("../utils/parse");
37
- const zod_1 = require("../utils/zod");
38
- function isActiveSpanTracer(value) {
39
- return (value !== null &&
40
- typeof value === 'object' &&
41
- typeof Reflect.get(value, 'startActiveSpan') === 'function');
42
- }
43
- function stringifyTelemetryValue(value) {
44
- try {
45
- return JSON.stringify(value);
46
- }
47
- catch {
48
- return undefined;
49
- }
50
- }
51
- function getToolInputSchema(tool) {
52
- if (!tool.inputSchema) {
53
- return undefined;
54
- }
55
- return (0, zod_1.isZodSchema)(tool.inputSchema) ? (0, zod_to_json_schema_1.zodToJsonSchema)(tool.inputSchema) : tool.inputSchema;
56
- }
57
- function summarizeToolForTelemetry(tool) {
58
- return {
59
- name: tool.name,
60
- description: tool.description,
61
- type: tool.mcpTool ? 'mcp' : 'local',
62
- ...(tool.mcpServerName ? { mcp_server: tool.mcpServerName } : {}),
63
- ...(tool.suspendSchema || tool.resumeSchema || tool.approval ? { approval: true } : {}),
64
- ...(tool.inputSchema ? { input_schema: getToolInputSchema(tool) } : {}),
65
- };
66
- }
67
- function summarizeProviderToolForTelemetry(tool) {
68
- const [provider] = tool.name.split('.');
69
- return {
70
- name: tool.name,
71
- provider,
72
- type: 'provider',
73
- args: tool.args,
74
- ...(tool.inputSchema ? { input_schema: getToolInputSchema(tool) } : {}),
75
- };
76
- }
77
- function isDeniedApprovalResumeData(value) {
78
- return value !== null && typeof value === 'object' && Reflect.get(value, 'approved') === false;
79
- }
80
- function shouldEmitToolExecutionStart(tool, resumeData) {
81
- if (!tool.approval)
82
- return true;
83
- if (!tool.approval.required && tool.approval.conditional !== true)
84
- return true;
85
- if (resumeData === undefined)
86
- return false;
87
- return !isDeniedApprovalResumeData(resumeData);
88
- }
89
- function getToolResumeJsonSchema(tool) {
90
- if (!tool.resumeSchema)
91
- return undefined;
92
- return (0, zod_1.isZodSchema)(tool.resumeSchema) ? (0, zod_to_json_schema_1.zodToJsonSchema)(tool.resumeSchema) : tool.resumeSchema;
93
- }
94
- function buildAgentRootInputAttributes(config) {
95
- const localTools = (config.tools ?? []).map(summarizeToolForTelemetry);
96
- const providerTools = (config.providerTools ?? []).map(summarizeProviderToolForTelemetry);
97
- const tools = [...localTools, ...providerTools];
98
- const toolNames = tools
99
- .map((tool) => (typeof tool.name === 'string' ? tool.name : undefined))
100
- .filter((name) => name !== undefined);
101
- const serialized = stringifyTelemetryValue({
102
- agent: config.name,
103
- tool_count: tools.length,
104
- tools,
105
- });
106
- return {
107
- ...(toolNames.length > 0 ? { 'langsmith.metadata.available_tools': toolNames } : {}),
108
- ...(serialized ? { 'gen_ai.prompt': serialized } : {}),
109
- };
110
- }
111
- const MAX_LOOP_ITERATIONS = 30;
112
- const DEFAULT_MEMORY_TASK_LOCK_TTL_MS = 30_000;
113
- const logger = (0, logger_1.createFilteredLogger)();
114
- function getAiSdk() {
115
- return (0, lazy_ai_1.loadAi)();
116
- }
117
- const EMPTY_MESSAGE_LIST = {
118
- messages: [],
119
- historyIds: [],
120
- inputIds: [],
121
- responseIds: [],
122
- };
123
- function hasFunctionProperty(value, property) {
124
- return property in value && typeof Reflect.get(value, property) === 'function';
125
- }
126
- function hasObservationLogObserverMemory(memory) {
127
- return ((0, observation_log_store_1.hasObservationLogStore)(memory) &&
128
- hasFunctionProperty(memory, 'getMessagesForObservationScope') &&
129
- hasFunctionProperty(memory, 'getCursor') &&
130
- hasFunctionProperty(memory, 'setCursor'));
131
- }
132
- class AgentRuntime {
133
- constructor(config) {
134
- this.backgroundTasks = new background_task_tracker_1.BackgroundTaskTracker();
135
- this.episodicMemoryTasksByResource = new Map();
136
- this.config = config;
137
- this.runId = config.runId ?? (0, run_state_1.generateRunId)();
138
- if (config.deferredTools && config.deferredTools.length > 0) {
139
- this.deferredToolManager = new deferred_tool_manager_1.DeferredToolManager(config.deferredTools, config.toolSearch);
140
- }
141
- this.runState = config.runState ?? new run_state_1.RunStateManager(config.checkpointStorage);
142
- this.eventBus = config.eventBus ?? new event_bus_1.AgentEventBus();
143
- this.modelCost = config.modelCost;
144
- this.currentState = {
145
- persistence: undefined,
146
- status: 'idle',
147
- messageList: EMPTY_MESSAGE_LIST,
148
- pendingToolCalls: {},
149
- };
150
- }
151
- setTelemetry(telemetry) {
152
- this.config.telemetry = telemetry;
153
- }
154
- async dispose() {
155
- this.eventBus.dispose();
156
- await this.backgroundTasks.flush();
157
- }
158
- getState() {
159
- return { ...this.currentState };
160
- }
161
- abort() {
162
- this.eventBus.abort();
163
- }
164
- async generate(input, options) {
165
- const abortScope = this.eventBus.createAbortScope(options?.abortSignal);
166
- let list = undefined;
167
- try {
168
- const initializedList = await this.initRun(input, options);
169
- list = initializedList;
170
- const rawResult = await this.withTelemetryRootSpan('generate', options, this.runId, async () => await this.runGenerateLoop({ list: initializedList, options, abortScope }));
171
- return this.finalizeGenerate(rawResult, list);
172
- }
173
- catch (error) {
174
- await this.flushTelemetry(options);
175
- const isAbort = abortScope.isAborted;
176
- this.updateState({ status: isAbort ? 'cancelled' : 'failed' });
177
- if (!isAbort) {
178
- this.eventBus.emit({ type: "error", message: String(error), error });
179
- }
180
- return {
181
- runId: this.runId,
182
- messages: list?.responseDelta() ?? [],
183
- finishReason: 'error',
184
- error,
185
- getState: () => this.getState(),
186
- };
187
- }
188
- finally {
189
- abortScope.dispose();
190
- }
191
- }
192
- async stream(input, options) {
193
- const abortScope = this.eventBus.createAbortScope(options?.abortSignal);
194
- let list;
195
- try {
196
- list = await this.initRun(input, options);
197
- }
198
- catch (error) {
199
- const isAbort = abortScope.isAborted;
200
- this.updateState({ status: isAbort ? 'cancelled' : 'failed' });
201
- if (!isAbort) {
202
- this.eventBus.emit({ type: "error", message: String(error), error });
203
- }
204
- abortScope.dispose();
205
- return { runId: this.runId, stream: (0, runtime_helpers_1.makeErrorStream)(error), getState: () => this.getState() };
206
- }
207
- return {
208
- runId: this.runId,
209
- stream: this.startStreamLoop({ list, options, abortScope }),
210
- getState: () => this.getState(),
211
- };
212
- }
213
- async resume(method, data, options) {
214
- this.runId = options.runId;
215
- const state = await this.runState.resume(this.runId);
216
- if (!state)
217
- throw new Error(`No suspended run found for runId: ${this.runId}`);
218
- const toolCall = state.pendingToolCalls[options.toolCallId];
219
- if (!toolCall)
220
- throw new Error(`No tool call found for toolCallId: ${options.toolCallId}`);
221
- const list = message_list_1.AgentMessageList.deserialize(state.messageList);
222
- this.hydrateDeferredToolsFromList(list);
223
- const toolForValidation = this.getCurrentTools(state.persistence).find((t) => t.name === toolCall.toolName);
224
- if (!toolForValidation)
225
- throw new Error(`Tool ${toolCall.toolName} not found`);
226
- let resumeData = data;
227
- let abortScope;
228
- if (!(0, cancellation_1.isCancellation)(resumeData) && toolForValidation.resumeSchema) {
229
- const parseResult = await (0, parse_1.parseWithSchema)(toolForValidation.resumeSchema, data);
230
- if (!parseResult.success) {
231
- throw new Error(`Invalid resume payload: ${parseResult.error}`);
232
- }
233
- resumeData = parseResult.data;
234
- }
235
- try {
236
- const { runId: _rid, toolCallId: _tcid, ...callerExecOptions } = options;
237
- const persisted = state.executionOptions ?? {};
238
- const persistedMaxIterations = persisted.maxIterations;
239
- const callerMaxIterations = callerExecOptions.maxIterations;
240
- if (callerMaxIterations !== undefined &&
241
- persistedMaxIterations !== undefined &&
242
- callerMaxIterations < persistedMaxIterations) {
243
- throw new Error(`Cannot decrease maxIterations when resuming a run. Expected >= ${persistedMaxIterations}, received ${callerMaxIterations}.`);
244
- }
245
- const mergedMaxIterations = callerMaxIterations ?? persistedMaxIterations;
246
- const mergedExecOptions = {
247
- ...callerExecOptions,
248
- ...(mergedMaxIterations !== undefined ? { maxIterations: mergedMaxIterations } : {}),
249
- ...(state.iterationCount !== undefined ? { iterationCount: state.iterationCount } : {}),
250
- };
251
- const tool = this.getCurrentTools(state.persistence, mergedExecOptions.executionCounter).find((t) => t.name === toolCall.toolName);
252
- if (!tool)
253
- throw new Error(`Tool ${toolCall.toolName} not found`);
254
- const resumeOptions = {
255
- persistence: state.persistence,
256
- ...mergedExecOptions,
257
- };
258
- abortScope = this.eventBus.createAbortScope(resumeOptions.abortSignal);
259
- const activeAbortScope = abortScope;
260
- const pendingResume = {
261
- pendingToolCalls: state.pendingToolCalls,
262
- resumeToolCallId: options.toolCallId,
263
- resumeData,
264
- messages: state.messageList.messages,
265
- };
266
- await this.ensureModelCost();
267
- await this.setListObservationLogMemory(list, state.persistence);
268
- if (method === 'generate') {
269
- const rawResult = await this.withTelemetryRootSpan('generate', resumeOptions, this.runId, async () => await this.runGenerateLoop({
270
- list,
271
- options: resumeOptions,
272
- abortScope: activeAbortScope,
273
- pendingResume,
274
- }));
275
- if (!rawResult.pendingSuspend) {
276
- await this.cleanupRun();
277
- }
278
- try {
279
- return this.finalizeGenerate(rawResult, list);
280
- }
281
- finally {
282
- abortScope.dispose();
283
- }
284
- }
285
- return {
286
- runId: this.runId,
287
- stream: this.startStreamLoop({
288
- list,
289
- options: resumeOptions,
290
- abortScope: activeAbortScope,
291
- pendingResume,
292
- }),
293
- getState: () => this.getState(),
294
- };
295
- }
296
- catch (error) {
297
- const isAbort = abortScope?.isAborted ?? false;
298
- abortScope?.dispose();
299
- this.updateState({ status: isAbort ? 'cancelled' : 'failed' });
300
- if (!isAbort) {
301
- this.eventBus.emit({ type: "error", message: String(error), error });
302
- }
303
- if (method === 'generate') {
304
- return {
305
- runId: this.runId,
306
- messages: [],
307
- finishReason: 'error',
308
- error,
309
- getState: () => this.getState(),
310
- };
311
- }
312
- return { runId: this.runId, stream: (0, runtime_helpers_1.makeErrorStream)(error), getState: () => this.getState() };
313
- }
314
- }
315
- async buildMessageList(input, options) {
316
- const list = new message_list_1.AgentMessageList();
317
- if (this.config.memory && options?.persistence?.threadId) {
318
- const memMessages = await this.loadHistoryMessages(options.persistence);
319
- if (memMessages.length > 0) {
320
- list.addHistory((0, strip_orphaned_tool_messages_1.stripOrphanedToolMessages)(memMessages));
321
- }
322
- }
323
- await this.setListObservationLogMemory(list, options?.persistence);
324
- list.addInput(input);
325
- return list;
326
- }
327
- async loadHistoryMessages(persistence) {
328
- const memory = this.config.memory;
329
- if (!memory)
330
- return [];
331
- const { threadId, resourceId } = persistence;
332
- if (this.config.observationalMemory && hasObservationLogObserverMemory(memory)) {
333
- const cursor = await memory.getCursor(threadId);
334
- if (cursor) {
335
- return await memory.getMessagesForObservationScope(threadId, {
336
- since: {
337
- sinceCreatedAt: cursor.lastObservedAt,
338
- sinceMessageId: cursor.lastObservedMessageId,
339
- },
340
- });
341
- }
342
- }
343
- return await memory.getMessages(threadId, {
344
- resourceId,
345
- });
346
- }
347
- async initRun(input, options) {
348
- this.updateState({
349
- status: 'running',
350
- persistence: options?.persistence,
351
- });
352
- this.eventBus.emit({ type: "agent_start" });
353
- await this.ensureModelCost();
354
- const normalizedInput = (0, runtime_helpers_1.normalizeInput)(input);
355
- this.incrementMessageCount(options?.executionCounter);
356
- return await this.buildMessageList(normalizedInput, options);
357
- }
358
- finalizeGenerate(result, list) {
359
- result.runId = this.runId;
360
- result.usage = this.applyCost(result.usage);
361
- result.model = this.modelIdString;
362
- this.updateState({ status: 'success', messageList: list.serialize() });
363
- this.eventBus.emit({ type: "agent_end", messages: result.messages });
364
- return { ...result, getState: () => this.getState() };
365
- }
366
- resolveTelemetry(options) {
367
- if (this.config.telemetry)
368
- return this.config.telemetry;
369
- const inherited = options?.telemetry;
370
- if (!inherited)
371
- return undefined;
372
- return { ...inherited, functionId: this.config.name };
373
- }
374
- async flushTelemetry(options) {
375
- await telemetry_1.Telemetry.forceFlush(this.resolveTelemetry(options));
376
- }
377
- buildAiSdkOptions(toolMap, options) {
378
- return {
379
- ...this.buildTelemetryOptions(options),
380
- experimental_repairToolCall: async (options) => {
381
- return await (0, fix_tool_call_1.fixToolCall)({
382
- toolCall: options.toolCall,
383
- error: options.error,
384
- }, toolMap);
385
- },
386
- };
387
- }
388
- buildSmoothStreamTransformOptions(options) {
389
- if (options?.smoothStream === false)
390
- return {};
391
- const { smoothStream } = (0, lazy_ai_1.loadAi)();
392
- return { experimental_transform: smoothStream(options?.smoothStream ?? {}) };
393
- }
394
- buildTelemetryOptions(options) {
395
- const t = this.resolveTelemetry(options);
396
- if (!t?.enabled)
397
- return {};
398
- return {
399
- experimental_telemetry: {
400
- isEnabled: true,
401
- functionId: t.functionId ?? this.config.name,
402
- metadata: t.metadata,
403
- recordInputs: t.recordInputs,
404
- recordOutputs: t.recordOutputs,
405
- tracer: t.tracer,
406
- integrations: t.integrations.length > 0 ? t.integrations : undefined,
407
- },
408
- };
409
- }
410
- buildTelemetryRootAttributes(t, spanName, runId) {
411
- const metadataAttributes = this.buildTelemetryMetadataAttributes(t, 'langsmith.metadata');
412
- return {
413
- 'langsmith.traceable': 'true',
414
- 'langsmith.trace.name': spanName,
415
- 'langsmith.span.kind': 'chain',
416
- 'langsmith.metadata.agent_name': this.config.name,
417
- 'langsmith.metadata.agent_run_id': runId,
418
- ...metadataAttributes,
419
- ...buildAgentRootInputAttributes(this.config),
420
- };
421
- }
422
- buildTelemetryMetadataAttributes(t, prefix) {
423
- return Object.fromEntries(Object.entries(t.metadata ?? {}).map(([key, value]) => [`${prefix}.${key}`, value]));
424
- }
425
- buildAiSdkOperationAttributes(operationId, t) {
426
- const functionId = t.functionId ?? this.config.name;
427
- return {
428
- 'operation.name': `${operationId} ${functionId}`,
429
- 'resource.name': functionId,
430
- 'ai.operationId': operationId,
431
- 'ai.telemetry.functionId': functionId,
432
- ...this.buildTelemetryMetadataAttributes(t, 'ai.telemetry.metadata'),
433
- };
434
- }
435
- recordExecutionCounter(fn) {
436
- try {
437
- fn();
438
- }
439
- catch {
440
- }
441
- }
442
- incrementMessageCount(counter) {
443
- if (!counter)
444
- return;
445
- this.recordExecutionCounter(() => counter.incrementMessageCount());
446
- }
447
- incrementToolCallCount(counter) {
448
- if (!counter)
449
- return;
450
- this.recordExecutionCounter(() => counter.incrementToolCallCount());
451
- }
452
- incrementTokenCount(counter, usage) {
453
- (0, execution_counter_1.incrementTokenCountFromUsage)(counter, usage);
454
- }
455
- async withTelemetryRootSpan(operation, options, runId, fn) {
456
- const t = this.resolveTelemetry(options);
457
- if (!t?.enabled || t.runtimeRootSpanEnabled === false || !isActiveSpanTracer(t.tracer)) {
458
- return await fn();
459
- }
460
- const spanName = `${t.functionId ?? this.config.name}.${operation}`;
461
- return await t.tracer.startActiveSpan(spanName, { attributes: this.buildTelemetryRootAttributes(t, spanName, runId) }, async (span) => {
462
- try {
463
- return await fn();
464
- }
465
- catch (error) {
466
- span.recordException?.(error);
467
- span.setStatus?.({ code: 2, message: String(error) });
468
- throw error;
469
- }
470
- finally {
471
- span.end();
472
- }
473
- });
474
- }
475
- async withTelemetryToolSpan(toolCallId, toolName, input, t, fn) {
476
- if (!t?.enabled || !isActiveSpanTracer(t.tracer)) {
477
- return await fn();
478
- }
479
- const shouldRecordInputs = t.recordInputs ?? true;
480
- const inputValue = shouldRecordInputs ? stringifyTelemetryValue(input) : undefined;
481
- return await t.tracer.startActiveSpan('ai.toolCall', {
482
- attributes: {
483
- ...this.buildAiSdkOperationAttributes('ai.toolCall', t),
484
- 'ai.toolCall.name': toolName,
485
- 'ai.toolCall.id': toolCallId,
486
- ...(inputValue !== undefined ? { 'ai.toolCall.args': inputValue } : {}),
487
- },
488
- }, async (span) => {
489
- try {
490
- const result = await fn();
491
- const shouldRecordOutputs = t.recordOutputs ?? true;
492
- const outputValue = shouldRecordOutputs ? stringifyTelemetryValue(result) : undefined;
493
- if (outputValue !== undefined) {
494
- span.setAttributes?.({ 'ai.toolCall.result': outputValue });
495
- }
496
- return result;
497
- }
498
- catch (error) {
499
- span.recordException?.(error);
500
- span.setStatus?.({ code: 2, message: String(error) });
501
- throw error;
502
- }
503
- finally {
504
- span.end();
505
- }
506
- });
507
- }
508
- async runGenerateLoop(ctx) {
509
- const { list, options, abortScope, pendingResume } = ctx;
510
- this.hydrateDeferredToolsFromList(list);
511
- let totalUsage;
512
- let lastFinishReason = 'stop';
513
- let structuredOutput;
514
- const toolCallSummary = [];
515
- const runTelemetry = this.resolveTelemetry(options);
516
- const staticLoopContext = this.buildStaticLoopContext({
517
- ...options,
518
- persistence: options?.persistence,
519
- });
520
- const pendingLoopContext = this.buildToolLoopContext(staticLoopContext.aiProviderTools, options?.persistence, options?.executionCounter);
521
- const pendingToolCtx = {
522
- toolMap: pendingLoopContext.toolMap,
523
- list,
524
- runId: this.runId,
525
- persistence: options?.persistence,
526
- telemetry: runTelemetry,
527
- executionCounter: options?.executionCounter,
528
- abortSignal: abortScope.signal,
529
- isAborted: () => abortScope.isAborted,
530
- };
531
- const maxIterations = options?.maxIterations ?? MAX_LOOP_ITERATIONS;
532
- let iterationCount = options?.iterationCount ?? 0;
533
- let reachedStopCondition = false;
534
- if (pendingResume) {
535
- const batch = await this.iteratePendingToolCallsConcurrent({
536
- ...pendingToolCtx,
537
- pendingResume,
538
- });
539
- for (const r of batch.results) {
540
- toolCallSummary.push(r.toolEntry);
541
- }
542
- if (Object.keys(batch.pending).length > 0) {
543
- const suspendRunId = await this.persistSuspension(batch.pending, options, list, totalUsage, maxIterations, iterationCount);
544
- return {
545
- runId: suspendRunId,
546
- messages: list.responseDelta(),
547
- finishReason: 'tool-calls',
548
- usage: totalUsage,
549
- pendingSuspend: batch.suspensions.map((s) => ({
550
- runId: suspendRunId,
551
- toolCallId: s.toolCallId,
552
- toolName: s.toolName,
553
- input: s.input,
554
- suspendPayload: s.payload,
555
- resumeSchema: s.resumeSchema,
556
- })),
557
- getState: () => this.getState(),
558
- };
559
- }
560
- }
561
- const { generateText } = (0, lazy_ai_1.loadAi)();
562
- for (; iterationCount < maxIterations; iterationCount++) {
563
- if (abortScope.isAborted) {
564
- this.updateState({ status: 'cancelled' });
565
- throw new Error('Agent run was aborted');
566
- }
567
- this.eventBus.emit({ type: "turn_start" });
568
- const { toolMap, aiTools, hasTools, effectiveInstructions } = this.buildToolLoopContext(staticLoopContext.aiProviderTools, options?.persistence, options?.executionCounter);
569
- const { system, messages } = list.forLlm(effectiveInstructions, this.config.instructionProviderOptions);
570
- const result = await generateText({
571
- model: staticLoopContext.model,
572
- system,
573
- messages,
574
- abortSignal: abortScope.signal,
575
- ...(hasTools ? { tools: aiTools } : {}),
576
- ...(staticLoopContext.providerOptions
577
- ? { providerOptions: staticLoopContext.providerOptions }
578
- : {}),
579
- ...(staticLoopContext.outputSpec ? { output: staticLoopContext.outputSpec } : {}),
580
- ...this.buildAiSdkOptions(toolMap, options),
581
- });
582
- const aiFinishReason = result.finishReason;
583
- lastFinishReason = (0, messages_1.fromAiFinishReason)(aiFinishReason);
584
- totalUsage = (0, runtime_helpers_1.accumulateUsage)(totalUsage, result.usage);
585
- this.incrementTokenCount(options?.executionCounter, result.usage);
586
- const responseMessages = result.response.messages;
587
- const newMessages = (0, messages_1.fromAiMessages)(responseMessages);
588
- list.addResponse(newMessages);
589
- if (aiFinishReason !== 'tool-calls') {
590
- if (staticLoopContext.outputSpec) {
591
- structuredOutput = result.output;
592
- }
593
- this.emitTurnEnd(newMessages, (0, runtime_helpers_1.extractSettledToolCalls)(newMessages));
594
- reachedStopCondition = true;
595
- break;
596
- }
597
- const batch = await this.iterateToolCallsConcurrent({
598
- toolMap,
599
- list,
600
- runId: this.runId,
601
- persistence: options?.persistence,
602
- telemetry: runTelemetry,
603
- executionCounter: options?.executionCounter,
604
- abortSignal: abortScope.signal,
605
- isAborted: () => abortScope.isAborted,
606
- toolCalls: result.toolCalls,
607
- });
608
- for (const r of batch.results) {
609
- toolCallSummary.push(r.toolEntry);
610
- }
611
- if (Object.keys(batch.pending).length > 0) {
612
- const suspendRunId = await this.persistSuspension(batch.pending, options, list, totalUsage, maxIterations, iterationCount + 1);
613
- return {
614
- runId: suspendRunId,
615
- messages: list.responseDelta(),
616
- finishReason: 'tool-calls',
617
- usage: totalUsage,
618
- pendingSuspend: batch.suspensions.map((s) => ({
619
- runId: suspendRunId,
620
- toolCallId: s.toolCallId,
621
- toolName: s.toolName,
622
- input: s.input,
623
- suspendPayload: s.payload,
624
- resumeSchema: s.resumeSchema,
625
- })),
626
- getState: () => this.getState(),
627
- };
628
- }
629
- this.emitTurnEnd(newMessages, (0, runtime_helpers_1.extractSettledToolCalls)(list.responseDelta()));
630
- }
631
- if (!reachedStopCondition && iterationCount >= maxIterations) {
632
- lastFinishReason = 'max-iterations';
633
- }
634
- await this.saveToMemory(list, options);
635
- await this.flushTelemetry(options);
636
- if (this.config.titleGeneration && options?.persistence?.threadId && this.config.memory) {
637
- const titlePromise = (0, title_generation_1.generateThreadTitle)({
638
- memory: this.config.memory,
639
- threadId: options.persistence.threadId,
640
- resourceId: options.persistence.resourceId,
641
- titleConfig: this.config.titleGeneration,
642
- agentModel: this.config.model,
643
- turnDelta: list.turnDelta(),
644
- executionCounter: options.executionCounter,
645
- });
646
- this.backgroundTasks.track(titlePromise);
647
- if (this.config.titleGeneration.sync) {
648
- await titlePromise;
649
- }
650
- }
651
- return {
652
- runId: this.runId,
653
- messages: list.responseDelta(),
654
- finishReason: lastFinishReason,
655
- usage: totalUsage,
656
- ...(structuredOutput !== undefined && { structuredOutput }),
657
- ...(toolCallSummary.length > 0 && { toolCalls: toolCallSummary }),
658
- getState: () => this.getState(),
659
- };
660
- }
661
- startStreamLoop(ctx) {
662
- const { options } = ctx;
663
- const { readable, writable } = new TransformStream();
664
- const writer = writable.getWriter();
665
- const writeEventChunk = (chunk) => {
666
- writer.write(chunk).catch(() => { });
667
- };
668
- const onToolExecutionStart = (data) => {
669
- if (data.type !== "tool_execution_start")
670
- return;
671
- writeEventChunk({
672
- type: 'tool-execution-start',
673
- toolCallId: data.toolCallId,
674
- toolName: data.toolName,
675
- startTime: Date.now(),
676
- });
677
- };
678
- const onToolExecutionEnd = (data) => {
679
- if (data.type !== "tool_execution_end")
680
- return;
681
- writeEventChunk({
682
- type: 'tool-execution-end',
683
- toolCallId: data.toolCallId,
684
- toolName: data.toolName,
685
- isError: data.isError,
686
- endTime: Date.now(),
687
- });
688
- };
689
- const onSubAgentStarted = (data) => {
690
- if (data.type !== "subagent_started")
691
- return;
692
- const { type: _type, ...payload } = data;
693
- writeEventChunk({ type: 'subagent-started', ...payload });
694
- };
695
- const onSubAgentCompleted = (data) => {
696
- if (data.type !== "subagent_completed")
697
- return;
698
- const { type: _type, ...payload } = data;
699
- writeEventChunk({ type: 'subagent-completed', ...payload });
700
- };
701
- this.eventBus.on("tool_execution_start", onToolExecutionStart);
702
- this.eventBus.on("tool_execution_end", onToolExecutionEnd);
703
- this.eventBus.on("subagent_started", onSubAgentStarted);
704
- this.eventBus.on("subagent_completed", onSubAgentCompleted);
705
- this.withTelemetryRootSpan('stream', options, this.runId, async () => await this.runStreamLoop({ ...ctx, writer }))
706
- .catch(async (error) => {
707
- await this.flushTelemetry(options);
708
- await this.cleanupRun();
709
- const isAbort = ctx.abortScope.isAborted;
710
- this.updateState({ status: isAbort ? 'cancelled' : 'failed' });
711
- if (!isAbort) {
712
- this.eventBus.emit({ type: "error", message: String(error), error });
713
- }
714
- try {
715
- await writer.write({ type: 'error', error });
716
- await writer.write({ type: 'finish', finishReason: 'error' });
717
- await writer.close();
718
- }
719
- catch {
720
- writer.abort(error).catch(() => { });
721
- }
722
- })
723
- .finally(async () => {
724
- await writer.close().catch(() => { });
725
- this.eventBus.off("tool_execution_start", onToolExecutionStart);
726
- this.eventBus.off("tool_execution_end", onToolExecutionEnd);
727
- this.eventBus.off("subagent_started", onSubAgentStarted);
728
- this.eventBus.off("subagent_completed", onSubAgentCompleted);
729
- ctx.abortScope.dispose();
730
- });
731
- return readable;
732
- }
733
- async runStreamLoop(ctx) {
734
- const { list, options, abortScope, pendingResume, writer } = ctx;
735
- this.hydrateDeferredToolsFromList(list);
736
- const writeChunk = async (chunk) => {
737
- await writer.write(chunk);
738
- };
739
- let totalUsage;
740
- let lastFinishReason = 'stop';
741
- let structuredOutput;
742
- const maxIterations = options?.maxIterations ?? MAX_LOOP_ITERATIONS;
743
- let iterationCount = options?.iterationCount ?? 0;
744
- let reachedStopCondition = false;
745
- const { streamText } = (0, lazy_ai_1.loadAi)();
746
- const closeStreamWithError = async (error, status) => {
747
- await this.cleanupRun();
748
- this.updateState({ status });
749
- await writer.write({ type: 'error', error });
750
- await writer.write({ type: 'finish', finishReason: 'error' });
751
- await writer.close();
752
- };
753
- const handleAbort = async () => {
754
- if (!abortScope.isAborted)
755
- return false;
756
- await closeStreamWithError(new Error('Agent run was aborted'), 'cancelled');
757
- return true;
758
- };
759
- const runTelemetry = this.resolveTelemetry(options);
760
- const staticLoopContext = this.buildStaticLoopContext({
761
- ...options,
762
- persistence: options?.persistence,
763
- });
764
- const pendingLoopContext = this.buildToolLoopContext(staticLoopContext.aiProviderTools, options?.persistence, options?.executionCounter);
765
- const pendingToolCtx = {
766
- toolMap: pendingLoopContext.toolMap,
767
- list,
768
- runId: this.runId,
769
- persistence: options?.persistence,
770
- telemetry: runTelemetry,
771
- executionCounter: options?.executionCounter,
772
- abortSignal: abortScope.signal,
773
- isAborted: () => abortScope.isAborted,
774
- };
775
- if (pendingResume) {
776
- try {
777
- const batch = await this.iteratePendingToolCallsConcurrent({
778
- ...pendingToolCtx,
779
- pendingResume,
780
- });
781
- for (const r of batch.results) {
782
- await writer.write({
783
- type: 'tool-result',
784
- toolCallId: r.toolCallId,
785
- toolName: r.toolName,
786
- output: r.modelOutput,
787
- ...(r.toolEntry.canceled ? { canceled: true } : {}),
788
- });
789
- if (r.customMessage) {
790
- await writer.write({ type: 'message', message: r.customMessage });
791
- }
792
- }
793
- for (const e of batch.errors) {
794
- await writer.write({
795
- type: 'tool-result',
796
- toolCallId: e.toolCallId,
797
- toolName: e.toolName,
798
- output: e.error,
799
- isError: true,
800
- });
801
- }
802
- if (Object.keys(batch.pending).length > 0) {
803
- const suspendRunId = await this.persistSuspension(batch.pending, options, list, totalUsage, maxIterations, iterationCount);
804
- for (const s of batch.suspensions) {
805
- await writer.write({
806
- type: 'tool-call-suspended',
807
- runId: suspendRunId,
808
- toolCallId: s.toolCallId,
809
- toolName: s.toolName,
810
- input: s.input,
811
- suspendPayload: s.payload,
812
- resumeSchema: s.resumeSchema,
813
- });
814
- }
815
- await writer.write({ type: 'finish', finishReason: 'tool-calls' });
816
- await writer.close();
817
- return;
818
- }
819
- }
820
- catch (error) {
821
- this.eventBus.emit({ type: "error", message: String(error), error });
822
- await closeStreamWithError(error, 'failed');
823
- return;
824
- }
825
- }
826
- for (; iterationCount < maxIterations; iterationCount++) {
827
- if (await handleAbort())
828
- return;
829
- this.eventBus.emit({ type: "turn_start" });
830
- const { toolMap, aiTools, hasTools, effectiveInstructions } = this.buildToolLoopContext(staticLoopContext.aiProviderTools, options?.persistence, options?.executionCounter);
831
- const { system, messages } = list.forLlm(effectiveInstructions, this.config.instructionProviderOptions);
832
- const result = streamText({
833
- model: staticLoopContext.model,
834
- system,
835
- messages,
836
- abortSignal: abortScope.signal,
837
- ...(hasTools ? { tools: aiTools } : {}),
838
- ...(staticLoopContext.providerOptions
839
- ? { providerOptions: staticLoopContext.providerOptions }
840
- : {}),
841
- ...(staticLoopContext.outputSpec ? { output: staticLoopContext.outputSpec } : {}),
842
- ...this.buildAiSdkOptions(toolMap, options),
843
- ...this.buildSmoothStreamTransformOptions(options),
844
- });
845
- try {
846
- for await (const chunk of result.fullStream) {
847
- if (chunk.type === 'finish')
848
- continue;
849
- if ((chunk.type === 'tool-result' || chunk.type === 'tool-error') &&
850
- chunk.providerExecuted) {
851
- await writeChunk({
852
- type: 'tool-execution-end',
853
- toolCallId: chunk.toolCallId,
854
- toolName: chunk.toolName ?? '',
855
- isError: chunk.type === 'tool-error',
856
- endTime: Date.now(),
857
- });
858
- }
859
- const converted = (0, stream_1.convertChunk)(chunk);
860
- if (converted)
861
- await writeChunk(converted);
862
- if (chunk.type === 'tool-call' && chunk.providerExecuted) {
863
- await writeChunk({
864
- type: 'tool-execution-start',
865
- toolCallId: chunk.toolCallId,
866
- toolName: chunk.toolName ?? '',
867
- startTime: Date.now(),
868
- });
869
- }
870
- }
871
- }
872
- catch (streamError) {
873
- if (await handleAbort())
874
- return;
875
- this.eventBus.emit({
876
- type: "error",
877
- message: String(streamError),
878
- error: streamError,
879
- });
880
- await closeStreamWithError(streamError, 'failed');
881
- return;
882
- }
883
- if (await handleAbort())
884
- return;
885
- const aiFinishReason = await result.finishReason;
886
- const usage = await result.usage;
887
- const response = await result.response;
888
- lastFinishReason = (0, messages_1.fromAiFinishReason)(aiFinishReason);
889
- totalUsage = (0, runtime_helpers_1.accumulateUsage)(totalUsage, usage);
890
- this.incrementTokenCount(options?.executionCounter, usage);
891
- const responseMessages = response.messages;
892
- const newMessages = (0, messages_1.fromAiMessages)(responseMessages);
893
- list.addResponse(newMessages);
894
- if (aiFinishReason !== 'tool-calls') {
895
- if (staticLoopContext.outputSpec) {
896
- structuredOutput = await result.output;
897
- }
898
- this.emitTurnEnd(newMessages, (0, runtime_helpers_1.extractSettledToolCalls)(newMessages));
899
- reachedStopCondition = true;
900
- break;
901
- }
902
- const toolCalls = await result.toolCalls;
903
- try {
904
- const batch = await this.iterateToolCallsConcurrent({
905
- toolMap,
906
- list,
907
- runId: this.runId,
908
- persistence: options?.persistence,
909
- telemetry: runTelemetry,
910
- executionCounter: options?.executionCounter,
911
- abortSignal: abortScope.signal,
912
- isAborted: () => abortScope.isAborted,
913
- toolCalls,
914
- });
915
- if (await handleAbort())
916
- return;
917
- for (const r of batch.results) {
918
- await writer.write({
919
- type: 'tool-result',
920
- toolCallId: r.toolCallId,
921
- toolName: r.toolName,
922
- output: r.modelOutput,
923
- ...(r.toolEntry.canceled ? { canceled: true } : {}),
924
- });
925
- if (r.customMessage) {
926
- await writer.write({ type: 'message', message: r.customMessage });
927
- }
928
- }
929
- for (const e of batch.errors) {
930
- await writer.write({
931
- type: 'tool-result',
932
- toolCallId: e.toolCallId,
933
- toolName: e.toolName,
934
- output: e.error,
935
- isError: true,
936
- });
937
- }
938
- if (Object.keys(batch.pending).length > 0) {
939
- const suspendRunId = await this.persistSuspension(batch.pending, options, list, totalUsage, maxIterations, iterationCount + 1);
940
- for (const s of batch.suspensions) {
941
- await writer.write({
942
- type: 'tool-call-suspended',
943
- runId: suspendRunId,
944
- toolCallId: s.toolCallId,
945
- toolName: s.toolName,
946
- input: s.input,
947
- suspendPayload: s.payload,
948
- resumeSchema: s.resumeSchema,
949
- });
950
- }
951
- await writer.write({ type: 'finish', finishReason: 'tool-calls' });
952
- await writer.close();
953
- return;
954
- }
955
- }
956
- catch (error) {
957
- this.eventBus.emit({ type: "error", message: String(error), error });
958
- await closeStreamWithError(error, 'failed');
959
- return;
960
- }
961
- this.emitTurnEnd(newMessages, (0, runtime_helpers_1.extractSettledToolCalls)(list.responseDelta()));
962
- }
963
- if (!reachedStopCondition && iterationCount >= maxIterations) {
964
- lastFinishReason = 'max-iterations';
965
- }
966
- await this.saveToMemory(list, options);
967
- if (this.config.titleGeneration && options?.persistence && this.config.memory) {
968
- const titlePromise = (0, title_generation_1.generateThreadTitle)({
969
- memory: this.config.memory,
970
- threadId: options.persistence.threadId,
971
- resourceId: options.persistence.resourceId,
972
- titleConfig: this.config.titleGeneration,
973
- agentModel: this.config.model,
974
- turnDelta: list.turnDelta(),
975
- executionCounter: options.executionCounter,
976
- });
977
- this.backgroundTasks.track(titlePromise);
978
- if (this.config.titleGeneration.sync) {
979
- await titlePromise;
980
- }
981
- }
982
- await this.cleanupRun();
983
- await this.flushTelemetry(options);
984
- const costUsage = this.applyCost(totalUsage);
985
- await writer.write({
986
- type: 'finish',
987
- finishReason: lastFinishReason,
988
- ...(costUsage && { usage: costUsage }),
989
- model: this.modelIdString,
990
- ...(structuredOutput !== undefined && { structuredOutput }),
991
- });
992
- this.updateState({ status: 'success', messageList: list.serialize() });
993
- this.eventBus.emit({ type: "agent_end", messages: list.responseDelta() });
994
- await writer.close();
995
- }
996
- async saveToMemory(list, options) {
997
- if (!this.config.memory || !options?.persistence)
998
- return;
999
- const delta = list.turnDelta();
1000
- if (delta.length === 0)
1001
- return;
1002
- await (0, memory_store_1.saveMessagesToThread)(this.config.memory, options.persistence.threadId, options.persistence.resourceId, delta);
1003
- const observationTasks = this.scheduleObservationLogJobs(options.persistence, options.executionCounter);
1004
- this.scheduleEpisodicMemoryJob(options.persistence, observationTasks, options.executionCounter);
1005
- }
1006
- scheduleObservationLogJobs(persistence, executionCounter) {
1007
- const { memory, observationalMemory } = this.config;
1008
- if (!memory || !observationalMemory || !(0, observation_log_store_1.hasObservationLogStore)(memory))
1009
- return [];
1010
- const scope = this.getObservationLogScope(persistence);
1011
- const runner = this.getMemoryTaskRunner(memory, observationalMemory.lockTtlMs);
1012
- const observe = observationalMemory.observe;
1013
- const observerThresholdTokens = observationalMemory.observerThresholdTokens;
1014
- const tasks = [];
1015
- if (observe &&
1016
- observerThresholdTokens !== undefined &&
1017
- hasObservationLogObserverMemory(memory)) {
1018
- tasks.push(this.scheduleMemoryTask(runner, scope, 'observer', async () => await (0, observation_log_observer_1.runObservationLogObserver)({
1019
- memory,
1020
- ...scope,
1021
- observerThresholdTokens,
1022
- observationLogTailLimit: observationalMemory.observationLogTailLimit ?? 0,
1023
- observe,
1024
- executionCounter,
1025
- })));
1026
- }
1027
- const reflect = observationalMemory.reflect;
1028
- const reflectorThresholdTokens = observationalMemory.reflectorThresholdTokens;
1029
- if (reflect && reflectorThresholdTokens !== undefined) {
1030
- tasks.push(this.scheduleMemoryTask(runner, scope, 'reflector', async () => await (0, observation_log_reflector_1.runObservationLogReflector)({
1031
- memory,
1032
- ...scope,
1033
- reflectorThresholdTokens,
1034
- reflect,
1035
- executionCounter,
1036
- })));
1037
- }
1038
- return tasks;
1039
- }
1040
- scheduleEpisodicMemoryJob(persistence, observationTasks, executionCounter) {
1041
- const { memory, episodicMemory } = this.config;
1042
- if (!memory ||
1043
- !episodicMemory ||
1044
- !(0, episodic_memory_1.isEpisodicMemoryEnabled)(episodicMemory) ||
1045
- !(0, episodic_memory_1.hasEpisodicMemoryStore)(memory) ||
1046
- !(0, observation_log_store_1.hasObservationLogStore)(memory) ||
1047
- !episodicMemory.extract) {
1048
- return;
1049
- }
1050
- const scope = (0, episodic_memory_1.getEpisodicMemoryScope)(persistence);
1051
- if (!scope)
1052
- return;
1053
- const observationScope = this.getObservationLogScope(persistence);
1054
- this.scheduleEpisodicMemoryTask(memory, scope.resourceId, async () => {
1055
- await Promise.allSettled(observationTasks);
1056
- await (0, episodic_memory_1.runEpisodicMemoryIndexer)({
1057
- memory,
1058
- config: episodicMemory,
1059
- scope,
1060
- observationScope,
1061
- threadId: persistence.threadId,
1062
- executionCounter,
1063
- });
1064
- });
1065
- }
1066
- scheduleEpisodicMemoryTask(memory, resourceId, task) {
1067
- const id = crypto.randomUUID();
1068
- const previous = this.episodicMemoryTasksByResource.get(resourceId) ?? Promise.resolve();
1069
- const done = previous
1070
- .catch(() => undefined)
1071
- .then(async () => await this.runEpisodicMemoryTask(memory, resourceId, id, task));
1072
- const queued = done.finally(() => {
1073
- if (this.episodicMemoryTasksByResource.get(resourceId) === queued) {
1074
- this.episodicMemoryTasksByResource.delete(resourceId);
1075
- }
1076
- });
1077
- this.episodicMemoryTasksByResource.set(resourceId, queued);
1078
- this.backgroundTasks.track(queued);
1079
- }
1080
- async runEpisodicMemoryTask(memory, resourceId, holderId, task) {
1081
- const taskLock = memory.episodic?.taskLock;
1082
- let lock = null;
1083
- try {
1084
- if (taskLock) {
1085
- lock = await taskLock.acquire(resourceId, {
1086
- holderId,
1087
- ttlMs: this.config.observationalMemory?.lockTtlMs ?? DEFAULT_MEMORY_TASK_LOCK_TTL_MS,
1088
- });
1089
- if (!lock)
1090
- return;
1091
- }
1092
- await task();
1093
- }
1094
- catch (error) {
1095
- const message = 'Episodic memory indexing task failed';
1096
- logger.warn(message, { error, resourceId });
1097
- this.eventBus.emit({ type: "error", message, error, source: 'episodic-memory' });
1098
- }
1099
- finally {
1100
- if (lock) {
1101
- await this.releaseEpisodicMemoryTaskLock(taskLock, lock, resourceId);
1102
- }
1103
- }
1104
- }
1105
- async releaseEpisodicMemoryTaskLock(taskLock, lock, resourceId) {
1106
- try {
1107
- await taskLock?.release(lock);
1108
- }
1109
- catch (error) {
1110
- logger.warn('Episodic memory indexing lock release failed', { error, resourceId });
1111
- }
1112
- }
1113
- async scheduleMemoryTask(runner, scope, taskKind, task) {
1114
- return await runner.schedule({ ...scope, taskKind }, task).done;
1115
- }
1116
- getMemoryTaskRunner(memory, lockTtlMs) {
1117
- this.memoryTasks ??= new scoped_memory_task_runner_1.ScopedMemoryTaskRunner({
1118
- tracker: this.backgroundTasks,
1119
- lockStore: (0, observation_log_store_1.hasObservationLogTaskLockStore)(memory) ? memory : undefined,
1120
- lockTtlMs,
1121
- onEvent: (event) => {
1122
- if (event.type !== 'failed')
1123
- return;
1124
- const source = event.task.taskKind;
1125
- const message = `Observation log ${source} task failed`;
1126
- logger.warn(message, {
1127
- error: event.error,
1128
- observationScopeId: event.task.observationScopeId,
1129
- });
1130
- this.eventBus.emit({ type: "error", message, error: event.error, source });
1131
- },
1132
- });
1133
- return this.memoryTasks;
1134
- }
1135
- getObservationLogScope(persistence) {
1136
- return {
1137
- observationScopeId: persistence.threadId,
1138
- };
1139
- }
1140
- buildThinkingProviderOptions() {
1141
- if (!this.config.thinking)
1142
- return undefined;
1143
- const provider = this.modelIdString.split('/')[0];
1144
- const thinking = this.config.thinking;
1145
- switch (provider) {
1146
- case 'anthropic': {
1147
- const cfg = thinking;
1148
- if (cfg.mode === 'adaptive') {
1149
- return { anthropic: { thinking: { type: 'adaptive' } } };
1150
- }
1151
- return {
1152
- anthropic: {
1153
- thinking: { type: 'enabled', budgetTokens: cfg.budgetTokens ?? 10000 },
1154
- },
1155
- };
1156
- }
1157
- case 'openai': {
1158
- const cfg = thinking;
1159
- return { openai: { reasoningEffort: cfg.reasoningEffort ?? 'medium' } };
1160
- }
1161
- case 'google': {
1162
- const cfg = thinking;
1163
- return {
1164
- google: {
1165
- thinkingConfig: {
1166
- ...(cfg.thinkingBudget !== undefined && { thinkingBudget: cfg.thinkingBudget }),
1167
- ...(cfg.thinkingLevel !== undefined && { thinkingLevel: cfg.thinkingLevel }),
1168
- },
1169
- },
1170
- };
1171
- }
1172
- case 'xai': {
1173
- const cfg = thinking;
1174
- return { xai: { reasoningEffort: cfg.reasoningEffort ?? 'high' } };
1175
- }
1176
- default:
1177
- return undefined;
1178
- }
1179
- }
1180
- buildCallProviderOptions(runProviderOptions) {
1181
- const thinkingOpts = this.buildThinkingProviderOptions();
1182
- if (!thinkingOpts && !runProviderOptions)
1183
- return undefined;
1184
- if (!thinkingOpts)
1185
- return runProviderOptions;
1186
- if (!runProviderOptions)
1187
- return thinkingOpts;
1188
- const merged = { ...thinkingOpts };
1189
- for (const [provider, opts] of Object.entries(runProviderOptions)) {
1190
- if (provider in merged) {
1191
- merged[provider] = { ...merged[provider], ...opts };
1192
- }
1193
- else {
1194
- merged[provider] = opts;
1195
- }
1196
- }
1197
- return merged;
1198
- }
1199
- isDelegateSubAgentCall(toolName) {
1200
- return toolName === delegate_sub_agent_tool_1.DELEGATE_SUB_AGENT_TOOL_NAME;
1201
- }
1202
- getToolCallBatchSize(toolName, toolMap) {
1203
- if (!this.isDelegateSubAgentCall(toolName))
1204
- return this.concurrency;
1205
- const tool = toolMap.get(toolName);
1206
- const delegateOptions = tool ? (0, delegate_sub_agent_tool_1.getInlineDelegateSubAgentToolOptions)(tool) : undefined;
1207
- return delegateOptions?.policy?.maxChildren ?? sub_agent_task_path_1.DEFAULT_SUB_AGENT_MAX_CHILDREN;
1208
- }
1209
- takeNextToolCallBatch(calls, start, toolMap) {
1210
- const first = calls[start];
1211
- if (!first) {
1212
- throw new Error('Unable to build tool-call batch');
1213
- }
1214
- const isDelegateBatch = this.isDelegateSubAgentCall(first.toolName);
1215
- const batchSize = this.getToolCallBatchSize(first.toolName, toolMap);
1216
- if (batchSize < 1 ||
1217
- Number.isNaN(batchSize) ||
1218
- (isDelegateBatch && !Number.isFinite(batchSize))) {
1219
- throw new Error(`Invalid tool-call batch size for ${first.toolName}: ${batchSize}`);
1220
- }
1221
- const batch = [];
1222
- for (let i = start; i < calls.length && batch.length < batchSize; i++) {
1223
- const candidate = calls[i];
1224
- if (this.isDelegateSubAgentCall(candidate.toolName) !== isDelegateBatch)
1225
- break;
1226
- batch.push(candidate);
1227
- }
1228
- return batch;
1229
- }
1230
- async iterateToolCallsConcurrent(ctx) {
1231
- const { toolCalls, toolMap, list, runId, telemetry: resolvedTelemetry, executionCounter, abortSignal, } = ctx;
1232
- const executableCalls = toolCalls.filter((tc) => !tc.providerExecuted);
1233
- const providerExecutedCount = toolCalls.length - executableCalls.length;
1234
- for (let i = 0; i < providerExecutedCount; i++) {
1235
- this.incrementToolCallCount(executionCounter);
1236
- }
1237
- const executableCallsById = new Map(executableCalls.map((tc) => [tc.toolCallId, tc]));
1238
- const unexecutedIds = new Set(executableCalls.map((tc) => tc.toolCallId));
1239
- const results = [];
1240
- const suspensions = [];
1241
- const errors = [];
1242
- const pending = {};
1243
- for (let batchStart = 0; batchStart < executableCalls.length;) {
1244
- if (ctx.isAborted()) {
1245
- this.updateState({ status: 'cancelled' });
1246
- throw new Error('Agent run was aborted');
1247
- }
1248
- const batch = this.takeNextToolCallBatch(executableCalls, batchStart, toolMap);
1249
- batchStart += batch.length;
1250
- const settledResults = await Promise.allSettled(batch.map(async (tc) => await this.processToolCall(tc.toolCallId, tc.toolName, tc.input, toolMap, list, runId, ctx.persistence, undefined, resolvedTelemetry, executionCounter, abortSignal, true)));
1251
- for (const tc of batch) {
1252
- unexecutedIds.delete(tc.toolCallId);
1253
- }
1254
- let hasSuspension = false;
1255
- for (let i = 0; i < settledResults.length; i++) {
1256
- const result = settledResults[i];
1257
- const tc = batch[i];
1258
- const toolInput = tc.input;
1259
- if (result.status === 'rejected') {
1260
- list.setToolCallError(tc.toolCallId, result.reason);
1261
- errors.push({
1262
- toolCallId: tc.toolCallId,
1263
- toolName: tc.toolName,
1264
- input: toolInput,
1265
- error: result.reason,
1266
- });
1267
- }
1268
- else if (result.value.outcome === 'suspended') {
1269
- hasSuspension = true;
1270
- suspensions.push({
1271
- toolCallId: tc.toolCallId,
1272
- toolName: tc.toolName,
1273
- input: toolInput,
1274
- payload: result.value.payload,
1275
- resumeSchema: result.value.resumeSchema,
1276
- });
1277
- pending[tc.toolCallId] = {
1278
- suspended: true,
1279
- toolCallId: tc.toolCallId,
1280
- toolName: tc.toolName,
1281
- input: toolInput,
1282
- suspendPayload: result.value.payload,
1283
- resumeSchema: result.value.resumeSchema,
1284
- runId,
1285
- };
1286
- }
1287
- else if (result.value.outcome === 'success') {
1288
- results.push({
1289
- toolCallId: tc.toolCallId,
1290
- toolName: tc.toolName,
1291
- input: toolInput,
1292
- toolEntry: result.value.toolEntry,
1293
- modelOutput: result.value.modelOutput,
1294
- customMessage: result.value.customMessage,
1295
- });
1296
- }
1297
- else if (result.value.outcome === 'error') {
1298
- errors.push({
1299
- toolCallId: tc.toolCallId,
1300
- toolName: tc.toolName,
1301
- input: toolInput,
1302
- error: result.value.error,
1303
- });
1304
- }
1305
- else if (result.value.outcome === 'noop') {
1306
- }
1307
- }
1308
- if (hasSuspension) {
1309
- for (const id of unexecutedIds) {
1310
- const tc = executableCallsById.get(id);
1311
- pending[tc.toolCallId] = {
1312
- suspended: false,
1313
- toolCallId: tc.toolCallId,
1314
- toolName: tc.toolName,
1315
- input: tc.input,
1316
- };
1317
- }
1318
- break;
1319
- }
1320
- }
1321
- return { results, suspensions, errors, pending };
1322
- }
1323
- async iteratePendingToolCallsConcurrent(ctx) {
1324
- const { pendingResume, toolMap, list, runId, persistence, telemetry: resolvedTelemetry, executionCounter, abortSignal, } = ctx;
1325
- const resumedId = pendingResume.resumeToolCallId;
1326
- const resumedEntry = pendingResume.pendingToolCalls[resumedId];
1327
- if (!resumedEntry) {
1328
- throw new Error(`No pending tool call found for toolCallId: ${resumedId}`);
1329
- }
1330
- const resumedToolName = resumedEntry.toolName;
1331
- const results = [];
1332
- const suspensions = [];
1333
- const errors = [];
1334
- const pending = {};
1335
- let processResult;
1336
- try {
1337
- processResult = await this.processToolCall(resumedEntry.toolCallId, resumedToolName, resumedEntry.input, toolMap, list, runId, persistence, pendingResume.resumeData, resolvedTelemetry, executionCounter, abortSignal, false);
1338
- }
1339
- catch (error) {
1340
- processResult = { outcome: 'error', error };
1341
- list.setToolCallError(resumedEntry.toolCallId, error);
1342
- }
1343
- if (processResult.outcome === 'suspended') {
1344
- pending[resumedId] = {
1345
- ...resumedEntry,
1346
- suspended: true,
1347
- suspendPayload: processResult.payload,
1348
- resumeSchema: processResult.resumeSchema,
1349
- runId,
1350
- };
1351
- suspensions.push({
1352
- toolCallId: resumedId,
1353
- toolName: resumedToolName,
1354
- input: resumedEntry.input,
1355
- payload: processResult.payload,
1356
- resumeSchema: processResult.resumeSchema,
1357
- });
1358
- }
1359
- else if (processResult.outcome === 'success') {
1360
- results.push({
1361
- toolCallId: resumedEntry.toolCallId,
1362
- toolName: resumedToolName,
1363
- input: resumedEntry.input,
1364
- toolEntry: processResult.toolEntry,
1365
- modelOutput: processResult.modelOutput,
1366
- customMessage: processResult.customMessage,
1367
- });
1368
- }
1369
- else if (processResult.outcome === 'cancelled') {
1370
- results.push({
1371
- toolCallId: resumedEntry.toolCallId,
1372
- toolName: resumedToolName,
1373
- input: resumedEntry.input,
1374
- toolEntry: processResult.toolEntry,
1375
- modelOutput: processResult.modelOutput,
1376
- });
1377
- list.addInput([
1378
- { role: 'user', content: [{ type: 'text', text: processResult.userMessage }] },
1379
- ]);
1380
- for (const id of Object.keys(pendingResume.pendingToolCalls)) {
1381
- if (id !== resumedId) {
1382
- const siblingEntry = pendingResume.pendingToolCalls[id];
1383
- const modelOutput = '[Skipped: a sibling tool call was cancelled]';
1384
- list.setToolCallResult(id, modelOutput, {
1385
- canceled: true,
1386
- });
1387
- results.push({
1388
- toolCallId: siblingEntry.toolCallId,
1389
- toolName: siblingEntry.toolName,
1390
- input: siblingEntry.input,
1391
- toolEntry: {
1392
- tool: siblingEntry.toolName,
1393
- input: siblingEntry.input,
1394
- output: modelOutput,
1395
- transformed: false,
1396
- canceled: true,
1397
- },
1398
- modelOutput,
1399
- });
1400
- }
1401
- }
1402
- return { results, suspensions, errors, pending };
1403
- }
1404
- else if (processResult.outcome === 'error') {
1405
- errors.push({
1406
- toolCallId: resumedEntry.toolCallId,
1407
- toolName: resumedToolName,
1408
- input: resumedEntry.input,
1409
- error: processResult.error,
1410
- });
1411
- }
1412
- else if (processResult.outcome === 'noop') {
1413
- }
1414
- const unexecuted = [];
1415
- for (const [id, entry] of Object.entries(pendingResume.pendingToolCalls)) {
1416
- if (id === resumedId)
1417
- continue;
1418
- const entryToolName = entry.toolName;
1419
- if (entry.suspended) {
1420
- pending[id] = entry;
1421
- suspensions.push({
1422
- toolCallId: id,
1423
- toolName: entryToolName,
1424
- input: entry.input,
1425
- payload: entry.suspendPayload,
1426
- resumeSchema: entry.resumeSchema,
1427
- });
1428
- }
1429
- else {
1430
- unexecuted.push({
1431
- toolCallId: id,
1432
- toolName: entryToolName,
1433
- input: entry.input,
1434
- });
1435
- }
1436
- }
1437
- if (unexecuted.length > 0) {
1438
- const batch = await this.iterateToolCallsConcurrent({
1439
- toolCalls: unexecuted,
1440
- toolMap,
1441
- list,
1442
- runId,
1443
- persistence,
1444
- telemetry: resolvedTelemetry,
1445
- executionCounter,
1446
- abortSignal,
1447
- isAborted: ctx.isAborted,
1448
- });
1449
- results.push(...batch.results);
1450
- suspensions.push(...batch.suspensions);
1451
- errors.push(...batch.errors);
1452
- Object.assign(pending, batch.pending);
1453
- }
1454
- return { results, suspensions, errors, pending };
1455
- }
1456
- async processToolCall(toolCallId, toolName, toolInput, toolMap, list, runId, persistence, resumeData, resolvedTelemetry, executionCounter, abortSignal, countToolCall = true) {
1457
- const builtTool = toolMap.get(toolName);
1458
- const makeToolError = (error) => {
1459
- this.eventBus.emit({
1460
- type: "tool_execution_end",
1461
- toolCallId,
1462
- toolName,
1463
- result: error,
1464
- isError: true,
1465
- });
1466
- list.setToolCallError(toolCallId, error);
1467
- return { outcome: 'error', error };
1468
- };
1469
- if (!builtTool) {
1470
- return makeToolError(new Error(`Tool ${toolName} not found`));
1471
- }
1472
- const settledBlock = list
1473
- .responseDelta()
1474
- .flatMap((m) => ((0, message_1.isLlmMessage)(m) && 'content' in m ? m.content : []))
1475
- .find((c) => c.type === 'tool-call' && c.toolCallId === toolCallId && c.state !== 'pending');
1476
- if (settledBlock) {
1477
- let settledResult;
1478
- if (settledBlock.state === 'resolved') {
1479
- settledResult = settledBlock.output;
1480
- }
1481
- else {
1482
- settledResult = settledBlock.error;
1483
- }
1484
- this.eventBus.emit({
1485
- type: "tool_execution_end",
1486
- toolCallId,
1487
- toolName,
1488
- result: settledResult,
1489
- isError: settledBlock.state === 'rejected',
1490
- });
1491
- return { outcome: 'noop' };
1492
- }
1493
- if ((0, cancellation_1.isCancellation)(resumeData) && !builtTool.handleCancellation) {
1494
- const modelOutput = `[Tool call cancelled. User said: "${resumeData.message}"]`;
1495
- this.eventBus.emit({
1496
- type: "tool_execution_end",
1497
- toolCallId,
1498
- toolName,
1499
- result: modelOutput,
1500
- isError: false,
1501
- });
1502
- list.setToolCallResult(toolCallId, modelOutput, { canceled: true });
1503
- return {
1504
- outcome: 'cancelled',
1505
- toolEntry: {
1506
- tool: toolName,
1507
- input: toolInput,
1508
- output: modelOutput,
1509
- transformed: false,
1510
- canceled: true,
1511
- },
1512
- modelOutput,
1513
- userMessage: resumeData.message,
1514
- canceled: true,
1515
- };
1516
- }
1517
- if (countToolCall) {
1518
- this.incrementToolCallCount(executionCounter);
1519
- }
1520
- if (builtTool.inputSchema) {
1521
- const result = await (0, parse_1.parseWithSchema)(builtTool.inputSchema, toolInput);
1522
- if (!result.success) {
1523
- return makeToolError(new Error(`Invalid tool input: ${result.error}`));
1524
- }
1525
- toolInput = result.data;
1526
- }
1527
- if (shouldEmitToolExecutionStart(builtTool, resumeData)) {
1528
- this.eventBus.emit({
1529
- type: "tool_execution_start",
1530
- toolCallId,
1531
- toolName,
1532
- args: toolInput,
1533
- });
1534
- }
1535
- let toolResult;
1536
- try {
1537
- toolResult = await this.withTelemetryToolSpan(toolCallId, toolName, toolInput, resolvedTelemetry, async () => await (0, tool_adapter_1.executeTool)(toolInput, builtTool, resumeData, resolvedTelemetry, toolCallId, {
1538
- runId,
1539
- persistence,
1540
- emitEvent: (event) => this.eventBus.emit(event),
1541
- abortSignal,
1542
- executionCounter,
1543
- }));
1544
- }
1545
- catch (error) {
1546
- return makeToolError(error);
1547
- }
1548
- if ((0, tool_adapter_1.isSuspendedToolResult)(toolResult)) {
1549
- if (builtTool?.suspendSchema) {
1550
- const parseResult = await (0, parse_1.parseWithSchema)(builtTool.suspendSchema, toolResult.payload);
1551
- if (!parseResult.success) {
1552
- return makeToolError(new Error(`Invalid suspend payload: ${parseResult.error}`));
1553
- }
1554
- toolResult.payload = parseResult.data;
1555
- }
1556
- if (!builtTool?.resumeSchema) {
1557
- const error = new Error(`Tool ${toolName} has no resume schema`);
1558
- return makeToolError(error);
1559
- }
1560
- const resumeSchema = getToolResumeJsonSchema(builtTool);
1561
- if (!resumeSchema) {
1562
- return makeToolError(new Error('Invalid resume schema'));
1563
- }
1564
- return {
1565
- outcome: 'suspended',
1566
- payload: toolResult.payload,
1567
- resumeSchema,
1568
- };
1569
- }
1570
- let modelResult;
1571
- try {
1572
- modelResult = builtTool.toModelOutput ? builtTool.toModelOutput(toolResult) : toolResult;
1573
- }
1574
- catch (error) {
1575
- return makeToolError(error);
1576
- }
1577
- this.eventBus.emit({
1578
- type: "tool_execution_end",
1579
- toolCallId,
1580
- toolName,
1581
- result: toolResult,
1582
- isError: false,
1583
- });
1584
- list.setToolCallResult(toolCallId, (0, json_value_1.toJsonValue)(modelResult));
1585
- const customMessage = builtTool?.toMessage?.(toolResult);
1586
- if (customMessage) {
1587
- list.addResponse([customMessage]);
1588
- }
1589
- return {
1590
- outcome: 'success',
1591
- toolEntry: {
1592
- tool: toolName,
1593
- input: toolInput,
1594
- output: toolResult,
1595
- transformed: !!builtTool.toModelOutput,
1596
- },
1597
- modelOutput: modelResult,
1598
- customMessage,
1599
- };
1600
- }
1601
- buildStaticLoopContext(execOptions) {
1602
- const { Output, jsonSchema } = getAiSdk();
1603
- const aiProviderTools = (0, tool_adapter_1.toAiSdkProviderTools)(this.config.providerTools);
1604
- const model = (0, model_factory_1.createModel)(this.config.model);
1605
- const outputSchema = this.config.structuredOutput;
1606
- const isRawJsonSchemaOutput = outputSchema !== undefined && !(0, zod_1.isZodSchema)(outputSchema);
1607
- const providerOptions = this.relaxStrictJsonSchemaIfNeeded(this.buildCallProviderOptions(execOptions?.providerOptions), isRawJsonSchemaOutput);
1608
- const outputSpec = outputSchema
1609
- ? Output.object({
1610
- schema: (0, zod_1.isZodSchema)(outputSchema)
1611
- ? outputSchema
1612
- : jsonSchema((0, json_schema_1.lockAdditionalProperties)(outputSchema)),
1613
- })
1614
- : undefined;
1615
- return {
1616
- model,
1617
- aiProviderTools,
1618
- providerOptions,
1619
- outputSpec,
1620
- };
1621
- }
1622
- relaxStrictJsonSchemaIfNeeded(providerOptions, isRawJsonSchemaOutput) {
1623
- if (!isRawJsonSchemaOutput)
1624
- return providerOptions;
1625
- const result = { ...providerOptions };
1626
- for (const provider of ['openai', 'groq']) {
1627
- result[provider] = { strictJsonSchema: false, ...result[provider] };
1628
- }
1629
- return result;
1630
- }
1631
- buildToolLoopContext(aiProviderTools, persistence, executionCounter) {
1632
- const allUserTools = this.getCurrentTools(persistence, executionCounter);
1633
- const aiTools = (0, tool_adapter_1.toAiSdkTools)(allUserTools);
1634
- const allTools = { ...aiTools, ...aiProviderTools };
1635
- const aiToolCount = Object.keys(allTools).length;
1636
- const toolMap = (0, tool_adapter_1.buildToolMap)(allUserTools);
1637
- const effectiveInstructions = this.composeEffectiveInstructions(allUserTools);
1638
- return {
1639
- toolMap,
1640
- aiTools: allTools,
1641
- hasTools: aiToolCount > 0,
1642
- effectiveInstructions,
1643
- };
1644
- }
1645
- getCurrentTools(persistence, executionCounter) {
1646
- const baseTools = this.config.tools ?? [];
1647
- const tools = [
1648
- ...baseTools,
1649
- ...(this.deferredToolManager?.hasTools
1650
- ? [
1651
- ...this.deferredToolManager.getControllerTools(),
1652
- ...this.deferredToolManager.getLoadedTools(),
1653
- ]
1654
- : []),
1655
- ];
1656
- const recallTool = this.createRecallMemoryToolForRun(persistence, tools, executionCounter);
1657
- return recallTool ? [...tools, recallTool] : tools;
1658
- }
1659
- createRecallMemoryToolForRun(persistence, existingTools, executionCounter) {
1660
- const { memory, episodicMemory } = this.config;
1661
- if (!memory ||
1662
- !episodicMemory ||
1663
- !(0, episodic_memory_1.isEpisodicMemoryEnabled)(episodicMemory) ||
1664
- !(0, episodic_memory_1.hasEpisodicMemoryStore)(memory)) {
1665
- return undefined;
1666
- }
1667
- const scope = (0, episodic_memory_1.getEpisodicMemoryScope)(persistence);
1668
- if (!scope)
1669
- return undefined;
1670
- if (existingTools.some((tool) => tool.name === episodic_memory_1.RECALL_MEMORY_TOOL_NAME)) {
1671
- throw new Error(`Tool name "${episodic_memory_1.RECALL_MEMORY_TOOL_NAME}" is reserved while episodic memory is enabled.`);
1672
- }
1673
- return (0, episodic_memory_1.createRecallMemoryTool)({ memory, config: episodicMemory, scope, executionCounter });
1674
- }
1675
- hydrateDeferredToolsFromList(list) {
1676
- if (!this.deferredToolManager?.hasTools)
1677
- return;
1678
- this.deferredToolManager.hydrateLoadedToolsFromMessages(list.serialize().messages);
1679
- }
1680
- composeEffectiveInstructions(tools) {
1681
- const fragments = tools
1682
- .map((t) => t.systemInstruction)
1683
- .filter((s) => typeof s === 'string' && s.trim().length > 0);
1684
- const userInstructions = this.config.instructions;
1685
- if (fragments.length === 0)
1686
- return userInstructions;
1687
- const block = `<built_in_rules>\n${fragments.map((f) => `- ${f}`).join('\n')}\n</built_in_rules>`;
1688
- return userInstructions ? `${block}\n\n${userInstructions}` : block;
1689
- }
1690
- async persistSuspension(pendingToolCalls, options, list, totalUsage, maxIterations, iterationCount) {
1691
- const resolvedMaxIterations = maxIterations ?? options?.maxIterations;
1692
- const resolvedIterationCount = iterationCount ?? options?.iterationCount;
1693
- const executionOptions = resolvedMaxIterations !== undefined ? { maxIterations: resolvedMaxIterations } : undefined;
1694
- const state = {
1695
- persistence: options?.persistence,
1696
- status: 'suspended',
1697
- messageList: list.serialize(),
1698
- pendingToolCalls,
1699
- usage: totalUsage,
1700
- executionOptions,
1701
- ...(resolvedIterationCount !== undefined ? { iterationCount: resolvedIterationCount } : {}),
1702
- };
1703
- await this.runState.suspend(this.runId, state);
1704
- this.updateState({ status: 'suspended', pendingToolCalls, messageList: list.serialize() });
1705
- return this.runId;
1706
- }
1707
- async cleanupRun() {
1708
- await this.runState.complete(this.runId);
1709
- }
1710
- emitTurnEnd(newMessages, toolResults) {
1711
- const assistantMsg = newMessages.find((m) => 'role' in m && m.role === 'assistant');
1712
- if (assistantMsg) {
1713
- this.eventBus.emit({ type: "turn_end", message: assistantMsg, toolResults });
1714
- }
1715
- }
1716
- updateState(patch) {
1717
- this.currentState = { ...this.currentState, ...patch };
1718
- }
1719
- get modelIdString() {
1720
- const m = this.config.model;
1721
- if (typeof m === 'string')
1722
- return m;
1723
- if ('id' in m && typeof m.id === 'string')
1724
- return m.id;
1725
- if ('modelId' in m && typeof m.modelId === 'string') {
1726
- const provider = 'provider' in m ? String(m.provider) : 'unknown';
1727
- return `${provider}/${m.modelId}`;
1728
- }
1729
- return 'unknown';
1730
- }
1731
- get concurrency() {
1732
- return this.config.toolCallConcurrency ?? 1;
1733
- }
1734
- async ensureModelCost() {
1735
- if (this.modelCost)
1736
- return this.modelCost;
1737
- try {
1738
- this.modelCost = await (0, catalog_1.getModelCost)(this.modelIdString);
1739
- }
1740
- catch {
1741
- }
1742
- return this.modelCost;
1743
- }
1744
- applyCost(usage) {
1745
- if (!usage || !this.modelCost)
1746
- return usage;
1747
- return { ...usage, cost: (0, catalog_1.computeCost)(usage, this.modelCost) };
1748
- }
1749
- async setListObservationLogMemory(list, options) {
1750
- const memory = this.config.memory;
1751
- if (!memory || !options?.threadId || !(0, observation_log_store_1.hasObservationLogStore)(memory))
1752
- return;
1753
- const scope = this.getObservationLogScope(options);
1754
- const observations = await memory.getActiveObservationLog({
1755
- ...scope,
1756
- order: 'asc',
1757
- });
1758
- list.observationLogMemory =
1759
- (0, observation_log_renderer_1.renderObservationLog)(observations, {
1760
- renderTokenBudget: this.config.observationLog?.renderTokenBudget,
1761
- }) ?? undefined;
1762
- if (observations.length > 0) {
1763
- list.seedLastCreatedAt(observations[observations.length - 1].createdAt.getTime());
1764
- }
1765
- }
1766
- getConfiguredTelemetry() {
1767
- return this.config.telemetry;
1768
- }
1769
- }
1770
- exports.AgentRuntime = AgentRuntime;
1771
- //# sourceMappingURL=agent-runtime.js.map