know-do-graph 0.1.0__py3-none-any.whl

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.
Files changed (63) hide show
  1. agents/__init__.py +0 -0
  2. agents/extraction_agent/__init__.py +0 -0
  3. agents/extraction_agent/agent.py +170 -0
  4. agents/graph_agent/__init__.py +5 -0
  5. agents/graph_agent/agent.py +373 -0
  6. agents/graph_agent/tools.py +2106 -0
  7. agents/maintenance_agent/__init__.py +0 -0
  8. agents/maintenance_agent/agent.py +283 -0
  9. agents/orchestrator/__init__.py +0 -0
  10. agents/orchestrator/agent.py +217 -0
  11. agents/review_agent/__init__.py +0 -0
  12. agents/review_agent/agent.py +188 -0
  13. agents/review_agent/tools.py +472 -0
  14. api/__init__.py +0 -0
  15. api/main.py +136 -0
  16. api/routes/__init__.py +0 -0
  17. api/routes/agent.py +81 -0
  18. api/routes/entries.py +411 -0
  19. api/routes/graph.py +132 -0
  20. api/routes/mem.py +179 -0
  21. api/routes/remote.py +815 -0
  22. api/routes/remote_sync.py +230 -0
  23. api/routes/retrieve.py +88 -0
  24. core/__init__.py +0 -0
  25. core/app_state.py +9 -0
  26. core/events.py +84 -0
  27. core/extraction/__init__.py +0 -0
  28. core/extraction/wikilink_parser.py +48 -0
  29. core/graph/__init__.py +0 -0
  30. core/graph/graph.py +204 -0
  31. core/memory/__init__.py +0 -0
  32. core/memory/memgraph.py +458 -0
  33. core/resources/starter.db +0 -0
  34. core/retrieval/__init__.py +0 -0
  35. core/retrieval/embedder.py +122 -0
  36. core/retrieval/fusion.py +52 -0
  37. core/retrieval/progressive.py +399 -0
  38. core/retrieval/retrieval.py +346 -0
  39. core/retrieval/vector_store.py +91 -0
  40. core/schemas/__init__.py +0 -0
  41. core/schemas/edge.py +46 -0
  42. core/schemas/entry.py +388 -0
  43. core/storage/__init__.py +0 -0
  44. core/storage/database.py +104 -0
  45. core/storage/models.py +66 -0
  46. core/storage/repository.py +243 -0
  47. core/sync/__init__.py +20 -0
  48. core/sync/autolink.py +301 -0
  49. core/sync/db_merge.py +297 -0
  50. core/sync/db_watcher.py +84 -0
  51. core/sync/remote_sync.py +345 -0
  52. examples/__init__.py +0 -0
  53. examples/example_entries.py +206 -0
  54. examples/pymatgen_interface_examples.py +811 -0
  55. frontend/dist/assets/index-BLfo7ZZu.css +1 -0
  56. frontend/dist/assets/index-G-mYbZ9R.js +83 -0
  57. frontend/dist/assets/index-G-mYbZ9R.js.map +1 -0
  58. frontend/dist/index.html +92 -0
  59. know_do_graph-0.1.0.dist-info/METADATA +765 -0
  60. know_do_graph-0.1.0.dist-info/RECORD +63 -0
  61. know_do_graph-0.1.0.dist-info/WHEEL +4 -0
  62. know_do_graph-0.1.0.dist-info/entry_points.txt +2 -0
  63. main.py +944 -0
@@ -0,0 +1,765 @@
1
+ Metadata-Version: 2.4
2
+ Name: know-do-graph
3
+ Version: 0.1.0
4
+ Summary: A wiki-native, agent-oriented infrastructure for executable knowledge, operational memory, and capability discovery.
5
+ Requires-Python: >=3.10
6
+ Requires-Dist: duckduckgo-search>=6.0
7
+ Requires-Dist: fastapi>=0.100
8
+ Requires-Dist: httpx>=0.25
9
+ Requires-Dist: networkx>=3.0
10
+ Requires-Dist: openai>=1.0
11
+ Requires-Dist: prompt-toolkit>=3.0
12
+ Requires-Dist: pydantic>=2.0
13
+ Requires-Dist: python-dotenv>=1.0
14
+ Requires-Dist: pyyaml>=6.0
15
+ Requires-Dist: rich>=13.0
16
+ Requires-Dist: sqlalchemy>=2.0
17
+ Requires-Dist: typer[all]
18
+ Requires-Dist: uvicorn[standard]
19
+ Provides-Extra: embeddings
20
+ Requires-Dist: numpy>=1.24; extra == 'embeddings'
21
+ Requires-Dist: sentence-transformers>=2.7; extra == 'embeddings'
22
+ Requires-Dist: sqlite-vec>=0.1.6; extra == 'embeddings'
23
+ Description-Content-Type: text/markdown
24
+
25
+ # Know-Do Graph
26
+
27
+ A wiki-native, agent-oriented infrastructure for **executable knowledge**, **operational memory**, and **capability discovery**.
28
+
29
+ Entries are the primary object — wiki pages that agents can read, traverse, and evolve.
30
+ The graph emerges naturally from `[[wikilink]]` references between entries.
31
+
32
+ ---
33
+
34
+ ## Quick start
35
+
36
+ ### Install from PyPI
37
+
38
+ ```bash
39
+ pip install know-do-graph
40
+
41
+ # Create an empty ./data/know_do_graph.db
42
+ know-do-graph init
43
+
44
+ # Or start from the database bundled with the package
45
+ know-do-graph init --starter
46
+
47
+ know-do-graph serve
48
+ ```
49
+
50
+ The starter database is copied into the working location; the installed package
51
+ is never used as the writable database. Existing databases are not replaced
52
+ unless `--force` is explicitly provided.
53
+
54
+ To choose another database path, set `KDG_DB_PATH` in the environment or in a
55
+ `.env` file in the directory where the command is run:
56
+
57
+ ```bash
58
+ KDG_DB_PATH=./my-data/my-memory.db
59
+ ```
60
+
61
+ Relative `KDG_DB_PATH` values are resolved from the current working directory.
62
+
63
+ ### Install from source
64
+
65
+ ```bash
66
+ # 1. Create and activate a virtual environment
67
+ python -m venv .venv
68
+ .venv\Scripts\activate # Windows
69
+ source .venv/bin/activate # macOS / Linux
70
+
71
+ # 2. Install everything (Python deps + Vite frontend build)
72
+ bash install.sh
73
+
74
+ # 3. Seed example entries (optional)
75
+ python examples/example_entries.py
76
+
77
+ # 4. Start the API server
78
+ python main.py serve
79
+ # → http://127.0.0.1:8000
80
+ # → http://127.0.0.1:8000/ui (graph browser)
81
+ # → http://127.0.0.1:8000/docs (interactive Swagger UI)
82
+ ```
83
+
84
+ > **Manual frontend build** (if you prefer not to use `install.sh`):
85
+ > ```bash
86
+ > cd frontend && npm install && npm run build && cd ..
87
+ > ```
88
+ > Re-run whenever you edit files under `frontend/src/` or `frontend/styles/`.
89
+
90
+ ### Frontend development (hot-reload)
91
+
92
+ ```bash
93
+ # Terminal 1 — API backend
94
+ python main.py serve
95
+
96
+ # Terminal 2 — Vite dev server with API proxy
97
+ cd frontend && npm run dev
98
+ # → http://localhost:5173 (proxies /entries, /graph, etc. to :8000)
99
+ ```
100
+
101
+ ---
102
+
103
+ ## CLI reference
104
+
105
+ Commands are available via `know-do-graph` after a package installation or
106
+ `python main.py` from a source checkout.
107
+
108
+ ### Database initialization
109
+
110
+ ```bash
111
+ # Create an empty database if one does not exist
112
+ know-do-graph init
113
+
114
+ # Copy the bundled starter database
115
+ know-do-graph init --starter
116
+
117
+ # Explicitly replace an existing database with the starter
118
+ know-do-graph init --starter --force
119
+ ```
120
+
121
+ ### Entry management
122
+
123
+ ```bash
124
+ # Add an entry
125
+ python main.py entry add "My Tool" \
126
+ --content "Useful for [[ASE Relaxation]]. See https://example.com" \
127
+ --type tool \
128
+ --tags "python,simulation" \
129
+ --source "https://example.com"
130
+
131
+ # List entries
132
+ python main.py entry list --limit 50
133
+
134
+ # Show full entry (by ID or slug)
135
+ python main.py entry show mace-calculator
136
+ python main.py entry show 3e3f0272
137
+
138
+ # Full-text search
139
+ python main.py entry search "relaxation"
140
+
141
+ # Delete
142
+ python main.py entry delete <entry-id> --yes
143
+ ```
144
+
145
+ ### File extraction
146
+
147
+ ```bash
148
+ # Extract from a single Markdown file
149
+ python main.py extract file notes/my_workflow.md --type workflow --tags "ase,phonon"
150
+
151
+ # Extract all .md/.txt files from a directory
152
+ python main.py extract file docs/ --type capability
153
+
154
+ # Skip automatic wikilink resolution
155
+ python main.py extract file notes/ --no-resolve
156
+ ```
157
+
158
+ ### Graph inspection
159
+
160
+ ```bash
161
+ python main.py graph stats
162
+ python main.py graph neighbors <entry-id> --depth 2
163
+ python main.py graph export --output data/nodes # writes YAML files
164
+ ```
165
+
166
+ ### Memory (Mem-Graph)
167
+
168
+ ```bash
169
+ # Record a trace manually
170
+ python main.py mem add "MACE calculator worked for bulk Fe relaxation" \
171
+ --session my-session --tags "success,atomistic"
172
+
173
+ # List traces for a session
174
+ python main.py mem list --session my-session
175
+
176
+ # Promote a trace into a full KDG entry
177
+ python main.py mem promote <mem-id> --session my-session --type capability
178
+ ```
179
+
180
+ ### Start the server
181
+
182
+ ```bash
183
+ python main.py serve # default: 127.0.0.1:8000
184
+ python main.py serve --host 0.0.0.0 --port 9000 --reload
185
+ ```
186
+
187
+ The CLI prints clickable URLs on startup:
188
+
189
+ ```
190
+ Know-Do Graph API → http://127.0.0.1:8000
191
+ Graph UI → http://127.0.0.1:8000/ui
192
+ Swagger → http://127.0.0.1:8000/docs
193
+ ```
194
+
195
+ ---
196
+
197
+ ## Graph Debugger UI
198
+
199
+ A built-in browser frontend for visualising and debugging the graph is served at **`/ui`**.
200
+
201
+ | Feature | Details |
202
+ |---------|---------|
203
+ | Force-directed layout | Nodes sized by degree, coloured by entry type |
204
+ | **Hover** | Tooltip with name, type, slug, refinement status, trust score, tags |
205
+ | **Click** | Side panel with full entry detail: content, wikilinks, all metadata, connected edges |
206
+ | Search & filter | Live search by title/slug; filter by entry type |
207
+ | Labels toggle | Show/hide node title labels |
208
+ | Click edge targets | Jump directly to a connected node from the detail panel |
209
+
210
+ Open it at `http://127.0.0.1:8000/ui` while the server is running.
211
+
212
+ ---
213
+
214
+ ## API reference
215
+
216
+ Interactive docs at `http://127.0.0.1:8000/docs` once the server is running.
217
+
218
+ ### Entries
219
+
220
+ | Method | Path | Description |
221
+ |--------|------|-------------|
222
+ | `GET` | `/entries/` | List entries (paginated) |
223
+ | `GET` | `/entries/search?q=...&tags=...&entry_type=...` | Full-text search |
224
+ | `GET` | `/entries/{id}` | Get entry by ID or slug |
225
+ | `POST` | `/entries/` | Create entry |
226
+ | `PUT` | `/entries/{id}` | Update entry |
227
+ | `DELETE` | `/entries/{id}` | Delete entry |
228
+ | `GET` | `/entries/{id}/related?depth=1&relation=...` | Traverse related entries |
229
+ | `GET` | `/entries/{id}/edges` | All edges incident to an entry |
230
+ | `GET` | `/entries/{id}/download` | Download script content (entries with `script_language` set) |
231
+ | `POST` | `/entries/{id}/feedback` | Record verification feedback (works / bugged / …) |
232
+
233
+ ### Graph
234
+
235
+ | Method | Path | Description |
236
+ |--------|------|-------------|
237
+ | `GET` | `/graph/stats` | Node/edge counts |
238
+ | `GET` | `/graph/full` | All nodes and edges (used by the UI) |
239
+ | `GET` | `/graph/neighbors/{id}?direction=both` | Immediate neighbors |
240
+ | `GET` | `/graph/subgraph/{id}?depth=2` | Ego-subgraph |
241
+ | `GET` | `/graph/path?source=...&target=...` | All simple paths between two entries |
242
+
243
+ ### Memory (Mem-Graph)
244
+
245
+ | Method | Path | Description |
246
+ |--------|------|-------------|
247
+ | `GET` | `/mem/sessions` | List all session IDs |
248
+ | `GET` | `/mem/{session}` | List traces for a session |
249
+ | `POST` | `/mem/{session}/add` | Add a plain-text trace |
250
+ | `POST` | `/mem/{session}/ingest/openai` | Ingest OpenAI chat messages |
251
+ | `POST` | `/mem/{session}/ingest/langchain` | Ingest LangChain messages |
252
+ | `POST` | `/mem/{session}/ingest/autogen` | Ingest AutoGen conversation |
253
+ | `POST` | `/mem/{session}/ingest/raw` | Ingest arbitrary JSON |
254
+ | `DELETE` | `/mem/{session}/{mem_id}` | Delete a trace |
255
+ | `POST` | `/mem/{session}/{mem_id}/promote` | Promote trace → KDG entry |
256
+
257
+ ### Progressive retrieval (hierarchical memory)
258
+
259
+ The graph is organised into four orthogonal **skill levels** so planning
260
+ context stays small and operational details are pulled on demand.
261
+
262
+ | Level | Stored as | Purpose |
263
+ |-------|-----------|---------|
264
+ | **L1 — Capability** | `entry_type` ∈ {`capability`, `workflow`} | Reusable high-level abilities (planner-facing) |
265
+ | **L2 — Procedure** | `entry_type` = `procedure` | Executable workflow decomposition |
266
+ | **L3 — Heuristic** | `entry_type` = `heuristic` | Empirical, conditional guidance (cooling rate ⇒ sp2/sp3 ratio, …) |
267
+ | **L4 — Constraint** | `entry_type` = `constraint` | Known failure modes / instability regions |
268
+
269
+ `EntryMetadata.skill_level` may override the level explicitly. New typed edges
270
+ wire the layers together:
271
+
272
+ - `decomposes_to` (L1 → L2)
273
+ - `heuristic_for` (L3 → L1/L2)
274
+ - `constraint_on` (L4 → L1/L2)
275
+
276
+ | Method | Path | Description |
277
+ |--------|------|-------------|
278
+ | `GET` | `/retrieve/plan?goal=…&k=5&include_l2=true` | L1 (+ L2) candidates for a goal — planner context |
279
+ | `GET` | `/retrieve/heuristics?skill=<id\|slug>&k=5` | L3 heuristics attached to a skill (fallback: semantic) |
280
+ | `GET` | `/retrieve/constraints?skill=<id\|slug>&k=5` | L4 constraints / failure modes (fallback: semantic) |
281
+ | `GET` | `/retrieve/expand/{skill}?stages=heuristics,constraints,decomposition` | Bundle used by verifier / debugging loops |
282
+
283
+ Recommended flow::
284
+
285
+ goal → /retrieve/plan
286
+ → pick skill, execute
287
+ → on verifier feedback or uncertainty
288
+ → /retrieve/heuristics + /retrieve/constraints
289
+ → refinement / debugging
290
+
291
+ GraphAgent exposes the same staging as tools (`retrieve_plan`,
292
+ `retrieve_heuristics`, `retrieve_constraints`) plus `create_heuristic`,
293
+ `create_constraint`, and `decompose_capability` so it can grow the L3/L4
294
+ layer instead of dumping operational knowledge into capability content.
295
+
296
+ To migrate an existing graph:
297
+
298
+ ```bash
299
+ python scripts/backfill_skill_levels.py --dry-run # preview
300
+ python scripts/backfill_skill_levels.py # apply
301
+ ```
302
+
303
+ ---
304
+
305
+ ## Node verification & self-evolution
306
+
307
+ Every entry carries metadata that lets the graph evolve from raw scraped notes
308
+ into a trusted capability library:
309
+
310
+ | Field | Purpose |
311
+ |-------|---------|
312
+ | `verification_status` | `unverified` (default) → `self_tested` / `peer_reviewed` / `community_tested` / `bugged` / `deprecated` |
313
+ | `feedback_log` | Append-only list of `{timestamp, agent_id, verdict, note, evidence}` |
314
+ | `needs_generalization` | Set automatically when `create_entry` detects an overly specific title (e.g. `Build H2O`) overlapping an existing generic node |
315
+ | `review_count` / `modify_count` | Incremented by `ReviewAgent` |
316
+ | `trust_score` / `usage_count` | Reserved for downstream ranking |
317
+
318
+ External agents that **execute** a skill should immediately report the outcome
319
+ via `POST /entries/{id}/feedback` (verdict `works` or `bugged`). The
320
+ `MaintenanceAgent` regularly sweeps for `unverified`, `bugged`, and
321
+ `needs_generalization` entries and proposes fixes; the `GraphAgent` exposes
322
+ `submit_feedback`, `list_by_verification`, and `list_needs_generalization`
323
+ tools so an LLM can do the same.
324
+
325
+ ### Abstraction guard
326
+
327
+ `create_entry` runs a heuristic that flags titles containing concrete
328
+ chemical formulas (`H2O`, `TiO2`, `TiO2/SrTiO3`) and any title that overlaps
329
+ an existing one. The new entry is still created, but with
330
+ `metadata.needs_generalization = True` so it surfaces in maintenance sweeps.
331
+ The agent system prompt gives BAD/GOOD examples — prefer
332
+ **`Build molecule from formula`** over **`Build H2O`**, and
333
+ **`Material interface construction`** over **`TiO2/SrTiO3 Interface`**.
334
+
335
+ `build_material_interface_workflow` is now deprecated for this reason and
336
+ returns an error explaining the generic alternative.
337
+
338
+ ---
339
+
340
+ ## Remote agent access
341
+
342
+ The server exposes a dedicated `/remote` interface so that agents running on
343
+ other machines can discover, query, and interact with the graph over plain HTTP
344
+ — no special client library required.
345
+
346
+ ### Discovery: the instruction sheet
347
+
348
+ When any client hits the server root (or `/remote`), it receives a plain-text
349
+ instruction sheet explaining every available endpoint, request formats, and
350
+ example `curl` commands:
351
+
352
+ ```bash
353
+ curl http://<host>:<port>/
354
+ # or
355
+ curl http://<host>:<port>/remote
356
+ ```
357
+
358
+ ### Remote agent endpoints
359
+
360
+ | Method | Path | Description |
361
+ |--------|------|-------------|
362
+ | `GET` | `/` | Instruction sheet (plain text) |
363
+ | `GET` | `/remote` | Same instruction sheet |
364
+ | `POST` | `/remote/chat` | Chat with the orchestrator agent (read-only; agents and humans) |
365
+ | `GET` | `/remote/search` | Search entries (`?q=&tags=&entry_type=&limit=`) |
366
+ | `GET` | `/remote/graph` | Graph stats + full node/edge dump |
367
+ | `GET` | `/remote/entry/{id}` | Entry by ID, slug, or alias |
368
+ | `GET` | `/remote/entry/{id}/related` | Related entries via BFS (`?depth=1&relation=`) |
369
+ | `POST` | `/remote/feedback` | Free-form feedback trace; optionally also updates an entry's verification (pass `entry_id` + `verdict`) |
370
+ | `POST` | `/entries/{id}/feedback` | Direct per-entry verification feedback |
371
+ | `DELETE` | `/remote/session/{id}` | Clear a session's chat history |
372
+ | `POST` | `/remote/submit` | Deposit raw knowledge into the inbox (agents and humans) |
373
+ | `GET` | `/remote/inbox` | List pending inbox submissions awaiting distillation (humans) |
374
+ | `POST` | `/remote/distill` | Run graph agent to convert inbox into proper nodes (humans) |
375
+
376
+ ### Chat (one-shot)
377
+
378
+ ```bash
379
+ curl -X POST http://<host>:<port>/remote/chat \
380
+ -H "Content-Type: application/json" \
381
+ -d '{"message": "What entries exist in the graph?"}'
382
+ ```
383
+
384
+ ```json
385
+ {"response": "The graph currently contains ...", "session_id": "a1b2c3..."}
386
+ ```
387
+
388
+ ### Chat (multi-turn)
389
+
390
+ Pass a stable `session_id` to retain conversation history across calls:
391
+
392
+ ```bash
393
+ # Turn 1
394
+ curl -X POST http://<host>:<port>/remote/chat \
395
+ -H "Content-Type: application/json" \
396
+ -d '{"message": "List all procedure entries", "session_id": "agent-42"}'
397
+
398
+ # Turn 2 — the server remembers the context from turn 1
399
+ curl -X POST http://<host>:<port>/remote/chat \
400
+ -H "Content-Type: application/json" \
401
+ -d '{"message": "Now show the dependencies of the first one", "session_id": "agent-42"}'
402
+
403
+ # Clear history when done
404
+ curl -X DELETE http://<host>:<port>/remote/session/agent-42
405
+ ```
406
+
407
+ ### Search
408
+
409
+ ```bash
410
+ # Free-text search
411
+ curl "http://<host>:<port>/remote/search?q=relaxation&limit=5"
412
+
413
+ # Filter by type
414
+ curl "http://<host>:<port>/remote/search?entry_type=tool"
415
+
416
+ # Combined: text + tags
417
+ curl "http://<host>:<port>/remote/search?q=ase&tags=python,simulation"
418
+ ```
419
+
420
+ ### Feedback / observations
421
+
422
+ There are **two complementary feedback channels**:
423
+
424
+ **(a) Per-entry verification feedback** — updates the entry's
425
+ `verification_status` (one of `unverified`, `self_tested`, `peer_reviewed`,
426
+ `community_tested`, `bugged`, `deprecated`) and appends to its `feedback_log`.
427
+ This is how the graph self-evolves — a node that an external agent has run
428
+ and confirmed working will be trusted higher next time.
429
+
430
+ ```bash
431
+ # Verdicts: works | peer_works | bugged | deprecated | unclear
432
+ curl -X POST http://<host>:<port>/entries/<id-or-slug>/feedback \
433
+ -H "Content-Type: application/json" \
434
+ -d '{
435
+ "verdict": "works",
436
+ "note": "Ran on H2O, energy converged in 12 steps",
437
+ "evidence": "log link or excerpt",
438
+ "agent_id": "matcreator-runner-1"
439
+ }'
440
+ ```
441
+
442
+ **(b) Free-form session feedback** — stored as a MemGraph trace; can later be
443
+ promoted to a full entry. Optionally also routes to (a) when you pass
444
+ `entry_id` and `verdict`:
445
+
446
+ ```bash
447
+ curl -X POST http://<host>:<port>/remote/feedback \
448
+ -H "Content-Type: application/json" \
449
+ -d '{
450
+ "session_id": "agent-42",
451
+ "content": "MACE relaxation diverged on Cu surfaces",
452
+ "tags": ["feedback", "graph-quality"],
453
+ "entry_id": "mace-relaxation",
454
+ "verdict": "bugged",
455
+ "agent_id": "matcreator-runner-1"
456
+ }'
457
+ ```
458
+
459
+ The `MaintenanceAgent` exposes `list_unverified()`, `list_bugged()`, and
460
+ `list_needs_generalization()` so it can sweep for entries needing attention.
461
+
462
+ Promote feedback traces to entries via `POST /mem/{session_id}/{mem_id}/promote`.
463
+
464
+ ### Knowledge inbox (submit → review → distill)
465
+
466
+ External agents — and humans — can deposit raw knowledge into an **inbox** for
467
+ later review and distillation into proper graph nodes. Nothing touches the
468
+ graph until you explicitly trigger distillation, so you stay in control of what
469
+ gets added.
470
+
471
+ **Step 1 — Submit** (agents or humans)
472
+
473
+ ```bash
474
+ # Plain-text summary or context dump
475
+ curl -X POST http://<host>:<port>/remote/submit \
476
+ -H "Content-Type: application/json" \
477
+ -d '{
478
+ "title": "MACE geometry optimisation walkthrough",
479
+ "content": "We used MACE-MP-0 to relax a bulk Fe structure ...",
480
+ "tags": ["mace", "relaxation"],
481
+ "agent_id": "matcreator-01"
482
+ }'
483
+
484
+ # OpenAI-style conversation transcript
485
+ curl -X POST http://<host>:<port>/remote/submit \
486
+ -H "Content-Type: application/json" \
487
+ -d '{
488
+ "title": "ASE relaxation session",
489
+ "format": "openai",
490
+ "messages": [
491
+ {"role": "user", "content": "How do I relax a structure with ASE?"},
492
+ {"role": "assistant", "content": "Use BFGS with an Atoms object ..."}
493
+ ],
494
+ "agent_id": "matcreator-01"
495
+ }'
496
+ ```
497
+
498
+ The submission is stored as a memory trace tagged `pending-distillation` and
499
+ returns the entry `id` for reference.
500
+
501
+ **Step 2 — Review the inbox** (humans)
502
+
503
+ ```bash
504
+ curl http://<host>:<port>/remote/inbox
505
+ # → list of pending submissions with a 300-char preview each
506
+
507
+ # Scope to a specific agent's session
508
+ curl "http://<host>:<port>/remote/inbox?session_id=matcreator-01"
509
+ ```
510
+
511
+ **Step 3 — Distill** (humans, when ready)
512
+
513
+ ```bash
514
+ # Process all pending submissions and create graph nodes
515
+ curl -X POST http://<host>:<port>/remote/distill \
516
+ -H "Content-Type: application/json" \
517
+ -d '{}'
518
+
519
+ # Preview what the agent would receive without touching the graph
520
+ curl -X POST http://<host>:<port>/remote/distill \
521
+ -H "Content-Type: application/json" \
522
+ -d '{"dry_run": true}'
523
+
524
+ # Distil only one agent's submissions
525
+ curl -X POST http://<host>:<port>/remote/distill \
526
+ -H "Content-Type: application/json" \
527
+ -d '{"session_id": "matcreator-01"}'
528
+ ```
529
+
530
+ The graph agent reads every pending submission, extracts reusable
531
+ capabilities/procedures/tools (following the abstraction rules), and marks the
532
+ inbox entries as promoted so they are not processed again.
533
+
534
+ ### Starting the server for remote access
535
+
536
+ ```bash
537
+ # Expose on all interfaces so other machines can connect:
538
+ python main.py serve --host 0.0.0.0 --port 8000
539
+
540
+ # With auto-reload during development:
541
+ python main.py serve --host 0.0.0.0 --port 8000 --reload
542
+ ```
543
+
544
+ Set `OPENAI_API_KEY` (and optionally `OPENAI_API_BASE`) before starting if you
545
+ want the `/remote/chat` endpoint to work.
546
+
547
+ ---
548
+
549
+ ## Connecting agent frameworks
550
+
551
+ MemGraph accepts session data in whichever format the agent framework already
552
+ produces. Pick the adapter that matches your stack.
553
+
554
+ ### OpenAI / OpenAI-compatible APIs
555
+
556
+ ```python
557
+ from core.memory.memgraph import MemGraph
558
+
559
+ response = openai_client.chat.completions.create(...)
560
+ messages = [m.model_dump() for m in response.choices[0].message] # or your history list
561
+
562
+ mg = MemGraph("my-session")
563
+ mg.ingest_openai_messages(messages, tags=["openai", "physics-qa"])
564
+ ```
565
+
566
+ Or via the API:
567
+
568
+ ```bash
569
+ curl -X POST http://localhost:8000/mem/my-session/ingest/openai \
570
+ -H "Content-Type: application/json" \
571
+ -d '{"messages": [{"role":"user","content":"..."},{"role":"assistant","content":"..."}]}'
572
+ ```
573
+
574
+ ### LangChain
575
+
576
+ ```python
577
+ from core.memory.memgraph import MemGraph
578
+
579
+ # chain.memory.chat_memory.messages → list of HumanMessage / AIMessage objects
580
+ mg = MemGraph("langchain-session")
581
+ mg.ingest_langchain_messages(chain.memory.chat_memory.messages)
582
+ ```
583
+
584
+ Objects only need a `.content` attribute (and optionally `.type` / `.role`).
585
+
586
+ ### AutoGen
587
+
588
+ ```python
589
+ from core.memory.memgraph import MemGraph
590
+
591
+ # groupchat.messages → list of {"name": "...", "content": "...", "role": "..."}
592
+ mg = MemGraph("autogen-session")
593
+ mg.ingest_autogen_messages(groupchat.messages, tags=["autogen", "multi-agent"])
594
+ ```
595
+
596
+ ### JSON session dump
597
+
598
+ ```python
599
+ from pathlib import Path
600
+ from core.memory.memgraph import MemGraph
601
+
602
+ mg = MemGraph("dump-session")
603
+ mg.ingest_file(Path("session_export.json"))
604
+ ```
605
+
606
+ Accepted JSON shapes:
607
+ - A **JSON array** → treated as an OpenAI/AutoGen message list
608
+ - A **JSON object** with a `messages`, `history`, `conversation`, or `turns` key → that list is extracted
609
+ - Anything else → stored as a single serialised trace
610
+
611
+ ### Plain text / log file
612
+
613
+ ```python
614
+ from pathlib import Path
615
+ from core.memory.memgraph import MemGraph
616
+
617
+ mg = MemGraph("log-session")
618
+ mg.ingest_text_file(Path("agent.log"), chunk_by="paragraph")
619
+ # chunk_by options: "none" | "line" | "paragraph"
620
+ ```
621
+
622
+ ### Direct `add()` (any framework)
623
+
624
+ ```python
625
+ mg = MemGraph("custom-session")
626
+ mg.add(
627
+ "Summarised finding from the session: ...",
628
+ tags=["finding", "success"],
629
+ success=True,
630
+ )
631
+ ```
632
+
633
+ ---
634
+
635
+ ## Entry format and wikilinks
636
+
637
+ Entries are wiki-style documents. Internal `[[wikilinks]]` automatically
638
+ create graph edges when you call `resolve_wikilinks()` or use the
639
+ `--resolve` flag during extraction.
640
+
641
+ ```markdown
642
+ # ASE Relaxation
643
+
644
+ Geometry optimisation workflow using [[ASE]].
645
+
646
+ ## Prerequisites
647
+ - [[ASE]]
648
+ - A [[MACE Calculator]] or other calculator
649
+
650
+ ## Related
651
+ - [[Phonon Workflow]]
652
+ ```
653
+
654
+ Supported `entry_type` values: `capability`, `procedure`, `workflow`, `tool`,
655
+ `repository`, `environment`, `dependency`, `data`, `analytical`, `memory`, `generic`.
656
+
657
+ Supported edge `relation` values: `dependency`, `compatible_with`, `alternative_to`,
658
+ `related_workflow`, `generated_from`, `memory_of`, `refinement_of`, `derived_from`,
659
+ `warning_about`, `cited_by`, `wikilink`, `prerequisite`, `replacement`,
660
+ `execution_pathway`, `transformation`, `provenance`, `compatibility`.
661
+
662
+ ---
663
+
664
+ ## Project structure
665
+
666
+ ```
667
+ core/
668
+ schemas/ Pydantic models — Entry, EntryMetadata, Edge, enums
669
+ graph/ KnowDoGraph (networkx wrapper) + app_state singleton
670
+ storage/ SQLAlchemy/SQLite models, DB session, repositories
671
+ retrieval/ RetrievalEngine — search, traversal
672
+ extraction/ Wikilink parser, external-ref extractor
673
+ memory/ MemGraph — session memory traces + ingestion adapters
674
+
675
+ agents/
676
+ extraction_agent/ File/text → entries + wikilink resolution
677
+ maintenance_agent/ Graph rebuild, dangling-edge cleanup, YAML export, promotion
678
+
679
+ api/
680
+ main.py FastAPI application
681
+ routes/
682
+ entries.py CRUD + search + traversal endpoints
683
+ graph.py Stats, subgraph, path-finding endpoints
684
+ mem.py Mem-Graph ingestion + management endpoints
685
+ remote.py Remote agent access + instruction sheet endpoints
686
+
687
+ data/
688
+ know_do_graph.db Default working SQLite database
689
+ memory/ Per-session JSON memory files
690
+ nodes/ YAML entry exports (via `graph export`)
691
+
692
+ examples/
693
+ example_entries.py Seed script with 5 cross-linked atomistic entries
694
+
695
+ main.py Typer CLI entry point
696
+ requirements.txt Python dependencies
697
+ ```
698
+
699
+ ---
700
+
701
+ ## Mem-Graph → Know-Do Graph promotion
702
+
703
+ Memory traces are shallow and mutable. When a trace represents a stable,
704
+ reusable insight, promote it:
705
+
706
+ ```bash
707
+ # CLI
708
+ python main.py mem promote <mem-id> --session my-session --type capability
709
+
710
+ # API
711
+ curl -X POST http://localhost:8000/mem/my-session/<mem-id>/promote \
712
+ -H "Content-Type: application/json" \
713
+ -d '{"entry_type": "capability", "tags": ["promoted"]}'
714
+ ```
715
+
716
+ The promotion pathway:
717
+
718
+ ```
719
+ raw mem trace → linked note → refined capability entry → validated knowledge
720
+ ```
721
+
722
+ ---
723
+
724
+ ## Development notes
725
+
726
+ - The default SQLite database is `./data/know_do_graph.db`, relative to the
727
+ directory where the process is started.
728
+ - Set `KDG_DB_PATH` to configure a different filename or path.
729
+ - `init` creates an empty database; `init --starter` copies the bundled starter
730
+ database to the working path.
731
+ - To package the current development database as the next starter, stop the API
732
+ server and run:
733
+
734
+ ```bash
735
+ ./scripts/build_starter.sh
736
+ ```
737
+
738
+ The script checkpoints `data/know_do_graph.db`, copies it to the tracked
739
+ release snapshot at `assets/starter.db`, builds the source distribution and
740
+ wheel into `dist/`, and verifies that the wheel contains the complete starter
741
+ database. The live database under `data/` is ignored by Git.
742
+ - The in-memory networkx graph is rebuilt from the database on every server startup (or via `MaintenanceAgent.rebuild_graph()`).
743
+ - All timestamps are UTC.
744
+ - Vector indexing and heavyweight graph databases are intentionally deferred — the architecture supports adding them later without structural changes.
745
+
746
+ ---
747
+
748
+ ## Agent web access
749
+
750
+ The `GraphAgent` has two complementary web tools:
751
+
752
+ | Tool | How it works | When to use |
753
+ |------|-------------|-------------|
754
+ | `web_search` | DuckDuckGo search API, returns titles + snippets | Discovering URLs, broad topic research |
755
+ | `fetch_url` | HTTP GET via `httpx` (or stdlib fallback), returns up to 20 000 chars of page text | Reading a specific URL the user provides, scraping docs/READMEs |
756
+
757
+ **`fetch_url` requires `httpx`** (already in `requirements.txt` if you're using the API server).
758
+ It falls back to `urllib` automatically if `httpx` is not installed.
759
+
760
+ Example agent usage:
761
+
762
+ ```
763
+ You: fetch https://ase.readthedocs.io/en/latest/ and create a tool entry for ASE
764
+ Agent: [calls fetch_url → reads page → calls create_entry]
765
+ ```