Skip to content

Tool System

ContextRouter’s tool system is built on two complementary patterns: platform tools for internal LLM capabilities, and federated tools for secure bi-directional execution on consumer projects.

Platform Tools

Platform tools are atomic, domain-agnostic LLM capabilities registered in the PlatformToolRegistry. They are the building blocks that YAML graph templates compose into pipelines.

Each platform tool:

  • Has a Pydantic config schema (frozen=True, extra="forbid")
  • Requires router:execute token scope
  • Wraps exceptions in PlatformServiceError
  • Has zero domain imports — pure LLM capability

Registry Architecture

All 36 platform tool bindings are registered at startup via register_all_platform_tools():

cortex/compiler/platform_tools/__init__.py
def register_all_platform_tools(registry: PlatformToolRegistry) -> None:
"""Wire all platform tool modules into the registry."""
# RAG pipeline (11): extract_query, detect_intent, retrieve, ground,
# generate, reflect, suggest, format_output, synthesize_results,
# web_search, no_results
register_tool_specs(registry, _GENERIC_RAG + [no_results_spec])
# SQL analytics (4): sql_plan, sql_execute, sql_verify, sql_visualizer
register_tool_specs(registry, _SQL_TOOLS)
# Content / news (6): classify, generate_content, review_content,
# filter_content, plan_content, match_semantic
register_router_content_tools(registry)
# Brain service (7): search, memory_read/write, blackboard_read/write,
# kg_query, upsert
register_brain_tools(registry)
# Worker service (4): start_workflow, get_status, execute_code,
# register_schedules
register_worker_tools(registry)
# Other (4):
register_router_rlm_tools(registry) # 1 RLM processing tool
register_language_tools(registry) # 1 grammar/spelling tool
register_shield_tools(registry) # 1 Shield scanning tool
register_ingest_tools(registry) # 1 file download tool

Tool Categories

See Graph Compiler — Platform Tools for the complete binding reference.

Federated Tools (Bi-Directional Execution)

In typical LLM applications, the orchestrator needs direct access to databases or APIs to execute tools. This creates a massive security liability — the central Mind would need credentials for every connected project (the Confused Deputy problem).

ContextRouter solves this with Bi-Directional Tool Binding via the ToolExecutorStream. External projects connect to Router which acts purely as a “Cognition Provider”. When the LLM decides to run a tool like export_products, Router does not execute it. Instead, it streams the tool request back down the persistent connection to the client project. The client executes locally inside its own VPC, and streams the result back up to the LLM.

See also: ContextUnity Security Scope, BiDi Execution

How it works

Consumer Project Router (Cognition Provider)
│ │
│ RegisterManifest(yaml) │
│ ──────────────────────────────▶ │ Compile graphs + validate tools
│ │
│ ToolExecutorStream() │
│ ◀─────────────────────────────── │ Graph node needs federated tool
│ │
│ Execute locally (own DB/API) │
│ ──────────────────────────────▶ │ Return result to graph
│ │

Declaring Federated Tools in Manifest

Consumer projects do not declare a graph-level federated_tools map. Federated BiDi tools are discovered from:

  1. toolkits: on the router or per-graph — toolkit classes register @federated_tool handlers.
  2. Template nodes — YAML templates list type: tool nodes with tool_binding: federated:<tool_name>.
  3. Inline graphs — each project tool node uses type: tool or inferred tool type with a namespaced binding, e.g. tool_binding: federated:medical_sql, with optional meta (handler, source, toolkit).
router:
toolkits:
- GardenerTools
graph:
gardener:
template: "yaml:gardener"
config:
taxonomy_version: "v2"

Tool isolation: Tools attached via a graph’s template + toolkits apply only to that compiled graph. Router derives the BiDi tool list from federated:* node bindings for registration.

Implementing a Federated Tool

from contextunity.core.sdk.tools import federated_tool
@federated_tool("export_products_for_normalization")
async def export_products_for_normalization(state: dict) -> dict:
"""Export products from the consumer's catalogue for normalisation."""
products = await fetch_products_from_local_db(state.get("filters", {}))
return {"products": products}

The @federated_tool decorator registers the handler in the project ToolRegistry. At RegisterManifest time, Router validates that every template type: tool node with tool_binding: federated:* is satisfied by generated bundle tools from explicit graph bindings or toolkits.

Tool Registration Flow

1. Consumer sends RegisterManifest(yaml) via gRPC
2. Router parses manifest → loads template → validates:
a. All `federated:*` tool bindings have handlers from explicit bindings or toolkits ✓
b. All platform tool_bindings exist in PlatformToolRegistry ✓
c. DAG is valid (no cycles, no phantom nodes) ✓
3. Graph compiled and cached by (tenant_id, graph_name)
4. Consumer opens ToolExecutorStream() — persistent BiDi connection
5. On ExecuteAgent(graph="gardener"):
- Platform nodes execute locally in Router
- Federated nodes stream requests to consumer via BiDi
6. Both kinds emit a unified `tool_result` trace event (`status`, `duration_ms`, `handler`, `source`, `toolkit`, `error`)