From a8678f5a88e6c4c3fab4493af58db720794c0e60 Mon Sep 17 00:00:00 2001 From: Dmytro Struk <13853051+dmytrostruk@users.noreply.github.com> Date: Wed, 30 Jul 2025 16:52:48 -0700 Subject: [PATCH] More examples --- .../foundry/foundry_with_existing_client.py | 45 ------ ...enai_assistants_with_existing_assistant.py | 47 +++++++ .../openai_assistants_with_function_tools.py | 117 ++++++++++++++++ .../openai_assistants_with_thread.py | 128 ++++++++++++++++++ 4 files changed, 292 insertions(+), 45 deletions(-) delete mode 100644 python/samples/getting_started/agents/foundry/foundry_with_existing_client.py create mode 100644 python/samples/getting_started/agents/openai_assistants_client/openai_assistants_with_existing_assistant.py create mode 100644 python/samples/getting_started/agents/openai_assistants_client/openai_assistants_with_function_tools.py create mode 100644 python/samples/getting_started/agents/openai_assistants_client/openai_assistants_with_thread.py diff --git a/python/samples/getting_started/agents/foundry/foundry_with_existing_client.py b/python/samples/getting_started/agents/foundry/foundry_with_existing_client.py deleted file mode 100644 index 6870a9606b..0000000000 --- a/python/samples/getting_started/agents/foundry/foundry_with_existing_client.py +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright (c) Microsoft. All rights reserved. - -import asyncio -import os -from random import randint -from typing import Annotated - -from agent_framework import ChatClientAgent -from agent_framework.foundry import FoundryChatClient -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("=== Foundry Chat Client with Existing AIProjectClient ===") - - # Create the client - client = AIProjectClient(endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"], credential=AzureCliCredential()) - - # Since no Agent ID is provided, the agent will be automatically created - # and deleted after getting a response - async with ChatClientAgent( - chat_client=FoundryChatClient( - client=client, - model_deployment_name=os.environ["FOUNDRY_MODEL_DEPLOYMENT_NAME"], - agent_name="WeatherAgent", - ), - instructions="You are a helpful weather agent.", - tools=get_weather, - ) as agent: - result = await agent.run("What's the weather like in London?") - print(f"Result: {result}\n") - - -if __name__ == "__main__": - asyncio.run(main()) diff --git a/python/samples/getting_started/agents/openai_assistants_client/openai_assistants_with_existing_assistant.py b/python/samples/getting_started/agents/openai_assistants_client/openai_assistants_with_existing_assistant.py new file mode 100644 index 0000000000..6af44fa1be --- /dev/null +++ b/python/samples/getting_started/agents/openai_assistants_client/openai_assistants_with_existing_assistant.py @@ -0,0 +1,47 @@ +# Copyright (c) Microsoft. All rights reserved. + +import asyncio +import os +from random import randint +from typing import Annotated + +from agent_framework import ChatClientAgent +from agent_framework.openai import OpenAIAssistantsClient +from openai import AsyncOpenAI +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("=== OpenAI Assistants Chat Client with Existing Assistant ===") + + # Create the client + client = AsyncOpenAI() + + # Create an assistant that will persist + created_assistant = await client.beta.assistants.create( + model=os.environ["OPENAI_CHAT_MODEL_ID"], name="WeatherAssistant" + ) + + try: + async with ChatClientAgent( + chat_client=OpenAIAssistantsClient(async_client=client, assistant_id=created_assistant.id), + instructions="You are a helpful weather agent.", + tools=get_weather, + ) as agent: + result = await agent.run("What's the weather like in Tokyo?") + print(f"Result: {result}\n") + finally: + # Clean up the assistant manually + await client.beta.assistants.delete(created_assistant.id) + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/python/samples/getting_started/agents/openai_assistants_client/openai_assistants_with_function_tools.py b/python/samples/getting_started/agents/openai_assistants_client/openai_assistants_with_function_tools.py new file mode 100644 index 0000000000..9e7fb2ddc7 --- /dev/null +++ b/python/samples/getting_started/agents/openai_assistants_client/openai_assistants_with_function_tools.py @@ -0,0 +1,117 @@ +# Copyright (c) Microsoft. All rights reserved. + +import asyncio +from datetime import datetime, timezone +from random import randint +from typing import Annotated + +from agent_framework import ChatClientAgent +from agent_framework.openai import OpenAIAssistantsClient +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." + + +def get_time() -> str: + """Get the current UTC time.""" + current_time = datetime.now(timezone.utc) + return f"The current UTC time is {current_time.strftime('%Y-%m-%d %H:%M:%S')}." + + +async def tools_on_agent_level() -> None: + """Example showing tools defined when creating the agent.""" + print("=== Tools Defined on Agent Level ===") + + # Tools are provided when creating the agent + # The agent can use these tools for any query during its lifetime + async with ChatClientAgent( + chat_client=OpenAIAssistantsClient(), + instructions="You are a helpful assistant that can provide weather and time information.", + tools=[get_weather, get_time], # Tools defined at agent creation + ) as agent: + # First query - agent can use weather tool + query1 = "What's the weather like in New York?" + print(f"User: {query1}") + result1 = await agent.run(query1) + print(f"Agent: {result1}\n") + + # Second query - agent can use time tool + query2 = "What's the current UTC time?" + print(f"User: {query2}") + result2 = await agent.run(query2) + print(f"Agent: {result2}\n") + + # Third query - agent can use both tools if needed + query3 = "What's the weather in London and what's the current UTC time?" + print(f"User: {query3}") + result3 = await agent.run(query3) + print(f"Agent: {result3}\n") + + +async def tools_on_run_level() -> None: + """Example showing tools passed to the run method.""" + print("=== Tools Passed to Run Method ===") + + # Agent created without tools + async with ChatClientAgent( + chat_client=OpenAIAssistantsClient(), + instructions="You are a helpful assistant.", + # No tools defined here + ) as agent: + # First query with weather tool + query1 = "What's the weather like in Seattle?" + print(f"User: {query1}") + result1 = await agent.run(query1, tools=[get_weather]) # Tool passed to run method + print(f"Agent: {result1}\n") + + # Second query with time tool + query2 = "What's the current UTC time?" + print(f"User: {query2}") + result2 = await agent.run(query2, tools=[get_time]) # Different tool for this query + print(f"Agent: {result2}\n") + + # Third query with multiple tools + query3 = "What's the weather in Chicago and what's the current UTC time?" + print(f"User: {query3}") + result3 = await agent.run(query3, tools=[get_weather, get_time]) # Multiple tools + print(f"Agent: {result3}\n") + + +async def mixed_tools_example() -> None: + """Example showing both agent-level tools and run-method tools.""" + print("=== Mixed Tools Example (Agent + Run Method) ===") + + # Agent created with some base tools + async with ChatClientAgent( + chat_client=OpenAIAssistantsClient(), + instructions="You are a comprehensive assistant that can help with various information requests.", + tools=[get_weather], # Base tool available for all queries + ) as agent: + # Query using both agent tool and additional run-method tools + query = "What's the weather in Denver and what's the current UTC time?" + print(f"User: {query}") + + # Agent has access to get_weather (from creation) + additional tools from run method + result = await agent.run( + query, + tools=[get_time], # Additional tools for this specific query + ) + print(f"Agent: {result}\n") + + +async def main() -> None: + print("=== OpenAI Assistants Chat Client Agent with Function Tools Examples ===\n") + + await tools_on_agent_level() + await tools_on_run_level() + await mixed_tools_example() + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/python/samples/getting_started/agents/openai_assistants_client/openai_assistants_with_thread.py b/python/samples/getting_started/agents/openai_assistants_client/openai_assistants_with_thread.py new file mode 100644 index 0000000000..71dd5efff7 --- /dev/null +++ b/python/samples/getting_started/agents/openai_assistants_client/openai_assistants_with_thread.py @@ -0,0 +1,128 @@ +# Copyright (c) Microsoft. All rights reserved. + +import asyncio +from random import randint +from typing import Annotated + +from agent_framework import ChatClientAgent, ChatClientAgentThread +from agent_framework.openai import OpenAIAssistantsClient +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 example_with_automatic_thread_creation() -> None: + """Example showing automatic thread creation (service-managed thread).""" + print("=== Automatic Thread Creation Example ===") + + async with ChatClientAgent( + chat_client=OpenAIAssistantsClient(), + instructions="You are a helpful weather agent.", + tools=get_weather, + ) as agent: + # First conversation - no thread provided, will be created automatically + query1 = "What's the weather like in Seattle?" + print(f"User: {query1}") + result1 = await agent.run(query1) + print(f"Agent: {result1.text}") + + # Second conversation - still no thread provided, will create another new thread + query2 = "What was the last city I asked about?" + print(f"\nUser: {query2}") + result2 = await agent.run(query2) + print(f"Agent: {result2.text}") + print("Note: Each call creates a separate thread, so the agent doesn't remember previous context.\n") + + +async def example_with_thread_persistence() -> None: + """Example showing thread persistence across multiple conversations.""" + print("=== Thread Persistence Example ===") + print("Using the same thread across multiple conversations to maintain context.\n") + + async with ChatClientAgent( + chat_client=OpenAIAssistantsClient(), + instructions="You are a helpful weather agent.", + tools=get_weather, + ) as agent: + # Create a new thread that will be reused + thread = agent.get_new_thread() + + # First conversation + query1 = "What's the weather like in Tokyo?" + print(f"User: {query1}") + result1 = await agent.run(query1, thread=thread) + print(f"Agent: {result1.text}") + + # Second conversation using the same thread - maintains context + query2 = "How about London?" + print(f"\nUser: {query2}") + result2 = await agent.run(query2, thread=thread) + print(f"Agent: {result2.text}") + + # Third conversation - agent should remember both previous cities + query3 = "Which of the cities I asked about has better weather?" + print(f"\nUser: {query3}") + result3 = await agent.run(query3, thread=thread) + print(f"Agent: {result3.text}") + print("Note: The agent remembers context from previous messages in the same thread.\n") + + +async def example_with_existing_thread_id() -> None: + """Example showing how to work with an existing thread ID from the service.""" + print("=== Existing Thread ID Example ===") + print("Using a specific thread ID to continue an existing conversation.\n") + + # First, create a conversation and capture the thread ID + existing_thread_id = None + + async with ChatClientAgent( + chat_client=OpenAIAssistantsClient(), + instructions="You are a helpful weather agent.", + tools=get_weather, + ) as agent: + # Start a conversation and get the thread ID + thread = agent.get_new_thread() + query1 = "What's the weather in Paris?" + print(f"User: {query1}") + result1 = await agent.run(query1, thread=thread) + print(f"Agent: {result1.text}") + + # The thread ID is set after the first response + existing_thread_id = thread.id + print(f"Thread ID: {existing_thread_id}") + + if existing_thread_id: + print("\n--- Continuing with the same thread ID in a new agent instance ---") + + # Create a new agent instance but use the existing thread ID + async with ChatClientAgent( + chat_client=OpenAIAssistantsClient(thread_id=existing_thread_id), + instructions="You are a helpful weather agent.", + tools=get_weather, + ) as agent: + # Create a thread with the existing ID + thread = ChatClientAgentThread(id=existing_thread_id) + + query2 = "What was the last city I asked about?" + print(f"User: {query2}") + result2 = await agent.run(query2, thread=thread) + print(f"Agent: {result2.text}") + print("Note: The agent continues the conversation from the previous thread.\n") + + +async def main() -> None: + print("=== OpenAI Assistants Chat Client Agent Thread Management Examples ===\n") + + await example_with_automatic_thread_creation() + await example_with_thread_persistence() + await example_with_existing_thread_id() + + +if __name__ == "__main__": + asyncio.run(main())