ToolSearchExtension#

Build extensions, choose hooks, and manage request-scoped state. See the guide.

class zett_agent.extensions.tool_search.ToolSearchExtension(*, limit=20, min_score=0.0, k1=1.5, b=0.75, storage=None, resend_definitions_after_compaction=True, catalog=ToolCatalogPlacement.SEARCH_DESCRIPTION, catalog_snippets=True, catalog_guidelines=True)[源代码]#

Search registered local tools with BM25 through the Responses or Anthropic API.

Tools marked deferred=True are the searchable ones: this extension adds one request-scoped tool_search tool and removes every deferred definition from provider requests. Matching definitions reach the model through tool_search_output; their handlers remain locally registered. Tools without deferred keep flowing to the model as ordinary functions, so ToolGuidelinesExtension renders their guidance as usual.

The search tool's signature and docstring supply its schema, description, snippet, and guidelines, just like any other @tool-decorated function. Definitions the session already received are not offered twice: a second search in a later turn would otherwise repeat a name the conversation already declares, which strict endpoints reject. The record covers one session; a compaction drops it by default, because the checkpoint replaces the messages that declared those definitions.

参数:
  • limit (int) -- Maximum number of matching tools considered per search.

  • min_score (float) -- Default score threshold. A search call may override it with score; only tools scoring strictly above it are returned.

  • k1 (float) -- BM25 term-frequency saturation.

  • b (float) -- BM25 length-normalization strength.

  • storage (ToolSearchStorage | None) -- Optional key/value store holding one session's sent definitions. None keeps the record in memory for the lifetime of this extension, which covers several turns of one process but not a restart. Provide one to make the record durable.

  • resend_definitions_after_compaction (bool) -- Re-offer definitions the session already received once a compaction replaces the messages that declared them. False keeps suppressing them after a checkpoint, so the model keeps the tools it loaded earlier but cannot load them again by searching.

  • catalog (ToolCatalogPlacement) -- Where to list the searchable tools so the model knows what exists before it searches. The search description by default, where it travels with the one tool that uses it; the system prompt keeps the search tool's own text short. ToolCatalogPlacement.NONE lists nothing. The list is independent of ToolGuidelinesExtension and combines with either of its placements.

  • catalog_snippets (bool) -- Include each listed tool's snippet.

  • catalog_guidelines (bool) -- Include each listed tool's guidelines.

备注

The list names every deferred tool registered for the request, not only those the session has not loaded yet. A list that shrank as tools were found would change the request prefix on every search and defeat provider prompt caching; a repeated name in a search result is already filtered out.

备注

Clearing the record after a compaction matters because the checkpoint no longer declares the definitions the model loaded earlier. Keeping it would hide those tools from the model for the rest of the conversation.

示例

Keep optional capabilities behind search:

agent = await Agent.create(
    model,
    tools=[warehouse_stock, billing_lookup],
    extensions=[ToolSearchExtension(storage=redis_store)],
)

备注

Client-side tool search needs the Responses API or the Anthropic Messages API. On Anthropic the deferred tools stay in the request with defer_loading and a search answers with tool_reference blocks. Chat Completions, Google, and Ollama reject local_tool_search tools, and an endpoint that ignores the protocol never issues a search.

async on_tool(context)[源代码]#

Register the decorated BM25 search tool for this request.

参数:

context (AgentRunContext)

返回类型:

None

async on_state(context)[源代码]#

List the searchable tools in the system instructions when that placement is chosen.

参数:

context (AgentRunContext)

返回类型:

None

async on_model_request(context, request, call_next)[源代码]#

Hide deferred definitions, or mark them deferred where the provider can.

A Responses endpoint learns a deferred definition only from the search result, so it never receives the definition up front. An adapter that declares NativeDeferredToolsModel.native_deferred_tools (Anthropic) must instead declare every deferred tool with defer_loading so a search result can refer to it by name; its guidelines then ride in the description, because no system prompt carries them.

参数:
返回类型:

AsyncIterator[ModelEvent]

async on_event(context, event)[源代码]#

Let the conversation rediscover definitions a compaction removed.

The checkpoint replaces the tool_search_output items that declared them, so the model must be able to search them up again instead of being told they are already loaded.

参数:
返回类型:

None

accept(config, event)#

Handle one external event and report whether it was accepted.

The Agent broadcasts each event to every registered extension. Override this synchronous hook when an extension waits for input from another thread, HTTP request, TUI, or Web UI. The default ignores the event. Config is passed separately and can be None before initialization. Each extension decides whether the supplied identity and payload match its protocol. Return True to include this extension's name in the broadcast result; returning False does not stop later receivers.

参数:
返回类型:

bool

async after_model(context, response)#

Run after the complete assistant message is appended.

参数:
返回类型:

None

async after_run(context, result)#

Run after a successful final answer is appended.

参数:
返回类型:

None

async after_tool(context, call, result, error)#

Inspect or modify a tool result before it is appended.

error is the original execution exception for a failed result and None after successful execution. Changes made to result are included in context, persistence, and the next model request. Raising prevents the result from being appended.

参数:
返回类型:

None

async after_turn(context, result)#

Run once the turn's assistant message and tool results are settled.

result is the assistant message that opened the turn: either the final answer, or the tool-calling message whose ToolMessages were appended. Every requested call is settled first, including calls that failed, and calls that steering skipped, which arrive as unsuccessful or skipped ToolMessages.

Steering that interrupts a turn is accepted while the runtime settles that batch, so its UserMessage is already appended when this hook runs and the steering turn follows as the next turn.

A turn that never completed, because the request failed or was cancelled, has no after_turn call; use on_error and RunCancelledEvent for those paths.

参数:
返回类型:

None

async before_model(context, request)#

Inspect the current request before preprocessing a primary model call.

Request fields are frozen. Change messages through AgentRunContext.add_message() or AgentRunContext.replace_messages(), local tools through context.tools, and provider tools through context.server_tools; the runtime rebuilds these fields before the next hook and before calling the provider. This is a shallow request view, not an immutable copy of each message or tool definition.

示例

Inspect the tools offered in this iteration:

async def before_model(self, context, request):
    offered = {definition.name for definition in request.tools}
    if "write_file" in offered:
        context.add_message(
            SystemMessage(content="Read existing files before editing."),
        )
参数:
返回类型:

None

async before_run(context)#

Run after the transformed user input is appended and published.

参数:

context (AgentRunContext)

返回类型:

None

async before_tool(context, call)#

Run before one requested tool is invoked.

参数:
返回类型:

None

async before_turn(context)#

Run before this turn's model call.

Runs after before_run() on the first turn and after the previous turn's after_turn() on later ones. Model request assembly, compaction, and before_model() follow this hook, so context edited here reaches the provider.

参数:

context (AgentRunContext)

返回类型:

None

property name: str#

Unique registration identity, defaulting to the concrete class name.

Override with a class attribute or assign an instance name to register independently configured instances of the same extension type.

async on_compact(context)#

Summarize restored context when a caller asks for compaction.

Agent.compact restores the session through on_tool and on_state exactly as a request does, appends no input message, and makes no primary model call: the only work a compaction pass does is what this hook performs. The default does nothing, so an extension with nothing to compact pays nothing.

示例

Usage:

async def on_compact(self, context):
    await self.compact(context)
参数:

context (AgentRunContext)

返回类型:

None

async on_error(context, error)#

Run before an agent error is propagated to the caller.

参数:
返回类型:

None

async on_message(context)#

Transform context.input_message after state restoration, before append.

Replace the pending UserMessage to implement externally selected modes. Do not append or persist it here: the runtime appends the final message exactly once after all input hooks finish. before_run sees that message through AgentRunContext.add_message() or AgentRunContext.replace_messages(), and persistence subscribers have already received it.

参数:

context (AgentRunContext)

返回类型:

None

async on_success(context, result)#

Run once after all after_run hooks succeed, before RUN_COMPLETED.

This callback observes a completed request, not an intermediate model step. Failed or cancelled requests do not trigger it. Callback errors propagate through on_error and prevent RUN_COMPLETED from being emitted.

示例

Usage:

async def on_success(self, context, result):
    await save_answer(context.session_id, result.content)
参数:
返回类型:

None

async on_tool_call(context, call, call_next)#

Wrap one registered local tool handler and return its ToolResult.

An extension may adjust call.arguments, return without calling the next layer, transform its result, or raise into normal tool-failure handling.

参数:
返回类型:

ToolResult

property pending: bool#

Return whether this extension is participating in an active request.

The Agent updates this state for every registered extension, including extensions whose hooks are currently idle. One extension instance may be shared by multiple Agents and sessions; pending remains true until all requests using that instance have finished, failed, or been cancelled. Persistent data retained between requests does not count.