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:
Eduard van Valkenburg
2026-02-07 08:10:47 +01:00
committed by GitHub
Unverified
parent 74ac470a56
commit 390f93344c
83 changed files with 606 additions and 498 deletions
@@ -4,10 +4,10 @@ import asyncio
from random import randint
from typing import Annotated
from agent_framework import ChatResponse, tool
from agent_framework import tool
from agent_framework.azure import AzureOpenAIResponsesClient
from azure.identity import AzureCliCredential
from pydantic import BaseModel, Field
from pydantic import BaseModel
"""
Azure Responses Client Direct Usage Example
@@ -20,42 +20,75 @@ Shows function calling capabilities with custom business logic.
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; see samples/getting_started/tools/function_tool_with_approval.py and samples/getting_started/tools/function_tool_with_approval_and_threads.py.
@tool(approval_mode="never_require")
def get_weather(
location: Annotated[str, Field(description="The location to get the weather for.")],
location: Annotated[str, "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."
class OutputStruct(BaseModel):
@tool(approval_mode="never_require")
def get_time():
"""Get the current time."""
from datetime import datetime
now = datetime.now()
return f"The current date time is {now.strftime('%Y-%m-%d - %H:%M:%S')}."
class WeatherDetail(BaseModel):
"""Structured output for weather information."""
location: str
weather: str
class Weather(BaseModel):
"""Container for multiple outputs."""
date_time: str
weather_details: list[WeatherDetail]
async def main() -> None:
# For authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
# authentication option.
client = AzureOpenAIResponsesClient(credential=AzureCliCredential())
client = AzureOpenAIResponsesClient(credential=AzureCliCredential(), api_version="preview")
message = "What's the weather in Amsterdam and in Paris?"
stream = True
print(f"User: {message}")
response = client.get_response(
message,
options={"response_format": Weather, "tools": [get_weather, get_time]},
stream=stream,
)
if stream:
response = await ChatResponse.from_chat_response_generator(
client.get_response(message, tools=get_weather, options={"response_format": OutputStruct}, stream=True),
output_format_type=OutputStruct,
)
if result := response.try_parse_value(OutputStruct):
print(f"Assistant: {result}")
else:
print(f"Assistant: {response.text}")
response = await response.get_final_response()
else:
response = await client.get_response(message, tools=get_weather, options={"response_format": OutputStruct})
if result := response.try_parse_value(OutputStruct):
print(f"Assistant: {result}")
else:
print(f"Assistant: {response.text}")
response = await response
if result := response.value:
print(f"Assistant: {result.model_dump_json(indent=2)}")
else:
print(f"Assistant: {response.text}")
# Expected output (time will be different):
"""
User: What's the weather in Amsterdam and in Paris?
Assistant: {
"date_time": "2026-02-06 - 13:30:40",
"weather_details": [
{
"location": "Amsterdam",
"weather": "The weather in Amsterdam is cloudy with a high of 21°C."
},
{
"location": "Paris",
"weather": "The weather in Paris is sunny with a high of 27°C."
}
]
}
"""
if __name__ == "__main__":
@@ -4,13 +4,12 @@ import asyncio
import random
import sys
from collections.abc import AsyncIterable, Awaitable, Mapping, Sequence
from typing import Any, ClassVar, Generic, TypedDict
from typing import Any, ClassVar, Generic
from agent_framework import (
BaseChatClient,
ChatMessage,
ChatMiddlewareLayer,
ChatOptions,
ChatResponse,
ChatResponseUpdate,
Content,
@@ -22,9 +21,9 @@ from agent_framework._clients import TOptions_co
from agent_framework.observability import ChatTelemetryLayer
if sys.version_info >= (3, 13):
from typing import TypeVar
pass
else:
from typing_extensions import TypeVar
pass
if sys.version_info >= (3, 12):
from typing import override # type: ignore # pragma: no cover
else:
@@ -38,13 +37,6 @@ This sample demonstrates implementing a custom chat client and optionally compos
middleware, telemetry, and function invocation layers explicitly.
"""
TOptions_co = TypeVar(
"TOptions_co",
bound=TypedDict, # type: ignore[valid-type]
default="ChatOptions",
covariant=True,
)
class EchoingChatClient(BaseChatClient[TOptions_co], Generic[TOptions_co]):
"""A custom chat client that echoes messages back with modifications.
@@ -32,14 +32,14 @@ async def main() -> None:
message = "What's the weather in Amsterdam and in Paris?"
stream = True
print(f"User: {message}")
print("Assistant: ", end="")
response = client.get_response(message, stream=stream, options={"tools": get_weather})
if stream:
print("Assistant: ", end="")
response = client.get_response(message, stream=True, tools=get_weather)
# TODO: review names of the methods, could be related to things like HTTP clients?
response.with_update_hook(lambda chunk: print(chunk.text, end=""))
response.with_transform_hook(lambda chunk: print(chunk.text, end=""))
await response.get_final_response()
else:
response = await client.get_response(message, tools=get_weather)
response = await response
print(f"Assistant: {response}")