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
@@ -6,11 +6,10 @@ from pathlib import Path
from agent_framework import (
AgentResponseUpdate,
Annotation,
ChatAgent,
CitationAnnotation,
Content,
HostedCodeInterpreterTool,
HostedFileContent,
TextContent,
)
from agent_framework.azure import AzureAIProjectAgentProvider
from azure.identity.aio import AzureCliCredential
@@ -34,19 +33,17 @@ QUERY = (
)
async def download_container_files(
file_contents: list[CitationAnnotation | HostedFileContent], agent: ChatAgent
) -> list[Path]:
async def download_container_files(file_contents: list[Annotation | Content], agent: ChatAgent) -> list[Path]:
"""Download container files using the OpenAI containers API.
Code interpreter generates files in containers, which require both file_id
and container_id to download. The container_id is stored in additional_properties.
This function works for both streaming (HostedFileContent) and non-streaming
(CitationAnnotation) responses.
This function works for both streaming (Content with type="hosted_file") and non-streaming
(Annotation) responses.
Args:
file_contents: List of CitationAnnotation or HostedFileContent objects
file_contents: List of Annotation or Content objects
containing file_id and container_id.
agent: The ChatAgent instance with access to the AzureAIClient.
@@ -64,28 +61,36 @@ async def download_container_files(
print(f"\nDownloading {len(file_contents)} container file(s) to {output_dir.absolute()}...")
# Access the OpenAI client from AzureAIClient
openai_client = agent.chat_client.client
openai_client = agent.chat_client.client # type: ignore[attr-defined]
downloaded_files: list[Path] = []
for content in file_contents:
file_id = content.file_id
# Handle both Annotation (TypedDict) and Content objects
if isinstance(content, dict): # Annotation TypedDict
file_id = content.get("file_id")
additional_props = content.get("additional_properties", {})
url = content.get("url")
else: # Content object
file_id = content.file_id
additional_props = content.additional_properties or {}
url = content.uri
# Extract container_id from additional_properties
if not content.additional_properties or "container_id" not in content.additional_properties:
if not additional_props or "container_id" not in additional_props:
print(f" File {file_id}: ✗ Missing container_id")
continue
container_id = content.additional_properties["container_id"]
container_id = additional_props["container_id"]
# Extract filename based on content type
if isinstance(content, CitationAnnotation):
filename = content.url or f"{file_id}.txt"
if isinstance(content, dict): # Annotation TypedDict
filename = url or f"{file_id}.txt"
# Extract filename from sandbox URL if present (e.g., sandbox:/mnt/data/sample.txt)
if filename.startswith("sandbox:"):
filename = filename.split("/")[-1]
else: # HostedFileContent
filename = content.additional_properties.get("filename") or f"{file_id}.txt"
else: # Content
filename = additional_props.get("filename") or f"{file_id}.txt"
output_path = output_dir / filename
@@ -133,17 +138,18 @@ async def non_streaming_example() -> None:
print(f"Agent: {result.text}\n")
# Check for annotations in the response
annotations_found: list[CitationAnnotation] = []
annotations_found: list[Annotation] = []
# AgentResponse has messages property, which contains ChatMessage objects
for message in result.messages:
for content in message.contents:
if content.type == "text" and content.annotations:
for annotation in content.annotations:
if isinstance(annotation, CitationAnnotation) and annotation.file_id:
if annotation.get("file_id"):
annotations_found.append(annotation)
print(f"Found file annotation: file_id={annotation.file_id}")
if annotation.additional_properties and "container_id" in annotation.additional_properties:
print(f" container_id={annotation.additional_properties['container_id']}")
print(f"Found file annotation: file_id={annotation['file_id']}")
additional_props = annotation.get("additional_properties", {})
if additional_props and "container_id" in additional_props:
print(f" container_id={additional_props['container_id']}")
if annotations_found:
print(f"SUCCESS: Found {len(annotations_found)} file annotation(s)")
@@ -174,7 +180,7 @@ async def streaming_example() -> None:
)
print(f"User: {QUERY}\n")
file_contents_found: list[HostedFileContent] = []
file_contents_found: list[Content] = []
text_chunks: list[str] = []
async for update in agent.run(QUERY, stream=True):
@@ -185,11 +191,11 @@ async def streaming_example() -> None:
text_chunks.append(content.text)
if content.annotations:
for annotation in content.annotations:
if isinstance(annotation, CitationAnnotation) and annotation.file_id:
print(f"Found streaming CitationAnnotation: file_id={annotation.file_id}")
elif isinstance(content, HostedFileContent):
if annotation.get("file_id"):
print(f"Found streaming annotation: file_id={annotation['file_id']}")
elif content.type == "hosted_file":
file_contents_found.append(content)
print(f"Found streaming HostedFileContent: file_id={content.file_id}")
print(f"Found streaming hosted_file: file_id={content.file_id}")
if content.additional_properties and "container_id" in content.additional_properties:
print(f" container_id={content.additional_properties['container_id']}")
@@ -49,9 +49,9 @@ async def non_streaming_example() -> None:
for content in message.contents:
if content.type == "text" and content.annotations:
for annotation in content.annotations:
if annotation.file_id:
annotations_found.append(annotation.file_id)
print(f"Found file annotation: file_id={annotation.file_id}")
if annotation.get("file_id"):
annotations_found.append(annotation["file_id"])
print(f"Found file annotation: file_id={annotation['file_id']}")
if annotations_found:
print(f"SUCCESS: Found {len(annotations_found)} file annotation(s)")
@@ -86,9 +86,9 @@ async def streaming_example() -> None:
text_chunks.append(content.text)
if content.annotations:
for annotation in content.annotations:
if annotation.file_id:
annotations_found.append(annotation.file_id)
print(f"Found streaming annotation: file_id={annotation.file_id}")
if annotation.get("file_id"):
annotations_found.append(annotation["file_id"])
print(f"Found streaming annotation: file_id={annotation['file_id']}")
elif content.type == "hosted_file":
file_ids_found.append(content.file_id)
print(f"Found streaming HostedFileContent: file_id={content.file_id}")
@@ -4,7 +4,7 @@ import asyncio
import os
from pathlib import Path
from agent_framework import HostedFileSearchTool, HostedVectorStoreContent
from agent_framework import Content, HostedFileSearchTool
from agent_framework.azure import AzureAIProjectAgentProvider
from azure.ai.agents.aio import AgentsClient
from azure.ai.agents.models import FileInfo, VectorStore
@@ -46,7 +46,7 @@ async def main() -> None:
print(f"Created vector store, vector store ID: {vector_store.id}")
# 2. Create file search tool with uploaded resources
file_search_tool = HostedFileSearchTool(inputs=[HostedVectorStoreContent(vector_store_id=vector_store.id)])
file_search_tool = HostedFileSearchTool(inputs=[Content.from_hosted_vector_store(vector_store_id=vector_store.id)])
# 3. Create an agent with file search capabilities using the provider
agent = await provider.create_agent(
@@ -3,7 +3,7 @@
import asyncio
from typing import Any
from agent_framework import SupportsAgentRun, AgentResponse, AgentThread, ChatMessage, HostedMCPTool
from agent_framework import AgentResponse, AgentThread, ChatMessage, HostedMCPTool, SupportsAgentRun
from agent_framework.azure import AzureAIProjectAgentProvider
from azure.identity.aio import AzureCliCredential