The Graph Query Abstraction Layer (src/services/graphQueries.js) provides a clean, semantic API for accessing graph data throughout the system. It hides the complexity of the internal data structure (Maps, instances, prototypes, edges) and provides consistent, well-documented functions.
Previously, graph queries were scattered throughout the codebase with inconsistent patterns:
- Direct access to
store.graphs.get(id) - Manual iteration over Maps and arrays
- Different patterns for checking if
instancesis a Map vs array - Repeated prototype lookups
- Inconsistent error handling
This led to:
- Bugs (like the
(graph.instances || []).map is not a functionerror) - Inconsistency between bridge-daemon and roleRunners
- Confusion for the LLM about what data is available
import { getGraphById, getActiveGraph, graphExists } from './graphQueries.js';
// Get a specific graph
const graph = getGraphById(store, 'graph-123');
// Get the currently active graph
const activeGraph = getActiveGraph(store);
// Check if a graph exists
if (graphExists(store, graphId)) { ... }import { getGraphSemanticStructure } from './graphQueries.js';
// Get nodes, edges, metadata WITHOUT x/y coordinates
const structure = getGraphSemanticStructure(store, graphId, {
includeDescriptions: true,
includeColors: true
});
// Returns:
// {
// graphId, name, nodeCount, edgeCount, isEmpty,
// nodes: [{ id, prototypeId, name, description?, color? }],
// edges: [{ id, sourceId, destinationId, label, directionality, definitionNodeIds }]
// }import { getGraphStatistics, listAllGraphs, findGraphsByName } from './graphQueries.js';
// Get high-level stats for LLM context
const stats = getGraphStatistics(store);
// Returns: { totalGraphs, activeGraph: {...}, allGraphs: [...] }
// List all graphs with node/edge counts
const allGraphs = listAllGraphs(store);
// Search for graphs by name
const results = findGraphsByName(store, 'solar system');Before: Direct access to bridgeStoreData.graphs, manual instance counting
After: Uses getGraphStatistics() and getGraphSemanticStructure()
// bridge-daemon.js lines 990-1013
const stats = getGraphStatistics(bridgeStoreData);
let graphContext = '';
if (stats.activeGraph) {
const ag = stats.activeGraph;
graphContext = `\n\n🎯 CURRENT GRAPH: "${ag.name}"`;
graphContext += `\nStatus: ${ag.nodeCount} nodes, ${ag.edgeCount} connections`;
const structure = getGraphSemanticStructure(bridgeStoreData, ag.id);
const exampleNodes = structure.nodes.slice(0, 3).map(n => n.name).join(', ');
graphContext += `\nExample concepts: ${exampleNodes}`;
}Before: Manual prototype lookups, edge iteration, Map/array handling
After: Uses getGraphSemanticStructure() for read_graph_structure tool
// roleRunners.js lines 602-624
const result = getGraphSemanticStructure(store, graphId, {
includeDescriptions: validation.sanitized.include_descriptions !== false,
includeColors: true
});
ops.push({
type: 'readResponse',
toolName: 'read_graph_structure',
data: result
});The abstraction layer should be referenced in tool schemas:
// toolValidator.js
this.registerSchema('read_graph_structure', {
description: 'Read semantic graph structure (nodes, edges, NO spatial data). See graphQueries.js for data format.',
// ...
});- Single Source of Truth: One place to handle graph data access
- Consistent Error Handling: Returns
{ error: 'Graph not found' }instead of crashing - Type Safety: Clear return types, handles Map vs array internally
- Maintainability: Update data structure in one place
- LLM Clarity: Clear semantic API that maps to tool descriptions
- Debugging: Easier to trace graph access through abstraction layer
- ✅ Create
graphQueries.jsmodule - ✅ Update
roleRunners.jsto usegetGraphSemanticStructure() - ✅ Update
bridge-daemon.jsto usegetGraphStatistics() - 🔄 Update tool descriptions to reference query functions
- 🔄 Update LLM prompts to explicitly list available query functions
- 🔄 Consider adding more semantic queries (e.g.,
getNodesByPrototype,findNodesByName)
See src/services/graphQueries.js for full function signatures and JSDoc comments.
| Function | Purpose | Returns |
|---|---|---|
getGraphById(store, id) |
Get graph by ID | {id, name, instances, edgeIds, metadata} |
getActiveGraph(store) |
Get active graph | Same as above |
getGraphSemanticStructure(store, id, opts) |
Get LLM-friendly structure | {graphId, name, nodes, edges, isEmpty} |
getPrototypeById(store, id) |
Get node prototype | {id, name, description, color} |
getEdgeById(store, id) |
Get edge | {id, sourceId, destinationId, ...} |
listAllGraphs(store) |
List all graphs | [{id, name, nodeCount, edgeCount, isActive}] |
getGraphStatistics(store) |
Get high-level stats | {totalGraphs, activeGraph, allGraphs} |
findGraphsByName(store, term) |
Search graphs by name | [{id, name, ...}] |
graphExists(store, id) |
Check if graph exists | boolean |