anona 0.6.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.
Files changed (36) hide show
  1. anona-0.6.0/LICENSE +21 -0
  2. anona-0.6.0/PKG-INFO +285 -0
  3. anona-0.6.0/README.md +239 -0
  4. anona-0.6.0/anona/__init__.py +4 -0
  5. anona-0.6.0/anona/client.py +743 -0
  6. anona-0.6.0/anona/integrations/__init__.py +16 -0
  7. anona-0.6.0/anona/integrations/_core.py +309 -0
  8. anona-0.6.0/anona/integrations/crewai.py +236 -0
  9. anona-0.6.0/anona/integrations/google_adk.py +309 -0
  10. anona-0.6.0/anona/integrations/langchain.py +229 -0
  11. anona-0.6.0/anona/integrations/litellm.py +155 -0
  12. anona-0.6.0/anona/integrations/llamaindex.py +252 -0
  13. anona-0.6.0/anona/integrations/mcp.py +167 -0
  14. anona-0.6.0/anona/integrations/ms_agent.py +234 -0
  15. anona-0.6.0/anona/integrations/strands.py +170 -0
  16. anona-0.6.0/anona.egg-info/PKG-INFO +285 -0
  17. anona-0.6.0/anona.egg-info/SOURCES.txt +34 -0
  18. anona-0.6.0/anona.egg-info/dependency_links.txt +1 -0
  19. anona-0.6.0/anona.egg-info/entry_points.txt +2 -0
  20. anona-0.6.0/anona.egg-info/requires.txt +33 -0
  21. anona-0.6.0/anona.egg-info/top_level.txt +1 -0
  22. anona-0.6.0/pyproject.toml +128 -0
  23. anona-0.6.0/setup.cfg +4 -0
  24. anona-0.6.0/tests/test_adapter_crewai.py +479 -0
  25. anona-0.6.0/tests/test_adapter_google_adk.py +641 -0
  26. anona-0.6.0/tests/test_adapter_langchain.py +567 -0
  27. anona-0.6.0/tests/test_adapter_llamaindex.py +429 -0
  28. anona-0.6.0/tests/test_adapter_ms_agent.py +376 -0
  29. anona-0.6.0/tests/test_adapter_strands.py +504 -0
  30. anona-0.6.0/tests/test_async_context.py +102 -0
  31. anona-0.6.0/tests/test_client.py +272 -0
  32. anona-0.6.0/tests/test_client_lifecycle.py +265 -0
  33. anona-0.6.0/tests/test_examples.py +243 -0
  34. anona-0.6.0/tests/test_mcp.py +193 -0
  35. anona-0.6.0/tests/test_memory_bridge.py +471 -0
  36. anona-0.6.0/tests/test_path_encoding.py +106 -0
anona-0.6.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Anona Labs
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
anona-0.6.0/PKG-INFO ADDED
@@ -0,0 +1,285 @@
1
+ Metadata-Version: 2.4
2
+ Name: anona
3
+ Version: 0.6.0
4
+ Summary: Anona Memory SDK — managed AI memory for intelligent agents
5
+ Author: Anona Labs
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/anonalabs/Anona-Memory-SDK
8
+ Project-URL: Repository, https://github.com/anonalabs/Anona-Memory-SDK
9
+ Keywords: ai,memory,agents,llm,rag,mcp
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Operating System :: OS Independent
18
+ Requires-Python: >=3.10
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ Requires-Dist: httpx>=0.24
22
+ Provides-Extra: litellm
23
+ Requires-Dist: litellm>=1.0; extra == "litellm"
24
+ Provides-Extra: mcp
25
+ Requires-Dist: mcp<2,>=1.2; extra == "mcp"
26
+ Provides-Extra: langchain
27
+ Requires-Dist: langchain>=1.3; extra == "langchain"
28
+ Requires-Dist: langchain-core>=1.4; extra == "langchain"
29
+ Provides-Extra: crewai
30
+ Requires-Dist: crewai>=1.0; extra == "crewai"
31
+ Provides-Extra: llamaindex
32
+ Requires-Dist: llama-index-core>=0.14; extra == "llamaindex"
33
+ Provides-Extra: adk
34
+ Requires-Dist: google-adk>=1.21; extra == "adk"
35
+ Provides-Extra: msagent
36
+ Requires-Dist: agent-framework-core>=1.0; extra == "msagent"
37
+ Provides-Extra: strands
38
+ Requires-Dist: strands-agents>=1.0; extra == "strands"
39
+ Provides-Extra: dev
40
+ Requires-Dist: pytest; extra == "dev"
41
+ Requires-Dist: pytest-asyncio; extra == "dev"
42
+ Requires-Dist: respx; extra == "dev"
43
+ Requires-Dist: anyio; extra == "dev"
44
+ Requires-Dist: anona[mcp]; extra == "dev"
45
+ Dynamic: license-file
46
+
47
+ # Anona Memory SDK
48
+
49
+ Official SDKs for [Anona Memory](https://memory.anonalabs.com) — managed AI memory for intelligent agents. Record, retrieve, and reason over memories per user/space via a simple client, or auto-inject memory into LiteLLM calls with one line.
50
+
51
+ - **Python** — this repository root. Documented below.
52
+ - **TypeScript** — [`typescript/`](typescript/). Zero dependencies, runs on Node 18+, Bun, Deno, Cloudflare Workers and the browser, with adapters for the Vercel AI SDK and the OpenAI Agents SDK. See [`typescript/README.md`](typescript/README.md).
53
+
54
+ ```typescript
55
+ import { Anona } from "@anona-labs/memory";
56
+
57
+ const anona = new Anona({ apiKey: process.env.ANONA_API_KEY! });
58
+ await anona.record({ spaceId: "support", content: "Alice prefers email" });
59
+ const hits = await anona.retrieve({ spaceId: "support", query: "how to contact Alice" });
60
+ ```
61
+
62
+ ```bash
63
+ npm install @anona-labs/memory
64
+ ```
65
+
66
+ ## Install
67
+
68
+ Install directly from GitHub:
69
+
70
+ ```bash
71
+ pip install git+https://github.com/anonalabs/Anona-Memory-SDK.git
72
+ ```
73
+
74
+ With the LiteLLM integration (or `mcp` for the MCP server):
75
+
76
+ ```bash
77
+ pip install "anona[litellm] @ git+https://github.com/anonalabs/Anona-Memory-SDK.git"
78
+ ```
79
+
80
+ > The package is not yet on PyPI, so install from the Git URL above. Once it's
81
+ > published, `pip install anona` will also work.
82
+
83
+ ## Quickstart
84
+
85
+ ```python
86
+ from anona import AnonaClient
87
+
88
+ # base_url defaults to https://api.anonalabs.com — pass it only to override.
89
+ client = AnonaClient(api_key="anona_live_...")
90
+
91
+ # Record a memory
92
+ client.record(space_id="space_123", content="User prefers dark mode.")
93
+
94
+ # Retrieve memories
95
+ results = client.retrieve(space_id="space_123", query="UI preferences", limit=5)
96
+ for r in results:
97
+ print(r["relevance_score"], r["content"])
98
+
99
+ # Reason: a synthesized insight across memories
100
+ summary = client.reason(space_id="space_123", query="What do we know about this user?")
101
+ print(summary)
102
+
103
+ client.close()
104
+ ```
105
+
106
+ ### Async ingestion (don't block on a write)
107
+
108
+ Recording runs fact extraction, so a normal `record()` takes a moment. In a
109
+ chat loop or any latency-sensitive path, queue the write with `background=True`
110
+ and poll the returned job instead:
111
+
112
+ ```python
113
+ import time
114
+
115
+ job = client.record(
116
+ space_id="space_123",
117
+ content="User prefers dark mode.",
118
+ background=True, # returns a job_id, doesn't wait
119
+ )
120
+
121
+ while True:
122
+ status = client.get_job(space_id="space_123", job_id=job["job_id"])
123
+ if status["status"] in ("completed", "failed", "cancelled", "not_found"):
124
+ break
125
+ time.sleep(2)
126
+
127
+ # Backfill many memories at once (always queued, up to 100 per call):
128
+ batch = client.record_batch(
129
+ space_id="space_123",
130
+ items=[
131
+ {"content": "User is on the Pro plan."},
132
+ {"content": "Signed up in 2024.", "timestamp": "2024-03-01T00:00:00Z"},
133
+ ],
134
+ )
135
+ print(batch["accepted"], "queued as job", batch["job_id"])
136
+ ```
137
+
138
+ Async variants (`async_record`, `async_retrieve`, `async_reason`) are available on the same client, or use it as a context manager:
139
+
140
+ ```python
141
+ async with AnonaClient(api_key="...") as client:
142
+ await client.async_record(space_id="space_123", content="...")
143
+ ```
144
+
145
+ ## API
146
+
147
+ ### `AnonaClient(api_key, base_url="https://api.anonalabs.com")`
148
+
149
+ - `record(space_id, content, metadata=None, background=False) -> dict` — store a memory; `background=True` queues it and returns a `job_id`
150
+ - `record_batch(space_id, items) -> dict` — bulk-ingest up to 100 items (always queued); returns a `job_id`
151
+ - `get_job(space_id, job_id) -> dict` — poll a queued job's status (free); `status` is one of pending / processing / completed / failed / cancelled / not_found
152
+ - `retrieve(space_id, query, limit=10) -> list[dict]`
153
+ - `reason(space_id, query) -> str | None`
154
+ - `list_spaces() -> list[dict]`
155
+ - `upload_file(space_id, file, *, filename=None, strategy=None, tags=None) -> dict` — upload a file (path / bytes / file-like) so retrieval can draw on its content; ingested asynchronously, returns `job_ids`. PDF, DOCX, PPTX, XLSX, images (OCR), HTML, TXT/MD, CSV, audio. Files over 25 MB are rejected client-side.
156
+ - `list_documents(space_id, limit=100, offset=0) -> list[dict]`
157
+ - `delete_document(space_id, document_id) -> None` — remove a document and the memories extracted from it
158
+ - `get_graph(space_id, limit=500, min_count=1) -> dict` — entity relationship graph (nodes + co-occurrence edges)
159
+ - `list_entities(space_id, limit=100, offset=0) -> list[dict]`
160
+ - `get_entity(space_id, entity_id) -> dict` — one entity + its observations
161
+ - `async_record(...)`, `async_record_batch(...)`, `async_get_job(...)`, `async_retrieve(...)`, `async_reason(...)`, `async_list_spaces(...)`, `async_upload_file(...)`, `async_list_documents(...)`, `async_delete_document(...)`, `async_get_graph(...)`, `async_list_entities(...)`, `async_get_entity(...)` — async equivalents
162
+ - `close()` / `aclose()` — release underlying HTTP clients
163
+
164
+ Errors raise `AnonaError(status_code, detail)`.
165
+
166
+ ## Framework adapters
167
+
168
+ Anona plugs into the Python agent frameworks through optional extras. Every
169
+ adapter handles recall and storage for you, and scopes memories per end user.
170
+
171
+ | Framework | Install | Import |
172
+ | --- | --- | --- |
173
+ | LangChain / LangGraph | `pip install 'anona[langchain]'` | `anona.integrations.langchain` |
174
+ | CrewAI | `pip install 'anona[crewai]'` | `anona.integrations.crewai` |
175
+ | LlamaIndex | `pip install 'anona[llamaindex]'` | `anona.integrations.llamaindex` |
176
+ | Google ADK | `pip install 'anona[adk]'` | `anona.integrations.google_adk` |
177
+ | Microsoft Agent Framework | `pip install 'anona[msagent]'` | `anona.integrations.ms_agent` |
178
+ | AWS Strands | `pip install 'anona[strands]'` | `anona.integrations.strands` |
179
+
180
+ All six are built on one `MemoryBridge`, which owns scope resolution and the
181
+ failure contract:
182
+
183
+ ```python
184
+ from anona.integrations import MemoryBridge
185
+ from anona.integrations.langchain import AnonaMemory
186
+
187
+ bridge = MemoryBridge(
188
+ api_key="anona_live_...",
189
+ space_id="my-space",
190
+ user_id="customer-42", # optional scope: this user's memories only
191
+ )
192
+
193
+ agent = create_agent(model="gpt-4o-mini", middleware=[AnonaMemory(bridge=bridge)])
194
+ ```
195
+
196
+ **Memory failures never raise into your agent.** A failed recall or store is
197
+ logged and the agent runs on without memory, rather than taking your
198
+ application down.
199
+
200
+ Each adapter's own module docstring documents its scoping, failure behaviour
201
+ and per-call cost. Full docs: https://docs.anonalabs.com/integrations/langchain
202
+
203
+ Runnable end-to-end scripts for all six live in [`examples/`](examples/).
204
+
205
+ ## LiteLLM integration
206
+
207
+ Auto-inject relevant memories into every `litellm.completion()` call, and auto-store the resulting Q&A pair:
208
+
209
+ ```python
210
+ from anona.integrations.litellm import AnonaMemory
211
+
212
+ mem = AnonaMemory(
213
+ api_key="anona_live_...",
214
+ space_id="space_123",
215
+ recall_limit=5, # how many memories to retrieve per call
216
+ inject_mode="system", # "system" or "user"
217
+ store_after=True, # auto-store the exchange after each call
218
+ )
219
+ mem.enable()
220
+
221
+ # All subsequent litellm.completion() calls now auto-recall + auto-store.
222
+ import litellm
223
+ litellm.completion(model="gpt-4o", messages=[{"role": "user", "content": "..."}])
224
+ ```
225
+
226
+ ## MCP server
227
+
228
+ The SDK ships an [MCP](https://modelcontextprotocol.io) server so any MCP client
229
+ — Claude Desktop, Claude Code, Cursor — can read and write Anona memory as native
230
+ tools: `record`, `retrieve`, `list_spaces`, and `reason`.
231
+
232
+ Install the extra:
233
+
234
+ ```bash
235
+ pip install "anona[mcp] @ git+https://github.com/anonalabs/Anona-Memory-SDK.git"
236
+ ```
237
+
238
+ **Claude Desktop / Cursor** — add to `claude_desktop_config.json` (or
239
+ `~/.cursor/mcp.json`), then restart:
240
+
241
+ ```json
242
+ {
243
+ "mcpServers": {
244
+ "anona": {
245
+ "command": "uvx",
246
+ "args": [
247
+ "--from",
248
+ "anona[mcp] @ git+https://github.com/anonalabs/Anona-Memory-SDK.git",
249
+ "anona-mcp"
250
+ ],
251
+ "env": {
252
+ "ANONA_API_KEY": "anona_live_...",
253
+ "ANONA_SPACE_ID": "space_123"
254
+ }
255
+ }
256
+ }
257
+ }
258
+ ```
259
+
260
+ **Claude Code** — one command:
261
+
262
+ ```bash
263
+ claude mcp add anona \
264
+ --env ANONA_API_KEY=anona_live_... \
265
+ --env ANONA_SPACE_ID=space_123 \
266
+ -- uvx --from "anona[mcp] @ git+https://github.com/anonalabs/Anona-Memory-SDK.git" anona-mcp
267
+ ```
268
+
269
+ `ANONA_SPACE_ID` sets the default space so you can just say "remember this"
270
+ without naming one; override it per call with the `space_id` argument. The key
271
+ is personal — the server only reaches spaces you are a member of.
272
+
273
+ ## Requirements
274
+
275
+ - Python >= 3.10
276
+ - `httpx >= 0.24`
277
+ - `litellm >= 1.0` (optional, only for the LiteLLM integration)
278
+ - `mcp >= 1.2` (optional, only for the MCP server)
279
+ - one of `langchain`, `crewai`, `llama-index-core`, `google-adk`,
280
+ `agent-framework-core`, `strands-agents` (optional, only for the matching
281
+ framework adapter — see the extras above for the verified version floors)
282
+
283
+ ## License
284
+
285
+ MIT
anona-0.6.0/README.md ADDED
@@ -0,0 +1,239 @@
1
+ # Anona Memory SDK
2
+
3
+ Official SDKs for [Anona Memory](https://memory.anonalabs.com) — managed AI memory for intelligent agents. Record, retrieve, and reason over memories per user/space via a simple client, or auto-inject memory into LiteLLM calls with one line.
4
+
5
+ - **Python** — this repository root. Documented below.
6
+ - **TypeScript** — [`typescript/`](typescript/). Zero dependencies, runs on Node 18+, Bun, Deno, Cloudflare Workers and the browser, with adapters for the Vercel AI SDK and the OpenAI Agents SDK. See [`typescript/README.md`](typescript/README.md).
7
+
8
+ ```typescript
9
+ import { Anona } from "@anona-labs/memory";
10
+
11
+ const anona = new Anona({ apiKey: process.env.ANONA_API_KEY! });
12
+ await anona.record({ spaceId: "support", content: "Alice prefers email" });
13
+ const hits = await anona.retrieve({ spaceId: "support", query: "how to contact Alice" });
14
+ ```
15
+
16
+ ```bash
17
+ npm install @anona-labs/memory
18
+ ```
19
+
20
+ ## Install
21
+
22
+ Install directly from GitHub:
23
+
24
+ ```bash
25
+ pip install git+https://github.com/anonalabs/Anona-Memory-SDK.git
26
+ ```
27
+
28
+ With the LiteLLM integration (or `mcp` for the MCP server):
29
+
30
+ ```bash
31
+ pip install "anona[litellm] @ git+https://github.com/anonalabs/Anona-Memory-SDK.git"
32
+ ```
33
+
34
+ > The package is not yet on PyPI, so install from the Git URL above. Once it's
35
+ > published, `pip install anona` will also work.
36
+
37
+ ## Quickstart
38
+
39
+ ```python
40
+ from anona import AnonaClient
41
+
42
+ # base_url defaults to https://api.anonalabs.com — pass it only to override.
43
+ client = AnonaClient(api_key="anona_live_...")
44
+
45
+ # Record a memory
46
+ client.record(space_id="space_123", content="User prefers dark mode.")
47
+
48
+ # Retrieve memories
49
+ results = client.retrieve(space_id="space_123", query="UI preferences", limit=5)
50
+ for r in results:
51
+ print(r["relevance_score"], r["content"])
52
+
53
+ # Reason: a synthesized insight across memories
54
+ summary = client.reason(space_id="space_123", query="What do we know about this user?")
55
+ print(summary)
56
+
57
+ client.close()
58
+ ```
59
+
60
+ ### Async ingestion (don't block on a write)
61
+
62
+ Recording runs fact extraction, so a normal `record()` takes a moment. In a
63
+ chat loop or any latency-sensitive path, queue the write with `background=True`
64
+ and poll the returned job instead:
65
+
66
+ ```python
67
+ import time
68
+
69
+ job = client.record(
70
+ space_id="space_123",
71
+ content="User prefers dark mode.",
72
+ background=True, # returns a job_id, doesn't wait
73
+ )
74
+
75
+ while True:
76
+ status = client.get_job(space_id="space_123", job_id=job["job_id"])
77
+ if status["status"] in ("completed", "failed", "cancelled", "not_found"):
78
+ break
79
+ time.sleep(2)
80
+
81
+ # Backfill many memories at once (always queued, up to 100 per call):
82
+ batch = client.record_batch(
83
+ space_id="space_123",
84
+ items=[
85
+ {"content": "User is on the Pro plan."},
86
+ {"content": "Signed up in 2024.", "timestamp": "2024-03-01T00:00:00Z"},
87
+ ],
88
+ )
89
+ print(batch["accepted"], "queued as job", batch["job_id"])
90
+ ```
91
+
92
+ Async variants (`async_record`, `async_retrieve`, `async_reason`) are available on the same client, or use it as a context manager:
93
+
94
+ ```python
95
+ async with AnonaClient(api_key="...") as client:
96
+ await client.async_record(space_id="space_123", content="...")
97
+ ```
98
+
99
+ ## API
100
+
101
+ ### `AnonaClient(api_key, base_url="https://api.anonalabs.com")`
102
+
103
+ - `record(space_id, content, metadata=None, background=False) -> dict` — store a memory; `background=True` queues it and returns a `job_id`
104
+ - `record_batch(space_id, items) -> dict` — bulk-ingest up to 100 items (always queued); returns a `job_id`
105
+ - `get_job(space_id, job_id) -> dict` — poll a queued job's status (free); `status` is one of pending / processing / completed / failed / cancelled / not_found
106
+ - `retrieve(space_id, query, limit=10) -> list[dict]`
107
+ - `reason(space_id, query) -> str | None`
108
+ - `list_spaces() -> list[dict]`
109
+ - `upload_file(space_id, file, *, filename=None, strategy=None, tags=None) -> dict` — upload a file (path / bytes / file-like) so retrieval can draw on its content; ingested asynchronously, returns `job_ids`. PDF, DOCX, PPTX, XLSX, images (OCR), HTML, TXT/MD, CSV, audio. Files over 25 MB are rejected client-side.
110
+ - `list_documents(space_id, limit=100, offset=0) -> list[dict]`
111
+ - `delete_document(space_id, document_id) -> None` — remove a document and the memories extracted from it
112
+ - `get_graph(space_id, limit=500, min_count=1) -> dict` — entity relationship graph (nodes + co-occurrence edges)
113
+ - `list_entities(space_id, limit=100, offset=0) -> list[dict]`
114
+ - `get_entity(space_id, entity_id) -> dict` — one entity + its observations
115
+ - `async_record(...)`, `async_record_batch(...)`, `async_get_job(...)`, `async_retrieve(...)`, `async_reason(...)`, `async_list_spaces(...)`, `async_upload_file(...)`, `async_list_documents(...)`, `async_delete_document(...)`, `async_get_graph(...)`, `async_list_entities(...)`, `async_get_entity(...)` — async equivalents
116
+ - `close()` / `aclose()` — release underlying HTTP clients
117
+
118
+ Errors raise `AnonaError(status_code, detail)`.
119
+
120
+ ## Framework adapters
121
+
122
+ Anona plugs into the Python agent frameworks through optional extras. Every
123
+ adapter handles recall and storage for you, and scopes memories per end user.
124
+
125
+ | Framework | Install | Import |
126
+ | --- | --- | --- |
127
+ | LangChain / LangGraph | `pip install 'anona[langchain]'` | `anona.integrations.langchain` |
128
+ | CrewAI | `pip install 'anona[crewai]'` | `anona.integrations.crewai` |
129
+ | LlamaIndex | `pip install 'anona[llamaindex]'` | `anona.integrations.llamaindex` |
130
+ | Google ADK | `pip install 'anona[adk]'` | `anona.integrations.google_adk` |
131
+ | Microsoft Agent Framework | `pip install 'anona[msagent]'` | `anona.integrations.ms_agent` |
132
+ | AWS Strands | `pip install 'anona[strands]'` | `anona.integrations.strands` |
133
+
134
+ All six are built on one `MemoryBridge`, which owns scope resolution and the
135
+ failure contract:
136
+
137
+ ```python
138
+ from anona.integrations import MemoryBridge
139
+ from anona.integrations.langchain import AnonaMemory
140
+
141
+ bridge = MemoryBridge(
142
+ api_key="anona_live_...",
143
+ space_id="my-space",
144
+ user_id="customer-42", # optional scope: this user's memories only
145
+ )
146
+
147
+ agent = create_agent(model="gpt-4o-mini", middleware=[AnonaMemory(bridge=bridge)])
148
+ ```
149
+
150
+ **Memory failures never raise into your agent.** A failed recall or store is
151
+ logged and the agent runs on without memory, rather than taking your
152
+ application down.
153
+
154
+ Each adapter's own module docstring documents its scoping, failure behaviour
155
+ and per-call cost. Full docs: https://docs.anonalabs.com/integrations/langchain
156
+
157
+ Runnable end-to-end scripts for all six live in [`examples/`](examples/).
158
+
159
+ ## LiteLLM integration
160
+
161
+ Auto-inject relevant memories into every `litellm.completion()` call, and auto-store the resulting Q&A pair:
162
+
163
+ ```python
164
+ from anona.integrations.litellm import AnonaMemory
165
+
166
+ mem = AnonaMemory(
167
+ api_key="anona_live_...",
168
+ space_id="space_123",
169
+ recall_limit=5, # how many memories to retrieve per call
170
+ inject_mode="system", # "system" or "user"
171
+ store_after=True, # auto-store the exchange after each call
172
+ )
173
+ mem.enable()
174
+
175
+ # All subsequent litellm.completion() calls now auto-recall + auto-store.
176
+ import litellm
177
+ litellm.completion(model="gpt-4o", messages=[{"role": "user", "content": "..."}])
178
+ ```
179
+
180
+ ## MCP server
181
+
182
+ The SDK ships an [MCP](https://modelcontextprotocol.io) server so any MCP client
183
+ — Claude Desktop, Claude Code, Cursor — can read and write Anona memory as native
184
+ tools: `record`, `retrieve`, `list_spaces`, and `reason`.
185
+
186
+ Install the extra:
187
+
188
+ ```bash
189
+ pip install "anona[mcp] @ git+https://github.com/anonalabs/Anona-Memory-SDK.git"
190
+ ```
191
+
192
+ **Claude Desktop / Cursor** — add to `claude_desktop_config.json` (or
193
+ `~/.cursor/mcp.json`), then restart:
194
+
195
+ ```json
196
+ {
197
+ "mcpServers": {
198
+ "anona": {
199
+ "command": "uvx",
200
+ "args": [
201
+ "--from",
202
+ "anona[mcp] @ git+https://github.com/anonalabs/Anona-Memory-SDK.git",
203
+ "anona-mcp"
204
+ ],
205
+ "env": {
206
+ "ANONA_API_KEY": "anona_live_...",
207
+ "ANONA_SPACE_ID": "space_123"
208
+ }
209
+ }
210
+ }
211
+ }
212
+ ```
213
+
214
+ **Claude Code** — one command:
215
+
216
+ ```bash
217
+ claude mcp add anona \
218
+ --env ANONA_API_KEY=anona_live_... \
219
+ --env ANONA_SPACE_ID=space_123 \
220
+ -- uvx --from "anona[mcp] @ git+https://github.com/anonalabs/Anona-Memory-SDK.git" anona-mcp
221
+ ```
222
+
223
+ `ANONA_SPACE_ID` sets the default space so you can just say "remember this"
224
+ without naming one; override it per call with the `space_id` argument. The key
225
+ is personal — the server only reaches spaces you are a member of.
226
+
227
+ ## Requirements
228
+
229
+ - Python >= 3.10
230
+ - `httpx >= 0.24`
231
+ - `litellm >= 1.0` (optional, only for the LiteLLM integration)
232
+ - `mcp >= 1.2` (optional, only for the MCP server)
233
+ - one of `langchain`, `crewai`, `llama-index-core`, `google-adk`,
234
+ `agent-framework-core`, `strands-agents` (optional, only for the matching
235
+ framework adapter — see the extras above for the verified version floors)
236
+
237
+ ## License
238
+
239
+ MIT
@@ -0,0 +1,4 @@
1
+ from .client import AnonaClient, AnonaError
2
+
3
+ __all__ = ["AnonaClient", "AnonaError"]
4
+ __version__ = "0.6.0"