@openai/agents-core 0.5.3 → 0.6.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 (112) hide show
  1. package/dist/computer.d.ts +10 -2
  2. package/dist/events.d.ts +1 -1
  3. package/dist/events.js.map +1 -1
  4. package/dist/events.mjs.map +1 -1
  5. package/dist/extensions/handoffFilters.d.ts +4 -3
  6. package/dist/extensions/handoffFilters.js +8 -3
  7. package/dist/extensions/handoffFilters.js.map +1 -1
  8. package/dist/extensions/handoffFilters.mjs +9 -4
  9. package/dist/extensions/handoffFilters.mjs.map +1 -1
  10. package/dist/index.d.ts +4 -4
  11. package/dist/index.js +8 -2
  12. package/dist/index.js.map +1 -1
  13. package/dist/index.mjs +2 -2
  14. package/dist/index.mjs.map +1 -1
  15. package/dist/items.d.ts +1158 -32
  16. package/dist/items.js +56 -2
  17. package/dist/items.js.map +1 -1
  18. package/dist/items.mjs +53 -1
  19. package/dist/items.mjs.map +1 -1
  20. package/dist/metadata.js +3 -3
  21. package/dist/metadata.mjs +3 -3
  22. package/dist/model.d.ts +14 -2
  23. package/dist/run.js +2 -2
  24. package/dist/run.js.map +1 -1
  25. package/dist/run.mjs +3 -3
  26. package/dist/run.mjs.map +1 -1
  27. package/dist/runContext.d.ts +12 -1
  28. package/dist/runContext.js +145 -41
  29. package/dist/runContext.js.map +1 -1
  30. package/dist/runContext.mjs +145 -41
  31. package/dist/runContext.mjs.map +1 -1
  32. package/dist/runState.d.ts +506 -18
  33. package/dist/runState.js +321 -15
  34. package/dist/runState.js.map +1 -1
  35. package/dist/runState.mjs +322 -16
  36. package/dist/runState.mjs.map +1 -1
  37. package/dist/runner/approvalRejection.d.ts +13 -0
  38. package/dist/runner/approvalRejection.js +44 -0
  39. package/dist/runner/approvalRejection.js.map +1 -0
  40. package/dist/runner/approvalRejection.mjs +37 -0
  41. package/dist/runner/approvalRejection.mjs.map +1 -0
  42. package/dist/runner/mcpApprovals.js +4 -1
  43. package/dist/runner/mcpApprovals.js.map +1 -1
  44. package/dist/runner/mcpApprovals.mjs +4 -1
  45. package/dist/runner/mcpApprovals.mjs.map +1 -1
  46. package/dist/runner/modelOutputs.d.ts +5 -1
  47. package/dist/runner/modelOutputs.js +552 -12
  48. package/dist/runner/modelOutputs.js.map +1 -1
  49. package/dist/runner/modelOutputs.mjs +552 -13
  50. package/dist/runner/modelOutputs.mjs.map +1 -1
  51. package/dist/runner/modelPreparation.js +5 -2
  52. package/dist/runner/modelPreparation.js.map +1 -1
  53. package/dist/runner/modelPreparation.mjs +5 -2
  54. package/dist/runner/modelPreparation.mjs.map +1 -1
  55. package/dist/runner/sessionPersistence.js +17 -3
  56. package/dist/runner/sessionPersistence.js.map +1 -1
  57. package/dist/runner/sessionPersistence.mjs +17 -3
  58. package/dist/runner/sessionPersistence.mjs.map +1 -1
  59. package/dist/runner/streaming.js +8 -0
  60. package/dist/runner/streaming.js.map +1 -1
  61. package/dist/runner/streaming.mjs +9 -1
  62. package/dist/runner/streaming.mjs.map +1 -1
  63. package/dist/runner/toolExecution.js +105 -95
  64. package/dist/runner/toolExecution.js.map +1 -1
  65. package/dist/runner/toolExecution.mjs +100 -90
  66. package/dist/runner/toolExecution.mjs.map +1 -1
  67. package/dist/runner/toolSearch.d.ts +23 -0
  68. package/dist/runner/toolSearch.js +426 -0
  69. package/dist/runner/toolSearch.js.map +1 -0
  70. package/dist/runner/toolSearch.mjs +416 -0
  71. package/dist/runner/toolSearch.mjs.map +1 -0
  72. package/dist/runner/turnResolution.js +2 -1
  73. package/dist/runner/turnResolution.js.map +1 -1
  74. package/dist/runner/turnResolution.mjs +2 -1
  75. package/dist/runner/turnResolution.mjs.map +1 -1
  76. package/dist/tool.d.ts +50 -0
  77. package/dist/tool.js +79 -0
  78. package/dist/tool.js.map +1 -1
  79. package/dist/tool.mjs +74 -0
  80. package/dist/tool.mjs.map +1 -1
  81. package/dist/toolIdentity.d.ts +23 -0
  82. package/dist/toolIdentity.js +105 -0
  83. package/dist/toolIdentity.js.map +1 -0
  84. package/dist/toolIdentity.mjs +89 -0
  85. package/dist/toolIdentity.mjs.map +1 -0
  86. package/dist/tooling.d.ts +24 -0
  87. package/dist/tooling.js +110 -0
  88. package/dist/tooling.js.map +1 -0
  89. package/dist/tooling.mjs +97 -0
  90. package/dist/tooling.mjs.map +1 -0
  91. package/dist/types/aliases.d.ts +3 -3
  92. package/dist/types/protocol.d.ts +417 -12
  93. package/dist/types/protocol.js +59 -4
  94. package/dist/types/protocol.js.map +1 -1
  95. package/dist/types/protocol.mjs +57 -2
  96. package/dist/types/protocol.mjs.map +1 -1
  97. package/dist/types/providerData.d.ts +2 -0
  98. package/dist/utils/index.d.ts +2 -0
  99. package/dist/utils/index.js +15 -1
  100. package/dist/utils/index.js.map +1 -1
  101. package/dist/utils/index.mjs +2 -0
  102. package/dist/utils/index.mjs.map +1 -1
  103. package/dist/utils/serialize.js +37 -6
  104. package/dist/utils/serialize.js.map +1 -1
  105. package/dist/utils/serialize.mjs +37 -6
  106. package/dist/utils/serialize.mjs.map +1 -1
  107. package/dist/utils/toolSearch.d.ts +1 -0
  108. package/dist/utils/toolSearch.js +13 -0
  109. package/dist/utils/toolSearch.js.map +1 -0
  110. package/dist/utils/toolSearch.mjs +2 -0
  111. package/dist/utils/toolSearch.mjs.map +1 -0
  112. package/package.json +2 -2
@@ -1,6 +1,10 @@
1
1
  import { ModelBehaviorError } from "../errors.mjs";
2
- import { RunHandoffCallItem, RunMessageOutputItem, RunReasoningItem, RunToolApprovalItem, RunToolCallItem, RunToolCallOutputItem, } from "../items.mjs";
2
+ import { RunHandoffCallItem, RunMessageOutputItem, RunReasoningItem, RunToolApprovalItem, RunToolCallItem, RunToolCallOutputItem, RunToolSearchCallItem, RunToolSearchOutputItem, } from "../items.mjs";
3
+ import { getClientToolSearchExecutor, getToolSearchRuntimeToolKey, } from "../tool.mjs";
3
4
  import { addErrorToCurrentSpan } from "../tracing/context.mjs";
5
+ import { getFunctionToolQualifiedName, getFunctionToolNamespace, getToolCallNamespace, resolveFunctionToolCallName, } from "../toolIdentity.mjs";
6
+ import { getToolSearchMatchKey, getToolSearchExecution, getToolSearchOutputReplacementKey, getToolSearchProviderCallId, } from "../utils/index.mjs";
7
+ import { addHostedMcpToolsFromToolSearchOutput, addLoadedToolNamesFromToolSearchOutput, createBuiltInClientToolSearchOutput, executeCustomClientToolSearch, getClientToolSearchHelper, } from "./toolSearch.mjs";
4
8
  function ensureToolAvailable(tool, message, data) {
5
9
  if (!tool) {
6
10
  addErrorToCurrentSpan({
@@ -18,17 +22,36 @@ function handleToolCallAction({ output, tool, agent, errorMessage, errorData, it
18
22
  actions.push(buildAction(resolvedTool));
19
23
  }
20
24
  function resolveFunctionOrHandoff(toolCall, handoffMap, functionMap, agent) {
21
- const handoff = handoffMap.get(toolCall.name);
22
- if (handoff) {
23
- return { type: 'handoff', handoff };
25
+ const resolvedToolName = resolveFunctionToolCallName(toolCall, functionMap) ?? toolCall.name;
26
+ const namespace = getToolCallNamespace(toolCall);
27
+ if (!namespace && typeof resolvedToolName === 'string') {
28
+ const functionTool = functionMap.get(resolvedToolName);
29
+ const handoff = handoffMap.get(toolCall.name);
30
+ if (functionTool && handoff && resolvedToolName.includes('.')) {
31
+ const message = `Ambiguous dotted tool call ${resolvedToolName} in agent ${agent.name}: it matches both a namespaced function tool and a handoff. Rename one of them or emit the function call with explicit namespace metadata.`;
32
+ addErrorToCurrentSpan({
33
+ message,
34
+ data: {
35
+ tool_name: resolvedToolName,
36
+ agent_name: agent.name,
37
+ },
38
+ });
39
+ throw new ModelBehaviorError(message);
40
+ }
41
+ if (functionTool && resolvedToolName.includes('.')) {
42
+ return { type: 'function', tool: functionTool };
43
+ }
44
+ if (handoff) {
45
+ return { type: 'handoff', handoff };
46
+ }
24
47
  }
25
- const functionTool = functionMap.get(toolCall.name);
48
+ const functionTool = functionMap.get(resolvedToolName);
26
49
  if (!functionTool) {
27
- const message = `Tool ${toolCall.name} not found in agent ${agent.name}.`;
50
+ const message = `Tool ${resolvedToolName} not found in agent ${agent.name}.`;
28
51
  addErrorToCurrentSpan({
29
52
  message,
30
53
  data: {
31
- tool_name: toolCall.name,
54
+ tool_name: resolvedToolName,
32
55
  agent_name: agent.name,
33
56
  },
34
57
  });
@@ -36,6 +59,271 @@ function resolveFunctionOrHandoff(toolCall, handoffMap, functionMap, agent) {
36
59
  }
37
60
  return { type: 'function', tool: functionTool };
38
61
  }
62
+ function normalizeFunctionToolCallForStorage(toolCall, tool) {
63
+ const namespace = getToolCallNamespace(toolCall);
64
+ const explicitNamespace = getFunctionToolNamespace(tool);
65
+ const qualifiedToolName = getFunctionToolQualifiedName(tool);
66
+ if (namespace ||
67
+ !explicitNamespace ||
68
+ !qualifiedToolName ||
69
+ toolCall.name !== qualifiedToolName) {
70
+ return toolCall;
71
+ }
72
+ return {
73
+ ...toolCall,
74
+ name: tool.name,
75
+ namespace: explicitNamespace,
76
+ };
77
+ }
78
+ function getRawAgentInputItem(item) {
79
+ if (item &&
80
+ typeof item === 'object' &&
81
+ 'rawItem' in item &&
82
+ item.rawItem &&
83
+ typeof item.rawItem === 'object') {
84
+ return item.rawItem;
85
+ }
86
+ return item;
87
+ }
88
+ function refreshLoadedDeferredToolNames(state) {
89
+ state.loadedToolNames.clear();
90
+ for (const toolSearchOutput of state.keyedToolSearchOutputsByKey.values()) {
91
+ addLoadedToolNamesFromToolSearchOutput(toolSearchOutput, state.loadedToolNames);
92
+ }
93
+ for (const toolSearchOutput of state.anonymousToolSearchOutputs) {
94
+ addLoadedToolNamesFromToolSearchOutput(toolSearchOutput, state.loadedToolNames);
95
+ }
96
+ }
97
+ function recordLoadedToolSearchOutput(state, toolSearchOutput) {
98
+ const replacementKey = getToolSearchOutputReplacementKey(toolSearchOutput);
99
+ if (replacementKey) {
100
+ state.keyedToolSearchOutputsByKey.set(replacementKey, toolSearchOutput);
101
+ }
102
+ else {
103
+ state.anonymousToolSearchOutputs.push(toolSearchOutput);
104
+ }
105
+ refreshLoadedDeferredToolNames(state);
106
+ }
107
+ function collectLoadedDeferredToolStateFromHistory(items, agent) {
108
+ const state = {
109
+ anonymousToolSearchOutputs: [],
110
+ keyedToolSearchOutputsByKey: new Map(),
111
+ loadedToolNames: new Set(),
112
+ };
113
+ for (const item of items) {
114
+ if (item instanceof RunToolSearchOutputItem &&
115
+ item.agent.name !== agent.name) {
116
+ continue;
117
+ }
118
+ const rawItem = getRawAgentInputItem(item);
119
+ if (rawItem?.type !== 'tool_search_output') {
120
+ continue;
121
+ }
122
+ const replacementKey = getToolSearchOutputReplacementKey(rawItem);
123
+ if (replacementKey) {
124
+ state.keyedToolSearchOutputsByKey.set(replacementKey, rawItem);
125
+ }
126
+ else {
127
+ state.anonymousToolSearchOutputs.push(rawItem);
128
+ }
129
+ }
130
+ refreshLoadedDeferredToolNames(state);
131
+ return state;
132
+ }
133
+ function seedHostedMcpToolsFromLoadedDeferredToolState(state, mcpToolMap, preserveExistingServerLabels) {
134
+ for (const toolSearchOutput of state.keyedToolSearchOutputsByKey.values()) {
135
+ addHostedMcpToolsFromToolSearchOutput(toolSearchOutput, mcpToolMap, {
136
+ preserveExistingServerLabels,
137
+ });
138
+ }
139
+ for (const toolSearchOutput of state.anonymousToolSearchOutputs) {
140
+ addHostedMcpToolsFromToolSearchOutput(toolSearchOutput, mcpToolMap, {
141
+ preserveExistingServerLabels,
142
+ });
143
+ }
144
+ }
145
+ function buildFunctionToolMap(tools) {
146
+ return new Map(tools
147
+ .filter((t) => t.type === 'function')
148
+ .map((t) => [getFunctionToolQualifiedName(t) ?? t.name, t]));
149
+ }
150
+ function registerRuntimeToolSearchTools(args) {
151
+ const { availableTools, functionMap, mcpToolMap, replaceableRuntimeToolKeys, runtimeTools, } = args;
152
+ const availableToolsByKey = new Map();
153
+ for (const tool of availableTools) {
154
+ const key = getToolSearchRuntimeToolKey(tool);
155
+ if (key) {
156
+ availableToolsByKey.set(key, tool);
157
+ }
158
+ }
159
+ const novelTools = [];
160
+ for (const runtimeTool of runtimeTools) {
161
+ const runtimeToolKey = getToolSearchRuntimeToolKey(runtimeTool);
162
+ if (!runtimeToolKey) {
163
+ throw new ModelBehaviorError('Client tool_search execute() returned an unsupported tool type.');
164
+ }
165
+ const existingTool = availableToolsByKey.get(runtimeToolKey);
166
+ if (existingTool && existingTool !== runtimeTool) {
167
+ if (!replaceableRuntimeToolKeys?.has(runtimeToolKey)) {
168
+ throw new ModelBehaviorError(`Client tool_search execute() returned tool "${runtimeToolKey}" that conflicts with an existing available tool.`);
169
+ }
170
+ }
171
+ else if (existingTool === runtimeTool) {
172
+ continue;
173
+ }
174
+ availableToolsByKey.set(runtimeToolKey, runtimeTool);
175
+ novelTools.push(runtimeTool);
176
+ if (runtimeTool.type === 'function') {
177
+ functionMap.set(getFunctionToolQualifiedName(runtimeTool) ?? runtimeTool.name, runtimeTool);
178
+ continue;
179
+ }
180
+ if (runtimeTool.type === 'hosted_tool' &&
181
+ runtimeTool.providerData?.type === 'mcp') {
182
+ mcpToolMap.set(runtimeTool.providerData.server_label, runtimeTool);
183
+ continue;
184
+ }
185
+ throw new ModelBehaviorError('Client tool_search execute() returned an unsupported tool type.');
186
+ }
187
+ return novelTools;
188
+ }
189
+ function buildGeneratedClientToolSearchOutputMap(modelResponse, tools, hasClientToolSearchTool) {
190
+ const clientToolSearchCalls = [];
191
+ const pendingClientToolSearchMatchKeys = [];
192
+ const resolvedToolSearchCallIds = new Set();
193
+ for (const output of modelResponse.output) {
194
+ if (output.type === 'tool_search_call') {
195
+ const toolSearchExecution = getToolSearchExecution(output);
196
+ if (toolSearchExecution === 'client' ||
197
+ (typeof toolSearchExecution === 'undefined' && hasClientToolSearchTool)) {
198
+ clientToolSearchCalls.push(output);
199
+ const matchKey = getToolSearchMatchKey(output);
200
+ if (matchKey) {
201
+ pendingClientToolSearchMatchKeys.push(matchKey);
202
+ }
203
+ }
204
+ continue;
205
+ }
206
+ if (output.type !== 'tool_search_output') {
207
+ continue;
208
+ }
209
+ const explicitCallId = getToolSearchProviderCallId(output);
210
+ const toolSearchExecution = getToolSearchExecution(output);
211
+ if (explicitCallId) {
212
+ resolvedToolSearchCallIds.add(explicitCallId);
213
+ const pendingIndex = pendingClientToolSearchMatchKeys.indexOf(explicitCallId);
214
+ if (pendingIndex >= 0) {
215
+ pendingClientToolSearchMatchKeys.splice(pendingIndex, 1);
216
+ }
217
+ continue;
218
+ }
219
+ if (toolSearchExecution !== 'server') {
220
+ const pendingMatchKey = pendingClientToolSearchMatchKeys.shift();
221
+ if (pendingMatchKey) {
222
+ resolvedToolSearchCallIds.add(pendingMatchKey);
223
+ }
224
+ }
225
+ }
226
+ const generatedOutputs = new Map();
227
+ for (const toolSearchCall of clientToolSearchCalls) {
228
+ const matchKey = getToolSearchMatchKey(toolSearchCall);
229
+ if (matchKey && resolvedToolSearchCallIds.has(matchKey)) {
230
+ continue;
231
+ }
232
+ generatedOutputs.set(toolSearchCall, createBuiltInClientToolSearchOutput(toolSearchCall, tools));
233
+ }
234
+ return generatedOutputs;
235
+ }
236
+ async function buildGeneratedClientToolSearchOutputMapAsync(args) {
237
+ const { agent, modelResponse, runContext, tools } = args;
238
+ const clientToolSearchTool = getClientToolSearchHelper(tools);
239
+ const hasClientToolSearchTool = typeof clientToolSearchTool !== 'undefined';
240
+ const executionTools = [...tools];
241
+ const clientToolSearchCalls = [];
242
+ const pendingClientToolSearchMatchKeys = [];
243
+ const resolvedToolSearchCallIds = new Set();
244
+ for (const output of modelResponse.output) {
245
+ if (output.type === 'tool_search_call') {
246
+ const toolSearchExecution = getToolSearchExecution(output);
247
+ if (toolSearchExecution === 'client' ||
248
+ (typeof toolSearchExecution === 'undefined' && hasClientToolSearchTool)) {
249
+ clientToolSearchCalls.push(output);
250
+ const matchKey = getToolSearchMatchKey(output);
251
+ if (matchKey) {
252
+ pendingClientToolSearchMatchKeys.push(matchKey);
253
+ }
254
+ }
255
+ continue;
256
+ }
257
+ if (output.type !== 'tool_search_output') {
258
+ continue;
259
+ }
260
+ const explicitCallId = getToolSearchProviderCallId(output);
261
+ const toolSearchExecution = getToolSearchExecution(output);
262
+ if (explicitCallId) {
263
+ resolvedToolSearchCallIds.add(explicitCallId);
264
+ const pendingIndex = pendingClientToolSearchMatchKeys.indexOf(explicitCallId);
265
+ if (pendingIndex >= 0) {
266
+ pendingClientToolSearchMatchKeys.splice(pendingIndex, 1);
267
+ }
268
+ continue;
269
+ }
270
+ if (toolSearchExecution !== 'server') {
271
+ const pendingMatchKey = pendingClientToolSearchMatchKeys.shift();
272
+ if (pendingMatchKey) {
273
+ resolvedToolSearchCallIds.add(pendingMatchKey);
274
+ }
275
+ }
276
+ }
277
+ const generatedOutputs = new Map();
278
+ for (const toolSearchCall of clientToolSearchCalls) {
279
+ const matchKey = getToolSearchMatchKey(toolSearchCall);
280
+ if (matchKey && resolvedToolSearchCallIds.has(matchKey)) {
281
+ continue;
282
+ }
283
+ if (clientToolSearchTool &&
284
+ getClientToolSearchExecutor(clientToolSearchTool)) {
285
+ const generatedOutput = await executeCustomClientToolSearch({
286
+ agent,
287
+ runContext,
288
+ toolSearchCall,
289
+ toolSearchTool: clientToolSearchTool,
290
+ tools: executionTools,
291
+ });
292
+ generatedOutputs.set(toolSearchCall, generatedOutput);
293
+ executionTools.push(...generatedOutput.runtimeTools);
294
+ continue;
295
+ }
296
+ generatedOutputs.set(toolSearchCall, {
297
+ output: createBuiltInClientToolSearchOutput(toolSearchCall, executionTools),
298
+ runtimeTools: [],
299
+ });
300
+ }
301
+ return generatedOutputs;
302
+ }
303
+ function ensureDeferredFunctionToolLoaded(toolCall, tool, loadedToolNames, agent) {
304
+ if (tool.deferLoading !== true) {
305
+ return;
306
+ }
307
+ const explicitNamespace = getFunctionToolNamespace(tool);
308
+ const qualifiedName = getFunctionToolQualifiedName(tool);
309
+ const isLoaded = (qualifiedName ? loadedToolNames.has(qualifiedName) : false) ||
310
+ ((!explicitNamespace || explicitNamespace === tool.name) &&
311
+ loadedToolNames.has(tool.name));
312
+ if (isLoaded) {
313
+ return;
314
+ }
315
+ const toolName = qualifiedName ?? tool.name;
316
+ const message = `Model produced deferred function call ${toolName} before it was loaded via tool_search.`;
317
+ addErrorToCurrentSpan({
318
+ message,
319
+ data: {
320
+ agent_name: agent.name,
321
+ tool_name: toolName,
322
+ tool_call_id: toolCall.callId,
323
+ },
324
+ });
325
+ throw new ModelBehaviorError(message);
326
+ }
39
327
  function parseShellCallStatus(status) {
40
328
  if (status === 'in_progress' ||
41
329
  status === 'completed' ||
@@ -61,7 +349,7 @@ function hasPendingShellOutputStatus(output) {
61
349
  * Walks a raw model response and classifies each item so the runner can schedule follow-up work.
62
350
  * Returns both the serializable RunItems (for history/streaming) and the actionable tool metadata.
63
351
  */
64
- export function processModelResponse(modelResponse, agent, tools, handoffs) {
352
+ export function processModelResponse(modelResponse, agent, tools, handoffs, priorItems = []) {
65
353
  const items = [];
66
354
  const runHandoffs = [];
67
355
  const runFunctions = [];
@@ -75,7 +363,7 @@ export function processModelResponse(modelResponse, agent, tools, handoffs) {
75
363
  // Resolve tools upfront so we can look up the concrete handler in O(1) while iterating outputs.
76
364
  const functionMap = new Map(tools
77
365
  .filter((t) => t.type === 'function')
78
- .map((t) => [t.name, t]));
366
+ .map((t) => [getFunctionToolQualifiedName(t) ?? t.name, t]));
79
367
  const computerTool = tools.find((t) => t.type === 'computer');
80
368
  const shellTool = tools.find((t) => t.type === 'shell');
81
369
  const applyPatchTool = tools.find((t) => t.type === 'apply_patch');
@@ -83,12 +371,40 @@ export function processModelResponse(modelResponse, agent, tools, handoffs) {
83
371
  .filter((t) => t.type === 'hosted_tool' && t.providerData?.type === 'mcp')
84
372
  .map((t) => t)
85
373
  .map((t) => [t.providerData.server_label, t]));
374
+ const originalMcpServerLabels = new Set(mcpToolMap.keys());
375
+ const hasClientToolSearchTool = tools.some((tool) => tool.type === 'hosted_tool' &&
376
+ tool.providerData?.type === 'tool_search' &&
377
+ tool.providerData.execution === 'client');
378
+ const loadedDeferredToolState = collectLoadedDeferredToolStateFromHistory(priorItems, agent);
379
+ seedHostedMcpToolsFromLoadedDeferredToolState(loadedDeferredToolState, mcpToolMap, originalMcpServerLabels);
380
+ const generatedClientToolSearchOutputsByCall = buildGeneratedClientToolSearchOutputMap(modelResponse, tools, hasClientToolSearchTool);
381
+ let hasGeneratedClientToolSearchOutputs = false;
86
382
  for (const output of modelResponse.output) {
87
383
  if (output.type === 'message') {
88
384
  if (output.role === 'assistant') {
89
385
  items.push(new RunMessageOutputItem(output, agent));
90
386
  }
91
387
  }
388
+ else if (output.type === 'tool_search_call') {
389
+ items.push(new RunToolSearchCallItem(output, agent));
390
+ toolsUsed.push('tool_search');
391
+ const generatedOutput = generatedClientToolSearchOutputsByCall.get(output);
392
+ if (generatedOutput) {
393
+ items.push(new RunToolSearchOutputItem(generatedOutput, agent));
394
+ recordLoadedToolSearchOutput(loadedDeferredToolState, generatedOutput);
395
+ addHostedMcpToolsFromToolSearchOutput(generatedOutput, mcpToolMap, {
396
+ preserveExistingServerLabels: originalMcpServerLabels,
397
+ });
398
+ hasGeneratedClientToolSearchOutputs = true;
399
+ }
400
+ }
401
+ else if (output.type === 'tool_search_output') {
402
+ items.push(new RunToolSearchOutputItem(output, agent));
403
+ recordLoadedToolSearchOutput(loadedDeferredToolState, output);
404
+ addHostedMcpToolsFromToolSearchOutput(output, mcpToolMap, {
405
+ preserveExistingServerLabels: originalMcpServerLabels,
406
+ });
407
+ }
92
408
  else if (output.type === 'hosted_tool_call') {
93
409
  items.push(new RunToolCallItem(output, agent));
94
410
  const toolName = output.name;
@@ -201,9 +517,9 @@ export function processModelResponse(modelResponse, agent, tools, handoffs) {
201
517
  if (output.type !== 'function_call') {
202
518
  continue;
203
519
  }
204
- toolsUsed.push(output.name);
205
520
  const resolved = resolveFunctionOrHandoff(output, handoffMap, functionMap, agent);
206
521
  if (resolved.type === 'handoff') {
522
+ toolsUsed.push(output.name);
207
523
  items.push(new RunHandoffCallItem(output, agent));
208
524
  runHandoffs.push({
209
525
  toolCall: output,
@@ -211,9 +527,12 @@ export function processModelResponse(modelResponse, agent, tools, handoffs) {
211
527
  });
212
528
  }
213
529
  else {
214
- items.push(new RunToolCallItem(output, agent));
530
+ ensureDeferredFunctionToolLoaded(output, resolved.tool, loadedDeferredToolState.loadedToolNames, agent);
531
+ const normalizedToolCall = normalizeFunctionToolCallForStorage(output, resolved.tool);
532
+ toolsUsed.push(getFunctionToolQualifiedName(resolved.tool) ?? resolved.tool.name);
533
+ items.push(new RunToolCallItem(normalizedToolCall, agent));
215
534
  runFunctions.push({
216
- toolCall: output,
535
+ toolCall: normalizedToolCall,
217
536
  tool: resolved.tool,
218
537
  });
219
538
  }
@@ -234,7 +553,227 @@ export function processModelResponse(modelResponse, agent, tools, handoffs) {
234
553
  runComputerActions.length > 0 ||
235
554
  runShellActions.length > 0 ||
236
555
  hasHostedShellCall ||
237
- runApplyPatchActions.length > 0);
556
+ runApplyPatchActions.length > 0 ||
557
+ hasGeneratedClientToolSearchOutputs);
558
+ },
559
+ };
560
+ }
561
+ export async function processModelResponseAsync(modelResponse, agent, tools, handoffs, state, priorItems = []) {
562
+ const clientToolSearchTool = getClientToolSearchHelper(tools);
563
+ const hasCustomClientToolSearchExecutor = Boolean(clientToolSearchTool && getClientToolSearchExecutor(clientToolSearchTool));
564
+ const hasRelevantClientToolSearchCall = modelResponse.output.some((output) => output.type === 'tool_search_call' &&
565
+ (getToolSearchExecution(output) === 'client' ||
566
+ (typeof getToolSearchExecution(output) === 'undefined' &&
567
+ typeof clientToolSearchTool !== 'undefined')));
568
+ if (!hasCustomClientToolSearchExecutor || !hasRelevantClientToolSearchCall) {
569
+ return processModelResponse(modelResponse, agent, tools, handoffs, priorItems);
570
+ }
571
+ const items = [];
572
+ const runHandoffs = [];
573
+ const runFunctions = [];
574
+ const runComputerActions = [];
575
+ const runShellActions = [];
576
+ let hasHostedShellCall = false;
577
+ const runApplyPatchActions = [];
578
+ const runMCPApprovalRequests = [];
579
+ const toolsUsed = [];
580
+ const handoffMap = new Map(handoffs.map((h) => [h.toolName, h]));
581
+ const functionMap = buildFunctionToolMap(tools);
582
+ const computerTool = tools.find((t) => t.type === 'computer');
583
+ const shellTool = tools.find((t) => t.type === 'shell');
584
+ const applyPatchTool = tools.find((t) => t.type === 'apply_patch');
585
+ const mcpToolMap = new Map(tools
586
+ .filter((t) => t.type === 'hosted_tool' && t.providerData?.type === 'mcp')
587
+ .map((t) => t)
588
+ .map((t) => [t.providerData.server_label, t]));
589
+ const originalMcpServerLabels = new Set(mcpToolMap.keys());
590
+ const replaceableRuntimeToolKeys = new Set(state
591
+ .getToolSearchRuntimeTools(agent)
592
+ .map((tool) => getToolSearchRuntimeToolKey(tool))
593
+ .filter((key) => typeof key === 'string'));
594
+ const loadedDeferredToolState = collectLoadedDeferredToolStateFromHistory(priorItems, agent);
595
+ seedHostedMcpToolsFromLoadedDeferredToolState(loadedDeferredToolState, mcpToolMap, originalMcpServerLabels);
596
+ const generatedClientToolSearchOutputsByCall = await buildGeneratedClientToolSearchOutputMapAsync({
597
+ agent,
598
+ modelResponse,
599
+ runContext: state._context,
600
+ tools,
601
+ });
602
+ let hasGeneratedClientToolSearchOutputs = false;
603
+ const availableTools = [...tools];
604
+ for (const output of modelResponse.output) {
605
+ if (output.type === 'message') {
606
+ if (output.role === 'assistant') {
607
+ items.push(new RunMessageOutputItem(output, agent));
608
+ }
609
+ }
610
+ else if (output.type === 'tool_search_call') {
611
+ items.push(new RunToolSearchCallItem(output, agent));
612
+ toolsUsed.push('tool_search');
613
+ const generatedOutput = generatedClientToolSearchOutputsByCall.get(output);
614
+ if (generatedOutput) {
615
+ items.push(new RunToolSearchOutputItem(generatedOutput.output, agent));
616
+ recordLoadedToolSearchOutput(loadedDeferredToolState, generatedOutput.output);
617
+ addHostedMcpToolsFromToolSearchOutput(generatedOutput.output, mcpToolMap, {
618
+ preserveExistingServerLabels: originalMcpServerLabels,
619
+ });
620
+ const novelRuntimeTools = registerRuntimeToolSearchTools({
621
+ availableTools,
622
+ functionMap,
623
+ mcpToolMap,
624
+ replaceableRuntimeToolKeys,
625
+ runtimeTools: generatedOutput.runtimeTools,
626
+ });
627
+ state.recordToolSearchRuntimeTools(agent, generatedOutput.output, novelRuntimeTools);
628
+ hasGeneratedClientToolSearchOutputs = true;
629
+ }
630
+ }
631
+ else if (output.type === 'tool_search_output') {
632
+ items.push(new RunToolSearchOutputItem(output, agent));
633
+ recordLoadedToolSearchOutput(loadedDeferredToolState, output);
634
+ addHostedMcpToolsFromToolSearchOutput(output, mcpToolMap, {
635
+ preserveExistingServerLabels: originalMcpServerLabels,
636
+ });
637
+ }
638
+ else if (output.type === 'hosted_tool_call') {
639
+ items.push(new RunToolCallItem(output, agent));
640
+ const toolName = output.name;
641
+ toolsUsed.push(toolName);
642
+ if (output.providerData?.type === 'mcp_approval_request' ||
643
+ output.name === 'mcp_approval_request') {
644
+ const providerData = output.providerData;
645
+ const mcpServerLabel = providerData.server_label;
646
+ const mcpServerTool = mcpToolMap.get(mcpServerLabel);
647
+ if (typeof mcpServerTool === 'undefined') {
648
+ const message = `MCP server (${mcpServerLabel}) not found in Agent (${agent.name})`;
649
+ addErrorToCurrentSpan({
650
+ message,
651
+ data: { mcp_server_label: mcpServerLabel },
652
+ });
653
+ throw new ModelBehaviorError(message);
654
+ }
655
+ const approvalItem = new RunToolApprovalItem({
656
+ type: 'hosted_tool_call',
657
+ name: providerData.name,
658
+ id: providerData.id,
659
+ status: 'in_progress',
660
+ providerData,
661
+ }, agent);
662
+ runMCPApprovalRequests.push({
663
+ requestItem: approvalItem,
664
+ mcpTool: mcpServerTool,
665
+ });
666
+ if (!mcpServerTool.providerData.on_approval) {
667
+ items.push(approvalItem);
668
+ }
669
+ }
670
+ }
671
+ else if (output.type === 'reasoning') {
672
+ items.push(new RunReasoningItem(output, agent));
673
+ }
674
+ else if (output.type === 'computer_call') {
675
+ handleToolCallAction({
676
+ output,
677
+ tool: computerTool,
678
+ agent,
679
+ errorMessage: 'Model produced computer action without a computer tool.',
680
+ errorData: { agent_name: agent.name },
681
+ items,
682
+ toolsUsed,
683
+ actions: runComputerActions,
684
+ buildAction: (resolvedTool) => ({
685
+ toolCall: output,
686
+ computer: resolvedTool,
687
+ }),
688
+ });
689
+ }
690
+ else if (output.type === 'shell_call') {
691
+ const resolvedShellTool = ensureToolAvailable(shellTool, 'Model produced shell action without a shell tool.', { agent_name: agent.name });
692
+ items.push(new RunToolCallItem(output, agent));
693
+ toolsUsed.push(resolvedShellTool.name);
694
+ const shellEnvironmentType = resolvedShellTool.environment?.type ?? 'local';
695
+ if (shellEnvironmentType !== 'local') {
696
+ if (isShellCallPendingStatus(output.status)) {
697
+ hasHostedShellCall = true;
698
+ }
699
+ continue;
700
+ }
701
+ if (!resolvedShellTool.shell) {
702
+ const message = 'Model produced local shell action without a local shell implementation.';
703
+ addErrorToCurrentSpan({
704
+ message,
705
+ data: { agent_name: agent.name },
706
+ });
707
+ throw new ModelBehaviorError(message);
708
+ }
709
+ runShellActions.push({
710
+ toolCall: output,
711
+ shell: resolvedShellTool,
712
+ });
713
+ }
714
+ else if (output.type === 'shell_call_output') {
715
+ items.push(new RunToolCallOutputItem(output, agent, output.output));
716
+ if (hasPendingShellOutputStatus(output)) {
717
+ hasHostedShellCall = true;
718
+ }
719
+ }
720
+ else if (output.type === 'apply_patch_call') {
721
+ handleToolCallAction({
722
+ output,
723
+ tool: applyPatchTool,
724
+ agent,
725
+ errorMessage: 'Model produced apply_patch action without an apply_patch tool.',
726
+ errorData: { agent_name: agent.name },
727
+ items,
728
+ toolsUsed,
729
+ actions: runApplyPatchActions,
730
+ buildAction: (resolvedTool) => ({
731
+ toolCall: output,
732
+ applyPatch: resolvedTool,
733
+ }),
734
+ });
735
+ }
736
+ if (output.type !== 'function_call') {
737
+ continue;
738
+ }
739
+ const resolved = resolveFunctionOrHandoff(output, handoffMap, functionMap, agent);
740
+ if (resolved.type === 'handoff') {
741
+ toolsUsed.push(output.name);
742
+ items.push(new RunHandoffCallItem(output, agent));
743
+ runHandoffs.push({
744
+ toolCall: output,
745
+ handoff: resolved.handoff,
746
+ });
747
+ }
748
+ else {
749
+ ensureDeferredFunctionToolLoaded(output, resolved.tool, loadedDeferredToolState.loadedToolNames, agent);
750
+ const normalizedToolCall = normalizeFunctionToolCallForStorage(output, resolved.tool);
751
+ toolsUsed.push(getFunctionToolQualifiedName(resolved.tool) ?? resolved.tool.name);
752
+ items.push(new RunToolCallItem(normalizedToolCall, agent));
753
+ runFunctions.push({
754
+ toolCall: normalizedToolCall,
755
+ tool: resolved.tool,
756
+ });
757
+ }
758
+ }
759
+ return {
760
+ newItems: items,
761
+ handoffs: runHandoffs,
762
+ functions: runFunctions,
763
+ computerActions: runComputerActions,
764
+ shellActions: runShellActions,
765
+ applyPatchActions: runApplyPatchActions,
766
+ mcpApprovalRequests: runMCPApprovalRequests,
767
+ toolsUsed,
768
+ hasToolsOrApprovalsToRun() {
769
+ return (runHandoffs.length > 0 ||
770
+ runFunctions.length > 0 ||
771
+ runMCPApprovalRequests.length > 0 ||
772
+ runComputerActions.length > 0 ||
773
+ runShellActions.length > 0 ||
774
+ hasHostedShellCall ||
775
+ runApplyPatchActions.length > 0 ||
776
+ hasGeneratedClientToolSearchOutputs);
238
777
  },
239
778
  };
240
779
  }