Agent tools¶
The memory operations as agent tools: descriptions, schemas, rendered results.
Handing these operations to an LLM takes three things beyond the calls themselves — text telling a model what a tool does and what to pass it, a JSON Schema for its arguments, and results rendered as text a model can read. None of that is specific to an agent framework, and all of it is the SDK’s to get right: the descriptions are the service’s copy, the schemas are this package’s own types, and a caller who writes their own rendering has to keep it in step with every field the contract adds.
So it lives here, reached from the session the tools are bound to, and wiring it into a framework is the only work left:
from memcoai import Memco
with Memco() as client:
with client.memory.with_session("coding") as session:
for tool in session.tools():
tool.name, tool.description, tool.parameters, tool.call
Each tool is bound to the session it was built from, so nothing a model sends can change which session a call is recorded under. What a model sends is untrusted: arguments are validated against the same types the schema was built from, and a bad one is reported the way a bad request is.
examples/langchain_agent.py is the whole of the LangChain wiring.
- AGENT_RECOVERABLE: tuple[type[MemcoInvalidRequestError], type[MemcoNotFoundError]] = (<class 'memcoai.errors.MemcoInvalidRequestError'>, <class 'memcoai.errors.MemcoNotFoundError'>)¶
The failures a model can act on, and the only ones a tool reports as text.
A malformed request it can correct, and a handle that resolves to nothing it can look for elsewhere. Everything else — a rejected or unscoped credential, a timeout, an unreachable service, a spent quota — is raised, because no wording a model reads will fix it and letting it read the failure only invites it to try again.
- class AsyncTool(name, description, parameters, call)[source]¶
Bases:
objectOne memory operation on an asyncio client. Mirrors
Tool.- Variables:
name (str) – The name a model calls, such as
memco_search.description (str) – What the operation is for, as a model should read it.
parameters (dict[str, Any]) – A JSON Schema object describing the arguments.
call (collections.abc.Callable[[...], collections.abc.Awaitable[str]]) – Runs the operation and renders the result as text, awaitably.
- Parameters:
Example
>>> for tool in session.tools(): ... print(tool.name, tool.parameters["required"])
- class AsyncToolset(iterable=(), /)[source]¶
-
Every memory operation as an awaitable tool. Mirrors
Toolset.Example
>>> toolset = session.tools() >>> runnable = create_agent(model, tools=toolset.to_langchain())
- to_langchain()[source]¶
Hand these tools to LangChain, bound as coroutines.
- Returns:
One
langchain_core.tools.StructuredToolper operation, each reached withainvoke.- Raises:
ImportError – If LangChain is not installed.
- Return type:
Example
>>> create_agent(model, tools=session.tools().to_langchain())
- to_anthropic()[source]¶
Describe these tools for the Anthropic Messages API.
- Returns:
One tool definition per operation, identical to the synchronous ones: a definition says nothing about how the host calls it.
- Return type:
Example
>>> await client.messages.create(tools=toolset.to_anthropic(), ...)
- to_openai()[source]¶
Describe these tools for the OpenAI function-calling API.
Example
>>> await client.chat.completions.create(tools=toolset.to_openai(), ...)
- async call(name, arguments)[source]¶
Run the tool a model named, and render what it returned.
- Parameters:
- Returns:
The result as text, or what the model got wrong. Nothing a model can send reaches the caller as an exception.
- Return type:
Example
>>> await toolset.call("memco_search", {"query": "how does X work"})
- class Tool(name, description, parameters, call)[source]¶
Bases:
objectOne memory operation, ready to hand to an agent framework.
- Variables:
name (str) – The name a model calls, such as
memco_search.description (str) – What the operation is for, as a model should read it.
parameters (dict[str, Any]) – A JSON Schema object describing the arguments, with a description on each. Every framework this SDK has been used with takes one of these directly.
call (collections.abc.Callable[[...], str]) – Runs the operation and renders the result as text. Takes the arguments the schema describes, by keyword.
- Parameters:
Example
>>> for tool in session.tools(): ... print(tool.name, tool.parameters["required"])
- class Toolset(iterable=(), /)[source]¶
-
Every memory operation as a tool, in the shape a framework wants it.
A tuple of
Tool, so it iterates and indexes like one. Theto_*methods hand the same tools to a particular framework, andcall()runs the one a model named — which is what the definition-only shapes need, since there the host dispatches rather than the framework.Example
>>> toolset = session.tools() >>> runnable = create_agent(model, tools=toolset.to_langchain()) >>> # or, driving the loop yourself: >>> response = anthropic.messages.create(tools=toolset.to_anthropic(), ...) >>> toolset.call(block.name, block.input)
- to_langchain()[source]¶
Hand these tools to LangChain.
LangChain takes a JSON Schema directly, so nothing is restated.
- Returns:
One
langchain_core.tools.StructuredToolper operation, ready forcreate_agent(tools=...).- Raises:
ImportError – If LangChain is not installed.
- Return type:
Example
>>> create_agent(model, tools=session.tools().to_langchain())
- to_anthropic()[source]¶
Describe these tools for the Anthropic Messages API.
Definitions only — pair them with
call()to run what the model asks for.Example
>>> client.messages.create(tools=session.tools().to_anthropic(), ...)
- to_openai()[source]¶
Describe these tools for the OpenAI Chat Completions API.
Definitions only — pair them with
call()to run what the model asks for, which also takes the JSON string that API hands back. Anything speaking the same shape takes these too; the Responses API wants a flatter one and is not what this emits.Example
>>> client.chat.completions.create(tools=session.tools().to_openai(), ...)
- call(name, arguments)[source]¶
Run the tool a model named, and render what it returned.
- Parameters:
- Returns:
The result as text, or what the model got wrong. Nothing a model can send reaches the caller as an exception.
- Return type:
Example
>>> toolset.call("memco_search", {"query": "how does X work"}) >>> toolset.call(call.function.name, call.function.arguments) # OpenAI
- briefing(domain, instructions)[source]¶
Render what the service says about a domain, for a model to be told.
Every word of this comes from
list_domains()and from opening the session — what the domain holds, when to draw on it, what belongs in it, and the tag vocabulary it uses. Supply it up front rather than leaving a model to ask: guidance behind a tool only steers the models that reach for it.- Parameters:
domain (DomainEntry) – The domain the session was opened in, from
list_domains.instructions (Instructions) – What the service said when the session was opened, as carried by the scope’s
instructions.
- Returns:
The guidance as text, ready to be a system prompt or part of one.
- Return type:
Example
>>> from memcoai import agent >>> entry = next(d for d in client.memory.list_domains().domains ... if d.slug == "coding") >>> with client.memory.with_session("coding") as session: ... print(agent.briefing(entry, session.instructions))
- render(value)[source]¶
Render an operation’s result as text a model can read.
Every result carries
Instructions— the service’s own guidance on what to do with what came back — and that is included, because a model that never sees it is left to guess.- Parameters:
value (SearchResult[Any] | Memory | AsyncMemory | WriteResult | FeedbackResult | RevertResult) – Any result a memory operation returns.
- Returns:
The result as text.
- Raises:
TypeError – If the value is not a result type this renders.
- Return type:
Example
>>> from memcoai import agent >>> print(agent.render(session.search("how does X work")))
The tools themselves are built from the session they are bound to:
memcoai.operations.Session.tools() and
memcoai.operations.AsyncSession.tools().