Skip to content

chat-agent/tools

The tools package defines the function schemas exposed to the LLM during the agentic loop and the Python functions that execute them.

The agent has access to 8 tools across three categories: retrieval, graph query, and schema exploration.


Tool registry

tools/__init__.py exports two objects consumed by agent_handler:

TOOLS    # list of OpenAI-compatible function schema dicts (sent to the LLM)
TOOL_MAP # dict mapping tool name → async Python function

Retrieval tools

get_graph_overview

Returns a compact structural map of the graph: node types with their counts and their top relationships. Use this for a quick overview before planning queries — cheaper than calling all schema tools individually.

Schema:

{
  "name": "get_graph_overview",
  "description": "Returns a compact overview of the graph: node types with counts and their top relationships.",
  "parameters": {}
}

Implementation (tools/graph_overview.py): thin wrapper around agentlib.graph.context.load_or_build_context(), which returns the cached skeleton generated at server startup.


Semantic similarity search over the knowledge graph. Embeds the query and returns the top-k nodes whose text property is closest in vector space.

Schema:

{
  "name": "vector_search",
  "description": "Semantic search over the knowledge base. Use for factual lookup.",
  "parameters": {
    "query": { "type": "string" },
    "top_k": { "type": "integer", "default": 5 }
  },
  "required": ["query"]
}

Implementation (tools/vector_search.py):

  1. Creates a TuringDB client and sets the active graph.
  2. Embeds query using agentlib.rag.embeddings.make_handler().
  3. Calls VectorIndexManager.vector_search() and returns results as list[dict].

Results from all vector_search calls during an agent loop are collected into the sources list on the final response.


graph_query

Executes a raw Cypher query against TuringDB. Used for structured graph traversal, filtering across multiple criteria, and aggregations that vector search cannot handle.

Schema:

{
  "name": "graph_query",
  "description": "Execute a TuringDB Cypher query for structured graph traversal or aggregation.",
  "parameters": {
    "cypher": { "type": "string" }
  },
  "required": ["cypher"]
}

Implementation (tools/query_graph.py): thin wrapper around agentlib.graph.query.run_graph_query(). See agentlib/graph for full query semantics.

Return value: list[dict] — one dict per result row, column names matching the RETURN aliases.

TuringDB Cypher deviations

TuringDB uses a Cypher subset. The agent system prompt includes these rules; they are repeated here as a reference.

Standard Cypher TuringDB
RETURN n (full node) Returns internal node ID only — use RETURN n.property
labels(n) anywhere Supported in RETURN only, not in WHERE
type(r) Use edgeType(r)
WITH Not supported
CONTAINS Not supported
DISTINCT Not supported
GROUP BY Not supported
Arithmetic in WHERE Not supported — use in RETURN only
WHERE x IN [...] Not supported

Schema exploration tools

These tools let the LLM iteratively discover the graph structure before writing a graph_query. They are thin wrappers around agentlib.graph.schema functions, which call TuringDB procedures directly.

The agent is instructed to call schema tools one at a time as needed, rather than fetching the full schema upfront.

get_node_labels

Returns all node label types in the graph.

{ "name": "get_node_labels", "parameters": {} }

Calls CALL db.labels(). Returns list[str].


get_edge_types

Returns all edge (relationship) types in the graph.

{ "name": "get_edge_types", "parameters": {} }

Calls CALL db.edgeTypes(). Returns list[str].


get_node_label_counts

Returns each node label with its total node count. Useful for gauging graph size and node type distribution before designing a query.

{ "name": "get_node_label_counts", "parameters": {} }

Calls CALL db.labels() then issues MATCH (n:{label}) RETURN count(n) per label. Returns list[dict] with keys label and count.


get_edge_type_counts

Returns each edge type with its total edge count. Useful for gauging relationship density before designing a query.

{ "name": "get_edge_type_counts", "parameters": {} }

Calls CALL db.edgeTypes() then issues MATCH ()-[e:{type}]->() RETURN count(e) per type. Returns list[dict] with keys edge_type and count.


get_property_types

Returns all property names and their types across nodes and edges.

{ "name": "get_property_types", "parameters": {} }

Calls CALL db.propertyTypes(). Returns list[dict].


The agent system prompt guides the LLM to use tools in this order:

  1. Check the graph skeleton (injected at startup) for a structural overview.
  2. Call get_node_labels or get_edge_types if the skeleton does not cover what is needed.
  3. Call get_node_label_counts or get_edge_type_counts to understand size and density.
  4. Call get_property_types to discover available properties for a specific query.
  5. Call graph_query with a well-formed TuringDB Cypher query.
  6. Call vector_search for free-text or semantic lookups.

Adding a new tool

  1. Create tools/my_tool.py with an async def tool_my_tool(...) -> list[dict] function.
  2. Add the OpenAI function schema dict to the TOOLS list in tools/__init__.py.
  3. Add "my_tool": tool_my_tool to TOOL_MAP.

The agent handler dispatches to TOOL_MAP by name — no other changes needed.