Skip to content

agentlib/graph

The graph package provides direct access to TuringDB's Cypher query engine and its metadata procedures. It is the low-level interface used by the agent's graph_query and schema tools.

agentlib/graph/
├── query.py    # run_graph_query() — execute arbitrary Cypher
├── schema.py   # fetch_node_labels(), fetch_edge_types(), fetch_node_label_counts(),
│               #   fetch_edge_type_counts(), fetch_property_types()
├── skeleton.py # build_skeleton() — compact graph summary for LLM context injection
└── context.py  # load_or_build_context() — skeleton with disk cache

query.pyrun_graph_query()

async def run_graph_query(
    cypher_query: str,
    turingdb_host: str = "localhost",
    turingdb_port: int = 1234,
    graph_name: str = "reactome",
) -> list[dict]

Creates a TuringDB client, sets the active graph, executes cypher_query, and returns the results as a list of row dictionaries (DataFrame.to_dict(orient="records")).

Parameters

Parameter Default Description
cypher_query Cypher query string to execute
turingdb_host "localhost" TuringDB host
turingdb_port 1234 TuringDB port
graph_name "reactome" Graph to query

Return value

A list[dict] where each dict is one result row. Column names match the RETURN aliases in the query.

Usage note

run_graph_query is defined as async but the underlying TuringDB.query() call is synchronous. For high-throughput use, consider running it in a thread pool executor to avoid blocking the event loop.

Example queries

Fetch a node by ID:

MATCH (n) WHERE n.dbId = 12345 RETURN n.dbId, n.displayName, n.text

Filter by label:

MATCH (n:Reaction) WHERE n.text IS NOT NULL RETURN n.dbId, n.displayName LIMIT 10

Count nodes by label:

MATCH (n:Pathway) RETURN count(n) as total

Traverse edges:

MATCH (p:Pathway)-[:hasEvent]->(r:ReactionLikeEvent) RETURN p.displayName, r.displayName LIMIT 20

TuringDB Cypher deviations

TuringDB implements a subset of OpenCypher. The agent system prompt includes these rules; they are repeated here as a reference.

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

schema.py — metadata introspection

The schema functions call TuringDB's built-in metadata procedures to discover the graph's structure. They are the implementation layer behind the agent's schema exploration tools (get_node_labels, get_edge_types, etc.).

All functions share the same signature pattern:

async def fetch_*(
    turingdb_host: str = "localhost",
    turingdb_port: int = 1234,
    graph_name: str = "reactome",
) -> list[str] | list[dict]

fetch_node_labels()

async def fetch_node_labels(...) -> list[str]

Calls CALL db.labels() and returns all node label types in the graph as a flat list of strings.

Example return value:

["Pathway", "Reaction", "Protein", "Complex", "Drug", "PhysicalEntity", ...]

fetch_edge_types()

async def fetch_edge_types(...) -> list[str]

Calls CALL db.edgeTypes() and returns all edge (relationship) types in the graph.

Example return value:

["hasEvent", "input", "output", "catalystActivity", "inferredTo", "release", ...]

fetch_node_label_counts()

async def fetch_node_label_counts(...) -> list[dict]

First calls fetch_node_labels(), then for each label issues:

MATCH (n:{label}) RETURN count(n)

Returns a list of {"label": str, "count": int} dicts, one per label. Useful for understanding graph size and node type distribution before designing a query.

Example return value:

[
  {"label": "Pathway", "count": 2547},
  {"label": "Reaction", "count": 15230},
  {"label": "Protein", "count": 10821},
  ...
]

Note

This function issues one query per label. On graphs with many distinct labels it may take a few seconds to complete.


fetch_edge_type_counts()

async def fetch_edge_type_counts(...) -> list[dict]

First calls fetch_edge_types(), then for each type issues:

MATCH ()-[e:{edge_type}]->() RETURN count(e)

Returns a list of {"edge_type": str, "count": int} dicts, one per relationship type.

Example return value:

[
  {"edge_type": "input", "count": 52130},
  {"edge_type": "output", "count": 43210},
  {"edge_type": "hasEvent", "count": 18420},
  ...
]

Note

Like fetch_node_label_counts, this issues one query per edge type. On graphs with many relationship types it may be slow.


fetch_property_types()

async def fetch_property_types(...) -> list[dict]

Calls CALL db.propertyTypes() and returns all property names and their types across both nodes and edges.

Example return value:

[
  {"propertyName": "dbId", "propertyType": "Integer"},
  {"propertyName": "displayName", "propertyType": "String"},
  {"propertyName": "text", "propertyType": "String"},
  {"propertyName": "isChimeric", "propertyType": "Boolean"},
  ...
]