attractor-engine 0.0.1__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.
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: attractor-engine
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: A brain-inspired memory engine — contextual storage and associative retrieval
|
|
5
|
+
Project-URL: Homepage, https://github.com/aag1091-alt/attractor
|
|
6
|
+
Project-URL: Repository, https://github.com/aag1091-alt/attractor
|
|
7
|
+
Author: aag1091-alt
|
|
8
|
+
License: MIT
|
|
9
|
+
Keywords: agents,ai,associative,attractor,contextual,database,hopfield,memory
|
|
10
|
+
Classifier: Development Status :: 1 - Planning
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Topic :: Database
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
19
|
+
Requires-Python: >=3.10
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
|
|
22
|
+
# attractor
|
|
23
|
+
|
|
24
|
+
A brain-inspired memory engine — contextual storage and associative retrieval.
|
|
25
|
+
|
|
26
|
+
**This package is under active development. Not yet functional.**
|
|
27
|
+
|
|
28
|
+
Attractor is a standalone memory service purpose-built for storing and retrieving contextual memory. It is designed to work like a brain — not like a key-value store or a vector database.
|
|
29
|
+
|
|
30
|
+
Named after the concept of **attractors** in dynamical systems: stored memories are energy minima, retrieval is gradient descent to the nearest basin. Give it a partial or noisy cue and it converges to the full memory.
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
attractor start # start the service
|
|
34
|
+
attractor connect # verify connection
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Status
|
|
38
|
+
|
|
39
|
+
Early development. Watch this repo for updates.
|
|
40
|
+
|
|
41
|
+
## Source
|
|
42
|
+
|
|
43
|
+
[github.com/aag1091-alt/attractor](https://github.com/aag1091-alt/attractor)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# attractor
|
|
2
|
+
|
|
3
|
+
A brain-inspired memory engine — contextual storage and associative retrieval.
|
|
4
|
+
|
|
5
|
+
**This package is under active development. Not yet functional.**
|
|
6
|
+
|
|
7
|
+
Attractor is a standalone memory service purpose-built for storing and retrieving contextual memory. It is designed to work like a brain — not like a key-value store or a vector database.
|
|
8
|
+
|
|
9
|
+
Named after the concept of **attractors** in dynamical systems: stored memories are energy minima, retrieval is gradient descent to the nearest basin. Give it a partial or noisy cue and it converges to the full memory.
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
attractor start # start the service
|
|
13
|
+
attractor connect # verify connection
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Status
|
|
17
|
+
|
|
18
|
+
Early development. Watch this repo for updates.
|
|
19
|
+
|
|
20
|
+
## Source
|
|
21
|
+
|
|
22
|
+
[github.com/aag1091-alt/attractor](https://github.com/aag1091-alt/attractor)
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
# Attractor — Phase 1 Service Structure
|
|
2
|
+
|
|
3
|
+
## Directory Layout
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
attractor/
|
|
7
|
+
├── attractor/ # core package
|
|
8
|
+
│ ├── __init__.py
|
|
9
|
+
│ ├── main.py # FastAPI app + server entrypoint
|
|
10
|
+
│ ├── config.py # service config (port, db url, model name)
|
|
11
|
+
│ │
|
|
12
|
+
│ ├── models/ # data models (Pydantic)
|
|
13
|
+
│ │ ├── __init__.py
|
|
14
|
+
│ │ ├── memory.py # Memory, ContextFrame, MemoryResponse
|
|
15
|
+
│ │ └── query.py # SearchQuery, SearchResponse
|
|
16
|
+
│ │
|
|
17
|
+
│ ├── store/ # storage abstraction
|
|
18
|
+
│ │ ├── __init__.py
|
|
19
|
+
│ │ ├── base.py # MemoryStore interface
|
|
20
|
+
│ │ └── pg_store.py # PostgreSQL + pgvector implementation
|
|
21
|
+
│ │
|
|
22
|
+
│ ├── embeddings/ # embedding model wrapper
|
|
23
|
+
│ │ ├── __init__.py
|
|
24
|
+
│ │ └── encoder.py # sentence-transformers loader + encode()
|
|
25
|
+
│ │
|
|
26
|
+
│ └── api/ # route handlers
|
|
27
|
+
│ ├── __init__.py
|
|
28
|
+
│ ├── memories.py # POST /memories, GET /memories/:id
|
|
29
|
+
│ └── search.py # POST /memories/search
|
|
30
|
+
│
|
|
31
|
+
├── cli.py # attractor start / attractor connect
|
|
32
|
+
├── pyproject.toml # dependencies + package config
|
|
33
|
+
└── README.md
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Data Models
|
|
39
|
+
|
|
40
|
+
### ContextFrame
|
|
41
|
+
The situational state at the time a memory was formed. Not metadata — retrieval key.
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
class ContextFrame(BaseModel):
|
|
45
|
+
topic: str | None # what was being discussed
|
|
46
|
+
entities: list[str] # who/what was involved
|
|
47
|
+
task: str | None # what was being done
|
|
48
|
+
session_id: str | None # which session this came from
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Memory (write)
|
|
52
|
+
```python
|
|
53
|
+
class Memory(BaseModel):
|
|
54
|
+
content: str # the memory text
|
|
55
|
+
context: ContextFrame # situational state
|
|
56
|
+
tags: list[str] = [] # optional labels
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### MemoryRecord (stored)
|
|
60
|
+
```python
|
|
61
|
+
class MemoryRecord(BaseModel):
|
|
62
|
+
id: str # uuid
|
|
63
|
+
content: str
|
|
64
|
+
context: ContextFrame
|
|
65
|
+
tags: list[str]
|
|
66
|
+
created_at: datetime
|
|
67
|
+
accessed_at: datetime
|
|
68
|
+
access_count: int # foundation for Phase 3 decay
|
|
69
|
+
vector: list[float] # embedding (not returned in API responses)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## API Endpoints
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
POST /memories write a memory
|
|
78
|
+
GET /memories/:id get by ID
|
|
79
|
+
POST /memories/search query by content + context filters
|
|
80
|
+
DELETE /memories/:id remove a memory
|
|
81
|
+
|
|
82
|
+
GET /health service health check
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### POST /memories
|
|
86
|
+
```json
|
|
87
|
+
// request
|
|
88
|
+
{
|
|
89
|
+
"content": "auth tokens should never be stored in localStorage",
|
|
90
|
+
"context": {
|
|
91
|
+
"topic": "security review",
|
|
92
|
+
"entities": ["auth", "frontend team"],
|
|
93
|
+
"task": "reviewing PR #42",
|
|
94
|
+
"session_id": "abc123"
|
|
95
|
+
},
|
|
96
|
+
"tags": ["security", "auth"]
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// response
|
|
100
|
+
{
|
|
101
|
+
"id": "550e8400-e29b-41d4-a716-446655440000",
|
|
102
|
+
"created_at": "2026-04-03T18:00:00Z"
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### POST /memories/search
|
|
107
|
+
```json
|
|
108
|
+
// request
|
|
109
|
+
{
|
|
110
|
+
"query": "where did we land on auth token storage",
|
|
111
|
+
"context_filter": {
|
|
112
|
+
"topic": "security review"
|
|
113
|
+
},
|
|
114
|
+
"limit": 5
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// response
|
|
118
|
+
{
|
|
119
|
+
"results": [
|
|
120
|
+
{
|
|
121
|
+
"id": "550e8400...",
|
|
122
|
+
"content": "auth tokens should never be stored in localStorage",
|
|
123
|
+
"context": { ... },
|
|
124
|
+
"score": 0.91,
|
|
125
|
+
"created_at": "2026-04-03T18:00:00Z"
|
|
126
|
+
}
|
|
127
|
+
]
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## Storage Layer
|
|
134
|
+
|
|
135
|
+
### MemoryStore interface (base.py)
|
|
136
|
+
```python
|
|
137
|
+
class MemoryStore(ABC):
|
|
138
|
+
@abstractmethod
|
|
139
|
+
def write(self, record: MemoryRecord) -> str: ...
|
|
140
|
+
|
|
141
|
+
@abstractmethod
|
|
142
|
+
def get(self, id: str) -> MemoryRecord | None: ...
|
|
143
|
+
|
|
144
|
+
@abstractmethod
|
|
145
|
+
def search(self, vector: list[float], context_filter: dict, limit: int) -> list[MemoryRecord]: ...
|
|
146
|
+
|
|
147
|
+
@abstractmethod
|
|
148
|
+
def delete(self, id: str) -> bool: ...
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### PostgreSQL + pgvector implementation (pg_store.py)
|
|
152
|
+
- One table: `memories`
|
|
153
|
+
- Schema mirrors MemoryRecord — content, context fields (JSONB), vector (pgvector), timestamps, access_count
|
|
154
|
+
- Search: pgvector ANN (`<=>` cosine operator) + WHERE filters on context JSONB fields
|
|
155
|
+
- Runs as a service alongside Attractor — no embedded DB
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## Embedding Layer
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
# encoder.py
|
|
163
|
+
from sentence_transformers import SentenceTransformer
|
|
164
|
+
|
|
165
|
+
class Encoder:
|
|
166
|
+
def __init__(self, model_name: str = "all-MiniLM-L6-v2"):
|
|
167
|
+
self.model = SentenceTransformer(model_name)
|
|
168
|
+
|
|
169
|
+
def encode(self, text: str) -> list[float]:
|
|
170
|
+
return self.model.encode(text).tolist()
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Model downloaded once on first run, cached locally. No API calls.
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## CLI
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
attractor start # start service (default port 7747)
|
|
181
|
+
attractor start --port 8000 # custom port
|
|
182
|
+
attractor start --db postgresql://localhost/attractor # custom db url
|
|
183
|
+
attractor connect # ping /health, confirm service is up
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Port 7747 — "loci" on a phone keypad. Keeping it.
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## Dependencies (pyproject.toml)
|
|
191
|
+
|
|
192
|
+
```
|
|
193
|
+
fastapi
|
|
194
|
+
uvicorn
|
|
195
|
+
asyncpg # async PostgreSQL driver
|
|
196
|
+
pgvector # pgvector Python client
|
|
197
|
+
sentence-transformers
|
|
198
|
+
numpy
|
|
199
|
+
pydantic
|
|
200
|
+
click # CLI
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## Phase 1 Complete When
|
|
206
|
+
|
|
207
|
+
- [ ] `attractor start` boots the service
|
|
208
|
+
- [ ] `attractor connect` confirms it's running
|
|
209
|
+
- [ ] Can write a memory with a context frame via POST /memories
|
|
210
|
+
- [ ] Can retrieve by ID via GET /memories/:id
|
|
211
|
+
- [ ] Can search by content query via POST /memories/search
|
|
212
|
+
- [ ] Context fields filter search results
|
|
213
|
+
- [ ] Data persists across service restarts
|
|
214
|
+
- [ ] Works on macOS, Linux, and Windows
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "attractor-engine"
|
|
7
|
+
version = "0.0.1"
|
|
8
|
+
description = "A brain-inspired memory engine — contextual storage and associative retrieval"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = { text = "MIT" }
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "aag1091-alt" }
|
|
14
|
+
]
|
|
15
|
+
keywords = ["memory", "database", "associative", "hopfield", "contextual", "ai", "agents", "attractor"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 1 - Planning",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"License :: OSI Approved :: MIT License",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3.10",
|
|
22
|
+
"Programming Language :: Python :: 3.11",
|
|
23
|
+
"Programming Language :: Python :: 3.12",
|
|
24
|
+
"Topic :: Database",
|
|
25
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
[project.urls]
|
|
29
|
+
Homepage = "https://github.com/aag1091-alt/attractor"
|
|
30
|
+
Repository = "https://github.com/aag1091-alt/attractor"
|
|
31
|
+
|
|
32
|
+
[tool.hatch.build.targets.wheel]
|
|
33
|
+
packages = ["src/attractor"]
|