mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
Python: Add samples syntax checking with pyright (#3710)
* Add samples syntax checking with pyright - Add pyrightconfig.samples.json with relaxed type checking but import validation - Add samples-syntax poe task to check samples for syntax and import errors - Add samples-syntax to check and pre-commit-check tasks - Fix 78 sample errors: - Update workflow builder imports to use agent_framework_orchestrations - Change content type isinstance checks to content.type comparisons - Use Content factory methods instead of removed content type classes - Fix TypedDict access patterns for Annotation - Fix various API mismatches (normalize_messages, ChatMessage.text, role) * fixed a bunch of samples and tweaks to pre-commit * updated lock * updated lock * fixes * added lint to samples
This commit is contained in:
committed by
GitHub
Unverified
parent
74ac470a56
commit
390f93344c
@@ -18,7 +18,7 @@ from typing import Annotated, Any
|
||||
import uvicorn
|
||||
|
||||
# Agent Framework imports
|
||||
from agent_framework import AgentResponseUpdate, ChatAgent, ChatMessage, FunctionResultContent, Role, tool
|
||||
from agent_framework import AgentResponseUpdate, ChatAgent, ChatMessage, tool
|
||||
from agent_framework.azure import AzureOpenAIChatClient
|
||||
|
||||
# Agent Framework ChatKit integration
|
||||
@@ -281,7 +281,7 @@ class WeatherChatKitServer(ChatKitServer[dict[str, Any]]):
|
||||
|
||||
title_prompt = [
|
||||
ChatMessage(
|
||||
role=Role.USER,
|
||||
role="user",
|
||||
text=(
|
||||
f"Generate a very short, concise title (max 40 characters) for a conversation "
|
||||
f"that starts with:\n\n{conversation_context}\n\n"
|
||||
@@ -332,7 +332,6 @@ class WeatherChatKitServer(ChatKitServer[dict[str, Any]]):
|
||||
runs the agent, converts the response back to ChatKit events using stream_agent_response,
|
||||
and creates interactive weather widgets when weather data is queried.
|
||||
"""
|
||||
from agent_framework import FunctionResultContent
|
||||
|
||||
if input_user_message is None:
|
||||
logger.debug("Received None user message, skipping")
|
||||
@@ -375,7 +374,7 @@ class WeatherChatKitServer(ChatKitServer[dict[str, Any]]):
|
||||
# Check for function results in the update
|
||||
if update.contents:
|
||||
for content in update.contents:
|
||||
if isinstance(content, FunctionResultContent):
|
||||
if content.type == "function_result":
|
||||
result = content.result
|
||||
|
||||
# Check if it's a WeatherResponse (string subclass with weather_data attribute)
|
||||
@@ -458,7 +457,7 @@ class WeatherChatKitServer(ChatKitServer[dict[str, Any]]):
|
||||
weather_data: WeatherData | None = None
|
||||
|
||||
# Create an agent message asking about the weather
|
||||
agent_messages = [ChatMessage(role=Role.USER, text=f"What's the weather in {city_label}?")]
|
||||
agent_messages = [ChatMessage(role="user", text=f"What's the weather in {city_label}?")]
|
||||
|
||||
logger.debug(f"Processing weather query: {agent_messages[0].text}")
|
||||
|
||||
@@ -472,7 +471,7 @@ class WeatherChatKitServer(ChatKitServer[dict[str, Any]]):
|
||||
# Check for function results in the update
|
||||
if update.contents:
|
||||
for content in update.contents:
|
||||
if isinstance(content, FunctionResultContent):
|
||||
if content.type == "function_result":
|
||||
result = content.result
|
||||
|
||||
# Check if it's a WeatherResponse (string subclass with weather_data attribute)
|
||||
@@ -563,7 +562,7 @@ async def chatkit_endpoint(request: Request):
|
||||
|
||||
|
||||
@app.post("/upload/{attachment_id}")
|
||||
async def upload_file(attachment_id: str, file: UploadFile = File(...)):
|
||||
async def upload_file(attachment_id: str, file: Annotated[UploadFile, File()]):
|
||||
"""Handle file upload for two-phase upload.
|
||||
|
||||
The client POSTs the file bytes here after creating the attachment
|
||||
@@ -585,7 +584,7 @@ async def upload_file(attachment_id: str, file: UploadFile = File(...)):
|
||||
attachment = await data_store.load_attachment(attachment_id, {"user_id": DEFAULT_USER_ID})
|
||||
|
||||
# Clear the upload_url since upload is complete
|
||||
attachment.upload_url = None
|
||||
attachment.upload_url = None # type: ignore[union-attr]
|
||||
|
||||
# Save the updated attachment back to the store
|
||||
await data_store.save_attachment(attachment, {"user_id": DEFAULT_USER_ID})
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from agent_framework import ConcurrentBuilder
|
||||
from agent_framework.azure import AzureOpenAIChatClient
|
||||
from agent_framework_orchestrations import ConcurrentBuilder
|
||||
from azure.ai.agentserver.agentframework import from_agent_framework
|
||||
from azure.identity import DefaultAzureCredential # pyright: ignore[reportUnknownVariableType]
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ def search_hotels(
|
||||
guests: Annotated[int, Field(description="Number of guests.")] = 2,
|
||||
) -> str:
|
||||
"""Search for available hotels based on location and dates.
|
||||
|
||||
|
||||
Returns:
|
||||
JSON string containing search results with hotel details including name, rating,
|
||||
price, distance to landmarks, amenities, and availability.
|
||||
@@ -88,7 +88,7 @@ def get_hotel_details(
|
||||
hotel_name: Annotated[str, Field(description="Name of the hotel to get details for.")],
|
||||
) -> str:
|
||||
"""Get detailed information about a specific hotel.
|
||||
|
||||
|
||||
Returns:
|
||||
JSON string containing detailed hotel information including description,
|
||||
check-in/out times, cancellation policy, reviews, and nearby attractions.
|
||||
@@ -167,7 +167,7 @@ def search_flights(
|
||||
passengers: Annotated[int, Field(description="Number of passengers.")] = 1,
|
||||
) -> str:
|
||||
"""Search for available flights between two locations.
|
||||
|
||||
|
||||
Returns:
|
||||
JSON string containing flight search results with details including flight numbers,
|
||||
airlines, departure/arrival times, prices, durations, and baggage allowances.
|
||||
@@ -289,7 +289,7 @@ def get_flight_details(
|
||||
flight_number: Annotated[str, Field(description="Flight number (e.g., 'AF007' or 'DL264').")],
|
||||
) -> str:
|
||||
"""Get detailed information about a specific flight.
|
||||
|
||||
|
||||
Returns:
|
||||
JSON string containing detailed flight information including airline, aircraft type,
|
||||
departure/arrival airports and times, gates, terminals, duration, and amenities.
|
||||
@@ -331,7 +331,7 @@ def search_activities(
|
||||
category: Annotated[str | None, Field(description="Activity category (e.g., 'Sightseeing', 'Culture', 'Culinary').")] = None,
|
||||
) -> str:
|
||||
"""Search for available activities and attractions at a destination.
|
||||
|
||||
|
||||
Returns:
|
||||
JSON string containing activity search results with details including name, category,
|
||||
duration, price, rating, description, availability, and booking requirements.
|
||||
@@ -440,10 +440,7 @@ def search_activities(
|
||||
}
|
||||
]
|
||||
|
||||
if category:
|
||||
activities = [act for act in all_activities if act["category"] == category]
|
||||
else:
|
||||
activities = all_activities
|
||||
activities = [act for act in all_activities if act["category"] == category] if category else all_activities
|
||||
else:
|
||||
activities = [
|
||||
{
|
||||
@@ -473,7 +470,7 @@ def get_activity_details(
|
||||
activity_name: Annotated[str, Field(description="Name of the activity to get details for.")],
|
||||
) -> str:
|
||||
"""Get detailed information about a specific activity.
|
||||
|
||||
|
||||
Returns:
|
||||
JSON string containing detailed activity information including description, duration,
|
||||
price, included items, meeting point, what to bring, cancellation policy, and reviews.
|
||||
@@ -552,7 +549,7 @@ def confirm_booking(
|
||||
customer_info: Annotated[dict, Field(description="Customer information including name and email.")],
|
||||
) -> str:
|
||||
"""Confirm a booking reservation.
|
||||
|
||||
|
||||
Returns:
|
||||
JSON string containing confirmation details including confirmation number,
|
||||
booking status, customer information, and next steps.
|
||||
@@ -587,9 +584,9 @@ def check_hotel_availability(
|
||||
rooms: Annotated[int, Field(description="Number of rooms needed.")] = 1,
|
||||
) -> str:
|
||||
"""Check availability for hotel rooms.
|
||||
|
||||
|
||||
Sample Date format: "December 15, 2025"
|
||||
|
||||
|
||||
Returns:
|
||||
JSON string containing availability status, available rooms count, price per night,
|
||||
and last checked timestamp.
|
||||
@@ -621,9 +618,9 @@ def check_flight_availability(
|
||||
passengers: Annotated[int, Field(description="Number of passengers.")] = 1,
|
||||
) -> str:
|
||||
"""Check availability for flight seats.
|
||||
|
||||
|
||||
Sample Date format: "December 15, 2025"
|
||||
|
||||
|
||||
Returns:
|
||||
JSON string containing availability status, available seats count, price per passenger,
|
||||
and last checked timestamp.
|
||||
@@ -654,9 +651,9 @@ def check_activity_availability(
|
||||
participants: Annotated[int, Field(description="Number of participants.")] = 1,
|
||||
) -> str:
|
||||
"""Check availability for activity bookings.
|
||||
|
||||
|
||||
Sample Date format: "December 16, 2025"
|
||||
|
||||
|
||||
Returns:
|
||||
JSON string containing availability status, available spots count, price per person,
|
||||
and last checked timestamp.
|
||||
@@ -688,7 +685,7 @@ def process_payment(
|
||||
booking_reference: Annotated[str, Field(description="Booking reference number for the payment.")],
|
||||
) -> str:
|
||||
"""Process payment for a booking.
|
||||
|
||||
|
||||
Returns:
|
||||
JSON string containing payment result with transaction ID, status, amount, currency,
|
||||
payment method details, and receipt URL.
|
||||
@@ -718,7 +715,7 @@ def validate_payment_method(
|
||||
payment_method: Annotated[dict, Field(description="Payment method to validate (type, number, expiry, cvv).")],
|
||||
) -> str:
|
||||
"""Validate payment method details.
|
||||
|
||||
|
||||
Returns:
|
||||
JSON string containing validation result with is_valid flag, payment method type,
|
||||
validation messages, supported currencies, and processing fee information.
|
||||
|
||||
@@ -154,19 +154,19 @@ async def run_workflow_with_response_tracking(query: str, chat_client: AzureAICl
|
||||
"""
|
||||
if chat_client is None:
|
||||
try:
|
||||
# Create AIProjectClient with the correct API version for V2 prompt agents
|
||||
project_client = AIProjectClient(
|
||||
endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"],
|
||||
credential=credential,
|
||||
api_version="2025-11-15-preview",
|
||||
)
|
||||
async with DefaultAzureCredential() as credential:
|
||||
# Create AIProjectClient with the correct API version for V2 prompt agents
|
||||
project_client = AIProjectClient(
|
||||
endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"],
|
||||
credential=credential,
|
||||
api_version="2025-11-15-preview",
|
||||
)
|
||||
|
||||
async with (
|
||||
DefaultAzureCredential() as credential,
|
||||
project_client,
|
||||
AzureAIClient(project_client=project_client, credential=credential) as client,
|
||||
):
|
||||
return await _run_workflow_with_client(query, client)
|
||||
async with (
|
||||
project_client,
|
||||
AzureAIClient(project_client=project_client, credential=credential) as client,
|
||||
):
|
||||
return await _run_workflow_with_client(query, client)
|
||||
except Exception as e:
|
||||
print(f"Error during workflow execution: {e}")
|
||||
raise
|
||||
@@ -369,27 +369,36 @@ async def _process_workflow_events(events, conversation_ids, response_ids):
|
||||
|
||||
def _track_agent_ids(event, agent, response_ids, conversation_ids):
|
||||
"""Track agent response and conversation IDs - supporting multiple responses per agent."""
|
||||
if isinstance(event.data, AgentResponseUpdate):
|
||||
if (
|
||||
isinstance(event.data, AgentResponseUpdate)
|
||||
and hasattr(event.data, "raw_representation")
|
||||
and event.data.raw_representation
|
||||
):
|
||||
# Check for conversation_id and response_id from raw_representation
|
||||
# V2 API stores conversation_id directly on raw_representation (ChatResponseUpdate)
|
||||
if hasattr(event.data, "raw_representation") and event.data.raw_representation:
|
||||
raw = event.data.raw_representation
|
||||
raw = event.data.raw_representation
|
||||
|
||||
# Try conversation_id directly on raw representation
|
||||
if hasattr(raw, "conversation_id") and raw.conversation_id:
|
||||
# Try conversation_id directly on raw representation
|
||||
if (
|
||||
hasattr(raw, "conversation_id")
|
||||
and raw.conversation_id # type: ignore[union-attr]
|
||||
and raw.conversation_id not in conversation_ids[agent] # type: ignore[union-attr]
|
||||
):
|
||||
# Only add if not already in the list
|
||||
conversation_ids[agent].append(raw.conversation_id) # type: ignore[union-attr]
|
||||
|
||||
# Extract response_id from the OpenAI event (available from first event)
|
||||
if hasattr(raw, "raw_representation") and raw.raw_representation: # type: ignore[union-attr]
|
||||
openai_event = raw.raw_representation # type: ignore[union-attr]
|
||||
|
||||
# Check if event has response object with id
|
||||
if (
|
||||
hasattr(openai_event, "response")
|
||||
and hasattr(openai_event.response, "id")
|
||||
and openai_event.response.id not in response_ids[agent]
|
||||
):
|
||||
# Only add if not already in the list
|
||||
if raw.conversation_id not in conversation_ids[agent]:
|
||||
conversation_ids[agent].append(raw.conversation_id)
|
||||
|
||||
# Extract response_id from the OpenAI event (available from first event)
|
||||
if hasattr(raw, "raw_representation") and raw.raw_representation:
|
||||
openai_event = raw.raw_representation
|
||||
|
||||
# Check if event has response object with id
|
||||
if hasattr(openai_event, "response") and hasattr(openai_event.response, "id"):
|
||||
# Only add if not already in the list
|
||||
if openai_event.response.id not in response_ids[agent]:
|
||||
response_ids[agent].append(openai_event.response.id)
|
||||
response_ids[agent].append(openai_event.response.id)
|
||||
|
||||
|
||||
async def create_and_run_workflow():
|
||||
|
||||
@@ -29,7 +29,7 @@ def print_section(title: str):
|
||||
|
||||
async def run_workflow():
|
||||
"""Execute the multi-agent travel planning workflow.
|
||||
|
||||
|
||||
Returns:
|
||||
Dictionary containing workflow data with agent response IDs
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user