Skip to content

feat: #2228 Add tool origin tracking to ToolCallItem and ToolCallOutputItem#2242

Open
habema wants to merge 2 commits intoopenai:mainfrom
habema:feat/track-tool-origin
Open

feat: #2228 Add tool origin tracking to ToolCallItem and ToolCallOutputItem#2242
habema wants to merge 2 commits intoopenai:mainfrom
habema:feat/track-tool-origin

Conversation

@habema
Copy link
Contributor

@habema habema commented Dec 28, 2025

Adds tool_origin field to ToolCallItem and ToolCallOutputItem to track where function tools came from (regular functions, MCP servers, or agent-as-tool). This helps with debugging and tracing which MCP server handled a call when using multiple servers.

The tool_origin is a ToolOrigin object that contains:

  • type: The origin type (FUNCTION, MCP, or AGENT_AS_TOOL)
  • mcp_server_name: The MCP server name (only set for MCP tools)
  • agent_as_tool_name: The agent name (only set for agent-as-tool)

New tests added

Closes #2228

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

habema added a commit to habema/openai-agents-python that referenced this pull request Dec 28, 2025
Copy link
Member

@seratch seratch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Our current top priority is to merge HITL enhancement, which changes runner internals a lot. So, we may ask you to resolve the conflicts after the big PR is merged.


return run_result.final_output

# Set origin tracking on the FunctionTool created by @function_tool
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it seems the code comment here is incorrect

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to Set origin tracking on run_agent (the FunctionTool returned by @function_tool) for more clarity

mcp_server_name: str | None = None
"""The name of the MCP server. Only set when type is MCP."""

agent_as_tool_name: str | None = None
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This object may receive feature requests to have more properties, so simply having the reference to the agent object may be fine. Same for mcp_server_name too

Copy link
Contributor Author

@habema habema Jan 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense. I've changed the implementation so that the objects are stored. I'm not too sure about the custom __repr__, below is an example of what ToolOrigin would look like with and without it. Let me know what you think.


Without a __repr__ method, ToolOrigin would look like:

  • MCP
    ToolOrigin(type=<ToolOriginType.MCP: 'mcp'>, mcp_server=<tests.mcp.helpers.FakeMCPServer object at 0x...>, agent_as_tool=None)
  • Agent as tool:
    ToolOrigin(type=<ToolOriginType.AGENT_AS_TOOL: 'agent_as_tool'>, mcp_server=None, agent_as_tool=Agent(name='test_agent', handoff_description=None, tools=[], mcp_servers=[], mcp_config={}, instructions='Test agent', prompt=None, handoffs=[], model=<tests.fake_model.FakeModel object at 0x...>, model_settings=ModelSettings(...), input_guardrails=[], output_guardrails=[], output_type=None, hooks=None, tool_use_behavior='run_llm_again', reset_tool_choice=True))
  • Function:
    ToolOrigin(type=<ToolOriginType.FUNCTION: 'function'>, mcp_server=None, agent_as_tool=None)

With the custom __repr__:

  • ToolOrigin(type='mcp', mcp_server_name='test_server')
  • ToolOrigin(type='agent_as_tool', agent_as_tool_name='test_agent')
  • ToolOrigin(type='function')

@seratch seratch added this to the 0.7.x milestone Jan 6, 2026
@seratch
Copy link
Member

seratch commented Jan 22, 2026

@codex review

@seratch seratch modified the milestones: 0.7.x, 0.8.x Jan 22, 2026
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8b2d12a8b0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

- Add ToolOriginType enum and ToolOrigin dataclass
- Add _tool_origin field to FunctionTool
- Set tool_origin for MCP tools and agent-as-tool
- Extract and set tool_origin in ToolCallItem and ToolCallOutputItem creation
- Add comprehensive tests for tool origin tracking
@habema habema force-pushed the feat/track-tool-origin branch from 8cbf13f to edbec4e Compare February 5, 2026 12:23
@habema habema marked this pull request as ready for review February 5, 2026 12:35
@habema habema requested a review from seratch February 5, 2026 12:35
@habema
Copy link
Contributor Author

habema commented Feb 5, 2026

Merged and updated to match new runner internals, and codex comment addressed.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e1b635702c

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +977 to 981
tool_origin = _get_tool_origin_info(tool_run.function_tool)
run_item = ToolCallOutputItem(
output=result,
raw_item=ItemHelpers.tool_call_output_item(tool_run.tool_call, result),
agent=agent,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve tool_origin on rejected function outputs

This path only sets tool_origin when run_single_tool returns a plain value, but approval rejections return a prebuilt FunctionToolResult (run_item=function_rejection_item(...)) and go through the isinstance(result, FunctionToolResult) branch without enrichment, so rejected function calls emit ToolCallOutputItem with tool_origin=None. In runs that depend on approval workflows, this makes output-item origin metadata inconsistent with successful calls and breaks origin-based tracing/auditing.

Useful? React with 👍 / 👎.

description: str | None = None
"""Optional tool description if known at item creation time."""

tool_origin: ToolOrigin | None = field(default=None, repr=False)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Serialize tool_origin in run state snapshots

tool_origin was added to ToolCallItem/ToolCallOutputItem, but run-state persistence does not include it (RunState._serialize_item/_deserialize_items only round-trip core fields like raw_item, agent, output, and description). Any interrupted run that is serialized and resumed will silently drop origin metadata from restored items, so the new tracing signal is lost exactly in resume flows.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Enable to access MCP server name via its converted function tool object

2 participants