豆豆友情提示:这是一个非官方 GitHub 代理镜像,主要用于网络测试或访问加速。请勿在此进行登录、注册或处理任何敏感信息。进行这些操作请务必访问官方网站 github.com。 Raw 内容也通过此代理提供。
Skip to content

Commit 73b9a9f

Browse files
mvanhornclaude
andcommitted
fix(schema): reject context param not immediately after self/cls
The self_or_cls_skipped flag persisted across all remaining params, so `def f(self, x: int, ctx: RunContextWrapper)` incorrectly passed validation. Now only the param at index 1 (immediately after self/cls) is treated as the effective first param. Adds a test for this edge case. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 008294b commit 73b9a9f

File tree

2 files changed

+17
-4
lines changed

2 files changed

+17
-4
lines changed

src/agents/function_schema.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -306,14 +306,15 @@ def function_schema(
306306
filtered_params.append((first_name, first_param))
307307

308308
# For parameters other than the first, raise error if any use RunContextWrapper or ToolContext
309-
# (unless self/cls was skipped, in which case the second param is the effective first param).
310-
for name, param in params[1:]:
309+
# (unless self/cls was skipped, in which case ONLY the param immediately after self/cls is
310+
# treated as the effective first param).
311+
for idx, (name, param) in enumerate(params[1:]):
311312
ann = type_hints.get(name, param.annotation)
312313
if ann != inspect._empty:
313314
origin = get_origin(ann) or ann
314315
if origin is RunContextWrapper or origin is ToolContext:
315-
if self_or_cls_skipped and not takes_context:
316-
# self/cls was the first param, so this is the effective first param
316+
if self_or_cls_skipped and not takes_context and idx == 0:
317+
# self/cls was the first param and this is immediately after it
317318
takes_context = True
318319
self_or_cls_skipped = False
319320
continue

tests/test_function_schema.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -934,6 +934,18 @@ def greet(self, ctx: RunContextWrapper[None], name: str) -> str:
934934
assert fs.takes_context is True
935935

936936

937+
def test_method_context_not_immediately_after_self_raises():
938+
"""Test that RunContextWrapper at position 3+ (not immediately after self) raises UserError."""
939+
940+
class MyTools:
941+
def greet(self, name: str, ctx: RunContextWrapper[None]) -> str:
942+
return f"Hello, {name}"
943+
944+
obj = MyTools()
945+
with pytest.raises(UserError, match="non-first position"):
946+
function_schema(obj.greet, use_docstring_info=False)
947+
948+
937949
def test_regular_unannotated_first_param_still_included():
938950
"""Test that a regular unannotated first param (not self/cls) is still included."""
939951

0 commit comments

Comments
 (0)