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]wherekey_datais the full state dict, or{f: state.get(f) for f in key_fields}whenkey_fieldsis 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=Trueroutes through the combined exact-then-semantic :meth:~memory_reuse.core.MemoryCache.lookup/storeflow;semantic=False(orexact_only=True) uses exact-only matching.- Scope resolution (state → context) and
:exc:
~memory_reuse.exceptions.ScopeViolationErrorbehaviour 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: |
required |
scope
|
_SCOPE_TYPE
|
Cache scope. For |
'global'
|
ttl
|
int | None
|
Time-to-live in seconds. Overrides the default TTL from
:class: |
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 |
False
|
exact_only
|
bool
|
When |
False
|
Returns:
| Type | Description |
|---|---|
Callable
|
The decorator function. |
Raises:
| Type | Description |
|---|---|
ScopeViolationError
|
At call time, if |
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: |
required |
scope
|
_SCOPE_TYPE
|
Cache scope. |
'global'
|
ttl
|
int
|
Time-to-live in seconds. Defaults to 300 (5 minutes). |
300
|
semantic
|
bool
|
When |
False
|
exact_only
|
bool
|
When |
False
|
Returns:
| Type | Description |
|---|---|
Callable
|
The decorator function. |
Raises:
| Type | Description |
|---|---|
ScopeViolationError
|
At call time, if |
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: |
required |
model
|
str
|
LiteLLM model string, e.g. |
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_id
|
str | None
|
User identifier for |
None
|
session_id
|
str | None
|
Session identifier for |
None
|
semantic
|
bool
|
When |
False
|
exact_only
|
bool
|
When |
False
|
**litellm_kwargs
|
Any
|
Additional keyword arguments forwarded to
|
{}
|
Returns:
| Type | Description |
|---|---|
Any
|
A |
Any
|
|
Raises:
| Type | Description |
|---|---|
ScopeViolationError
|
If |
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: |
required |
model
|
str
|
LiteLLM embedding model string, e.g.
|
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 |
None
|
session_id
|
str | None
|
Session identifier for |
None
|
**litellm_kwargs
|
Any
|
Additional keyword arguments forwarded to
|
{}
|
Returns:
| Type | Description |
|---|---|
Any
|
A |
Raises:
| Type | Description |
|---|---|
ScopeViolationError
|
If |
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: |
required |
scope
|
_SCOPE_TYPE
|
Cache scope — |
'global'
|
ttl
|
int
|
Time-to-live in seconds. Defaults to 300 (5 minutes). |
300
|
semantic
|
bool
|
When |
False
|
exact_only
|
bool
|
When |
False
|
Returns:
| Type | Description |
|---|---|
Callable
|
The decorator function. |
Raises:
| Type | Description |
|---|---|
BackendNotAvailableError
|
On first invocation, if Strands is not
installed. The message names |
ScopeViolationError
|
At call time, if |
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: |
required |
scope
|
_SCOPE_TYPE
|
Cache scope ( |
'global'
|
ttl
|
int
|
Time-to-live in seconds. Defaults to 300 (5 minutes). |
300
|
semantic
|
bool
|
When |
False
|
exact_only
|
bool
|
When |
False
|
Returns:
| Type | Description |
|---|---|
Callable
|
The decorator function. |
Raises:
| Type | Description |
|---|---|
ConfigurationError
|
At decoration time, if both |
ScopeViolationError
|
At call time, if |
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)