Skip to content

Integrations

LangGraph

memory_reuse.integrations.langgraph.cached_node

cached_node(cache: MemoryCache, *, scope: _SCOPE_TYPE = 'global', ttl: int | None = None, key_fields: list[str] | None = None, semantic: bool = False, exact_only: bool = False) -> Callable

Decorator for LangGraph nodes — caches the full node output.

The cache key is derived from the input state (or a subset defined by key_fields). Both sync and async node functions are supported.

This is the supported entry point for node-level output caching and, by extension, node skip-detection. The node-level contract is:

  • Node_Cache_Key = [func.__qualname__, key_data] where key_data is the full state dict, or {f: state.get(f) for f in key_fields} when key_fields is set.
  • A hit returns the stored output and skips the node body; a miss executes the body and stores the result under that key.
  • semantic=True routes through the combined exact-then-semantic :meth:~memory_reuse.core.MemoryCache.lookup / store flow; semantic=False (or exact_only=True) uses exact-only matching.
  • Scope resolution (state → context) and :exc:~memory_reuse.exceptions.ScopeViolationError behaviour are shared with the other cache layers.

Skip-detection within a graph run is the emergent behaviour of decorating each node with cached_node: every decorated node performs its own lookup on its current input, so only nodes whose inputs changed re-execute. Use :meth:~memory_reuse.core.MemoryCache.invalidate_node to force a node to re-run when its upstream state is known to have changed.

Parameters:

Name Type Description Default
cache MemoryCache

The :class:~memory_reuse.core.MemoryCache instance to use.

required
scope _SCOPE_TYPE

Cache scope. For "user" or "session" scope the decorated function or the LangGraph state must expose a user_id / session_id key.

'global'
ttl int | None

Time-to-live in seconds. Overrides the default TTL from :class:~memory_reuse.config.CacheConfig.

None
key_fields list[str] | None

If provided, only these fields from the input state are included when computing the cache key. Useful to ignore ephemeral state fields.

None
semantic bool

When True, route through the combined exact-then-semantic flow (:meth:~memory_reuse.core.MemoryCache.lookup / :meth:~memory_reuse.core.MemoryCache.store) so a reworded but equivalent state can hit the cache. The semantic query text is derived from the key_fields subset (or full state) rendered to a string. Requires semantic_enabled=True on the cache config to have any effect; otherwise behaviour is identical to Phase 1.

False
exact_only bool

When True, force Phase 1 exact-only behaviour for this call site even when the cache has semantic matching enabled. Useful for nodes whose correctness depends on exact input.

False

Returns:

Type Description
Callable

The decorator function.

Raises:

Type Description
ScopeViolationError

At call time, if scope requires a scope ID that cannot be found.

Example::

@cached_node(cache, scope="user", key_fields=["messages"])
async def summarise(state: dict) -> dict:
    return {"summary": llm.invoke(state["messages"])}

memory_reuse.integrations.langgraph.cached_tool

cached_tool(cache: MemoryCache, *, scope: _SCOPE_TYPE = 'global', ttl: int = 300, semantic: bool = False, exact_only: bool = False) -> Callable

Decorator for tool/function calls — caches the return value.

The cache key is derived from the function's qualified name and all of its arguments. Both sync and async callables are supported.

Parameters:

Name Type Description Default
cache MemoryCache

The :class:~memory_reuse.core.MemoryCache instance to use.

required
scope _SCOPE_TYPE

Cache scope.

'global'
ttl int

Time-to-live in seconds. Defaults to 300 (5 minutes).

300
semantic bool

When True, route through the combined exact-then-semantic flow (:meth:~memory_reuse.core.MemoryCache.lookup / :meth:~memory_reuse.core.MemoryCache.store) so a reworded but equivalent call can hit the cache. The semantic query text is derived from the string form of the bound arguments. Requires semantic_enabled=True on the cache config to have any effect; otherwise behaviour is identical to Phase 1.

False
exact_only bool

When True, force Phase 1 exact-only behaviour for this call site even when the cache has semantic matching enabled. Useful for tools with side effects or destructive operations.

False

Returns:

Type Description
Callable

The decorator function.

Raises:

Type Description
ScopeViolationError

At call time, if scope requires a scope ID that cannot be found.

Example::

@cached_tool(cache, scope="global", ttl=600)
async def fetch_weather(city: str) -> dict:
    return weather_api.get(city)

LiteLLM

memory_reuse.integrations.litellm.cached_litellm_completion async

cached_litellm_completion(cache: MemoryCache, *, model: str, messages: list[dict[str, str]], ttl: int = 3600, scope: _SCOPE_TYPE = 'global', user_id: str | None = None, session_id: str | None = None, semantic: bool = False, exact_only: bool = False, **litellm_kwargs: Any) -> Any

Cached wrapper around litellm.acompletion.

On a cache hit the LLM is not called and the previously stored response object is returned immediately. On a cache miss the response is fetched from LiteLLM, stored in the cache, and returned.

The cache key is derived from model, messages, and any extra litellm_kwargs (e.g. temperature, max_tokens). Changing any of these values produces a different cache key and triggers a fresh LLM call.

Parameters:

Name Type Description Default
cache MemoryCache

The :class:~memory_reuse.core.MemoryCache instance to use.

required
model str

LiteLLM model string, e.g. "gpt-4o-mini", "anthropic/claude-3-haiku", "bedrock/amazon.titan-text-v2".

required
messages list[dict[str, str]]

Chat messages in OpenAI format.

required
ttl int

Time-to-live in seconds. Defaults to 3600 (1 hour).

3600
scope _SCOPE_TYPE

Cache scope — "global", "user", or "session".

'global'
user_id str | None

User identifier for scope="user". Falls back to the value set via :meth:~memory_reuse.core.MemoryCache.set_context.

None
session_id str | None

Session identifier for scope="session". Falls back to context.

None
semantic bool

When True, route through the combined exact-then-semantic flow (:meth:~memory_reuse.core.MemoryCache.lookup / :meth:~memory_reuse.core.MemoryCache.store) so a reworded but equivalent prompt can hit the cache. The semantic query text is derived from the concatenated message contents. Requires semantic_enabled=True on the cache config to have any effect; otherwise behaviour is identical to Phase 1.

False
exact_only bool

When True, force Phase 1 exact-only behaviour for this call site even when the cache has semantic matching enabled.

False
**litellm_kwargs Any

Additional keyword arguments forwarded to litellm.acompletion (e.g. temperature, max_tokens, stream=False).

{}

Returns:

Type Description
Any

A litellm.ModelResponse object (identical shape to the OpenAI

Any

ChatCompletion response).

Raises:

Type Description
ScopeViolationError

If scope requires an ID that cannot be found.

ImportError

If LiteLLM is not installed.

Example::

response = await cached_litellm_completion(
    cache,
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "Explain caching in one line"}],
    ttl=600,
    scope="user",
    user_id="alice",
)
print(response.choices[0].message.content)

memory_reuse.integrations.litellm.cached_litellm_embedding async

cached_litellm_embedding(cache: MemoryCache, *, model: str, input: list[str] | str, ttl: int = 86400, scope: _SCOPE_TYPE = 'global', user_id: str | None = None, session_id: str | None = None, **litellm_kwargs: Any) -> Any

Cached wrapper around litellm.aembedding.

Embedding calls are expensive and deterministic — the same text always produces the same vector. Caching them with a long TTL (default 24 hours) is safe and eliminates significant cost for repeated RAG pipelines.

Parameters:

Name Type Description Default
cache MemoryCache

The :class:~memory_reuse.core.MemoryCache instance to use.

required
model str

LiteLLM embedding model string, e.g. "text-embedding-3-small", "bedrock/amazon.titan-embed-text-v2".

required
input list[str] | str

A single string or list of strings to embed.

required
ttl int

Time-to-live in seconds. Defaults to 86400 (24 hours) — safe because embeddings are deterministic.

86400
scope _SCOPE_TYPE

Cache scope.

'global'
user_id str | None

User identifier for scope="user".

None
session_id str | None

Session identifier for scope="session".

None
**litellm_kwargs Any

Additional keyword arguments forwarded to litellm.aembedding.

{}

Returns:

Type Description
Any

A litellm.EmbeddingResponse object.

Raises:

Type Description
ScopeViolationError

If scope requires an ID that cannot be found.

ImportError

If LiteLLM is not installed.

Example::

response = await cached_litellm_embedding(
    cache,
    model="text-embedding-3-small",
    input=["What is machine learning?", "Explain neural networks"],
)
vectors = [item["embedding"] for item in response.data]

Strands Agents

Requires the strands extra (pip install "memory-reuse[strands]").

memory_reuse.integrations.strands.cached_tool

cached_tool(cache: MemoryCache, *, scope: _SCOPE_TYPE = 'global', ttl: int = 300, semantic: bool = False, exact_only: bool = False) -> Callable

Decorator for Strands tool calls — caches the return value.

Thin parity wrapper over :func:memory_reuse.integrations.langgraph.cached_tool. After the Strands dependency guard runs (on first invocation), the call delegates to the shared decorator machinery, so the cache key ([tool_qualname, bound_args]), sync/async support, scope resolution with :exc:~memory_reuse.exceptions.ScopeViolationError, TTL expiry, exact-vs- semantic routing, and error propagation without storing on a raised body are all identical to the LangGraph decorator by construction (Req 6.1-6.12).

Parameters:

Name Type Description Default
cache MemoryCache

The :class:~memory_reuse.core.MemoryCache instance to use.

required
scope _SCOPE_TYPE

Cache scope — "global", "user", or "session".

'global'
ttl int

Time-to-live in seconds. Defaults to 300 (5 minutes).

300
semantic bool

When True, route through the combined exact-then-semantic lookup / store flow on the cache.

False
exact_only bool

When True, force exact-only matching even when the cache has semantic matching enabled.

False

Returns:

Type Description
Callable

The decorator function.

Raises:

Type Description
BackendNotAvailableError

On first invocation, if Strands is not installed. The message names pip install "memory-reuse[strands]".

ScopeViolationError

At call time, if scope requires a scope ID that cannot be resolved.

Example::

@cached_tool(cache, scope="global", ttl=600)
async def fetch_weather(city: str) -> dict:
    return weather_api.get(city)

CrewAI

Requires the crewai extra (pip install "memory-reuse[crewai]").

memory_reuse.integrations.crewai.cached_tool

cached_tool(cache: MemoryCache, *, scope: _SCOPE_TYPE = 'global', ttl: int = 300, semantic: bool = False, exact_only: bool = False) -> Callable

Decorator for CrewAI tool calls — caches the return value.

Mirrors :func:memory_reuse.integrations.langgraph.cached_tool exactly: the cache key is derived from the tool's qualified name and all of its arguments, both sync and async callables are supported, scope resolution and :exc:~memory_reuse.exceptions.ScopeViolationError behaviour, TTL expiry, exact-vs-semantic routing, and error-propagation-without-store are shared by delegating to the base decorator.

CrewAI adds one decoration-time guard: supplying both exact_only=True and semantic=True is contradictory, so it is rejected with a :exc:~memory_reuse.exceptions.ConfigurationError rather than silently ignoring one argument (Req 7.8). CrewAI is imported lazily inside the returned wrapper, so a missing dependency surfaces as a clear :exc:~memory_reuse.exceptions.BackendNotAvailableError naming the extra.

Parameters:

Name Type Description Default
cache MemoryCache

The :class:~memory_reuse.core.MemoryCache instance to use.

required
scope _SCOPE_TYPE

Cache scope ("global", "user", or "session").

'global'
ttl int

Time-to-live in seconds. Defaults to 300 (5 minutes).

300
semantic bool

When True, route through the combined exact-then-semantic flow so a reworded but equivalent call can hit the cache.

False
exact_only bool

When True, force exact-only behaviour for this call site even when the cache has semantic matching enabled.

False

Returns:

Type Description
Callable

The decorator function.

Raises:

Type Description
ConfigurationError

At decoration time, if both exact_only and semantic are True.

ScopeViolationError

At call time, if scope requires a scope ID that cannot be found.

BackendNotAvailableError

At call time, if CrewAI is not installed.

Example::

@cached_tool(cache, scope="global", ttl=600)
async def fetch_weather(city: str) -> dict:
    return weather_api.get(city)