deepagents-graph-memory 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.
- deepagents_graph_memory/__init__.py +20 -0
- deepagents_graph_memory/backend.py +838 -0
- deepagents_graph_memory/errors.py +21 -0
- deepagents_graph_memory/ladybug_store.py +847 -0
- deepagents_graph_memory/paths.py +253 -0
- deepagents_graph_memory/py.typed +1 -0
- deepagents_graph_memory/recall.py +936 -0
- deepagents_graph_memory/renderers.py +199 -0
- deepagents_graph_memory/stores.py +378 -0
- deepagents_graph_memory/tools.py +193 -0
- deepagents_graph_memory/vgs.py +210 -0
- deepagents_graph_memory-0.1.0.dist-info/METADATA +770 -0
- deepagents_graph_memory-0.1.0.dist-info/RECORD +16 -0
- deepagents_graph_memory-0.1.0.dist-info/WHEEL +5 -0
- deepagents_graph_memory-0.1.0.dist-info/licenses/LICENSE +21 -0
- deepagents_graph_memory-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,770 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: deepagents-graph-memory
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Graph-backed context scratchpad for LangChain Deep Agents.
|
|
5
|
+
Author-email: Pranav Bedi <pranavbedi80@gmail.com>, Taha Khan <ktaha2005.net@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Repository, https://github.com/TahaK29/deepagents-graph-memory
|
|
8
|
+
Project-URL: Documentation, https://github.com/TahaK29/deepagents-graph-memory#readme
|
|
9
|
+
Project-URL: Issues, https://github.com/TahaK29/deepagents-graph-memory/issues
|
|
10
|
+
Keywords: deepagents,langchain,langgraph,context,graph,ladybug
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
20
|
+
Requires-Python: <3.15,>=3.11
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: deepagents>=0.6.10
|
|
24
|
+
Requires-Dist: ladybug==0.20.3
|
|
25
|
+
Requires-Dist: langchain-core<2.0.0,>=1.4.0
|
|
26
|
+
Requires-Dist: wcmatch>=10.1
|
|
27
|
+
Provides-Extra: test
|
|
28
|
+
Requires-Dist: pytest>=8.0.0; extra == "test"
|
|
29
|
+
Requires-Dist: pytest-asyncio>=1.0.0; extra == "test"
|
|
30
|
+
Requires-Dist: ruff<0.16.0,>=0.12.2; extra == "test"
|
|
31
|
+
Dynamic: license-file
|
|
32
|
+
|
|
33
|
+
# deepagents-graph-memory
|
|
34
|
+
|
|
35
|
+
An experimental graph-backed workflow and trace store for LangChain Deep Agents. It records linked project context in LadybugDB, supports keyword search and bounded traversal, and exposes read-only Markdown views for inspection.
|
|
36
|
+
|
|
37
|
+
Created by **Pranav Bedi and Taha Khan**.
|
|
38
|
+
|
|
39
|
+
The [workflow evaluation](https://github.com/TahaK29/deepagents-graph-memory/blob/main/evals/README.md) runs twelve offline integration scenarios and offers an opt-in, bounded graph-versus-notes model comparison. Offline passes verify retrieval mechanics, not improved model decisions.
|
|
40
|
+
|
|
41
|
+
**Debugging a missing graph fact?** See [Inspecting the graph](#inspecting-the-graph) for a copyable Python example that needs no model or provider key.
|
|
42
|
+
|
|
43
|
+
[](https://github.com/TahaK29/deepagents-graph-memory)
|
|
44
|
+
[](https://python.org)
|
|
45
|
+
[](https://ladybugdb.com)
|
|
46
|
+
[](https://python.langchain.com)
|
|
47
|
+
[](https://opensource.org/licenses/MIT)
|
|
48
|
+
|
|
49
|
+
<p align="center">
|
|
50
|
+
<img src="https://raw.githubusercontent.com/TahaK29/deepagents-graph-memory/main/assets/vgs-graph.png" alt="Virtual Graph System: connected reasoning traces" width="50%">
|
|
51
|
+
</p>
|
|
52
|
+
|
|
53
|
+
## Motivation
|
|
54
|
+
|
|
55
|
+
Neo4j's [context graph article](https://neo4j.com/blog/genai/from-recall-to-reasoning-how-context-graphs-upgrade-an-agents-brain/) inspired this project. The package records supplied situations, rationales, actions, outcomes, artifacts, and links so agents can retrieve connected work context. It does not verify causal claims, infer new relationships, transfer knowledge automatically, or unlearn outdated facts. A rationale or causal label is an assertion supplied by the caller.
|
|
56
|
+
|
|
57
|
+
## What It Does
|
|
58
|
+
|
|
59
|
+
| Structured Traces | Graph Recall | Virtual Graph Views |
|
|
60
|
+
|---|---|---|
|
|
61
|
+
| Situation → Rationale → Action → Outcome | Keyword search + bounded traversal | Read-only `/graph/...` markdown projections |
|
|
62
|
+
| Caller-supplied links and metadata | Anchor-based seed expansion | Schema, index, node, search |
|
|
63
|
+
| Workflow and project context | Approximate output sizing plus depth, node, and edge limits | Inspectable through backend methods |
|
|
64
|
+
|
|
65
|
+
This is **not** ordinary user memory. Don't use it for facts like "the user likes ice cream." Use it for connected work state like *"this failing test led to this hypothesis, this edit, this result, and this final decision."*
|
|
66
|
+
|
|
67
|
+
The namespace option scopes graph data; it is not an authorization boundary, and schema inspection remains database-wide. `GraphMemoryBackend.create()` uses in-memory LadybugDB by default. Its data remains available while the backend/store is open and disappears when it closes or the process exits; there is no automatic cleanup after each agent invocation. Supply a filesystem `path` for [persistent storage](#persistent-storage).
|
|
68
|
+
|
|
69
|
+
### Sharing one graph between agents
|
|
70
|
+
|
|
71
|
+
Create one store and pass it to each backend. Use the same project namespace so both writers can inspect the same graph. Agent and subagent IDs are supplied by the caller; they are not inferred from the agent runtime.
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
from deepagents_graph_memory import GraphMemoryBackend, graph_memory_tools, make_graph_subject
|
|
75
|
+
from deepagents_graph_memory.ladybug_store import LadybugGraphStore
|
|
76
|
+
|
|
77
|
+
store = LadybugGraphStore.memory()
|
|
78
|
+
parent = GraphMemoryBackend(store, namespace=("project", "demo"))
|
|
79
|
+
subagent = GraphMemoryBackend(store, namespace=("project", "demo"))
|
|
80
|
+
subject = make_graph_subject("src/parser.py", "empty-field parsing", "linux")
|
|
81
|
+
# Give the same subject to each worker when creating its tools.
|
|
82
|
+
worker_record = next(tool for tool in graph_memory_tools(subagent, bound_subject=subject) if tool.name == "record_graph_trace")
|
|
83
|
+
|
|
84
|
+
parent.record_graph_trace(
|
|
85
|
+
situation="test failed at revision a1", rationale="the parser missed an empty field",
|
|
86
|
+
action="asked a subagent to inspect the parser", outcome="cause identified",
|
|
87
|
+
run_id="run-1", agent_id="parent", subject=subject,
|
|
88
|
+
)
|
|
89
|
+
worker_record.invoke({
|
|
90
|
+
"situation": "parser skipped an empty field at revision a1", "rationale": "split removed the field",
|
|
91
|
+
"action": "patched the parser", "outcome": "test passed at revision b2",
|
|
92
|
+
"artifacts": ["src/parser.py"], "run_id": "run-1", "agent_id": "parent", "subagent_id": "parser-debugger",
|
|
93
|
+
}) # The binding supplies subject even though this call omits it.
|
|
94
|
+
print(parent.ls("/graph/nodes/Trace/").entries)
|
|
95
|
+
print(parent.read("/graph/search/parser.md").file_data["content"])
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Writes through one store are serialized and each trace or document batch commits atomically. Existing node and edge properties survive updates that omit them; the last successful writer wins when writers set the same property. Shared Artifact and Evidence values retain links to every trace, with per-trace IDs on the links. Distinct in-memory stores do not share data. For a persistent graph, create one backend with `path=...` and pass its `.store` to other backends in the same process. Close the shared store only after all agents finish using it.
|
|
99
|
+
|
|
100
|
+
## Quick Start
|
|
101
|
+
|
|
102
|
+
Install the package:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
pip install deepagents-graph-memory
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Complete the one-time [full-text search setup](#full-text-search-setup) before
|
|
109
|
+
running graph search or recall.
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
from deepagents import create_deep_agent
|
|
113
|
+
from deepagents.backends import CompositeBackend, StateBackend
|
|
114
|
+
from deepagents_graph_memory import (
|
|
115
|
+
GraphMemoryBackend,
|
|
116
|
+
graph_context_middleware,
|
|
117
|
+
graph_memory_tools,
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
MODEL = "google_genai:gemini-3.5-flash"
|
|
121
|
+
|
|
122
|
+
# In-memory LadybugDB graph; no database path required
|
|
123
|
+
graph_backend = GraphMemoryBackend.create()
|
|
124
|
+
graph_tools = graph_memory_tools(graph_backend)
|
|
125
|
+
|
|
126
|
+
agent = create_deep_agent(
|
|
127
|
+
model=MODEL,
|
|
128
|
+
tools=graph_tools,
|
|
129
|
+
middleware=[graph_context_middleware()],
|
|
130
|
+
memory=["/graph/index.md", "/graph/schema.md"],
|
|
131
|
+
backend=CompositeBackend(
|
|
132
|
+
default=StateBackend(), # Working files and offloaded tool results.
|
|
133
|
+
routes={"/graph/": graph_backend}, # Read-only graph inspection.
|
|
134
|
+
),
|
|
135
|
+
subagents=[{
|
|
136
|
+
# Configure the default worker explicitly so it also gets graph guidance.
|
|
137
|
+
"name": "general-purpose",
|
|
138
|
+
"description": "Investigate a focused task and return findings with evidence.",
|
|
139
|
+
"system_prompt": "Complete the assigned task and report findings with source paths.",
|
|
140
|
+
"tools": graph_tools,
|
|
141
|
+
"middleware": [graph_context_middleware()],
|
|
142
|
+
}],
|
|
143
|
+
)
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Configure the selected model provider integration and credentials separately. The no-provider-key example below only exercises backend inspection.
|
|
147
|
+
|
|
148
|
+
## Using VGS and VFS Together
|
|
149
|
+
|
|
150
|
+
Keep filesystem tools available for files, scratch work, and full tool output.
|
|
151
|
+
Use the graph to connect meaningful findings, failed attempts, decisions, and
|
|
152
|
+
outcomes to their evidence. A test log belongs in VFS; a trace can record what
|
|
153
|
+
failed, what changed, and which test run supports the result.
|
|
154
|
+
|
|
155
|
+
`graph_context_middleware()` adds this guidance to one agent without changing
|
|
156
|
+
model-wide profiles or removing filesystem instructions. Pass graph tools
|
|
157
|
+
explicitly. Add the middleware and graph tools to each subagent that needs them;
|
|
158
|
+
parent middleware does not automatically propagate to every subagent. The quick
|
|
159
|
+
start overrides the built-in general-purpose worker for this reason. Precompiled
|
|
160
|
+
or remote agents need their own setup and access to the evidence they cite.
|
|
161
|
+
|
|
162
|
+
The first lookup depends on the task: read a known file directly for a file edit,
|
|
163
|
+
or recall earlier attempts and dependencies when resuming work. Verify current
|
|
164
|
+
files or tool results before relying on historical findings. Record selective
|
|
165
|
+
outcomes rather than mirroring every read, file, or log line into the graph.
|
|
166
|
+
|
|
167
|
+
Deep Agents' existing filesystem middleware can offload large tool responses
|
|
168
|
+
under `/large_tool_results/`. Keep that location on a writable VFS backend so the
|
|
169
|
+
agent can use `read_file` and `grep` to inspect the dump. This package does not
|
|
170
|
+
change the offload threshold or copy the full dump into LadybugDB. When recording a
|
|
171
|
+
finding, use `evidence_refs` to cite the actual saved location and source identity,
|
|
172
|
+
including the revision or observation time when known.
|
|
173
|
+
|
|
174
|
+
Save captured evidence before recording a claim about it. File and graph writes
|
|
175
|
+
are separate operations: if trace recording fails after an action succeeded,
|
|
176
|
+
retry the recording with its operation ID rather than repeating the action.
|
|
177
|
+
Missing, inaccessible, or changed evidence cannot verify the original finding.
|
|
178
|
+
The middleware provides agent guidance; it does not fetch sources or enforce
|
|
179
|
+
atomic writes across VFS and LadybugDB.
|
|
180
|
+
|
|
181
|
+
You can keep your existing filesystem backend and add only the graph tools and
|
|
182
|
+
middleware. Mounting `/graph/` through the native `CompositeBackend` is optional;
|
|
183
|
+
it enables read-only file inspection of graph views. `write_file`, `edit_file`,
|
|
184
|
+
and uploads cannot mutate those views. Keep the physical LadybugDB database outside
|
|
185
|
+
the agent's writable file workspace. Ordinary preferences, instructions, and
|
|
186
|
+
notes remain in VFS or `/memories/`.
|
|
187
|
+
|
|
188
|
+
**Storage lifetimes are separate.** `StateBackend` uses thread state; retaining
|
|
189
|
+
those files across process restarts requires a durable checkpointer. Saving LadybugDB
|
|
190
|
+
with `path=...` does not persist VFS files. For evidence that must survive across
|
|
191
|
+
threads or deployments, configure a suitable persistent file/store backend and
|
|
192
|
+
give readers access to it. Do not assume a saved graph makes an old dump available.
|
|
193
|
+
|
|
194
|
+
## Persistent Storage
|
|
195
|
+
|
|
196
|
+
Persistence works through the Python library API in scripts, notebooks, agent
|
|
197
|
+
runners, background workers, or web applications. It does not depend on a web
|
|
198
|
+
framework or cloud provider. The application opens one store, passes it to its
|
|
199
|
+
agents, and closes it after they finish.
|
|
200
|
+
|
|
201
|
+
Pass a `str` or `pathlib.Path` to create or reopen a LadybugDB database file. The parent
|
|
202
|
+
directory must already exist; the package does not create directories or mount
|
|
203
|
+
storage. Examples use `.lbdb`; the path accepts any extension. Omitting `path`,
|
|
204
|
+
or passing `None`, keeps the default in-memory behavior.
|
|
205
|
+
|
|
206
|
+
This example writes a trace, closes the database, and reopens it without an LLM:
|
|
207
|
+
|
|
208
|
+
```python
|
|
209
|
+
from pathlib import Path
|
|
210
|
+
from tempfile import TemporaryDirectory
|
|
211
|
+
|
|
212
|
+
from deepagents_graph_memory import GraphMemoryBackend
|
|
213
|
+
|
|
214
|
+
with TemporaryDirectory() as directory: # Use a durable directory in your app.
|
|
215
|
+
path = Path(directory) / "project.lbdb"
|
|
216
|
+
graph = GraphMemoryBackend.create(path=path, namespace=("project", "demo"))
|
|
217
|
+
try:
|
|
218
|
+
trace_id = graph.record_graph_trace(
|
|
219
|
+
situation="parser test failed", rationale="empty field was dropped",
|
|
220
|
+
action="fixed the parser", outcome="test passed",
|
|
221
|
+
)
|
|
222
|
+
finally:
|
|
223
|
+
graph.close()
|
|
224
|
+
|
|
225
|
+
reopened = GraphMemoryBackend.create(path=path, namespace=("project", "demo"))
|
|
226
|
+
try:
|
|
227
|
+
print(reopened.read(f"/graph/nodes/Trace/{trace_id}.md").file_data["content"])
|
|
228
|
+
finally:
|
|
229
|
+
reopened.close()
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
Successful writes commit during execution. `close()` releases the connection and
|
|
233
|
+
database lock; it does not delete a disk database. Calling it again is safe.
|
|
234
|
+
Backends sharing one store share its lifetime, so closing any of them closes that
|
|
235
|
+
store for all of them. Keep the database open across requests and close it during
|
|
236
|
+
application shutdown. Do not close it inside an active transaction.
|
|
237
|
+
|
|
238
|
+
Invalid paths and open failures raise errors instead of falling back to memory.
|
|
239
|
+
The path names a database file, not a directory or a URL such as `s3://...`.
|
|
240
|
+
Keep its containing directory on durable storage, including LadybugDB's associated
|
|
241
|
+
files. Reuse the same namespace when resuming the same project.
|
|
242
|
+
|
|
243
|
+
### FastAPI and containers
|
|
244
|
+
|
|
245
|
+
FastAPI is one lifecycle example; other applications use the same `create(path=...)`
|
|
246
|
+
and `close()` calls in their own startup and shutdown code.
|
|
247
|
+
|
|
248
|
+
Configure your deployment to mount durable storage at `/data`, then open the
|
|
249
|
+
database once in FastAPI's lifespan. FastAPI is an application dependency; this
|
|
250
|
+
package does not install it.
|
|
251
|
+
|
|
252
|
+
```python
|
|
253
|
+
from contextlib import asynccontextmanager
|
|
254
|
+
|
|
255
|
+
from fastapi import FastAPI
|
|
256
|
+
from deepagents_graph_memory import GraphMemoryBackend
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
@asynccontextmanager
|
|
260
|
+
async def lifespan(app: FastAPI):
|
|
261
|
+
graph = GraphMemoryBackend.create(
|
|
262
|
+
path="/data/project.lbdb", namespace=("project", "demo"),
|
|
263
|
+
)
|
|
264
|
+
app.state.graph = graph
|
|
265
|
+
try:
|
|
266
|
+
yield
|
|
267
|
+
finally:
|
|
268
|
+
graph.close()
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
app = FastAPI(lifespan=lifespan)
|
|
272
|
+
# Use app.state.graph when constructing agents in your request handlers.
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
Use one worker process per writable database, for example
|
|
276
|
+
`uvicorn app:app --workers 1`. Parent and subagents in that process reuse the
|
|
277
|
+
store. A replacement container must open the same mounted database after the old
|
|
278
|
+
process releases it; rolling deployments must not overlap database owners. A
|
|
279
|
+
single replica setting alone does not prevent overlap during replacement.
|
|
280
|
+
|
|
281
|
+
The developer configures the volume, permissions, and retention across container
|
|
282
|
+
replacement. An ordinary container filesystem is not durable. The package accepts
|
|
283
|
+
a filesystem path and has no cloud SDKs, blob uploads, or automatic LangSmith
|
|
284
|
+
storage integration. It cannot detect whether your mount survives redeployment.
|
|
285
|
+
|
|
286
|
+
[Azure Container Apps storage mounts](https://learn.microsoft.com/en-us/azure/container-apps/storage-mounts)
|
|
287
|
+
and [AWS ECS EFS volumes](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/efs-volumes.html)
|
|
288
|
+
describe provider setup. These links are not a claim of tested LadybugDB compatibility:
|
|
289
|
+
network filesystems must support LadybugDB's locking and file operations, and need
|
|
290
|
+
deployment-specific recovery tests. Local filesystem persistence is covered by
|
|
291
|
+
this package's tests; Azure Files and EFS have not been integration-tested here.
|
|
292
|
+
|
|
293
|
+
## How It Works
|
|
294
|
+
|
|
295
|
+
### Graph Traces
|
|
296
|
+
|
|
297
|
+
`record_graph_trace` records the core reasoning shape:
|
|
298
|
+
|
|
299
|
+
```
|
|
300
|
+
Situation -> Rationale -> Action -> Outcome
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
For example:
|
|
304
|
+
|
|
305
|
+
```
|
|
306
|
+
Situation: "sheep saw lion"
|
|
307
|
+
Rationale: "lion is dangerous"
|
|
308
|
+
Action: "sheep ran away"
|
|
309
|
+
Outcome: "sheep survived"
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
The graph stores edges like:
|
|
313
|
+
|
|
314
|
+
```
|
|
315
|
+
sheep saw lion --LED_TO--> lion is dangerous
|
|
316
|
+
lion is dangerous --JUSTIFIED--> sheep ran away
|
|
317
|
+
sheep ran away --PRODUCED--> sheep survived
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
Related findings can share a narrow `subject` within a namespace. Create it once
|
|
321
|
+
with `make_graph_subject(entity, aspect, environment)` and pass it to workers with
|
|
322
|
+
`graph_memory_tools(backend, bound_subject=subject)`. A worker may omit `subject`
|
|
323
|
+
when recording a trace; a different explicit subject is rejected. Keep changing
|
|
324
|
+
revisions in the trace context or evidence, and use separate subjects for environments
|
|
325
|
+
whose states should not be compared as one question. `observed_at` is
|
|
326
|
+
the time of the observation, while server-generated `recorded_at` is when the trace
|
|
327
|
+
was saved. A caller may explicitly supersede an earlier **state** finding only
|
|
328
|
+
with evidence and a strictly newer observation. The old trace and parallel newer
|
|
329
|
+
findings remain in the graph; explanations are never superseded by this rule.
|
|
330
|
+
For a reviewed disagreement between two or more same-subject traces, an evidenced
|
|
331
|
+
resolution trace can use `resolves=[...]`. Recall places that resolution ahead of
|
|
332
|
+
the reviewed originals and links them; this records a caller judgment, not a
|
|
333
|
+
database check of its truth.
|
|
334
|
+
|
|
335
|
+
```python
|
|
336
|
+
from deepagents_graph_memory import GraphMemoryBackend
|
|
337
|
+
from deepagents_graph_memory.errors import GraphMemoryValidationError
|
|
338
|
+
|
|
339
|
+
graph = GraphMemoryBackend.create()
|
|
340
|
+
common = dict(subject="tests/test_parser.py::test_empty@linux", finding_type="state")
|
|
341
|
+
graph.record_graph_trace(
|
|
342
|
+
trace_id="failed", situation="parser test at revision a1", rationale="pytest exit 1",
|
|
343
|
+
action="ran pytest", outcome="failed", evidence=["pytest output at a1: failed"],
|
|
344
|
+
observed_at="2026-09-19T10:00:00Z", **common,
|
|
345
|
+
)
|
|
346
|
+
graph.record_graph_trace(
|
|
347
|
+
trace_id="passed", situation="parser test at revision b2", rationale="pytest exit 0",
|
|
348
|
+
action="reran pytest", outcome="passed", evidence=["pytest output at b2: passed"],
|
|
349
|
+
observed_at="2026-09-19T11:00:00Z", supersedes=["failed"], **common,
|
|
350
|
+
)
|
|
351
|
+
try:
|
|
352
|
+
graph.record_graph_trace(
|
|
353
|
+
trace_id="delayed", situation="late report from revision a1", rationale="old output",
|
|
354
|
+
action="reported result", outcome="failed", evidence=["pytest output at a1: failed"],
|
|
355
|
+
observed_at="2026-09-19T09:30:00Z", supersedes=["passed"], **common,
|
|
356
|
+
)
|
|
357
|
+
except GraphMemoryValidationError:
|
|
358
|
+
pass # An older observation cannot supersede the newer one.
|
|
359
|
+
print(graph.recall_graph_memory("failed", anchors=["/graph/nodes/Trace/failed.md"], max_nodes=2))
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
The caller supplies the subject and supersession assertion. Graph storage does not
|
|
363
|
+
detect contradictions, verify the evidence, or gate external actions. Recall brings
|
|
364
|
+
same-subject findings together when budgets permit and flags incomplete context;
|
|
365
|
+
the reading agent must compare and verify material disagreements before deciding.
|
|
366
|
+
It ranks a single subject's terminal findings and resolutions before applying the
|
|
367
|
+
node limit, using observation time for order when present. Competing branches stay
|
|
368
|
+
visible when the budget fits them. A partial history is labeled incomplete, and
|
|
369
|
+
an omitted anchor gets a direct path to inspect. This currently scans one subject's
|
|
370
|
+
traces during recall, so very large subjects may cost more to read.
|
|
371
|
+
|
|
372
|
+
Structured `evidence_refs` identify captured sources across reports. The caller
|
|
373
|
+
assigns a distinct `source_id` to each actual execution or snapshot at collection;
|
|
374
|
+
`locator` points to its log, file, or document. Reusing that ID cites the same
|
|
375
|
+
source, while changing its locator, revision, or observation time raises an error.
|
|
376
|
+
Optional `summary` describes a reporter's reading and belongs to that citation.
|
|
377
|
+
Plain `evidence` strings still work, but are unstructured caller reports. Neither
|
|
378
|
+
kind of evidence is fetched or verified by the graph. Distinct cited sources are
|
|
379
|
+
not necessarily independent experiments, and partial recall cannot establish a
|
|
380
|
+
complete source count.
|
|
381
|
+
|
|
382
|
+
```python
|
|
383
|
+
from deepagents_graph_memory import GraphMemoryBackend
|
|
384
|
+
|
|
385
|
+
graph = GraphMemoryBackend.create()
|
|
386
|
+
ref = {
|
|
387
|
+
"source_id": "pytest-run-17", "locator": "logs/pytest-run-17.txt",
|
|
388
|
+
"revision": "commit-a1", "observed_at": "2026-09-19T10:00:00Z",
|
|
389
|
+
}
|
|
390
|
+
for agent, summary in [("worker-a", "empty input failed"), ("worker-b", "parser failed")]:
|
|
391
|
+
graph.record_graph_trace(
|
|
392
|
+
situation="parser check", rationale="read pytest output", action="reported result",
|
|
393
|
+
outcome="failed", subject="parser@linux", agent_id=agent,
|
|
394
|
+
evidence_refs=[{**ref, "summary": summary}],
|
|
395
|
+
)
|
|
396
|
+
print(graph.recall_graph_memory("parser@linux", max_nodes=3))
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
Conclusions can cite prior Trace IDs with `depends_on`. The targets must already
|
|
400
|
+
exist in the same namespace. Recall follows these links within its node, edge,
|
|
401
|
+
and depth budgets. If a cited finding is explicitly superseded or reviewed in a
|
|
402
|
+
resolution, recall marks the dependent conclusion `needs recheck` and shows the
|
|
403
|
+
changed premise's update path. This also applies through a chain of dependencies.
|
|
404
|
+
It flags review; it does not prove the decision false or change the original trace.
|
|
405
|
+
Missing evidence, cycles, or an incomplete dependency traversal produce an
|
|
406
|
+
unknown-status warning. A fresh conclusion should cite the current findings it
|
|
407
|
+
actually used.
|
|
408
|
+
|
|
409
|
+
```python
|
|
410
|
+
from deepagents_graph_memory import GraphMemoryBackend
|
|
411
|
+
|
|
412
|
+
graph = GraphMemoryBackend.create()
|
|
413
|
+
graph.record_graph_trace(
|
|
414
|
+
trace_id="probe-failed", situation="checkout probe", rationale="run 1",
|
|
415
|
+
action="tested checkout", outcome="failed", subject="checkout@staging",
|
|
416
|
+
finding_type="state", observed_at="2026-09-19T10:00:00Z", evidence=["run 1 log"],
|
|
417
|
+
)
|
|
418
|
+
graph.record_graph_trace(
|
|
419
|
+
trace_id="mitigation", situation="checkout failed", rationale="probe-failed",
|
|
420
|
+
action="chose temporary mitigation", outcome="disable checkout",
|
|
421
|
+
depends_on=["probe-failed"],
|
|
422
|
+
)
|
|
423
|
+
graph.record_graph_trace(
|
|
424
|
+
trace_id="probe-passed", situation="checkout probe", rationale="run 2",
|
|
425
|
+
action="tested checkout", outcome="passed", subject="checkout@staging",
|
|
426
|
+
finding_type="state", observed_at="2026-09-19T11:00:00Z", evidence=["run 2 log"],
|
|
427
|
+
supersedes=["probe-failed"],
|
|
428
|
+
)
|
|
429
|
+
context = graph.recall_graph_memory("mitigation", anchors=["/graph/nodes/Trace/mitigation.md"])
|
|
430
|
+
assert "needs recheck" in context
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
Use `operation_id` when retrying the same trace write. Replaying the same request
|
|
434
|
+
returns its original trace ID without changing the graph; changing the normalized
|
|
435
|
+
request under that ID raises `GraphMemoryValidationError`. A new execution needs a
|
|
436
|
+
new ID, even if its text is identical. The identity is scoped to the backend
|
|
437
|
+
namespace, and `operation_id` cannot be combined with `trace_id`.
|
|
438
|
+
|
|
439
|
+
```python
|
|
440
|
+
from deepagents_graph_memory import GraphMemoryBackend
|
|
441
|
+
|
|
442
|
+
graph = GraphMemoryBackend.create()
|
|
443
|
+
payload = dict(situation="network timeout", rationale="probe failed", action="checked network", outcome="unavailable")
|
|
444
|
+
first = graph.record_graph_trace(operation_id="network-probe-7", **payload)
|
|
445
|
+
assert graph.record_graph_trace(operation_id="network-probe-7", **payload) == first
|
|
446
|
+
assert graph.record_graph_trace(operation_id="network-probe-8", **payload) != first
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
The `record_graph_trace` tool uses its injected tool-call ID and runtime thread ID
|
|
450
|
+
for retries when no explicit `operation_id` is supplied. Direct calls without
|
|
451
|
+
either ID continue to append traces.
|
|
452
|
+
|
|
453
|
+
Writes are issued as LadybugDB Cypher `MERGE` statements (no raw Cypher is exposed to the agent).
|
|
454
|
+
|
|
455
|
+
### Graph Recall
|
|
456
|
+
|
|
457
|
+
`recall_graph_memory` searches for seed facts, expands through useful edges, and returns compact markdown with source `/graph/...` paths. Pass anchors (file paths, run IDs, task IDs) to give recall a concrete starting point.
|
|
458
|
+
|
|
459
|
+
Matching generated trace components and paths are summarized once in recall. Explicit component anchors, custom nodes with different content, and direct `/graph/...` debug views remain available.
|
|
460
|
+
|
|
461
|
+
Recall uses LadybugDB keyword search to find seed nodes, then bounded Cypher `MATCH` traversal to expand connected context. The token budget estimates output size; it is not an exact token cap. No vector/embedding search is used.
|
|
462
|
+
|
|
463
|
+
```python
|
|
464
|
+
graph_backend.recall_graph_memory("what services did incident 123 affect and what do they depend on?")
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
## Graph Tools
|
|
468
|
+
|
|
469
|
+
```python
|
|
470
|
+
graph_memory_tools(graph_backend)
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
| Tool | Purpose |
|
|
474
|
+
|---|---|
|
|
475
|
+
| `recall_graph_memory` | Primary read path -- search, expand, return context |
|
|
476
|
+
| `record_graph_trace` | High-level write -- Situation → Rationale → Action → Outcome |
|
|
477
|
+
|
|
478
|
+
Low-level write tools are available for application builders but not exposed by default, since unconstrained agents can create drifting labels and relationship types:
|
|
479
|
+
|
|
480
|
+
```python
|
|
481
|
+
graph_memory_tools(graph_backend, include_low_level_writes=True)
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
| Tool | Purpose |
|
|
485
|
+
|---|---|
|
|
486
|
+
| `add_graph_node` | Create or update entities |
|
|
487
|
+
| `add_graph_edge` | Create or update relationships |
|
|
488
|
+
| `add_graph_documents` | Ingest LangChain documents |
|
|
489
|
+
|
|
490
|
+
For production use, prefer domain-specific tools that call `graph_backend.add_graph_node(...)` and `graph_backend.add_graph_edge(...)` with your application's approved labels and relationships.
|
|
491
|
+
|
|
492
|
+
## Virtual Graph Views
|
|
493
|
+
|
|
494
|
+
The backend projects graph state into read-only markdown paths:
|
|
495
|
+
|
|
496
|
+
| Path | Description |
|
|
497
|
+
|---|---|
|
|
498
|
+
| `/graph/schema.md` | Current graph schema |
|
|
499
|
+
| `/graph/index.md` | Graph memory landing page |
|
|
500
|
+
| `/graph/nodes/{label}/{id}.md` | Single node with properties and relationships |
|
|
501
|
+
| `/graph/search/{query}.md` | Search results with preview text |
|
|
502
|
+
|
|
503
|
+
These are generated virtual paths, not files on disk or browser links. Node pages include stored properties, provenance when present, and bounded one-hop relationships. Writes go through graph tools, not file operations.
|
|
504
|
+
|
|
505
|
+
### Inspecting the graph
|
|
506
|
+
|
|
507
|
+
Use backend methods to check a recorded fact directly, even when recall does not select it. This example runs locally without an LLM or provider key:
|
|
508
|
+
|
|
509
|
+
```python
|
|
510
|
+
from deepagents_graph_memory import GraphMemoryBackend
|
|
511
|
+
|
|
512
|
+
backend = GraphMemoryBackend.create()
|
|
513
|
+
trace_id = backend.record_graph_trace(
|
|
514
|
+
trace_id="debug-trace-1",
|
|
515
|
+
situation="scope test failed",
|
|
516
|
+
rationale="a graph read might use the wrong scope",
|
|
517
|
+
action="checked the read path",
|
|
518
|
+
outcome="scope test passed",
|
|
519
|
+
source="tests/test_scope.py",
|
|
520
|
+
)
|
|
521
|
+
|
|
522
|
+
print(trace_id)
|
|
523
|
+
print([entry["path"] for entry in backend.ls("/graph/nodes/Trace/").entries])
|
|
524
|
+
node_path = f"/graph/nodes/Trace/{trace_id}.md"
|
|
525
|
+
node = backend.read(node_path)
|
|
526
|
+
if node.error:
|
|
527
|
+
raise RuntimeError(node.error)
|
|
528
|
+
print(node.file_data["content"])
|
|
529
|
+
print(backend.read("/graph/schema.md").file_data["content"])
|
|
530
|
+
print(backend.read("/graph/search/scope.md").file_data["content"])
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
For a missing answer, read the exact known node path first. A "not found" error means that node is absent from the active scope; a returned page lets you inspect its text, provenance, and relationships. Then try `backend.recall_graph_memory("scope test", anchors=[node_path])` to start recall at that node. `ls()` helps discover paths. If a directory exceeds `max_nodes`, listing and recursive file discovery return an error instead of silently omitting files; increase `max_nodes` or use a known node path. Inspection bypasses recall's relevance selection, while node relationships still obey `max_nodes` and `max_edges`. `read()` also accepts line `offset` and `limit`.
|
|
534
|
+
|
|
535
|
+
`grep()` searches the rendered Markdown for case-sensitive literal text and returns
|
|
536
|
+
matching lines with their line numbers. Use `/graph/search/{query}.md` or
|
|
537
|
+
`recall_graph_memory()` for ranked keyword search. `glob()` matches relative to its
|
|
538
|
+
`path`: `*.md` matches filenames at any depth, `/*.md` matches only the root, and
|
|
539
|
+
`nodes/**/*.md` matches paths under `nodes/`. Directory paths work with or without
|
|
540
|
+
a trailing slash. Reads preserve newlines and provide pagination metadata when
|
|
541
|
+
the installed Deep Agents version supports it. On current Deep Agents,
|
|
542
|
+
`grep(..., max_count=10)` reports `truncated=True` when more matching lines exist;
|
|
543
|
+
older versions without truncation metadata return an error if the cap is exceeded.
|
|
544
|
+
Async variants follow the installed Deep Agents protocol, including its supported
|
|
545
|
+
arguments.
|
|
546
|
+
|
|
547
|
+
## Optional Graph-Only Mode
|
|
548
|
+
|
|
549
|
+
For applications that deliberately omit filesystem tools, the existing
|
|
550
|
+
`register_vgs_harness_profile(model)` helper enables graph-only behavior:
|
|
551
|
+
|
|
552
|
+
- Deep Agents default VFS tools are hidden: `ls`, `read_file`, `write_file`, `edit_file`, `delete`, `glob`, `grep` (where available)
|
|
553
|
+
- VGS prompt guidance is added
|
|
554
|
+
- The caller passes `graph_memory_tools(graph_backend)` explicitly; the profile does not install them
|
|
555
|
+
|
|
556
|
+
With file tools hidden, agents use `recall_graph_memory`, which queries the graph store directly. `memory=["/graph/index.md", "/graph/schema.md"]` loads those two views into agent context; it does not enable interactive graph browsing. Developers can still inspect through `GraphMemoryBackend.ls()`, `read()`, `glob()`, and `grep()`.
|
|
557
|
+
|
|
558
|
+
Use the combined setup above when the agent needs files or offloaded tool output.
|
|
559
|
+
The graph-only helper changes the profile for a model key throughout the process;
|
|
560
|
+
do not register it for a model used by combined-mode agents. Adding
|
|
561
|
+
`graph_context_middleware()` does not undo an existing tool exclusion. Graph tools
|
|
562
|
+
remain opt-in for ordinary Deep Agents applications.
|
|
563
|
+
Application-supplied instructions are preserved. Older Deep Agents releases'
|
|
564
|
+
automatically added filesystem guidance is removed in graph-only mode. Tool
|
|
565
|
+
exclusion controls model exposure; it is not an authorization boundary.
|
|
566
|
+
|
|
567
|
+
## Architecture
|
|
568
|
+
|
|
569
|
+
### System Overview
|
|
570
|
+
|
|
571
|
+
```mermaid
|
|
572
|
+
graph TB
|
|
573
|
+
Agent["LangChain Deep Agent"]
|
|
574
|
+
|
|
575
|
+
subgraph VGS ["Virtual Graph System"]
|
|
576
|
+
Tools["Graph Tools<br/><i>tools.py</i>"]
|
|
577
|
+
Backend["GraphMemoryBackend<br/><i>backend.py</i>"]
|
|
578
|
+
Recall["Recall Engine<br/><i>recall.py</i>"]
|
|
579
|
+
Renderers["Markdown Renderers<br/><i>renderers.py</i>"]
|
|
580
|
+
Paths["Path Parser<br/><i>paths.py</i>"]
|
|
581
|
+
VGSProfile["Graph Context Guidance<br/><i>vgs.py</i>"]
|
|
582
|
+
end
|
|
583
|
+
|
|
584
|
+
subgraph Store ["Storage"]
|
|
585
|
+
LadybugDB["LadybugDB Graph: Memory or Disk<br/><i>ladybug_store.py</i>"]
|
|
586
|
+
end
|
|
587
|
+
|
|
588
|
+
Agent -->|"record_graph_trace<br/>recall_graph_memory"| Tools
|
|
589
|
+
Agent -->|"file tools"| VFS["VFS: Files and Tool Dumps"]
|
|
590
|
+
Tools --> Backend
|
|
591
|
+
Backend --> Recall
|
|
592
|
+
Backend --> Renderers
|
|
593
|
+
Backend --> Paths
|
|
594
|
+
Recall --> LadybugDB
|
|
595
|
+
Renderers --> LadybugDB
|
|
596
|
+
VGSProfile -.->|"guides graph and file use"| Agent
|
|
597
|
+
|
|
598
|
+
style VGS fill:#1e293b,stroke:#334155,color:#e2e8f0
|
|
599
|
+
style Store fill:#1e293b,stroke:#334155,color:#e2e8f0
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
### Combined and Graph-Only Setups
|
|
603
|
+
|
|
604
|
+
```mermaid
|
|
605
|
+
graph LR
|
|
606
|
+
subgraph Combined ["Combined Setup"]
|
|
607
|
+
VFS["VFS Tools<br/>ls, read_file, write_file,<br/>edit_file, glob, grep"]
|
|
608
|
+
GraphTools["Graph Tools<br/>recall_graph_memory<br/>record_graph_trace"]
|
|
609
|
+
GraphTools -->|"evidence references"| VFS
|
|
610
|
+
end
|
|
611
|
+
|
|
612
|
+
subgraph VGSMode ["Optional Graph-Only Profile"]
|
|
613
|
+
VFSHidden["VFS Tools<br/><s>hidden</s>"]
|
|
614
|
+
OnlyGraph["Graph Tools"]
|
|
615
|
+
end
|
|
616
|
+
|
|
617
|
+
VFSHidden ~~~ OnlyGraph
|
|
618
|
+
|
|
619
|
+
style VFSHidden fill:#991b1b,stroke:#7f1d1d,color:#fecaca
|
|
620
|
+
style GraphTools fill:#065f46,stroke:#064e3b,color:#a7f3d0
|
|
621
|
+
```
|
|
622
|
+
|
|
623
|
+
### Recall Pipeline
|
|
624
|
+
|
|
625
|
+
```mermaid
|
|
626
|
+
graph LR
|
|
627
|
+
Q["Query or Anchors"] --> Seed["Seed Search<br/><i>full-text + relationship labels</i>"]
|
|
628
|
+
Seed --> Expand["Graph Expansion<br/><i>bounded traversal</i>"]
|
|
629
|
+
Expand --> Budget["Budget Enforcement<br/><i>tokens, depth, nodes, edges</i>"]
|
|
630
|
+
Budget --> MD["Markdown Output<br/><i>with /graph/... source paths</i>"]
|
|
631
|
+
```
|
|
632
|
+
|
|
633
|
+
### Trace Data Model
|
|
634
|
+
|
|
635
|
+
```mermaid
|
|
636
|
+
graph LR
|
|
637
|
+
S["Situation"] -->|LED_TO| R["Rationale"]
|
|
638
|
+
R -->|JUSTIFIED| A["Action"]
|
|
639
|
+
A -->|PRODUCED| O["Outcome"]
|
|
640
|
+
|
|
641
|
+
style S fill:#7c3aed,stroke:#6d28d9,color:#ede9fe
|
|
642
|
+
style R fill:#2563eb,stroke:#1d4ed8,color:#dbeafe
|
|
643
|
+
style A fill:#d97706,stroke:#b45309,color:#fef3c7
|
|
644
|
+
style O fill:#059669,stroke:#047857,color:#d1fae5
|
|
645
|
+
```
|
|
646
|
+
|
|
647
|
+
### Module Reference
|
|
648
|
+
|
|
649
|
+
| Component | Module | Description |
|
|
650
|
+
|---|---|---|
|
|
651
|
+
| **Backend** | `backend.py` | `BackendProtocol` implementation for Deep Agents |
|
|
652
|
+
| **Graph Store** | `ladybug_store.py` | LadybugDB adapter with FTS indexing and scoped queries |
|
|
653
|
+
| **Recall Engine** | `recall.py` | Seed search → expansion → budget enforcement → markdown output |
|
|
654
|
+
| **Tools** | `tools.py` | LangChain tools with error boundaries |
|
|
655
|
+
| **Renderers** | `renderers.py` | Graph data → markdown view projections |
|
|
656
|
+
| **Paths** | `paths.py` | Virtual path parsing and validation |
|
|
657
|
+
| **Graph Guidance** | `vgs.py` | Agent-local combined guidance and optional graph-only profiles |
|
|
658
|
+
| **Errors** | `errors.py` | `GraphMemoryError`, `GraphMemoryConfigurationError`, `GraphMemoryPathError`, `GraphMemoryValidationError` |
|
|
659
|
+
|
|
660
|
+
## Example Domain: SRE
|
|
661
|
+
|
|
662
|
+
VGS is domain-agnostic; here is one example of how a project might shape its labels and relationships:
|
|
663
|
+
|
|
664
|
+
```
|
|
665
|
+
Langfuse DEPENDS_ON Redis
|
|
666
|
+
Langfuse DEPENDS_ON Postgres
|
|
667
|
+
SRE Team OWNS Langfuse
|
|
668
|
+
Incident 123 AFFECTED Langfuse
|
|
669
|
+
Incident 123 RESOLVED_BY "Restart Ingestion Workers" Runbook
|
|
670
|
+
```
|
|
671
|
+
|
|
672
|
+
Recall query:
|
|
673
|
+
```python
|
|
674
|
+
graph_backend.recall_graph_memory("what services did incident 123 affect and what do they depend on?")
|
|
675
|
+
```
|
|
676
|
+
|
|
677
|
+
## Installation
|
|
678
|
+
|
|
679
|
+
```bash
|
|
680
|
+
pip install deepagents-graph-memory
|
|
681
|
+
# Optional test tools:
|
|
682
|
+
pip install "deepagents-graph-memory[test]"
|
|
683
|
+
```
|
|
684
|
+
|
|
685
|
+
### Full-text search setup
|
|
686
|
+
|
|
687
|
+
LadybugDB 0.20.3 requires a separately installed `fts` extension for graph search
|
|
688
|
+
and recall. A fresh `pip install` does not provide it. Satisfy the native runtime
|
|
689
|
+
[requirements](#requirements) first, then run this once during
|
|
690
|
+
development setup or your image build with network access, following the
|
|
691
|
+
[official extension installation](https://docs.ladybugdb.com/extensions/#install-an-extension):
|
|
692
|
+
|
|
693
|
+
```python
|
|
694
|
+
import ladybug
|
|
695
|
+
|
|
696
|
+
with ladybug.Database(":memory:", buffer_pool_size=64 * 1024 * 1024) as database:
|
|
697
|
+
with ladybug.Connection(database) as connection:
|
|
698
|
+
connection.execute("INSTALL fts;").close()
|
|
699
|
+
connection.execute("LOAD fts;").close()
|
|
700
|
+
```
|
|
701
|
+
|
|
702
|
+
Provision for the same LadybugDB version, OS, architecture, and runtime user.
|
|
703
|
+
Keep the installed extension cache available in the runtime image or volume;
|
|
704
|
+
building as a different user does not make that user's cache available to your
|
|
705
|
+
application. After provisioning, runtime search loads the local extension.
|
|
706
|
+
The adapter does not download extensions or fall back to another search method;
|
|
707
|
+
a missing extension raises a configuration error.
|
|
708
|
+
|
|
709
|
+
### Requirements
|
|
710
|
+
|
|
711
|
+
- Python 3.11–3.14 (`>=3.11,<3.15`)
|
|
712
|
+
- Deep Agents 0.6.10 or later (`>=0.6.10`)
|
|
713
|
+
- LadybugDB via `ladybug==0.20.3`
|
|
714
|
+
- An OpenSSL 3 runtime available to LadybugDB's native library; `pip` does not install it.
|
|
715
|
+
|
|
716
|
+
Fresh installations can resolve the newest Deep Agents release; applications can
|
|
717
|
+
also lock an older supported version. CI tests the latest release across the
|
|
718
|
+
platform matrix and runs separate compatibility checks with 0.6.10, 0.6.12, and
|
|
719
|
+
0.7.1. The current tested latest release is 0.7.15. Future releases still need
|
|
720
|
+
those checks to pass; an open dependency range is not a compatibility guarantee.
|
|
721
|
+
Versions before 0.6.10 are outside the supported range; the former 0.5.2 minimum
|
|
722
|
+
lacks the harness-profile API this package uses.
|
|
723
|
+
|
|
724
|
+
Use your platform's maintained OpenSSL 3 runtime. On Windows, install the matching
|
|
725
|
+
architecture from a maintained distribution such as
|
|
726
|
+
[Shining Light Productions](https://slproweb.com/products/Win32OpenSSL.html).
|
|
727
|
+
The native library needs `libssl-3-x64.dll` and `libcrypto-3-x64.dll` on x64;
|
|
728
|
+
select the installer's option to copy DLLs to the Windows system directory.
|
|
729
|
+
If your application keeps them elsewhere, register that directory with
|
|
730
|
+
[`os.add_dll_directory`](https://docs.python.org/3/library/os.html#os.add_dll_directory)
|
|
731
|
+
before importing Ladybug and keep the returned handle alive; each worker process
|
|
732
|
+
needs the same setup. PATH alone and importing Python's `ssl` module do not satisfy
|
|
733
|
+
this requirement. See [Ladybug's Windows dependency guidance](https://github.com/LadybugDB/ladybug/issues/775).
|
|
734
|
+
|
|
735
|
+
The exact pin excludes the Windows FTS ABI regression in 0.20.4 reported in
|
|
736
|
+
[upstream issue #971](https://github.com/LadybugDB/ladybug/issues/971).
|
|
737
|
+
|
|
738
|
+
The [Ladybug 0.20.3 wheels](https://pypi.org/project/ladybug/0.20.3/#files)
|
|
739
|
+
include macOS 15+ (Intel and Apple Silicon), Linux, and Windows builds for
|
|
740
|
+
x86-64 and ARM64. Check the available wheel for your Python version, architecture,
|
|
741
|
+
and OS; wheel availability does not establish that this package passed tests on
|
|
742
|
+
every combination.
|
|
743
|
+
|
|
744
|
+
## Development
|
|
745
|
+
|
|
746
|
+
```bash
|
|
747
|
+
git clone https://github.com/TahaK29/deepagents-graph-memory.git
|
|
748
|
+
cd deepagents-graph-memory
|
|
749
|
+
pip install -e ".[test]"
|
|
750
|
+
python3 -m pytest -q # Run all tests
|
|
751
|
+
python3 -m ruff check . # Lint
|
|
752
|
+
```
|
|
753
|
+
|
|
754
|
+
## Design
|
|
755
|
+
|
|
756
|
+
`GraphMemoryBackend.create()` creates a LadybugDB in-memory graph via `ladybug.Database(":memory:")`. Supply `path=...` to create or reopen a disk database. Persistence depends on retaining that filesystem across restarts; each writable database has one owning process. Both modes use the same graph tools and namespace rules.
|
|
757
|
+
|
|
758
|
+
Recall uses full-text search to find seed nodes, relationship-label search for relationship-oriented questions, and bounded graph traversal to recover connected context. Vector search and graph algorithms are intentionally not part of the default recall path.
|
|
759
|
+
|
|
760
|
+
Raw Cypher is not exposed as an agent-facing read or write path. Generated graph views are read-only projections.
|
|
761
|
+
|
|
762
|
+
For the full design rationale, see [DESIGN.md](https://github.com/TahaK29/deepagents-graph-memory/blob/main/DESIGN.md).
|
|
763
|
+
|
|
764
|
+
## License
|
|
765
|
+
|
|
766
|
+
MIT
|
|
767
|
+
|
|
768
|
+
---
|
|
769
|
+
|
|
770
|
+
**deepagents-graph-memory** is experimental. [GitHub Issues](https://github.com/TahaK29/deepagents-graph-memory/issues)
|