Skip to content

Commit c37f74f

Browse files
Python: Add Azure Cosmos history provider package (microsoft#4271)
* Created cosmos history provider * add marker * Python: address Cosmos PR feedback - address provider/test/sample review feedback and cleanup typing - add cosmos integration test coverage and skip gating - add dedicated cosmos emulator jobs to python merge/integration workflows - switch cosmos workflow execution to package poe integration-tests task Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: handle empty Cosmos session id - replace default partition fallback for empty session_id - log warning and generate GUID when session_id is empty - update unit tests to validate GUID fallback behavior Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix sample * fix cross partition query --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 945933c commit c37f74f

14 files changed

Lines changed: 1622 additions & 451 deletions

File tree

.github/workflows/python-integration-tests.yml

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,51 @@ jobs:
247247
timeout-minutes: 15
248248
run: uv run --directory packages/azure-ai poe integration-tests -n logical --dist worksteal --timeout=120 --session-timeout=900 --timeout_method thread --retries 2 --retry-delay 5
249249

250+
# Azure Cosmos integration tests
251+
python-tests-cosmos:
252+
name: Python Integration Tests - Cosmos
253+
runs-on: ubuntu-latest
254+
environment: integration
255+
timeout-minutes: 60
256+
services:
257+
cosmosdb:
258+
image: mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator:vnext-preview
259+
ports:
260+
- 8081:8081
261+
env:
262+
AZURE_COSMOS_ENDPOINT: "http://localhost:8081/"
263+
# Static Azure Cosmos DB emulator key (documented): https://learn.microsoft.com/en-us/azure/cosmos-db/emulator
264+
AZURE_COSMOS_KEY: "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw=="
265+
AZURE_COSMOS_DATABASE_NAME: "agent-framework-cosmos-it-db"
266+
AZURE_COSMOS_CONTAINER_NAME: "agent-framework-cosmos-it-container"
267+
defaults:
268+
run:
269+
working-directory: python
270+
steps:
271+
- uses: actions/checkout@v6
272+
with:
273+
ref: ${{ inputs.checkout-ref }}
274+
persist-credentials: false
275+
- name: Set up python and install the project
276+
id: python-setup
277+
uses: ./.github/actions/python-setup
278+
with:
279+
python-version: ${{ env.UV_PYTHON }}
280+
os: ${{ runner.os }}
281+
- name: Wait for Cosmos DB emulator
282+
run: |
283+
for i in {1..60}; do
284+
if curl --silent --show-error http://localhost:8081/ > /dev/null; then
285+
echo "Cosmos DB emulator is ready."
286+
exit 0
287+
fi
288+
sleep 2
289+
done
290+
echo "Cosmos DB emulator did not become ready in time." >&2
291+
exit 1
292+
- name: Test with pytest (Cosmos integration)
293+
run: uv run --directory packages/azure-cosmos poe integration-tests -n logical --dist worksteal --timeout=120 --session-timeout=900 --timeout_method thread --retries 2 --retry-delay 5
294+
250295
python-integration-tests-check:
251296
if: always()
252297
runs-on: ubuntu-latest
@@ -257,7 +302,8 @@ jobs:
257302
python-tests-azure-openai,
258303
python-tests-misc-integration,
259304
python-tests-functions,
260-
python-tests-azure-ai
305+
python-tests-azure-ai,
306+
python-tests-cosmos
261307
]
262308
steps:
263309
- name: Fail workflow if tests failed

.github/workflows/python-merge-tests.yml

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ jobs:
3838
miscChanged: ${{ steps.filter.outputs.misc }}
3939
functionsChanged: ${{ steps.filter.outputs.functions }}
4040
azureAiChanged: ${{ steps.filter.outputs.azure-ai }}
41+
cosmosChanged: ${{ steps.filter.outputs.cosmos }}
4142
steps:
4243
- uses: actions/checkout@v6
4344
- uses: dorny/paths-filter@v3
@@ -67,6 +68,8 @@ jobs:
6768
- 'python/packages/durabletask/**'
6869
azure-ai:
6970
- 'python/packages/azure-ai/**'
71+
cosmos:
72+
- 'python/packages/azure-cosmos/**'
7073
# run only if 'python' files were changed
7174
- name: python tests
7275
if: steps.filter.outputs.python == 'true'
@@ -390,6 +393,64 @@ jobs:
390393

391394
# TODO: Add python-tests-lab
392395

396+
# Azure Cosmos integration tests
397+
python-tests-cosmos:
398+
name: Python Tests - Cosmos Integration
399+
needs: paths-filter
400+
if: >
401+
github.event_name != 'pull_request' &&
402+
needs.paths-filter.outputs.pythonChanges == 'true' &&
403+
(github.event_name != 'merge_group' ||
404+
needs.paths-filter.outputs.cosmosChanged == 'true' ||
405+
needs.paths-filter.outputs.coreChanged == 'true')
406+
runs-on: ubuntu-latest
407+
environment: integration
408+
services:
409+
cosmosdb:
410+
image: mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator:vnext-preview
411+
ports:
412+
- 8081:8081
413+
env:
414+
AZURE_COSMOS_ENDPOINT: "http://localhost:8081/"
415+
# Static Azure Cosmos DB emulator key (documented): https://learn.microsoft.com/en-us/azure/cosmos-db/emulator
416+
AZURE_COSMOS_KEY: "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw=="
417+
AZURE_COSMOS_DATABASE_NAME: "agent-framework-cosmos-it-db"
418+
AZURE_COSMOS_CONTAINER_NAME: "agent-framework-cosmos-it-container"
419+
defaults:
420+
run:
421+
working-directory: python
422+
steps:
423+
- uses: actions/checkout@v6
424+
- name: Set up python and install the project
425+
id: python-setup
426+
uses: ./.github/actions/python-setup
427+
with:
428+
python-version: ${{ env.UV_PYTHON }}
429+
os: ${{ runner.os }}
430+
- name: Wait for Cosmos DB emulator
431+
run: |
432+
for i in {1..60}; do
433+
if curl --silent --show-error http://localhost:8081/ > /dev/null; then
434+
echo "Cosmos DB emulator is ready."
435+
exit 0
436+
fi
437+
sleep 2
438+
done
439+
echo "Cosmos DB emulator did not become ready in time." >&2
440+
exit 1
441+
- name: Test with pytest (Cosmos integration)
442+
run: uv run --directory packages/azure-cosmos poe integration-tests -n logical --dist worksteal --timeout=120 --session-timeout=900 --timeout_method thread --retries 2 --retry-delay 5
443+
working-directory: ./python
444+
- name: Surface failing tests
445+
if: always()
446+
uses: pmeier/pytest-results-action@v0.7.2
447+
with:
448+
path: ./python/**.xml
449+
summary: true
450+
display-options: fEX
451+
fail-on-empty: false
452+
title: Cosmos integration test results
453+
393454
python-integration-tests-check:
394455
if: always()
395456
runs-on: ubuntu-latest
@@ -401,6 +462,7 @@ jobs:
401462
python-tests-misc-integration,
402463
python-tests-functions,
403464
python-tests-azure-ai,
465+
python-tests-cosmos,
404466
]
405467
steps:
406468
- name: Fail workflow if tests failed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Azure Cosmos DB Package (agent-framework-azure-cosmos)
2+
3+
Azure Cosmos DB history provider integration for Agent Framework.
4+
5+
## Main Classes
6+
7+
- **`CosmosHistoryProvider`** - Persistent conversation history storage backed by Azure Cosmos DB
8+
9+
## Usage
10+
11+
```python
12+
from agent_framework_azure_cosmos import CosmosHistoryProvider
13+
14+
provider = CosmosHistoryProvider(
15+
endpoint="https://<account>.documents.azure.com:443/",
16+
credential="<key-or-token-credential>",
17+
database_name="agent-framework",
18+
container_name="chat-history",
19+
)
20+
```
21+
22+
Container name is configured on the provider. `session_id` is used as the partition key.
23+
24+
## Import Path
25+
26+
```python
27+
from agent_framework_azure_cosmos import CosmosHistoryProvider
28+
```
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) Microsoft Corporation.
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
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Get Started with Microsoft Agent Framework Azure Cosmos DB
2+
3+
Please install this package via pip:
4+
5+
```bash
6+
pip install agent-framework-azure-cosmos --pre
7+
```
8+
9+
## Azure Cosmos DB History Provider
10+
11+
The Azure Cosmos DB integration provides `CosmosHistoryProvider` for persistent conversation history storage.
12+
13+
### Basic Usage Example
14+
15+
```python
16+
from azure.identity.aio import DefaultAzureCredential
17+
from agent_framework_azure_cosmos import CosmosHistoryProvider
18+
19+
provider = CosmosHistoryProvider(
20+
endpoint="https://<account>.documents.azure.com:443/",
21+
credential=DefaultAzureCredential(),
22+
database_name="agent-framework",
23+
container_name="chat-history",
24+
)
25+
```
26+
27+
Credentials follow the same pattern used by other Azure connectors in the repository:
28+
29+
- Pass a credential object (for example `DefaultAzureCredential`)
30+
- Or pass a key string directly
31+
- Or set `AZURE_COSMOS_KEY` in the environment
32+
33+
Container naming behavior:
34+
35+
- Container name is configured on the provider (`container_name` or `AZURE_COSMOS_CONTAINER_NAME`)
36+
- `session_id` is used as the Cosmos partition key for reads/writes
37+
38+
See `samples/cosmos_history_provider.py` for a runnable package-local example.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Copyright (c) Microsoft. All rights reserved.
2+
3+
import importlib.metadata
4+
5+
from ._history_provider import CosmosHistoryProvider
6+
7+
try:
8+
__version__ = importlib.metadata.version(__name__)
9+
except importlib.metadata.PackageNotFoundError:
10+
__version__ = "0.0.0" # Fallback for development mode
11+
12+
__all__ = [
13+
"CosmosHistoryProvider",
14+
"__version__",
15+
]

0 commit comments

Comments
 (0)