Skip to content

latent.agents.retriever

@retriever — observability decorator for document retrieval.

Mirrors the @tool decorator pattern: wrap an async function so the framework can register it as a typed primitive AND emit structured events around its invocation. The decorator solves the duck-typing gap previously present in agent-studio's TracedStream — RetrieverStart / RetrieverEnd events now live in latent.events and the trace pipeline can dispatch them via isinstance like every other event.

How events reach the stream

A decorated retriever IS an async generator: it yields its events directly. Tool authors who chain retrievers drain them with async for and forward events into their own (also async-generator) tool body. The framework's @tool decorator unifies coroutine and async-generator tools so ReActAgent async fors every tool uniformly — events forward into the agent's stream and the final non-event yield is the tool result.

@retriever implies @tool: the decorator stamps _tool_meta so a bare decorated retriever is passable to ReActAgent(tools=[...]) directly; no separate @tool wrapper is needed for the common case.

No ContextVar, no side-channel — events emit where the decorator's wrapper runs, directly visible at the call site. This is intentional: the older ContextVar approach hid the data flow and made testing awkward; the async-generator pattern is the same shape Python uses elsewhere for streaming (FastAPI streaming responses, async iterables in httpx, etc.).

Decorator contract

The decorated function must:

  • be an async def (the framework awaits it)
  • take a positional or keyword argument named query (the search input)
  • return an iterable of objects with either a content attribute (e.g. RetrievedChunk) or be str-convertible

A retriever name is taken from the function's __name__ by default; override with @retriever(name="my-retriever").

Calling pattern inside a tool body

The decorated retriever is an async generator. Iterate with async for, distinguish events from the result by type:

@retriever
async def search_kb(query: str, k: int = 4):
    return await chroma.retrieve(query, k=k)

@tool
async def search_knowledge_base(query: str):
    chunks = None
    async for item in search_kb(query):
        if isinstance(item, AgentEvent):
            yield item        # forward events to the agent stream
        else:
            chunks = item     # last non-event yield = retriever result
    yield format_chunks(chunks)  # tool's final yield = ToolResult.output

Tools that don't call retrievers stay plain coroutines; the @tool / ReActAgent layer detects async-generator tools and handles either shape.

Calling outside an agent loop

Decorated retrievers called from a notebook / script / test still work — iterate the generator and treat the last item as the result:

async for item in search_kb("hi"):
    if not isinstance(item, AgentEvent):
        chunks = item

Functions

retriever

retriever(fn: F | None = None, name: str | None = None) -> Any

Decorator that turns an async retrieval function into an async generator emitting :class:RetrieverStart / :class:RetrieverEnd events around the underlying call.

Supports both @retriever and @retriever(name="…") forms.

@retriever implies @tool: the decorated function is also registered as an LLM-callable tool. Pass it to ReActAgent(tools=...) directly — no separate @tool wrapper needed for the common case (retriever whose return value IS the tool output). For the composition case (one tool fanning out to multiple retrievers + post-processing), write a separate @tool-decorated async generator that drains the @retriever-decorated building blocks. Both decorators can stack.

Args: fn: The async retrieval function to wrap. Implicitly provided when used as @retriever without parentheses. name: Override the retriever name in emitted RetrieverStart / RetrieverEnd events. Defaults to fn.__name__. Does NOT affect the tool name exposed to the LLM — that always comes from fn.__name__ via the tool schema.

Returns: An async-generator function carrying __is_retriever__ (for framework introspection) and _tool_meta (so ReActAgent registers it as a tool).

Attributes

F