Navegador

navegador / docs / api / graph.md
Source Blame History 281 lines
ce0374a… lmata 1 # Graph API
ce0374a… lmata 2
ce0374a… lmata 3 ```python
ce0374a… lmata 4 from navegador.graph import GraphStore
ce0374a… lmata 5 from navegador.context import ContextLoader, ContextBundle, ContextNode
ce0374a… lmata 6 ```
ce0374a… lmata 7
ce0374a… lmata 8 ---
ce0374a… lmata 9
ce0374a… lmata 10 ## GraphStore
ce0374a… lmata 11
ce0374a… lmata 12 The database abstraction layer. Both SQLite and Redis backends implement this interface.
ce0374a… lmata 13
ce0374a… lmata 14 ```python
ce0374a… lmata 15 class GraphStore:
ce0374a… lmata 16 @classmethod
ce0374a… lmata 17 def sqlite(cls, path: str | Path = "navegador.db") -> "GraphStore": ...
ce0374a… lmata 18
ce0374a… lmata 19 @classmethod
ce0374a… lmata 20 def redis(cls, url: str = "redis://localhost:6379") -> "GraphStore": ...
ce0374a… lmata 21
ce0374a… lmata 22 def query(
ce0374a… lmata 23 self,
ce0374a… lmata 24 cypher: str,
ce0374a… lmata 25 params: dict | None = None,
ce0374a… lmata 26 ) -> list[dict]: ...
ce0374a… lmata 27
ce0374a… lmata 28 def create_node(
ce0374a… lmata 29 self,
ce0374a… lmata 30 label: str,
ce0374a… lmata 31 properties: dict,
ce0374a… lmata 32 ) -> str: ... # returns node ID
ce0374a… lmata 33
ce0374a… lmata 34 def merge_node(
ce0374a… lmata 35 self,
ce0374a… lmata 36 label: str,
ce0374a… lmata 37 match_properties: dict,
ce0374a… lmata 38 set_properties: dict | None = None,
ce0374a… lmata 39 ) -> str: ... # upsert by match_properties, returns node ID
ce0374a… lmata 40
ce0374a… lmata 41 def create_edge(
ce0374a… lmata 42 self,
ce0374a… lmata 43 from_id: str,
ce0374a… lmata 44 to_id: str,
ce0374a… lmata 45 edge_type: str,
ce0374a… lmata 46 properties: dict | None = None,
ce0374a… lmata 47 ) -> None: ...
ce0374a… lmata 48
ce0374a… lmata 49 def merge_edge(
ce0374a… lmata 50 self,
ce0374a… lmata 51 from_label: str,
ce0374a… lmata 52 from_match: dict,
ce0374a… lmata 53 to_label: str,
ce0374a… lmata 54 to_match: dict,
ce0374a… lmata 55 edge_type: str,
ce0374a… lmata 56 properties: dict | None = None,
ce0374a… lmata 57 ) -> None: ...
ce0374a… lmata 58
ce0374a… lmata 59 def clear(self) -> None: ...
ce0374a… lmata 60
ce0374a… lmata 61 def close(self) -> None: ...
89816aa… lmata 62
89816aa… lmata 63 def export_jsonl(self, fp: IO[str]) -> None: ...
89816aa… lmata 64 """Write all nodes and edges to a JSONL stream."""
89816aa… lmata 65
89816aa… lmata 66 def import_jsonl(self, fp: IO[str]) -> None: ...
89816aa… lmata 67 """Read nodes and edges from a JSONL stream and merge into the graph."""
ce0374a… lmata 68 ```
ce0374a… lmata 69
ce0374a… lmata 70 ### Usage
ce0374a… lmata 71
ce0374a… lmata 72 ```python
ce0374a… lmata 73 # SQLite (local dev)
ce0374a… lmata 74 store = GraphStore.sqlite(".navegador/navegador.db")
ce0374a… lmata 75
ce0374a… lmata 76 # Redis (production)
ce0374a… lmata 77 store = GraphStore.redis("redis://localhost:6379")
ce0374a… lmata 78
ce0374a… lmata 79 # raw Cypher query
ce0374a… lmata 80 results = store.query(
ce0374a… lmata 81 "MATCH (f:Function {name: $name}) RETURN f",
ce0374a… lmata 82 params={"name": "validate_token"}
ce0374a… lmata 83 )
ce0374a… lmata 84
ce0374a… lmata 85 # create a node
ce0374a… lmata 86 node_id = store.create_node("Concept", {
ce0374a… lmata 87 "name": "Idempotency",
ce0374a… lmata 88 "description": "Operations safe to retry"
ce0374a… lmata 89 })
ce0374a… lmata 90
ce0374a… lmata 91 # upsert a node (match by name, update description)
ce0374a… lmata 92 node_id = store.merge_node(
ce0374a… lmata 93 "Concept",
ce0374a… lmata 94 match_properties={"name": "Idempotency"},
ce0374a… lmata 95 set_properties={"description": "Updated description"}
ce0374a… lmata 96 )
ce0374a… lmata 97
ce0374a… lmata 98 # create an edge
ce0374a… lmata 99 store.create_edge(from_id, to_id, "ANNOTATES")
ce0374a… lmata 100
ce0374a… lmata 101 # wipe the graph
ce0374a… lmata 102 store.clear()
ce0374a… lmata 103 ```
ce0374a… lmata 104
ce0374a… lmata 105 ### Context manager
ce0374a… lmata 106
ce0374a… lmata 107 `GraphStore` implements the context manager protocol:
ce0374a… lmata 108
ce0374a… lmata 109 ```python
ce0374a… lmata 110 with GraphStore.sqlite(".navegador/navegador.db") as store:
ce0374a… lmata 111 results = store.query("MATCH (n) RETURN count(n) AS total")
ce0374a… lmata 112 ```
ce0374a… lmata 113
ce0374a… lmata 114 ---
ce0374a… lmata 115
ce0374a… lmata 116 ## ContextLoader
ce0374a… lmata 117
ce0374a… lmata 118 Builds structured context bundles from graph queries. Each method corresponds to a CLI command.
ce0374a… lmata 119
ce0374a… lmata 120 ```python
ce0374a… lmata 121 class ContextLoader:
ce0374a… lmata 122 def __init__(self, store: GraphStore) -> None: ...
ce0374a… lmata 123
ce0374a… lmata 124 def load_file(self, path: str) -> ContextBundle: ...
ce0374a… lmata 125
ce0374a… lmata 126 def load_function(
ce0374a… lmata 127 self,
ce0374a… lmata 128 name: str,
ce0374a… lmata 129 *,
ce0374a… lmata 130 file: str = "",
ce0374a… lmata 131 depth: int = 1,
ce0374a… lmata 132 ) -> ContextBundle: ...
ce0374a… lmata 133
ce0374a… lmata 134 def load_class(
ce0374a… lmata 135 self,
ce0374a… lmata 136 name: str,
ce0374a… lmata 137 *,
ce0374a… lmata 138 file: str = "",
ce0374a… lmata 139 ) -> ContextBundle: ...
ce0374a… lmata 140
ce0374a… lmata 141 def explain(
ce0374a… lmata 142 self,
ce0374a… lmata 143 name: str,
ce0374a… lmata 144 *,
ce0374a… lmata 145 file: str = "",
ce0374a… lmata 146 ) -> ContextBundle: ...
ce0374a… lmata 147
ce0374a… lmata 148 def load_concept(self, name: str) -> ContextBundle: ...
ce0374a… lmata 149
ce0374a… lmata 150 def load_domain(self, name: str) -> ContextBundle: ...
ce0374a… lmata 151
ce0374a… lmata 152 def search(
ce0374a… lmata 153 self,
ce0374a… lmata 154 query: str,
ce0374a… lmata 155 *,
ce0374a… lmata 156 all_layers: bool = False,
ce0374a… lmata 157 docs_only: bool = False,
ce0374a… lmata 158 limit: int = 20,
ce0374a… lmata 159 ) -> list[ContextNode]: ...
ce0374a… lmata 160
ce0374a… lmata 161 def search_by_docstring(
ce0374a… lmata 162 self,
ce0374a… lmata 163 query: str,
ce0374a… lmata 164 *,
ce0374a… lmata 165 limit: int = 20,
ce0374a… lmata 166 ) -> list[ContextNode]: ...
ce0374a… lmata 167
ce0374a… lmata 168 def decorated_by(
ce0374a… lmata 169 self,
ce0374a… lmata 170 decorator: str,
ce0374a… lmata 171 ) -> list[ContextNode]: ...
ce0374a… lmata 172 ```
ce0374a… lmata 173
ce0374a… lmata 174 ### Usage
ce0374a… lmata 175
ce0374a… lmata 176 ```python
ce0374a… lmata 177 store = GraphStore.sqlite(".navegador/navegador.db")
ce0374a… lmata 178 loader = ContextLoader(store)
ce0374a… lmata 179
ce0374a… lmata 180 # file context
ce0374a… lmata 181 bundle = loader.load_file("src/auth/service.py")
ce0374a… lmata 182
ce0374a… lmata 183 # function with 2-hop call graph
ce0374a… lmata 184 bundle = loader.load_function("validate_token", depth=2)
ce0374a… lmata 185
ce0374a… lmata 186 # class hierarchy
ce0374a… lmata 187 bundle = loader.load_class("PaymentProcessor", file="src/payments/processor.py")
ce0374a… lmata 188
ce0374a… lmata 189 # universal explain
ce0374a… lmata 190 bundle = loader.explain("AuthService")
ce0374a… lmata 191
ce0374a… lmata 192 # concept with annotated code
ce0374a… lmata 193 bundle = loader.load_concept("Idempotency")
ce0374a… lmata 194
ce0374a… lmata 195 # domain overview
ce0374a… lmata 196 bundle = loader.load_domain("Payments")
ce0374a… lmata 197
ce0374a… lmata 198 # search
ce0374a… lmata 199 nodes = loader.search("rate limit", all_layers=True, limit=10)
ce0374a… lmata 200
ce0374a… lmata 201 # all @login_required functions
ce0374a… lmata 202 nodes = loader.decorated_by("login_required")
ce0374a… lmata 203 ```
ce0374a… lmata 204
ce0374a… lmata 205 ---
ce0374a… lmata 206
ce0374a… lmata 207 ## ContextBundle
ce0374a… lmata 208
ce0374a… lmata 209 The structured result type returned by `ContextLoader` methods.
ce0374a… lmata 210
ce0374a… lmata 211 ```python
ce0374a… lmata 212 @dataclass
ce0374a… lmata 213 class ContextBundle:
ce0374a… lmata 214 root: ContextNode
ce0374a… lmata 215 nodes: list[ContextNode]
ce0374a… lmata 216 edges: list[ContextEdge]
ce0374a… lmata 217 metadata: dict
ce0374a… lmata 218
ce0374a… lmata 219 def to_json(self) -> str: ...
ce0374a… lmata 220 def to_markdown(self) -> str: ...
ce0374a… lmata 221 def to_dict(self) -> dict: ...
ce0374a… lmata 222 ```
ce0374a… lmata 223
ce0374a… lmata 224 ---
ce0374a… lmata 225
ce0374a… lmata 226 ## ContextNode
ce0374a… lmata 227
ce0374a… lmata 228 A single node in a context bundle.
ce0374a… lmata 229
ce0374a… lmata 230 ```python
ce0374a… lmata 231 @dataclass
ce0374a… lmata 232 class ContextNode:
ce0374a… lmata 233 id: str
ce0374a… lmata 234 label: str # e.g. "Function", "Concept"
ce0374a… lmata 235 name: str
ce0374a… lmata 236 properties: dict # all node properties
ce0374a… lmata 237 layer: str # "code" or "knowledge"
ce0374a… lmata 238 ```
ce0374a… lmata 239
ce0374a… lmata 240 ---
ce0374a… lmata 241
ce0374a… lmata 242 ## ContextEdge
ce0374a… lmata 243
ce0374a… lmata 244 ```python
ce0374a… lmata 245 @dataclass
ce0374a… lmata 246 class ContextEdge:
ce0374a… lmata 247 from_id: str
ce0374a… lmata 248 to_id: str
ce0374a… lmata 249 edge_type: str # e.g. "CALLS", "ANNOTATES"
ce0374a… lmata 250 properties: dict
ce0374a… lmata 251 ```
89816aa… lmata 252
89816aa… lmata 253 ---
89816aa… lmata 254
89816aa… lmata 255 ## Schema migrations
89816aa… lmata 256
89816aa… lmata 257 ```python
89816aa… lmata 258 from navegador.graph import migrate
89816aa… lmata 259
89816aa… lmata 260 store = GraphStore.sqlite(".navegador/navegador.db")
89816aa… lmata 261 migrate(store) # applies any pending schema migrations; idempotent
89816aa… lmata 262 ```
89816aa… lmata 263
89816aa… lmata 264 The `migrate()` function is safe to call on every startup. It compares the stored migration version against the current schema and applies only missing migrations.
ce0374a… lmata 265
ce0374a… lmata 266 ---
ce0374a… lmata 267
ce0374a… lmata 268 ## Formatting output
ce0374a… lmata 269
ce0374a… lmata 270 ```python
ce0374a… lmata 271 bundle = loader.load_function("validate_token")
ce0374a… lmata 272
ce0374a… lmata 273 # JSON string
ce0374a… lmata 274 print(bundle.to_json())
ce0374a… lmata 275
ce0374a… lmata 276 # Markdown string (for agent consumption)
ce0374a… lmata 277 print(bundle.to_markdown())
5e4b8e4… anonymous 278
ce0374a… lmata 279 # Python dict (for further processing)
ce0374a… lmata 280 data = bundle.to_dict()
ce0374a… lmata 281 ```

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button