Skip to content

Commit 4dea57d

Browse files
authored
Merge pull request #2 from aayush3011/users/akataria/asyncFixes
Code refactoring, async code fixes and error handling
2 parents 6eb3a1d + d73d0a2 commit 4dea57d

40 files changed

Lines changed: 8106 additions & 1762 deletions

.github/workflows/ci.yml

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
permissions:
10+
contents: read
11+
12+
jobs:
13+
lint:
14+
runs-on: ubuntu-latest
15+
strategy:
16+
matrix:
17+
python-version: ["3.11", "3.12", "3.13"]
18+
steps:
19+
- uses: actions/checkout@v4
20+
- uses: actions/setup-python@v5
21+
with:
22+
python-version: ${{ matrix.python-version }}
23+
- name: Install dependencies
24+
run: pip install ruff
25+
- name: Ruff check
26+
run: ruff check agent_memory_toolkit/ tests/
27+
- name: Ruff format check
28+
run: ruff format --check agent_memory_toolkit/ tests/
29+
30+
test:
31+
runs-on: ubuntu-latest
32+
strategy:
33+
matrix:
34+
python-version: ["3.11", "3.12", "3.13"]
35+
steps:
36+
- uses: actions/checkout@v4
37+
- uses: actions/setup-python@v5
38+
with:
39+
python-version: ${{ matrix.python-version }}
40+
- name: Install package with dev dependencies
41+
run: pip install -e ".[dev]"
42+
- name: Run unit tests with coverage
43+
run: pytest tests/unit/ --cov=agent_memory_toolkit --cov-report=xml --cov-report=term-missing -v
44+
- name: Upload coverage
45+
if: always()
46+
uses: actions/upload-artifact@v4
47+
with:
48+
name: coverage-report-${{ matrix.python-version }}
49+
path: coverage.xml

Docs/azure_testing.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@ You need:
2222

2323
- an Azure subscription
2424
- `az login`
25-
- Python 3.10+
25+
- Python 3.11+
2626
- Azure Functions Core Tools v4
2727
- dependencies installed:
2828

2929
```bash
30-
pip install -r requirements.txt
30+
pip install -e ".[dev]"
3131
pip install -r azure_functions/requirements.txt
3232
```
3333

@@ -190,7 +190,7 @@ memory.connect_cosmos()
190190
import os
191191
from dotenv import load_dotenv
192192
from azure.identity.aio import DefaultAzureCredential as AsyncDefaultAzureCredential
193-
from agent_memory_toolkit import AsyncAgentMemory
193+
from agent_memory_toolkit.aio import AsyncAgentMemory
194194

195195
load_dotenv()
196196

Docs/design_patterns.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Write a turn memory every time a user or agent message is produced. If the appli
1212

1313
```python
1414
from azure.identity.aio import DefaultAzureCredential as AsyncDefaultAzureCredential
15-
from agent_memory_toolkit import AsyncAgentMemory
15+
from agent_memory_toolkit.aio import AsyncAgentMemory
1616

1717
mem = AsyncAgentMemory(
1818
cosmos_endpoint=COSMOS_ENDPOINT,

Docs/local_testing.md

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ This guide covers the shortest path to running the library locally, then validat
1010

1111
| Tool | Install command | Purpose |
1212
|------|-----------------|---------|
13-
| Python 3.10+ | `brew install python@3.12` | Runtime |
13+
| Python 3.11+ | `brew install python@3.13` | Runtime |
1414
| Azure CLI | `brew install azure-cli` | `az login` for `DefaultAzureCredential` |
1515
| Azure Functions Core Tools v4 | `brew install azure-functions-core-tools@4` | Run Functions locally |
1616
| Azurite | `npm install -g azurite` | Local storage emulator for Functions |
@@ -19,7 +19,7 @@ This guide covers the shortest path to running the library locally, then validat
1919
### Python packages
2020

2121
```bash
22-
pip install -r requirements.txt
22+
pip install -e ".[dev]"
2323
pip install -r azure_functions/requirements.txt
2424
```
2525

@@ -168,7 +168,7 @@ for r in results:
168168
import os, uuid
169169
from dotenv import load_dotenv
170170
from azure.identity.aio import DefaultAzureCredential as AsyncDefaultAzureCredential
171-
from agent_memory_toolkit import AsyncAgentMemory
171+
from agent_memory_toolkit.aio import AsyncAgentMemory
172172

173173
load_dotenv()
174174

@@ -217,7 +217,7 @@ azurite --silent --location /tmp/azurite --debug /tmp/azurite/debug.log
217217

218218
```bash
219219
cd azure_functions
220-
pip install -r requirements.txt
220+
pip install -r azure_functions/requirements.txt
221221
func start
222222
```
223223

@@ -324,7 +324,7 @@ User summaries also update incrementally when one already exists.
324324

325325
| Problem | Fix |
326326
|---------|-----|
327-
| `ImportError: azure.identity` | Run `pip install -r requirements.txt` |
327+
| `ImportError: azure.identity` | Run `pip install -e ".[dev]"` |
328328
| `DefaultAzureCredential` fails | Run `az login` and confirm the active subscription |
329329
| Cosmos 403 | Check Cosmos DB RBAC and wait for propagation |
330330
| `func: command not found` | Install Azure Functions Core Tools v4 |
@@ -334,6 +334,3 @@ User summaries also update incrementally when one already exists.
334334
| Function 401 in Azure | Set `ADF_KEY` or pass `?code=<key>` |
335335

336336
For full cloud deployment and validation, see `Docs/azure_testing.md`.
337-
| Functions host can't connect to storage | Make sure Azurite is running before starting `func start` |
338-
| Embeddings 401/403 | Confirm the "Cognitive Services OpenAI User" role is assigned to your identity on the AI resource |
339-
| Functions 401 Unauthorized | The HTTP trigger requires a function key. Pass it as `?code=<key>` in the URL or set `ADF_KEY` in `.env`. See "Get the function key" above. |

README.md

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Azure Cosmos DB Agent Memory Toolkit
22

33
[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT)
4-
[![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/downloads/)
4+
[![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)
55
[![Azure Cosmos DB](https://img.shields.io/badge/Azure-Cosmos%20DB-0078D4?logo=microsoft-azure)](https://azure.microsoft.com/en-us/products/cosmos-db/)
66
[![Follow on X](https://img.shields.io/twitter/follow/AzureCosmosDB?style=social)](https://twitter.com/AzureCosmosDB)
77
[![LinkedIn](https://img.shields.io/badge/LinkedIn-Azure%20Cosmos%20DB-0077B5?logo=linkedin)](https://www.linkedin.com/showcase/azure-cosmos-db/)
@@ -71,11 +71,24 @@ Agent Memory Toolkit is a Python library and Azure-backed reference implementati
7171
## Project Structure
7272

7373
```
74-
agent_memory_toolkit/ Python library — AgentMemory (sync) + AsyncAgentMemory (async)
74+
agent_memory_toolkit/ Python library — sync API
75+
memory.py AgentMemory orchestrator
76+
cosmos_memory_client.py CosmosMemoryStore — Cosmos DB CRUD + vector search
77+
embeddings.py EmbeddingsClient — Azure OpenAI embeddings
78+
processing.py ProcessingClient — Durable Functions polling
79+
models.py Pydantic data models (MemoryRecord, enums)
80+
exceptions.py Custom exception hierarchy
81+
_query_builder.py Shared query builder (private)
82+
aio/ Async API (mirrors azure.cosmos.aio convention)
83+
memory.py AsyncAgentMemory
84+
cosmos_memory_client.py AsyncCosmosMemoryStore
85+
embeddings.py AsyncEmbeddingsClient
86+
processing.py AsyncProcessingClient
7587
azure_functions/ Durable Functions — orchestrator, activities, HTTP trigger
7688
prompts/ LLM system prompts — summarize, facts, user_summary + update variants
7789
Samples/ Demo notebooks — sync (Demo.ipynb) + async (Demo_async.ipynb)
7890
Docs/ Documentation — concepts, local testing, Azure deployment
91+
tests/ Unit tests (pytest) — 184 tests, 87% coverage
7992
```
8093

8194
---
@@ -85,7 +98,10 @@ Docs/ Documentation — concepts, local testing, Azure
8598
### 1. Install
8699

87100
```bash
88-
pip install -r requirements.txt
101+
pip install .
102+
103+
# With dev/test dependencies
104+
pip install ".[dev]"
89105
```
90106

91107
### 2. Local-only (no Azure)
@@ -156,7 +172,11 @@ result = memory.generate_user_summary(user_id="user-001")
156172
summary = memory.get_user_summary(user_id="user-001")
157173
```
158174

159-
> The async API (`AsyncAgentMemory`) is identical — just `await` each call.
175+
> The async API (`AsyncAgentMemory`) is identical — just `await` each call. Import from the `aio` subpackage:
176+
>
177+
> ```python
178+
> from agent_memory_toolkit.aio import AsyncAgentMemory
179+
> ```
160180
161181
---
162182

Samples/Demo_async.ipynb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
"sys.path.insert(0, os.path.abspath(\"..\"))\n",
4444
"\n",
4545
"from dotenv import load_dotenv\n",
46-
"from agent_memory_toolkit import AsyncAgentMemory\n",
46+
"from agent_memory_toolkit.aio import AsyncAgentMemory\n",
4747
"\n",
4848
"# Load environment variables from .env in the repo root\n",
4949
"load_dotenv(os.path.join(\"..\", \".env\"))\n",

agent_memory_toolkit/__init__.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,25 @@
11
"""Agent Memory Toolkit – local and cloud agent memory management."""
22

3+
from agent_memory_toolkit.aio import AsyncAgentMemory
4+
from agent_memory_toolkit.exceptions import (
5+
AgentMemoryError,
6+
AuthenticationError,
7+
ConfigurationError,
8+
CosmosNotConnectedError,
9+
CosmosOperationError,
10+
EmbeddingError,
11+
MemoryNotFoundError,
12+
OrchestrationTimeoutError,
13+
ProcessingError,
14+
ValidationError,
15+
)
316
from agent_memory_toolkit.memory import AgentMemory
4-
from agent_memory_toolkit.async_memory import AsyncAgentMemory
17+
from agent_memory_toolkit.models import MemoryRecord, MemoryRole, MemoryType, SearchResult
518

6-
__all__ = ["AgentMemory", "AsyncAgentMemory"]
19+
__all__ = [
20+
"AgentMemory", "AsyncAgentMemory",
21+
"MemoryRecord", "MemoryRole", "MemoryType", "SearchResult",
22+
"AgentMemoryError", "ConfigurationError", "ValidationError",
23+
"CosmosNotConnectedError", "CosmosOperationError", "MemoryNotFoundError",
24+
"EmbeddingError", "ProcessingError", "OrchestrationTimeoutError", "AuthenticationError",
25+
]
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
"""Reusable query-builder for parameterized Cosmos DB queries.
2+
3+
The :class:`_QueryBuilder` helper eliminates duplicated
4+
condition/parameter-building patterns across the sync and async clients.
5+
"""
6+
7+
from __future__ import annotations
8+
9+
from typing import Any
10+
11+
12+
class _QueryBuilder:
13+
"""Accumulates optional WHERE conditions and their parameterized values.
14+
15+
Usage::
16+
17+
qb = _QueryBuilder()
18+
qb.add_filter("c.user_id", "@user_id", some_user_id)
19+
qb.add_filter("c.role", "@role", some_role)
20+
where = qb.build_where() # " WHERE c.user_id = @user_id AND c.role = @role"
21+
params = qb.get_parameters() # [{"name": "@user_id", "value": ...}, ...]
22+
"""
23+
24+
def __init__(self) -> None:
25+
self._conditions: list[str] = []
26+
self._parameters: list[dict[str, Any]] = []
27+
28+
def add_filter(self, field: str, param_name: str, value: Any) -> None:
29+
"""Add a filter only when *value* is not ``None``."""
30+
if value is None:
31+
return
32+
self._conditions.append(f"{field} = {param_name}")
33+
self._parameters.append({"name": param_name, "value": value})
34+
35+
def build_where(self) -> str:
36+
"""Return the ``WHERE …`` clause (or empty string if no filters)."""
37+
if not self._conditions:
38+
return ""
39+
return " WHERE " + " AND ".join(self._conditions)
40+
41+
def get_parameters(self) -> list[dict[str, Any]]:
42+
"""Return a *copy* of the accumulated parameters list."""
43+
return list(self._parameters)

0 commit comments

Comments
 (0)