|
89816aa…
|
lmata
|
1 |
# Intelligence Layer |
|
89816aa…
|
lmata
|
2 |
|
|
89816aa…
|
lmata
|
3 |
The intelligence layer adds capabilities that go beyond structural graph queries: semantic similarity search, community detection, natural language queries, and documentation generation. These features require an LLM provider or embedding model. |
|
89816aa…
|
lmata
|
4 |
|
|
89816aa…
|
lmata
|
5 |
--- |
|
89816aa…
|
lmata
|
6 |
|
|
89816aa…
|
lmata
|
7 |
## Setup |
|
89816aa…
|
lmata
|
8 |
|
|
89816aa…
|
lmata
|
9 |
Install the intelligence extras: |
|
89816aa…
|
lmata
|
10 |
|
|
89816aa…
|
lmata
|
11 |
```bash |
|
89816aa…
|
lmata
|
12 |
pip install "navegador[intelligence]" |
|
89816aa…
|
lmata
|
13 |
``` |
|
89816aa…
|
lmata
|
14 |
|
|
89816aa…
|
lmata
|
15 |
Configure your LLM provider: |
|
89816aa…
|
lmata
|
16 |
|
|
89816aa…
|
lmata
|
17 |
=== "OpenAI" |
|
89816aa…
|
lmata
|
18 |
|
|
89816aa…
|
lmata
|
19 |
```bash |
|
89816aa…
|
lmata
|
20 |
export NAVEGADOR_LLM_PROVIDER=openai |
|
89816aa…
|
lmata
|
21 |
export OPENAI_API_KEY=sk-... |
|
89816aa…
|
lmata
|
22 |
``` |
|
89816aa…
|
lmata
|
23 |
|
|
89816aa…
|
lmata
|
24 |
=== "Anthropic" |
|
89816aa…
|
lmata
|
25 |
|
|
89816aa…
|
lmata
|
26 |
```bash |
|
89816aa…
|
lmata
|
27 |
export NAVEGADOR_LLM_PROVIDER=anthropic |
|
89816aa…
|
lmata
|
28 |
export ANTHROPIC_API_KEY=sk-ant-... |
|
89816aa…
|
lmata
|
29 |
``` |
|
89816aa…
|
lmata
|
30 |
|
|
89816aa…
|
lmata
|
31 |
=== "Local (Ollama)" |
|
89816aa…
|
lmata
|
32 |
|
|
89816aa…
|
lmata
|
33 |
```bash |
|
89816aa…
|
lmata
|
34 |
export NAVEGADOR_LLM_PROVIDER=ollama |
|
89816aa…
|
lmata
|
35 |
export NAVEGADOR_LLM_MODEL=llama3.2 |
|
89816aa…
|
lmata
|
36 |
# no API key required; Ollama must be running on localhost:11434 |
|
89816aa…
|
lmata
|
37 |
``` |
|
89816aa…
|
lmata
|
38 |
|
|
89816aa…
|
lmata
|
39 |
Or set via `navegador.toml`: |
|
89816aa…
|
lmata
|
40 |
|
|
89816aa…
|
lmata
|
41 |
```toml |
|
89816aa…
|
lmata
|
42 |
[intelligence] |
|
89816aa…
|
lmata
|
43 |
provider = "openai" |
|
89816aa…
|
lmata
|
44 |
model = "text-embedding-3-small" # embedding model |
|
89816aa…
|
lmata
|
45 |
llm_model = "gpt-4o-mini" # generation model |
|
89816aa…
|
lmata
|
46 |
``` |
|
89816aa…
|
lmata
|
47 |
|
|
89816aa…
|
lmata
|
48 |
--- |
|
89816aa…
|
lmata
|
49 |
|
|
89816aa…
|
lmata
|
50 |
## Semantic search |
|
89816aa…
|
lmata
|
51 |
|
|
89816aa…
|
lmata
|
52 |
Standard `navegador search` matches on names and text. Semantic search matches on **meaning**: a query for "billing" finds code about "invoices", "subscriptions", and "charges" even when those words don't appear in the query. |
|
89816aa…
|
lmata
|
53 |
|
|
89816aa…
|
lmata
|
54 |
```bash |
|
89816aa…
|
lmata
|
55 |
navegador search "handle payment failure" --semantic |
|
89816aa…
|
lmata
|
56 |
navegador search "retry with backoff" --semantic --limit 10 |
|
89816aa…
|
lmata
|
57 |
navegador search "authentication middleware" --semantic --all |
|
89816aa…
|
lmata
|
58 |
``` |
|
89816aa…
|
lmata
|
59 |
|
|
89816aa…
|
lmata
|
60 |
!!! note |
|
89816aa…
|
lmata
|
61 |
First run after ingestion builds the embedding index. This may take a minute on large codebases. The index is cached in the database and updated incrementally on re-ingest. |
|
89816aa…
|
lmata
|
62 |
|
|
89816aa…
|
lmata
|
63 |
### Combining semantic and text search |
|
89816aa…
|
lmata
|
64 |
|
|
89816aa…
|
lmata
|
65 |
```bash |
|
89816aa…
|
lmata
|
66 |
# semantic search scoped to a domain |
|
89816aa…
|
lmata
|
67 |
navegador search "billing failure" --semantic --domain Payments |
|
89816aa…
|
lmata
|
68 |
|
|
89816aa…
|
lmata
|
69 |
# hybrid: semantic ranking with text pre-filter |
|
89816aa…
|
lmata
|
70 |
navegador search "rate limit" --semantic --all |
|
89816aa…
|
lmata
|
71 |
``` |
|
89816aa…
|
lmata
|
72 |
|
|
89816aa…
|
lmata
|
73 |
### Python API |
|
89816aa…
|
lmata
|
74 |
|
|
89816aa…
|
lmata
|
75 |
```python |
|
89816aa…
|
lmata
|
76 |
from navegador.graph import GraphStore |
|
89816aa…
|
lmata
|
77 |
from navegador.intelligence import SemanticSearch |
|
89816aa…
|
lmata
|
78 |
|
|
89816aa…
|
lmata
|
79 |
store = GraphStore.sqlite(".navegador/navegador.db") |
|
89816aa…
|
lmata
|
80 |
search = SemanticSearch(store) |
|
89816aa…
|
lmata
|
81 |
|
|
89816aa…
|
lmata
|
82 |
results = search.query("handle payment failure", limit=10) |
|
89816aa…
|
lmata
|
83 |
for node in results: |
|
89816aa…
|
lmata
|
84 |
print(f"[{node.label}] {node.name} score={node.score:.3f}") |
|
89816aa…
|
lmata
|
85 |
``` |
|
89816aa…
|
lmata
|
86 |
|
|
89816aa…
|
lmata
|
87 |
--- |
|
89816aa…
|
lmata
|
88 |
|
|
89816aa…
|
lmata
|
89 |
## Community detection |
|
89816aa…
|
lmata
|
90 |
|
|
89816aa…
|
lmata
|
91 |
Community detection groups nodes in the graph into clusters based on structural connectivity. Clusters typically correspond to logical modules or subsystems, even when the code doesn't explicitly organize itself that way. |
|
89816aa…
|
lmata
|
92 |
|
|
89816aa…
|
lmata
|
93 |
```bash |
|
89816aa…
|
lmata
|
94 |
navegador intelligence communities |
|
89816aa…
|
lmata
|
95 |
navegador intelligence communities --algorithm louvain |
|
89816aa…
|
lmata
|
96 |
navegador intelligence communities --format json |
|
89816aa…
|
lmata
|
97 |
``` |
|
89816aa…
|
lmata
|
98 |
|
|
89816aa…
|
lmata
|
99 |
### Algorithms |
|
89816aa…
|
lmata
|
100 |
|
|
89816aa…
|
lmata
|
101 |
| Algorithm | Best for | |
|
89816aa…
|
lmata
|
102 |
|---|---| |
|
89816aa…
|
lmata
|
103 |
| `louvain` (default) | Large codebases; fast and produces stable clusters | |
|
89816aa…
|
lmata
|
104 |
| `leiden` | Higher modularity; slower | |
|
89816aa…
|
lmata
|
105 |
| `label-propagation` | Very large graphs | |
|
89816aa…
|
lmata
|
106 |
|
|
89816aa…
|
lmata
|
107 |
### Output |
|
89816aa…
|
lmata
|
108 |
|
|
89816aa…
|
lmata
|
109 |
``` |
|
89816aa…
|
lmata
|
110 |
Detected 6 communities: |
|
89816aa…
|
lmata
|
111 |
|
|
89816aa…
|
lmata
|
112 |
Community 1 (47 nodes) — suggested name: Auth |
|
89816aa…
|
lmata
|
113 |
Core: AuthService, validate_token, JWTManager |
|
89816aa…
|
lmata
|
114 |
Files: src/auth/ (12 files) |
|
89816aa…
|
lmata
|
115 |
|
|
89816aa…
|
lmata
|
116 |
Community 2 (38 nodes) — suggested name: Payments |
|
89816aa…
|
lmata
|
117 |
Core: PaymentProcessor, charge_card, StripeClient |
|
89816aa…
|
lmata
|
118 |
Files: src/payments/ (9 files) |
|
89816aa…
|
lmata
|
119 |
|
|
89816aa…
|
lmata
|
120 |
Community 3 (22 nodes) — suggested name: Orders |
|
89816aa…
|
lmata
|
121 |
Core: OrderService, create_order, OrderRepository |
|
89816aa…
|
lmata
|
122 |
Files: src/orders/ (6 files) |
|
89816aa…
|
lmata
|
123 |
... |
|
89816aa…
|
lmata
|
124 |
``` |
|
89816aa…
|
lmata
|
125 |
|
|
89816aa…
|
lmata
|
126 |
Suggested names are generated by the LLM by inspecting the core nodes of each cluster. |
|
89816aa…
|
lmata
|
127 |
|
|
89816aa…
|
lmata
|
128 |
### Persisting communities |
|
89816aa…
|
lmata
|
129 |
|
|
89816aa…
|
lmata
|
130 |
```bash |
|
89816aa…
|
lmata
|
131 |
navegador intelligence communities --save |
|
89816aa…
|
lmata
|
132 |
``` |
|
89816aa…
|
lmata
|
133 |
|
|
89816aa…
|
lmata
|
134 |
This writes `Community` nodes and `MEMBER_OF` edges into the graph, making communities queryable: |
|
89816aa…
|
lmata
|
135 |
|
|
89816aa…
|
lmata
|
136 |
```bash |
|
89816aa…
|
lmata
|
137 |
navegador query "MATCH (f:Function)-[:MEMBER_OF]->(c:Community) WHERE c.name = 'Payments' RETURN f.name, f.file" |
|
89816aa…
|
lmata
|
138 |
``` |
|
89816aa…
|
lmata
|
139 |
|
|
89816aa…
|
lmata
|
140 |
--- |
|
89816aa…
|
lmata
|
141 |
|
|
89816aa…
|
lmata
|
142 |
## Natural language queries |
|
89816aa…
|
lmata
|
143 |
|
|
89816aa…
|
lmata
|
144 |
`navegador ask` lets you query the graph in plain English. The LLM translates your question into Cypher, executes it, and returns a natural language answer with citations. |
|
89816aa…
|
lmata
|
145 |
|
|
89816aa…
|
lmata
|
146 |
```bash |
|
89816aa…
|
lmata
|
147 |
navegador ask "Which functions call process_payment?" |
|
89816aa…
|
lmata
|
148 |
navegador ask "What rules govern the Payments domain?" |
|
89816aa…
|
lmata
|
149 |
navegador ask "Show me all classes that inherit from BaseProcessor" |
|
89816aa…
|
lmata
|
150 |
navegador ask "What decisions have been made about the database?" |
|
89816aa…
|
lmata
|
151 |
``` |
|
89816aa…
|
lmata
|
152 |
|
|
89816aa…
|
lmata
|
153 |
### How it works |
|
89816aa…
|
lmata
|
154 |
|
|
89816aa…
|
lmata
|
155 |
1. Your question is embedded and matched against graph schema context |
|
89816aa…
|
lmata
|
156 |
2. The LLM generates a Cypher query based on the question and schema |
|
89816aa…
|
lmata
|
157 |
3. Navegador executes the query against the graph |
|
89816aa…
|
lmata
|
158 |
4. The LLM formats the results as a natural language answer with source references |
|
89816aa…
|
lmata
|
159 |
|
|
89816aa…
|
lmata
|
160 |
### Safety |
|
89816aa…
|
lmata
|
161 |
|
|
89816aa…
|
lmata
|
162 |
Generated queries are run in read-only mode. Write operations (`CREATE`, `MERGE`, `DELETE`, `SET`) in generated queries are blocked. |
|
89816aa…
|
lmata
|
163 |
|
|
89816aa…
|
lmata
|
164 |
```bash |
|
89816aa…
|
lmata
|
165 |
# show the generated Cypher without executing |
|
89816aa…
|
lmata
|
166 |
navegador ask "Which functions have no tests?" --show-query |
|
89816aa…
|
lmata
|
167 |
|
|
89816aa…
|
lmata
|
168 |
# execute and show both Cypher and answer |
|
89816aa…
|
lmata
|
169 |
navegador ask "Which functions have no tests?" --verbose |
|
89816aa…
|
lmata
|
170 |
``` |
|
89816aa…
|
lmata
|
171 |
|
|
89816aa…
|
lmata
|
172 |
--- |
|
89816aa…
|
lmata
|
173 |
|
|
89816aa…
|
lmata
|
174 |
## Documentation generation |
|
89816aa…
|
lmata
|
175 |
|
|
89816aa…
|
lmata
|
176 |
`navegador docgen` generates or improves docstrings for undocumented functions and classes, using graph context to produce accurate, context-aware descriptions. |
|
89816aa…
|
lmata
|
177 |
|
|
89816aa…
|
lmata
|
178 |
```bash |
|
89816aa…
|
lmata
|
179 |
# generate docs for all undocumented functions in a file |
|
89816aa…
|
lmata
|
180 |
navegador docgen src/payments/processor.py |
|
89816aa…
|
lmata
|
181 |
|
|
89816aa…
|
lmata
|
182 |
# generate docs for a specific function |
|
89816aa…
|
lmata
|
183 |
navegador docgen --target process_payment |
|
89816aa…
|
lmata
|
184 |
|
|
89816aa…
|
lmata
|
185 |
# dry run: show what would be generated without writing |
|
89816aa…
|
lmata
|
186 |
navegador docgen src/payments/processor.py --dry-run |
|
89816aa…
|
lmata
|
187 |
|
|
89816aa…
|
lmata
|
188 |
# write directly to source files |
|
89816aa…
|
lmata
|
189 |
navegador docgen src/payments/processor.py --write |
|
89816aa…
|
lmata
|
190 |
``` |
|
89816aa…
|
lmata
|
191 |
|
|
89816aa…
|
lmata
|
192 |
### What it includes |
|
89816aa…
|
lmata
|
193 |
|
|
89816aa…
|
lmata
|
194 |
The generated docstring draws on: |
|
89816aa…
|
lmata
|
195 |
|
|
89816aa…
|
lmata
|
196 |
- The function's call graph (what it calls and what calls it) |
|
89816aa…
|
lmata
|
197 |
- Related concepts and rules from the knowledge layer |
|
89816aa…
|
lmata
|
198 |
- The class or module context |
|
89816aa…
|
lmata
|
199 |
- Existing docstrings in the same file as style examples |
|
89816aa…
|
lmata
|
200 |
|
|
89816aa…
|
lmata
|
201 |
### Output |
|
89816aa…
|
lmata
|
202 |
|
|
89816aa…
|
lmata
|
203 |
```python |
|
89816aa…
|
lmata
|
204 |
def process_payment(order_id: str, amount: Decimal, idempotency_key: str) -> PaymentResult: |
|
89816aa…
|
lmata
|
205 |
"""Process a payment for an order. |
|
89816aa…
|
lmata
|
206 |
|
|
89816aa…
|
lmata
|
207 |
Charges the card on file for the given order using the Stripe payment |
|
89816aa…
|
lmata
|
208 |
processor. Requires an idempotency key to prevent double-charging on |
|
89816aa…
|
lmata
|
209 |
client retries (see: RequireIdempotencyKey rule, UseStripeForPayments |
|
89816aa…
|
lmata
|
210 |
decision). |
|
89816aa…
|
lmata
|
211 |
|
|
89816aa…
|
lmata
|
212 |
Args: |
|
89816aa…
|
lmata
|
213 |
order_id: The unique identifier of the order to charge. |
|
89816aa…
|
lmata
|
214 |
amount: The amount to charge in the order's currency. |
|
89816aa…
|
lmata
|
215 |
idempotency_key: Client-supplied key for idempotent retries. |
|
89816aa…
|
lmata
|
216 |
|
|
89816aa…
|
lmata
|
217 |
Returns: |
|
89816aa…
|
lmata
|
218 |
PaymentResult with charge_id and status. |
|
89816aa…
|
lmata
|
219 |
|
|
89816aa…
|
lmata
|
220 |
Raises: |
|
89816aa…
|
lmata
|
221 |
PaymentError: If the charge fails or the card is declined. |
|
89816aa…
|
lmata
|
222 |
DuplicatePaymentError: If a payment with this idempotency_key |
|
89816aa…
|
lmata
|
223 |
already exists with a different amount. |
|
89816aa…
|
lmata
|
224 |
""" |
|
89816aa…
|
lmata
|
225 |
``` |
|
89816aa…
|
lmata
|
226 |
|
|
89816aa…
|
lmata
|
227 |
### Batch generation |
|
89816aa…
|
lmata
|
228 |
|
|
89816aa…
|
lmata
|
229 |
```bash |
|
89816aa…
|
lmata
|
230 |
# generate docs for all undocumented functions in the repo |
|
89816aa…
|
lmata
|
231 |
navegador docgen ./src --write --format google |
|
89816aa…
|
lmata
|
232 |
|
|
89816aa…
|
lmata
|
233 |
# formats: google (default), numpy, sphinx |
|
89816aa…
|
lmata
|
234 |
``` |
|
89816aa…
|
lmata
|
235 |
|
|
89816aa…
|
lmata
|
236 |
!!! warning |
|
89816aa…
|
lmata
|
237 |
`--write` modifies source files in place. Review changes with `--dry-run` first and commit before running with `--write` so you can diff and revert. |
|
89816aa…
|
lmata
|
238 |
|
|
89816aa…
|
lmata
|
239 |
--- |
|
89816aa…
|
lmata
|
240 |
|
|
89816aa…
|
lmata
|
241 |
## Python API |
|
89816aa…
|
lmata
|
242 |
|
|
89816aa…
|
lmata
|
243 |
```python |
|
89816aa…
|
lmata
|
244 |
from navegador.graph import GraphStore |
|
89816aa…
|
lmata
|
245 |
from navegador.intelligence import SemanticSearch, CommunityDetector, NaturalLanguageQuery, DocGenerator |
|
89816aa…
|
lmata
|
246 |
|
|
89816aa…
|
lmata
|
247 |
store = GraphStore.sqlite(".navegador/navegador.db") |
|
89816aa…
|
lmata
|
248 |
|
|
89816aa…
|
lmata
|
249 |
# semantic search |
|
89816aa…
|
lmata
|
250 |
search = SemanticSearch(store) |
|
89816aa…
|
lmata
|
251 |
results = search.query("retry logic", limit=5) |
|
89816aa…
|
lmata
|
252 |
|
|
89816aa…
|
lmata
|
253 |
# community detection |
|
89816aa…
|
lmata
|
254 |
detector = CommunityDetector(store) |
|
89816aa…
|
lmata
|
255 |
communities = detector.detect(algorithm="louvain", save=True) |
|
89816aa…
|
lmata
|
256 |
|
|
89816aa…
|
lmata
|
257 |
# natural language query |
|
89816aa…
|
lmata
|
258 |
nlq = NaturalLanguageQuery(store) |
|
89816aa…
|
lmata
|
259 |
answer = nlq.ask("What functions call process_payment?") |
|
89816aa…
|
lmata
|
260 |
print(answer.text) |
|
89816aa…
|
lmata
|
261 |
print(answer.cypher) # generated Cypher |
|
89816aa…
|
lmata
|
262 |
|
|
89816aa…
|
lmata
|
263 |
# doc generation |
|
89816aa…
|
lmata
|
264 |
docgen = DocGenerator(store) |
|
89816aa…
|
lmata
|
265 |
draft = docgen.generate_for_function("process_payment") |
|
89816aa…
|
lmata
|
266 |
print(draft.docstring) |
|
89816aa…
|
lmata
|
267 |
``` |