@openai/agents-core
Version:
The OpenAI Agents SDK is a lightweight yet powerful framework for building multi-agent workflows.
197 lines • 7.61 kB
JavaScript
import { getFunctionToolStateKey, getHostedMcpApprovalRequestIdentity, getHostedMcpApprovalStateKey, } from "./toolIdentity.mjs";
export function getHostedMcpApprovalToolName(toolName, toolCall) {
const identity = getHostedMcpApprovalRequestIdentity(toolCall);
return identity
? (getHostedMcpApprovalStateKey(identity) ?? toolName)
: toolName;
}
export function getToolInvocationCallId(toolCall) {
const hostedMcpIdentity = getHostedMcpApprovalRequestIdentity(toolCall);
if (hostedMcpIdentity?.requestId) {
return hostedMcpIdentity.requestId;
}
if ('callId' in toolCall && typeof toolCall.callId === 'string') {
return toolCall.callId;
}
if (typeof toolCall.id === 'string') {
return toolCall.id;
}
const providerData = toolCall.providerData;
if (typeof providerData?.id === 'string') {
return providerData.id;
}
return typeof providerData?.itemId === 'string'
? providerData.itemId
: undefined;
}
export function getToolInvocationFingerprint(toolName, toolCall) {
return stableStringify({
caller: getCanonicalToolCaller(toolCall),
type: toolCall.type,
toolName: canonicalizeToolName(toolName, toolCall),
payload: getInvocationPayload(toolCall),
});
}
export function getToolInvocationNameFromFingerprint(fingerprint) {
try {
const value = JSON.parse(fingerprint);
return typeof value.toolName === 'string' ? value.toolName : undefined;
}
catch {
return undefined;
}
}
export function validateToolInvocationApproval(context, agent, tool, toolCall) {
const toolName = getCanonicalToolName(tool, toolCall);
return context._validateToolInvocation(agent, toolName, toolCall);
}
export function validateToolInvocationName(context, agent, toolName, toolCall) {
return context._validateToolInvocation(agent, toolName, toolCall);
}
export function getHandoffToolInvocationName(handoffName) {
return `handoff:${handoffName}`;
}
export function validateHandoffToolInvocation(context, agent, handoffName, toolCall) {
return context._validateToolInvocation(agent, getHandoffToolInvocationName(handoffName), toolCall);
}
export function getToolInvocationApproval(context, agent, tool, toolCall) {
const toolName = getCanonicalToolName(tool, toolCall);
const { callId } = context._validateToolInvocation(agent, toolName, toolCall);
return context.isToolApproved({ toolName, callId, agent });
}
export function getToolInvocationRejectionMessage(context, agent, tool, toolCall) {
const toolName = getCanonicalToolName(tool, toolCall);
const { callId } = context._validateToolInvocation(agent, toolName, toolCall);
return context._getFunctionRejectionMessage(toolName, callId, agent);
}
export function getBoundToolInvocationRejectionMessage(context, agent, toolName, toolCall) {
return context._getToolInvocationRejectionMessage(agent, toolName, toolCall);
}
function getCanonicalToolName(tool, toolCall) {
return toolCall.type === 'function_call'
? (getFunctionToolStateKey(tool) ?? tool.name)
: tool.name;
}
function canonicalizeToolName(toolName, toolCall) {
if (toolCall.type === 'hosted_tool_call') {
return getHostedMcpApprovalToolName(toolName, toolCall);
}
if (toolCall.type === 'computer_call' &&
(toolName === 'computer' || toolName === 'computer_use_preview')) {
return 'computer';
}
return toolName;
}
export function getCanonicalToolCaller(toolCall) {
if (toolCall && typeof toolCall === 'object' && 'caller' in toolCall) {
const caller = toolCall.caller;
if (caller?.type === 'program') {
return { type: 'program', callerId: caller.callerId };
}
}
return { type: 'direct' };
}
function getInvocationPayload(toolCall) {
switch (toolCall.type) {
case 'function_call':
return normalizeJsonString(toolCall.arguments);
case 'hosted_tool_call': {
const providerData = toolCall.providerData;
const args = toolCall.arguments ?? providerData?.arguments;
const serverLabel = typeof providerData?.server_label === 'string'
? providerData.server_label
: typeof providerData?.serverLabel === 'string'
? providerData.serverLabel
: undefined;
return {
serverLabel,
arguments: typeof args === 'string' ? normalizeJsonString(args) : args,
};
}
case 'computer_call':
return toolCall.actions ?? toolCall.action;
case 'shell_call':
return toolCall.action;
case 'apply_patch_call':
return toolCall.operation;
}
}
function normalizeJsonString(value) {
try {
return { format: 'json', value: JSON.parse(encodeJsonNumbers(value)) };
}
catch {
return { format: 'raw', value };
}
}
const JSON_TOKEN_PREFIX = '\u0000openai-agents-json:';
function encodeJsonNumbers(value) {
let encoded = '';
let index = 0;
while (index < value.length) {
const character = value[index];
if (character === '"') {
let end = index + 1;
while (end < value.length) {
if (value[end] === '\\') {
end += 2;
continue;
}
if (value[end] === '"') {
end += 1;
break;
}
end += 1;
}
const token = value.slice(index, end);
const decoded = JSON.parse(token);
encoded += decoded.startsWith(JSON_TOKEN_PREFIX)
? JSON.stringify(`${JSON_TOKEN_PREFIX}string:${decoded}`)
: token;
index = end;
continue;
}
if (character === '-' || (character >= '0' && character <= '9')) {
const match = value
.slice(index)
.match(/^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?/);
if (!match) {
throw new Error('Invalid JSON number.');
}
encoded += JSON.stringify(`${JSON_TOKEN_PREFIX}number:${canonicalizeJsonNumber(match[0])}`);
index += match[0].length;
continue;
}
encoded += character;
index += 1;
}
return encoded;
}
function canonicalizeJsonNumber(value) {
const lower = value.toLowerCase();
const [mantissa, exponentText = '0'] = lower.split('e');
const negative = mantissa.startsWith('-');
const unsignedMantissa = negative ? mantissa.slice(1) : mantissa;
const [integer, fraction = ''] = unsignedMantissa.split('.');
let digits = `${integer}${fraction}`.replace(/^0+/, '');
if (digits.length === 0) {
return negative ? '-0' : '0';
}
let exponent = BigInt(exponentText) - BigInt(fraction.length);
while (digits.endsWith('0')) {
digits = digits.slice(0, -1);
exponent += 1n;
}
return `${negative ? '-' : ''}${digits}e${exponent}`;
}
function stableStringify(value) {
return JSON.stringify(value, (_key, currentValue) => {
if (!currentValue ||
typeof currentValue !== 'object' ||
Array.isArray(currentValue)) {
return currentValue;
}
return Object.fromEntries(Object.entries(currentValue).sort(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0)));
});
}
//# sourceMappingURL=toolInvocation.mjs.map