augmem.cortext 1.2.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.
@@ -0,0 +1,3 @@
1
+ include README.md
2
+ recursive-include augmem/cortext/native *
3
+ recursive-include augmem/cortext/models *
@@ -0,0 +1,285 @@
1
+ Metadata-Version: 2.4
2
+ Name: augmem.cortext
3
+ Version: 1.2.0
4
+ Summary: Python bindings for the Cortext memory engine
5
+ Author: augmem
6
+ License: Apache-2.0
7
+ Project-URL: Homepage, https://github.com/augmem/cortext
8
+ Project-URL: Repository, https://github.com/augmem/cortext
9
+ Project-URL: Issues, https://github.com/augmem/cortext/issues
10
+ Keywords: memory,retrieval,embeddings,llm,agents
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: Apache Software License
14
+ Classifier: Operating System :: MacOS
15
+ Classifier: Operating System :: Microsoft :: Windows
16
+ Classifier: Operating System :: POSIX :: Linux
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3 :: Only
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
24
+ Requires-Python: >=3.10
25
+ Description-Content-Type: text/markdown
26
+
27
+ # augmem.cortext
28
+
29
+ Python bindings for Cortext, the on-device memory engine behind augmem. Use it
30
+ to persist text, audio, and image signals, then retrieve relevant context for
31
+ agents, applications, notebooks, and LLM prompts.
32
+
33
+ The PyPI wheels ship cross-platform native Cortext libraries for supported
34
+ desktop/server platforms. They do not embed the large AIST GGUF model. On first
35
+ engine creation, the wrapper uses `CORTEXT_AIST_MODEL_PATH` if set, then any
36
+ bundled/local model already present, otherwise it downloads the default AIST
37
+ GGUF model into the user cache and verifies its checksum before use.
38
+
39
+ ## Install
40
+
41
+ ```bash
42
+ pip install augmem.cortext
43
+ ```
44
+
45
+ ```python
46
+ import augmem.cortext as cortext
47
+
48
+ print(cortext.version())
49
+ ```
50
+
51
+ Python 3.10+ is required. Release wheels target Linux, macOS, and Windows on
52
+ `x86_64`/`aarch64` where native artifacts are published.
53
+
54
+ ## Quickstart
55
+
56
+ <!-- quickstart retention examples matching bindings/python/augmem/cortext/__init__.py -->
57
+
58
+ ```python
59
+ import augmem.cortext as cortext
60
+
61
+ cfg = cortext.Config(
62
+ focus=0.55, # retrieval selectivity
63
+ sensitivity=0.50, # responsiveness to new or surprising input
64
+ stability=0.65, # preference for durable, stable context
65
+ )
66
+
67
+ with cortext.Cortext("memory.sqlite", config=cfg) as memory:
68
+ memory.process_text(
69
+ "The garage door code is 8841.",
70
+ source_id="user/profile",
71
+ include_embedding=False,
72
+ retention=cortext.Retention.DURABLE,
73
+ )
74
+
75
+ ctx = memory.process_text(
76
+ "We are leaving soon. What should I remember about the garage?",
77
+ source_id="chat/assistant",
78
+ include_embedding=False,
79
+ retention=cortext.Retention.EPHEMERAL,
80
+ )
81
+
82
+ for item in ctx.get("retrieved_memory", []):
83
+ print(item.get("text"), item.get("rel"))
84
+
85
+ if ctx.get("consolidation_recommended"):
86
+ memory.consolidate()
87
+
88
+ memory.flush()
89
+ ```
90
+
91
+ Use `":memory:"` for a temporary engine. Use a file path when memories should
92
+ survive process restarts.
93
+
94
+ ## Chat Completions Memory Loop
95
+
96
+ The normal loop is simple:
97
+
98
+ 1. Call `process_text` for turns or observations you are willing to remember.
99
+ 2. On later turns, read `ctx["retrieved_memory"]`.
100
+ 3. Pass those snippets as context messages to Chat Completions.
101
+ 4. Call `consolidate()` when Cortext recommends it.
102
+
103
+ Install the OpenAI SDK and set `OPENAI_API_KEY`:
104
+
105
+ ```bash
106
+ pip install openai
107
+ ```
108
+
109
+ ```python
110
+ from openai import OpenAI
111
+ import augmem.cortext as cortext
112
+ import os
113
+
114
+ client = OpenAI()
115
+ memory = cortext.Cortext("memory.sqlite")
116
+
117
+ def answer(conversation_id: str, user_message: str) -> str:
118
+ ctx = memory.process_text(
119
+ user_message,
120
+ source_id=f"conversation/{conversation_id}",
121
+ include_embedding=False,
122
+ retention=cortext.Retention.DURABLE,
123
+ )
124
+
125
+ memories = "\n".join(
126
+ f"- {m.get('text', '')}"
127
+ for m in ctx.get("retrieved_memory", [])[:6]
128
+ if m.get("text")
129
+ )
130
+
131
+ completion = client.chat.completions.create(
132
+ model=os.environ.get("OPENAI_MODEL", "gpt-5-mini"),
133
+ messages=[
134
+ {
135
+ "role": "developer",
136
+ "content": (
137
+ "Use the supplied Cortext memories when they are relevant. "
138
+ "Ignore them when they are not relevant."
139
+ ),
140
+ },
141
+ {
142
+ "role": "developer",
143
+ "content": f"Cortext retrieved memory:\n{memories or '- none'}",
144
+ },
145
+ {"role": "user", "content": user_message},
146
+ ],
147
+ )
148
+
149
+ if ctx.get("consolidation_recommended"):
150
+ memory.consolidate()
151
+
152
+ return completion.choices[0].message.content or ""
153
+ ```
154
+
155
+ Retention (default `Retention.NATURAL`): episode algorithms decide boundary and
156
+ write. Pass `retention=Retention.DURABLE` for explicit turn commit,
157
+ `Retention.BOUNDARY` for an explicit edge only, or `Retention.EPHEMERAL` for
158
+ retrieve-without-store queries. Use `embed_*` for embedding-only work.
159
+
160
+ ## Returned Context
161
+
162
+ `process_*` returns a dictionary parsed from the native context packet. Common
163
+ fields:
164
+
165
+ - `retrieved_memory`: long-term memories selected for the current signal.
166
+ - `working_memory`: short-term active context.
167
+ - `should_interrupt`, `interrupt_aborted`, `at_boundary`: realtime behavior
168
+ flags.
169
+ - `consolidation_recommended`, `consolidation_required`: maintenance hints.
170
+ - `output`: scores, storage decisions, filter status, and operation timings.
171
+ - `encode_ms`, `process_ms`, `hydrate_ms`, `total_ms`: latency breakdown.
172
+ - `embedding`, `embedding_dimension`: present only when requested.
173
+
174
+ Memory entries commonly include `text`, `source_id`, `timestamp`, `modality`,
175
+ `mimetype`, `rel`, usage counts, scores, and soft-anchor metadata. For prompt
176
+ assembly, pass `include_embedding=False`; embeddings are large and rarely
177
+ needed in the returned packet.
178
+
179
+ ## Audio and Image
180
+
181
+ Audio input is 16 kHz mono float PCM:
182
+
183
+ ```python
184
+ pcm = [0.0] * 16000
185
+ ctx = memory.process_audio(pcm, "mic/main", include_embedding=False)
186
+ ```
187
+
188
+ Image input is row-major RGB or RGBA bytes:
189
+
190
+ ```python
191
+ rgb = bytes([0, 0, 0] * 64 * 64)
192
+ ctx = memory.process_image(rgb, 64, 64, 3, "camera/main", include_embedding=False)
193
+ ```
194
+
195
+ Use media variants when you want to store original bytes next to the canonical
196
+ signal:
197
+
198
+ ```python
199
+ media = cortext.Media(data=jpeg_bytes, mimetype="image/jpeg")
200
+ ctx = memory.process_image_with_media(
201
+ rgb, 64, 64, 3, "camera/main", media, include_embedding=False
202
+ )
203
+ ```
204
+
205
+ ## Runtime Assets and Model Cache
206
+
207
+ The wheel contains the native Cortext shared library for supported platforms.
208
+ The AIST GGUF model is intentionally not embedded in registry packages because
209
+ of PyPI size constraints.
210
+
211
+ Model resolution on engine creation:
212
+
213
+ 1. `CORTEXT_AIST_MODEL_PATH=/path/to/AIST-87M_q8_0.gguf`
214
+ 2. A bundled or checkout-local model, if one exists.
215
+ 3. Download the default AIST GGUF model to the user cache and verify its
216
+ checksum before loading it.
217
+
218
+ The first run may need network access and enough cache space for the model
219
+ (roughly 135-142 MiB, depending on quantization). Later runs reuse the verified
220
+ cache. Set `CORTEXT_MODEL_CACHE_DIR` to control the cache root, or set
221
+ `CORTEXT_AIST_MODEL_PATH` for offline deployments and pinned model files.
222
+
223
+ Native library override:
224
+
225
+ - `CORTEXT_LIBRARY_PATH=/path/to/libcortext.so`
226
+ - or `cortext.Cortext(..., library_path="/path/to/libcortext.so")`
227
+
228
+ ## API Shape
229
+
230
+ ```python
231
+ memory = cortext.Cortext(
232
+ db_path="memory.sqlite",
233
+ config=cortext.Config(),
234
+ library_path=None,
235
+ )
236
+ ```
237
+
238
+ Core methods:
239
+
240
+ - `process_text(text, source_id, include_embedding=True) -> dict`
241
+ - `process_audio(pcm, source_id, include_embedding=True) -> dict`
242
+ - `process_image(data, width, height, channels, source_id, include_embedding=True) -> dict`
243
+ - `process_audio_with_media(...) -> dict`
244
+ - `process_image_with_media(...) -> dict`
245
+ - `embed_text(text) -> list[float]`
246
+ - `embed_audio(pcm) -> list[float]`
247
+ - `embed_image(data, width, height, channels) -> list[float]`
248
+ - `consolidate() -> dict`
249
+ - `flush()`, `reset()`, `close()`
250
+
251
+ Each `process_*`, `embed_*`, and `consolidate` method has a JSON variant that
252
+ returns the raw native JSON string.
253
+
254
+ ## Troubleshooting
255
+
256
+ - First engine creation is slow: the model may be downloading and verifying.
257
+ - Model download fails: check network access, cache write permission, or set
258
+ `CORTEXT_AIST_MODEL_PATH` to a local GGUF file.
259
+ - Checksum failure: remove the partially downloaded cache file and retry.
260
+ - Native library cannot be found: install a supported wheel, set
261
+ `CORTEXT_LIBRARY_PATH`, or pass `library_path=...`.
262
+ - Very large context objects: call `process_text(..., include_embedding=False)`.
263
+ - Need a clean temporary run: use `cortext.Cortext(":memory:")`.
264
+ - Native failure details: call `cortext.last_error()` immediately after the
265
+ exception.
266
+
267
+ ## Build From Source
268
+
269
+ For local development from a repository checkout:
270
+
271
+ ```bash
272
+ cmake --preset ffi-release
273
+ cmake --build --preset ffi-release --target cortext
274
+ export CORTEXT_LIBRARY_PATH="$PWD/build/ffi-release/libcortext.so"
275
+ export CORTEXT_AIST_MODEL_PATH="$PWD/models/AIST-87M-GGUF/AIST-87M_q8_0.gguf"
276
+ ```
277
+
278
+ Build a release wheel with native libraries:
279
+
280
+ ```bash
281
+ python scripts/build_python_package.py --zig /path/to/zig --skip-models
282
+ ```
283
+
284
+ The wheel is written to `bindings/python/dist/`. Registry wheels should include
285
+ native libraries but leave the large AIST model to the runtime cache path above.
@@ -0,0 +1,259 @@
1
+ # augmem.cortext
2
+
3
+ Python bindings for Cortext, the on-device memory engine behind augmem. Use it
4
+ to persist text, audio, and image signals, then retrieve relevant context for
5
+ agents, applications, notebooks, and LLM prompts.
6
+
7
+ The PyPI wheels ship cross-platform native Cortext libraries for supported
8
+ desktop/server platforms. They do not embed the large AIST GGUF model. On first
9
+ engine creation, the wrapper uses `CORTEXT_AIST_MODEL_PATH` if set, then any
10
+ bundled/local model already present, otherwise it downloads the default AIST
11
+ GGUF model into the user cache and verifies its checksum before use.
12
+
13
+ ## Install
14
+
15
+ ```bash
16
+ pip install augmem.cortext
17
+ ```
18
+
19
+ ```python
20
+ import augmem.cortext as cortext
21
+
22
+ print(cortext.version())
23
+ ```
24
+
25
+ Python 3.10+ is required. Release wheels target Linux, macOS, and Windows on
26
+ `x86_64`/`aarch64` where native artifacts are published.
27
+
28
+ ## Quickstart
29
+
30
+ <!-- quickstart retention examples matching bindings/python/augmem/cortext/__init__.py -->
31
+
32
+ ```python
33
+ import augmem.cortext as cortext
34
+
35
+ cfg = cortext.Config(
36
+ focus=0.55, # retrieval selectivity
37
+ sensitivity=0.50, # responsiveness to new or surprising input
38
+ stability=0.65, # preference for durable, stable context
39
+ )
40
+
41
+ with cortext.Cortext("memory.sqlite", config=cfg) as memory:
42
+ memory.process_text(
43
+ "The garage door code is 8841.",
44
+ source_id="user/profile",
45
+ include_embedding=False,
46
+ retention=cortext.Retention.DURABLE,
47
+ )
48
+
49
+ ctx = memory.process_text(
50
+ "We are leaving soon. What should I remember about the garage?",
51
+ source_id="chat/assistant",
52
+ include_embedding=False,
53
+ retention=cortext.Retention.EPHEMERAL,
54
+ )
55
+
56
+ for item in ctx.get("retrieved_memory", []):
57
+ print(item.get("text"), item.get("rel"))
58
+
59
+ if ctx.get("consolidation_recommended"):
60
+ memory.consolidate()
61
+
62
+ memory.flush()
63
+ ```
64
+
65
+ Use `":memory:"` for a temporary engine. Use a file path when memories should
66
+ survive process restarts.
67
+
68
+ ## Chat Completions Memory Loop
69
+
70
+ The normal loop is simple:
71
+
72
+ 1. Call `process_text` for turns or observations you are willing to remember.
73
+ 2. On later turns, read `ctx["retrieved_memory"]`.
74
+ 3. Pass those snippets as context messages to Chat Completions.
75
+ 4. Call `consolidate()` when Cortext recommends it.
76
+
77
+ Install the OpenAI SDK and set `OPENAI_API_KEY`:
78
+
79
+ ```bash
80
+ pip install openai
81
+ ```
82
+
83
+ ```python
84
+ from openai import OpenAI
85
+ import augmem.cortext as cortext
86
+ import os
87
+
88
+ client = OpenAI()
89
+ memory = cortext.Cortext("memory.sqlite")
90
+
91
+ def answer(conversation_id: str, user_message: str) -> str:
92
+ ctx = memory.process_text(
93
+ user_message,
94
+ source_id=f"conversation/{conversation_id}",
95
+ include_embedding=False,
96
+ retention=cortext.Retention.DURABLE,
97
+ )
98
+
99
+ memories = "\n".join(
100
+ f"- {m.get('text', '')}"
101
+ for m in ctx.get("retrieved_memory", [])[:6]
102
+ if m.get("text")
103
+ )
104
+
105
+ completion = client.chat.completions.create(
106
+ model=os.environ.get("OPENAI_MODEL", "gpt-5-mini"),
107
+ messages=[
108
+ {
109
+ "role": "developer",
110
+ "content": (
111
+ "Use the supplied Cortext memories when they are relevant. "
112
+ "Ignore them when they are not relevant."
113
+ ),
114
+ },
115
+ {
116
+ "role": "developer",
117
+ "content": f"Cortext retrieved memory:\n{memories or '- none'}",
118
+ },
119
+ {"role": "user", "content": user_message},
120
+ ],
121
+ )
122
+
123
+ if ctx.get("consolidation_recommended"):
124
+ memory.consolidate()
125
+
126
+ return completion.choices[0].message.content or ""
127
+ ```
128
+
129
+ Retention (default `Retention.NATURAL`): episode algorithms decide boundary and
130
+ write. Pass `retention=Retention.DURABLE` for explicit turn commit,
131
+ `Retention.BOUNDARY` for an explicit edge only, or `Retention.EPHEMERAL` for
132
+ retrieve-without-store queries. Use `embed_*` for embedding-only work.
133
+
134
+ ## Returned Context
135
+
136
+ `process_*` returns a dictionary parsed from the native context packet. Common
137
+ fields:
138
+
139
+ - `retrieved_memory`: long-term memories selected for the current signal.
140
+ - `working_memory`: short-term active context.
141
+ - `should_interrupt`, `interrupt_aborted`, `at_boundary`: realtime behavior
142
+ flags.
143
+ - `consolidation_recommended`, `consolidation_required`: maintenance hints.
144
+ - `output`: scores, storage decisions, filter status, and operation timings.
145
+ - `encode_ms`, `process_ms`, `hydrate_ms`, `total_ms`: latency breakdown.
146
+ - `embedding`, `embedding_dimension`: present only when requested.
147
+
148
+ Memory entries commonly include `text`, `source_id`, `timestamp`, `modality`,
149
+ `mimetype`, `rel`, usage counts, scores, and soft-anchor metadata. For prompt
150
+ assembly, pass `include_embedding=False`; embeddings are large and rarely
151
+ needed in the returned packet.
152
+
153
+ ## Audio and Image
154
+
155
+ Audio input is 16 kHz mono float PCM:
156
+
157
+ ```python
158
+ pcm = [0.0] * 16000
159
+ ctx = memory.process_audio(pcm, "mic/main", include_embedding=False)
160
+ ```
161
+
162
+ Image input is row-major RGB or RGBA bytes:
163
+
164
+ ```python
165
+ rgb = bytes([0, 0, 0] * 64 * 64)
166
+ ctx = memory.process_image(rgb, 64, 64, 3, "camera/main", include_embedding=False)
167
+ ```
168
+
169
+ Use media variants when you want to store original bytes next to the canonical
170
+ signal:
171
+
172
+ ```python
173
+ media = cortext.Media(data=jpeg_bytes, mimetype="image/jpeg")
174
+ ctx = memory.process_image_with_media(
175
+ rgb, 64, 64, 3, "camera/main", media, include_embedding=False
176
+ )
177
+ ```
178
+
179
+ ## Runtime Assets and Model Cache
180
+
181
+ The wheel contains the native Cortext shared library for supported platforms.
182
+ The AIST GGUF model is intentionally not embedded in registry packages because
183
+ of PyPI size constraints.
184
+
185
+ Model resolution on engine creation:
186
+
187
+ 1. `CORTEXT_AIST_MODEL_PATH=/path/to/AIST-87M_q8_0.gguf`
188
+ 2. A bundled or checkout-local model, if one exists.
189
+ 3. Download the default AIST GGUF model to the user cache and verify its
190
+ checksum before loading it.
191
+
192
+ The first run may need network access and enough cache space for the model
193
+ (roughly 135-142 MiB, depending on quantization). Later runs reuse the verified
194
+ cache. Set `CORTEXT_MODEL_CACHE_DIR` to control the cache root, or set
195
+ `CORTEXT_AIST_MODEL_PATH` for offline deployments and pinned model files.
196
+
197
+ Native library override:
198
+
199
+ - `CORTEXT_LIBRARY_PATH=/path/to/libcortext.so`
200
+ - or `cortext.Cortext(..., library_path="/path/to/libcortext.so")`
201
+
202
+ ## API Shape
203
+
204
+ ```python
205
+ memory = cortext.Cortext(
206
+ db_path="memory.sqlite",
207
+ config=cortext.Config(),
208
+ library_path=None,
209
+ )
210
+ ```
211
+
212
+ Core methods:
213
+
214
+ - `process_text(text, source_id, include_embedding=True) -> dict`
215
+ - `process_audio(pcm, source_id, include_embedding=True) -> dict`
216
+ - `process_image(data, width, height, channels, source_id, include_embedding=True) -> dict`
217
+ - `process_audio_with_media(...) -> dict`
218
+ - `process_image_with_media(...) -> dict`
219
+ - `embed_text(text) -> list[float]`
220
+ - `embed_audio(pcm) -> list[float]`
221
+ - `embed_image(data, width, height, channels) -> list[float]`
222
+ - `consolidate() -> dict`
223
+ - `flush()`, `reset()`, `close()`
224
+
225
+ Each `process_*`, `embed_*`, and `consolidate` method has a JSON variant that
226
+ returns the raw native JSON string.
227
+
228
+ ## Troubleshooting
229
+
230
+ - First engine creation is slow: the model may be downloading and verifying.
231
+ - Model download fails: check network access, cache write permission, or set
232
+ `CORTEXT_AIST_MODEL_PATH` to a local GGUF file.
233
+ - Checksum failure: remove the partially downloaded cache file and retry.
234
+ - Native library cannot be found: install a supported wheel, set
235
+ `CORTEXT_LIBRARY_PATH`, or pass `library_path=...`.
236
+ - Very large context objects: call `process_text(..., include_embedding=False)`.
237
+ - Need a clean temporary run: use `cortext.Cortext(":memory:")`.
238
+ - Native failure details: call `cortext.last_error()` immediately after the
239
+ exception.
240
+
241
+ ## Build From Source
242
+
243
+ For local development from a repository checkout:
244
+
245
+ ```bash
246
+ cmake --preset ffi-release
247
+ cmake --build --preset ffi-release --target cortext
248
+ export CORTEXT_LIBRARY_PATH="$PWD/build/ffi-release/libcortext.so"
249
+ export CORTEXT_AIST_MODEL_PATH="$PWD/models/AIST-87M-GGUF/AIST-87M_q8_0.gguf"
250
+ ```
251
+
252
+ Build a release wheel with native libraries:
253
+
254
+ ```bash
255
+ python scripts/build_python_package.py --zig /path/to/zig --skip-models
256
+ ```
257
+
258
+ The wheel is written to `bindings/python/dist/`. Registry wheels should include
259
+ native libraries but leave the large AIST model to the runtime cache path above.