Observed since 20 Oct, 22:01 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
Universal Tool Orchestration Platform - Intelligent, secure tool orchestration for LLM-based agent systems
Universal Tool Orchestration Platform for LLM-Based Agent Systems
Context is precious. Execution is sacred. Trust is earned.
Agent-Gantry is a Python library (v0.20.0) for building agents that can discover, select, and execute the right tools without flooding every prompt with every schema your organization owns. It combines semantic retrieval, provider schema conversion, secure execution, framework bridges, MCP/A2A interoperability, persistence adapters, and observability into one tool orchestration layer.
The project documentation is now an Astro + React + TypeScript site with an implementation journey, interactive tool lifecycle walkthrough, integration matrix, and production operations guidance.
npm install
npm run dev # local docs server
npm run build # type-check and static build
npm run preview # verify the generated site styling
Start with the rich docs in src/pages/index.astro. The published site lives at codehalwell.github.io/Agent-Gantry.
uv add agent-gantry
# or
pip install agent-gantry
Useful extras:
uv add "agent-gantry[openai]"
uv add "agent-gantry[anthropic]"
uv add "agent-gantry[google-genai]"
uv add "agent-gantry[lancedb,nomic]"
uv add "agent-gantry[mcp,a2a]"
uv add "agent-gantry[agent-frameworks]"
uv add "agent-gantry[all]"
from openai import AsyncOpenAI
from agent_gantry import AgentGantry, set_default_gantry, with_semantic_tools
client = AsyncOpenAI()
gantry = AgentGantry()
set_default_gantry(gantry)
@gantry.register(tags=["weather"])
def get_weather(city: str) -> str:
"""Get the current weather for a city."""
return f"The weather in {city} is 72°F and sunny."
@with_semantic_tools(limit=3, dialect="openai")
async def ask_llm(prompt: str, *, tools=None):
return await client.chat.completions.create(
model="gpt-5.5",
messages=[{"role": "user", "content": prompt}],
tools=tools,
)
await ask_llm("What's the weather in San Francisco?")
Agent-Gantry automatically fingerprints registered tools, syncs definitions to the configured vector store, retrieves semantically relevant tools, and converts schemas to the requested provider dialect.
Use the same registry with any supported framework. Install the framework SDK you use; Gantry imports it only when it builds native tools or live hooks.
# Native LangChain tools, ready for model.bind_tools(tools).
tools = await gantry.framework("langchain").select("What's the weather?", limit=3)
# Dynamic Pydantic AI tools, reselected on every model turn.
from pydantic_ai import Agent
agent = Agent("openai:gpt-5.5", toolsets=[gantry.framework("pydantic-ai").live(limit=3)])
# Discover all twelve integrations without installing their SDKs.
from agent_gantry import supported_frameworks
print(supported_frameworks())
Framework names preserve adapter types for editor completion. Hyphenated names
such as google-adk and openai-agents also work. Existing adapter classes and
imports remain available. See the integration recipes
for each framework's install command, static tools, and live selection hook.
execute_batch() and execute_tool_calls().gantry.serve_mcp() / agent-gantry serve-mcp --module my_app.tools — two meta-tools instead of the whole tool list.add_a2a_agent(), and serve your own registry as an A2A agent (Agent Card at /.well-known/agent.json) with gantry.serve_a2a().SKILL.md) directory with gantry.add_skills_from_directory(...) and inject only the skills relevant to each prompt.agent-gantry install-skill --claude or target a project-local skills directory.JevSelector replaces embed-then-search for tools, skills and MCP servers; JevReranker refines the shortlist when the catalogue is too large to send. Both fail open to semantic routing.Agent-Gantry supports Python 3.10–3.14. CrewAI's current SDK requires Python
3.10–3.13; the agent-frameworks extra includes it only on those versions.
Semantic routing embeds the query and searches. A selector asks a decision model directly, which needs no embedder, no vector store and no sync — and can return nothing when nothing fits, which top-k cannot express.
from agent_gantry import AgentGantry, JevSelector
gantry = AgentGantry(selector=JevSelector(threshold=0.3)) # reads TYPESAFE_API_KEY
@gantry.register(tags=["email"], examples=["show my messages", "any new mail"])
def list_inbox(limit: int = 10) -> list[str]:
"""List the most recent messages sitting in the inbox."""
return []
@gantry.register(tags=["email"], examples=["email Bob about the meeting"])
def send_email(to: str, body: str) -> str:
"""Send an email message to a named recipient."""
return "sent"
# With a key, this honours the negation and returns list_inbox alone.
# Without one, selection fails open and semantic routing answers instead.
tools = await gantry.retrieve_tools("show my messages, but do not send anything")
The same selector covers retrieve_skills() and retrieve_mcp_servers(). Above
a few hundred entries, keep semantic search and refine it instead:
from agent_gantry import AgentGantry, JevReranker
gantry = AgentGantry(reranker=JevReranker()) # reorders the vector-search shortlist
Write examples=[...] on your tools before reaching for either: on our own
benchmark that moved the default embedder from 1/5 to 5/5, more than any model
change did. See agent_gantry/adapters/selectors/README.md for the measured
trade-offs.
from agent_gantry import AgentGantry
from agent_gantry.schema.execution import ToolCall
gantry = AgentGantry()
@gantry.register(tags=["finance"])
def calculate_tax(amount: float) -> float:
"""Calculate US sales tax for an amount."""
return amount * 0.08
tools = await gantry.retrieve_tools("What is the tax on $100?", limit=5)
result = await gantry.execute(ToolCall(
tool_name="calculate_tax",
arguments={"amount": 100.0},
))
uv sync --all-extras
uv run pytest
npm install
npm run build
MIT
Download counts and popularity will appear here as the collector receives them.
| Version | Published | Direct dependencies | Open version |
|---|---|---|---|
| 0.20.0 | 17 Oct 2026 | 55 |
This describes our collected data; it is not a security assessment.
Observed since 20 Oct, 22:01 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:f172a67e314328cbecb4b698c298eb121e39078a71c5f1c6c8adc24ebc70dfbf