Skip to content

feat: expose the wrapped callable on FunctionTool (closes #3381)#3692

Closed
fede-kamel wants to merge 2 commits into
openai:mainfrom
fede-kamel:feat/function-tool-expose-callable
Closed

feat: expose the wrapped callable on FunctionTool (closes #3381)#3692
fede-kamel wants to merge 2 commits into
openai:mainfrom
fede-kamel:feat/function-tool-expose-callable

Conversation

@fede-kamel

Copy link
Copy Markdown

Summary

Adds a public FunctionTool.function attribute that holds the original Python callable wrapped by @function_tool.

Today the wrapped function is only reachable by walking the closure of on_invoke_tool (...on_invoke_tool._invoke_tool_impl.__closure__), which is brittle and got an extra hop in 0.16 with the failure-handling indirection. This gives code outside the Agents runtime a stable hook to introspect, directly test, or re-run a tool's body without constructing a ToolContext and doing a JSON encode/decode cycle.

  • New field is None for tools not backed by a plain function (agent-as-tool, hosted-tool wrappers), so the attribute is always present and safe to check.
  • Added as a keyword-only dataclass field, so it does not change the positional constructor order of FunctionTool.
  • Documented via the field docstring (renders in the API reference).

This revives the approach from #2146 (which was closed only over an unrelated pytest fixture-collection regression, not the concept). Happy to rename to func or also wire __wrapped__ for inspect.unwrap() if preferred.

Test plan

  • New tests/test_function_tool_exposes_function.py: sync + async tools expose a runnable .function; directly-constructed tools expose None.
  • tests/test_function_tool.py (49 tests) still pass — no regression.
  • make format, make lint, make typecheck (mypy + pyright) clean.

Issue number

Closes #3381

Checks

  • I've added new tests (if relevant)
  • I've added/updated the relevant documentation
  • I've run make lint and make format
  • I've made sure tests pass

Add a public FunctionTool.function attribute holding the original Python
callable that @function_tool wrapped (None for tools not backed by a plain
function). Gives code outside the runtime a stable hook to introspect,
directly test, or re-run the underlying function without a ToolContext/JSON
round-trip.

Closes openai#3381
@fede-kamel fede-kamel force-pushed the feat/function-tool-expose-callable branch from dbd627d to a76a6da Compare June 25, 2026 22:02
@seratch seratch added duplicate This issue or pull request already exists feature:core labels Jun 25, 2026
@seratch seratch changed the title Expose the wrapped callable on FunctionTool (closes #3381) feat: expose the wrapped callable on FunctionTool (closes #3381) Jun 25, 2026
@fede-kamel

Copy link
Copy Markdown
Author

Following up on the duplicate label — agreed, this overlaps with the earlier #3396, which exposes the same original callable (there as FunctionTool.func; here as FunctionTool.function). The implementations are close to equivalent, so I'm happy to close this one in favor of #3396 if that's the preferred candidate — or to fold anything useful from this PR's tests into it. Whichever keeps the review load smallest.

@fede-kamel

Copy link
Copy Markdown
Author

Closing in favor of the earlier #3396, which covers the same ground. Hope the extra test angles here are useful as a reference if needed.

@fede-kamel fede-kamel closed this Jul 7, 2026
@fede-kamel fede-kamel deleted the feat/function-tool-expose-callable branch July 7, 2026 00:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

duplicate This issue or pull request already exists feature:core

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Provide stable public access to the underlying function on FunctionTool

2 participants