Skip to content

fix: make ToolContext hashable to match RunContextWrapper#3097

Merged
seratch merged 1 commit intoopenai:mainfrom
ioleksiuk:toolcontext-hash-bug
May 4, 2026
Merged

fix: make ToolContext hashable to match RunContextWrapper#3097
seratch merged 1 commit intoopenai:mainfrom
ioleksiuk:toolcontext-hash-bug

Conversation

@ioleksiuk
Copy link
Copy Markdown
Contributor

Summary

ToolContext (src/agents/tool_context.py) is decorated with bare @dataclass, which defaults to eq=True and therefore sets __hash__ = None, making instances unhashable. Its parent RunContextWrapper (src/agents/run_context.py) is decorated @dataclass(eq=False) and is hashable by identity. The subclass silently dropped the parent's hashability contract, so user code that puts a tool context into a set, dict key, WeakKeyDictionary, lru_cache, etc. — a reasonable thing to do given the parent supports it — fails with TypeError: unhashable type: 'ToolContext'.

Repro against main / v0.15.1:

from agents.run_context import RunContextWrapper
from agents.tool_context import ToolContext

hash(RunContextWrapper(context=None))                                            # OK
hash(ToolContext(context=None, tool_name="t", tool_call_id="c", tool_arguments="{}"))
# TypeError: unhashable type: 'ToolContext'

Fix: switch the decorator to @dataclass(eq=False) so the subclass preserves the parent's identity-based hashing. This is a one-line change with no behavior impact for code that does not rely on hashing — ToolContext already defines its own __init__, so the dataclass-generated __eq__ was the only thing the bare decorator was adding, and identity equality is what the parent intentionally uses.

Test plan

  • Added tests/test_tool_context.py::test_tool_context_is_hashable_like_run_context_wrapper covering hash(ToolContext(...)), equality of repeated hashes, and use as a dict key.
  • uv run pytest tests/test_tool_context.py -v — all 15 tests pass.
  • make format, make lint — clean.
  • make typecheck — no new errors in the touched files (pre-existing errors in voice/sandbox modules are unrelated).
  • make tests — same 12 pre-existing failures as main (sandbox/runloop and voice modules); no new failures.

Issue number

N/A

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

@github-actions github-actions Bot added bug Something isn't working feature:core labels May 3, 2026
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.
@ioleksiuk ioleksiuk force-pushed the toolcontext-hash-bug branch from 32d2f72 to b5f9b8a Compare May 3, 2026 06:44
@seratch
Copy link
Copy Markdown
Member

seratch commented May 4, 2026

@codex review

@seratch seratch added this to the 0.15.x milestone May 4, 2026
@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Another round soon, please!

ℹ️ 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".

@seratch seratch merged commit 63ebf5a into openai:main May 4, 2026
10 checks passed
@ioleksiuk
Copy link
Copy Markdown
Contributor Author

Thank you for the quick response, @seratch ! 🙌

@ioleksiuk ioleksiuk deleted the toolcontext-hash-bug branch May 4, 2026 05:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working feature:core

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants