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.py — run_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"},
...
]