@openai/agents-core 0.3.6 → 0.3.8
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/errors.d.ts +40 -0
- package/dist/errors.js +38 -1
- package/dist/errors.js.map +1 -1
- package/dist/errors.mjs +34 -0
- package/dist/errors.mjs.map +1 -1
- package/dist/index.d.ts +6 -2
- package/dist/index.js +13 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +3 -1
- package/dist/index.mjs.map +1 -1
- package/dist/metadata.js +2 -2
- package/dist/metadata.mjs +2 -2
- package/dist/result.d.ts +17 -0
- package/dist/result.js +71 -24
- package/dist/result.js.map +1 -1
- package/dist/result.mjs +69 -22
- package/dist/result.mjs.map +1 -1
- package/dist/run.d.ts +14 -47
- package/dist/run.js +421 -994
- package/dist/run.js.map +1 -1
- package/dist/run.mjs +405 -978
- package/dist/run.mjs.map +1 -1
- package/dist/runState.d.ts +1286 -172
- package/dist/runState.js +146 -16
- package/dist/runState.js.map +1 -1
- package/dist/runState.mjs +142 -12
- package/dist/runState.mjs.map +1 -1
- package/dist/runner/constants.d.ts +1 -0
- package/dist/runner/constants.js +6 -0
- package/dist/runner/constants.js.map +1 -0
- package/dist/runner/constants.mjs +3 -0
- package/dist/runner/constants.mjs.map +1 -0
- package/dist/runner/conversation.d.ts +85 -0
- package/dist/runner/conversation.js +275 -0
- package/dist/runner/conversation.js.map +1 -0
- package/dist/runner/conversation.mjs +269 -0
- package/dist/runner/conversation.mjs.map +1 -0
- package/dist/runner/guardrails.d.ts +23 -0
- package/dist/runner/guardrails.js +174 -0
- package/dist/runner/guardrails.js.map +1 -0
- package/dist/runner/guardrails.mjs +166 -0
- package/dist/runner/guardrails.mjs.map +1 -0
- package/dist/runner/items.d.ts +18 -0
- package/dist/runner/items.js +89 -0
- package/dist/runner/items.js.map +1 -0
- package/dist/runner/items.mjs +79 -0
- package/dist/runner/items.mjs.map +1 -0
- package/dist/runner/mcpApprovals.d.ts +25 -0
- package/dist/runner/mcpApprovals.js +66 -0
- package/dist/runner/mcpApprovals.js.map +1 -0
- package/dist/runner/mcpApprovals.mjs +63 -0
- package/dist/runner/mcpApprovals.mjs.map +1 -0
- package/dist/runner/modelOutputs.d.ts +10 -0
- package/dist/runner/modelOutputs.js +206 -0
- package/dist/runner/modelOutputs.js.map +1 -0
- package/dist/runner/modelOutputs.mjs +203 -0
- package/dist/runner/modelOutputs.mjs.map +1 -0
- package/dist/runner/modelPreparation.d.ts +8 -0
- package/dist/runner/modelPreparation.js +41 -0
- package/dist/runner/modelPreparation.js.map +1 -0
- package/dist/runner/modelPreparation.mjs +38 -0
- package/dist/runner/modelPreparation.mjs.map +1 -0
- package/dist/runner/modelSettings.d.ts +20 -0
- package/dist/runner/modelSettings.js +97 -0
- package/dist/runner/modelSettings.js.map +1 -0
- package/dist/runner/modelSettings.mjs +92 -0
- package/dist/runner/modelSettings.mjs.map +1 -0
- package/dist/runner/runLoop.d.ts +32 -0
- package/dist/runner/runLoop.js +62 -0
- package/dist/runner/runLoop.js.map +1 -0
- package/dist/runner/runLoop.mjs +57 -0
- package/dist/runner/runLoop.mjs.map +1 -0
- package/dist/runner/sessionPersistence.d.ts +26 -0
- package/dist/runner/sessionPersistence.js +441 -0
- package/dist/runner/sessionPersistence.js.map +1 -0
- package/dist/runner/sessionPersistence.mjs +431 -0
- package/dist/runner/sessionPersistence.mjs.map +1 -0
- package/dist/runner/steps.d.ts +48 -0
- package/dist/runner/steps.js +40 -0
- package/dist/runner/steps.js.map +1 -0
- package/dist/runner/steps.mjs +36 -0
- package/dist/runner/steps.mjs.map +1 -0
- package/dist/runner/streaming.d.ts +9 -0
- package/dist/runner/streaming.js +74 -0
- package/dist/runner/streaming.js.map +1 -0
- package/dist/runner/streaming.mjs +65 -0
- package/dist/runner/streaming.mjs.map +1 -0
- package/dist/runner/toolExecution.d.ts +15 -0
- package/dist/runner/toolExecution.js +997 -0
- package/dist/runner/toolExecution.js.map +1 -0
- package/dist/runner/toolExecution.mjs +984 -0
- package/dist/runner/toolExecution.mjs.map +1 -0
- package/dist/runner/toolUseTracker.d.ts +9 -0
- package/dist/runner/toolUseTracker.js +34 -0
- package/dist/runner/toolUseTracker.js.map +1 -0
- package/dist/runner/toolUseTracker.mjs +30 -0
- package/dist/runner/toolUseTracker.mjs.map +1 -0
- package/dist/runner/tracing.d.ts +23 -0
- package/dist/runner/tracing.js +45 -0
- package/dist/runner/tracing.js.map +1 -0
- package/dist/runner/tracing.mjs +41 -0
- package/dist/runner/tracing.mjs.map +1 -0
- package/dist/runner/turnPreparation.d.ts +30 -0
- package/dist/runner/turnPreparation.js +80 -0
- package/dist/runner/turnPreparation.js.map +1 -0
- package/dist/runner/turnPreparation.mjs +74 -0
- package/dist/runner/turnPreparation.mjs.map +1 -0
- package/dist/runner/turnResolution.d.ts +3 -0
- package/dist/runner/turnResolution.js +531 -0
- package/dist/runner/turnResolution.js.map +1 -0
- package/dist/runner/turnResolution.mjs +526 -0
- package/dist/runner/turnResolution.mjs.map +1 -0
- package/dist/runner/types.d.ts +66 -0
- package/dist/runner/types.js +3 -0
- package/dist/runner/types.js.map +1 -0
- package/dist/runner/types.mjs +2 -0
- package/dist/runner/types.mjs.map +1 -0
- package/dist/shims/mcp-server/node.js +76 -30
- package/dist/shims/mcp-server/node.js.map +1 -1
- package/dist/shims/mcp-server/node.mjs +76 -30
- package/dist/shims/mcp-server/node.mjs.map +1 -1
- package/dist/tool.d.ts +28 -2
- package/dist/tool.js +7 -1
- package/dist/tool.js.map +1 -1
- package/dist/tool.mjs +8 -2
- package/dist/tool.mjs.map +1 -1
- package/dist/toolGuardrail.d.ts +101 -0
- package/dist/toolGuardrail.js +58 -0
- package/dist/toolGuardrail.js.map +1 -0
- package/dist/toolGuardrail.mjs +51 -0
- package/dist/toolGuardrail.mjs.map +1 -0
- package/dist/tracing/config.d.ts +3 -0
- package/dist/tracing/config.js +3 -0
- package/dist/tracing/config.js.map +1 -0
- package/dist/tracing/config.mjs +2 -0
- package/dist/tracing/config.mjs.map +1 -0
- package/dist/tracing/context.d.ts +2 -0
- package/dist/tracing/context.js +95 -24
- package/dist/tracing/context.js.map +1 -1
- package/dist/tracing/context.mjs +95 -24
- package/dist/tracing/context.mjs.map +1 -1
- package/dist/tracing/createSpans.d.ts +11 -11
- package/dist/tracing/index.d.ts +2 -0
- package/dist/tracing/index.js.map +1 -1
- package/dist/tracing/index.mjs.map +1 -1
- package/dist/tracing/provider.js +54 -4
- package/dist/tracing/provider.js.map +1 -1
- package/dist/tracing/provider.mjs +54 -4
- package/dist/tracing/provider.mjs.map +1 -1
- package/dist/tracing/spans.d.ts +2 -0
- package/dist/tracing/spans.js +6 -0
- package/dist/tracing/spans.js.map +1 -1
- package/dist/tracing/spans.mjs +6 -0
- package/dist/tracing/spans.mjs.map +1 -1
- package/dist/tracing/traces.d.ts +11 -1
- package/dist/tracing/traces.js +15 -2
- package/dist/tracing/traces.js.map +1 -1
- package/dist/tracing/traces.mjs +15 -2
- package/dist/tracing/traces.mjs.map +1 -1
- package/dist/types/protocol.d.ts +11 -0
- package/dist/types/protocol.js +1 -0
- package/dist/types/protocol.js.map +1 -1
- package/dist/types/protocol.mjs +1 -0
- package/dist/types/protocol.mjs.map +1 -1
- package/dist/utils/binary.d.ts +6 -0
- package/dist/utils/binary.js +53 -0
- package/dist/utils/binary.js.map +1 -0
- package/dist/utils/binary.mjs +49 -0
- package/dist/utils/binary.mjs.map +1 -0
- package/dist/utils/toolGuardrails.d.ts +24 -0
- package/dist/utils/toolGuardrails.js +58 -0
- package/dist/utils/toolGuardrails.js.map +1 -0
- package/dist/utils/toolGuardrails.mjs +54 -0
- package/dist/utils/toolGuardrails.mjs.map +1 -0
- package/package.json +4 -3
- package/dist/runImplementation.d.ts +0 -161
- package/dist/runImplementation.js +0 -2054
- package/dist/runImplementation.js.map +0 -1
- package/dist/runImplementation.mjs +0 -2028
- package/dist/runImplementation.mjs.map +0 -1
|
@@ -0,0 +1,997 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getToolCallOutputItem = getToolCallOutputItem;
|
|
7
|
+
exports.executeFunctionToolCalls = executeFunctionToolCalls;
|
|
8
|
+
exports.executeShellActions = executeShellActions;
|
|
9
|
+
exports.executeApplyPatchOperations = executeApplyPatchOperations;
|
|
10
|
+
exports.executeComputerActions = executeComputerActions;
|
|
11
|
+
exports.executeHandoffCalls = executeHandoffCalls;
|
|
12
|
+
exports.collectInterruptions = collectInterruptions;
|
|
13
|
+
exports.checkForFinalOutputFromTools = checkForFinalOutputFromTools;
|
|
14
|
+
const agent_1 = require("../agent.js");
|
|
15
|
+
const errors_1 = require("../errors.js");
|
|
16
|
+
const handoff_1 = require("../handoff.js");
|
|
17
|
+
const items_1 = require("../items.js");
|
|
18
|
+
const logger_1 = __importDefault(require("../logger.js"));
|
|
19
|
+
const tool_1 = require("../tool.js");
|
|
20
|
+
const base64_1 = require("../utils/base64.js");
|
|
21
|
+
const smartString_1 = require("../utils/smartString.js");
|
|
22
|
+
const utils_1 = require("../utils/index.js");
|
|
23
|
+
const createSpans_1 = require("../tracing/createSpans.js");
|
|
24
|
+
const toolGuardrails_1 = require("../utils/toolGuardrails.js");
|
|
25
|
+
const steps_1 = require("./steps.js");
|
|
26
|
+
const TOOL_APPROVAL_REJECTION_MESSAGE = 'Tool execution was not approved.';
|
|
27
|
+
/**
|
|
28
|
+
* @internal
|
|
29
|
+
* Normalizes tool outputs once so downstream code works with fully structured protocol items.
|
|
30
|
+
* Doing this here keeps API surface stable even when providers add new shapes.
|
|
31
|
+
*/
|
|
32
|
+
function getToolCallOutputItem(toolCall, output) {
|
|
33
|
+
const maybeStructuredOutputs = normalizeStructuredToolOutputs(output);
|
|
34
|
+
if (maybeStructuredOutputs) {
|
|
35
|
+
const structuredItems = maybeStructuredOutputs.map(convertStructuredToolOutputToInputItem);
|
|
36
|
+
return {
|
|
37
|
+
type: 'function_call_result',
|
|
38
|
+
name: toolCall.name,
|
|
39
|
+
callId: toolCall.callId,
|
|
40
|
+
status: 'completed',
|
|
41
|
+
output: structuredItems,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
type: 'function_call_result',
|
|
46
|
+
name: toolCall.name,
|
|
47
|
+
callId: toolCall.callId,
|
|
48
|
+
status: 'completed',
|
|
49
|
+
output: {
|
|
50
|
+
type: 'text',
|
|
51
|
+
text: (0, smartString_1.toSmartString)(output),
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* @internal
|
|
57
|
+
* Runs every function tool call requested by the model and returns their outputs alongside
|
|
58
|
+
* the `RunItem` instances that should be appended to history.
|
|
59
|
+
*/
|
|
60
|
+
async function executeFunctionToolCalls(agent, toolRuns, runner, state) {
|
|
61
|
+
const deps = { agent, runner, state };
|
|
62
|
+
try {
|
|
63
|
+
const results = await Promise.all(toolRuns.map(async (toolRun) => {
|
|
64
|
+
const parsedArgs = parseToolArguments(toolRun);
|
|
65
|
+
const approvalOutcome = await handleFunctionApproval(deps, toolRun, parsedArgs);
|
|
66
|
+
if (approvalOutcome !== 'approved') {
|
|
67
|
+
return approvalOutcome;
|
|
68
|
+
}
|
|
69
|
+
return runApprovedFunctionTool(deps, toolRun);
|
|
70
|
+
}));
|
|
71
|
+
return results;
|
|
72
|
+
}
|
|
73
|
+
catch (e) {
|
|
74
|
+
throw new errors_1.ToolCallError(`Failed to run function tools: ${e}`, e, state);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function parseToolArguments(toolRun) {
|
|
78
|
+
let parsedArgs = toolRun.toolCall.arguments;
|
|
79
|
+
if (toolRun.tool.parameters) {
|
|
80
|
+
if ((0, utils_1.isZodObject)(toolRun.tool.parameters)) {
|
|
81
|
+
parsedArgs = toolRun.tool.parameters.parse(parsedArgs);
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
parsedArgs = JSON.parse(parsedArgs);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return parsedArgs;
|
|
88
|
+
}
|
|
89
|
+
function buildApprovalRequestResult(deps, toolRun) {
|
|
90
|
+
return {
|
|
91
|
+
type: 'function_approval',
|
|
92
|
+
tool: toolRun.tool,
|
|
93
|
+
runItem: new items_1.RunToolApprovalItem(toolRun.toolCall, deps.agent),
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
async function buildApprovalRejectionResult(deps, toolRun) {
|
|
97
|
+
const { agent } = deps;
|
|
98
|
+
return (0, createSpans_1.withFunctionSpan)(async (span) => {
|
|
99
|
+
const response = 'Tool execution was not approved.';
|
|
100
|
+
span.setError({
|
|
101
|
+
message: response,
|
|
102
|
+
data: {
|
|
103
|
+
tool_name: toolRun.tool.name,
|
|
104
|
+
error: `Tool execution for ${toolRun.toolCall.callId} was manually rejected by user.`,
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
span.spanData.output = response;
|
|
108
|
+
return {
|
|
109
|
+
type: 'function_output',
|
|
110
|
+
tool: toolRun.tool,
|
|
111
|
+
output: response,
|
|
112
|
+
runItem: new items_1.RunToolCallOutputItem(getToolCallOutputItem(toolRun.toolCall, response), agent, response),
|
|
113
|
+
};
|
|
114
|
+
}, {
|
|
115
|
+
data: {
|
|
116
|
+
name: toolRun.tool.name,
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
async function handleFunctionApproval(deps, toolRun, parsedArgs) {
|
|
121
|
+
const { state } = deps;
|
|
122
|
+
const needsApproval = await toolRun.tool.needsApproval(state._context, parsedArgs, toolRun.toolCall.callId);
|
|
123
|
+
if (!needsApproval) {
|
|
124
|
+
return 'approved';
|
|
125
|
+
}
|
|
126
|
+
const approval = state._context.isToolApproved({
|
|
127
|
+
toolName: toolRun.tool.name,
|
|
128
|
+
callId: toolRun.toolCall.callId,
|
|
129
|
+
});
|
|
130
|
+
if (approval === false) {
|
|
131
|
+
return await buildApprovalRejectionResult(deps, toolRun);
|
|
132
|
+
}
|
|
133
|
+
if (approval !== true) {
|
|
134
|
+
return buildApprovalRequestResult(deps, toolRun);
|
|
135
|
+
}
|
|
136
|
+
return 'approved';
|
|
137
|
+
}
|
|
138
|
+
async function runApprovedFunctionTool(deps, toolRun) {
|
|
139
|
+
const { agent, runner, state } = deps;
|
|
140
|
+
return (0, createSpans_1.withFunctionSpan)(async (span) => {
|
|
141
|
+
if (runner.config.traceIncludeSensitiveData) {
|
|
142
|
+
span.spanData.input = toolRun.toolCall.arguments;
|
|
143
|
+
}
|
|
144
|
+
try {
|
|
145
|
+
const inputGuardrailResult = await (0, toolGuardrails_1.runToolInputGuardrails)({
|
|
146
|
+
guardrails: toolRun.tool.inputGuardrails,
|
|
147
|
+
context: state._context,
|
|
148
|
+
agent,
|
|
149
|
+
toolCall: toolRun.toolCall,
|
|
150
|
+
onResult: (result) => {
|
|
151
|
+
state._toolInputGuardrailResults.push(result);
|
|
152
|
+
},
|
|
153
|
+
});
|
|
154
|
+
emitToolStart(runner, state._context, agent, toolRun.tool, toolRun.toolCall);
|
|
155
|
+
let toolOutput;
|
|
156
|
+
if (inputGuardrailResult.type === 'reject') {
|
|
157
|
+
toolOutput = inputGuardrailResult.message;
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
toolOutput = await toolRun.tool.invoke(state._context, toolRun.toolCall.arguments, { toolCall: toolRun.toolCall });
|
|
161
|
+
toolOutput = await (0, toolGuardrails_1.runToolOutputGuardrails)({
|
|
162
|
+
guardrails: toolRun.tool.outputGuardrails,
|
|
163
|
+
context: state._context,
|
|
164
|
+
agent,
|
|
165
|
+
toolCall: toolRun.toolCall,
|
|
166
|
+
toolOutput,
|
|
167
|
+
onResult: (result) => {
|
|
168
|
+
state._toolOutputGuardrailResults.push(result);
|
|
169
|
+
},
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
const stringResult = (0, smartString_1.toSmartString)(toolOutput);
|
|
173
|
+
emitToolEnd(runner, state._context, agent, toolRun.tool, stringResult, toolRun.toolCall);
|
|
174
|
+
if (runner.config.traceIncludeSensitiveData) {
|
|
175
|
+
span.spanData.output = stringResult;
|
|
176
|
+
}
|
|
177
|
+
const functionResult = {
|
|
178
|
+
type: 'function_output',
|
|
179
|
+
tool: toolRun.tool,
|
|
180
|
+
output: toolOutput,
|
|
181
|
+
runItem: new items_1.RunToolCallOutputItem(getToolCallOutputItem(toolRun.toolCall, toolOutput), agent, toolOutput),
|
|
182
|
+
};
|
|
183
|
+
const nestedRunResult = (0, agent_1.consumeAgentToolRunResult)(toolRun.toolCall);
|
|
184
|
+
if (nestedRunResult) {
|
|
185
|
+
functionResult.agentRunResult = nestedRunResult;
|
|
186
|
+
const nestedInterruptions = nestedRunResult.interruptions;
|
|
187
|
+
if (nestedInterruptions.length > 0) {
|
|
188
|
+
functionResult.interruptions = nestedInterruptions;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return functionResult;
|
|
192
|
+
}
|
|
193
|
+
catch (error) {
|
|
194
|
+
span.setError({
|
|
195
|
+
message: 'Error running tool',
|
|
196
|
+
data: {
|
|
197
|
+
tool_name: toolRun.tool.name,
|
|
198
|
+
error: String(error),
|
|
199
|
+
},
|
|
200
|
+
});
|
|
201
|
+
const errorResult = String(error);
|
|
202
|
+
emitToolEnd(runner, state._context, agent, toolRun.tool, errorResult, toolRun.toolCall);
|
|
203
|
+
throw error;
|
|
204
|
+
}
|
|
205
|
+
}, {
|
|
206
|
+
data: {
|
|
207
|
+
name: toolRun.tool.name,
|
|
208
|
+
},
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* @internal
|
|
213
|
+
*/
|
|
214
|
+
// Internal helper: dispatch a computer action and return a screenshot (sync/async)
|
|
215
|
+
async function _runComputerActionAndScreenshot(computer, toolCall) {
|
|
216
|
+
const action = toolCall.action;
|
|
217
|
+
let screenshot;
|
|
218
|
+
// Dispatch based on action type string (assume action.type exists)
|
|
219
|
+
switch (action.type) {
|
|
220
|
+
case 'click':
|
|
221
|
+
await computer.click(action.x, action.y, action.button);
|
|
222
|
+
break;
|
|
223
|
+
case 'double_click':
|
|
224
|
+
await computer.doubleClick(action.x, action.y);
|
|
225
|
+
break;
|
|
226
|
+
case 'drag':
|
|
227
|
+
await computer.drag(action.path.map((p) => [p.x, p.y]));
|
|
228
|
+
break;
|
|
229
|
+
case 'keypress':
|
|
230
|
+
await computer.keypress(action.keys);
|
|
231
|
+
break;
|
|
232
|
+
case 'move':
|
|
233
|
+
await computer.move(action.x, action.y);
|
|
234
|
+
break;
|
|
235
|
+
case 'screenshot':
|
|
236
|
+
screenshot = await computer.screenshot();
|
|
237
|
+
break;
|
|
238
|
+
case 'scroll':
|
|
239
|
+
await computer.scroll(action.x, action.y, action.scroll_x, action.scroll_y);
|
|
240
|
+
break;
|
|
241
|
+
case 'type':
|
|
242
|
+
await computer.type(action.text);
|
|
243
|
+
break;
|
|
244
|
+
case 'wait':
|
|
245
|
+
await computer.wait();
|
|
246
|
+
break;
|
|
247
|
+
default:
|
|
248
|
+
action; // ensures that we handle every action we know of
|
|
249
|
+
// Unknown action, just take screenshot
|
|
250
|
+
break;
|
|
251
|
+
}
|
|
252
|
+
if (typeof screenshot !== 'undefined') {
|
|
253
|
+
return screenshot;
|
|
254
|
+
}
|
|
255
|
+
// Always return screenshot as base64 string
|
|
256
|
+
if (typeof computer.screenshot === 'function') {
|
|
257
|
+
screenshot = await computer.screenshot();
|
|
258
|
+
if (typeof screenshot !== 'undefined') {
|
|
259
|
+
return screenshot;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
throw new Error('Computer does not implement screenshot()');
|
|
263
|
+
}
|
|
264
|
+
function toErrorMessage(error) {
|
|
265
|
+
if (error instanceof Error) {
|
|
266
|
+
return error.message || error.toString();
|
|
267
|
+
}
|
|
268
|
+
try {
|
|
269
|
+
return JSON.stringify(error);
|
|
270
|
+
}
|
|
271
|
+
catch {
|
|
272
|
+
return String(error);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
async function resolveToolApproval(options) {
|
|
276
|
+
const { runContext, toolName, callId, approvalItem, needsApproval, onApproval, } = options;
|
|
277
|
+
if (!needsApproval) {
|
|
278
|
+
return 'approved';
|
|
279
|
+
}
|
|
280
|
+
if (onApproval) {
|
|
281
|
+
const decision = await onApproval(runContext, approvalItem);
|
|
282
|
+
if (decision.approve === true) {
|
|
283
|
+
runContext.approveTool(approvalItem);
|
|
284
|
+
}
|
|
285
|
+
else if (decision.approve === false) {
|
|
286
|
+
runContext.rejectTool(approvalItem);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
const approval = runContext.isToolApproved({
|
|
290
|
+
toolName,
|
|
291
|
+
callId,
|
|
292
|
+
});
|
|
293
|
+
if (approval === true) {
|
|
294
|
+
return 'approved';
|
|
295
|
+
}
|
|
296
|
+
if (approval === false) {
|
|
297
|
+
return 'rejected';
|
|
298
|
+
}
|
|
299
|
+
return 'pending';
|
|
300
|
+
}
|
|
301
|
+
async function handleToolApprovalDecision(options) {
|
|
302
|
+
const { runContext, toolName, callId, approvalItem, needsApproval, onApproval, buildRejectionItem, } = options;
|
|
303
|
+
const approvalState = await resolveToolApproval({
|
|
304
|
+
runContext,
|
|
305
|
+
toolName,
|
|
306
|
+
callId,
|
|
307
|
+
approvalItem,
|
|
308
|
+
needsApproval,
|
|
309
|
+
onApproval,
|
|
310
|
+
});
|
|
311
|
+
if (approvalState === 'rejected') {
|
|
312
|
+
return { status: 'rejected', item: buildRejectionItem() };
|
|
313
|
+
}
|
|
314
|
+
if (approvalState === 'pending') {
|
|
315
|
+
return { status: 'pending', item: approvalItem };
|
|
316
|
+
}
|
|
317
|
+
return { status: 'approved' };
|
|
318
|
+
}
|
|
319
|
+
function emitToolStart(runner, runContext, agent, tool, toolCall) {
|
|
320
|
+
runner.emit('agent_tool_start', runContext, agent, tool, { toolCall });
|
|
321
|
+
if (typeof agent.emit === 'function') {
|
|
322
|
+
agent.emit('agent_tool_start', runContext, tool, { toolCall });
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
function emitToolEnd(runner, runContext, agent, tool, output, toolCall) {
|
|
326
|
+
runner.emit('agent_tool_end', runContext, agent, tool, output, { toolCall });
|
|
327
|
+
if (typeof agent.emit === 'function') {
|
|
328
|
+
agent.emit('agent_tool_end', runContext, tool, output, { toolCall });
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
async function executeShellActions(agent, actions, runner, runContext, customLogger = undefined) {
|
|
332
|
+
const _logger = customLogger ?? logger_1.default;
|
|
333
|
+
const results = [];
|
|
334
|
+
for (const action of actions) {
|
|
335
|
+
const shellTool = action.shell;
|
|
336
|
+
const toolCall = action.toolCall;
|
|
337
|
+
const approvalItem = new items_1.RunToolApprovalItem(toolCall, agent, shellTool.name);
|
|
338
|
+
const approvalDecision = await handleToolApprovalDecision({
|
|
339
|
+
runContext,
|
|
340
|
+
toolName: shellTool.name,
|
|
341
|
+
callId: toolCall.callId,
|
|
342
|
+
approvalItem,
|
|
343
|
+
needsApproval: await shellTool.needsApproval(runContext, toolCall.action, toolCall.callId),
|
|
344
|
+
onApproval: shellTool.onApproval,
|
|
345
|
+
buildRejectionItem: () => {
|
|
346
|
+
const response = TOOL_APPROVAL_REJECTION_MESSAGE;
|
|
347
|
+
const rejectionOutput = {
|
|
348
|
+
stdout: '',
|
|
349
|
+
stderr: response,
|
|
350
|
+
outcome: { type: 'exit', exitCode: null },
|
|
351
|
+
};
|
|
352
|
+
return new items_1.RunToolCallOutputItem({
|
|
353
|
+
type: 'shell_call_output',
|
|
354
|
+
callId: toolCall.callId,
|
|
355
|
+
output: [rejectionOutput],
|
|
356
|
+
}, agent, response);
|
|
357
|
+
},
|
|
358
|
+
});
|
|
359
|
+
if (approvalDecision.status !== 'approved') {
|
|
360
|
+
results.push(approvalDecision.item);
|
|
361
|
+
continue;
|
|
362
|
+
}
|
|
363
|
+
emitToolStart(runner, runContext, agent, shellTool, toolCall);
|
|
364
|
+
let shellOutputs;
|
|
365
|
+
const providerMeta = {};
|
|
366
|
+
let maxOutputLength;
|
|
367
|
+
try {
|
|
368
|
+
const shellResult = await shellTool.shell.run(toolCall.action);
|
|
369
|
+
shellOutputs = shellResult.output ?? [];
|
|
370
|
+
if (shellResult.providerData) {
|
|
371
|
+
Object.assign(providerMeta, shellResult.providerData);
|
|
372
|
+
}
|
|
373
|
+
if (typeof shellResult.maxOutputLength === 'number') {
|
|
374
|
+
maxOutputLength = shellResult.maxOutputLength;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
catch (err) {
|
|
378
|
+
const errorText = toErrorMessage(err);
|
|
379
|
+
shellOutputs = [
|
|
380
|
+
{
|
|
381
|
+
stdout: '',
|
|
382
|
+
stderr: errorText,
|
|
383
|
+
outcome: { type: 'exit', exitCode: null },
|
|
384
|
+
},
|
|
385
|
+
];
|
|
386
|
+
_logger.error('Failed to execute shell action:', err);
|
|
387
|
+
}
|
|
388
|
+
shellOutputs = shellOutputs ?? [];
|
|
389
|
+
emitToolEnd(runner, runContext, agent, shellTool, JSON.stringify(shellOutputs), toolCall);
|
|
390
|
+
const rawItem = {
|
|
391
|
+
type: 'shell_call_output',
|
|
392
|
+
callId: toolCall.callId,
|
|
393
|
+
output: shellOutputs ?? [],
|
|
394
|
+
};
|
|
395
|
+
if (typeof maxOutputLength === 'number') {
|
|
396
|
+
rawItem.maxOutputLength = maxOutputLength;
|
|
397
|
+
}
|
|
398
|
+
if (Object.keys(providerMeta).length > 0) {
|
|
399
|
+
rawItem.providerData = providerMeta;
|
|
400
|
+
}
|
|
401
|
+
results.push(new items_1.RunToolCallOutputItem(rawItem, agent, rawItem.output));
|
|
402
|
+
}
|
|
403
|
+
return results;
|
|
404
|
+
}
|
|
405
|
+
async function executeApplyPatchOperations(agent, actions, runner, runContext, customLogger = undefined) {
|
|
406
|
+
const _logger = customLogger ?? logger_1.default;
|
|
407
|
+
const results = [];
|
|
408
|
+
for (const action of actions) {
|
|
409
|
+
const applyPatchTool = action.applyPatch;
|
|
410
|
+
const toolCall = action.toolCall;
|
|
411
|
+
const approvalItem = new items_1.RunToolApprovalItem(toolCall, agent, applyPatchTool.name);
|
|
412
|
+
const approvalDecision = await handleToolApprovalDecision({
|
|
413
|
+
runContext,
|
|
414
|
+
toolName: applyPatchTool.name,
|
|
415
|
+
callId: toolCall.callId,
|
|
416
|
+
approvalItem,
|
|
417
|
+
needsApproval: await applyPatchTool.needsApproval(runContext, toolCall.operation, toolCall.callId),
|
|
418
|
+
onApproval: applyPatchTool.onApproval,
|
|
419
|
+
buildRejectionItem: () => {
|
|
420
|
+
const response = TOOL_APPROVAL_REJECTION_MESSAGE;
|
|
421
|
+
return new items_1.RunToolCallOutputItem({
|
|
422
|
+
type: 'apply_patch_call_output',
|
|
423
|
+
callId: toolCall.callId,
|
|
424
|
+
status: 'failed',
|
|
425
|
+
output: response,
|
|
426
|
+
}, agent, response);
|
|
427
|
+
},
|
|
428
|
+
});
|
|
429
|
+
if (approvalDecision.status !== 'approved') {
|
|
430
|
+
results.push(approvalDecision.item);
|
|
431
|
+
continue;
|
|
432
|
+
}
|
|
433
|
+
emitToolStart(runner, runContext, agent, applyPatchTool, toolCall);
|
|
434
|
+
let status = 'completed';
|
|
435
|
+
let output = '';
|
|
436
|
+
try {
|
|
437
|
+
let result;
|
|
438
|
+
switch (toolCall.operation.type) {
|
|
439
|
+
case 'create_file':
|
|
440
|
+
result = await applyPatchTool.editor.createFile(toolCall.operation);
|
|
441
|
+
break;
|
|
442
|
+
case 'update_file':
|
|
443
|
+
result = await applyPatchTool.editor.updateFile(toolCall.operation);
|
|
444
|
+
break;
|
|
445
|
+
case 'delete_file':
|
|
446
|
+
result = await applyPatchTool.editor.deleteFile(toolCall.operation);
|
|
447
|
+
break;
|
|
448
|
+
default:
|
|
449
|
+
throw new Error('Unsupported apply_patch operation');
|
|
450
|
+
}
|
|
451
|
+
if (result && typeof result.status === 'string') {
|
|
452
|
+
status = result.status;
|
|
453
|
+
}
|
|
454
|
+
if (result && typeof result.output === 'string') {
|
|
455
|
+
output = result.output;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
catch (err) {
|
|
459
|
+
status = 'failed';
|
|
460
|
+
output = toErrorMessage(err);
|
|
461
|
+
_logger.error('Failed to execute apply_patch operation:', err);
|
|
462
|
+
}
|
|
463
|
+
emitToolEnd(runner, runContext, agent, applyPatchTool, output, toolCall);
|
|
464
|
+
const rawItem = {
|
|
465
|
+
type: 'apply_patch_call_output',
|
|
466
|
+
callId: toolCall.callId,
|
|
467
|
+
status,
|
|
468
|
+
};
|
|
469
|
+
if (output) {
|
|
470
|
+
rawItem.output = output;
|
|
471
|
+
}
|
|
472
|
+
results.push(new items_1.RunToolCallOutputItem(rawItem, agent, output));
|
|
473
|
+
}
|
|
474
|
+
return results;
|
|
475
|
+
}
|
|
476
|
+
/**
|
|
477
|
+
* @internal
|
|
478
|
+
* Executes any computer-use actions emitted by the model and returns the resulting items so
|
|
479
|
+
* the run history reflects the computer session.
|
|
480
|
+
*/
|
|
481
|
+
async function executeComputerActions(agent, actions, runner, runContext, customLogger = undefined) {
|
|
482
|
+
const _logger = customLogger ?? logger_1.default;
|
|
483
|
+
const results = [];
|
|
484
|
+
for (const action of actions) {
|
|
485
|
+
const toolCall = action.toolCall;
|
|
486
|
+
// Hooks: on_tool_start (global + agent)
|
|
487
|
+
emitToolStart(runner, runContext, agent, action.computer, toolCall);
|
|
488
|
+
// Run the action and get screenshot
|
|
489
|
+
let output;
|
|
490
|
+
try {
|
|
491
|
+
const computer = await (0, tool_1.resolveComputer)({
|
|
492
|
+
tool: action.computer,
|
|
493
|
+
runContext,
|
|
494
|
+
});
|
|
495
|
+
output = await _runComputerActionAndScreenshot(computer, toolCall);
|
|
496
|
+
}
|
|
497
|
+
catch (err) {
|
|
498
|
+
_logger.error('Failed to execute computer action:', err);
|
|
499
|
+
output = '';
|
|
500
|
+
}
|
|
501
|
+
// Hooks: on_tool_end (global + agent)
|
|
502
|
+
emitToolEnd(runner, runContext, agent, action.computer, output, toolCall);
|
|
503
|
+
// Return the screenshot as a data URL when available; fall back to an empty string on failures.
|
|
504
|
+
const imageUrl = output ? `data:image/png;base64,${output}` : '';
|
|
505
|
+
const rawItem = {
|
|
506
|
+
type: 'computer_call_result',
|
|
507
|
+
callId: toolCall.callId,
|
|
508
|
+
output: { type: 'computer_screenshot', data: imageUrl },
|
|
509
|
+
};
|
|
510
|
+
results.push(new items_1.RunToolCallOutputItem(rawItem, agent, imageUrl));
|
|
511
|
+
}
|
|
512
|
+
return results;
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* @internal
|
|
516
|
+
* Drives handoff calls by invoking the downstream agent and capturing any generated items so
|
|
517
|
+
* the current agent can continue with the new context.
|
|
518
|
+
*/
|
|
519
|
+
async function executeHandoffCalls(agent, originalInput, preStepItems, newStepItems, newResponse, runHandoffs, runner, runContext) {
|
|
520
|
+
newStepItems = [...newStepItems];
|
|
521
|
+
if (runHandoffs.length === 0) {
|
|
522
|
+
logger_1.default.warn('Incorrectly called executeHandoffCalls with no handoffs. This should not happen. Moving on.');
|
|
523
|
+
return new steps_1.SingleStepResult(originalInput, newResponse, preStepItems, newStepItems, { type: 'next_step_run_again' });
|
|
524
|
+
}
|
|
525
|
+
if (runHandoffs.length > 1) {
|
|
526
|
+
// multiple handoffs. Ignoring all but the first one by adding reject responses for those
|
|
527
|
+
const outputMessage = 'Multiple handoffs detected, ignoring this one.';
|
|
528
|
+
for (let i = 1; i < runHandoffs.length; i++) {
|
|
529
|
+
newStepItems.push(new items_1.RunToolCallOutputItem(getToolCallOutputItem(runHandoffs[i].toolCall, outputMessage), agent, outputMessage));
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
const actualHandoff = runHandoffs[0];
|
|
533
|
+
return (0, createSpans_1.withHandoffSpan)(async (handoffSpan) => {
|
|
534
|
+
const handoff = actualHandoff.handoff;
|
|
535
|
+
const newAgent = await handoff.onInvokeHandoff(runContext, actualHandoff.toolCall.arguments);
|
|
536
|
+
handoffSpan.spanData.to_agent = newAgent.name;
|
|
537
|
+
if (runHandoffs.length > 1) {
|
|
538
|
+
const requestedAgents = runHandoffs.map((h) => h.handoff.agentName);
|
|
539
|
+
handoffSpan.setError({
|
|
540
|
+
message: 'Multiple handoffs requested',
|
|
541
|
+
data: {
|
|
542
|
+
requested_agents: requestedAgents,
|
|
543
|
+
},
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
newStepItems.push(new items_1.RunHandoffOutputItem(getToolCallOutputItem(actualHandoff.toolCall, (0, handoff_1.getTransferMessage)(newAgent)), agent, newAgent));
|
|
547
|
+
runner.emit('agent_handoff', runContext, agent, newAgent);
|
|
548
|
+
agent.emit('agent_handoff', runContext, newAgent);
|
|
549
|
+
const inputFilter = handoff.inputFilter ?? runner.config.handoffInputFilter;
|
|
550
|
+
if (inputFilter) {
|
|
551
|
+
logger_1.default.debug('Filtering inputs for handoff');
|
|
552
|
+
if (typeof inputFilter !== 'function') {
|
|
553
|
+
handoffSpan.setError({
|
|
554
|
+
message: 'Invalid input filter',
|
|
555
|
+
data: {
|
|
556
|
+
details: 'not callable',
|
|
557
|
+
},
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
const handoffInputData = {
|
|
561
|
+
inputHistory: Array.isArray(originalInput)
|
|
562
|
+
? [...originalInput]
|
|
563
|
+
: originalInput,
|
|
564
|
+
preHandoffItems: [...preStepItems],
|
|
565
|
+
newItems: [...newStepItems],
|
|
566
|
+
runContext,
|
|
567
|
+
};
|
|
568
|
+
const filtered = inputFilter(handoffInputData);
|
|
569
|
+
originalInput = filtered.inputHistory;
|
|
570
|
+
preStepItems = filtered.preHandoffItems;
|
|
571
|
+
newStepItems = filtered.newItems;
|
|
572
|
+
}
|
|
573
|
+
return new steps_1.SingleStepResult(originalInput, newResponse, preStepItems, newStepItems, { type: 'next_step_handoff', newAgent });
|
|
574
|
+
}, {
|
|
575
|
+
data: {
|
|
576
|
+
from_agent: agent.name,
|
|
577
|
+
},
|
|
578
|
+
});
|
|
579
|
+
}
|
|
580
|
+
const NOT_FINAL_OUTPUT = {
|
|
581
|
+
isFinalOutput: false,
|
|
582
|
+
isInterrupted: undefined,
|
|
583
|
+
};
|
|
584
|
+
/**
|
|
585
|
+
* Collects approval interruptions from tool execution results and any additional
|
|
586
|
+
* RunItems (e.g., shell/apply_patch approval placeholders).
|
|
587
|
+
*/
|
|
588
|
+
function collectInterruptions(toolResults, additionalItems = []) {
|
|
589
|
+
const interruptions = [];
|
|
590
|
+
for (const item of additionalItems) {
|
|
591
|
+
if (item instanceof items_1.RunToolApprovalItem) {
|
|
592
|
+
interruptions.push(item);
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
for (const result of toolResults) {
|
|
596
|
+
if (result.runItem instanceof items_1.RunToolApprovalItem) {
|
|
597
|
+
interruptions.push(result.runItem);
|
|
598
|
+
}
|
|
599
|
+
if (result.type === 'function_output') {
|
|
600
|
+
if (Array.isArray(result.interruptions)) {
|
|
601
|
+
interruptions.push(...result.interruptions);
|
|
602
|
+
}
|
|
603
|
+
else if (result.agentRunResult) {
|
|
604
|
+
const nestedInterruptions = result.agentRunResult.interruptions;
|
|
605
|
+
if (nestedInterruptions.length > 0) {
|
|
606
|
+
interruptions.push(...nestedInterruptions);
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
return interruptions;
|
|
612
|
+
}
|
|
613
|
+
/**
|
|
614
|
+
* @internal
|
|
615
|
+
* Determines whether tool executions produced a final agent output, triggered an interruption,
|
|
616
|
+
* or whether the agent loop should continue collecting more responses.
|
|
617
|
+
*/
|
|
618
|
+
async function checkForFinalOutputFromTools(agent, toolResults, state, additionalInterruptions = []) {
|
|
619
|
+
if (toolResults.length === 0 && additionalInterruptions.length === 0) {
|
|
620
|
+
return NOT_FINAL_OUTPUT;
|
|
621
|
+
}
|
|
622
|
+
const interruptions = collectInterruptions(toolResults, additionalInterruptions);
|
|
623
|
+
if (interruptions.length > 0) {
|
|
624
|
+
return {
|
|
625
|
+
isFinalOutput: false,
|
|
626
|
+
isInterrupted: true,
|
|
627
|
+
interruptions,
|
|
628
|
+
};
|
|
629
|
+
}
|
|
630
|
+
if (agent.toolUseBehavior === 'run_llm_again') {
|
|
631
|
+
return NOT_FINAL_OUTPUT;
|
|
632
|
+
}
|
|
633
|
+
const firstToolResult = toolResults[0];
|
|
634
|
+
if (agent.toolUseBehavior === 'stop_on_first_tool') {
|
|
635
|
+
if (firstToolResult?.type === 'function_output') {
|
|
636
|
+
const stringOutput = (0, smartString_1.toSmartString)(firstToolResult.output);
|
|
637
|
+
return {
|
|
638
|
+
isFinalOutput: true,
|
|
639
|
+
isInterrupted: undefined,
|
|
640
|
+
finalOutput: stringOutput,
|
|
641
|
+
};
|
|
642
|
+
}
|
|
643
|
+
return NOT_FINAL_OUTPUT;
|
|
644
|
+
}
|
|
645
|
+
const toolUseBehavior = agent.toolUseBehavior;
|
|
646
|
+
if (typeof toolUseBehavior === 'object') {
|
|
647
|
+
const stoppingTool = toolResults.find((r) => toolUseBehavior.stopAtToolNames.includes(r.tool.name));
|
|
648
|
+
if (stoppingTool?.type === 'function_output') {
|
|
649
|
+
const stringOutput = (0, smartString_1.toSmartString)(stoppingTool.output);
|
|
650
|
+
return {
|
|
651
|
+
isFinalOutput: true,
|
|
652
|
+
isInterrupted: undefined,
|
|
653
|
+
finalOutput: stringOutput,
|
|
654
|
+
};
|
|
655
|
+
}
|
|
656
|
+
return NOT_FINAL_OUTPUT;
|
|
657
|
+
}
|
|
658
|
+
if (typeof toolUseBehavior === 'function') {
|
|
659
|
+
return toolUseBehavior(state._context, toolResults);
|
|
660
|
+
}
|
|
661
|
+
throw new errors_1.UserError(`Invalid toolUseBehavior: ${toolUseBehavior}`, state);
|
|
662
|
+
}
|
|
663
|
+
/**
|
|
664
|
+
* Accepts whatever the tool returned and attempts to coerce it into the structured protocol
|
|
665
|
+
* shapes we expose to downstream model adapters (input_text/input_image/input_file). Tools are
|
|
666
|
+
* allowed to return either a single structured object or an array of them; anything else falls
|
|
667
|
+
* back to the legacy string pipeline.
|
|
668
|
+
*/
|
|
669
|
+
function normalizeStructuredToolOutputs(output) {
|
|
670
|
+
if (Array.isArray(output)) {
|
|
671
|
+
const structured = [];
|
|
672
|
+
for (const item of output) {
|
|
673
|
+
const normalized = normalizeStructuredToolOutput(item);
|
|
674
|
+
if (!normalized) {
|
|
675
|
+
return null;
|
|
676
|
+
}
|
|
677
|
+
structured.push(normalized);
|
|
678
|
+
}
|
|
679
|
+
return structured;
|
|
680
|
+
}
|
|
681
|
+
const normalized = normalizeStructuredToolOutput(output);
|
|
682
|
+
return normalized ? [normalized] : null;
|
|
683
|
+
}
|
|
684
|
+
/**
|
|
685
|
+
* Best-effort normalization of a single tool output item. If the object already matches the
|
|
686
|
+
* protocol shape we simply cast it; otherwise we copy the recognised fields into the canonical
|
|
687
|
+
* structure. Returning null lets the caller know we should revert to plain-string handling.
|
|
688
|
+
*/
|
|
689
|
+
function normalizeStructuredToolOutput(value) {
|
|
690
|
+
if (!isRecord(value)) {
|
|
691
|
+
return null;
|
|
692
|
+
}
|
|
693
|
+
const type = value.type;
|
|
694
|
+
if (type === 'text' && typeof value.text === 'string') {
|
|
695
|
+
const output = { type: 'text', text: value.text };
|
|
696
|
+
if (isRecord(value.providerData)) {
|
|
697
|
+
output.providerData = value.providerData;
|
|
698
|
+
}
|
|
699
|
+
return output;
|
|
700
|
+
}
|
|
701
|
+
if (type === 'image') {
|
|
702
|
+
const output = { type: 'image' };
|
|
703
|
+
let imageString;
|
|
704
|
+
let imageFileId;
|
|
705
|
+
const fallbackImageMediaType = isNonEmptyString(value.mediaType)
|
|
706
|
+
? value.mediaType
|
|
707
|
+
: undefined;
|
|
708
|
+
const imageField = value.image;
|
|
709
|
+
if (typeof imageField === 'string' && imageField.length > 0) {
|
|
710
|
+
imageString = imageField;
|
|
711
|
+
}
|
|
712
|
+
else if (isRecord(imageField)) {
|
|
713
|
+
const imageObj = imageField;
|
|
714
|
+
const inlineMediaType = isNonEmptyString(imageObj.mediaType)
|
|
715
|
+
? imageObj.mediaType
|
|
716
|
+
: fallbackImageMediaType;
|
|
717
|
+
if (isNonEmptyString(imageObj.url)) {
|
|
718
|
+
imageString = imageObj.url;
|
|
719
|
+
}
|
|
720
|
+
else if (isNonEmptyString(imageObj.data)) {
|
|
721
|
+
imageString = toInlineImageString(imageObj.data, inlineMediaType);
|
|
722
|
+
}
|
|
723
|
+
else if (imageObj.data instanceof Uint8Array &&
|
|
724
|
+
imageObj.data.length > 0) {
|
|
725
|
+
imageString = toInlineImageString(imageObj.data, inlineMediaType);
|
|
726
|
+
}
|
|
727
|
+
if (!imageString) {
|
|
728
|
+
const candidateId = (isNonEmptyString(imageObj.fileId) && imageObj.fileId) ||
|
|
729
|
+
(isNonEmptyString(imageObj.id) && imageObj.id) ||
|
|
730
|
+
undefined;
|
|
731
|
+
if (candidateId) {
|
|
732
|
+
imageFileId = candidateId;
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
if (!imageString &&
|
|
737
|
+
typeof value.imageUrl === 'string' &&
|
|
738
|
+
value.imageUrl.length > 0) {
|
|
739
|
+
imageString = value.imageUrl;
|
|
740
|
+
}
|
|
741
|
+
if (!imageFileId &&
|
|
742
|
+
typeof value.fileId === 'string' &&
|
|
743
|
+
value.fileId.length > 0) {
|
|
744
|
+
imageFileId = value.fileId;
|
|
745
|
+
}
|
|
746
|
+
if (!imageString &&
|
|
747
|
+
typeof value.data === 'string' &&
|
|
748
|
+
value.data.length > 0) {
|
|
749
|
+
imageString = fallbackImageMediaType
|
|
750
|
+
? toInlineImageString(value.data, fallbackImageMediaType)
|
|
751
|
+
: value.data;
|
|
752
|
+
}
|
|
753
|
+
else if (!imageString &&
|
|
754
|
+
value.data instanceof Uint8Array &&
|
|
755
|
+
value.data.length > 0) {
|
|
756
|
+
imageString = toInlineImageString(value.data, fallbackImageMediaType);
|
|
757
|
+
}
|
|
758
|
+
if (typeof value.detail === 'string' && value.detail.length > 0) {
|
|
759
|
+
output.detail = value.detail;
|
|
760
|
+
}
|
|
761
|
+
if (imageString) {
|
|
762
|
+
output.image = imageString;
|
|
763
|
+
}
|
|
764
|
+
else if (imageFileId) {
|
|
765
|
+
output.image = { fileId: imageFileId };
|
|
766
|
+
}
|
|
767
|
+
else {
|
|
768
|
+
return null;
|
|
769
|
+
}
|
|
770
|
+
if (isRecord(value.providerData)) {
|
|
771
|
+
output.providerData = value.providerData;
|
|
772
|
+
}
|
|
773
|
+
return output;
|
|
774
|
+
}
|
|
775
|
+
if (type === 'file') {
|
|
776
|
+
const fileValue = normalizeFileValue(value);
|
|
777
|
+
if (!fileValue) {
|
|
778
|
+
return null;
|
|
779
|
+
}
|
|
780
|
+
const output = { type: 'file', file: fileValue };
|
|
781
|
+
if (isRecord(value.providerData)) {
|
|
782
|
+
output.providerData = value.providerData;
|
|
783
|
+
}
|
|
784
|
+
return output;
|
|
785
|
+
}
|
|
786
|
+
return null;
|
|
787
|
+
}
|
|
788
|
+
/**
|
|
789
|
+
* Translates the normalized tool output into the protocol `input_*` items. This is the last hop
|
|
790
|
+
* before we hand the data to model-specific adapters, so we generate the exact schema expected by
|
|
791
|
+
* the protocol definitions.
|
|
792
|
+
*/
|
|
793
|
+
function convertStructuredToolOutputToInputItem(output) {
|
|
794
|
+
if (output.type === 'text') {
|
|
795
|
+
const result = {
|
|
796
|
+
type: 'input_text',
|
|
797
|
+
text: output.text,
|
|
798
|
+
};
|
|
799
|
+
if (output.providerData) {
|
|
800
|
+
result.providerData = output.providerData;
|
|
801
|
+
}
|
|
802
|
+
return result;
|
|
803
|
+
}
|
|
804
|
+
if (output.type === 'image') {
|
|
805
|
+
const result = { type: 'input_image' };
|
|
806
|
+
if (typeof output.detail === 'string' && output.detail.length > 0) {
|
|
807
|
+
result.detail = output.detail;
|
|
808
|
+
}
|
|
809
|
+
if (typeof output.image === 'string' && output.image.length > 0) {
|
|
810
|
+
result.image = output.image;
|
|
811
|
+
}
|
|
812
|
+
else if (isRecord(output.image)) {
|
|
813
|
+
const imageObj = output.image;
|
|
814
|
+
const inlineMediaType = isNonEmptyString(imageObj.mediaType)
|
|
815
|
+
? imageObj.mediaType
|
|
816
|
+
: undefined;
|
|
817
|
+
if (isNonEmptyString(imageObj.url)) {
|
|
818
|
+
result.image = imageObj.url;
|
|
819
|
+
}
|
|
820
|
+
else if (isNonEmptyString(imageObj.data)) {
|
|
821
|
+
result.image =
|
|
822
|
+
inlineMediaType && !imageObj.data.startsWith('data:')
|
|
823
|
+
? asDataUrl(imageObj.data, inlineMediaType)
|
|
824
|
+
: imageObj.data;
|
|
825
|
+
}
|
|
826
|
+
else if (imageObj.data instanceof Uint8Array &&
|
|
827
|
+
imageObj.data.length > 0) {
|
|
828
|
+
const base64 = (0, base64_1.encodeUint8ArrayToBase64)(imageObj.data);
|
|
829
|
+
result.image = asDataUrl(base64, inlineMediaType);
|
|
830
|
+
}
|
|
831
|
+
else {
|
|
832
|
+
const referencedId = (isNonEmptyString(imageObj.fileId) && imageObj.fileId) ||
|
|
833
|
+
(isNonEmptyString(imageObj.id) && imageObj.id) ||
|
|
834
|
+
undefined;
|
|
835
|
+
if (referencedId) {
|
|
836
|
+
result.image = { id: referencedId };
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
if (output.providerData) {
|
|
841
|
+
result.providerData = output.providerData;
|
|
842
|
+
}
|
|
843
|
+
return result;
|
|
844
|
+
}
|
|
845
|
+
if (output.type === 'file') {
|
|
846
|
+
const result = { type: 'input_file' };
|
|
847
|
+
const fileValue = output.file;
|
|
848
|
+
if (typeof fileValue === 'string') {
|
|
849
|
+
result.file = fileValue;
|
|
850
|
+
}
|
|
851
|
+
else if (fileValue && typeof fileValue === 'object') {
|
|
852
|
+
const record = fileValue;
|
|
853
|
+
if ('data' in record && record.data) {
|
|
854
|
+
const mediaType = record.mediaType ?? 'text/plain';
|
|
855
|
+
if (typeof record.data === 'string') {
|
|
856
|
+
result.file = asDataUrl(record.data, mediaType);
|
|
857
|
+
}
|
|
858
|
+
else {
|
|
859
|
+
const base64 = (0, base64_1.encodeUint8ArrayToBase64)(record.data);
|
|
860
|
+
result.file = asDataUrl(base64, mediaType);
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
else if (typeof record.url === 'string' && record.url.length > 0) {
|
|
864
|
+
result.file = { url: record.url };
|
|
865
|
+
}
|
|
866
|
+
else {
|
|
867
|
+
const referencedId = (typeof record.id === 'string' &&
|
|
868
|
+
record.id.length > 0 &&
|
|
869
|
+
record.id) ||
|
|
870
|
+
(typeof record.fileId === 'string' && record.fileId.length > 0
|
|
871
|
+
? record.fileId
|
|
872
|
+
: undefined);
|
|
873
|
+
if (referencedId) {
|
|
874
|
+
result.file = { id: referencedId };
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
if (typeof record.filename === 'string' && record.filename.length > 0) {
|
|
878
|
+
result.filename = record.filename;
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
if (output.providerData) {
|
|
882
|
+
result.providerData = output.providerData;
|
|
883
|
+
}
|
|
884
|
+
return result;
|
|
885
|
+
}
|
|
886
|
+
const exhaustiveCheck = output;
|
|
887
|
+
return exhaustiveCheck;
|
|
888
|
+
}
|
|
889
|
+
function normalizeFileValue(value) {
|
|
890
|
+
const directFile = value.file;
|
|
891
|
+
if (typeof directFile === 'string' && directFile.length > 0) {
|
|
892
|
+
return directFile;
|
|
893
|
+
}
|
|
894
|
+
const normalizedObject = normalizeFileObjectCandidate(directFile);
|
|
895
|
+
if (normalizedObject) {
|
|
896
|
+
return normalizedObject;
|
|
897
|
+
}
|
|
898
|
+
const legacyValue = normalizeLegacyFileValue(value);
|
|
899
|
+
if (legacyValue) {
|
|
900
|
+
return legacyValue;
|
|
901
|
+
}
|
|
902
|
+
return null;
|
|
903
|
+
}
|
|
904
|
+
function normalizeFileObjectCandidate(value) {
|
|
905
|
+
if (!isRecord(value)) {
|
|
906
|
+
return null;
|
|
907
|
+
}
|
|
908
|
+
if ('data' in value && value.data !== undefined) {
|
|
909
|
+
const dataValue = value.data;
|
|
910
|
+
const hasStringData = typeof dataValue === 'string' && dataValue.length > 0;
|
|
911
|
+
const hasBinaryData = dataValue instanceof Uint8Array && dataValue.length > 0;
|
|
912
|
+
if (!hasStringData && !hasBinaryData) {
|
|
913
|
+
return null;
|
|
914
|
+
}
|
|
915
|
+
if (!isNonEmptyString(value.mediaType) ||
|
|
916
|
+
!isNonEmptyString(value.filename)) {
|
|
917
|
+
return null;
|
|
918
|
+
}
|
|
919
|
+
return {
|
|
920
|
+
data: typeof dataValue === 'string' ? dataValue : new Uint8Array(dataValue),
|
|
921
|
+
mediaType: value.mediaType,
|
|
922
|
+
filename: value.filename,
|
|
923
|
+
};
|
|
924
|
+
}
|
|
925
|
+
if (isNonEmptyString(value.url)) {
|
|
926
|
+
const result = { url: value.url };
|
|
927
|
+
if (isNonEmptyString(value.filename)) {
|
|
928
|
+
result.filename = value.filename;
|
|
929
|
+
}
|
|
930
|
+
return result;
|
|
931
|
+
}
|
|
932
|
+
const referencedId = (isNonEmptyString(value.id) && value.id) ||
|
|
933
|
+
(isNonEmptyString(value.fileId) && value.fileId);
|
|
934
|
+
if (referencedId) {
|
|
935
|
+
const result = { id: referencedId };
|
|
936
|
+
if (isNonEmptyString(value.filename)) {
|
|
937
|
+
result.filename = value.filename;
|
|
938
|
+
}
|
|
939
|
+
return result;
|
|
940
|
+
}
|
|
941
|
+
return null;
|
|
942
|
+
}
|
|
943
|
+
function normalizeLegacyFileValue(value) {
|
|
944
|
+
const filename = typeof value.filename === 'string' && value.filename.length > 0
|
|
945
|
+
? value.filename
|
|
946
|
+
: undefined;
|
|
947
|
+
const mediaType = typeof value.mediaType === 'string' && value.mediaType.length > 0
|
|
948
|
+
? value.mediaType
|
|
949
|
+
: undefined;
|
|
950
|
+
if (typeof value.fileData === 'string' && value.fileData.length > 0) {
|
|
951
|
+
if (!mediaType || !filename) {
|
|
952
|
+
return null;
|
|
953
|
+
}
|
|
954
|
+
return { data: value.fileData, mediaType, filename };
|
|
955
|
+
}
|
|
956
|
+
if (value.fileData instanceof Uint8Array && value.fileData.length > 0) {
|
|
957
|
+
if (!mediaType || !filename) {
|
|
958
|
+
return null;
|
|
959
|
+
}
|
|
960
|
+
return { data: new Uint8Array(value.fileData), mediaType, filename };
|
|
961
|
+
}
|
|
962
|
+
if (typeof value.fileUrl === 'string' && value.fileUrl.length > 0) {
|
|
963
|
+
const result = { url: value.fileUrl };
|
|
964
|
+
if (filename) {
|
|
965
|
+
result.filename = filename;
|
|
966
|
+
}
|
|
967
|
+
return result;
|
|
968
|
+
}
|
|
969
|
+
if (typeof value.fileId === 'string' && value.fileId.length > 0) {
|
|
970
|
+
const result = { id: value.fileId };
|
|
971
|
+
if (filename) {
|
|
972
|
+
result.filename = filename;
|
|
973
|
+
}
|
|
974
|
+
return result;
|
|
975
|
+
}
|
|
976
|
+
return null;
|
|
977
|
+
}
|
|
978
|
+
function isRecord(value) {
|
|
979
|
+
return typeof value === 'object' && value !== null;
|
|
980
|
+
}
|
|
981
|
+
function isNonEmptyString(value) {
|
|
982
|
+
return typeof value === 'string' && value.length > 0;
|
|
983
|
+
}
|
|
984
|
+
function toInlineImageString(data, mediaType) {
|
|
985
|
+
if (typeof data === 'string') {
|
|
986
|
+
if (mediaType && !data.startsWith('data:')) {
|
|
987
|
+
return asDataUrl(data, mediaType);
|
|
988
|
+
}
|
|
989
|
+
return data;
|
|
990
|
+
}
|
|
991
|
+
const base64 = (0, base64_1.encodeUint8ArrayToBase64)(data);
|
|
992
|
+
return asDataUrl(base64, mediaType);
|
|
993
|
+
}
|
|
994
|
+
function asDataUrl(base64, mediaType) {
|
|
995
|
+
return mediaType ? `data:${mediaType};base64,${base64}` : base64;
|
|
996
|
+
}
|
|
997
|
+
//# sourceMappingURL=toolExecution.js.map
|