core.tool_catalog module

Redis-backed tool catalog: the bridge that lets the inference tier present tools to the LLM without importing any tool handler module.

The dedicated tools service owns tools/ and is the only process that imports tool handlers. On boot (and on every reload_tools) it serializes its ToolRegistry into a catalog — each tool’s name / description / JSON parameters / behaviour flags plus the permission map — and publishes it to Redis. The inference tier’s RemoteToolRegistry loads that catalog and reproduces the registry’s read surface (OpenAI schemas, tool_names, repeat_allowed_tools, is_allowed …) byte-for-byte, so prompt rendering, the vector classifier, and the function-calling schema all keep working while execution is delegated.

Storage (all keys binary-safe; services use a decode_responses=False client):

  • sg:tools:catalog:seq — monotonic INCR counter for blob versions.

  • sg:tools:catalog:v{seq} — msgpack blob {tools, permissions, schema_hash}.

  • sg:tools:catalog:current — the active seq (atomic pointer swap).

  • sg:pubsub:tools:catalog — JSON {version, schema_hash} published on change.

schema_hash is a content hash of the tool schemas (independent of seq, which advances on every restart). Inference stamps its loaded schema_hash into each delegated call; the tools service rejects a mismatch with CATALOG_STALE so a deploy that changed a schema cannot silently run the model against the wrong parameters.

core.tool_catalog.schema_hash(tools)[source]

Stable content hash over the catalog’s tool schemas.

Hashes the name / description / parameters / flags of every tool (sorted by name) so two registries with identical tool definitions produce the same hash regardless of load order or restart. Used for the staleness check.

Return type:

str

Parameters:

tools (list[dict[str, Any]])

core.tool_catalog.build_catalog_payload(registry)[source]

Serialize a live ToolRegistry into a catalog dict (pure, no I/O).

Captures everything the inference tier needs to present tools without the handler code: each tool’s name / description / JSON parameters / the no_background + allow_repeat flags, plus the per-tool permission map.

Return type:

dict[str, Any]

Parameters:

registry (ToolRegistry)

core.tool_catalog.openai_tool_dict(entry)[source]

Build an OpenAI function-calling tool dict from a catalog entry.

Mirrors ToolRegistry._ensure_cache_unlocked exactly so the schema the LLM sees is identical whether sourced from the live registry or the catalog.

Return type:

dict[str, Any]

Parameters:

entry (dict[str, Any])

async core.tool_catalog.publish_catalog(redis, registry, *, prune_keep=3)[source]

Publish registry’s catalog to Redis under a fresh version and announce it.

Writes the new blob first, then atomically flips current to it, then publishes a pubsub notification so live RemoteToolRegistry readers hot-reload. Old blob versions beyond prune_keep are best-effort deleted.

Returns (seq, schema_hash) of the published catalog.

Return type:

tuple[int, str]

Parameters:
async core.tool_catalog.load_catalog(redis)[source]

Load the current catalog blob from Redis, or None if not published yet.

Returns the decoded {tools, permissions, schema_hash, version} dict.

Return type:

Optional[dict[str, Any]]

Parameters:

redis (Any)