cortex-vault 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cortex_vault-0.1.0/PKG-INFO +231 -0
- cortex_vault-0.1.0/README.md +203 -0
- cortex_vault-0.1.0/pyproject.toml +77 -0
- cortex_vault-0.1.0/setup.cfg +4 -0
- cortex_vault-0.1.0/setup.py +5 -0
- cortex_vault-0.1.0/src/cortex_memory/__init__.py +33 -0
- cortex_vault-0.1.0/src/cortex_memory/__main__.py +65 -0
- cortex_vault-0.1.0/src/cortex_memory/agent.py +225 -0
- cortex_vault-0.1.0/src/cortex_memory/config.py +112 -0
- cortex_vault-0.1.0/src/cortex_memory/graph/__init__.py +4 -0
- cortex_vault-0.1.0/src/cortex_memory/graph/memory_graph.py +87 -0
- cortex_vault-0.1.0/src/cortex_memory/ingestion/__init__.py +14 -0
- cortex_vault-0.1.0/src/cortex_memory/ingestion/ingestor.py +226 -0
- cortex_vault-0.1.0/src/cortex_memory/llm/__init__.py +4 -0
- cortex_vault-0.1.0/src/cortex_memory/llm/chat.py +84 -0
- cortex_vault-0.1.0/src/cortex_memory/prompts/__init__.py +4 -0
- cortex_vault-0.1.0/src/cortex_memory/prompts/templates.py +59 -0
- cortex_vault-0.1.0/src/cortex_memory/retrieval/__init__.py +4 -0
- cortex_vault-0.1.0/src/cortex_memory/retrieval/retriever.py +196 -0
- cortex_vault-0.1.0/src/cortex_vault.egg-info/PKG-INFO +231 -0
- cortex_vault-0.1.0/src/cortex_vault.egg-info/SOURCES.txt +25 -0
- cortex_vault-0.1.0/src/cortex_vault.egg-info/dependency_links.txt +1 -0
- cortex_vault-0.1.0/src/cortex_vault.egg-info/entry_points.txt +2 -0
- cortex_vault-0.1.0/src/cortex_vault.egg-info/requires.txt +11 -0
- cortex_vault-0.1.0/src/cortex_vault.egg-info/top_level.txt +1 -0
- cortex_vault-0.1.0/tests/test_ingestor.py +82 -0
- cortex_vault-0.1.0/tests/test_retriever.py +107 -0
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cortex-vault
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: LLM-powered long-term memory layer backed by a Neo4j knowledge graph.
|
|
5
|
+
Author: tdevansh
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Repository, https://github.com/tdevansh/cortex-vault
|
|
8
|
+
Keywords: llm,memory,neo4j,langchain,knowledge-graph,retrieval-augmented-generation,agent
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
16
|
+
Requires-Python: >=3.10
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
Requires-Dist: langchain-groq>=0.2
|
|
19
|
+
Requires-Dist: langchain>=0.3
|
|
20
|
+
Requires-Dist: sentence-transformers>=3.0
|
|
21
|
+
Requires-Dist: neo4j>=5.0
|
|
22
|
+
Requires-Dist: python-dotenv>=1.0
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
25
|
+
Requires-Dist: pytest-mock>=3.14; extra == "dev"
|
|
26
|
+
Requires-Dist: ruff>=0.4; extra == "dev"
|
|
27
|
+
Requires-Dist: mypy>=1.10; extra == "dev"
|
|
28
|
+
|
|
29
|
+
# cortex-memory
|
|
30
|
+
|
|
31
|
+
> An LLM-powered long-term memory layer backed by a **Neo4j knowledge graph** — packaged as a reusable Python library you can drop into any project.
|
|
32
|
+
|
|
33
|
+
[](https://www.python.org/)
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## What it does
|
|
38
|
+
|
|
39
|
+
1. **Chat** — queries the LLM with retrieved memory context injected automatically.
|
|
40
|
+
2. **Retrieve** — embeds your query with `all-MiniLM-L6-v2`, runs a Neo4j vector-index search, then re-ranks with:
|
|
41
|
+
- `importance_weight` (very_high → low)
|
|
42
|
+
- `stability_weight` (permanent → transient)
|
|
43
|
+
- `tag_matches` between the query and stored memory tags
|
|
44
|
+
3. **Ingest** — asks the LLM to decide if an input is worth storing. If so, it extracts `type`, `label`, `content`, `stability`, `importance`, and `related_entities`, chunks the text, embeds each chunk, and upserts it into Neo4j as a `Memory` node linked to `Entity` nodes via `RELATED_TO`.
|
|
45
|
+
4. **Reinforce** — memories recalled during chat have their `last_accessed` refreshed; `transient` memories are promoted to `stable`.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Project structure
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
cortex-ai-memory/
|
|
53
|
+
├── src/
|
|
54
|
+
│ └── cortex_memory/ ← installable package
|
|
55
|
+
│ ├── __init__.py ← public API
|
|
56
|
+
│ ├── __main__.py ← CLI entrypoint
|
|
57
|
+
│ ├── agent.py ← CortexMemory orchestrator
|
|
58
|
+
│ ├── config.py ← CortexConfig dataclass
|
|
59
|
+
│ ├── graph/
|
|
60
|
+
│ │ └── memory_graph.py ← Neo4j upsert (MemoryGraph)
|
|
61
|
+
│ ├── retrieval/
|
|
62
|
+
│ │ └── retriever.py ← WeightedMemoryRetriever
|
|
63
|
+
│ ├── ingestion/
|
|
64
|
+
│ │ └── ingestor.py ← ingestion pipeline
|
|
65
|
+
│ ├── llm/
|
|
66
|
+
│ │ └── chat.py ← LLM client + chat_with_assistant
|
|
67
|
+
│ └── prompts/
|
|
68
|
+
│ └── templates.py ← all prompt strings
|
|
69
|
+
├── examples/
|
|
70
|
+
│ ├── basic_chat.py
|
|
71
|
+
│ └── ingest_document.py
|
|
72
|
+
├── tests/
|
|
73
|
+
│ ├── test_retriever.py
|
|
74
|
+
│ └── test_ingestor.py
|
|
75
|
+
├── setups/
|
|
76
|
+
│ └── neo4j/ ← Docker / docker-compose setup
|
|
77
|
+
├── pyproject.toml
|
|
78
|
+
├── requirements-dev.txt
|
|
79
|
+
└── .env.example
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Prerequisites
|
|
85
|
+
|
|
86
|
+
- Python 3.10+
|
|
87
|
+
- Docker (for Neo4j 5.13+)
|
|
88
|
+
- A [Groq API key](https://console.groq.com/keys)
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## Installation
|
|
93
|
+
|
|
94
|
+
### As a dependency in another project
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
pip install git+https://github.com/your-org/cortex-ai-memory.git
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### For local development
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
git clone https://github.com/your-org/cortex-ai-memory.git
|
|
104
|
+
cd cortex-ai-memory
|
|
105
|
+
pip install -e ".[dev]"
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## Configuration
|
|
111
|
+
|
|
112
|
+
Copy `.env.example` to `.env` and fill in your values:
|
|
113
|
+
|
|
114
|
+
```env
|
|
115
|
+
NEO4J_URI=bolt://localhost:7687
|
|
116
|
+
NEO4J_USERNAME=neo4j
|
|
117
|
+
NEO4J_PASSWORD=your_neo4j_password_here
|
|
118
|
+
GROQ_API_KEY=your_groq_api_key_here
|
|
119
|
+
|
|
120
|
+
# Optional overrides
|
|
121
|
+
# CORTEX_MODEL=openai/gpt-oss-20b
|
|
122
|
+
# CORTEX_EMBEDDER=all-MiniLM-L6-v2
|
|
123
|
+
# CORTEX_TOP_K=5
|
|
124
|
+
# CORTEX_SCORE_THRESHOLD=0.65
|
|
125
|
+
# CORTEX_CHUNK_MAX_CHARS=400
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## Usage
|
|
131
|
+
|
|
132
|
+
### Python API
|
|
133
|
+
|
|
134
|
+
```python
|
|
135
|
+
from cortex_memory import CortexMemory
|
|
136
|
+
|
|
137
|
+
# Context manager — closes Neo4j connections automatically
|
|
138
|
+
with CortexMemory.from_env() as memory:
|
|
139
|
+
# Retrieve + chat + ingest + reinforce — all in one call
|
|
140
|
+
response = memory.chat("What do I know about Japan?")
|
|
141
|
+
print(response)
|
|
142
|
+
|
|
143
|
+
# Ingest standalone text
|
|
144
|
+
memory.ingest("User booked flights to Tokyo for March.", source="upload")
|
|
145
|
+
|
|
146
|
+
# Raw retrieval without chat
|
|
147
|
+
results = memory.retrieve("Japan travel plans", top_k=5)
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### CLI
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
# Chat
|
|
154
|
+
cortex-memory chat "What do I know about Japan?"
|
|
155
|
+
|
|
156
|
+
# Ingest
|
|
157
|
+
cortex-memory ingest "User loves hiking in the Alps and dislikes crowded cities."
|
|
158
|
+
|
|
159
|
+
# Override top-k and disable auto-ingestion
|
|
160
|
+
cortex-memory chat "Remind me about my diet goals." --top-k 3 --no-ingest
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## Running Neo4j with Docker
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
docker run -d \
|
|
169
|
+
--name memory-graph-neo4j \
|
|
170
|
+
-p 7474:7474 \
|
|
171
|
+
-p 7687:7687 \
|
|
172
|
+
-e NEO4J_AUTH=neo4j/your_neo4j_password_here \
|
|
173
|
+
-v neo4j_data:/data \
|
|
174
|
+
neo4j:5.15
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Or using **docker-compose** (see `setups/neo4j/`):
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
docker-compose -f setups/neo4j/docker-compose.yml up -d
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Verify at **http://localhost:7474**.
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## Running tests
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
pytest tests/
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## Memory schema
|
|
196
|
+
|
|
197
|
+
| Field | Description |
|
|
198
|
+
|---|---|
|
|
199
|
+
| `id` | UUID |
|
|
200
|
+
| `type` | `context`, `event`, `fact`, … |
|
|
201
|
+
| `label` | Short title |
|
|
202
|
+
| `content` | Chunked text |
|
|
203
|
+
| `source` | `upload`, `assistant_chat`, `cli`, … |
|
|
204
|
+
| `created_at` / `last_accessed` | ISO timestamps |
|
|
205
|
+
| `stability` | `transient` → `stable` → `permanent` |
|
|
206
|
+
| `status` | `active` |
|
|
207
|
+
| `tags` | Keyword list |
|
|
208
|
+
| `embedding` | 384-dim vector (`all-MiniLM-L6-v2`) |
|
|
209
|
+
| `importance` | `very_high`, `high`, `medium`, `low` |
|
|
210
|
+
|
|
211
|
+
Related entities are linked as `(:Memory)-[:RELATED_TO]->(:Entity)`.
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## Using in another project
|
|
216
|
+
|
|
217
|
+
```python
|
|
218
|
+
# my_project/memory_layer.py
|
|
219
|
+
from cortex_memory import CortexMemory, CortexConfig
|
|
220
|
+
|
|
221
|
+
# Explicit config — no .env needed
|
|
222
|
+
config = CortexConfig(
|
|
223
|
+
neo4j_uri="bolt://localhost:7687",
|
|
224
|
+
neo4j_username="neo4j",
|
|
225
|
+
neo4j_password="secret",
|
|
226
|
+
groq_api_key="gsk_...",
|
|
227
|
+
top_k=10,
|
|
228
|
+
score_threshold=0.70,
|
|
229
|
+
)
|
|
230
|
+
memory = CortexMemory(config)
|
|
231
|
+
```
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
# cortex-memory
|
|
2
|
+
|
|
3
|
+
> An LLM-powered long-term memory layer backed by a **Neo4j knowledge graph** — packaged as a reusable Python library you can drop into any project.
|
|
4
|
+
|
|
5
|
+
[](https://www.python.org/)
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## What it does
|
|
10
|
+
|
|
11
|
+
1. **Chat** — queries the LLM with retrieved memory context injected automatically.
|
|
12
|
+
2. **Retrieve** — embeds your query with `all-MiniLM-L6-v2`, runs a Neo4j vector-index search, then re-ranks with:
|
|
13
|
+
- `importance_weight` (very_high → low)
|
|
14
|
+
- `stability_weight` (permanent → transient)
|
|
15
|
+
- `tag_matches` between the query and stored memory tags
|
|
16
|
+
3. **Ingest** — asks the LLM to decide if an input is worth storing. If so, it extracts `type`, `label`, `content`, `stability`, `importance`, and `related_entities`, chunks the text, embeds each chunk, and upserts it into Neo4j as a `Memory` node linked to `Entity` nodes via `RELATED_TO`.
|
|
17
|
+
4. **Reinforce** — memories recalled during chat have their `last_accessed` refreshed; `transient` memories are promoted to `stable`.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Project structure
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
cortex-ai-memory/
|
|
25
|
+
├── src/
|
|
26
|
+
│ └── cortex_memory/ ← installable package
|
|
27
|
+
│ ├── __init__.py ← public API
|
|
28
|
+
│ ├── __main__.py ← CLI entrypoint
|
|
29
|
+
│ ├── agent.py ← CortexMemory orchestrator
|
|
30
|
+
│ ├── config.py ← CortexConfig dataclass
|
|
31
|
+
│ ├── graph/
|
|
32
|
+
│ │ └── memory_graph.py ← Neo4j upsert (MemoryGraph)
|
|
33
|
+
│ ├── retrieval/
|
|
34
|
+
│ │ └── retriever.py ← WeightedMemoryRetriever
|
|
35
|
+
│ ├── ingestion/
|
|
36
|
+
│ │ └── ingestor.py ← ingestion pipeline
|
|
37
|
+
│ ├── llm/
|
|
38
|
+
│ │ └── chat.py ← LLM client + chat_with_assistant
|
|
39
|
+
│ └── prompts/
|
|
40
|
+
│ └── templates.py ← all prompt strings
|
|
41
|
+
├── examples/
|
|
42
|
+
│ ├── basic_chat.py
|
|
43
|
+
│ └── ingest_document.py
|
|
44
|
+
├── tests/
|
|
45
|
+
│ ├── test_retriever.py
|
|
46
|
+
│ └── test_ingestor.py
|
|
47
|
+
├── setups/
|
|
48
|
+
│ └── neo4j/ ← Docker / docker-compose setup
|
|
49
|
+
├── pyproject.toml
|
|
50
|
+
├── requirements-dev.txt
|
|
51
|
+
└── .env.example
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Prerequisites
|
|
57
|
+
|
|
58
|
+
- Python 3.10+
|
|
59
|
+
- Docker (for Neo4j 5.13+)
|
|
60
|
+
- A [Groq API key](https://console.groq.com/keys)
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Installation
|
|
65
|
+
|
|
66
|
+
### As a dependency in another project
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
pip install git+https://github.com/your-org/cortex-ai-memory.git
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### For local development
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
git clone https://github.com/your-org/cortex-ai-memory.git
|
|
76
|
+
cd cortex-ai-memory
|
|
77
|
+
pip install -e ".[dev]"
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Configuration
|
|
83
|
+
|
|
84
|
+
Copy `.env.example` to `.env` and fill in your values:
|
|
85
|
+
|
|
86
|
+
```env
|
|
87
|
+
NEO4J_URI=bolt://localhost:7687
|
|
88
|
+
NEO4J_USERNAME=neo4j
|
|
89
|
+
NEO4J_PASSWORD=your_neo4j_password_here
|
|
90
|
+
GROQ_API_KEY=your_groq_api_key_here
|
|
91
|
+
|
|
92
|
+
# Optional overrides
|
|
93
|
+
# CORTEX_MODEL=openai/gpt-oss-20b
|
|
94
|
+
# CORTEX_EMBEDDER=all-MiniLM-L6-v2
|
|
95
|
+
# CORTEX_TOP_K=5
|
|
96
|
+
# CORTEX_SCORE_THRESHOLD=0.65
|
|
97
|
+
# CORTEX_CHUNK_MAX_CHARS=400
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Usage
|
|
103
|
+
|
|
104
|
+
### Python API
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
from cortex_memory import CortexMemory
|
|
108
|
+
|
|
109
|
+
# Context manager — closes Neo4j connections automatically
|
|
110
|
+
with CortexMemory.from_env() as memory:
|
|
111
|
+
# Retrieve + chat + ingest + reinforce — all in one call
|
|
112
|
+
response = memory.chat("What do I know about Japan?")
|
|
113
|
+
print(response)
|
|
114
|
+
|
|
115
|
+
# Ingest standalone text
|
|
116
|
+
memory.ingest("User booked flights to Tokyo for March.", source="upload")
|
|
117
|
+
|
|
118
|
+
# Raw retrieval without chat
|
|
119
|
+
results = memory.retrieve("Japan travel plans", top_k=5)
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### CLI
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
# Chat
|
|
126
|
+
cortex-memory chat "What do I know about Japan?"
|
|
127
|
+
|
|
128
|
+
# Ingest
|
|
129
|
+
cortex-memory ingest "User loves hiking in the Alps and dislikes crowded cities."
|
|
130
|
+
|
|
131
|
+
# Override top-k and disable auto-ingestion
|
|
132
|
+
cortex-memory chat "Remind me about my diet goals." --top-k 3 --no-ingest
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## Running Neo4j with Docker
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
docker run -d \
|
|
141
|
+
--name memory-graph-neo4j \
|
|
142
|
+
-p 7474:7474 \
|
|
143
|
+
-p 7687:7687 \
|
|
144
|
+
-e NEO4J_AUTH=neo4j/your_neo4j_password_here \
|
|
145
|
+
-v neo4j_data:/data \
|
|
146
|
+
neo4j:5.15
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Or using **docker-compose** (see `setups/neo4j/`):
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
docker-compose -f setups/neo4j/docker-compose.yml up -d
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Verify at **http://localhost:7474**.
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## Running tests
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
pytest tests/
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## Memory schema
|
|
168
|
+
|
|
169
|
+
| Field | Description |
|
|
170
|
+
|---|---|
|
|
171
|
+
| `id` | UUID |
|
|
172
|
+
| `type` | `context`, `event`, `fact`, … |
|
|
173
|
+
| `label` | Short title |
|
|
174
|
+
| `content` | Chunked text |
|
|
175
|
+
| `source` | `upload`, `assistant_chat`, `cli`, … |
|
|
176
|
+
| `created_at` / `last_accessed` | ISO timestamps |
|
|
177
|
+
| `stability` | `transient` → `stable` → `permanent` |
|
|
178
|
+
| `status` | `active` |
|
|
179
|
+
| `tags` | Keyword list |
|
|
180
|
+
| `embedding` | 384-dim vector (`all-MiniLM-L6-v2`) |
|
|
181
|
+
| `importance` | `very_high`, `high`, `medium`, `low` |
|
|
182
|
+
|
|
183
|
+
Related entities are linked as `(:Memory)-[:RELATED_TO]->(:Entity)`.
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## Using in another project
|
|
188
|
+
|
|
189
|
+
```python
|
|
190
|
+
# my_project/memory_layer.py
|
|
191
|
+
from cortex_memory import CortexMemory, CortexConfig
|
|
192
|
+
|
|
193
|
+
# Explicit config — no .env needed
|
|
194
|
+
config = CortexConfig(
|
|
195
|
+
neo4j_uri="bolt://localhost:7687",
|
|
196
|
+
neo4j_username="neo4j",
|
|
197
|
+
neo4j_password="secret",
|
|
198
|
+
groq_api_key="gsk_...",
|
|
199
|
+
top_k=10,
|
|
200
|
+
score_threshold=0.70,
|
|
201
|
+
)
|
|
202
|
+
memory = CortexMemory(config)
|
|
203
|
+
```
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "cortex-vault"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "LLM-powered long-term memory layer backed by a Neo4j knowledge graph."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
authors = [{ name = "tdevansh" }]
|
|
13
|
+
|
|
14
|
+
keywords = [
|
|
15
|
+
"llm", "memory", "neo4j", "langchain", "knowledge-graph",
|
|
16
|
+
"retrieval-augmented-generation", "agent",
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
classifiers = [
|
|
20
|
+
"Development Status :: 3 - Alpha",
|
|
21
|
+
"Intended Audience :: Developers",
|
|
22
|
+
"Programming Language :: Python :: 3",
|
|
23
|
+
"Programming Language :: Python :: 3.10",
|
|
24
|
+
"Programming Language :: Python :: 3.11",
|
|
25
|
+
"Programming Language :: Python :: 3.12",
|
|
26
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
dependencies = [
|
|
30
|
+
"langchain-groq>=0.2",
|
|
31
|
+
"langchain>=0.3",
|
|
32
|
+
"sentence-transformers>=3.0",
|
|
33
|
+
"neo4j>=5.0",
|
|
34
|
+
"python-dotenv>=1.0",
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
[project.optional-dependencies]
|
|
38
|
+
dev = [
|
|
39
|
+
"pytest>=8.0",
|
|
40
|
+
"pytest-mock>=3.14",
|
|
41
|
+
"ruff>=0.4",
|
|
42
|
+
"mypy>=1.10",
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
[project.scripts]
|
|
46
|
+
cortex-vault = "cortex_memory.__main__:main"
|
|
47
|
+
|
|
48
|
+
[project.urls]
|
|
49
|
+
Repository = "https://github.com/tdevansh/cortex-vault"
|
|
50
|
+
|
|
51
|
+
[tool.setuptools.packages.find]
|
|
52
|
+
where = ["src"]
|
|
53
|
+
|
|
54
|
+
# ---------------------------------------------------------------------------
|
|
55
|
+
# Ruff (linting + formatting)
|
|
56
|
+
# ---------------------------------------------------------------------------
|
|
57
|
+
[tool.ruff]
|
|
58
|
+
line-length = 100
|
|
59
|
+
target-version = "py310"
|
|
60
|
+
|
|
61
|
+
[tool.ruff.lint]
|
|
62
|
+
select = ["E", "F", "I", "UP", "B"]
|
|
63
|
+
ignore = ["E501"]
|
|
64
|
+
|
|
65
|
+
# ---------------------------------------------------------------------------
|
|
66
|
+
# Mypy (type-checking)
|
|
67
|
+
# ---------------------------------------------------------------------------
|
|
68
|
+
[tool.mypy]
|
|
69
|
+
python_version = "3.10"
|
|
70
|
+
warn_return_any = true
|
|
71
|
+
ignore_missing_imports = true
|
|
72
|
+
|
|
73
|
+
# ---------------------------------------------------------------------------
|
|
74
|
+
# Pytest
|
|
75
|
+
# ---------------------------------------------------------------------------
|
|
76
|
+
[tool.pytest.ini_options]
|
|
77
|
+
testpaths = ["tests"]
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""
|
|
2
|
+
cortex_memory
|
|
3
|
+
~~~~~~~~~~~~~
|
|
4
|
+
An LLM-powered memory layer backed by a Neo4j knowledge graph.
|
|
5
|
+
|
|
6
|
+
Public API::
|
|
7
|
+
|
|
8
|
+
from cortex_memory import CortexMemory, CortexConfig
|
|
9
|
+
|
|
10
|
+
# Quickstart — reads NEO4J_* and GROQ_API_KEY from .env
|
|
11
|
+
memory = CortexMemory.from_env()
|
|
12
|
+
response = memory.chat("What do I know about Japan?")
|
|
13
|
+
memory.ingest("User is planning a trip to Kyoto in October.")
|
|
14
|
+
memory.close()
|
|
15
|
+
|
|
16
|
+
Low-level access::
|
|
17
|
+
|
|
18
|
+
from cortex_memory import WeightedMemoryRetriever, ingest_text_to_memory_graph
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from cortex_memory.agent import CortexMemory
|
|
22
|
+
from cortex_memory.config import CortexConfig
|
|
23
|
+
from cortex_memory.ingestion.ingestor import ingest_text_to_memory_graph
|
|
24
|
+
from cortex_memory.retrieval.retriever import WeightedMemoryRetriever
|
|
25
|
+
|
|
26
|
+
__all__ = [
|
|
27
|
+
"CortexMemory",
|
|
28
|
+
"CortexConfig",
|
|
29
|
+
"ingest_text_to_memory_graph",
|
|
30
|
+
"WeightedMemoryRetriever",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
__version__ = "0.1.0"
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""
|
|
2
|
+
cortex_memory.__main__
|
|
3
|
+
~~~~~~~~~~~~~~~~~~~~~~~
|
|
4
|
+
CLI entrypoint — invoked via ``python -m cortex_memory`` or the
|
|
5
|
+
``cortex-memory`` script installed by pyproject.toml.
|
|
6
|
+
|
|
7
|
+
Usage
|
|
8
|
+
-----
|
|
9
|
+
cortex-memory chat "What do I know about Japan?"
|
|
10
|
+
cortex-memory ingest "User loves hiking in the Alps."
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import argparse
|
|
16
|
+
import sys
|
|
17
|
+
|
|
18
|
+
from cortex_memory import CortexMemory
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def main() -> None:
|
|
22
|
+
parser = argparse.ArgumentParser(
|
|
23
|
+
prog="cortex-vault",
|
|
24
|
+
description="Cortex Vault CLI — interact with your Neo4j memory graph.",
|
|
25
|
+
)
|
|
26
|
+
sub = parser.add_subparsers(dest="command", required=True)
|
|
27
|
+
|
|
28
|
+
# --- chat ---
|
|
29
|
+
chat_parser = sub.add_parser("chat", help="Query the memory agent.")
|
|
30
|
+
chat_parser.add_argument("query", help="The query to send to the assistant.")
|
|
31
|
+
chat_parser.add_argument(
|
|
32
|
+
"--top-k", type=int, default=None, help="Number of memories to retrieve."
|
|
33
|
+
)
|
|
34
|
+
chat_parser.add_argument(
|
|
35
|
+
"--no-ingest", action="store_true", help="Disable auto-ingestion of the query."
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
# --- ingest ---
|
|
39
|
+
ingest_parser = sub.add_parser("ingest", help="Ingest text into memory.")
|
|
40
|
+
ingest_parser.add_argument("text", help="Text to evaluate and store.")
|
|
41
|
+
ingest_parser.add_argument(
|
|
42
|
+
"--source", default="cli", help="Source tag for the memory (default: 'cli')."
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
args = parser.parse_args()
|
|
46
|
+
|
|
47
|
+
with CortexMemory.from_env() as memory:
|
|
48
|
+
if args.command == "chat":
|
|
49
|
+
response = memory.chat(
|
|
50
|
+
args.query,
|
|
51
|
+
top_k=args.top_k,
|
|
52
|
+
auto_ingest=not args.no_ingest,
|
|
53
|
+
)
|
|
54
|
+
print(f"\n🤖 Assistant:\n{response}\n")
|
|
55
|
+
|
|
56
|
+
elif args.command == "ingest":
|
|
57
|
+
ingested = memory.ingest(args.text, source=args.source)
|
|
58
|
+
if ingested:
|
|
59
|
+
print("✅ Memory ingested successfully.")
|
|
60
|
+
else:
|
|
61
|
+
print("❌ No ingestion was performed.")
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
if __name__ == "__main__":
|
|
65
|
+
main()
|