Skip to content

Commit b5f9b8a

Browse files
committed
fix: make ToolContext hashable to match RunContextWrapper
ToolContext was decorated with bare @DataClass, which sets __hash__ = None when eq defaults to True. Its parent RunContextWrapper uses @DataClass(eq=False) and is hashable by identity, so the subclass silently dropped the parent's hashability contract. Switch ToolContext to @DataClass(eq=False) to restore consistency with the parent and add a regression test.
1 parent f2fb9ff commit b5f9b8a

2 files changed

Lines changed: 18 additions & 1 deletion

File tree

src/agents/tool_context.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ def _assert_must_pass_tool_arguments() -> str:
3232
_MISSING = object()
3333

3434

35-
@dataclass
35+
@dataclass(eq=False)
3636
class ToolContext(RunContextWrapper[TContext]):
3737
"""The context of a tool call."""
3838

tests/test_tool_context.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,23 @@
1212
from tests.utils.hitl import make_context_wrapper
1313

1414

15+
def test_tool_context_is_hashable_like_run_context_wrapper() -> None:
16+
# RunContextWrapper is declared with @dataclass(eq=False) so instances remain
17+
# hashable by identity. ToolContext inherits from it and must preserve that
18+
# contract; a bare @dataclass on the subclass would set __hash__ = None.
19+
parent: RunContextWrapper[dict[str, object]] = RunContextWrapper(context={})
20+
child: ToolContext[dict[str, object]] = ToolContext(
21+
context={},
22+
tool_name="t",
23+
tool_call_id="call-hash",
24+
tool_arguments="{}",
25+
)
26+
27+
assert hash(parent) == hash(parent)
28+
assert hash(child) == hash(child)
29+
assert {child: "value"}[child] == "value"
30+
31+
1532
def test_tool_context_requires_fields() -> None:
1633
ctx: RunContextWrapper[dict[str, object]] = RunContextWrapper(context={})
1734
with pytest.raises(ValueError):

0 commit comments

Comments
 (0)