Skip to content

feat: add opt-in ToolCache for caching tool invocation results in ToolInvoker and Agent#11824

Open
Kunal-Somani wants to merge 2 commits into
deepset-ai:mainfrom
Kunal-Somani:feat/tool-cache
Open

feat: add opt-in ToolCache for caching tool invocation results in ToolInvoker and Agent#11824
Kunal-Somani wants to merge 2 commits into
deepset-ai:mainfrom
Kunal-Somani:feat/tool-cache

Conversation

@Kunal-Somani

Copy link
Copy Markdown
Contributor

Related Issues

Proposed Changes: Adds an opt-in ToolCache so ToolInvoker and Agent can avoid re-invoking the same tool call multiple times within an agent loop (e.g. re-fetching a document already fetched a few steps earlier).

  • New haystack/tools/tool_cache.py: ToolCache, ToolCacheBackend (ABC), InMemoryToolCache (default backend), and ToolCacheStats (hits/misses/calls_saved).
  • Tool gains a cacheable: bool = False field — caching is opt-in per tool so write-effecting tools never accidentally serve a stale cached result for a side-effecting call. ComponentTool inherits and serializes this field too.
  • ToolInvoker accepts an optional tool_cache param. Cache lookups happen against the original LLM-provided arguments (not state-injected/streaming-callback-injected ones) so identical logical calls hit the cache consistently. Cache hits skip invocation entirely while keeping the existing ThreadPoolExecutor/future-based concurrent execution path unchanged.
  • Agent accepts the same tool_cache param and passes it straight through to its internal ToolInvoker. When configured, run()/run_async() include a tool_cache_stats key in their output dict with the run's hit/miss/calls_saved counts.
  • tool_cache is intentionally excluded from to_dict()/from_dict() on both ToolInvoker and Agent — cache backends are runtime objects, not serializable configuration.

How did you test it?

  • New test/tools/test_tool_cache.py (15 tests): ToolCacheStats, InMemoryToolCache get/set/clear, make_cache_key determinism, ToolCache hit/miss/TTL-expiry/scope-validation.
  • New TestToolInvokerCaching class in test_tool_invoker.py (3 tests): cacheable tool's second identical call is served from cache (function invoked once, not twice); non-cacheable tool always invokes; different arguments produce cache misses.
  • New test in test_agent.py: tool_cache_stats appears in Agent.run() output when a cache is configured.
  • Updated existing to_dict()/serialization test fixtures across 9 files to include the new cacheable: False field on serialized Tool objects (test_tool.py, test_component_tool.py, test_agent.py, test_agent_breakpoints.py, test_agent_hitl.py, and the Azure/HuggingFace/OpenAI chat generator tests) — pure fixture updates, no behavior changes in those files.
  • Full local test suite: PYTHONPATH="" hatch run test:unit test — 5307 passed, 4 skipped, 0 failed.
  • hatch run fmt and hatch run test:types clean.

Notes for the reviewer

Not a breaking change — cacheable defaults to False and tool_cache defaults to None on both ToolInvoker and Agent, so existing behavior is unchanged unless a cache is explicitly configured.

Checklist

  • I have read the contributors guidelines and the code of conduct.
  • I have updated the related issue with new insights and changes.
  • I have added unit tests and updated the docstrings.
  • I've used one of the conventional commit types for my PR title: fix:, feat:, build:, chore:, ci:, docs:, style:, refactor:, perf:, test: and added ! in case the PR includes breaking changes.
  • I have documented my code.
  • I have added a release note file, following the contributors guidelines.
  • I have run pre-commit hooks and fixed any issue.

@Kunal-Somani Kunal-Somani requested a review from a team as a code owner June 29, 2026 18:17
@Kunal-Somani Kunal-Somani requested review from julian-risch and removed request for a team June 29, 2026 18:17
@vercel

vercel Bot commented Jun 29, 2026

Copy link
Copy Markdown

@Kunal-Somani is attempting to deploy a commit to the deepset Team on Vercel.

A member of the Team first needs to authorize it.

@github-actions github-actions Bot added topic:tests type:documentation Improvements on the docs labels Jun 29, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Coverage report

Click to see where and how coverage changed

FileStatementsMissingCoverageCoverage
(new stmts)
Lines missing
  haystack/components/agents
  agent.py 1246
  haystack/components/tools
  tool_invoker.py 868, 877
  haystack/tools
  component_tool.py
  tool.py
  tool_cache.py 38-39
Project Total  

This report was generated by python-coverage-comment-action

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

topic:tests type:documentation Improvements on the docs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cache tool results inside Agent loops (avoid duplicate identical tool calls)

1 participant