Skip to content

Commit 40c1709

Browse files
authored
fix(agents-core): respect tracingDisabled for function tool calls (#1000)
1 parent 1ba7510 commit 40c1709

File tree

2 files changed

+147
-146
lines changed

2 files changed

+147
-146
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
'@openai/agents-core': patch
3+
---
4+
5+
fix(agents-core): respect tracingDisabled for function tool calls
6+
7+
`buildApprovalRejectionResult` and `runApprovedFunctionTool` called
8+
`withFunctionSpan()` directly, bypassing the `tracingDisabled` /
9+
`getCurrentTrace()` guard that the existing `withToolFunctionSpan` helper
10+
provides. This caused span creation even when `tracingDisabled: true` was
11+
set in `RunConfig`, and could trigger "No existing trace found" errors.
12+
13+
Both functions now use `withToolFunctionSpan`, consistent with
14+
`executeShellActions`, `executeApplyPatchOperations`, and
15+
`executeComputerActions`.

packages/agents-core/src/runner/toolExecution.ts

Lines changed: 132 additions & 146 deletions
Original file line numberDiff line numberDiff line change
@@ -272,47 +272,40 @@ async function buildApprovalRejectionResult<TContext>(
272272
toolRun: ToolRunFunction<TContext>,
273273
): Promise<FunctionToolResult<TContext>> {
274274
const { agent, runner, state, toolErrorFormatter } = deps;
275-
return withFunctionSpan(
276-
async (span) => {
277-
const response = await resolveApprovalRejectionMessage({
278-
runContext: state._context,
279-
toolType: 'function',
280-
toolName: toolRun.tool.name,
281-
callId: toolRun.toolCall.callId,
282-
toolErrorFormatter,
283-
});
284-
const traceErrorMessage = runner.config.traceIncludeSensitiveData
285-
? response
286-
: TOOL_APPROVAL_REJECTION_MESSAGE;
287-
288-
span.setError({
289-
message: traceErrorMessage,
290-
data: {
291-
tool_name: toolRun.tool.name,
292-
error: `Tool execution for ${toolRun.toolCall.callId} was manually rejected by user.`,
293-
},
294-
});
275+
return withToolFunctionSpan(runner, toolRun.tool.name, async (span) => {
276+
const response = await resolveApprovalRejectionMessage({
277+
runContext: state._context,
278+
toolType: 'function',
279+
toolName: toolRun.tool.name,
280+
callId: toolRun.toolCall.callId,
281+
toolErrorFormatter,
282+
});
283+
const traceErrorMessage = runner.config.traceIncludeSensitiveData
284+
? response
285+
: TOOL_APPROVAL_REJECTION_MESSAGE;
295286

296-
if (runner.config.traceIncludeSensitiveData) {
297-
span.spanData.output = response;
298-
}
299-
return {
300-
type: 'function_output' as const,
301-
tool: toolRun.tool,
302-
output: response,
303-
runItem: new RunToolCallOutputItem(
304-
getToolCallOutputItem(toolRun.toolCall, response),
305-
agent,
306-
response,
307-
),
308-
};
309-
},
310-
{
287+
span?.setError({
288+
message: traceErrorMessage,
311289
data: {
312-
name: toolRun.tool.name,
290+
tool_name: toolRun.tool.name,
291+
error: `Tool execution for ${toolRun.toolCall.callId} was manually rejected by user.`,
313292
},
314-
},
315-
);
293+
});
294+
295+
if (span && runner.config.traceIncludeSensitiveData) {
296+
span.spanData.output = response;
297+
}
298+
return {
299+
type: 'function_output' as const,
300+
tool: toolRun.tool,
301+
output: response,
302+
runItem: new RunToolCallOutputItem(
303+
getToolCallOutputItem(toolRun.toolCall, response),
304+
agent,
305+
response,
306+
),
307+
};
308+
});
316309
}
317310

318311
async function handleFunctionApproval<TContext>(
@@ -353,132 +346,125 @@ async function runApprovedFunctionTool<TContext>(
353346
toolRun: ToolRunFunction<TContext>,
354347
): Promise<FunctionToolResult<TContext>> {
355348
const { agent, runner, state } = deps;
356-
return withFunctionSpan(
357-
async (span) => {
358-
if (runner.config.traceIncludeSensitiveData) {
359-
span.spanData.input = toolRun.toolCall.arguments;
360-
}
349+
return withToolFunctionSpan(runner, toolRun.tool.name, async (span) => {
350+
if (span && runner.config.traceIncludeSensitiveData) {
351+
span.spanData.input = toolRun.toolCall.arguments;
352+
}
361353

362-
try {
363-
const inputGuardrailResult = await runToolInputGuardrails({
364-
guardrails: toolRun.tool.inputGuardrails,
354+
try {
355+
const inputGuardrailResult = await runToolInputGuardrails({
356+
guardrails: toolRun.tool.inputGuardrails,
357+
context: state._context,
358+
agent,
359+
toolCall: toolRun.toolCall,
360+
onResult: (result) => {
361+
state._toolInputGuardrailResults.push(result);
362+
},
363+
});
364+
365+
emitToolStart(
366+
runner,
367+
state._context,
368+
agent,
369+
toolRun.tool,
370+
toolRun.toolCall,
371+
);
372+
373+
let toolOutput: unknown;
374+
if (inputGuardrailResult.type === 'reject') {
375+
toolOutput = inputGuardrailResult.message;
376+
} else {
377+
const resumeState = state.getPendingAgentToolRun(
378+
toolRun.tool.name,
379+
toolRun.toolCall.callId,
380+
);
381+
toolOutput = await invokeFunctionTool({
382+
tool: toolRun.tool,
383+
runContext: state._context,
384+
input: toolRun.toolCall.arguments,
385+
details: { toolCall: toolRun.toolCall, resumeState },
386+
});
387+
toolOutput = await runToolOutputGuardrails({
388+
guardrails: toolRun.tool.outputGuardrails,
365389
context: state._context,
366390
agent,
367391
toolCall: toolRun.toolCall,
392+
toolOutput,
368393
onResult: (result) => {
369-
state._toolInputGuardrailResults.push(result);
394+
state._toolOutputGuardrailResults.push(result);
370395
},
371396
});
397+
}
398+
const stringResult = toSmartString(toolOutput);
399+
400+
emitToolEnd(
401+
runner,
402+
state._context,
403+
agent,
404+
toolRun.tool,
405+
stringResult,
406+
toolRun.toolCall,
407+
);
372408

373-
emitToolStart(
374-
runner,
375-
state._context,
409+
if (span && runner.config.traceIncludeSensitiveData) {
410+
span.spanData.output = stringResult;
411+
}
412+
413+
const functionResult: FunctionToolResult<TContext> = {
414+
type: 'function_output' as const,
415+
tool: toolRun.tool,
416+
output: toolOutput,
417+
runItem: new RunToolCallOutputItem(
418+
getToolCallOutputItem(toolRun.toolCall, toolOutput),
376419
agent,
377-
toolRun.tool,
378-
toolRun.toolCall,
379-
);
420+
toolOutput,
421+
),
422+
};
380423

381-
let toolOutput: unknown;
382-
if (inputGuardrailResult.type === 'reject') {
383-
toolOutput = inputGuardrailResult.message;
424+
const nestedRunResult = consumeAgentToolRunResult(toolRun.toolCall) as
425+
| RunResult<TContext, Agent<TContext, any>>
426+
| undefined;
427+
if (nestedRunResult) {
428+
functionResult.agentRunResult = nestedRunResult;
429+
const nestedInterruptions = nestedRunResult.interruptions;
430+
if (nestedInterruptions.length > 0) {
431+
functionResult.interruptions = nestedInterruptions;
432+
state.setPendingAgentToolRun(
433+
toolRun.tool.name,
434+
toolRun.toolCall.callId,
435+
nestedRunResult.state.toString(),
436+
);
384437
} else {
385-
const resumeState = state.getPendingAgentToolRun(
438+
state.clearPendingAgentToolRun(
386439
toolRun.tool.name,
387440
toolRun.toolCall.callId,
388441
);
389-
toolOutput = await invokeFunctionTool({
390-
tool: toolRun.tool,
391-
runContext: state._context,
392-
input: toolRun.toolCall.arguments,
393-
details: { toolCall: toolRun.toolCall, resumeState },
394-
});
395-
toolOutput = await runToolOutputGuardrails({
396-
guardrails: toolRun.tool.outputGuardrails,
397-
context: state._context,
398-
agent,
399-
toolCall: toolRun.toolCall,
400-
toolOutput,
401-
onResult: (result) => {
402-
state._toolOutputGuardrailResults.push(result);
403-
},
404-
});
405-
}
406-
const stringResult = toSmartString(toolOutput);
407-
408-
emitToolEnd(
409-
runner,
410-
state._context,
411-
agent,
412-
toolRun.tool,
413-
stringResult,
414-
toolRun.toolCall,
415-
);
416-
417-
if (runner.config.traceIncludeSensitiveData) {
418-
span.spanData.output = stringResult;
419-
}
420-
421-
const functionResult: FunctionToolResult<TContext> = {
422-
type: 'function_output' as const,
423-
tool: toolRun.tool,
424-
output: toolOutput,
425-
runItem: new RunToolCallOutputItem(
426-
getToolCallOutputItem(toolRun.toolCall, toolOutput),
427-
agent,
428-
toolOutput,
429-
),
430-
};
431-
432-
const nestedRunResult = consumeAgentToolRunResult(toolRun.toolCall) as
433-
| RunResult<TContext, Agent<TContext, any>>
434-
| undefined;
435-
if (nestedRunResult) {
436-
functionResult.agentRunResult = nestedRunResult;
437-
const nestedInterruptions = nestedRunResult.interruptions;
438-
if (nestedInterruptions.length > 0) {
439-
functionResult.interruptions = nestedInterruptions;
440-
state.setPendingAgentToolRun(
441-
toolRun.tool.name,
442-
toolRun.toolCall.callId,
443-
nestedRunResult.state.toString(),
444-
);
445-
} else {
446-
state.clearPendingAgentToolRun(
447-
toolRun.tool.name,
448-
toolRun.toolCall.callId,
449-
);
450-
}
451442
}
443+
}
452444

453-
return functionResult;
454-
} catch (error) {
455-
span.setError({
456-
message: 'Error running tool',
457-
data: {
458-
tool_name: toolRun.tool.name,
459-
error: String(error),
460-
},
461-
});
445+
return functionResult;
446+
} catch (error) {
447+
span?.setError({
448+
message: 'Error running tool',
449+
data: {
450+
tool_name: toolRun.tool.name,
451+
error: String(error),
452+
},
453+
});
462454

463-
const errorResult = String(error);
464-
emitToolEnd(
465-
runner,
466-
state._context,
467-
agent,
468-
toolRun.tool,
469-
errorResult,
470-
toolRun.toolCall,
471-
);
455+
const errorResult = String(error);
456+
emitToolEnd(
457+
runner,
458+
state._context,
459+
agent,
460+
toolRun.tool,
461+
errorResult,
462+
toolRun.toolCall,
463+
);
472464

473-
throw error;
474-
}
475-
},
476-
{
477-
data: {
478-
name: toolRun.tool.name,
479-
},
480-
},
481-
);
465+
throw error;
466+
}
467+
});
482468
}
483469

484470
/**

0 commit comments

Comments
 (0)