Skip to content

Commit 4c2c11d

Browse files
committed
addressed Copilot review items
1 parent 3b76267 commit 4c2c11d

3 files changed

Lines changed: 96 additions & 39 deletions

File tree

Docs/troubleshooting.md

Lines changed: 47 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ Use this guide when local memory works but Cosmos DB, embeddings, Durable Functi
99
| Symptom | First checks |
1010
|---------|--------------|
1111
| Import errors | Install with `pip install -e ".[dev]"` and import `CosmosMemoryClient` or `AsyncCosmosMemoryClient`. |
12-
| Missing configuration | Verify `.env`, `azure_functions/local.settings.json`, and Azure Function App settings use the same endpoint, database, and container values. |
12+
| Missing configuration | Verify `.env`, `function_app/local.settings.json`, and Azure Function App settings use the same endpoint, database, container, and AI deployment values. |
1313
| Cosmos 401 or 403 | Run `az login` and confirm Cosmos DB data-plane RBAC is assigned. |
1414
| Cosmos operations fail before connecting | Call `create_memory_store()` or `connect_cosmos()` before cloud operations. |
15-
| Search returns no vector results | Confirm embeddings are generated and `EMBEDDING_DIMENSIONS` matches the container vector policy. |
16-
| Durable Function calls fail | Start the Functions host and check `ADF_ENDPOINT`, `ADF_KEY`, and the orchestrator route. |
15+
| Search returns no vector results | Confirm embeddings are generated and `AI_FOUNDRY_EMBEDDING_DIMENSIONS` matches the container vector policy. |
16+
| Durable Functions processing fails | Start the Functions host and check `function_app/local.settings.json`, the change feed trigger, and the orchestrator logs. |
1717
| Change feed does not create summaries or facts | Confirm change feed settings, thresholds, lease container, counter container, and that inserted documents have `type: "turn"`. |
1818

1919
---
@@ -24,7 +24,7 @@ Install the package from the repository root:
2424

2525
```bash
2626
pip install -e ".[dev]"
27-
pip install -r azure_functions/requirements.txt
27+
pip install -r function_app/requirements.txt
2828
```
2929

3030
The public clients are:
@@ -40,21 +40,45 @@ If notebooks cannot import the package, run them from the repo root with paths s
4040

4141
## 2. Configuration And Authentication
4242

43-
For local runs, keep `.env` and `azure_functions/local.settings.json` aligned:
43+
For local runs, keep `.env`, `function_app/local.settings.json`, and deployed Function App settings aligned:
4444

4545
```env
4646
COSMOS_DB_ENDPOINT=https://<account>.documents.azure.com:443/
47+
COSMOS_DB__accountEndpoint=https://<account>.documents.azure.com:443/
48+
COSMOS_DB_KEY=
4749
COSMOS_DB_DATABASE=ai_memory
4850
COSMOS_DB_CONTAINER=memories
4951
COSMOS_DB_COUNTERS_CONTAINER=counter
5052
COSMOS_DB_LEASE_CONTAINER=leases
51-
AI_FOUNDRY_ENDPOINT=https://<project>.services.ai.azure.com/
52-
EMBEDDING_MODEL=text-embedding-3-large
53-
EMBEDDING_DIMENSIONS=1536
54-
ADF_ENDPOINT=http://localhost:7071/api
55-
ADF_KEY=
53+
COSMOS_DB_THROUGHPUT_MODE=serverless
54+
COSMOS_DB_AUTOSCALE_MAX_RU=1000
55+
56+
AI_FOUNDRY_ENDPOINT=https://<account>.openai.azure.com/
57+
AI_FOUNDRY_API_KEY=
58+
AI_FOUNDRY_EMBEDDING_DEPLOYMENT_NAME=text-embedding-3-large
59+
AI_FOUNDRY_EMBEDDING_DIMENSIONS=1536
60+
AI_FOUNDRY_EMBEDDING_DATA_TYPE=float32
61+
AI_FOUNDRY_EMBEDDING_DISTANCE_FUNCTION=cosine
62+
AI_FOUNDRY_CHAT_DEPLOYMENT_NAME=<chat-deployment-name>
5663
```
5764

65+
The notebooks and samples pass these values into the client like this:
66+
67+
| `.env` setting | Client argument |
68+
|---|---|
69+
| `COSMOS_DB_ENDPOINT` | `cosmos_endpoint` |
70+
| `COSMOS_DB_DATABASE` | `cosmos_database` |
71+
| `COSMOS_DB_CONTAINER` | `cosmos_container` |
72+
| `COSMOS_DB_COUNTERS_CONTAINER` | `cosmos_counter_container` |
73+
| `COSMOS_DB_LEASE_CONTAINER` | `cosmos_lease_container` |
74+
| `COSMOS_DB_KEY` | `cosmos_key` |
75+
| `AI_FOUNDRY_ENDPOINT` | `ai_foundry_endpoint` |
76+
| `AI_FOUNDRY_API_KEY` | `ai_foundry_api_key` |
77+
| `AI_FOUNDRY_EMBEDDING_DEPLOYMENT_NAME` | `embedding_deployment_name` |
78+
| `AI_FOUNDRY_CHAT_DEPLOYMENT_NAME` | `chat_deployment_name` |
79+
80+
`AI_FOUNDRY_EMBEDDING_DIMENSIONS`, `AI_FOUNDRY_EMBEDDING_DATA_TYPE`, and `AI_FOUNDRY_EMBEDDING_DISTANCE_FUNCTION` are read by the toolkit when creating the Cosmos DB vector policy. The Function App also reads `COSMOS_DB__accountEndpoint` for its identity-based Cosmos DB trigger binding; set it to the same value as `COSMOS_DB_ENDPOINT`.
81+
5882
Run `az login` before using `DefaultAzureCredential`.
5983

6084
Required roles:
@@ -89,8 +113,8 @@ Use `COSMOS_DB_THROUGHPUT_MODE=serverless` for the default setup. Use `autoscale
89113
Embedding failures usually mean one of these is wrong:
90114

91115
- `AI_FOUNDRY_ENDPOINT`
92-
- `EMBEDDING_MODEL`
93-
- `EMBEDDING_DIMENSIONS`
116+
- `AI_FOUNDRY_EMBEDDING_DEPLOYMENT_NAME`
117+
- `AI_FOUNDRY_EMBEDDING_DIMENSIONS`
94118
- Azure OpenAI / AI Services RBAC
95119

96120
For hybrid search, `search_terms` is required when `hybrid_search=True`.
@@ -101,23 +125,17 @@ If search returns documents but scores look poor, check that records have an `em
101125

102126
## 5. Durable Functions Processing
103127

104-
Thread summaries, fact extraction, and user summaries require the Functions host.
128+
Durable Functions processing requires the Functions host.
105129

106130
Start local dependencies:
107131

108132
```bash
109133
azurite --silent --location /tmp/azurite --debug /tmp/azurite/debug.log
110-
cd azure_functions
134+
cd function_app
111135
func start
112136
```
113137

114-
The SDK posts to:
115-
116-
```text
117-
<ADF_ENDPOINT>/orchestrators/memory_orchestrator
118-
```
119-
120-
For local testing, `ADF_ENDPOINT` is usually `http://localhost:7071/api` and `ADF_KEY` is blank. For Azure, use the deployed Function App URL and set `ADF_KEY` if function-key auth is enabled.
138+
The SDK does not post to a Function endpoint. With `DurableFunctionProcessor`, the SDK writes turns to Cosmos DB and the deployed Function App picks them up from the Cosmos DB change feed. For local testing, keep `function_app/local.settings.json` aligned with `.env` and confirm the Functions host starts the change feed trigger.
121139

122140
If orchestration polling times out, check the Functions logs first. The orchestration may still be running, or an activity may be waiting on Cosmos DB or the LLM endpoint.
123141

@@ -129,24 +147,30 @@ Automatic processing requires these settings in the Functions app or `local.sett
129147

130148
```json
131149
"COSMOS_DB__accountEndpoint": "https://<account>.documents.azure.com:443/",
150+
"COSMOS_DB_ENDPOINT": "https://<account>.documents.azure.com:443/",
151+
"COSMOS_DB_DATABASE": "ai_memory",
152+
"COSMOS_DB_CONTAINER": "memories",
132153
"COSMOS_DB_COUNTERS_CONTAINER": "counter",
133154
"COSMOS_DB_LEASE_CONTAINER": "leases",
155+
"AI_FOUNDRY_ENDPOINT": "https://<account>.openai.azure.com/",
156+
"AI_FOUNDRY_CHAT_DEPLOYMENT_NAME": "gpt-4o-mini",
157+
"AI_FOUNDRY_EMBEDDING_DEPLOYMENT_NAME": "text-embedding-3-large",
134158
"THREAD_SUMMARY_EVERY_N": "5",
135159
"FACT_EXTRACTION_EVERY_N": "3",
136160
"USER_SUMMARY_EVERY_N": "10"
137161
```
138162

139163
Set a threshold to `"0"` to disable that processing type.
140164

141-
Only documents with `type: "turn"` increment counters. Derived memories such as `summary`, `fact`, and `user_summary` do not trigger threshold counts.
165+
Cosmos DB memory documents store their category in the JSON `type` field. Only documents with `type: "turn"` increment counters. Derived memories with `type: "summary"`, `type: "fact"`, or `type: "user_summary"` do not trigger threshold counts.
142166

143167
If nothing fires:
144168

145169
- verify the Functions host shows the Cosmos DB trigger
146170
- confirm the `leases` container exists
147171
- confirm the `counter` container is writable
148172
- insert enough new turn documents to cross the configured threshold
149-
- check for generated documents with `memory_type="summary"`, `memory_type="fact"`, or `get_user_summary(user_id=...)`
173+
- check for generated documents where the Cosmos JSON field is `type="summary"`, `type="fact"`, or `type="user_summary"`
150174

151175
---
152176

Samples/Notebooks/Demo.ipynb

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -363,10 +363,18 @@
363363
},
364364
"outputs": [],
365365
"source": [
366-
"# Delete the tool memory (index 2 – the tool call)\n",
367-
"tool_memory_id = memory.local_memory[2][\"id\"]\n",
368-
"print(f\"Deleting memory {tool_memory_id[:8]}...\")\n",
369-
"memory.delete_local(tool_memory_id)\n",
366+
"# Delete the user's booking request by role/content instead of a fixed index\n",
367+
"booking_requests = [\n",
368+
" m for m in memory.get_local(user_id=USER_ID, role=\"user\")\n",
369+
" if \"book a trip to Seattle\" in m[\"content\"]\n",
370+
"]\n",
371+
"if not booking_requests:\n",
372+
" raise ValueError(\"Expected to find the user's Seattle booking request.\")\n",
373+
"\n",
374+
"delete_target = booking_requests[0]\n",
375+
"delete_target_id = delete_target[\"id\"]\n",
376+
"print(f\"Deleting user memory {delete_target_id[:8]}... {delete_target['content'][:60]}\")\n",
377+
"memory.delete_local(delete_target_id)\n",
370378
"\n",
371379
"# Verify it's gone\n",
372380
"print(f\"\\nRemaining memories: {len(memory.get_local())}\")\n",

Samples/Notebooks/Demo_async.ipynb

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@
237237
},
238238
{
239239
"cell_type": "code",
240-
"execution_count": null,
240+
"execution_count": 15,
241241
"id": "942e3714",
242242
"metadata": {
243243
"ExecuteTime": {
@@ -251,20 +251,45 @@
251251
"shell.execute_reply": "2026-05-04T20:25:45.663296Z"
252252
}
253253
},
254-
"outputs": [],
254+
"outputs": [
255+
{
256+
"name": "stdout",
257+
"output_type": "stream",
258+
"text": [
259+
"Total memories: 19\n",
260+
"\n",
261+
"Memories for user-68421be1: 19\n",
262+
"Agent memories: 10\n",
263+
" [4d27c469...] This weekend Seattle will be around 55°F with partly cloudy \n",
264+
" [5991e394...] Sure! I found round-trip flights departing Friday evening an\n",
265+
" [ae314a6e...] I found a round-trip on Alaska Airlines for $275 and two hot\n",
266+
" [bc5681e4...] Got it. I'll always select an aisle seat for your bookings.\n",
267+
" [eccd2557...] Noted — I'll follow that order: weather, then flights, then \n",
268+
" [d2109708...] Will do — no overnight bookings without your explicit approv\n",
269+
" [f0fd3216...] Got it. I'll always select an aisle seat for your bookings.\n",
270+
" [d90de470...] Noted — I'll follow that order: weather, then flights, then \n",
271+
" [5156acad...] Will do — no overnight bookings without your explicit approv\n",
272+
" [5ba8a11c...] Understood — only hotels with complimentary breakfast.\n",
273+
"\n",
274+
"Fact memories: 0\n",
275+
"\n",
276+
"Agent memories for user-68421be1: 10\n"
277+
]
278+
}
279+
],
255280
"source": [
256281
"# Get all memories\n",
257282
"all_memories = memory.get_local()\n",
258283
"print(f\"Total memories: {len(all_memories)}\\n\")\n",
259284
"\n",
260285
"# Filter by user_id\n",
261-
"user1_memories = memory.get_local(user_id=USER_ID)\n",
262-
"print(f\"Memories for user-001: {len(user1_memories)}\")\n",
286+
"user_memories = memory.get_local(user_id=USER_ID)\n",
287+
"print(f\"Memories for {USER_ID}: {len(user_memories)}\")\n",
263288
"\n",
264289
"# Filter by role\n",
265-
"tool_memories = memory.get_local(role=\"agent\")\n",
266-
"print(f\"Tool memories: {len(tool_memories)}\")\n",
267-
"for m in tool_memories:\n",
290+
"agent_memories = memory.get_local(role=\"agent\")\n",
291+
"print(f\"Agent memories: {len(agent_memories)}\")\n",
292+
"for m in agent_memories:\n",
268293
" print(f\" [{m['id'][:8]}...] {m['content'][:60]}\")\n",
269294
"\n",
270295
"# Filter by type\n",
@@ -273,9 +298,9 @@
273298
"for m in facts:\n",
274299
" print(f\" [{m['id'][:8]}...] {m['content']}\")\n",
275300
"\n",
276-
"# Combine filters: user-001 + agent role\n",
277-
"user1_agent = memory.get_local(user_id=USER_ID, role=\"agent\")\n",
278-
"print(f\"\\nAgent memories for user-001: {len(user1_agent)}\")"
301+
"# Combine filters: current user + agent role\n",
302+
"user_agent_memories = memory.get_local(user_id=USER_ID, role=\"agent\")\n",
303+
"print(f\"\\nAgent memories for {USER_ID}: {len(user_agent_memories)}\")"
279304
]
280305
},
281306
{
@@ -473,9 +498,9 @@
473498
},
474499
"outputs": [],
475500
"source": [
476-
"# Get all memories for user-001\n",
501+
"# Get all memories for the current demo user\n",
477502
"results = await memory.get_memories(user_id=USER_ID)\n",
478-
"print(f\"Memories for user-001: {len(results)}\\n\")\n",
503+
"print(f\"Memories for {USER_ID}: {len(results)}\\n\")\n",
479504
"for r in results:\n",
480505
" print(f\" [{r['thread_id'][:8]}...] [{r['id'][:8]}...] role={r['role']:<6} type={r['type']:<8} {r['content'][:50]}\")\n",
481506
"\n",

0 commit comments

Comments
 (0)