ctxgraph 0.2.3__tar.gz → 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ctxgraph-0.2.3 → ctxgraph-0.3.0}/PKG-INFO +156 -75
- {ctxgraph-0.2.3 → ctxgraph-0.3.0}/README.md +155 -74
- {ctxgraph-0.2.3 → ctxgraph-0.3.0}/pyproject.toml +1 -1
- {ctxgraph-0.2.3 → ctxgraph-0.3.0}/src/ctxgraph/capsule/renderer.py +9 -1
- ctxgraph-0.3.0/src/ctxgraph/capsule/savings.py +85 -0
- ctxgraph-0.3.0/src/ctxgraph/cli/main.py +537 -0
- ctxgraph-0.3.0/src/ctxgraph/config/init.py +26 -0
- ctxgraph-0.3.0/src/ctxgraph/history.py +69 -0
- ctxgraph-0.3.0/src/ctxgraph/skills/__init__.py +38 -0
- {ctxgraph-0.2.3 → ctxgraph-0.3.0}/src/ctxgraph/view/visualizer.py +10 -2
- {ctxgraph-0.2.3 → ctxgraph-0.3.0}/src/ctxgraph.egg-info/PKG-INFO +156 -75
- {ctxgraph-0.2.3 → ctxgraph-0.3.0}/src/ctxgraph.egg-info/SOURCES.txt +5 -0
- ctxgraph-0.3.0/tests/test_e2e.py +219 -0
- ctxgraph-0.2.3/src/ctxgraph/cli/main.py +0 -262
- {ctxgraph-0.2.3 → ctxgraph-0.3.0}/setup.cfg +0 -0
- {ctxgraph-0.2.3 → ctxgraph-0.3.0}/src/ctxgraph/__init__.py +0 -0
- {ctxgraph-0.2.3 → ctxgraph-0.3.0}/src/ctxgraph/analyzers/__init__.py +0 -0
- {ctxgraph-0.2.3 → ctxgraph-0.3.0}/src/ctxgraph/analyzers/python/__init__.py +0 -0
- {ctxgraph-0.2.3 → ctxgraph-0.3.0}/src/ctxgraph/analyzers/python/importer.py +0 -0
- {ctxgraph-0.2.3 → ctxgraph-0.3.0}/src/ctxgraph/analyzers/python/semantic.py +0 -0
- {ctxgraph-0.2.3 → ctxgraph-0.3.0}/src/ctxgraph/analyzers/python/symbols.py +0 -0
- {ctxgraph-0.2.3 → ctxgraph-0.3.0}/src/ctxgraph/capsule/__init__.py +0 -0
- {ctxgraph-0.2.3 → ctxgraph-0.3.0}/src/ctxgraph/cli/__init__.py +0 -0
- {ctxgraph-0.2.3 → ctxgraph-0.3.0}/src/ctxgraph/clients/__init__.py +0 -0
- {ctxgraph-0.2.3 → ctxgraph-0.3.0}/src/ctxgraph/clients/models.py +0 -0
- {ctxgraph-0.2.3 → ctxgraph-0.3.0}/src/ctxgraph/config/__init__.py +0 -0
- {ctxgraph-0.2.3 → ctxgraph-0.3.0}/src/ctxgraph/config/providers.py +0 -0
- {ctxgraph-0.2.3 → ctxgraph-0.3.0}/src/ctxgraph/config/settings.py +0 -0
- {ctxgraph-0.2.3 → ctxgraph-0.3.0}/src/ctxgraph/exclude/__init__.py +0 -0
- {ctxgraph-0.2.3 → ctxgraph-0.3.0}/src/ctxgraph/exclude/patterns.py +0 -0
- {ctxgraph-0.2.3 → ctxgraph-0.3.0}/src/ctxgraph/graph/__init__.py +0 -0
- {ctxgraph-0.2.3 → ctxgraph-0.3.0}/src/ctxgraph/graph/builder.py +0 -0
- {ctxgraph-0.2.3 → ctxgraph-0.3.0}/src/ctxgraph/graph/models.py +0 -0
- {ctxgraph-0.2.3 → ctxgraph-0.3.0}/src/ctxgraph/graph/query.py +0 -0
- {ctxgraph-0.2.3 → ctxgraph-0.3.0}/src/ctxgraph/graph/storage.py +0 -0
- {ctxgraph-0.2.3 → ctxgraph-0.3.0}/src/ctxgraph/mcp/__init__.py +0 -0
- {ctxgraph-0.2.3 → ctxgraph-0.3.0}/src/ctxgraph/mcp/server.py +0 -0
- {ctxgraph-0.2.3 → ctxgraph-0.3.0}/src/ctxgraph/view/__init__.py +0 -0
- {ctxgraph-0.2.3 → ctxgraph-0.3.0}/src/ctxgraph/wrapper/__init__.py +0 -0
- {ctxgraph-0.2.3 → ctxgraph-0.3.0}/src/ctxgraph/wrapper/claude.py +0 -0
- {ctxgraph-0.2.3 → ctxgraph-0.3.0}/src/ctxgraph.egg-info/dependency_links.txt +0 -0
- {ctxgraph-0.2.3 → ctxgraph-0.3.0}/src/ctxgraph.egg-info/entry_points.txt +0 -0
- {ctxgraph-0.2.3 → ctxgraph-0.3.0}/src/ctxgraph.egg-info/requires.txt +0 -0
- {ctxgraph-0.2.3 → ctxgraph-0.3.0}/src/ctxgraph.egg-info/top_level.txt +0 -0
- {ctxgraph-0.2.3 → ctxgraph-0.3.0}/tests/test_analyzers.py +0 -0
- {ctxgraph-0.2.3 → ctxgraph-0.3.0}/tests/test_benchmark.py +0 -0
- {ctxgraph-0.2.3 → ctxgraph-0.3.0}/tests/test_capsule.py +0 -0
- {ctxgraph-0.2.3 → ctxgraph-0.3.0}/tests/test_config.py +0 -0
- {ctxgraph-0.2.3 → ctxgraph-0.3.0}/tests/test_integration.py +0 -0
- {ctxgraph-0.2.3 → ctxgraph-0.3.0}/tests/test_model_mode.py +0 -0
- {ctxgraph-0.2.3 → ctxgraph-0.3.0}/tests/test_models.py +0 -0
- {ctxgraph-0.2.3 → ctxgraph-0.3.0}/tests/test_query.py +0 -0
- {ctxgraph-0.2.3 → ctxgraph-0.3.0}/tests/test_storage.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ctxgraph
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: AI context engine for Python — cuts LLM tokens 97% via code knowledge graphs. Build, query, and generate compact context capsules for Claude, OpenAI, Ollama.
|
|
5
5
|
Author: ctxgraph contributors
|
|
6
6
|
License: MIT
|
|
@@ -86,10 +86,10 @@ Repository (.py files)
|
|
|
86
86
|
### Architecture
|
|
87
87
|
|
|
88
88
|
```
|
|
89
|
-
┌─────────┐ ┌──────────────┐ ┌──────────────┐
|
|
90
|
-
│ CLI │───▶│ Analyzers │───▶│ SQLite DB │
|
|
91
|
-
│ typer │ │ AST-based │ │ .ctxgraph/ │
|
|
92
|
-
└────┬────┘ └──────────────┘ └──────┬───────┘
|
|
89
|
+
┌─────────┐ ┌──────────────┐ ┌──────────────┐ ┌─────────────┐
|
|
90
|
+
│ CLI │───▶│ Analyzers │───▶│ SQLite DB │───▶│ Skills/Hist │
|
|
91
|
+
│ typer │ │ AST-based │ │ .ctxgraph/ │ │ .ctxgraph/ │
|
|
92
|
+
└────┬────┘ └──────────────┘ └──────┬───────┘ └─────────────┘
|
|
93
93
|
│ │
|
|
94
94
|
├── ctx build ──────────────────────▶│ Graph build
|
|
95
95
|
│ │
|
|
@@ -97,9 +97,17 @@ Repository (.py files)
|
|
|
97
97
|
│ │
|
|
98
98
|
├── ctx query ◀─────────────────────│ Keyword search
|
|
99
99
|
│ │
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
100
|
+
├── ctx ask ◀──────────────────────│ LLM query + savings
|
|
101
|
+
│ │
|
|
102
|
+
├── ctx view ◀──────────────────────│ D3.js viz
|
|
103
|
+
│ │
|
|
104
|
+
├── ctx serve ◀─────────────────────│ MCP server
|
|
105
|
+
│ │
|
|
106
|
+
├── ctx init ───────────────────────│ Scaffold project
|
|
107
|
+
│ │
|
|
108
|
+
├── ctx history ◀───────────────────│ Query log
|
|
109
|
+
│ │
|
|
110
|
+
└── ctx skill ◀─────────────────────│ Skill management
|
|
103
111
|
│ │
|
|
104
112
|
└── ccg wrapper ───▶ Claude Code ───┘ AI tool
|
|
105
113
|
```
|
|
@@ -159,10 +167,36 @@ JSON: 426 tokens DSL: 143 tokens
|
|
|
159
167
|
|
|
160
168
|
**+16.7pp average coverage improvement** — better answers, concrete file names, real code structure.
|
|
161
169
|
|
|
170
|
+
### Token Savings Display
|
|
171
|
+
|
|
172
|
+
Use `--savings` to see how many tokens each capsule saves:
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
ctx capsule "user authentication" --savings
|
|
176
|
+
# ┌──────────────────────────┬──────────────┐
|
|
177
|
+
# │ Metric │ Value │
|
|
178
|
+
# ├──────────────────────────┼──────────────┤
|
|
179
|
+
# │ Raw Project .py Files │ 10,587 tokens│
|
|
180
|
+
# │ Capsule DSL │ 132 tokens │
|
|
181
|
+
# │ JSON Equivalent │ 490 tokens │
|
|
182
|
+
# │ Savings vs Raw │ 98.8% │
|
|
183
|
+
# │ DSL vs JSON │ 73.1% │
|
|
184
|
+
# └──────────────────────────┴──────────────┘
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
`ctx ask` shows this automatically on every query.
|
|
188
|
+
|
|
162
189
|
---
|
|
163
190
|
|
|
164
191
|
## Commands
|
|
165
192
|
|
|
193
|
+
### `ctx init` — Scaffold project
|
|
194
|
+
```bash
|
|
195
|
+
ctx init
|
|
196
|
+
# Creates: .ctxgraph/config.toml, .ctxgraph/skills/, .ctxgraph/history.jsonl
|
|
197
|
+
```
|
|
198
|
+
Sets up a fresh `.ctxgraph/` directory with default config and built-in skills. Idempotent — safe to run on existing projects.
|
|
199
|
+
|
|
166
200
|
### `ctx build` — Build knowledge graph
|
|
167
201
|
```bash
|
|
168
202
|
ctx build # Current directory
|
|
@@ -170,12 +204,24 @@ ctx build /path/to/project # Specific repo
|
|
|
170
204
|
ctx build --exclude "vendor/*" # Custom exclude patterns
|
|
171
205
|
```
|
|
172
206
|
|
|
207
|
+
### `ctx ask <query>` — Ask questions via LLM
|
|
208
|
+
```bash
|
|
209
|
+
ctx ask "how does JWT auth work" # Uses configured provider
|
|
210
|
+
ctx ask "fix login bug" --provider claude --model claude-sonnet-4-20250514
|
|
211
|
+
ctx ask "refactor payment flow" --skill project-style # Activate a skill
|
|
212
|
+
ctx ask "find auth code" --graph # Show graph search results
|
|
213
|
+
ctx ask "deep dive" --mode deep # Deep graph context
|
|
214
|
+
```
|
|
215
|
+
Shows token savings automatically. Requires a running Ollama instance (or other configured provider).
|
|
216
|
+
|
|
173
217
|
### `ctx capsule <query>` — Generate context
|
|
174
218
|
```bash
|
|
175
219
|
ctx capsule "fix JWT token validation" # Balanced (default: 20 nodes, depth 2)
|
|
176
220
|
ctx capsule "fix JWT token validation" --mode fast # Fast (10 nodes, depth 1)
|
|
177
221
|
ctx capsule "fix JWT token validation" --mode deep # Deep (40 nodes, depth 3)
|
|
178
222
|
ctx capsule --overview # Project architecture overview
|
|
223
|
+
ctx capsule "fix auth" --savings # Show token savings table
|
|
224
|
+
ctx capsule "fix auth" --skill project-style # Prepends skill context
|
|
179
225
|
```
|
|
180
226
|
|
|
181
227
|
| Mode | Max Nodes | BFS Depth | When to Use |
|
|
@@ -217,6 +263,22 @@ Claude Desktop config:
|
|
|
217
263
|
```
|
|
218
264
|
Tools: `search_graph`, `get_context_capsule`, `get_file_dependencies`, `get_project_overview`.
|
|
219
265
|
|
|
266
|
+
### `ctx history` — Query history
|
|
267
|
+
```bash
|
|
268
|
+
ctx history # Last 10 queries
|
|
269
|
+
ctx history -n 20 # Last 20
|
|
270
|
+
ctx history --filter "auth" # Filter by keyword
|
|
271
|
+
ctx history --stats # Aggregate statistics
|
|
272
|
+
```
|
|
273
|
+
History stored in JSONL format at `.ctxgraph/history.jsonl`. Auto-prunes to 1000 entries.
|
|
274
|
+
|
|
275
|
+
### `ctx skill` — Manage skills
|
|
276
|
+
```bash
|
|
277
|
+
ctx skill list # Show all available skills
|
|
278
|
+
ctx skill show project-style # Display skill contents
|
|
279
|
+
```
|
|
280
|
+
Skills are TOML files in `.ctxgraph/skills/`. Activate with `ctx ask --skill <name>` or `ctx capsule --skill <name>`.
|
|
281
|
+
|
|
220
282
|
### `ctx info` — Graph statistics
|
|
221
283
|
```bash
|
|
222
284
|
ctx info
|
|
@@ -330,9 +392,15 @@ ctx capsule "extract payment processing into separate module" --mode deep
|
|
|
330
392
|
|
|
331
393
|
## Framework Integrations
|
|
332
394
|
|
|
333
|
-
ctxgraph
|
|
395
|
+
ctxgraph is a Python library first — the CLI is just a wrapper. This makes it easy to feed code context into LangChain, LangGraph, OpenAI Agents, or any LLM pipeline.
|
|
396
|
+
|
|
397
|
+
### How the Python API works
|
|
398
|
+
|
|
399
|
+
The flow is always the same:
|
|
334
400
|
|
|
335
|
-
|
|
401
|
+
1. **`build_graph(path)`** → scans your code, stores a knowledge graph in `path/.ctxgraph/graph.db`
|
|
402
|
+
2. **`get_storage(path)`** → opens that SQLite database for queries (fast, no re-scanning)
|
|
403
|
+
3. **`render_capsule(storage, query)`** → searches the graph, returns a compact text capsule
|
|
336
404
|
|
|
337
405
|
```python
|
|
338
406
|
from pathlib import Path
|
|
@@ -340,154 +408,158 @@ from ctxgraph.graph.builder import build_graph, get_storage
|
|
|
340
408
|
from ctxgraph.capsule.renderer import render_capsule
|
|
341
409
|
from ctxgraph.graph.query import search_relevant_nodes
|
|
342
410
|
|
|
343
|
-
# 1
|
|
344
|
-
stats = build_graph(Path("/path/to/
|
|
411
|
+
# --- Step 1: Build (one-time, ~0.1-1s per project) ---
|
|
412
|
+
stats = build_graph(Path("/path/to/my_project"))
|
|
345
413
|
print(f"Built: {stats['total_nodes']} nodes, {stats['total_edges']} edges")
|
|
346
414
|
|
|
347
|
-
# 2
|
|
348
|
-
storage = get_storage(Path("/path/to/
|
|
415
|
+
# --- Step 2: Use (instant — reads the .db file) ---
|
|
416
|
+
storage = get_storage(Path("/path/to/my_project"))
|
|
349
417
|
|
|
350
|
-
#
|
|
418
|
+
# Generate a capsule — a token-efficient DSL string
|
|
351
419
|
capsule = render_capsule(storage, "fix JWT token validation", max_nodes=20)
|
|
352
420
|
print(capsule)
|
|
353
|
-
|
|
354
|
-
#
|
|
421
|
+
# → [CTX]fix JWT token validation
|
|
422
|
+
# [F]src/auth/jwt.py
|
|
423
|
+
# D:JWT token creation and validation
|
|
424
|
+
# [F]src/auth/middleware.py
|
|
425
|
+
# D:Auth middleware for request validation
|
|
426
|
+
# ...
|
|
427
|
+
|
|
428
|
+
# Or search for nodes programmatically
|
|
355
429
|
results = search_relevant_nodes(storage, "auth login", max_nodes=10, max_depth=2)
|
|
356
430
|
for node, score in results:
|
|
357
431
|
print(f" {node.type}:{node.name} (score={score})")
|
|
358
432
|
```
|
|
359
433
|
|
|
434
|
+
> **Tip:** `build_graph` is a one-time setup. In production, run `ctx build` during CI/deployment and let your app code only call `get_storage` + `render_capsule`.
|
|
435
|
+
|
|
360
436
|
### LangChain
|
|
361
437
|
|
|
362
|
-
|
|
438
|
+
Pass the capsule as context in your prompt template. The LLM gets exactly the files, classes, and dependencies it needs — no token waste.
|
|
363
439
|
|
|
364
440
|
```python
|
|
365
441
|
from pathlib import Path
|
|
366
442
|
from langchain_openai import ChatOpenAI
|
|
367
443
|
from langchain_core.prompts import ChatPromptTemplate
|
|
368
|
-
from ctxgraph.graph.builder import
|
|
444
|
+
from ctxgraph.graph.builder import get_storage # graph already built
|
|
369
445
|
from ctxgraph.capsule.renderer import render_capsule
|
|
370
446
|
|
|
371
|
-
#
|
|
372
|
-
build_graph(Path("./my_project"))
|
|
447
|
+
# Load existing graph (zero build time)
|
|
373
448
|
storage = get_storage(Path("./my_project"))
|
|
374
449
|
|
|
375
|
-
# Generate
|
|
376
|
-
context = render_capsule(storage, "
|
|
450
|
+
# Generate capsule for the question
|
|
451
|
+
context = render_capsule(storage, "login rate limiter", max_nodes=15)
|
|
377
452
|
|
|
378
453
|
prompt = ChatPromptTemplate.from_messages([
|
|
379
|
-
("system", "You are a senior Python
|
|
454
|
+
("system", "You are a senior Python dev. Answer using the code context below.\n\n{context}"),
|
|
380
455
|
("user", "{question}"),
|
|
381
456
|
])
|
|
382
457
|
|
|
383
458
|
llm = ChatOpenAI(model="gpt-4o")
|
|
384
|
-
|
|
459
|
+
response = prompt | llm | (lambda msg: msg.content)
|
|
385
460
|
|
|
386
|
-
response
|
|
461
|
+
print(response.invoke({
|
|
387
462
|
"context": context,
|
|
388
|
-
"question": "Where is the
|
|
389
|
-
})
|
|
463
|
+
"question": "Where is the rate limiter applied in the login flow?",
|
|
464
|
+
}))
|
|
465
|
+
# → "The rate limiter is in src/auth/middleware.py at line 42.
|
|
466
|
+
# It wraps the login endpoint with a 5req/min limit per IP."
|
|
390
467
|
```
|
|
391
468
|
|
|
392
469
|
### LangGraph
|
|
393
470
|
|
|
394
|
-
|
|
471
|
+
Expose ctxgraph as a tool the agent calls on-demand. The agent fetches context only when it hits a code-related question.
|
|
395
472
|
|
|
396
473
|
```python
|
|
397
474
|
from pathlib import Path
|
|
398
|
-
from typing import Literal
|
|
399
475
|
from langgraph.graph import StateGraph, MessagesState
|
|
400
476
|
from langgraph.prebuilt import ToolNode
|
|
401
477
|
from langchain_openai import ChatOpenAI
|
|
402
478
|
from langchain_core.tools import tool
|
|
403
|
-
from ctxgraph.graph.builder import
|
|
479
|
+
from ctxgraph.graph.builder import get_storage
|
|
404
480
|
from ctxgraph.capsule.renderer import render_capsule
|
|
405
481
|
|
|
406
|
-
# Pre-
|
|
407
|
-
|
|
408
|
-
storage = get_storage(Path("./my_project"))
|
|
482
|
+
# Pre-built graph — loaded instantly
|
|
483
|
+
_storage = get_storage(Path("./my_project"))
|
|
409
484
|
|
|
410
485
|
@tool
|
|
411
486
|
def code_context(task: str) -> str:
|
|
412
|
-
"""
|
|
413
|
-
|
|
487
|
+
"""Fetch relevant source code for a development task.
|
|
488
|
+
Use this whenever the user asks about implementation details,
|
|
489
|
+
bug fixes, or architecture in the codebase."""
|
|
490
|
+
return render_capsule(_storage, task, max_nodes=20)
|
|
414
491
|
|
|
492
|
+
# --- Build LangGraph ---
|
|
415
493
|
tools = [code_context]
|
|
416
|
-
tool_node = ToolNode(tools)
|
|
417
|
-
|
|
418
494
|
model = ChatOpenAI(model="gpt-4o", temperature=0).bind_tools(tools)
|
|
419
495
|
|
|
420
|
-
def
|
|
421
|
-
return "tools" if state["messages"][-1].tool_calls else "__end__"
|
|
422
|
-
|
|
423
|
-
def call_model(state: MessagesState):
|
|
496
|
+
def agent_node(state: MessagesState):
|
|
424
497
|
return {"messages": [model.invoke(state["messages"])]}
|
|
425
498
|
|
|
426
499
|
graph = StateGraph(MessagesState)
|
|
427
|
-
graph.add_node("agent",
|
|
428
|
-
graph.add_node("tools",
|
|
500
|
+
graph.add_node("agent", agent_node)
|
|
501
|
+
graph.add_node("tools", ToolNode(tools))
|
|
429
502
|
graph.set_entry_point("agent")
|
|
430
|
-
graph.add_conditional_edges(
|
|
503
|
+
graph.add_conditional_edges(
|
|
504
|
+
"agent",
|
|
505
|
+
lambda s: "tools" if s["messages"][-1].tool_calls else "__end__",
|
|
506
|
+
)
|
|
431
507
|
graph.add_edge("tools", "agent")
|
|
432
508
|
|
|
433
509
|
app = graph.compile()
|
|
434
510
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
511
|
+
# --- Run ---
|
|
512
|
+
for chunk in app.stream({"messages": [("user", "How does payment retry work?")]}):
|
|
513
|
+
for node, vals in chunk.items():
|
|
514
|
+
msg = vals["messages"][0]
|
|
515
|
+
if hasattr(msg, "content") and msg.content:
|
|
516
|
+
print(f"[{node}]: {msg.content[:300]}")
|
|
438
517
|
```
|
|
439
518
|
|
|
519
|
+
When the user asks about code, the agent calls `code_context("payment retry")`, gets back a capsule with `[F]src/payment/retry.py`, `[F]src/payment/processor.py`, and their dependency edges, then answers with those files in context.
|
|
520
|
+
|
|
440
521
|
### OpenAI Agents SDK
|
|
441
522
|
|
|
442
|
-
|
|
523
|
+
Same pattern — ctxgraph is a function tool the agent invokes.
|
|
443
524
|
|
|
444
525
|
```python
|
|
445
526
|
from pathlib import Path
|
|
446
|
-
from openai import AzureOpenAI # or OpenAI for standard API
|
|
447
527
|
from agents import Agent, Runner, function_tool
|
|
448
|
-
from ctxgraph.graph.builder import
|
|
528
|
+
from ctxgraph.graph.builder import get_storage
|
|
449
529
|
from ctxgraph.capsule.renderer import render_capsule
|
|
450
530
|
|
|
451
|
-
|
|
452
|
-
build_graph(Path("./my_project"))
|
|
453
|
-
storage = get_storage(Path("./my_project"))
|
|
531
|
+
_storage = get_storage(Path("./my_project"))
|
|
454
532
|
|
|
455
533
|
@function_tool
|
|
456
534
|
def fetch_code_context(task_description: str) -> str:
|
|
457
|
-
"""Retrieve
|
|
458
|
-
|
|
535
|
+
"""Retrieve code context from the project's knowledge graph.
|
|
536
|
+
Provide a task description like 'JWT auth middleware' or 'payment processor'."""
|
|
537
|
+
return render_capsule(_storage, task_description, max_nodes=20)
|
|
459
538
|
|
|
460
539
|
agent = Agent(
|
|
461
540
|
name="Code Assistant",
|
|
462
|
-
instructions="You
|
|
463
|
-
model="gpt-4o",
|
|
541
|
+
instructions="You help developers understand their codebase. Use fetch_code_context to get relevant files before answering.",
|
|
542
|
+
model="gpt-4o",
|
|
464
543
|
tools=[fetch_code_context],
|
|
465
544
|
)
|
|
466
545
|
|
|
467
|
-
result = Runner.run_sync(
|
|
468
|
-
agent,
|
|
469
|
-
"How does the JWT authentication middleware work?",
|
|
470
|
-
)
|
|
546
|
+
result = Runner.run_sync(agent, "How does the notification system handle email vs SMS?")
|
|
471
547
|
print(result.final_output)
|
|
472
548
|
```
|
|
473
549
|
|
|
474
|
-
### Azure OpenAI
|
|
550
|
+
### Azure OpenAI (direct client)
|
|
475
551
|
|
|
476
|
-
For Azure OpenAI,
|
|
552
|
+
For Azure OpenAI or any OpenAI-compatible endpoint, inject the capsule directly into the system message.
|
|
477
553
|
|
|
478
554
|
```python
|
|
479
555
|
import os
|
|
480
556
|
from openai import AzureOpenAI
|
|
481
557
|
from pathlib import Path
|
|
482
|
-
from ctxgraph.graph.builder import
|
|
558
|
+
from ctxgraph.graph.builder import get_storage
|
|
483
559
|
from ctxgraph.capsule.renderer import render_capsule
|
|
484
560
|
|
|
485
|
-
# Build graph
|
|
486
|
-
build_graph(Path("./my_project"))
|
|
487
561
|
storage = get_storage(Path("./my_project"))
|
|
488
|
-
|
|
489
|
-
# Generate context capsule
|
|
490
|
-
context = render_capsule(storage, "authentication and authorization", max_nodes=25)
|
|
562
|
+
context = render_capsule(storage, "event bus architecture", max_nodes=25)
|
|
491
563
|
|
|
492
564
|
client = AzureOpenAI(
|
|
493
565
|
api_version="2024-08-01-preview",
|
|
@@ -498,8 +570,8 @@ client = AzureOpenAI(
|
|
|
498
570
|
response = client.chat.completions.create(
|
|
499
571
|
model="gpt-4o", # deployment name
|
|
500
572
|
messages=[
|
|
501
|
-
{"role": "system", "content": f"You are a senior
|
|
502
|
-
{"role": "user", "content": "
|
|
573
|
+
{"role": "system", "content": f"You are a senior developer. Code context:\n\n{context}"},
|
|
574
|
+
{"role": "user", "content": "How do I add a new event handler?"},
|
|
503
575
|
],
|
|
504
576
|
)
|
|
505
577
|
print(response.choices[0].message.content)
|
|
@@ -521,25 +593,34 @@ python benchmarks/run_ollama_comparison.py # Requires local Ollama
|
|
|
521
593
|
### Project Structure
|
|
522
594
|
```
|
|
523
595
|
src/ctxgraph/
|
|
524
|
-
├── cli/main.py — Typer CLI (
|
|
596
|
+
├── cli/main.py — Typer CLI (9 commands)
|
|
525
597
|
├── graph/
|
|
526
598
|
│ ├── models.py — Node, Edge, Graph dataclasses
|
|
527
599
|
│ ├── storage.py — SQLite persistence
|
|
528
600
|
│ ├── builder.py — Graph build orchestrator
|
|
529
601
|
│ └── query.py — Tokenizer + BFS + relevance scoring
|
|
530
|
-
├── capsule/
|
|
602
|
+
├── capsule/
|
|
603
|
+
│ ├── renderer.py — DSL context generation
|
|
604
|
+
│ └── savings.py — Token savings computation
|
|
531
605
|
├── analyzers/python/
|
|
532
606
|
│ ├── importer.py — AST import extraction
|
|
533
607
|
│ ├── symbols.py — AST class/function/method analysis
|
|
534
608
|
│ └── semantic.py — Docstring summarization
|
|
535
609
|
├── config/
|
|
610
|
+
│ ├── __init__.py
|
|
611
|
+
│ ├── init.py — Project scaffold (.ctxgraph dir)
|
|
536
612
|
│ ├── settings.py — TOML/JSON/env config loading
|
|
537
613
|
│ └── providers.py — Ollama, Claude, OpenAI clients
|
|
538
614
|
├── clients/models.py — Mode enum (fast/balanced/deep)
|
|
539
615
|
├── exclude/patterns.py — Exclusion pattern matching
|
|
540
616
|
├── view/visualizer.py — D3.js HTML graph generator
|
|
541
617
|
├── wrapper/claude.py — ccg Claude wrapper
|
|
542
|
-
|
|
618
|
+
├── mcp/server.py — MCP protocol server
|
|
619
|
+
├── skills/
|
|
620
|
+
│ ├── __init__.py — Skill discovery + loading
|
|
621
|
+
│ ├── project-style.toml — Default skill: project conventions
|
|
622
|
+
│ └── field-guide.toml — Default skill: field guide
|
|
623
|
+
└── history.py — JSONL history append/query/stats
|
|
543
624
|
```
|
|
544
625
|
|
|
545
626
|
---
|