mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
Python: [BREAKING] update to v1.0.0 (#5062)
* updates to final deprecated pieces and versions * fix mypy * fix readme links
This commit is contained in:
committed by
GitHub
Unverified
parent
5f06b68535
commit
3446eb8d5d
@@ -88,7 +88,7 @@ async def main(client_name: ClientName = "openai_chat") -> None:
|
||||
"""Run a basic prompt using a selected built-in client."""
|
||||
client = get_client(client_name)
|
||||
|
||||
message = Message("user", text="What's the weather in Amsterdam and in Paris?")
|
||||
message = Message("user", contents=["What's the weather in Amsterdam and in Paris?"])
|
||||
stream = os.getenv("STREAM", "false").lower() == "true"
|
||||
print(f"Client: {client_name}")
|
||||
print(f"User: {message.text}")
|
||||
|
||||
@@ -31,7 +31,7 @@ async def main() -> None:
|
||||
|
||||
try:
|
||||
task = asyncio.create_task(
|
||||
client.get_response(messages=[Message(role="user", text="Tell me a fantasy story.")])
|
||||
client.get_response(messages=[Message(role="user", contents=["Tell me a fantasy story."])])
|
||||
)
|
||||
await asyncio.sleep(1)
|
||||
task.cancel()
|
||||
|
||||
@@ -98,7 +98,7 @@ class EchoingChatClient(BaseChatClient[OptionsT]):
|
||||
response_text = f"{response_text} {suffix}"
|
||||
stream_delay_seconds = float(options.get("stream_delay_seconds", 0.05))
|
||||
|
||||
response_message = Message(role="assistant", text=response_text)
|
||||
response_message = Message(role="assistant", contents=[response_text])
|
||||
|
||||
response = ChatResponse(
|
||||
messages=[response_message],
|
||||
@@ -150,7 +150,7 @@ async def main() -> None:
|
||||
# Use the chat client directly
|
||||
print("Using chat client directly:")
|
||||
direct_response = await echo_client.get_response(
|
||||
[Message(role="user", text="Hello, custom chat client!")],
|
||||
[Message(role="user", contents=["Hello, custom chat client!"])],
|
||||
options={
|
||||
"uppercase": True,
|
||||
"suffix": "(CUSTOM OPTIONS)",
|
||||
|
||||
@@ -35,25 +35,27 @@ class BudgetSummaryClient:
|
||||
**kwargs: Any,
|
||||
) -> ChatResponse:
|
||||
summary_text = f"Budget summary generated from {len(messages)} prompt messages."
|
||||
return ChatResponse(messages=[Message(role="assistant", text=summary_text)])
|
||||
return ChatResponse(messages=[Message(role="assistant", contents=[summary_text])])
|
||||
|
||||
|
||||
def _build_long_history() -> list[Message]:
|
||||
history = [Message(role="system", text="You are a migration copilot.")]
|
||||
history = [Message(role="system", contents=["You are a migration copilot."])]
|
||||
for i in range(1, 8):
|
||||
history.append(
|
||||
Message(
|
||||
role="user",
|
||||
text=f"Iteration {i}: capture migration requirements and edge cases.",
|
||||
contents=[f"Iteration {i}: capture migration requirements and edge cases."],
|
||||
)
|
||||
)
|
||||
history.append(
|
||||
Message(
|
||||
role="assistant",
|
||||
text=(
|
||||
f"Iteration {i}: detailed plan with dependencies, rollback guidance, and testing details. "
|
||||
"This sentence is intentionally long to create token pressure."
|
||||
),
|
||||
contents=[
|
||||
(
|
||||
f"Iteration {i}: detailed plan with dependencies, rollback guidance, and testing details. "
|
||||
"This sentence is intentionally long to create token pressure."
|
||||
)
|
||||
],
|
||||
)
|
||||
)
|
||||
return history
|
||||
|
||||
@@ -57,17 +57,17 @@ class InspectingChatClient(BaseChatClient[Any]):
|
||||
self.last_messages = list(messages)
|
||||
|
||||
async def _get_response() -> ChatResponse:
|
||||
return ChatResponse(messages=[Message(role="assistant", text="done")])
|
||||
return ChatResponse(messages=[Message(role="assistant", contents=["done"])])
|
||||
|
||||
return _get_response()
|
||||
|
||||
|
||||
def _build_messages() -> list[Message]:
|
||||
return [
|
||||
Message(role="user", text="Collect the deployment requirements."),
|
||||
Message(role="assistant", text="I will gather the constraints first."),
|
||||
Message(role="user", text="Summarize the rollout risks."),
|
||||
Message(role="assistant", text="The main risks are drift, downtime, and rollback gaps."),
|
||||
Message(role="user", contents=["Collect the deployment requirements."]),
|
||||
Message(role="assistant", contents=["I will gather the constraints first."]),
|
||||
Message(role="user", contents=["Summarize the rollout risks."]),
|
||||
Message(role="assistant", contents=["The main risks are drift, downtime, and rollback gaps."]),
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -51,15 +51,15 @@ class LocalSummaryClient:
|
||||
options: dict[str, Any] | None = None,
|
||||
**kwargs: Any,
|
||||
) -> ChatResponse:
|
||||
return ChatResponse(messages=[Message(role="assistant", text=f"Summary for {len(messages)} messages.")])
|
||||
return ChatResponse(messages=[Message(role="assistant", contents=[f"Summary for {len(messages)} messages."])])
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
# 1. Build one baseline history and print it once.
|
||||
messages = [
|
||||
Message(role="system", text="You are a helpful assistant."),
|
||||
Message(role="user", text="Plan a data migration."),
|
||||
Message(role="assistant", text="I will gather requirements."),
|
||||
Message(role="system", contents=["You are a helpful assistant."]),
|
||||
Message(role="user", contents=["Plan a data migration."]),
|
||||
Message(role="assistant", contents=["I will gather requirements."]),
|
||||
Message(
|
||||
role="assistant",
|
||||
contents=[
|
||||
@@ -79,9 +79,9 @@ async def main() -> None:
|
||||
)
|
||||
],
|
||||
),
|
||||
Message(role="assistant", text="I found three core tables."),
|
||||
Message(role="user", text="Estimate effort and risks."),
|
||||
Message(role="assistant", text="Primary risk is schema drift."),
|
||||
Message(role="assistant", contents=["I found three core tables."]),
|
||||
Message(role="user", contents=["Estimate effort and risks."]),
|
||||
Message(role="assistant", contents=["Primary risk is schema drift."]),
|
||||
]
|
||||
print("\n--- Before compaction ---")
|
||||
print(f"Message count: {len(messages)}")
|
||||
|
||||
@@ -50,11 +50,11 @@ class KeepLastUserTurnStrategy:
|
||||
|
||||
def _messages() -> list[Message]:
|
||||
return [
|
||||
Message(role="system", text="You are concise."),
|
||||
Message(role="user", text="first request"),
|
||||
Message(role="assistant", text="first response"),
|
||||
Message(role="user", text="second request"),
|
||||
Message(role="assistant", text="second response"),
|
||||
Message(role="system", contents=["You are concise."]),
|
||||
Message(role="user", contents=["first request"]),
|
||||
Message(role="assistant", contents=["first response"]),
|
||||
Message(role="user", contents=["second request"]),
|
||||
Message(role="assistant", contents=["second response"]),
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -45,30 +45,34 @@ class TiktokenTokenizer(TokenizerProtocol):
|
||||
|
||||
def _build_messages() -> list[Message]:
|
||||
return [
|
||||
Message(role="system", text="You are a migration assistant."),
|
||||
Message(role="system", contents=["You are a migration assistant."]),
|
||||
Message(
|
||||
role="user",
|
||||
text="List all migration risks and include detailed mitigations for each risk category.",
|
||||
contents=["List all migration risks and include detailed mitigations for each risk category."],
|
||||
),
|
||||
Message(
|
||||
role="assistant",
|
||||
text=(
|
||||
"Primary risks include schema drift, missing foreign key constraints, "
|
||||
"and data quality regressions. Mitigations include staged validation, "
|
||||
"shadow writes, and replay-based verification."
|
||||
),
|
||||
contents=[
|
||||
(
|
||||
"Primary risks include schema drift, missing foreign key constraints, "
|
||||
"and data quality regressions. Mitigations include staged validation, "
|
||||
"shadow writes, and replay-based verification."
|
||||
)
|
||||
],
|
||||
),
|
||||
Message(
|
||||
role="user",
|
||||
text=("Now provide a detailed checklist with owners, rollback gates, and validation criteria."),
|
||||
contents=[("Now provide a detailed checklist with owners, rollback gates, and validation criteria.")],
|
||||
),
|
||||
Message(
|
||||
role="assistant",
|
||||
text=(
|
||||
"Checklist: baseline snapshots, migration dry-run, production "
|
||||
"canary, progressive deployment, automated integrity checks, and "
|
||||
"post-migration reconciliation."
|
||||
),
|
||||
contents=[
|
||||
(
|
||||
"Checklist: baseline snapshots, migration dry-run, production "
|
||||
"canary, progressive deployment, automated integrity checks, and "
|
||||
"post-migration reconciliation."
|
||||
)
|
||||
],
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ These samples demonstrate how to use context providers to enrich agent conversat
|
||||
|
||||
| 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. |
|
||||
| [`simple_context_provider.py`](simple_context_provider.py) | Implement a custom context provider by extending `ContextProvider` 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). |
|
||||
|
||||
@@ -7,7 +7,7 @@ These samples demonstrate different approaches to managing conversation history
|
||||
| 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. |
|
||||
| [`custom_history_provider.py`](custom_history_provider.py) | Implement a custom history provider by extending `HistoryProvider`, enabling conversation persistence in your preferred storage backend. |
|
||||
| [`cosmos_history_provider.py`](cosmos_history_provider.py) | Use Azure Cosmos DB as a history provider for durable conversation storage with `CosmosHistoryProvider`. |
|
||||
| [`redis_history_provider.py`](redis_history_provider.py) | Use Redis as a history provider for persistent conversation history storage across sessions. |
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ Shows how to create an agent that can search and retrieve information from Micro
|
||||
- Uses Azure CLI credentials for authentication
|
||||
- Leverages MCP to access Microsoft documentation tools
|
||||
|
||||
**Requirements**: `pip install agent-framework-foundry --pre`
|
||||
**Requirements**: `pip install agent-framework-foundry`
|
||||
|
||||
**Key concepts**: Azure AI Foundry integration, MCP server usage, async patterns, resource management
|
||||
|
||||
@@ -53,7 +53,7 @@ Shows how to create an agent using an inline YAML string rather than a file.
|
||||
|
||||
- Uses Azure AI Foundry v2 Client with instructions.
|
||||
|
||||
**Requirements**: `pip install agent-framework-foundry --pre`
|
||||
**Requirements**: `pip install agent-framework-foundry`
|
||||
|
||||
**Key concepts**: Inline YAML definition.
|
||||
|
||||
|
||||
@@ -14,7 +14,13 @@ async def main():
|
||||
"""Create an agent from a declarative yaml specification and run it."""
|
||||
# get the path
|
||||
current_path = Path(__file__).parent
|
||||
yaml_path = current_path.parent.parent.parent.parent / "declarative-agents" / "agent-samples" / "azure" / "AzureOpenAIResponses.yaml"
|
||||
yaml_path = (
|
||||
current_path.parent.parent.parent.parent
|
||||
/ "declarative-agents"
|
||||
/ "agent-samples"
|
||||
/ "azure"
|
||||
/ "AzureOpenAIResponses.yaml"
|
||||
)
|
||||
# load the yaml from the path
|
||||
with yaml_path.open("r") as f:
|
||||
yaml_str = f.read()
|
||||
|
||||
@@ -22,7 +22,13 @@ async def main():
|
||||
"""Create an agent from a declarative yaml specification and run it."""
|
||||
# get the path
|
||||
current_path = Path(__file__).parent
|
||||
yaml_path = current_path.parent.parent.parent.parent / "declarative-agents" / "agent-samples" / "chatclient" / "GetWeather.yaml"
|
||||
yaml_path = (
|
||||
current_path.parent.parent.parent.parent
|
||||
/ "declarative-agents"
|
||||
/ "agent-samples"
|
||||
/ "chatclient"
|
||||
/ "GetWeather.yaml"
|
||||
)
|
||||
# load the yaml from the path
|
||||
with yaml_path.open("r") as f:
|
||||
yaml_str = f.read()
|
||||
|
||||
@@ -28,7 +28,13 @@ async def main():
|
||||
"""Create an agent from a declarative yaml specification and run it."""
|
||||
# get the path
|
||||
current_path = Path(__file__).parent
|
||||
yaml_path = current_path.parent.parent.parent.parent / "declarative-agents" / "agent-samples" / "foundry" / "MicrosoftLearnAgent.yaml"
|
||||
yaml_path = (
|
||||
current_path.parent.parent.parent.parent
|
||||
/ "declarative-agents"
|
||||
/ "agent-samples"
|
||||
/ "foundry"
|
||||
/ "MicrosoftLearnAgent.yaml"
|
||||
)
|
||||
# create the agent from the yaml
|
||||
async with (
|
||||
AzureCliCredential() as credential,
|
||||
|
||||
@@ -13,7 +13,13 @@ async def main():
|
||||
"""Create an agent from a declarative yaml specification and run it."""
|
||||
# get the path
|
||||
current_path = Path(__file__).parent
|
||||
yaml_path = current_path.parent.parent.parent.parent / "declarative-agents" / "agent-samples" / "openai" / "OpenAIResponses.yaml"
|
||||
yaml_path = (
|
||||
current_path.parent.parent.parent.parent
|
||||
/ "declarative-agents"
|
||||
/ "agent-samples"
|
||||
/ "openai"
|
||||
/ "OpenAIResponses.yaml"
|
||||
)
|
||||
# create the agent from the yaml
|
||||
agent = AgentFactory(safe_mode=False).create_agent_from_yaml_path(yaml_path)
|
||||
# use the agent
|
||||
|
||||
@@ -68,7 +68,7 @@ async def security_filter_middleware(
|
||||
role="assistant",
|
||||
)
|
||||
|
||||
response = ChatResponse(messages=[Message(role="assistant", text=error_message)])
|
||||
response = ChatResponse(messages=[Message(role="assistant", contents=[error_message])])
|
||||
context.result = ResponseStream(blocked_stream(), finalizer=lambda _, r=response: r)
|
||||
else:
|
||||
# Non-streaming mode: return complete response
|
||||
@@ -76,7 +76,7 @@ async def security_filter_middleware(
|
||||
messages=[
|
||||
Message(
|
||||
role="assistant",
|
||||
text=error_message,
|
||||
contents=[error_message],
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
@@ -127,9 +127,13 @@ async def security_and_override_middleware(
|
||||
messages=[
|
||||
Message(
|
||||
role="assistant",
|
||||
text="I cannot process requests containing sensitive information. "
|
||||
"Please rephrase your question without including passwords, secrets, or other "
|
||||
"sensitive data.",
|
||||
contents=[
|
||||
(
|
||||
"I cannot process requests containing sensitive information. "
|
||||
"Please rephrase your question without including passwords, secrets, or other "
|
||||
"sensitive data."
|
||||
)
|
||||
],
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
@@ -71,10 +71,12 @@ class PreTerminationMiddleware(AgentMiddleware):
|
||||
messages=[
|
||||
Message(
|
||||
role="assistant",
|
||||
text=(
|
||||
f"Sorry, I cannot process requests containing '{blocked_word}'. "
|
||||
"Please rephrase your question."
|
||||
),
|
||||
contents=[
|
||||
(
|
||||
f"Sorry, I cannot process requests containing '{blocked_word}'. "
|
||||
"Please rephrase your question."
|
||||
)
|
||||
],
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
@@ -86,7 +86,7 @@ async def weather_override_middleware(context: ChatContext, call_next: Callable[
|
||||
# For non-streaming: just replace with a new message
|
||||
current_text = context.result.text if isinstance(context.result, ChatResponse) else ""
|
||||
custom_message = f"Weather Advisory: [0] {''.join(chunks)} Original message was: {current_text}"
|
||||
context.result = ChatResponse(messages=[Message(role="assistant", text=custom_message)])
|
||||
context.result = ChatResponse(messages=[Message(role="assistant", contents=[custom_message])])
|
||||
|
||||
|
||||
async def validate_weather_middleware(context: ChatContext, call_next: Callable[[], Awaitable[None]]) -> None:
|
||||
@@ -111,7 +111,7 @@ async def validate_weather_middleware(context: ChatContext, call_next: Callable[
|
||||
|
||||
context.result = ResponseStream(_validated_stream(), finalizer=ChatResponse.from_updates)
|
||||
elif isinstance(context.result, ChatResponse):
|
||||
context.result.messages.append(Message(role="assistant", text=validation_note))
|
||||
context.result.messages.append(Message(role="assistant", contents=[validation_note]))
|
||||
|
||||
|
||||
async def agent_cleanup_middleware(context: AgentContext, call_next: Callable[[], Awaitable[None]]) -> None:
|
||||
@@ -153,7 +153,7 @@ async def agent_cleanup_middleware(context: AgentContext, call_next: Callable[[]
|
||||
cleaned_messages.append(
|
||||
Message(
|
||||
role=message.role,
|
||||
text=text,
|
||||
contents=[text],
|
||||
author_name=message.author_name,
|
||||
message_id=message.message_id,
|
||||
additional_properties=message.additional_properties,
|
||||
@@ -166,7 +166,7 @@ async def agent_cleanup_middleware(context: AgentContext, call_next: Callable[[]
|
||||
if not found_validation:
|
||||
raise RuntimeError("Expected validation note not found in agent response.")
|
||||
|
||||
cleaned_messages.append(Message(role="assistant", text=" Agent: OK"))
|
||||
cleaned_messages.append(Message(role="assistant", contents=[" Agent: OK"]))
|
||||
response.messages = cleaned_messages
|
||||
return response
|
||||
|
||||
|
||||
@@ -121,7 +121,7 @@ async def run_chat_client() -> None:
|
||||
print(f"User: {message}")
|
||||
print("Assistant: ", end="")
|
||||
async for chunk in client.get_response(
|
||||
[Message(role="user", text=message)],
|
||||
[Message(role="user", contents=[message])],
|
||||
stream=True,
|
||||
options={"tools": [get_weather]},
|
||||
):
|
||||
|
||||
@@ -92,7 +92,7 @@ async def run_chat_client(client: "SupportsChatGetResponse", stream: bool = Fals
|
||||
if stream:
|
||||
print("Assistant: ", end="")
|
||||
async for chunk in client.get_response(
|
||||
[Message(role="user", text=message)],
|
||||
[Message(role="user", contents=[message])],
|
||||
stream=True,
|
||||
options={"tools": [get_weather]},
|
||||
):
|
||||
@@ -101,7 +101,7 @@ async def run_chat_client(client: "SupportsChatGetResponse", stream: bool = Fals
|
||||
print("")
|
||||
else:
|
||||
response = await client.get_response(
|
||||
[Message(role="user", text=message)],
|
||||
[Message(role="user", contents=[message])],
|
||||
options={"tools": [get_weather]},
|
||||
)
|
||||
print(f"Assistant: {response}")
|
||||
|
||||
@@ -80,7 +80,7 @@ async def run_chat_client(client: "SupportsChatGetResponse", stream: bool = Fals
|
||||
if stream:
|
||||
print("Assistant: ", end="")
|
||||
async for chunk in client.get_response(
|
||||
[Message(role="user", text=message)],
|
||||
[Message(role="user", contents=[message])],
|
||||
stream=True,
|
||||
options={"tools": [get_weather]},
|
||||
):
|
||||
@@ -89,7 +89,7 @@ async def run_chat_client(client: "SupportsChatGetResponse", stream: bool = Fals
|
||||
print("")
|
||||
else:
|
||||
response = await client.get_response(
|
||||
[Message(role="user", text=message)],
|
||||
[Message(role="user", contents=[message])],
|
||||
options={"tools": [get_weather]},
|
||||
)
|
||||
print(f"Assistant: {response}")
|
||||
|
||||
@@ -84,7 +84,7 @@ async def run_chat_client(client: "SupportsChatGetResponse", stream: bool = Fals
|
||||
if stream:
|
||||
print("Assistant: ", end="")
|
||||
async for chunk in client.get_response(
|
||||
[Message(role="user", text=message)],
|
||||
[Message(role="user", contents=[message])],
|
||||
stream=True,
|
||||
options={"tools": [get_weather]},
|
||||
):
|
||||
@@ -93,7 +93,7 @@ async def run_chat_client(client: "SupportsChatGetResponse", stream: bool = Fals
|
||||
print("")
|
||||
else:
|
||||
response = await client.get_response(
|
||||
[Message(role="user", text=message)],
|
||||
[Message(role="user", contents=[message])],
|
||||
options={"tools": [get_weather]},
|
||||
)
|
||||
print(f"Assistant: {response}")
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
from agent_framework import Agent
|
||||
from agent_framework.anthropic import AnthropicChatOptions, AnthropicClient
|
||||
from agent_framework.anthropic import AnthropicClient
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# Load environment variables from .env file
|
||||
@@ -15,12 +16,20 @@ This sample demonstrates using Anthropic with:
|
||||
- Setting up an Anthropic-based agent with hosted tools.
|
||||
- Using the `thinking` feature.
|
||||
- Displaying both thinking and usage information during streaming responses.
|
||||
|
||||
Environment variables:
|
||||
ANTHROPIC_API_KEY — Your Anthropic API key
|
||||
ANTHROPIC_CHAT_MODEL — The Anthropic model to use (e.g., "claude-sonnet-4-6")
|
||||
|
||||
"""
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
"""Example of streaming response (get results as they are generated)."""
|
||||
client = AnthropicClient[AnthropicChatOptions]()
|
||||
client = AnthropicClient(
|
||||
api_key=os.getenv("ANTHROPIC_API_KEY"),
|
||||
model=os.getenv("ANTHROPIC_CHAT_MODEL"),
|
||||
)
|
||||
|
||||
# Create MCP tool configuration using instance method
|
||||
mcp_tool = client.get_mcp_tool(
|
||||
|
||||
@@ -76,19 +76,19 @@ async def example_with_session_persistence_in_memory() -> None:
|
||||
# First conversation
|
||||
query1 = "What's the weather like in Tokyo?"
|
||||
print(f"User: {query1}")
|
||||
result1 = await agent.run(query1, session=session, store=False)
|
||||
result1 = await agent.run(query1, session=session, options={"store": False})
|
||||
print(f"Agent: {result1.text}")
|
||||
|
||||
# Second conversation using the same session - maintains context
|
||||
query2 = "How about London?"
|
||||
print(f"\nUser: {query2}")
|
||||
result2 = await agent.run(query2, session=session, store=False)
|
||||
result2 = await agent.run(query2, session=session, options={"store": False})
|
||||
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, session=session, store=False)
|
||||
result3 = await agent.run(query3, session=session, options={"store": False})
|
||||
print(f"Agent: {result3.text}")
|
||||
print("Note: The agent remembers context from previous messages in the same session.\n")
|
||||
|
||||
@@ -114,7 +114,7 @@ async def example_with_existing_session_id() -> None:
|
||||
|
||||
query1 = "What's the weather in Paris?"
|
||||
print(f"User: {query1}")
|
||||
result1 = await agent.run(query1, session=session)
|
||||
result1 = await agent.run(query1, session=session, options={"store": False})
|
||||
print(f"Agent: {result1.text}")
|
||||
|
||||
# The session ID is set after the first response
|
||||
|
||||
@@ -9,7 +9,6 @@ This folder contains Azure AI Foundry and Foundry Local samples for Agent Framew
|
||||
| [`foundry_agent_basic.py`](foundry_agent_basic.py) | Foundry Agent basic example |
|
||||
| [`foundry_agent_custom_client.py`](foundry_agent_custom_client.py) | Foundry Agent custom client configuration |
|
||||
| [`foundry_agent_hosted.py`](foundry_agent_hosted.py) | Foundry Agent for hosted agents |
|
||||
| [`foundry_agent_with_env_vars.py`](foundry_agent_with_env_vars.py) | Foundry Agent using environment variables |
|
||||
| [`foundry_agent_with_function_tools.py`](foundry_agent_with_function_tools.py) | Foundry Agent with local function tools |
|
||||
|
||||
## FoundryChatClient Samples
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
from agent_framework import Agent
|
||||
from agent_framework.foundry import FoundryAgent, RawFoundryAgentChatClient
|
||||
from azure.identity import AzureCliCredential
|
||||
from dotenv import load_dotenv
|
||||
|
||||
load_dotenv()
|
||||
"""
|
||||
Foundry Agent — Custom client configuration
|
||||
|
||||
@@ -25,9 +27,9 @@ Environment variables:
|
||||
async def main() -> None:
|
||||
# Option 1: Default — full middleware on both agent and client
|
||||
agent = FoundryAgent(
|
||||
project_endpoint="https://your-project.services.ai.azure.com",
|
||||
agent_name="my-agent",
|
||||
agent_version="1.0",
|
||||
project_endpoint=os.getenv("FOUNDRY_PROJECT_ENDPOINT"),
|
||||
agent_name=os.getenv("FOUNDRY_AGENT_NAME"),
|
||||
agent_version=os.getenv("FOUNDRY_AGENT_VERSION"),
|
||||
credential=AzureCliCredential(),
|
||||
)
|
||||
result = await agent.run("Hello from the default setup!")
|
||||
@@ -35,9 +37,9 @@ async def main() -> None:
|
||||
|
||||
# Option 2: Raw client — no client-level middleware (agent middleware still active)
|
||||
agent_raw_client = FoundryAgent(
|
||||
project_endpoint="https://your-project.services.ai.azure.com",
|
||||
agent_name="my-agent",
|
||||
agent_version="1.0",
|
||||
project_endpoint=os.getenv("FOUNDRY_PROJECT_ENDPOINT"),
|
||||
agent_name=os.getenv("FOUNDRY_AGENT_NAME"),
|
||||
agent_version=os.getenv("FOUNDRY_AGENT_VERSION"),
|
||||
credential=AzureCliCredential(),
|
||||
client_type=RawFoundryAgentChatClient,
|
||||
)
|
||||
@@ -47,9 +49,9 @@ async def main() -> None:
|
||||
# Option 3: Composition — use Agent(client=...) directly
|
||||
# this will not run the checks that the `FoundryAgent` does on things like tools.
|
||||
client = RawFoundryAgentChatClient(
|
||||
project_endpoint="https://your-project.services.ai.azure.com",
|
||||
agent_name="my-agent",
|
||||
agent_version="1.0",
|
||||
project_endpoint=os.getenv("FOUNDRY_PROJECT_ENDPOINT"),
|
||||
agent_name=os.getenv("FOUNDRY_AGENT_NAME"),
|
||||
agent_version=os.getenv("FOUNDRY_AGENT_VERSION"),
|
||||
credential=AzureCliCredential(),
|
||||
)
|
||||
agent_composed = Agent(client=client)
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
from agent_framework.foundry import FoundryAgent
|
||||
from azure.identity import AzureCliCredential
|
||||
from dotenv import load_dotenv
|
||||
|
||||
load_dotenv()
|
||||
|
||||
"""
|
||||
Foundry Agent — Connect to a HostedAgent (no version needed)
|
||||
@@ -20,8 +24,8 @@ Environment variables:
|
||||
async def main() -> None:
|
||||
# HostedAgents don't need agent_version
|
||||
agent = FoundryAgent(
|
||||
project_endpoint="https://your-project.services.ai.azure.com",
|
||||
agent_name="my-hosted-agent",
|
||||
project_endpoint=os.getenv("FOUNDRY_PROJECT_ENDPOINT"),
|
||||
agent_name=os.getenv("FOUNDRY_AGENT_NAME"),
|
||||
credential=AzureCliCredential(),
|
||||
)
|
||||
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
from agent_framework.foundry import FoundryAgent
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
"""
|
||||
Foundry Agent with Environment Variables
|
||||
|
||||
This sample shows the recommended pattern for advanced samples that use
|
||||
environment variables for configuration.
|
||||
|
||||
Environment variables:
|
||||
FOUNDRY_PROJECT_ENDPOINT — Azure AI Foundry project endpoint
|
||||
FOUNDRY_AGENT_NAME — Name of the agent in Foundry
|
||||
FOUNDRY_AGENT_VERSION — Version of the agent (optional, for PromptAgents)
|
||||
"""
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
agent = FoundryAgent(
|
||||
project_endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"],
|
||||
agent_name=os.environ["FOUNDRY_AGENT_NAME"],
|
||||
agent_version=os.environ.get("FOUNDRY_AGENT_VERSION"),
|
||||
credential=AzureCliCredential(),
|
||||
)
|
||||
|
||||
session = agent.create_session()
|
||||
|
||||
result = await agent.run("Hello! My name is Alice.", session=session)
|
||||
print(f"Agent: {result}\n")
|
||||
|
||||
result = await agent.run("What's my name?", session=session)
|
||||
print(f"Agent: {result}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -1,13 +1,14 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
from typing import Annotated
|
||||
|
||||
from agent_framework import tool
|
||||
from agent_framework.foundry import FoundryAgent
|
||||
from azure.identity import AzureCliCredential
|
||||
from pydantic import Field
|
||||
from dotenv import load_dotenv
|
||||
|
||||
load_dotenv()
|
||||
"""
|
||||
Foundry Agent with Local Function Tools
|
||||
|
||||
@@ -25,9 +26,8 @@ Environment variables:
|
||||
"""
|
||||
|
||||
|
||||
@tool(approval_mode="never_require")
|
||||
def get_weather(
|
||||
location: Annotated[str, Field(description="The city to get weather for.")],
|
||||
location: Annotated[str, "The city to get weather for."],
|
||||
) -> str:
|
||||
"""Get the current weather for a location."""
|
||||
return f"The weather in {location} is sunny, 22°C."
|
||||
@@ -35,11 +35,11 @@ def get_weather(
|
||||
|
||||
async def main() -> None:
|
||||
agent = FoundryAgent(
|
||||
project_endpoint="https://your-project.services.ai.azure.com",
|
||||
agent_name="my-weather-agent",
|
||||
agent_version="1.0",
|
||||
project_endpoint=os.getenv("FOUNDRY_PROJECT_ENDPOINT"),
|
||||
agent_name=os.getenv("FOUNDRY_AGENT_NAME"),
|
||||
agent_version=os.getenv("FOUNDRY_AGENT_VERSION"),
|
||||
credential=AzureCliCredential(),
|
||||
tools=[get_weather],
|
||||
tools=get_weather,
|
||||
)
|
||||
|
||||
result = await agent.run("What's the weather in Paris?")
|
||||
|
||||
+24
-31
@@ -8,9 +8,8 @@ from agent_framework import Agent
|
||||
from agent_framework.foundry import FoundryChatClient
|
||||
from azure.identity import AzureCliCredential
|
||||
from dotenv import load_dotenv
|
||||
from openai import AsyncAzureOpenAI
|
||||
from openai import AsyncOpenAI
|
||||
|
||||
# Load environment variables from .env file
|
||||
load_dotenv()
|
||||
|
||||
"""
|
||||
@@ -18,12 +17,16 @@ Foundry Chat Client with Code Interpreter and Files Example
|
||||
|
||||
This sample demonstrates using get_code_interpreter_tool() with Responses on Foundry
|
||||
for Python code execution and data analysis with uploaded files.
|
||||
|
||||
Environment variables:
|
||||
FOUNDRY_PROJECT_ENDPOINT — Foundry project endpoint
|
||||
FOUNDRY_MODEL — Foundry model to use (e.g. "gpt-4o-mini")
|
||||
"""
|
||||
|
||||
# Helper functions
|
||||
|
||||
|
||||
async def create_sample_file_and_upload(openai_client: AsyncAzureOpenAI) -> tuple[str, str]:
|
||||
async def create_sample_file_and_upload(openai_client: AsyncOpenAI) -> tuple[str, str]:
|
||||
"""Create a sample CSV file and upload it for Foundry code interpreter use."""
|
||||
csv_data = """name,department,salary,years_experience
|
||||
Alice Johnson,Engineering,95000,5
|
||||
@@ -51,7 +54,7 @@ Frank Wilson,Engineering,88000,6
|
||||
return temp_file_path, uploaded_file.id
|
||||
|
||||
|
||||
async def cleanup_files(openai_client: AsyncAzureOpenAI, temp_file_path: str, file_id: str) -> None:
|
||||
async def cleanup_files(openai_client: AsyncOpenAI, temp_file_path: str, file_id: str) -> None:
|
||||
"""Clean up both local temporary file and uploaded file."""
|
||||
# Clean up: delete the uploaded file
|
||||
await openai_client.files.delete(file_id)
|
||||
@@ -65,39 +68,29 @@ async def cleanup_files(openai_client: AsyncAzureOpenAI, temp_file_path: str, fi
|
||||
async def main() -> None:
|
||||
print("=== Foundry Chat Client with Code Interpreter and File Upload ===")
|
||||
|
||||
# Initialize the underlying OpenAI client for file operations
|
||||
credential = AzureCliCredential()
|
||||
|
||||
async def get_token():
|
||||
token = credential.get_token("https://cognitiveservices.azure.com/.default")
|
||||
return token.token
|
||||
|
||||
openai_client = AsyncAzureOpenAI(
|
||||
azure_ad_token_provider=get_token,
|
||||
api_version="2024-05-01-preview",
|
||||
# Create the FoundryChatClient
|
||||
client = FoundryChatClient(
|
||||
project_endpoint=os.getenv("FOUNDRY_PROJECT_ENDPOINT"),
|
||||
model=os.getenv("FOUNDRY_MODEL"),
|
||||
credential=AzureCliCredential(),
|
||||
)
|
||||
|
||||
# use the openai client from the foundry client to upload files for the code interpreter tool
|
||||
openai_client = client.project_client.get_openai_client()
|
||||
temp_file_path, file_id = await create_sample_file_and_upload(openai_client)
|
||||
|
||||
# Create agent using FoundryChatClient
|
||||
client = FoundryChatClient(credential=credential)
|
||||
|
||||
# Create code interpreter tool with file access
|
||||
code_interpreter_tool = client.get_code_interpreter_tool(file_ids=[file_id])
|
||||
|
||||
# Create agent with code interpreter tool with file access
|
||||
agent = Agent(
|
||||
client=client,
|
||||
instructions="You are a helpful assistant that can analyze data files using Python code.",
|
||||
tools=[code_interpreter_tool],
|
||||
tools=FoundryChatClient.get_code_interpreter_tool(file_ids=[file_id]),
|
||||
)
|
||||
|
||||
# Test the code interpreter with the uploaded file
|
||||
query = "Analyze the employee data in the uploaded CSV file. Calculate average salary by department."
|
||||
print(f"User: {query}")
|
||||
result = await agent.run(query)
|
||||
print(f"Agent: {result.text}")
|
||||
|
||||
await cleanup_files(openai_client, temp_file_path, file_id)
|
||||
try:
|
||||
# Test the code interpreter with the uploaded file
|
||||
query = "Analyze the employee data in the uploaded CSV file. Calculate average salary by department."
|
||||
print(f"User: {query}")
|
||||
result = await agent.run(query)
|
||||
print(f"Agent: {result.text}")
|
||||
finally:
|
||||
await cleanup_files(openai_client, temp_file_path, file_id)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -35,7 +35,7 @@ def get_time():
|
||||
async def main() -> None:
|
||||
client = OllamaChatClient()
|
||||
message = "What time is it? Use a tool call"
|
||||
messages = [Message(role="user", text=message)]
|
||||
messages = [Message(role="user", contents=[message])]
|
||||
stream = False
|
||||
print(f"User: {message}")
|
||||
if stream:
|
||||
|
||||
@@ -256,7 +256,7 @@ async def main() -> None:
|
||||
"""Result hook that wraps the response text in quotes."""
|
||||
if response.text:
|
||||
return ChatResponse(
|
||||
messages=[Message(text=f'"{response.text}"', role="assistant")],
|
||||
messages=[Message(contents=[f'"{response.text}"'], role="assistant")],
|
||||
additional_properties=response.additional_properties,
|
||||
)
|
||||
return response
|
||||
@@ -293,7 +293,7 @@ async def main() -> None:
|
||||
# In real code, this would create an AgentResponse
|
||||
text = "".join(u.text or "" for u in updates)
|
||||
return ChatResponse(
|
||||
messages=[Message(text=f"[AGENT FINAL] {text}", role="assistant")],
|
||||
messages=[Message(contents=[f"[AGENT FINAL] {text}"], role="assistant")],
|
||||
additional_properties={"layer": "agent"},
|
||||
)
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ async def demo_anthropic_chat_client() -> None:
|
||||
|
||||
# Standard options work great:
|
||||
response = await client.get_response(
|
||||
[Message("user", text="What is the capital of France?")],
|
||||
[Message("user", contents=["What is the capital of France?"])],
|
||||
options={
|
||||
"temperature": 1, # Must be 1 when thinking is enabled
|
||||
"max_tokens": 2048,
|
||||
@@ -116,7 +116,7 @@ async def demo_openai_chat_client_reasoning_models() -> None:
|
||||
# With specific options, you get full IDE autocomplete!
|
||||
# Try typing `client.get_response("Hello", options={` and see the suggestions
|
||||
response = await client.get_response(
|
||||
[Message("user", text="What is 2 + 2?")],
|
||||
[Message("user", contents=["What is 2 + 2?"])],
|
||||
options={
|
||||
"max_tokens": 100,
|
||||
"allow_multiple_tool_calls": True,
|
||||
|
||||
Reference in New Issue
Block a user