Metadata-Version: 2.4
Name: langgraph-velesdb
Version: 5.1.0
Summary: LangGraph memory tools for VelesDB: drop the why() knowledge-graph memory wedge into any LangGraph agent.
Author-email: VelesDB Team <contact@wiscale.fr>
License: MIT
Project-URL: Homepage, https://velesdb.com
Project-URL: Repository, https://github.com/cyberlife-coder/VelesDB
Keywords: langgraph,langchain,velesdb,agent-memory,knowledge-graph,local-first,why,llm
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: langchain-core<2.0.0,>=0.3.0
Requires-Dist: velesdb>=5.0.0
Provides-Extra: dev
Requires-Dist: pytest<9.0,>=7.0; extra == "dev"
Requires-Dist: langgraph>=0.2.0; extra == "dev"
Dynamic: license-file

# langgraph-velesdb

Drop VelesDB's local-first agent memory — the **`why()` knowledge-graph wedge** —
into any [LangGraph](https://github.com/langchain-ai/langgraph) agent in three lines.

Most agent memory is vector recall: it finds text that *looks like* the query.
VelesDB **connects** memories with typed links, so `why()` answers with the
best-matching memory **plus the connected subgraph** — context that shares no
words with the question, which a plain vector recall is blind to. The store is on
disk, so memory persists across agent runs.

![recall() finds the booking but misses the reason; why() reaches it through typed links, across a session restart](https://raw.githubusercontent.com/cyberlife-coder/VelesDB/develop/examples/agent_memory/why_across_sessions.gif)

## Install

```bash
pip install langgraph-velesdb        # pulls langchain-core + velesdb
```

## Use

```python
from langgraph.prebuilt import create_react_agent
from langgraph_velesdb import make_memory_tools

# Offline by default (hash embedder); pass a configured MemoryService for Ollama.
agent = create_react_agent(llm, make_memory_tools("./agent_memory"))
```

`make_memory_tools` returns ten tools the agent can call:

| Tool                   | What it does |
|------------------------|--------------|
| `remember`             | store a fact (optionally with `links`, `metadata`, `ttl_seconds`), return its id |
| `recall`               | semantic (vector) recall — no metadata |
| `recall_where`         | filtered recall (metadata `[field, op, value]` triples) **with metadata attached**, e.g. the auto `_veles_date` stamp |
| `recall_fused`         | fused vector + graph recall; pass `date_field="_veles_date"` for a dated timeline |
| `relate`               | link two memories with a typed edge |
| `forget`               | delete a memory by id (`True` if it existed, `False` if it was already gone) |
| `feedback`             | reinforce or weaken a memory after using it, closing the self-improving recall loop |
| `why`                  | best-matching memory **+ its connected subgraph** (the wedge) |
| `save_working_context` | persist the current goal/constraints/decisions/pending actions under a project + session |
| `load_working_context` | resume a prior run's working context — call at the start of a session |

For a pre-configured backend (e.g. Ollama embeddings), build the service yourself
and pass it through:

```python
from velesdb import MemoryService
tools = make_memory_tools(service=MemoryService("./agent_memory"))
```

### Cross-run resumption

`save_working_context` / `load_working_context` let an agent pick up a task
across separate runs instead of restarting from scratch:

`make_memory_tools` returns a *list* of tools, so index them by name first
(the same pattern LangGraph's `ToolNode`/`create_react_agent` use internally):

```python
tools = {t.name: t for t in make_memory_tools("./agent_memory")}

tools["save_working_context"].invoke({
    "project": "veles",
    "session": "issue-1546",
    "working": {
        "goal": "ship the langgraph tool set",
        "pending_actions": ["open the PR"],
    },
})

# ... next run, same project + session:
tools["load_working_context"].invoke({"project": "veles", "session": "issue-1546"})
```

### Dated recall

Every `remember`-ed fact is auto-stamped with `_veles_date` (today, as a
`YYYYMMDD` int) unless you set that metadata key yourself. Point
`recall_fused` at it to get a chronological timeline instead of a ranked list:

```python
tools = {t.name: t for t in make_memory_tools("./agent_memory")}

tools["recall_fused"].invoke({"query": "what changed this week", "date_field": "_veles_date"})
# -> {"memories": [...], "dated_context": "...", "now": "..."}
```

## Compatibility

This package declares a floor of `velesdb>=5.0.0` — the release that
carries the `load_working_context` `{found, working, other_sessions}`
envelope this toolkit relays, plus `feedback`, `save_working_context` and
the automatic `_veles_date` metadata stamp. The floor moved from 3.12.0
with the 5.0.0 train, exactly as the changelog mandated: it could not be
raised in advance because the version that carries the envelope did not
exist yet. The call-time detection below remains as a net for an
environment that pins an older wheel by hand, e.g.:

```json
{"error": "feedback requires velesdb > 3.12.0 — upgrade with `pip install -U velesdb`"}
```

so a single unsupported call surfaces to the agent as a normal tool result it
can react to, instead of an uncaught `AttributeError` killing the whole graph
run. `recall_where`/`recall_fused` still work, but their `metadata` stays
empty for auto-dating until you upgrade. `forget` works on 3.12.0 too, but
returns `None` instead of a `True`/`False` existed-or-not signal. Upgrading
past 3.12.0 (`pip install -U velesdb`) removes all of these degradations.

**A second failure mode, which no version floor can express.**
`load_working_context` returns `{found, working, other_sessions}` — the
envelope this toolkit's docstring describes to the model. Wheels published
*before* that change have the method and return the **bare** working context
(or `None`), so the presence check above passes and the description becomes
false: the model reads `found` as `None`, treats a resumable session as a
fresh start, and restarts on top of live work. The tool therefore inspects
what it got back and reports the drift as a normal error payload:

```json
{"error": "load_working_context returned the pre-envelope shape: the installed velesdb has the method but predates the {found, working, other_sessions} envelope this package documents. ..."}
```

Presence is not shape, and `hasattr` only ever proved presence.

`list_working_contexts` (browse saved sessions for a project) is not exposed
here: it exists on the WASM and MCP surfaces but not yet on the `velesdb`
Python binding (`MemoryService`), and this package only ever calls the
binding — no memory logic is reimplemented in this MIT-licensed integration.
It will be added once the Python binding grows the method.

## License

MIT — see [LICENSE](./LICENSE). Wraps [`velesdb`](https://pypi.org/project/velesdb/),
which is under the VelesDB Core License 1.0.
