diff --git a/.changeset/easy-rivers-build.md b/.changeset/easy-rivers-build.md new file mode 100644 index 00000000..5fcb5c0d --- /dev/null +++ b/.changeset/easy-rivers-build.md @@ -0,0 +1,6 @@ +--- +'@openai/agents-realtime': patch +'@openai/agents-core': patch +--- + +feat: Fix #412 add optional details data to function tool execution diff --git a/packages/agents-core/src/runImplementation.ts b/packages/agents-core/src/runImplementation.ts index 3acff6d9..056ea15f 100644 --- a/packages/agents-core/src/runImplementation.ts +++ b/packages/agents-core/src/runImplementation.ts @@ -741,6 +741,7 @@ export async function executeFunctionToolCalls( const result = await toolRun.tool.invoke( state._context, toolRun.toolCall.arguments, + { toolCall: toolRun.toolCall }, ); // Use string data for tracing and event emitter const stringResult = toSmartString(result); diff --git a/packages/agents-core/src/tool.ts b/packages/agents-core/src/tool.ts index 01581480..e571fde9 100644 --- a/packages/agents-core/src/tool.ts +++ b/packages/agents-core/src/tool.ts @@ -17,6 +17,7 @@ import { getCurrentSpan } from './tracing'; import { RunToolApprovalItem, RunToolCallOutputItem } from './items'; import { toSmartString } from './utils/smartString'; import * as ProviderData from './types/providerData'; +import * as protocol from './types/protocol'; /** * A function that determines if a tool call should be approved. @@ -67,6 +68,7 @@ export type FunctionTool< invoke: ( runContext: RunContext, input: string, + details?: { toolCall: protocol.FunctionCallItem }, ) => Promise; /** @@ -411,6 +413,7 @@ type ToolExecuteFunction< > = ( input: ToolExecuteArgument, context?: RunContext, + details?: { toolCall: protocol.FunctionCallItem }, ) => Promise | unknown; /** @@ -591,6 +594,7 @@ export function tool< async function _invoke( runContext: RunContext, input: string, + details?: { toolCall: protocol.FunctionCallItem }, ): Promise { const [error, parsed] = await safeExecute(() => parser(input)); if (error !== null) { @@ -608,7 +612,7 @@ export function tool< logger.debug(`Invoking tool ${name} with input ${input}`); } - const result = await options.execute(parsed, runContext); + const result = await options.execute(parsed, runContext, details); const stringResult = toSmartString(result); if (logger.dontLogToolData) { @@ -623,8 +627,9 @@ export function tool< async function invoke( runContext: RunContext, input: string, + details?: { toolCall: protocol.FunctionCallItem }, ): Promise { - return _invoke(runContext, input).catch((error) => { + return _invoke(runContext, input, details).catch((error) => { if (toolErrorFunction) { const currentSpan = getCurrentSpan(); currentSpan?.setError({ diff --git a/packages/agents-realtime/src/realtimeSession.ts b/packages/agents-realtime/src/realtimeSession.ts index 2f791c2b..f8cde48d 100644 --- a/packages/agents-realtime/src/realtimeSession.ts +++ b/packages/agents-realtime/src/realtimeSession.ts @@ -486,7 +486,9 @@ export class RealtimeSession< }); this.#context.context.history = JSON.parse(JSON.stringify(this.#history)); // deep copy of the history - const result = await tool.invoke(this.#context, toolCall.arguments); + const result = await tool.invoke(this.#context, toolCall.arguments, { + toolCall, + }); let stringResult: string; if (isBackgroundResult(result)) { // Don't generate a new response, just send the result