mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
Python: Remove duplicate samples (#3899)
* Remove duplicate samples * Correct paths * Update readme * Update readme * Fix ruff --------- Co-authored-by: Evan Mattson <35585003+moonbox3@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
Unverified
parent
1441fd903c
commit
e064f943ae
@@ -34,8 +34,8 @@ Key Concepts:
|
||||
|
||||
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production;
|
||||
# See:
|
||||
# samples/getting_started/tools/function_tool_with_approval.py
|
||||
# samples/getting_started/tools/function_tool_with_approval_and_sessions.py.
|
||||
# samples/02-agents/tools/function_tool_with_approval.py
|
||||
# samples/02-agents/tools/function_tool_with_approval_and_sessions.py.
|
||||
@tool(approval_mode="never_require")
|
||||
def process_refund(order_number: Annotated[str, "Order number to process refund for"]) -> str:
|
||||
"""Simulated function to process a refund for a given order number."""
|
||||
|
||||
@@ -11,37 +11,26 @@ from the streaming workflow events.
|
||||
Verifies GitHub issue #2718: files generated by code interpreter in
|
||||
HandoffBuilder workflows can be properly retrieved.
|
||||
|
||||
Toggle USE_V2_CLIENT to switch between:
|
||||
- V1: AzureAIAgentClient (azure-ai-agents SDK)
|
||||
- V2: AzureAIClient (azure-ai-projects 2.x with Responses API)
|
||||
|
||||
IMPORTANT: When using V2 AzureAIClient with HandoffBuilder, each agent must
|
||||
have its own client instance. The V2 client binds to a single server-side
|
||||
agent name, so sharing a client between agents causes routing issues.
|
||||
|
||||
Prerequisites:
|
||||
- AZURE_AI_PROJECT_ENDPOINT must be your Azure AI Foundry Agent Service (V2) project endpoint.
|
||||
- `az login` (Azure CLI authentication)
|
||||
- V1: AZURE_AI_AGENT_PROJECT_CONNECTION_STRING
|
||||
- V2: AZURE_AI_PROJECT_ENDPOINT, AZURE_AI_MODEL_DEPLOYMENT_NAME
|
||||
- AZURE_AI_MODEL_DEPLOYMENT_NAME
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
from collections.abc import AsyncIterable, AsyncIterator
|
||||
from contextlib import asynccontextmanager
|
||||
import os
|
||||
from collections.abc import AsyncIterable
|
||||
from typing import cast
|
||||
|
||||
from agent_framework import (
|
||||
Agent,
|
||||
AgentResponseUpdate,
|
||||
Message,
|
||||
WorkflowEvent,
|
||||
WorkflowRunState,
|
||||
)
|
||||
from agent_framework.azure import AzureOpenAIResponsesClient
|
||||
from agent_framework.orchestrations import HandoffAgentUserRequest, HandoffBuilder
|
||||
from azure.identity.aio import AzureCliCredential
|
||||
|
||||
# Toggle between V1 (AzureAIAgentClient) and V2 (AzureAIClient)
|
||||
USE_V2_CLIENT = False
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
|
||||
async def _drain(stream: AsyncIterable[WorkflowEvent]) -> list[WorkflowEvent]:
|
||||
@@ -66,7 +55,7 @@ def _handle_events(events: list[WorkflowEvent]) -> tuple[list[WorkflowEvent[Hand
|
||||
WorkflowRunState.IDLE,
|
||||
WorkflowRunState.IDLE_WITH_PENDING_REQUESTS,
|
||||
}:
|
||||
print(f"[status] {event.state.name}")
|
||||
print(f"[status] {event.state}")
|
||||
elif event.type == "request_info" and isinstance(event.data, HandoffAgentUserRequest):
|
||||
requests.append(cast(WorkflowEvent[HandoffAgentUserRequest], event))
|
||||
elif event.type == "output":
|
||||
@@ -81,8 +70,8 @@ def _handle_events(events: list[WorkflowEvent]) -> tuple[list[WorkflowEvent[Hand
|
||||
file_id = annotation["file_id"] # type: ignore
|
||||
file_ids.append(file_id)
|
||||
print(f"[Found file annotation: file_id={file_id}]")
|
||||
elif event.type == "output":
|
||||
conversation = cast(list[Message], event.data)
|
||||
elif isinstance(data, list):
|
||||
conversation = cast(list[Message], data)
|
||||
if isinstance(conversation, list):
|
||||
print("\n=== Final Conversation Snapshot ===")
|
||||
for message in conversation:
|
||||
@@ -93,148 +82,104 @@ def _handle_events(events: list[WorkflowEvent]) -> tuple[list[WorkflowEvent[Hand
|
||||
return requests, file_ids
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def create_agents_v1(credential: AzureCliCredential) -> AsyncIterator[tuple[Agent, Agent]]:
|
||||
"""Create agents using V1 AzureAIAgentClient."""
|
||||
from agent_framework.azure import AzureAIAgentClient
|
||||
|
||||
async with AzureAIAgentClient(credential=credential) as client:
|
||||
triage = client.as_agent(
|
||||
name="triage_agent",
|
||||
instructions=(
|
||||
"You are a triage agent. Route code-related requests to the code_specialist. "
|
||||
"When the user asks to create or generate files, hand off to code_specialist "
|
||||
"by calling handoff_to_code_specialist."
|
||||
),
|
||||
)
|
||||
|
||||
# Create code interpreter tool using instance method
|
||||
code_interpreter_tool = client.get_code_interpreter_tool()
|
||||
|
||||
code_specialist = client.as_agent(
|
||||
name="code_specialist",
|
||||
instructions=(
|
||||
"You are a Python code specialist. Use the code interpreter to execute Python code "
|
||||
"and create files when requested. Always save files to /mnt/data/ directory."
|
||||
),
|
||||
tools=[code_interpreter_tool],
|
||||
)
|
||||
|
||||
yield triage, code_specialist # type: ignore
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def create_agents_v2(credential: AzureCliCredential) -> AsyncIterator[tuple[Agent, Agent]]:
|
||||
"""Create agents using V2 AzureAIClient.
|
||||
|
||||
Each agent needs its own client instance because the V2 client binds
|
||||
to a single server-side agent name.
|
||||
"""
|
||||
from agent_framework.azure import AzureAIClient
|
||||
|
||||
async with (
|
||||
AzureAIClient(credential=credential) as triage_client,
|
||||
AzureAIClient(credential=credential) as code_client,
|
||||
):
|
||||
triage = triage_client.as_agent(
|
||||
name="TriageAgent",
|
||||
instructions="You are a triage agent. Your ONLY job is to route requests to the appropriate specialist.",
|
||||
)
|
||||
|
||||
# Create code interpreter tool using instance method
|
||||
code_interpreter_tool = code_client.get_code_interpreter_tool()
|
||||
|
||||
code_specialist = code_client.as_agent(
|
||||
name="CodeSpecialist",
|
||||
instructions=(
|
||||
"You are a Python code specialist. You have access to a code interpreter tool. "
|
||||
"Use the code interpreter to execute Python code and create files. "
|
||||
"Always save files to /mnt/data/ directory. "
|
||||
"Do NOT discuss handoffs or routing - just complete the coding task directly."
|
||||
),
|
||||
tools=[code_interpreter_tool],
|
||||
)
|
||||
|
||||
yield triage, code_specialist
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
"""Run a simple handoff workflow with code interpreter file generation."""
|
||||
client_version = "V2 (AzureAIClient)" if USE_V2_CLIENT else "V1 (AzureAIAgentClient)"
|
||||
print(f"=== Handoff Workflow with Code Interpreter File Generation [{client_version}] ===\n")
|
||||
print("=== Handoff Workflow with Code Interpreter File Generation ===\n")
|
||||
|
||||
async with AzureCliCredential() as credential:
|
||||
create_agents = create_agents_v2 if USE_V2_CLIENT else create_agents_v1
|
||||
client = AzureOpenAIResponsesClient(
|
||||
project_endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"],
|
||||
deployment_name=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"],
|
||||
credential=AzureCliCredential(),
|
||||
)
|
||||
|
||||
async with create_agents(credential) as (triage, code_specialist):
|
||||
workflow = (
|
||||
HandoffBuilder(
|
||||
termination_condition=lambda conv: sum(1 for msg in conv if msg.role == "user") >= 2,
|
||||
)
|
||||
.participants([triage, code_specialist])
|
||||
.with_start_agent(triage)
|
||||
.build()
|
||||
)
|
||||
triage = client.as_agent(
|
||||
name="triage_agent",
|
||||
instructions=(
|
||||
"You are a triage agent. Route code-related requests to the code_specialist. "
|
||||
"When the user asks to create or generate files, hand off to code_specialist "
|
||||
"by calling handoff_to_code_specialist."
|
||||
),
|
||||
)
|
||||
|
||||
user_inputs = [
|
||||
"Please create a text file called hello.txt with 'Hello from handoff workflow!' inside it.",
|
||||
"exit",
|
||||
]
|
||||
input_index = 0
|
||||
all_file_ids: list[str] = []
|
||||
code_interpreter_tool = client.get_code_interpreter_tool()
|
||||
|
||||
print(f"User: {user_inputs[0]}")
|
||||
events = await _drain(workflow.run(user_inputs[0], stream=True))
|
||||
requests, file_ids = _handle_events(events)
|
||||
all_file_ids.extend(file_ids)
|
||||
input_index += 1
|
||||
code_specialist = client.as_agent(
|
||||
name="code_specialist",
|
||||
instructions=(
|
||||
"You are a Python code specialist. Use the code interpreter to execute Python code "
|
||||
"and create files when requested. Always save files to /mnt/data/ directory."
|
||||
),
|
||||
tools=[code_interpreter_tool],
|
||||
)
|
||||
|
||||
while requests:
|
||||
request = requests[0]
|
||||
if input_index >= len(user_inputs):
|
||||
break
|
||||
user_input = user_inputs[input_index]
|
||||
print(f"\nUser: {user_input}")
|
||||
workflow = (
|
||||
HandoffBuilder(
|
||||
termination_condition=lambda conv: sum(1 for msg in conv if msg.role == "user") >= 2,
|
||||
)
|
||||
.participants([triage, code_specialist])
|
||||
.with_start_agent(triage)
|
||||
.build()
|
||||
)
|
||||
|
||||
responses = {request.request_id: HandoffAgentUserRequest.create_response(user_input)}
|
||||
events = await _drain(workflow.run(stream=True, responses=responses))
|
||||
requests, file_ids = _handle_events(events)
|
||||
all_file_ids.extend(file_ids)
|
||||
input_index += 1
|
||||
user_inputs = [
|
||||
"Please create a text file called hello.txt with 'Hello from handoff workflow!' inside it.",
|
||||
"exit",
|
||||
]
|
||||
input_index = 0
|
||||
all_file_ids: list[str] = []
|
||||
|
||||
print("\n" + "=" * 50)
|
||||
if all_file_ids:
|
||||
print(f"SUCCESS: Found {len(all_file_ids)} file ID(s) in handoff workflow:")
|
||||
for fid in all_file_ids:
|
||||
print(f" - {fid}")
|
||||
else:
|
||||
print("WARNING: No file IDs captured from the handoff workflow.")
|
||||
print("=" * 50)
|
||||
print(f"User: {user_inputs[0]}")
|
||||
events = await _drain(workflow.run(user_inputs[0], stream=True))
|
||||
requests, file_ids = _handle_events(events)
|
||||
all_file_ids.extend(file_ids)
|
||||
input_index += 1
|
||||
|
||||
"""
|
||||
Sample Output:
|
||||
while requests:
|
||||
request = requests[0]
|
||||
if input_index >= len(user_inputs):
|
||||
break
|
||||
user_input = user_inputs[input_index]
|
||||
print(f"\nUser: {user_input}")
|
||||
|
||||
User: Please create a text file called hello.txt with 'Hello from handoff workflow!' inside it.
|
||||
[Found HostedFileContent: file_id=assistant-JT1sA...]
|
||||
responses = {request.request_id: HandoffAgentUserRequest.create_response(user_input)}
|
||||
events = await _drain(workflow.run(stream=True, responses=responses))
|
||||
requests, file_ids = _handle_events(events)
|
||||
all_file_ids.extend(file_ids)
|
||||
input_index += 1
|
||||
|
||||
=== Conversation So Far ===
|
||||
- user: Please create a text file called hello.txt with 'Hello from handoff workflow!' inside it.
|
||||
- triage_agent: I am handing off your request to create the text file "hello.txt" with the specified content to the code specialist. They will assist you shortly.
|
||||
- code_specialist: The file "hello.txt" has been created with the content "Hello from handoff workflow!". You can download it using the link below:
|
||||
print("\n" + "=" * 50)
|
||||
if all_file_ids:
|
||||
print(f"SUCCESS: Found {len(all_file_ids)} file ID(s) in handoff workflow:")
|
||||
for fid in all_file_ids:
|
||||
print(f" - {fid}")
|
||||
else:
|
||||
print("WARNING: No file IDs captured from the handoff workflow.")
|
||||
print("=" * 50)
|
||||
|
||||
[hello.txt](sandbox:/mnt/data/hello.txt)
|
||||
===========================
|
||||
"""
|
||||
Sample Output:
|
||||
|
||||
[status] IDLE_WITH_PENDING_REQUESTS
|
||||
User: Please create a text file called hello.txt with 'Hello from handoff workflow!' inside it.
|
||||
[Found HostedFileContent: file_id=assistant-JT1sA...]
|
||||
|
||||
User: exit
|
||||
[status] IDLE
|
||||
=== Conversation So Far ===
|
||||
- user: Please create a text file called hello.txt with 'Hello from handoff workflow!' inside it.
|
||||
- triage_agent: I am handing off your request to create the text file "hello.txt" with the specified content to the code specialist. They will assist you shortly.
|
||||
- code_specialist: The file "hello.txt" has been created with the content "Hello from handoff workflow!". You can download it using the link below:
|
||||
|
||||
==================================================
|
||||
SUCCESS: Found 1 file ID(s) in handoff workflow:
|
||||
- assistant-JT1sA...
|
||||
==================================================
|
||||
""" # noqa: E501
|
||||
[hello.txt](sandbox:/mnt/data/hello.txt)
|
||||
===========================
|
||||
|
||||
[status] IDLE_WITH_PENDING_REQUESTS
|
||||
|
||||
User: exit
|
||||
[status] IDLE
|
||||
|
||||
==================================================
|
||||
SUCCESS: Found 1 file ID(s) in handoff workflow:
|
||||
- assistant-JT1sA...
|
||||
==================================================
|
||||
""" # noqa: E501
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in New Issue
Block a user