Skip to content

Tool and agent registries

ChemGraph provides explicit registries for discovering in-process tools and worker graphs without eagerly importing every implementation. These registries are intended to support orchestration and, later, controlled benchmarking.

The first registry release deliberately excludes MCP tools, generated IRI API tool collections, skills, selector middleware, and benchmark code. The main_agent graph is also excluded from both registries: it remains the orchestration graph that consumes registered workers.

Tool registry

ToolRegistry contains the LangChain BaseTool objects implemented in chemgraph.tools. The manifest stores import paths and metadata, so creating a registry does not import optional tool modules.

from chemgraph.registry import ToolRegistry

registry = ToolRegistry()

# Inspect metadata without loading tool implementations.
print(registry.names())
ase_specs = registry.specs(tags={"ase"})

# Resolve only the tools needed by a graph or model.
tools = registry.resolve(["molecule_name_to_smiles", "run_ase"])

Tools can be selected by one or more tags. A tool must contain every requested tag to match:

analysis_tools = registry.resolve(tags={"ase", "analysis"})

Some tools need optional Python packages, environment variables, or external executables. Use availability() to inspect those requirements, or set require_available=True to fail before loading the tool:

status = registry.availability("run_docking")
if status.available:
    docking = registry.get("run_docking", require_available=True)
else:
    print(status.issues)

Passing require_available=False does not make an unavailable dependency work; it only defers validation to the tool implementation.

Agent registry

AgentRegistry contains ChemGraph worker graph constructors. It provides the same canonical workflow names used by the command-line interface, except for main_agent:

from chemgraph.registry import AgentRegistry

registry = AgentRegistry()
print(registry.names())

worker = registry.build("single_agent", llm=model)

The registered workers are single_agent, multi_agent, python_relp, graspa, mock_agent, graspa_mcp, rag_agent, single_agent_xanes, molecular_docking, and single_agent_iri. Existing python_repl, graspa_agent, and iri spellings are supported as aliases.

Standalone workers keep their existing default in-memory checkpointer. When a worker is handed to an orchestration graph, use as_subagent() or as_subagents(). These adapters compile the worker with checkpointer=None so it inherits checkpointing from the parent graph:

workers = registry.as_subagents(
    ["single_agent", "python_relp"],
    llm=model,
)

main_graph = construct_main_agent_graph(model, subagents=workers)

as_subagents() validates names, availability, constructor loading, and constructor options for the whole requested set before invoking any constructor. Per-worker constructor arguments are supplied through options:

workers = registry.as_subagents(
    ["single_agent", "graspa_mcp"],
    llm=model,
    options={
        "graspa_mcp": {
            "executor_tools": executor_tools,
            "analysis_tools": analysis_tools,
        }
    },
)

Both registries support explicit custom registration with ToolSpec or AgentSpec. Passing replace=True allows an existing canonical specification to be replaced. An agent replacement may retain, remove, or add aliases owned by that same canonical agent, but it cannot claim a canonical name or alias owned by another entry.

Batch prevalidation catches registry, availability, import, and constructor option errors. It does not roll back workers if a constructor itself raises at runtime after an earlier worker was constructed.