Files
microsoft--agent-framework/python/packages/azure-cosmos-memory/README.md
Theo van Kraay a057cd505c Python: Add agent-framework-azure-cosmos-memory context provider (#6719)
* Add agent-framework-azure-cosmos-memory context provider (draft)

Introduces CosmosMemoryContextProvider, a ContextProvider that wraps the azure-cosmos-agent-memory toolkit to give agents long-term, Cosmos DB-backed memory (fact/procedural recall + user summaries). Includes package scaffolding, unit tests (mocked client), live Azure integration tests (marked), samples, README, and AGENTS.md.

Draft: uv.lock is intentionally left unchanged. This package depends on azure-cosmos-agent-memory (requires Python >=3.11), which is unsatisfiable against the workspace's current >=3.10 floor, so adding it to the shared lock requires a workspace decision (raise floor to 3.11 or exclude from workspace). Test coverage to be expanded.

* ci: exclude azure-cosmos-memory from uv workspace resolution

The package depends on azure-cosmos-agent-memory which requires Python
>=3.11 and a prompty pre-release (>=2.0.0a9). Both are unsatisfiable
against the workspace's >=3.10 floor and pre-release policy, causing
uv sync to fail in every Python CI job. Exclude the package from the
shared workspace so it is resolved and tested as a standalone package.

* ci: fix code-quality failures for azure-cosmos-memory

- Strip trailing whitespace from package files (pre-commit trailing-whitespace hook)
- Exclude the package README from markdown-code-lint: the package is excluded
  from the uv workspace, so its README snippets import a module that is not
  installed in the workspace env and Pyright cannot resolve it

* Exclude azure-cosmos-memory README from markdown-code-lint task

* Address PR review comments on cosmos-memory context provider

- Wire credential into Cosmos and AI Foundry clients; let toolkit own
  DefaultAzureCredential when none supplied (remove dead import).
- Honor auto_extract=False by zeroing extraction/summary cadence thresholds.
- Skip whitespace-only conversation turns and store stripped content.
- Show confidence 0.0 and coerce confidence to float in _format_memories.
- Register both 'integration' and 'azure' pytest markers accurately.
- Fix duplicated install block in README.
- Update and extend unit tests for new credential wiring and fixes.

* Include azure-cosmos-memory in the uv workspace

Follow the github_copilot pattern for a package with a Python 3.11-only
dependency: lower requires-python to >=3.10 and gate azure-cosmos-agent-memory
behind a python_version >= '3.11' marker. Add a direct, gated prompty
pre-release dependency so the workspace's if-necessary-or-explicit prerelease
policy permits the toolkit's transitive prompty requirement. Guard the test
modules with pytest.importorskip so the 3.10 CI leg skips cleanly. Remove the
workspace exclude and the markdown-code-lint exclude, and regenerate uv.lock.

* Address review feedback on cosmos-memory provider

Rename provider parameters to match Agent Framework conventions:
foundry_endpoint (was ai_foundry_endpoint) and embedding_model/chat_model
(were *_deployment_name). Move DEFAULT_* to module-level constants, type
memory_types as a Literal, use DEFAULT_CONTEXT_PROMPT as the default value,
and add ProcessorConfig/CosmosMemorySettings TypedDicts. Resolve connection
settings via agent_framework load_settings with required-field validation,
replacing the manual getenv/raise blocks. Scope user_id/thread_id to the
provider state and drop the unpreventable first-turn warning.

Rewrite the samples around Agent (not raw SessionContext), provider-scoped
state, and session-id threading; use PEP 723 inline dependencies instead of a
samples dependency group; use a plain input() loop; remove the dead custom
processor stub. Update README/AGENTS for the renamed parameters and env vars.
Add a samples ruff per-file-ignores entry now that the package is linted in CI.

* Add emulator-backed vector search integration test

Bump azure-cosmos-agent-memory to >=0.2.0b2 (adds the embeddings/chat client
injection seam) and add tests/test_emulator.py: an integration (not azure)
suite that exercises real Cosmos vector search with a quantizedFlat index
against a local Cosmos DB emulator, using deterministic in-memory fakes for
embeddings and chat so no Azure AI Foundry account or LLM is required.

To run on a stock emulator the fixture strips the toolkit's full-text index
(the provider only does pure vector search) and requests provisioned autoscale
throughput instead of serverless. The suite skips cleanly when no emulator is
reachable.

* Fix CI typing and package checks for azure-cosmos-memory

The package recently joined the uv workspace, so its source and tests are now covered by the Test Typing Checks and Package Checks gates for the first time.

tests: rename stale constructor kwargs to the current provider API (foundry_endpoint/embedding_model/chat_model); use a typed _STUB_AGENT for the unused agent param so pyright/pyrefly/ty/zuban all accept it; make processor_config values ints; assert non-None memory_client in the emulator tests.

source: relax reportUnknown*/reportOptional* for this package only (the toolkit ships no py.typed; mirrors the hosting-telegram precedent); decouple the conditional toolkit import from the annotation type; use settings.get(); fix memory_types list invariance; drop a redundant None guard; read role via getattr.

* Apply pyupgrade: single-arg AsyncGenerator in test_integration

* Make Cosmos memory extraction drain transparently on provider exit

The provider now drains in-flight background memory extraction in __aexit__, so applications no longer need to call flush() in their own control flow; the client's close() would otherwise cancel pending extraction tasks. flush() is hardened against clients that expose no usable background-task registry.

sample: interactive_chat reads input via asyncio.to_thread so the event loop stays free and background extraction runs during the session; removes the manual flush now that the provider drains on exit.

tests: add explicit transparent-extraction integration tests (emulator: after_run schedules extraction and __aexit__ drains it; live Azure: a fact is extracted and recalled in a later session with no manual flush). Emulator tests reuse a single fixed database to avoid exhausting the emulator's partition budget across runs.

* Add custom extraction-prompt seam and sample to cosmos-memory provider

Adds a prompts_dir option to CosmosMemoryContextProvider that points the Agent Memory Toolkit pipeline at a caller-supplied directory of Prompty templates, so callers can override extract_memories.prompty to control what the extraction LLM produces. The toolkit exposes no public prompts-directory seam, so the provider contains the one internal touch (swapping the pipeline's template loader after the store connects); applies to both provider-built and supplied clients.

sample: interactive_chat_custom_extraction.py - the interactive chat wired with a custom coding-assistant extraction rubric. It derives a complete prompts directory at runtime (copies the bundled templates and augments extract_memories.prompty) so it stays schema-compatible with the installed toolkit.

tests: unit tests assert the provider redirects the pipeline loader only when prompts_dir is set; an emulator integration test proves end to end that a unique marker in a custom extract_memories.prompty reaches the extraction LLM call.

* docs: document prompts_dir custom-extraction seam in cosmos-memory README

Replaces the stale, non-functional CustomMemoryProcessor snippet with the working prompts_dir approach, lists the new interactive_chat_custom_extraction.py sample, and corrects the interactive-sample feature list.

* Address review: rename _new_session, drop defensive toolkit import guard

Sample (comment): rename _new_thread to _new_session in both interactive samples (a new session is the new thread).

Provider (comment): replace the _memory_toolkit_available flag + __init__ ImportError guard with a plain guarded import that re-raises a clear ImportError, matching the github_copilot package's pattern for its 3.11-only SDK. Kept requires-python >=3.10 (bumping this one workspace member to 3.11 would force the entire uv workspace lock floor to 3.11). Tests now run importorskip before importing the package, mirroring github_copilot.

* Pass cadence via cadence_thresholds instead of mutating os.environ

* Mark package alpha and drop private naming in samples

* Require Python 3.11 and inject user summary as untrusted context

* CI: exclude azure-cosmos-memory from uv sync on Python 3.10

* Re-trigger CI (flaky external link check)

* Require chat/embedding models instead of silent defaults

* Fix pyright: narrow resolved chat/embedding models to str

---------

Co-authored-by: Theo van Kraay <thvankra@microsoft.com>
2026-07-20 09:44:11 +00:00

18 KiB

Get Started with Microsoft Agent Framework Azure Cosmos DB Memory

Please install this package via pip:

pip install agent-framework-azure-cosmos-memory --pre

Azure Cosmos DB Memory Context Provider

The Azure Cosmos DB Memory integration provides CosmosMemoryContextProvider for long-term semantic memory storage using the Azure Cosmos DB Agent Memory Toolkit.

This context provider enables:

  • Semantic memory retrieval - Facts, procedural knowledge, and episodic memories
  • Automatic memory extraction - Conversation turns are processed to extract structured knowledge
  • User profile consolidation - Cross-thread user profiles with preferences and facts
  • Memory reconciliation - Deduplication and contradiction resolution

Basic Usage Example

from azure.identity.aio import DefaultAzureCredential
from agent_framework.foundry import FoundryChatClient
from agent_framework_azure_cosmos_memory import CosmosMemoryContextProvider

# A single AI Foundry endpoint powers both memory and the chat agent
foundry_endpoint = "https://<project>.services.ai.azure.com"

# Create the memory provider
memory_provider = CosmosMemoryContextProvider(
    cosmos_endpoint="https://<account>.documents.azure.com:443/",
    cosmos_database="ai_memory",
    foundry_endpoint=foundry_endpoint,
    credential=DefaultAzureCredential(),
)

# Create an agent with memory - reuses the same AI Foundry endpoint
agent = FoundryChatClient(
    project_endpoint=foundry_endpoint,
    model="gpt-4o-mini",
    credential=DefaultAzureCredential(),
).as_agent(
    instructions="You are a helpful assistant with long-term memory.",
    context_providers=[memory_provider]
)

# Use the agent - memories are automatically stored and retrieved
session = agent.create_session()
await agent.run("I love hiking and prefer vegetarian food.", session=session)
await agent.run("What do you know about my preferences?", session=session)

Authentication Options

The provider supports the same authentication modes as other Azure integrations:

  • Managed identity / RBAC (recommended): Pass DefaultAzureCredential()
  • Connection string: Set environment variables
  • Environment variables: COSMOS_ENDPOINT, COSMOS_DATABASE, FOUNDRY_ENDPOINT

Development Setup

To avoid dependency conflicts with your system Python, it's recommended to use a virtual environment:

Option 1: Using venv (Built-in, Cross-Platform)

Bash/Linux/macOS:

# Navigate to the package directory
cd python/packages/azure-cosmos-memory

# Create virtual environment
python3 -m venv .venv

# Activate virtual environment
source .venv/bin/activate

# Install package in development mode with all dependencies
pip install -e ".[dev]"

# OPTIONAL: sample dependencies (needed for the samples). The samples also declare these
# inline via PEP 723, so you can instead run them with `uv run samples/<name>.py`.
pip install agent-framework-foundry python-dotenv

# Verify installation
python -c "from agent_framework_azure_cosmos_memory import CosmosMemoryContextProvider; print('✓ Package installed')"

PowerShell:

# Navigate to the package directory
cd python\packages\azure-cosmos-memory

# Create virtual environment
python -m venv .venv

# Activate virtual environment
.\.venv\Scripts\Activate.ps1

# If you get execution policy errors, run first:
# Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

# Install package in development mode with all dependencies
pip install -e ".[dev]"

# OPTIONAL: sample dependencies (needed for the samples). The samples also declare these
# inline via PEP 723, so you can instead run them with `uv run samples/<name>.py`.
pip install agent-framework-foundry python-dotenv

# Verify installation
python -c "from agent_framework_azure_cosmos_memory import CosmosMemoryContextProvider; print('✓ Package installed')"

To deactivate the virtual environment:

deactivate  # Works on all platforms

Option 2: Using uv (Fast Alternative)

If you have uv installed:

# Sync all dependencies including dev dependencies
uv sync --prerelease=allow

# Run samples with uv (it manages the environment for you)
uv run python samples/interactive_chat.py

How to Run the Samples

Important: Before running samples, complete the Development Setup above to create a virtual environment and install the package.

This package includes three samples demonstrating different usage patterns:

1. Basic Usage (samples/basic_usage.py) - API Demonstration

This sample shows the raw ContextProvider API by manually calling before_run() and after_run(). It demonstrates:

  • How the provider searches for memories
  • How memories are injected into context
  • How conversations are stored
  • Not a real agent - just shows the API mechanics

Run it:

Ensure your virtual environment is activated, then:

# Bash/Linux/macOS
export COSMOS_ENDPOINT="https://<your-account>.documents.azure.com:443/"
export FOUNDRY_ENDPOINT="https://<your-project>.services.ai.azure.com"
python samples/basic_usage.py
# PowerShell
$env:COSMOS_ENDPOINT="https://<your-account>.documents.azure.com:443/"
$env:FOUNDRY_ENDPOINT="https://<your-project>.services.ai.azure.com"
python samples/basic_usage.py

2. Interactive Chat (samples/interactive_chat.py) - Real Agent Integration

This sample shows real-world usage with Agent Framework. It demonstrates:

  • Full Agent Framework integration - actual chatbot you can interact with
  • Multi-turn conversations - see memories persist across sessions
  • User/thread scoping - test memory isolation
  • Interactive CLI - chat with the agent, switch users, start new threads

Prerequisites:

  1. Complete Development Setup - Create a venv and install the package with test dependencies:

    pip install -e ".[dev]"
    

    The samples declare their own dependencies via PEP 723 inline metadata, so you can also just run them with uv run samples/interactive_chat.py. To install the sample dependencies manually into your venv:

    pip install agent-framework-foundry python-dotenv
    
  2. Azure Resources - You'll need:

    • An Azure Cosmos DB account with a database (e.g., ai_memory)
    • An Azure AI Foundry project with embedding and chat deployments
    • The following deployments configured in AI Foundry:
      • text-embedding-3-large (or your preferred embedding model)
      • gpt-4o-mini (or your preferred chat model)
  3. Configure environment variables - Set these in your activated virtual environment.

    Note: A single FOUNDRY_ENDPOINT powers everything:

    • The memory provider uses it internally for embeddings + memory extraction.
    • The chat agent you talk to uses it via FoundryChatClient.

    Authentication is via DefaultAzureCredential (i.e. az login), so no API key is required.

    Bash/Linux/macOS:

    # Cosmos DB
    export COSMOS_ENDPOINT="https://<your-account>.documents.azure.com:443/"
    export COSMOS_DATABASE="ai_memory"
    
    # AI Foundry - used by BOTH the memory provider and the chat agent
    export FOUNDRY_ENDPOINT="https://<your-project>.services.ai.azure.com"
    export EMBEDDING_MODEL="text-embedding-3-large"
    export CHAT_MODEL="gpt-4o-mini"
    

    PowerShell:

    # Cosmos DB
    $env:COSMOS_ENDPOINT="https://<your-account>.documents.azure.com:443/"
    $env:COSMOS_DATABASE="ai_memory"
    
    # AI Foundry - used by BOTH the memory provider and the chat agent
    $env:FOUNDRY_ENDPOINT="https://<your-project>.services.ai.azure.com"
    $env:EMBEDDING_MODEL="text-embedding-3-large"
    $env:CHAT_MODEL="gpt-4o-mini"
    
  4. Ensure Azure authentication - The samples use DefaultAzureCredential, which tries:

    • Environment variables (service principal)
    • Managed identity (if running in Azure)
    • Azure CLI (az login)
    • Interactive browser login (fallback)

    For local development, the easiest option is: az login

  5. Run the sample (ensure your virtual environment is activated):

    Bash/Linux/macOS:

    # Make sure venv is activated (you should see (.venv) in your prompt)
    python samples/interactive_chat.py
    

    PowerShell:

    # Make sure venv is activated (you should see (.venv) in your prompt)
    python samples/interactive_chat.py
    

Interactive sample features:

  • Chat naturally and tell the assistant your preferences
  • Use /new to start a new thread (memories persist across threads)
  • Use /user <id> to switch users (test memory isolation)
  • Use /quit to exit

The interactive sample demonstrates:

  • Real agent with memory integration
  • Multi-turn conversations with memory persisting across threads
  • Multi-user and multi-thread memory scoping

3. Interactive Chat with Custom Extraction (samples/interactive_chat_custom_extraction.py)

The same interactive chat as above, but wired with a custom memory-extraction prompt so you can control what the pipeline extracts. It uses a coding-assistant rubric that classifies architectural and technical decisions as durable facts. See Custom Memory Extraction Rubric below for how the prompts_dir seam works.

Run it the same way as the interactive chat (same prerequisites and environment variables):

python samples/interactive_chat_custom_extraction.py

Custom Memory Extraction Rubric

You can control both how often memories are extracted and what gets extracted.

Control extraction cadence (processor_config)

processor_config sets how many turns pass between each pipeline step. The provider forwards these to the toolkit client via its cadence_thresholds argument (no global environment mutation); keys you omit fall back to the toolkit's environment/defaults. This applies only when the provider builds the client, so pass processor_config together with the connection arguments rather than a pre-built memory_client:

memory_provider = CosmosMemoryContextProvider(
    cosmos_endpoint=...,
    foundry_endpoint=...,
    processor_config={
        "FACT_EXTRACTION_EVERY_N": 1,    # Extract after every turn
        "DEDUP_EVERY_N": 3,              # Deduplicate every 3 extractions
        "USER_SUMMARY_EVERY_N": 5,       # Update user profile every 5 turns
        "THREAD_SUMMARY_EVERY_N": 10,    # Summarize thread every 10 turns
    },
)

Customize the extraction prompt (prompts_dir)

To change what the LLM extracts and how it classifies memories, supply your own Prompty templates via prompts_dir. When set, the toolkit's extraction and summarization steps read their templates (including extract_memories.prompty) from that directory instead of the bundled defaults:

memory_provider = CosmosMemoryContextProvider(
    cosmos_endpoint=...,
    foundry_endpoint=...,
    prompts_dir="./my_prompts",
)

The directory must contain the complete template set, since the loader resolves each template by name with no fallback to the bundled copies. The simplest way to customize just the extraction rubric is to copy the toolkit's bundled templates and edit extract_memories.prompty (keeping its inputs and JSON output schema intact). See samples/interactive_chat_custom_extraction.py for a working example that builds this directory at runtime, so the custom prompt stays compatible with the installed toolkit's schema.

Configuration

memory_provider = CosmosMemoryContextProvider(
    source_id="cosmos_memory",                    # Provider identifier
    cosmos_endpoint="https://...",                # Cosmos DB endpoint
    cosmos_database="ai_memory",                  # Database name
    foundry_endpoint="https://...",               # AI Foundry endpoint
    credential=DefaultAzureCredential(),          # Azure credential

    # Memory retrieval options
    top_k=5,                                      # Number of memories to retrieve
    min_confidence=0.7,                           # Minimum confidence score (0.0-1.0)
    memory_types=["fact", "procedural"],          # Types to retrieve

    # Processing options
    auto_extract=True,                            # Auto-extract memories after runs
    processor_config={                            # Optional processor settings
        "FACT_EXTRACTION_EVERY_N": 1,            # Extract facts every N turns
        "DEDUP_EVERY_N": 5,                      # Deduplicate every N extractions
    }
)

Memory Types

The provider retrieves four types of memories:

Type Description Default TTL
fact Declarative knowledge ("user prefers dark mode") None
procedural Behavioral rules ("always confirm before deleting") None
episodic Past experiences with context and outcomes 90 days
unclassified Memories that couldn't be confidently classified None

Each memory has a confidence score (0.0-1.0). Use min_confidence to filter low-quality extractions.

Processing Pipeline

The memory toolkit automatically:

  1. Stores conversation turns - Raw messages saved to Cosmos DB
  2. Extracts memories - LLM extracts facts, rules, and experiences
  3. Generates summaries - Thread and user-level summaries
  4. Reconciles duplicates - Merges similar memories and resolves contradictions

Processing can run:

  • In-process (default) - Zero infrastructure, suitable for prototypes and low TPS
  • Azure Functions - Scalable processing via Cosmos DB change feed

Working with Multiple Providers

Combine with other context providers for comprehensive memory:

from agent_framework import InMemoryHistoryProvider
from agent_framework_azure_cosmos import CosmosHistoryProvider
from agent_framework_azure_cosmos_memory import CosmosMemoryContextProvider

agent = client.as_agent(
    context_providers=[
        # Short-term: recent conversation
        InMemoryHistoryProvider("recent"),

        # Mid-term: persistent conversation history
        CosmosHistoryProvider(
            endpoint=cosmos_endpoint,
            credential=credential,
            database_name="agent-framework",
            container_name="chat-history",
        ),

        # Long-term: semantic memory with facts and profiles
        CosmosMemoryContextProvider(
            cosmos_endpoint=cosmos_endpoint,
            foundry_endpoint=foundry_endpoint,
            credential=credential,
        ),
    ]
)

User and Thread Scoping

Memories are scoped by user_id and thread_id:

session = agent.create_session()

# Set user_id and thread_id in the provider-scoped state (keyed by the provider's source_id)
scoped = session.state.setdefault("cosmos_memory", {})
scoped["user_id"] = "user-123"
scoped["thread_id"] = "thread-456"

await agent.run("Remember that I'm allergic to peanuts.", session=session)

If not provided, the provider uses session.session_id as both user and thread identifiers.

Advanced: Custom Processing

For fine-grained control over memory processing:

from azure.cosmos.agent_memory.aio import AsyncCosmosMemoryClient

# Create a custom memory client. To disable automatic extraction, zero the cadence thresholds
# on the client you build - the provider cannot reconfigure a client you pass in, so supplying
# a memory_client together with auto_extract=False or processor_config raises ValueError.
memory_client = AsyncCosmosMemoryClient(
    cosmos_endpoint=cosmos_endpoint,
    cosmos_database="ai_memory",
    ai_foundry_endpoint=ai_foundry_endpoint,
    use_default_credential=True,
    cadence_thresholds={
        "FACT_EXTRACTION_EVERY_N": 0,
        "THREAD_SUMMARY_EVERY_N": 0,
        "USER_SUMMARY_EVERY_N": 0,
    },
)

# Pass to the provider
memory_provider = CosmosMemoryContextProvider(
    memory_client=memory_client,
)

# Manually trigger processing when needed
await memory_client.process_now(user_id="user-123", thread_id="thread-456")

To let the provider disable extraction for you, omit memory_client and pass auto_extract=False with the connection arguments instead - the provider then builds the client with the extraction and summary steps zeroed.

Environment Variables

All configuration can be provided via environment variables:

Using a .env file (cross-platform, recommended):

COSMOS_ENDPOINT=https://<account>.documents.azure.com:443/
COSMOS_DATABASE=ai_memory
FOUNDRY_ENDPOINT=https://<project>.services.ai.azure.com
EMBEDDING_MODEL=text-embedding-3-large
CHAT_MODEL=gpt-4o-mini

# Optional: Processing configuration
FACT_EXTRACTION_EVERY_N=1
DEDUP_EVERY_N=5
THREAD_SUMMARY_EVERY_N=10
USER_SUMMARY_EVERY_N=20

Or set in your shell session:

Bash/Linux/macOS:

export COSMOS_ENDPOINT=https://<account>.documents.azure.com:443/
export COSMOS_DATABASE=ai_memory
export FOUNDRY_ENDPOINT=https://<project>.services.ai.azure.com

PowerShell:

$env:COSMOS_ENDPOINT="https://<account>.documents.azure.com:443/"
$env:COSMOS_DATABASE="ai_memory"
$env:FOUNDRY_ENDPOINT="https://<project>.services.ai.azure.com"

See Also