Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

openai_agents: tool wrapper is re-applied on every turn

未关闭
#7,301 2 条评论 0 个 reaction 已指派 1 人 在 GitHub 查看

@alexander-alderman-webb 已经在做这个了。

开始于 2026年8月31日。

评估

这个 Issue 还没有评估数据。

描述

Bug Python Spans
How do you use Sentry?

Sentry SaaS (sentry.io)

Version

2.68.1

Steps to Reproduce

We ran into the tool-rebuild problem that #6961 fixed. Our agent crash-looped on UserError: ToolSearchTool() requires at least one searchable Responses surface, because defer_loading came back False on every tool. Moving to 2.67.0 fixed it for us, and the switch to RunHooks in #6994 looks like the right call.

While reading that fix I noticed one thing still worth reporting in patches/tools.py. It now sets on_invoke_tool in place:

tool.on_invoke_tool = create_wrapped_invoke(tool, original_on_invoke)

get_all_tools returns the agent's own tool objects and runs once per turn, so the wrapper goes on again on each turn and the previous one stays underneath it.

That file is only wired up for openai-agents < 0.3.2, so this repro calls _get_all_tools directly with a stub standing in for the original:

import asyncio, sentry_sdk
sentry_sdk.init(dsn="https://a@b.ingest.sentry.io/1", traces_sample_rate=1.0)
from sentry_sdk.integrations.openai_agents.patches.tools import _get_all_tools
from agents import Agent, FunctionTool

async def invoke(ctx, args): return "ok"

tool = FunctionTool(
    name="t", description="d",
    params_json_schema={"type": "object", "properties": {}, "additionalProperties": False},
    on_invoke_tool=invoke,
)
agent = Agent(name="a", tools=[tool])

async def original(a, c): return list(a.tools)   # stands in for get_all_tools

async def main():
    for turn in range(1, 6):
        await _get_all_tools(original, agent, None)
        f, depth = agent.tools[0].on_invoke_tool, 0
        while hasattr(f, "__wrapped__"):
            f, depth = f.__wrapped__, depth + 1
        print(f"after turn {turn}: wrapper depth = {depth}")

asyncio.run(main())
Expected Result

A tool gets wrapped once, however many turns a run takes, and one tool call produces one gen_ai.execute_tool span.

Actual Result
after turn 1: wrapper depth = 1
after turn 2: wrapper depth = 2
after turn 3: wrapper depth = 3
after turn 4: wrapper depth = 4
after turn 5: wrapper depth = 5

A tool call on turn N opens N nested gen_ai.execute_tool spans, and the wrapping stays on the caller's Agent after the run.

_patch_run_hooks in patches/runner.py already guards against this with _sentry_is_patched. The same flag on the tool would cover it.

Tested on Python 3.13 with openai-agents 0.17.5.

主要语言
Python
星标
2.2k
派生
672
平均合并
22 小时 47 分钟
30 天内合并 PR
224

贡献指南

打开贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

getsentry/sentry-python 的其他 Issue

查看 getsentry/sentry-python 的全部 Issue

相似的 Issue

更多 Python Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。