Python: Fix broken samples and add missing READMEs (#5038)

* Python: Fix broken samples and add missing READMEs

- simple_context_provider: move instructions kwarg into options dict
- suspend_resume_session: use OpenAIChatCompletionClient for in-memory demo
- foundry_chat_client_with_hosted_mcp: move store kwarg into options dict
- Add README.md for context_providers and conversations sample folders

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Python: Fix additional sample issues in context_providers

- mem0_basic: send preferences query before sleep so Mem0 can learn them,
  print result from new session recall
- mem0_sessions: add session for multi-turn conversation in agent-scoped
  example, remove user_id from agent-scoped provider (Mem0 API stores
  memories without user_id when agent_id is provided), use single message
  for storing preferences
- redis_basics: print retrieved context messages instead of raw object
- redis_sessions: add missing load_dotenv() call
- redis_basics/redis_sessions: fix docstrings referencing wrong client type
- azure_redis_conversation: replace duplicate copyright with load_dotenv()

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Python: Fix broken link in declarative README

openai_responses_agent.py was renamed to openai_agent.py

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Giles Odigwe
2026-04-01 14:35:16 -07:00
committed by GitHub
Unverified
parent 15e435b472
commit 6f6ee61834
11 changed files with 88 additions and 32 deletions
@@ -0,0 +1,28 @@
# Context Provider Samples
These samples demonstrate how to use context providers to enrich agent conversations with external knowledge — from custom logic to Azure AI Search (RAG) and memory services.
## Samples
| File / Folder | Description |
|---------------|-------------|
| [`simple_context_provider.py`](simple_context_provider.py) | Implement a custom context provider by extending `BaseContextProvider` to extract and inject structured user information across turns. |
| [`azure_ai_foundry_memory.py`](azure_ai_foundry_memory.py) | Use `FoundryMemoryProvider` to add semantic memory — automatically retrieves, searches, and stores memories via Azure AI Foundry. |
| [`azure_ai_search/`](azure_ai_search/) | Retrieval Augmented Generation (RAG) with Azure AI Search in semantic and agentic modes. See its own [README](azure_ai_search/README.md). |
| [`mem0/`](mem0/) | Memory-powered context using the Mem0 integration (open-source and managed). See its own [README](mem0/README.md). |
| [`redis/`](redis/) | Redis-backed context providers for conversation memory and sessions. See its own [README](redis/README.md). |
## Prerequisites
**For `simple_context_provider.py`:**
- `FOUNDRY_PROJECT_ENDPOINT`: Your Azure AI Foundry project endpoint
- `FOUNDRY_MODEL`: Model deployment name
- Azure CLI authentication (`az login`)
**For `azure_ai_foundry_memory.py`:**
- `FOUNDRY_PROJECT_ENDPOINT`: Your Azure AI Foundry project endpoint
- `FOUNDRY_MODEL`: Chat/responses model deployment name
- `AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME`: Embedding model deployment name (e.g., `text-embedding-ada-002`)
- Azure CLI authentication (`az login`)
See each subfolder's README for provider-specific prerequisites.
@@ -57,12 +57,16 @@ async def main() -> None:
# Now tell the agent the company code and the report format that you want to use
# and it should be able to invoke the tool and return the report.
query = "I always work with CNTS and I always want a detailed report format. Please remember and retrieve it."
print(f"User: {query}")
result = await agent.run(query)
print(f"Agent: {result}\n")
# Mem0 processes and indexes memories asynchronously.
# Wait for memories to be indexed before querying in a new thread.
# In production, consider implementing retry logic or using Mem0's
# eventual consistency handling instead of a fixed delay.
print("Waiting for memories to be processed...")
await asyncio.sleep(12) # Empirically determined delay for Mem0 indexing
await asyncio.sleep(15) # Empirically determined delay for Mem0 indexing
print("\nRequest within a new session:")
# Create a new session for the agent.
# The new session has no context of the previous conversation.
@@ -70,7 +74,10 @@ async def main() -> None:
# Since we have the mem0 component in the session, the agent should be able to
# retrieve the company report without asking for clarification, as it will
# be able to remember the user preferences from Mem0 component.
query = "Please retrieve my company report"
print(f"User: {query}")
result = await agent.run(query, session=session)
print(f"Agent: {result}")
if __name__ == "__main__":
@@ -71,8 +71,6 @@ async def example_agent_scoped_memory() -> None:
print("2. Agent-Scoped Memory Example:")
print("-" * 40)
user_id = "user123"
async with (
AzureCliCredential() as credential,
Agent(
@@ -83,34 +81,23 @@ async def example_agent_scoped_memory() -> None:
context_providers=[
Mem0ContextProvider(
source_id="mem0",
user_id=user_id,
agent_id="scoped_assistant",
)
],
) as scoped_agent,
):
# Store some information
query = "Remember that for this conversation, I'm working on a Python project about data analysis."
query = (
"Remember that I'm working on a Python project about data analysis "
"and I prefer using pandas and matplotlib."
)
print(f"User: {query}")
result = await scoped_agent.run(query)
print(f"Agent: {result}\n")
# Test memory retrieval
query = "What project am I working on?"
print(f"User: {query}")
result = await scoped_agent.run(query)
print(f"Agent: {result}\n")
# Store more information
query = "Also remember that I prefer using pandas and matplotlib for this project."
print(f"User: {query}")
result = await scoped_agent.run(query)
print(f"Agent: {result}\n")
# Test comprehensive memory retrieval
new_session = scoped_agent.create_session()
query = "What do you know about my current project and preferences?"
print(f"User: {query}")
result = await scoped_agent.run(query)
print(f"User (new session): {query}")
result = await scoped_agent.run(query, session=new_session)
print(f"Agent: {result}\n")
@@ -30,9 +30,10 @@ from agent_framework.foundry import FoundryChatClient
from agent_framework.redis import RedisHistoryProvider
from azure.identity import AzureCliCredential
from azure.identity.aio import AzureCliCredential as AsyncAzureCliCredential
from dotenv import load_dotenv
from redis.credentials import CredentialProvider
# Copyright (c) Microsoft. All rights reserved.
load_dotenv()
class AzureCredentialProvider(CredentialProvider):
@@ -100,7 +100,7 @@ def search_flights(origin_airport_code: str, destination_airport_code: str, deta
def create_chat_client() -> FoundryChatClient:
"""Create an Azure OpenAI Responses client using a Foundry project endpoint."""
"""Create a FoundryChatClient using a Foundry project endpoint."""
return FoundryChatClient(
project_endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"],
model=os.environ["FOUNDRY_MODEL"],
@@ -34,10 +34,12 @@ from agent_framework import Agent
from agent_framework.foundry import FoundryChatClient
from agent_framework.redis import RedisContextProvider
from azure.identity import AzureCliCredential
from dotenv import load_dotenv
from redisvl.extensions.cache.embeddings import EmbeddingsCache
from redisvl.utils.vectorize import OpenAITextVectorizer
# Copyright (c) Microsoft. All rights reserved.
# Load environment variables from .env file
load_dotenv()
# Default Redis URL for local Redis Stack.
@@ -48,7 +50,7 @@ REDIS_URL = os.getenv("REDIS_URL", "redis://localhost:6379")
# Please set OPENAI_API_KEY to use the OpenAI vectorizer.
# For chat responses, also set FOUNDRY_PROJECT_ENDPOINT and FOUNDRY_MODEL.
def create_chat_client() -> FoundryChatClient:
"""Create an Azure OpenAI Responses client using a Foundry project endpoint."""
"""Create a FoundryChatClient using a Foundry project endpoint."""
return FoundryChatClient(
project_endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"],
model=os.environ["FOUNDRY_MODEL"],
@@ -50,9 +50,11 @@ class UserInfoMemory(ContextProvider):
# Use the chat client to extract structured information
result = await self._chat_client.get_response(
messages=request_messages, # type: ignore
instructions="Extract the user's name and age from the message if present. "
"If not present return nulls.",
options={"response_format": UserInfo},
options={
"instructions": "Extract the user's name and age from the message if present. "
"If not present return nulls.",
"response_format": UserInfo,
},
)
# Update user info with extracted data
@@ -0,0 +1,28 @@
# Conversation & Session Management Samples
These samples demonstrate different approaches to managing conversation history and session state in Agent Framework.
## Samples
| File | Description |
|------|-------------|
| [`suspend_resume_session.py`](suspend_resume_session.py) | Suspend and resume conversation sessions, comparing service-managed sessions (Azure AI Foundry) with in-memory sessions (OpenAI). |
| [`custom_history_provider.py`](custom_history_provider.py) | Implement a custom history provider by extending `BaseHistoryProvider`, enabling conversation persistence in your preferred storage backend. |
| [`redis_history_provider.py`](redis_history_provider.py) | Use Redis as a history provider for persistent conversation history storage across sessions. |
## Prerequisites
**For `suspend_resume_session.py`:**
- `FOUNDRY_PROJECT_ENDPOINT`: Your Azure AI Foundry project endpoint (service-managed session)
- `FOUNDRY_MODEL`: The Foundry model deployment name
- `OPENAI_API_KEY`: Your OpenAI API key (in-memory session)
- Azure CLI authentication (`az login`)
**For `custom_history_provider.py`:**
- `OPENAI_API_KEY`: Your OpenAI API key
**For `redis_history_provider.py`:**
- `OPENAI_API_KEY`: Your OpenAI API key
- A running Redis server — default URL is `redis://localhost:6379`
- Override via the `REDIS_URL` environment variable for remote or authenticated instances
- Quickstart with Docker: `docker run -d --name redis-stack -p 6379:6379 redis/redis-stack-server:latest`
@@ -4,6 +4,7 @@ import asyncio
from agent_framework import Agent, AgentSession
from agent_framework.foundry import FoundryChatClient
from agent_framework.openai import OpenAIChatCompletionClient
from azure.identity.aio import AzureCliCredential
from dotenv import load_dotenv
@@ -62,7 +63,7 @@ async def suspend_resume_in_memory_session() -> None:
# OpenAI Chat Client is used as an example here,
# other chat clients can be used as well.
agent = Agent(
client=FoundryChatClient(),
client=OpenAIChatCompletionClient(),
name="MemoryBot",
instructions="You are a helpful assistant that remembers our conversation.",
)
@@ -68,7 +68,7 @@ Illustrates a basic agent using Azure OpenAI with structured responses.
**Key concepts**: Azure OpenAI integration, credential management, structured outputs
### 5. **OpenAI Responses Agent** ([`openai_responses_agent.py`](./openai_responses_agent.py))
### 5. **OpenAI Responses Agent** ([`openai_agent.py`](./openai_agent.py))
Demonstrates the simplest possible agent using OpenAI directly.
@@ -51,7 +51,7 @@ async def handle_approvals_with_session(query: str, agent: "SupportsAgentRun", s
"""Here we let the session deal with the previous responses, and we just rerun with the approval."""
from agent_framework import Message
result = await agent.run(query, session=session, store=True)
result = await agent.run(query, session=session, options={"store": True})
while len(result.user_input_requests) > 0:
new_input: list[Any] = []
for user_input_needed in result.user_input_requests:
@@ -66,7 +66,7 @@ async def handle_approvals_with_session(query: str, agent: "SupportsAgentRun", s
contents=[user_input_needed.to_function_approval_response(user_approval.lower() == "y")],
)
)
result = await agent.run(new_input, session=session, store=True)
result = await agent.run(new_input, session=session, options={"store": True})
return result