@openai/agents-core 0.5.4 → 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.
- package/dist/computer.d.ts +10 -2
- package/dist/events.d.ts +1 -1
- package/dist/events.js.map +1 -1
- package/dist/events.mjs.map +1 -1
- package/dist/extensions/handoffFilters.d.ts +4 -3
- package/dist/extensions/handoffFilters.js +8 -3
- package/dist/extensions/handoffFilters.js.map +1 -1
- package/dist/extensions/handoffFilters.mjs +9 -4
- package/dist/extensions/handoffFilters.mjs.map +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.js +8 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/index.mjs.map +1 -1
- package/dist/items.d.ts +1158 -32
- package/dist/items.js +56 -2
- package/dist/items.js.map +1 -1
- package/dist/items.mjs +53 -1
- package/dist/items.mjs.map +1 -1
- package/dist/metadata.js +3 -3
- package/dist/metadata.mjs +3 -3
- package/dist/model.d.ts +14 -2
- package/dist/run.js +2 -2
- package/dist/run.js.map +1 -1
- package/dist/run.mjs +3 -3
- package/dist/run.mjs.map +1 -1
- package/dist/runContext.js +116 -67
- package/dist/runContext.js.map +1 -1
- package/dist/runContext.mjs +116 -67
- package/dist/runContext.mjs.map +1 -1
- package/dist/runState.d.ts +493 -17
- package/dist/runState.js +303 -12
- package/dist/runState.js.map +1 -1
- package/dist/runState.mjs +304 -13
- package/dist/runState.mjs.map +1 -1
- package/dist/runner/modelOutputs.d.ts +5 -1
- package/dist/runner/modelOutputs.js +552 -12
- package/dist/runner/modelOutputs.js.map +1 -1
- package/dist/runner/modelOutputs.mjs +552 -13
- package/dist/runner/modelOutputs.mjs.map +1 -1
- package/dist/runner/modelPreparation.js +5 -2
- package/dist/runner/modelPreparation.js.map +1 -1
- package/dist/runner/modelPreparation.mjs +5 -2
- package/dist/runner/modelPreparation.mjs.map +1 -1
- package/dist/runner/sessionPersistence.js +17 -3
- package/dist/runner/sessionPersistence.js.map +1 -1
- package/dist/runner/sessionPersistence.mjs +17 -3
- package/dist/runner/sessionPersistence.mjs.map +1 -1
- package/dist/runner/streaming.js +8 -0
- package/dist/runner/streaming.js.map +1 -1
- package/dist/runner/streaming.mjs +9 -1
- package/dist/runner/streaming.mjs.map +1 -1
- package/dist/runner/toolExecution.js +102 -67
- package/dist/runner/toolExecution.js.map +1 -1
- package/dist/runner/toolExecution.mjs +102 -67
- package/dist/runner/toolExecution.mjs.map +1 -1
- package/dist/runner/toolSearch.d.ts +23 -0
- package/dist/runner/toolSearch.js +426 -0
- package/dist/runner/toolSearch.js.map +1 -0
- package/dist/runner/toolSearch.mjs +416 -0
- package/dist/runner/toolSearch.mjs.map +1 -0
- package/dist/runner/turnResolution.js +2 -1
- package/dist/runner/turnResolution.js.map +1 -1
- package/dist/runner/turnResolution.mjs +2 -1
- package/dist/runner/turnResolution.mjs.map +1 -1
- package/dist/tool.d.ts +50 -0
- package/dist/tool.js +79 -0
- package/dist/tool.js.map +1 -1
- package/dist/tool.mjs +74 -0
- package/dist/tool.mjs.map +1 -1
- package/dist/toolIdentity.d.ts +23 -0
- package/dist/toolIdentity.js +105 -0
- package/dist/toolIdentity.js.map +1 -0
- package/dist/toolIdentity.mjs +89 -0
- package/dist/toolIdentity.mjs.map +1 -0
- package/dist/tooling.d.ts +24 -0
- package/dist/tooling.js +110 -0
- package/dist/tooling.js.map +1 -0
- package/dist/tooling.mjs +97 -0
- package/dist/tooling.mjs.map +1 -0
- package/dist/types/aliases.d.ts +3 -3
- package/dist/types/protocol.d.ts +417 -12
- package/dist/types/protocol.js +59 -4
- package/dist/types/protocol.js.map +1 -1
- package/dist/types/protocol.mjs +57 -2
- package/dist/types/protocol.mjs.map +1 -1
- package/dist/types/providerData.d.ts +2 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.js +15 -1
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/index.mjs +2 -0
- package/dist/utils/index.mjs.map +1 -1
- package/dist/utils/serialize.js +37 -6
- package/dist/utils/serialize.js.map +1 -1
- package/dist/utils/serialize.mjs +37 -6
- package/dist/utils/serialize.mjs.map +1 -1
- package/dist/utils/toolSearch.d.ts +1 -0
- package/dist/utils/toolSearch.js +13 -0
- package/dist/utils/toolSearch.js.map +1 -0
- package/dist/utils/toolSearch.mjs +2 -0
- package/dist/utils/toolSearch.mjs.map +1 -0
- 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
|
|
22
|
-
|
|
23
|
-
|
|
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(
|
|
48
|
+
const functionTool = functionMap.get(resolvedToolName);
|
|
26
49
|
if (!functionTool) {
|
|
27
|
-
const message = `Tool ${
|
|
50
|
+
const message = `Tool ${resolvedToolName} not found in agent ${agent.name}.`;
|
|
28
51
|
addErrorToCurrentSpan({
|
|
29
52
|
message,
|
|
30
53
|
data: {
|
|
31
|
-
tool_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
|
-
|
|
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:
|
|
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
|
}
|