Quickstart
Build an index and select tools for a query — the entire public surface of tool_curator is one factory function and two methods.
Tool Curator
from tool_curator import get_curator, load_tool_context
curator = get_curator(
mode = "rag",
top_k = 15,
model_name = "BAAI/bge-small-en-v1.5",
index_dir = "/path/to/cache", # "" disables disk caching
)
# your_tools: list[tuple[str, str]] — (tool_name, tool_description) pairs.
# This should already reflect your own access-control filtering — the
# curator never widens a tool pool, it only narrows it.
your_tools = [
("get_account_balance", "Returns the current balance for a customer account."),
("initiate_wire_transfer", "Initiates an outbound wire transfer between accounts."),
# ...
]
# Build once, e.g. at session start when the tool pool becomes known.
synonyms = load_tool_context("/path/to/domain_synonyms.json") # optional, {} if omitted
curator.build_index(your_tools, extra_context=synonyms)
# Per query.
selected = curator.select("can I send money to Rahul?", your_tools)
# selected: same (name, description) format, trimmed to top_k entries
That’s the whole interface: build_index() once per session, select() once per message. See API Reference: tool_curator for every parameter, and Configuration & Domain Synonyms for how domain_synonyms.json actually moves the accuracy numbers.
Multilingual Normalizer
from multilingual_normalizer import get_normalizer
normalizer = get_normalizer(provider="gemini", api_key="...")
english_query, language = normalizer.normalize(user_query)
# english_query is safe to hand to curator.select() (or any English-only retriever)
# language is the detected source language, "English" for the fast-path case
Run this before curator.select() in your per-message flow — the curator’s BGE embeddings are English-only, so an untranslated non-English query will retrieve on noise. See Multilingual Normalizer for the fast-path heuristic and how to add your own translation backend.
Putting them together
from tool_curator import get_curator, load_tool_context
from multilingual_normalizer import get_normalizer
curator = get_curator(mode="rag", top_k=15, index_dir=".tool_cache")
normalizer = get_normalizer(provider="gemini", api_key=GEMINI_API_KEY)
curator.build_index(your_tools, extra_context=load_tool_context("domain_synonyms.json"))
# Per message:
english_query, language = normalizer.normalize(user_message)
selected = curator.select(english_query, your_tools)
tool_declarations = build_llm_tool_declarations(selected) # your own LLM-format conversion
# proceed with your existing LLM call using tool_declarations
Everything downstream — tool execution, streaming, persistence — is unaffected; neither plug-in has a role in actually invoking tools. For a worked example wiring this into a multi-server MCP orchestration layer, see the Integration Guide.