Python: [BREAKING] cleanup of thread API and serialization (#893)

* cleanup of threads and serialization

* fix for sliding window

* fix redis test

* updated from comments

* updated context provider and threads

* updated lock

* add asyncio default

* fix redis tests

* fix tests

* fix tests

* renamed to invoking

* fixed tests

* fix for instructions
This commit is contained in:
Eduard van Valkenburg
2025-09-29 18:22:34 +02:00
committed by GitHub
Unverified
parent bf5931932e
commit 10d10364a9
52 changed files with 1642 additions and 1411 deletions
@@ -9,6 +9,7 @@ This folder contains examples demonstrating different ways to create and use age
| [`azure_ai_basic.py`](azure_ai_basic.py) | The simplest way to create an agent using `ChatAgent` with `AzureAIAgentClient`. It automatically handles all configuration using environment variables. |
| [`azure_ai_with_explicit_settings.py`](azure_ai_with_explicit_settings.py) | Shows how to create an agent with explicitly configured `AzureAIAgentClient` settings, including project endpoint, model deployment, credentials, and agent name. |
| [`azure_ai_with_existing_agent.py`](azure_ai_with_existing_agent.py) | Shows how to work with a pre-existing agent by providing the agent ID to the Azure AI chat client. This example also demonstrates proper cleanup of manually created agents. |
| [`azure_ai_with_existing_thread.py`](azure_ai_with_existing_thread.py) | Shows how to work with a pre-existing thread by providing the thread ID to the Azure AI chat client. This example also demonstrates proper cleanup of manually created threads. |
| [`azure_ai_with_function_tools.py`](azure_ai_with_function_tools.py) | Demonstrates how to use function tools with agents. Shows both agent-level tools (defined when creating the agent) and query-level tools (provided with specific queries). |
| [`azure_ai_with_code_interpreter.py`](azure_ai_with_code_interpreter.py) | Shows how to use the HostedCodeInterpreterTool with Azure AI agents to write and execute Python code. Includes helper methods for accessing code interpreter data from response chunks. |
| [`azure_ai_with_local_mcp.py`](azure_ai_with_local_mcp.py) | Shows how to integrate Azure AI agents with Model Context Protocol (MCP) servers for enhanced functionality and tool integration. Demonstrates both agent-level and run-level tool configuration. |
@@ -0,0 +1,52 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
import os
from random import randint
from typing import Annotated
from agent_framework import ChatAgent
from agent_framework.azure import AzureAIAgentClient
from azure.ai.projects.aio import AIProjectClient
from azure.identity.aio import AzureCliCredential
from pydantic import Field
def get_weather(
location: Annotated[str, Field(description="The location to get the weather for.")],
) -> str:
"""Get the weather for a given location."""
conditions = ["sunny", "cloudy", "rainy", "stormy"]
return f"The weather in {location} is {conditions[randint(0, 3)]} with a high of {randint(10, 30)}°C."
async def main() -> None:
print("=== Azure AI Chat Client with Existing Thread ===")
# Create the client
async with (
AzureCliCredential() as credential,
AIProjectClient(endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"], credential=credential) as client,
):
# Create an thread that will persist
created_thread = await client.agents.threads.create()
try:
async with ChatAgent(
# passing in the client is optional here, so if you take the agent_id from the portal
# you can use it directly without the two lines above.
chat_client=AzureAIAgentClient(project_client=client),
instructions="You are a helpful weather agent.",
tools=get_weather,
) as agent:
thread = agent.get_new_thread(service_thread_id=created_thread.id)
assert thread.is_initialized
result = await agent.run("What's the weather like in Tokyo?", thread=thread)
print(f"Result: {result}\n")
finally:
# Clean up the thread manually
await client.agents.threads.delete(created_thread.id)
if __name__ == "__main__":
asyncio.run(main())
@@ -4,7 +4,7 @@ import asyncio
from random import randint
from typing import Annotated
from agent_framework import AgentThread, ChatAgent, ChatMessageList
from agent_framework import AgentThread, ChatAgent, ChatMessageStore
from agent_framework.azure import AzureOpenAIChatClient
from azure.identity import AzureCliCredential
from pydantic import Field
@@ -125,7 +125,7 @@ async def example_with_existing_thread_messages() -> None:
# You can also create a new thread from existing messages
messages = await thread.message_store.list_messages() if thread.message_store else []
new_thread = AgentThread(message_store=ChatMessageList(messages))
new_thread = AgentThread(message_store=ChatMessageStore(messages))
query3 = "How does the Paris weather compare to London?"
print(f"User: {query3}")
@@ -101,8 +101,7 @@ class EchoAgent(BaseAgent):
# Notify the thread of new messages if provided
if thread is not None:
await self._notify_thread_of_new_messages(thread, normalized_messages)
await self._notify_thread_of_new_messages(thread, response_message)
await self._notify_thread_of_new_messages(thread, normalized_messages, response_message)
return AgentRunResponse(messages=[response_message])
@@ -136,10 +135,6 @@ class EchoAgent(BaseAgent):
else:
response_text = f"{self.echo_prefix}[Non-text message received]"
# Notify the thread of input messages if provided
if thread is not None:
await self._notify_thread_of_new_messages(thread, normalized_messages)
# Simulate streaming by yielding the response word by word
words = response_text.split()
for i, word in enumerate(words):
@@ -157,7 +152,7 @@ class EchoAgent(BaseAgent):
# Notify the thread of the complete response if provided
if thread is not None:
complete_response = ChatMessage(role=Role.ASSISTANT, contents=[TextContent(text=response_text)])
await self._notify_thread_of_new_messages(thread, complete_response)
await self._notify_thread_of_new_messages(thread, normalized_messages, complete_response)
async def main() -> None:
@@ -4,7 +4,7 @@ import asyncio
from random import randint
from typing import Annotated
from agent_framework import AgentThread, ChatAgent, ChatMessageList
from agent_framework import AgentThread, ChatAgent, ChatMessageStore
from agent_framework.openai import OpenAIChatClient
from pydantic import Field
@@ -119,7 +119,7 @@ async def example_with_existing_thread_messages() -> None:
# You can also create a new thread from existing messages
messages = await thread.message_store.list_messages() if thread.message_store else []
new_thread = AgentThread(message_store=ChatMessageList(messages))
new_thread = AgentThread(message_store=ChatMessageStore(messages))
query3 = "How does the Paris weather compare to London?"
print(f"User: {query3}")