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.
- agents/__init__.py +0 -0
- agents/extraction_agent/__init__.py +0 -0
- agents/extraction_agent/agent.py +170 -0
- agents/graph_agent/__init__.py +5 -0
- agents/graph_agent/agent.py +373 -0
- agents/graph_agent/tools.py +2106 -0
- agents/maintenance_agent/__init__.py +0 -0
- agents/maintenance_agent/agent.py +283 -0
- agents/orchestrator/__init__.py +0 -0
- agents/orchestrator/agent.py +217 -0
- agents/review_agent/__init__.py +0 -0
- agents/review_agent/agent.py +188 -0
- agents/review_agent/tools.py +472 -0
- api/__init__.py +0 -0
- api/main.py +136 -0
- api/routes/__init__.py +0 -0
- api/routes/agent.py +81 -0
- api/routes/entries.py +411 -0
- api/routes/graph.py +132 -0
- api/routes/mem.py +179 -0
- api/routes/remote.py +815 -0
- api/routes/remote_sync.py +230 -0
- api/routes/retrieve.py +88 -0
- core/__init__.py +0 -0
- core/app_state.py +9 -0
- core/events.py +84 -0
- core/extraction/__init__.py +0 -0
- core/extraction/wikilink_parser.py +48 -0
- core/graph/__init__.py +0 -0
- core/graph/graph.py +204 -0
- core/memory/__init__.py +0 -0
- core/memory/memgraph.py +458 -0
- core/resources/starter.db +0 -0
- core/retrieval/__init__.py +0 -0
- core/retrieval/embedder.py +122 -0
- core/retrieval/fusion.py +52 -0
- core/retrieval/progressive.py +399 -0
- core/retrieval/retrieval.py +346 -0
- core/retrieval/vector_store.py +91 -0
- core/schemas/__init__.py +0 -0
- core/schemas/edge.py +46 -0
- core/schemas/entry.py +388 -0
- core/storage/__init__.py +0 -0
- core/storage/database.py +104 -0
- core/storage/models.py +66 -0
- core/storage/repository.py +243 -0
- core/sync/__init__.py +20 -0
- core/sync/autolink.py +301 -0
- core/sync/db_merge.py +297 -0
- core/sync/db_watcher.py +84 -0
- core/sync/remote_sync.py +345 -0
- examples/__init__.py +0 -0
- examples/example_entries.py +206 -0
- examples/pymatgen_interface_examples.py +811 -0
- frontend/dist/assets/index-BLfo7ZZu.css +1 -0
- frontend/dist/assets/index-G-mYbZ9R.js +83 -0
- frontend/dist/assets/index-G-mYbZ9R.js.map +1 -0
- frontend/dist/index.html +92 -0
- know_do_graph-0.1.0.dist-info/METADATA +765 -0
- know_do_graph-0.1.0.dist-info/RECORD +63 -0
- know_do_graph-0.1.0.dist-info/WHEEL +4 -0
- know_do_graph-0.1.0.dist-info/entry_points.txt +2 -0
- 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
|
+
```
|