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
@@ -27,12 +27,6 @@ repos:
|
||||
name: Check Valid Python Samples
|
||||
types: ["python"]
|
||||
exclude: ^python/packages/lab/cookiecutter-agent-framework-lab/
|
||||
- repo: https://github.com/nbQA-dev/nbQA
|
||||
rev: 1.9.1
|
||||
hooks:
|
||||
- id: nbqa-check-ast
|
||||
name: Check Valid Python Notebooks
|
||||
types: ["jupyter"]
|
||||
- repo: https://github.com/asottile/pyupgrade
|
||||
rev: v3.20.0
|
||||
hooks:
|
||||
@@ -47,6 +41,13 @@ repos:
|
||||
entry: uv --directory ./python run poe pre-commit-check
|
||||
language: system
|
||||
files: ^python/
|
||||
- repo: https://github.com/PyCQA/bandit
|
||||
rev: 1.8.5
|
||||
hooks:
|
||||
- id: bandit
|
||||
name: Bandit Security Checks
|
||||
args: ["-c", "python/pyproject.toml"]
|
||||
additional_dependencies: ["bandit[toml]"]
|
||||
- repo: https://github.com/astral-sh/uv-pre-commit
|
||||
# uv version.
|
||||
rev: 0.7.18
|
||||
@@ -56,10 +57,3 @@ repos:
|
||||
name: Update uv lockfile
|
||||
files: python/pyproject.toml
|
||||
args: [--project, python]
|
||||
- repo: https://github.com/PyCQA/bandit
|
||||
rev: 1.8.5
|
||||
hooks:
|
||||
- id: bandit
|
||||
name: Bandit Security Checks
|
||||
args: ["-c", "python/pyproject.toml"]
|
||||
additional_dependencies: ["bandit[toml]"]
|
||||
|
||||
@@ -72,6 +72,12 @@ from agent_framework.azure import AzureOpenAIChatClient, AzureAIAgentClient
|
||||
|
||||
When modifying samples, update associated README files in the same or parent folders.
|
||||
|
||||
### Samples Syntax Checking
|
||||
|
||||
Run `uv run poe samples-syntax` to check samples for syntax errors and missing imports from `agent_framework`. This uses a relaxed pyright configuration that validates imports without strict type checking.
|
||||
|
||||
Some samples depend on external packages (e.g., `azure.ai.agentserver.agentframework`, `microsoft_agents`) that are not installed in the dev environment. These are excluded in `pyrightconfig.samples.json`. When adding or modifying these excluded samples, add them to the exclude list and manually verify they have no import errors from `agent_framework` packages by temporarily removing them from the exclude list and running the check.
|
||||
|
||||
## Package Documentation
|
||||
|
||||
### Core
|
||||
|
||||
@@ -6,6 +6,7 @@ import base64
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
from asyncio import iscoroutine
|
||||
from collections.abc import AsyncIterable, AsyncIterator, Awaitable, Callable, Mapping, MutableMapping, Sequence
|
||||
from copy import deepcopy
|
||||
from typing import TYPE_CHECKING, Any, ClassVar, Final, Generic, Literal, NewType, cast, overload
|
||||
@@ -2676,7 +2677,10 @@ class ResponseStream(AsyncIterable[TUpdate], Generic[TUpdate, TFinal]):
|
||||
if hasattr(self._stream_source, "__aiter__"):
|
||||
self._stream = self._stream_source # type: ignore[assignment]
|
||||
else:
|
||||
self._stream = await self._stream_source # type: ignore[assignment]
|
||||
if not iscoroutine(self._stream_source):
|
||||
self._stream = self._stream_source # type: ignore[assignment]
|
||||
else:
|
||||
self._stream = await self._stream_source # type: ignore[assignment]
|
||||
if isinstance(self._stream, ResponseStream) and self._wrap_inner:
|
||||
self._inner_stream = self._stream
|
||||
return self._stream
|
||||
@@ -2739,12 +2743,12 @@ class ResponseStream(AsyncIterable[TUpdate], Generic[TUpdate, TFinal]):
|
||||
"""
|
||||
if self._wrap_inner:
|
||||
if self._inner_stream is None:
|
||||
if self._inner_stream_source is None:
|
||||
raise ValueError("No inner stream configured for this stream.")
|
||||
if isinstance(self._inner_stream_source, ResponseStream):
|
||||
self._inner_stream = self._inner_stream_source
|
||||
else:
|
||||
self._inner_stream = await self._inner_stream_source
|
||||
# Use _get_stream() to resolve the awaitable - this properly handles
|
||||
# the case where _stream_source and _inner_stream_source are the same
|
||||
# coroutine (e.g., from from_awaitable), avoiding double-await errors.
|
||||
await self._get_stream()
|
||||
if self._inner_stream is None:
|
||||
raise RuntimeError("Inner stream not available")
|
||||
if not self._finalized:
|
||||
# Consume outer stream (which delegates to inner) if not already consumed
|
||||
if not self._consumed:
|
||||
|
||||
@@ -225,8 +225,10 @@ test = "python run_tasks_in_packages_if_exists.py test"
|
||||
fmt = "python run_tasks_in_packages_if_exists.py fmt"
|
||||
format.ref = "fmt"
|
||||
lint = "python run_tasks_in_packages_if_exists.py lint"
|
||||
samples-lint = "ruff check samples --fix --exclude samples/autogen-migration,samples/semantic-kernel-migration --ignore E501,ASYNC,B901,TD002"
|
||||
pyright = "python run_tasks_in_packages_if_exists.py pyright"
|
||||
mypy = "python run_tasks_in_packages_if_exists.py mypy"
|
||||
samples-syntax = "pyright -p pyrightconfig.samples.json --warnings"
|
||||
typing = ["pyright", "mypy"]
|
||||
# cleaning
|
||||
clean-dist-packages = "python run_tasks_in_packages_if_exists.py clean-dist"
|
||||
@@ -238,7 +240,7 @@ build-meta = "python -m flit build"
|
||||
build = ["build-packages", "build-meta"]
|
||||
publish = "uv publish"
|
||||
# combined checks
|
||||
check = ["fmt", "lint", "pyright", "mypy", "test", "markdown-code-lint"]
|
||||
check = ["fmt", "lint", "pyright", "mypy", "samples-lint", "samples-syntax", "test", "markdown-code-lint"]
|
||||
|
||||
[tool.poe.tasks.all-tests-cov]
|
||||
cmd = """
|
||||
@@ -323,7 +325,9 @@ sequence = [
|
||||
{ ref = "fmt" },
|
||||
{ ref = "lint" },
|
||||
{ ref = "pre-commit-pyright ${files}" },
|
||||
{ ref = "pre-commit-markdown-code-lint ${files}" }
|
||||
{ ref = "pre-commit-markdown-code-lint ${files}" },
|
||||
{ ref = "samples-lint" },
|
||||
{ ref = "samples-syntax" }
|
||||
]
|
||||
args = [{ name = "files", default = ".", positional = true, multiple = true }]
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"include": ["samples"],
|
||||
"exclude": [
|
||||
"**/autogen/**",
|
||||
"**/autogen-migration/**",
|
||||
"**/semantic-kernel-migration/**",
|
||||
"**/demos/**",
|
||||
"**/agent_with_foundry_tracing.py"
|
||||
],
|
||||
"typeCheckingMode": "off",
|
||||
"reportMissingImports": "error",
|
||||
"reportAttributeAccessIssue": "error"
|
||||
}
|
||||
@@ -7,7 +7,7 @@ to other specialized agents based on the task requirements.
|
||||
|
||||
import asyncio
|
||||
|
||||
from agent_framework import WorkflowEvent
|
||||
from agent_framework import AgentResponseUpdate, WorkflowEvent
|
||||
from orderedmultidict import Any
|
||||
|
||||
|
||||
@@ -99,7 +99,6 @@ async def run_autogen() -> None:
|
||||
async def run_agent_framework() -> None:
|
||||
"""Agent Framework's HandoffBuilder for agent coordination."""
|
||||
from agent_framework import (
|
||||
AgentResponseUpdate,
|
||||
WorkflowRunState,
|
||||
)
|
||||
from agent_framework.openai import OpenAIChatClient
|
||||
|
||||
@@ -48,7 +48,7 @@ async def run_autogen() -> None:
|
||||
|
||||
async def run_agent_framework() -> None:
|
||||
"""Agent Framework's as_tool() for hierarchical agents with streaming."""
|
||||
from agent_framework import FunctionCallContent, FunctionResultContent
|
||||
from agent_framework import Content
|
||||
from agent_framework.openai import OpenAIChatClient
|
||||
|
||||
client = OpenAIChatClient(model_id="gpt-4.1-mini")
|
||||
@@ -78,7 +78,7 @@ async def run_agent_framework() -> None:
|
||||
print("[Agent Framework]")
|
||||
|
||||
# Track accumulated function calls (they stream in incrementally)
|
||||
accumulated_calls: dict[str, FunctionCallContent] = {}
|
||||
accumulated_calls: dict[str, Content] = {}
|
||||
|
||||
async for chunk in coordinator.run("Create a tagline for a coffee shop", stream=True):
|
||||
# Stream text tokens
|
||||
@@ -88,7 +88,7 @@ async def run_agent_framework() -> None:
|
||||
# Process streaming function calls and results
|
||||
if chunk.contents:
|
||||
for content in chunk.contents:
|
||||
if isinstance(content, FunctionCallContent):
|
||||
if content.type == "function_call":
|
||||
# Accumulate function call content as it streams in
|
||||
call_id = content.call_id
|
||||
if call_id in accumulated_calls:
|
||||
@@ -105,7 +105,7 @@ async def run_agent_framework() -> None:
|
||||
current_args = accumulated_calls[call_id].arguments
|
||||
print(f" Arguments: {current_args}", flush=True)
|
||||
|
||||
elif isinstance(content, FunctionResultContent):
|
||||
elif content.type == "function_result":
|
||||
# Tool result - shows writer's response
|
||||
result_text = content.result if isinstance(content.result, str) else str(content.result)
|
||||
if result_text.strip():
|
||||
|
||||
@@ -154,11 +154,11 @@ async def main() -> None:
|
||||
words = ["Hello", " ", "from", " ", "the", " ", "streaming", " ", "response", "!"]
|
||||
for word in words:
|
||||
await asyncio.sleep(0.05) # Simulate network delay
|
||||
yield ChatResponseUpdate(contents=[Content.from_text(word)], role=Role.ASSISTANT)
|
||||
yield ChatResponseUpdate(contents=[Content.from_text(word)], role="assistant")
|
||||
|
||||
def combine_updates(updates: Sequence[ChatResponseUpdate]) -> ChatResponse:
|
||||
"""Finalizer that combines all updates into a single response."""
|
||||
return ChatResponse.from_chat_response_updates(updates)
|
||||
return ChatResponse.from_updates(updates)
|
||||
|
||||
stream = ResponseStream(generate_updates(), finalizer=combine_updates)
|
||||
|
||||
@@ -237,7 +237,7 @@ async def main() -> None:
|
||||
)
|
||||
|
||||
print("Starting iteration (cleanup happens after):")
|
||||
async for update in stream4:
|
||||
async for _update in stream4:
|
||||
pass # Just consume the stream
|
||||
print(f"Cleanup was performed: {cleanup_performed['value']}")
|
||||
|
||||
|
||||
@@ -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
|
||||
"""
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import asyncio
|
||||
|
||||
from agent_framework import HostedMCPTool, HostedWebSearchTool, TextReasoningContent, UsageContent
|
||||
from agent_framework import HostedMCPTool, HostedWebSearchTool
|
||||
from agent_framework.anthropic import AnthropicChatOptions, AnthropicClient
|
||||
|
||||
"""
|
||||
@@ -40,9 +40,9 @@ async def main() -> None:
|
||||
print("Agent: ", end="", flush=True)
|
||||
async for chunk in agent.run(query, stream=True):
|
||||
for content in chunk.contents:
|
||||
if isinstance(content, TextReasoningContent):
|
||||
if content.type == "text_reasoning":
|
||||
print(f"\033[32m{content.text}\033[0m", end="", flush=True)
|
||||
if isinstance(content, UsageContent):
|
||||
if content.type == "usage":
|
||||
print(f"\n\033[34m[Usage so far: {content.usage_details}]\033[0m\n", end="", flush=True)
|
||||
if chunk.text:
|
||||
print(chunk.text, end="", flush=True)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import asyncio
|
||||
|
||||
from agent_framework import HostedMCPTool, HostedWebSearchTool, TextReasoningContent, UsageContent
|
||||
from agent_framework import HostedMCPTool, HostedWebSearchTool
|
||||
from agent_framework.anthropic import AnthropicClient
|
||||
from anthropic import AsyncAnthropicFoundry
|
||||
|
||||
@@ -51,9 +51,9 @@ async def main() -> None:
|
||||
print("Agent: ", end="", flush=True)
|
||||
async for chunk in agent.run(query, stream=True):
|
||||
for content in chunk.contents:
|
||||
if isinstance(content, TextReasoningContent):
|
||||
if content.type == "text_reasoning":
|
||||
print(f"\033[32m{content.text}\033[0m", end="", flush=True)
|
||||
if isinstance(content, UsageContent):
|
||||
if content.type == "usage":
|
||||
print(f"\n\033[34m[Usage so far: {content.usage_details}]\033[0m\n", end="", flush=True)
|
||||
if chunk.text:
|
||||
print(chunk.text, end="", flush=True)
|
||||
|
||||
@@ -4,7 +4,7 @@ import asyncio
|
||||
import logging
|
||||
from pathlib import Path
|
||||
|
||||
from agent_framework import HostedCodeInterpreterTool, HostedFileContent
|
||||
from agent_framework import Content, HostedCodeInterpreterTool
|
||||
from agent_framework.anthropic import AnthropicChatOptions, AnthropicClient
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -52,7 +52,7 @@ async def main() -> None:
|
||||
query = "Create a presentation about renewable energy with 5 slides"
|
||||
print(f"User: {query}")
|
||||
print("Agent: ", end="", flush=True)
|
||||
files: list[HostedFileContent] = []
|
||||
files: list[Content] = []
|
||||
async for chunk in agent.run(query, stream=True):
|
||||
for content in chunk.contents:
|
||||
match content.type:
|
||||
|
||||
+33
-27
@@ -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']}")
|
||||
|
||||
|
||||
+6
-6
@@ -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
|
||||
|
||||
|
||||
+1
-2
@@ -5,7 +5,6 @@ import os
|
||||
|
||||
from agent_framework import (
|
||||
HostedCodeInterpreterTool,
|
||||
HostedFileContent,
|
||||
)
|
||||
from agent_framework.azure import AzureAIAgentsProvider
|
||||
from azure.ai.agents.aio import AgentsClient
|
||||
@@ -63,7 +62,7 @@ async def main() -> None:
|
||||
for content in chunk.contents:
|
||||
if content.type == "text":
|
||||
print(content.text, end="", flush=True)
|
||||
elif content.type == "hosted_file" and isinstance(content, HostedFileContent):
|
||||
elif content.type == "hosted_file" and content.file_id:
|
||||
file_ids.append(content.file_id)
|
||||
print(f"\n[File generated: {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 AzureAIAgentsProvider
|
||||
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
|
||||
agent = await provider.create_agent(
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import asyncio
|
||||
from typing import Any
|
||||
|
||||
from agent_framework import SupportsAgentRun, AgentResponse, AgentThread, HostedMCPTool
|
||||
from agent_framework import AgentResponse, AgentThread, HostedMCPTool, SupportsAgentRun
|
||||
from agent_framework.azure import AzureAIAgentsProvider
|
||||
from azure.identity.aio import AzureCliCredential
|
||||
|
||||
|
||||
+1
-1
@@ -5,10 +5,10 @@ from datetime import datetime, timezone
|
||||
from typing import Any
|
||||
|
||||
from agent_framework import (
|
||||
SupportsAgentRun,
|
||||
AgentThread,
|
||||
HostedMCPTool,
|
||||
HostedWebSearchTool,
|
||||
SupportsAgentRun,
|
||||
tool,
|
||||
)
|
||||
from agent_framework.azure import AzureAIAgentsProvider
|
||||
|
||||
+3
-3
@@ -2,7 +2,7 @@
|
||||
|
||||
import asyncio
|
||||
|
||||
from agent_framework import ChatAgent, HostedFileSearchTool, HostedVectorStoreContent
|
||||
from agent_framework import ChatAgent, Content, HostedFileSearchTool
|
||||
from agent_framework.azure import AzureOpenAIResponsesClient
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
@@ -22,7 +22,7 @@ Prerequisites:
|
||||
# Helper functions
|
||||
|
||||
|
||||
async def create_vector_store(client: AzureOpenAIResponsesClient) -> tuple[str, HostedVectorStoreContent]:
|
||||
async def create_vector_store(client: AzureOpenAIResponsesClient) -> tuple[str, Content]:
|
||||
"""Create a vector store with sample documents."""
|
||||
file = await client.client.files.create(
|
||||
file=("todays_weather.txt", b"The weather today is sunny with a high of 75F."), purpose="assistants"
|
||||
@@ -35,7 +35,7 @@ async def create_vector_store(client: AzureOpenAIResponsesClient) -> tuple[str,
|
||||
if result.last_error is not None:
|
||||
raise Exception(f"Vector store file processing failed with status: {result.last_error.message}")
|
||||
|
||||
return file.id, HostedVectorStoreContent(vector_store_id=vector_store.id)
|
||||
return file.id, Content.from_hosted_vector_store(vector_store_id=vector_store.id)
|
||||
|
||||
|
||||
async def delete_vector_store(client: AzureOpenAIResponsesClient, file_id: str, vector_store_id: str) -> None:
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ Azure OpenAI Responses Client, including user approval workflows for function ca
|
||||
"""
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from agent_framework import SupportsAgentRun, AgentThread
|
||||
from agent_framework import AgentThread, SupportsAgentRun
|
||||
|
||||
|
||||
async def handle_approvals_without_thread(query: str, agent: "SupportsAgentRun"):
|
||||
|
||||
@@ -12,7 +12,7 @@ from agent_framework import (
|
||||
ChatMessage,
|
||||
Content,
|
||||
Role,
|
||||
TextContent,
|
||||
normalize_messages,
|
||||
)
|
||||
|
||||
"""
|
||||
@@ -88,12 +88,14 @@ class EchoAgent(BaseAgent):
|
||||
) -> AgentResponse:
|
||||
"""Non-streaming implementation."""
|
||||
# Normalize input messages to a list
|
||||
normalized_messages = self._normalize_messages(messages)
|
||||
normalized_messages = normalize_messages(messages)
|
||||
|
||||
if not normalized_messages:
|
||||
response_message = ChatMessage(
|
||||
role=Role.ASSISTANT,
|
||||
contents=[Content.from_text(text="Hello! I'm a custom echo agent. Send me a message and I'll echo it back.")],
|
||||
contents=[
|
||||
Content.from_text(text="Hello! I'm a custom echo agent. Send me a message and I'll echo it back.")
|
||||
],
|
||||
)
|
||||
else:
|
||||
# For simplicity, echo the last user message
|
||||
@@ -120,7 +122,7 @@ class EchoAgent(BaseAgent):
|
||||
) -> AsyncIterable[AgentResponseUpdate]:
|
||||
"""Streaming implementation."""
|
||||
# Normalize input messages to a list
|
||||
normalized_messages = self._normalize_messages(messages)
|
||||
normalized_messages = normalize_messages(messages)
|
||||
|
||||
if not normalized_messages:
|
||||
response_text = "Hello! I'm a custom echo agent. Send me a message and I'll echo it back."
|
||||
|
||||
@@ -5,7 +5,15 @@ from collections.abc import Awaitable, Callable
|
||||
from random import randint
|
||||
from typing import Annotated
|
||||
|
||||
from agent_framework import ChatAgent, ChatContext, ChatMessage, ChatResponse, Role, chat_middleware, tool
|
||||
from agent_framework import (
|
||||
ChatAgent,
|
||||
ChatContext,
|
||||
ChatMessage,
|
||||
ChatResponse,
|
||||
MiddlewareTermination,
|
||||
chat_middleware,
|
||||
tool,
|
||||
)
|
||||
from agent_framework.openai import OpenAIResponsesClient
|
||||
from pydantic import Field
|
||||
|
||||
@@ -39,7 +47,7 @@ async def security_and_override_middleware(
|
||||
context.result = ChatResponse(
|
||||
messages=[
|
||||
ChatMessage(
|
||||
role=Role.ASSISTANT,
|
||||
role="assistant",
|
||||
text="I cannot process requests containing sensitive information. "
|
||||
"Please rephrase your question without including passwords, secrets, or other "
|
||||
"sensitive data.",
|
||||
@@ -48,8 +56,7 @@ async def security_and_override_middleware(
|
||||
)
|
||||
|
||||
# Set terminate flag to stop execution
|
||||
context.terminate = True
|
||||
return
|
||||
raise MiddlewareTermination
|
||||
|
||||
# Continue to next middleware or AI execution
|
||||
await next(context)
|
||||
|
||||
+1
-1
@@ -70,7 +70,7 @@ async def main() -> None:
|
||||
# Show information about the generated image
|
||||
for message in result.messages:
|
||||
for content in message.contents:
|
||||
if content.type == "image_generation" and content.outputs:
|
||||
if content.type == "image_generation_tool_result" and content.outputs:
|
||||
for output in content.outputs:
|
||||
if output.type in ("data", "uri") and output.uri:
|
||||
show_image_info(output.uri)
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@ async def main() -> None:
|
||||
print(f"Result: {result}\n")
|
||||
|
||||
for message in result.messages:
|
||||
code_blocks = [c for c in message.contents if c.type == "code_interpreter_tool_input"]
|
||||
code_blocks = [c for c in message.contents if c.type == "code_interpreter_tool_call"]
|
||||
outputs = [c for c in message.contents if c.type == "code_interpreter_tool_result"]
|
||||
if code_blocks:
|
||||
code_inputs = code_blocks[0].inputs or []
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ OpenAI Responses Client, including user approval workflows for function call sec
|
||||
"""
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from agent_framework import SupportsAgentRun, AgentThread
|
||||
from agent_framework import AgentThread, SupportsAgentRun
|
||||
|
||||
|
||||
async def handle_approvals_without_thread(query: str, agent: "SupportsAgentRun"):
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""Host a single Azure OpenAI-powered agent inside Azure Functions.
|
||||
|
||||
Components used in this sample:
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""Host multiple Azure OpenAI agents inside a single Azure Functions app.
|
||||
|
||||
Components used in this sample:
|
||||
|
||||
+1
-1
@@ -163,7 +163,7 @@ class RedisStreamResponseHandler:
|
||||
has_seen_data = True
|
||||
|
||||
# Process entries from the stream
|
||||
for stream_name, stream_entries in entries:
|
||||
for _stream_name, stream_entries in entries:
|
||||
for entry_id, entry_data in stream_entries:
|
||||
start_id = entry_id.decode() if isinstance(entry_id, bytes) else entry_id
|
||||
|
||||
|
||||
+2
@@ -1,3 +1,5 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""Chain two runs of a single agent inside a Durable Functions orchestration.
|
||||
|
||||
Components used in this sample:
|
||||
|
||||
+2
@@ -1,3 +1,5 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""Fan out concurrent runs across two agents inside a Durable Functions orchestration.
|
||||
|
||||
Components used in this sample:
|
||||
|
||||
+2
@@ -1,3 +1,5 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""Route email requests through conditional orchestration with two agents.
|
||||
|
||||
Components used in this sample:
|
||||
|
||||
+2
@@ -1,3 +1,5 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""Iterate on generated content with a human-in-the-loop Durable orchestration.
|
||||
|
||||
Components used in this sample:
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""
|
||||
Example showing how to configure AI agents with different trigger configurations.
|
||||
|
||||
|
||||
@@ -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}")
|
||||
|
||||
|
||||
|
||||
@@ -211,7 +211,7 @@ class PreferencesContextProvider(ContextProvider):
|
||||
msgs = [request_messages] if isinstance(request_messages, ChatMessage) else list(request_messages)
|
||||
|
||||
for msg in msgs:
|
||||
content = msg.content if hasattr(msg, "content") else ""
|
||||
content = msg.text if hasattr(msg, "text") else ""
|
||||
# Very simple extraction - in production, use LLM-based extraction
|
||||
if isinstance(content, str) and "prefer" in content.lower() and ":" in content:
|
||||
parts = content.split(":")
|
||||
|
||||
@@ -63,15 +63,16 @@ async def main() -> None:
|
||||
thread_id = "azure_test_thread"
|
||||
|
||||
# Factory for creating Azure Redis chat message store
|
||||
chat_message_store_factory = lambda: RedisChatMessageStore(
|
||||
credential_provider=credential_provider,
|
||||
host=redis_host,
|
||||
port=10000,
|
||||
ssl=True,
|
||||
thread_id=thread_id,
|
||||
key_prefix="chat_messages",
|
||||
max_messages=100,
|
||||
)
|
||||
def chat_message_store_factory():
|
||||
return RedisChatMessageStore(
|
||||
credential_provider=credential_provider,
|
||||
host=redis_host,
|
||||
port=10000,
|
||||
ssl=True,
|
||||
thread_id=thread_id,
|
||||
key_prefix="chat_messages",
|
||||
max_messages=100,
|
||||
)
|
||||
|
||||
# Create chat client
|
||||
client = OpenAIChatClient()
|
||||
|
||||
@@ -52,12 +52,14 @@ async def main() -> None:
|
||||
vector_distance_metric="cosine",
|
||||
thread_id=thread_id,
|
||||
)
|
||||
chat_message_store_factory = lambda: RedisChatMessageStore(
|
||||
redis_url="redis://localhost:6379",
|
||||
thread_id=thread_id,
|
||||
key_prefix="chat_messages",
|
||||
max_messages=100,
|
||||
)
|
||||
|
||||
def chat_message_store_factory():
|
||||
return RedisChatMessageStore(
|
||||
redis_url="redis://localhost:6379",
|
||||
thread_id=thread_id,
|
||||
key_prefix="chat_messages",
|
||||
max_messages=100,
|
||||
)
|
||||
|
||||
# Create chat client for the agent
|
||||
client = OpenAIChatClient(model_id=os.getenv("OPENAI_CHAT_MODEL_ID"), api_key=os.getenv("OPENAI_API_KEY"))
|
||||
|
||||
@@ -14,8 +14,8 @@ from agent_framework import (
|
||||
ChatResponseUpdate,
|
||||
Content,
|
||||
FunctionInvocationContext,
|
||||
Role,
|
||||
TextContent,
|
||||
MiddlewareTermination,
|
||||
ResponseStream,
|
||||
chat_middleware,
|
||||
function_middleware,
|
||||
tool,
|
||||
@@ -44,7 +44,7 @@ async def security_filter_middleware(
|
||||
|
||||
# Check only the last message (most recent user input)
|
||||
last_message = context.messages[-1] if context.messages else None
|
||||
if last_message and last_message.role == Role.USER and last_message.text:
|
||||
if last_message and last_message.role == "user" and last_message.text:
|
||||
message_lower = last_message.text.lower()
|
||||
for term in blocked_terms:
|
||||
if term in message_lower:
|
||||
@@ -56,26 +56,25 @@ async def security_filter_middleware(
|
||||
|
||||
if context.stream:
|
||||
# Streaming mode: return async generator
|
||||
async def blocked_stream() -> AsyncIterable[ChatResponseUpdate]:
|
||||
async def blocked_stream(msg: str = error_message) -> AsyncIterable[ChatResponseUpdate]:
|
||||
yield ChatResponseUpdate(
|
||||
contents=[Content.from_text(text=error_message)],
|
||||
role=Role.ASSISTANT,
|
||||
contents=[Content.from_text(text=msg)],
|
||||
role="assistant",
|
||||
)
|
||||
|
||||
context.result = blocked_stream()
|
||||
context.result = ResponseStream(blocked_stream(), finalizer=ChatResponse.from_updates)
|
||||
else:
|
||||
# Non-streaming mode: return complete response
|
||||
context.result = ChatResponse(
|
||||
messages=[
|
||||
ChatMessage(
|
||||
role=Role.ASSISTANT,
|
||||
role="assistant",
|
||||
text=error_message,
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
context.terminate = True
|
||||
return
|
||||
raise MiddlewareTermination
|
||||
|
||||
await next(context)
|
||||
|
||||
@@ -93,8 +92,7 @@ async def atlantis_location_filter_middleware(
|
||||
"Blocked! Hold up right there!! Tell the user that "
|
||||
"'Atlantis is a special place, we must never ask about the weather there!!'"
|
||||
)
|
||||
context.terminate = True
|
||||
return
|
||||
raise MiddlewareTermination
|
||||
|
||||
await next(context)
|
||||
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""Client application for interacting with a Durable Task hosted agent.
|
||||
|
||||
This client connects to the Durable Task Scheduler and sends requests to
|
||||
registered agents, demonstrating how to interact with agents from external processes.
|
||||
|
||||
Prerequisites:
|
||||
Prerequisites:
|
||||
- The worker must be running with the agent registered
|
||||
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
|
||||
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
|
||||
(plus AZURE_OPENAI_API_KEY or Azure CLI authentication)
|
||||
- Durable Task Scheduler must be running
|
||||
"""
|
||||
@@ -29,12 +31,12 @@ def get_client(
|
||||
log_handler: logging.Handler | None = None
|
||||
) -> DurableAIAgentClient:
|
||||
"""Create a configured DurableAIAgentClient.
|
||||
|
||||
|
||||
Args:
|
||||
taskhub: Task hub name (defaults to TASKHUB env var or "default")
|
||||
endpoint: Scheduler endpoint (defaults to ENDPOINT env var or "http://localhost:8080")
|
||||
log_handler: Optional logging handler for client logging
|
||||
|
||||
|
||||
Returns:
|
||||
Configured DurableAIAgentClient instance
|
||||
"""
|
||||
@@ -59,7 +61,7 @@ def get_client(
|
||||
|
||||
def run_client(agent_client: DurableAIAgentClient) -> None:
|
||||
"""Run client interactions with the Joker agent.
|
||||
|
||||
|
||||
Args:
|
||||
agent_client: The DurableAIAgentClient instance
|
||||
"""
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""Single Agent Sample - Durable Task Integration (Combined Worker + Client)
|
||||
|
||||
This sample demonstrates running both the worker and client in a single process.
|
||||
The worker is started first to register the agent, then client operations are
|
||||
performed against the running worker.
|
||||
|
||||
Prerequisites:
|
||||
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
|
||||
Prerequisites:
|
||||
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
|
||||
(plus AZURE_OPENAI_API_KEY or Azure CLI authentication)
|
||||
- Durable Task Scheduler must be running (e.g., using Docker)
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""Worker process for hosting a single Azure OpenAI-powered agent using Durable Task.
|
||||
|
||||
This worker registers agents as durable entities and continuously listens for requests.
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""Client application for interacting with multiple hosted agents.
|
||||
|
||||
This client connects to the Durable Task Scheduler and interacts with two different
|
||||
agents (WeatherAgent and MathAgent), demonstrating how to work with multiple agents
|
||||
each with their own specialized capabilities and tools.
|
||||
|
||||
Prerequisites:
|
||||
Prerequisites:
|
||||
- The worker must be running with both agents registered
|
||||
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
|
||||
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
|
||||
(plus AZURE_OPENAI_API_KEY or Azure CLI authentication)
|
||||
- Durable Task Scheduler must be running
|
||||
"""
|
||||
@@ -30,12 +32,12 @@ def get_client(
|
||||
log_handler: logging.Handler | None = None
|
||||
) -> DurableAIAgentClient:
|
||||
"""Create a configured DurableAIAgentClient.
|
||||
|
||||
|
||||
Args:
|
||||
taskhub: Task hub name (defaults to TASKHUB env var or "default")
|
||||
endpoint: Scheduler endpoint (defaults to ENDPOINT env var or "http://localhost:8080")
|
||||
log_handler: Optional logging handler for client logging
|
||||
|
||||
|
||||
Returns:
|
||||
Configured DurableAIAgentClient instance
|
||||
"""
|
||||
@@ -60,7 +62,7 @@ def get_client(
|
||||
|
||||
def run_client(agent_client: DurableAIAgentClient) -> None:
|
||||
"""Run client interactions with both WeatherAgent and MathAgent.
|
||||
|
||||
|
||||
Args:
|
||||
agent_client: The DurableAIAgentClient instance
|
||||
"""
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""Multi-Agent Sample - Durable Task Integration (Combined Worker + Client)
|
||||
|
||||
This sample demonstrates running both the worker and client in a single process
|
||||
for multiple agents with different tools. The worker registers two agents
|
||||
(WeatherAgent and MathAgent), each with their own specialized capabilities.
|
||||
|
||||
Prerequisites:
|
||||
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
|
||||
Prerequisites:
|
||||
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
|
||||
(plus AZURE_OPENAI_API_KEY or Azure CLI authentication)
|
||||
- Durable Task Scheduler must be running (e.g., using Docker)
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""Worker process for hosting multiple agents with different tools using Durable Task.
|
||||
|
||||
This worker registers two agents - a weather assistant and a math assistant - each
|
||||
|
||||
@@ -7,7 +7,7 @@ This client demonstrates:
|
||||
2. Streaming the response from Redis in real-time
|
||||
3. Handling reconnection and cursor-based resumption
|
||||
|
||||
Prerequisites:
|
||||
Prerequisites:
|
||||
- The worker must be running with the TravelPlanner agent registered
|
||||
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
|
||||
- Redis must be running
|
||||
@@ -59,12 +59,12 @@ def get_client(
|
||||
log_handler: logging.Handler | None = None
|
||||
) -> DurableAIAgentClient:
|
||||
"""Create a configured DurableAIAgentClient.
|
||||
|
||||
|
||||
Args:
|
||||
taskhub: Task hub name (defaults to TASKHUB env var or "default")
|
||||
endpoint: Scheduler endpoint (defaults to ENDPOINT env var or "http://localhost:8080")
|
||||
log_handler: Optional log handler for client logging
|
||||
|
||||
|
||||
Returns:
|
||||
Configured DurableAIAgentClient instance
|
||||
"""
|
||||
@@ -89,7 +89,7 @@ def get_client(
|
||||
|
||||
async def stream_from_redis(thread_id: str, cursor: str | None = None) -> None:
|
||||
"""Stream agent responses from Redis.
|
||||
|
||||
|
||||
Args:
|
||||
thread_id: The conversation/thread ID to stream from
|
||||
cursor: Optional cursor to resume from. If None, starts from beginning.
|
||||
@@ -132,7 +132,7 @@ async def stream_from_redis(thread_id: str, cursor: str | None = None) -> None:
|
||||
|
||||
def run_client(agent_client: DurableAIAgentClient) -> None:
|
||||
"""Run client interactions with the TravelPlanner agent.
|
||||
|
||||
|
||||
Args:
|
||||
agent_client: The DurableAIAgentClient instance
|
||||
"""
|
||||
|
||||
@@ -8,8 +8,8 @@ with reliable Redis-based streaming for agent responses.
|
||||
The worker is started first to register the TravelPlanner agent with Redis streaming
|
||||
callback, then client operations are performed against the running worker.
|
||||
|
||||
Prerequisites:
|
||||
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
|
||||
Prerequisites:
|
||||
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
|
||||
(plus AZURE_OPENAI_API_KEY or Azure CLI authentication)
|
||||
- Durable Task Scheduler must be running (e.g., using Docker)
|
||||
- Redis must be running (e.g., docker run -d --name redis -p 6379:6379 redis:latest)
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
This worker registers the TravelPlanner agent with the Durable Task Scheduler
|
||||
and uses RedisStreamCallback to persist streaming responses to Redis for reliable delivery.
|
||||
|
||||
Prerequisites:
|
||||
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
|
||||
Prerequisites:
|
||||
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
|
||||
(plus AZURE_OPENAI_API_KEY or Azure CLI authentication)
|
||||
- Start a Durable Task Scheduler (e.g., using Docker)
|
||||
- Start Redis (e.g., docker run -d --name redis -p 6379:6379 redis:latest)
|
||||
@@ -145,7 +145,7 @@ class RedisStreamCallback(AgentResponseCallbackProtocol):
|
||||
|
||||
def create_travel_agent() -> "ChatAgent":
|
||||
"""Create the TravelPlanner agent using Azure OpenAI.
|
||||
|
||||
|
||||
Returns:
|
||||
ChatAgent: The configured TravelPlanner agent with travel planning tools.
|
||||
"""
|
||||
@@ -174,12 +174,12 @@ def get_worker(
|
||||
log_handler: logging.Handler | None = None
|
||||
) -> DurableTaskSchedulerWorker:
|
||||
"""Create a configured DurableTaskSchedulerWorker.
|
||||
|
||||
|
||||
Args:
|
||||
taskhub: Task hub name (defaults to TASKHUB env var or "default")
|
||||
endpoint: Scheduler endpoint (defaults to ENDPOINT env var or "http://localhost:8080")
|
||||
log_handler: Optional log handler for worker logging
|
||||
|
||||
|
||||
Returns:
|
||||
Configured DurableTaskSchedulerWorker instance
|
||||
"""
|
||||
@@ -202,10 +202,10 @@ def get_worker(
|
||||
|
||||
def setup_worker(worker: DurableTaskSchedulerWorker) -> DurableAIAgentWorker:
|
||||
"""Set up the worker with the TravelPlanner agent and Redis streaming callback.
|
||||
|
||||
|
||||
Args:
|
||||
worker: The DurableTaskSchedulerWorker instance
|
||||
|
||||
|
||||
Returns:
|
||||
DurableAIAgentWorker with agent and callback registered
|
||||
"""
|
||||
|
||||
+7
-5
@@ -1,12 +1,14 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""Client application for starting a single agent chaining orchestration.
|
||||
|
||||
This client connects to the Durable Task Scheduler and starts an orchestration
|
||||
that runs a writer agent twice sequentially on the same thread, demonstrating
|
||||
how conversation context is maintained across multiple agent invocations.
|
||||
|
||||
Prerequisites:
|
||||
Prerequisites:
|
||||
- The worker must be running with the writer agent and orchestration registered
|
||||
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
|
||||
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
|
||||
(plus AZURE_OPENAI_API_KEY or Azure CLI authentication)
|
||||
- Durable Task Scheduler must be running
|
||||
"""
|
||||
@@ -30,12 +32,12 @@ def get_client(
|
||||
log_handler: logging.Handler | None = None
|
||||
) -> DurableTaskSchedulerClient:
|
||||
"""Create a configured DurableTaskSchedulerClient.
|
||||
|
||||
|
||||
Args:
|
||||
taskhub: Task hub name (defaults to TASKHUB env var or "default")
|
||||
endpoint: Scheduler endpoint (defaults to ENDPOINT env var or "http://localhost:8080")
|
||||
log_handler: Optional logging handler for client logging
|
||||
|
||||
|
||||
Returns:
|
||||
Configured DurableTaskSchedulerClient instance
|
||||
"""
|
||||
@@ -58,7 +60,7 @@ def get_client(
|
||||
|
||||
def run_client(client: DurableTaskSchedulerClient) -> None:
|
||||
"""Run client to start and monitor the orchestration.
|
||||
|
||||
|
||||
Args:
|
||||
client: The DurableTaskSchedulerClient instance
|
||||
"""
|
||||
|
||||
+4
-2
@@ -1,3 +1,5 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""Single Agent Orchestration Chaining Sample - Durable Task Integration
|
||||
|
||||
This sample demonstrates chaining two invocations of the same agent inside a Durable Task
|
||||
@@ -10,8 +12,8 @@ Components used:
|
||||
- DurableTaskSchedulerClient and orchestration for sequential agent invocations
|
||||
- Thread management to maintain conversation context across invocations
|
||||
|
||||
Prerequisites:
|
||||
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
|
||||
Prerequisites:
|
||||
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
|
||||
(plus AZURE_OPENAI_API_KEY or Azure CLI authentication)
|
||||
- Durable Task Scheduler must be running (e.g., using Docker emulator)
|
||||
|
||||
|
||||
+15
-13
@@ -1,11 +1,13 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""Worker process for hosting a single agent with chaining orchestration using Durable Task.
|
||||
|
||||
This worker registers a writer agent and an orchestration function that demonstrates
|
||||
chaining behavior by running the agent twice sequentially on the same thread,
|
||||
preserving conversation context between invocations.
|
||||
|
||||
Prerequisites:
|
||||
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
|
||||
Prerequisites:
|
||||
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
|
||||
(plus AZURE_OPENAI_API_KEY or Azure CLI authentication)
|
||||
- Start a Durable Task Scheduler (e.g., using Docker)
|
||||
"""
|
||||
@@ -31,10 +33,10 @@ WRITER_AGENT_NAME = "WriterAgent"
|
||||
|
||||
def create_writer_agent() -> "ChatAgent":
|
||||
"""Create the Writer agent using Azure OpenAI.
|
||||
|
||||
|
||||
This agent refines short pieces of text, enhancing initial sentences
|
||||
and polishing improved versions further.
|
||||
|
||||
|
||||
Returns:
|
||||
ChatAgent: The configured Writer agent
|
||||
"""
|
||||
@@ -51,7 +53,7 @@ def create_writer_agent() -> "ChatAgent":
|
||||
|
||||
def get_orchestration():
|
||||
"""Get the orchestration function for this sample.
|
||||
|
||||
|
||||
Returns:
|
||||
The orchestration function to register with the worker
|
||||
"""
|
||||
@@ -62,18 +64,18 @@ def single_agent_chaining_orchestration(
|
||||
context: OrchestrationContext, _: str
|
||||
) -> Generator[Task[AgentResponse], AgentResponse, str]:
|
||||
"""Orchestration that runs the writer agent twice on the same thread.
|
||||
|
||||
|
||||
This demonstrates chaining behavior where the output of the first agent run
|
||||
becomes part of the input for the second run, all while maintaining the
|
||||
conversation context through a shared thread.
|
||||
|
||||
|
||||
Args:
|
||||
context: The orchestration context
|
||||
_: Input parameter (unused)
|
||||
|
||||
|
||||
Yields:
|
||||
Task[AgentRunResponse]: Tasks that resolve to AgentRunResponse
|
||||
|
||||
|
||||
Returns:
|
||||
str: The final refined text from the second agent run
|
||||
"""
|
||||
@@ -123,12 +125,12 @@ def get_worker(
|
||||
log_handler: logging.Handler | None = None
|
||||
) -> DurableTaskSchedulerWorker:
|
||||
"""Create a configured DurableTaskSchedulerWorker.
|
||||
|
||||
|
||||
Args:
|
||||
taskhub: Task hub name (defaults to TASKHUB env var or "default")
|
||||
endpoint: Scheduler endpoint (defaults to ENDPOINT env var or "http://localhost:8080")
|
||||
log_handler: Optional logging handler for worker logging
|
||||
|
||||
|
||||
Returns:
|
||||
Configured DurableTaskSchedulerWorker instance
|
||||
"""
|
||||
@@ -151,10 +153,10 @@ def get_worker(
|
||||
|
||||
def setup_worker(worker: DurableTaskSchedulerWorker) -> DurableAIAgentWorker:
|
||||
"""Set up the worker with agents and orchestrations registered.
|
||||
|
||||
|
||||
Args:
|
||||
worker: The DurableTaskSchedulerWorker instance
|
||||
|
||||
|
||||
Returns:
|
||||
DurableAIAgentWorker with agents and orchestrations registered
|
||||
"""
|
||||
|
||||
+7
-5
@@ -1,12 +1,14 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""Client application for starting a multi-agent concurrent orchestration.
|
||||
|
||||
This client connects to the Durable Task Scheduler and starts an orchestration
|
||||
that runs two agents (physicist and chemist) concurrently, then retrieves and
|
||||
displays the aggregated results.
|
||||
|
||||
Prerequisites:
|
||||
Prerequisites:
|
||||
- The worker must be running with both agents and orchestration registered
|
||||
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
|
||||
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
|
||||
(plus AZURE_OPENAI_API_KEY or Azure CLI authentication)
|
||||
- Durable Task Scheduler must be running
|
||||
"""
|
||||
@@ -30,12 +32,12 @@ def get_client(
|
||||
log_handler: logging.Handler | None = None
|
||||
) -> DurableTaskSchedulerClient:
|
||||
"""Create a configured DurableTaskSchedulerClient.
|
||||
|
||||
|
||||
Args:
|
||||
taskhub: Task hub name (defaults to TASKHUB env var or "default")
|
||||
endpoint: Scheduler endpoint (defaults to ENDPOINT env var or "http://localhost:8080")
|
||||
log_handler: Optional logging handler for client logging
|
||||
|
||||
|
||||
Returns:
|
||||
Configured DurableTaskSchedulerClient instance
|
||||
"""
|
||||
@@ -58,7 +60,7 @@ def get_client(
|
||||
|
||||
def run_client(client: DurableTaskSchedulerClient, prompt: str = "What is temperature?") -> None:
|
||||
"""Run client to start and monitor the orchestration.
|
||||
|
||||
|
||||
Args:
|
||||
client: The DurableTaskSchedulerClient instance
|
||||
prompt: The prompt to send to both agents
|
||||
|
||||
+4
-2
@@ -1,3 +1,5 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""Multi-Agent Orchestration Sample - Durable Task Integration (Combined Worker + Client)
|
||||
|
||||
This sample demonstrates running both the worker and client in a single process for
|
||||
@@ -7,8 +9,8 @@ concurrent multi-agent orchestration. The worker registers two domain-specific a
|
||||
The orchestration uses OrchestrationAgentExecutor to execute agents concurrently
|
||||
and aggregate their responses.
|
||||
|
||||
Prerequisites:
|
||||
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
|
||||
Prerequisites:
|
||||
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
|
||||
(plus AZURE_OPENAI_API_KEY or Azure CLI authentication)
|
||||
- Durable Task Scheduler must be running (e.g., using Docker)
|
||||
|
||||
|
||||
+14
-12
@@ -1,11 +1,13 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""Worker process for hosting multiple agents with orchestration using Durable Task.
|
||||
|
||||
This worker registers two domain-specific agents (physicist and chemist) and an orchestration
|
||||
function that runs them concurrently. The orchestration uses OrchestrationAgentExecutor
|
||||
function that runs them concurrently. The orchestration uses OrchestrationAgentExecutor
|
||||
to execute agents in parallel and aggregate their responses.
|
||||
|
||||
Prerequisites:
|
||||
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
|
||||
Prerequisites:
|
||||
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
|
||||
(plus AZURE_OPENAI_API_KEY or Azure CLI authentication)
|
||||
- Start a Durable Task Scheduler (e.g., using Docker)
|
||||
"""
|
||||
@@ -33,7 +35,7 @@ CHEMIST_AGENT_NAME = "ChemistAgent"
|
||||
|
||||
def create_physicist_agent() -> "ChatAgent":
|
||||
"""Create the Physicist agent using Azure OpenAI.
|
||||
|
||||
|
||||
Returns:
|
||||
ChatAgent: The configured Physicist agent
|
||||
"""
|
||||
@@ -45,7 +47,7 @@ def create_physicist_agent() -> "ChatAgent":
|
||||
|
||||
def create_chemist_agent() -> "ChatAgent":
|
||||
"""Create the Chemist agent using Azure OpenAI.
|
||||
|
||||
|
||||
Returns:
|
||||
ChatAgent: The configured Chemist agent
|
||||
"""
|
||||
@@ -57,14 +59,14 @@ def create_chemist_agent() -> "ChatAgent":
|
||||
|
||||
def multi_agent_concurrent_orchestration(context: OrchestrationContext, prompt: str) -> Generator[Task[Any], Any, dict[str, str]]:
|
||||
"""Orchestration that runs both agents in parallel and aggregates results.
|
||||
|
||||
|
||||
Uses DurableAIAgentOrchestrationContext to wrap the orchestration context and
|
||||
access agents via the OrchestrationAgentExecutor.
|
||||
|
||||
|
||||
Args:
|
||||
context: The orchestration context
|
||||
prompt: The prompt to send to both agents
|
||||
|
||||
|
||||
Returns:
|
||||
dict: Dictionary with 'physicist' and 'chemist' response texts
|
||||
"""
|
||||
@@ -115,12 +117,12 @@ def get_worker(
|
||||
log_handler: logging.Handler | None = None
|
||||
) -> DurableTaskSchedulerWorker:
|
||||
"""Create a configured DurableTaskSchedulerWorker.
|
||||
|
||||
|
||||
Args:
|
||||
taskhub: Task hub name (defaults to TASKHUB env var or "default")
|
||||
endpoint: Scheduler endpoint (defaults to ENDPOINT env var or "http://localhost:8080")
|
||||
log_handler: Optional logging handler for worker logging
|
||||
|
||||
|
||||
Returns:
|
||||
Configured DurableTaskSchedulerWorker instance
|
||||
"""
|
||||
@@ -143,10 +145,10 @@ def get_worker(
|
||||
|
||||
def setup_worker(worker: DurableTaskSchedulerWorker) -> DurableAIAgentWorker:
|
||||
"""Set up the worker with agents and orchestrations registered.
|
||||
|
||||
|
||||
Args:
|
||||
worker: The DurableTaskSchedulerWorker instance
|
||||
|
||||
|
||||
Returns:
|
||||
DurableAIAgentWorker with agents and orchestrations registered
|
||||
"""
|
||||
|
||||
+7
-5
@@ -1,11 +1,13 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""Client application for starting a spam detection orchestration.
|
||||
|
||||
This client connects to the Durable Task Scheduler and starts an orchestration
|
||||
that uses conditional logic to either handle spam emails or draft professional responses.
|
||||
|
||||
Prerequisites:
|
||||
Prerequisites:
|
||||
- The worker must be running with both agents, orchestration, and activities registered
|
||||
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
|
||||
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
|
||||
(plus AZURE_OPENAI_API_KEY or Azure CLI authentication)
|
||||
- Durable Task Scheduler must be running
|
||||
"""
|
||||
@@ -28,12 +30,12 @@ def get_client(
|
||||
log_handler: logging.Handler | None = None
|
||||
) -> DurableTaskSchedulerClient:
|
||||
"""Create a configured DurableTaskSchedulerClient.
|
||||
|
||||
|
||||
Args:
|
||||
taskhub: Task hub name (defaults to TASKHUB env var or "default")
|
||||
endpoint: Scheduler endpoint (defaults to ENDPOINT env var or "http://localhost:8080")
|
||||
log_handler: Optional logging handler for client logging
|
||||
|
||||
|
||||
Returns:
|
||||
Configured DurableTaskSchedulerClient instance
|
||||
"""
|
||||
@@ -60,7 +62,7 @@ def run_client(
|
||||
email_content: str = "Hello! I wanted to reach out about our upcoming project meeting."
|
||||
) -> None:
|
||||
"""Run client to start and monitor the spam detection orchestration.
|
||||
|
||||
|
||||
Args:
|
||||
client: The DurableTaskSchedulerClient instance
|
||||
email_id: The email ID
|
||||
|
||||
+4
-2
@@ -1,3 +1,5 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""Multi-Agent Orchestration with Conditionals Sample - Durable Task Integration
|
||||
|
||||
This sample demonstrates conditional orchestration logic with two agents:
|
||||
@@ -7,8 +9,8 @@ This sample demonstrates conditional orchestration logic with two agents:
|
||||
The orchestration branches based on spam detection results, calling different
|
||||
activity functions to handle spam or send legitimate email responses.
|
||||
|
||||
Prerequisites:
|
||||
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
|
||||
Prerequisites:
|
||||
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
|
||||
(plus AZURE_OPENAI_API_KEY or Azure CLI authentication)
|
||||
- Durable Task Scheduler must be running (e.g., using Docker)
|
||||
|
||||
|
||||
+15
-13
@@ -1,3 +1,5 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""Worker process for hosting spam detection and email assistant agents with conditional orchestration.
|
||||
|
||||
This worker registers two domain-specific agents (spam detector and email assistant) and an
|
||||
@@ -51,7 +53,7 @@ class EmailPayload(BaseModel):
|
||||
|
||||
def create_spam_agent() -> "ChatAgent":
|
||||
"""Create the Spam Detection agent using Azure OpenAI.
|
||||
|
||||
|
||||
Returns:
|
||||
ChatAgent: The configured Spam Detection agent
|
||||
"""
|
||||
@@ -63,7 +65,7 @@ def create_spam_agent() -> "ChatAgent":
|
||||
|
||||
def create_email_agent() -> "ChatAgent":
|
||||
"""Create the Email Assistant agent using Azure OpenAI.
|
||||
|
||||
|
||||
Returns:
|
||||
ChatAgent: The configured Email Assistant agent
|
||||
"""
|
||||
@@ -75,11 +77,11 @@ def create_email_agent() -> "ChatAgent":
|
||||
|
||||
def handle_spam_email(context: ActivityContext, reason: str) -> str:
|
||||
"""Activity function to handle spam emails.
|
||||
|
||||
|
||||
Args:
|
||||
context: The activity context
|
||||
reason: The reason why the email was marked as spam
|
||||
|
||||
|
||||
Returns:
|
||||
str: Confirmation message
|
||||
"""
|
||||
@@ -89,11 +91,11 @@ def handle_spam_email(context: ActivityContext, reason: str) -> str:
|
||||
|
||||
def send_email(context: ActivityContext, message: str) -> str:
|
||||
"""Activity function to send emails.
|
||||
|
||||
|
||||
Args:
|
||||
context: The activity context
|
||||
message: The email message to send
|
||||
|
||||
|
||||
Returns:
|
||||
str: Confirmation message
|
||||
"""
|
||||
@@ -103,17 +105,17 @@ def send_email(context: ActivityContext, message: str) -> str:
|
||||
|
||||
def spam_detection_orchestration(context: OrchestrationContext, payload_raw: Any) -> Generator[Task[Any], Any, str]:
|
||||
"""Orchestration that detects spam and conditionally drafts email responses.
|
||||
|
||||
|
||||
This orchestration:
|
||||
1. Validates the input payload
|
||||
2. Runs the spam detection agent
|
||||
3. If spam: calls handle_spam_email activity
|
||||
4. If legitimate: runs email assistant agent and calls send_email activity
|
||||
|
||||
|
||||
Args:
|
||||
context: The orchestration context
|
||||
payload_raw: The input payload dictionary
|
||||
|
||||
|
||||
Returns:
|
||||
str: Result message from activity functions
|
||||
"""
|
||||
@@ -198,12 +200,12 @@ def get_worker(
|
||||
log_handler: logging.Handler | None = None
|
||||
) -> DurableTaskSchedulerWorker:
|
||||
"""Create a configured DurableTaskSchedulerWorker.
|
||||
|
||||
|
||||
Args:
|
||||
taskhub: Task hub name (defaults to TASKHUB env var or "default")
|
||||
endpoint: Scheduler endpoint (defaults to ENDPOINT env var or "http://localhost:8080")
|
||||
log_handler: Optional logging handler for worker logging
|
||||
|
||||
|
||||
Returns:
|
||||
Configured DurableTaskSchedulerWorker instance
|
||||
"""
|
||||
@@ -226,10 +228,10 @@ def get_worker(
|
||||
|
||||
def setup_worker(worker: DurableTaskSchedulerWorker) -> DurableAIAgentWorker:
|
||||
"""Set up the worker with agents, orchestrations, and activities registered.
|
||||
|
||||
|
||||
Args:
|
||||
worker: The DurableTaskSchedulerWorker instance
|
||||
|
||||
|
||||
Returns:
|
||||
DurableAIAgentWorker with agents, orchestrations, and activities registered
|
||||
"""
|
||||
|
||||
+13
-11
@@ -1,11 +1,13 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""Client application for starting a human-in-the-loop content generation orchestration.
|
||||
|
||||
This client connects to the Durable Task Scheduler and demonstrates the HITL pattern
|
||||
by starting an orchestration, sending approval/rejection events, and monitoring progress.
|
||||
|
||||
Prerequisites:
|
||||
Prerequisites:
|
||||
- The worker must be running with the agent, orchestration, and activities registered
|
||||
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
|
||||
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
|
||||
(plus AZURE_OPENAI_API_KEY or Azure CLI authentication)
|
||||
- Durable Task Scheduler must be running
|
||||
"""
|
||||
@@ -34,12 +36,12 @@ def get_client(
|
||||
log_handler: logging.Handler | None = None
|
||||
) -> DurableTaskSchedulerClient:
|
||||
"""Create a configured DurableTaskSchedulerClient.
|
||||
|
||||
|
||||
Args:
|
||||
taskhub: Task hub name (defaults to TASKHUB env var or "default")
|
||||
endpoint: Scheduler endpoint (defaults to ENDPOINT env var or "http://localhost:8080")
|
||||
log_handler: Optional logging handler for client logging
|
||||
|
||||
|
||||
Returns:
|
||||
Configured DurableTaskSchedulerClient instance
|
||||
"""
|
||||
@@ -64,7 +66,7 @@ def _log_completion_result(
|
||||
metadata: OrchestrationState | None,
|
||||
) -> None:
|
||||
"""Log the orchestration completion result.
|
||||
|
||||
|
||||
Args:
|
||||
metadata: The orchestration metadata
|
||||
"""
|
||||
@@ -94,7 +96,7 @@ def _wait_and_log_completion(
|
||||
timeout: int = 60
|
||||
) -> None:
|
||||
"""Wait for orchestration completion and log the result.
|
||||
|
||||
|
||||
Args:
|
||||
client: The DurableTaskSchedulerClient instance
|
||||
instance_id: The orchestration instance ID
|
||||
@@ -116,7 +118,7 @@ def send_approval(
|
||||
feedback: str = ""
|
||||
) -> None:
|
||||
"""Send approval or rejection event to the orchestration.
|
||||
|
||||
|
||||
Args:
|
||||
client: The DurableTaskSchedulerClient instance
|
||||
instance_id: The orchestration instance ID
|
||||
@@ -148,14 +150,14 @@ def wait_for_notification(
|
||||
timeout_seconds: int = 10
|
||||
) -> bool:
|
||||
"""Wait for the orchestration to reach a notification point.
|
||||
|
||||
|
||||
Polls the orchestration status until it appears to be waiting for approval.
|
||||
|
||||
|
||||
Args:
|
||||
client: The DurableTaskSchedulerClient instance
|
||||
instance_id: The orchestration instance ID
|
||||
timeout_seconds: Maximum time to wait
|
||||
|
||||
|
||||
Returns:
|
||||
True if notification detected, False if timeout
|
||||
"""
|
||||
@@ -202,7 +204,7 @@ def wait_for_notification(
|
||||
|
||||
def run_interactive_client(client: DurableTaskSchedulerClient) -> None:
|
||||
"""Run an interactive client that prompts for user input and handles approval workflow.
|
||||
|
||||
|
||||
Args:
|
||||
client: The DurableTaskSchedulerClient instance
|
||||
"""
|
||||
|
||||
+4
-2
@@ -1,3 +1,5 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""Human-in-the-Loop Orchestration Sample - Durable Task Integration
|
||||
|
||||
This sample demonstrates the HITL pattern with a WriterAgent that generates content
|
||||
@@ -7,8 +9,8 @@ and waits for human approval. The orchestration handles:
|
||||
- Iterative refinement based on feedback
|
||||
- Activity functions for notifications and publishing
|
||||
|
||||
Prerequisites:
|
||||
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
|
||||
Prerequisites:
|
||||
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
|
||||
(plus AZURE_OPENAI_API_KEY or Azure CLI authentication)
|
||||
- Durable Task Scheduler must be running (e.g., using Docker)
|
||||
|
||||
|
||||
+15
-13
@@ -1,11 +1,13 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""Worker process for hosting a writer agent with human-in-the-loop orchestration.
|
||||
|
||||
This worker registers a WriterAgent and an orchestration function that implements
|
||||
a human-in-the-loop review workflow. The orchestration pauses for external events
|
||||
(human approval/rejection) with timeout handling, and iterates based on feedback.
|
||||
|
||||
Prerequisites:
|
||||
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
|
||||
Prerequisites:
|
||||
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
|
||||
(plus AZURE_OPENAI_API_KEY or Azure CLI authentication)
|
||||
- Start a Durable Task Scheduler (e.g., using Docker)
|
||||
"""
|
||||
@@ -54,7 +56,7 @@ class HumanApproval(BaseModel):
|
||||
|
||||
def create_writer_agent() -> "ChatAgent":
|
||||
"""Create the Writer agent using Azure OpenAI.
|
||||
|
||||
|
||||
Returns:
|
||||
ChatAgent: The configured Writer agent
|
||||
"""
|
||||
@@ -73,7 +75,7 @@ def create_writer_agent() -> "ChatAgent":
|
||||
|
||||
def notify_user_for_approval(context: ActivityContext, content: dict[str, str]) -> str:
|
||||
"""Activity function to notify user for approval.
|
||||
|
||||
|
||||
Args:
|
||||
context: The activity context
|
||||
content: The generated content dictionary
|
||||
@@ -88,7 +90,7 @@ def notify_user_for_approval(context: ActivityContext, content: dict[str, str])
|
||||
|
||||
def publish_content(context: ActivityContext, content: dict[str, str]) -> str:
|
||||
"""Activity function to publish approved content.
|
||||
|
||||
|
||||
Args:
|
||||
context: The activity context
|
||||
content: The generated content dictionary
|
||||
@@ -105,7 +107,7 @@ def content_generation_hitl_orchestration(
|
||||
payload_raw: Any
|
||||
) -> Generator[Task[Any], Any, dict[str, str]]:
|
||||
"""Human-in-the-loop orchestration for content generation with approval workflow.
|
||||
|
||||
|
||||
This orchestration:
|
||||
1. Generates initial content using WriterAgent
|
||||
2. Loops up to max_review_attempts times:
|
||||
@@ -115,14 +117,14 @@ def content_generation_hitl_orchestration(
|
||||
d. If rejected: incorporates feedback and regenerates
|
||||
e. If timeout: raises TimeoutError
|
||||
3. Raises RuntimeError if max attempts exhausted
|
||||
|
||||
|
||||
Args:
|
||||
context: The orchestration context
|
||||
payload_raw: The input payload
|
||||
|
||||
|
||||
Returns:
|
||||
dict: Result with published content
|
||||
|
||||
|
||||
Raises:
|
||||
ValueError: If input is invalid or agent returns no content
|
||||
TimeoutError: If human approval times out
|
||||
@@ -285,12 +287,12 @@ def get_worker(
|
||||
log_handler: logging.Handler | None = None
|
||||
) -> DurableTaskSchedulerWorker:
|
||||
"""Create a configured DurableTaskSchedulerWorker.
|
||||
|
||||
|
||||
Args:
|
||||
taskhub: Task hub name (defaults to TASKHUB env var or "default")
|
||||
endpoint: Scheduler endpoint (defaults to ENDPOINT env var or "http://localhost:8080")
|
||||
log_handler: Optional logging handler for worker logging
|
||||
|
||||
|
||||
Returns:
|
||||
Configured DurableTaskSchedulerWorker instance
|
||||
"""
|
||||
@@ -313,10 +315,10 @@ def get_worker(
|
||||
|
||||
def setup_worker(worker: DurableTaskSchedulerWorker) -> DurableAIAgentWorker:
|
||||
"""Set up the worker with agents, orchestrations, and activities registered.
|
||||
|
||||
|
||||
Args:
|
||||
worker: The DurableTaskSchedulerWorker instance
|
||||
|
||||
|
||||
Returns:
|
||||
DurableAIAgentWorker with agents, orchestrations, and activities registered
|
||||
"""
|
||||
|
||||
@@ -26,7 +26,7 @@ Self-Reflection LLM Runner
|
||||
Reflexion: language agents with verbal reinforcement learning.
|
||||
Noah Shinn, Federico Cassano, Ashwin Gopinath, Karthik Narasimhan, and Shunyu Yao. 2023.
|
||||
In Proceedings of the 37th International Conference on Neural Information Processing Systems (NIPS '23). Curran Associates Inc., Red Hook, NY, USA, Article 377, 8634–8652.
|
||||
https://arxiv.org/abs/2303.11366
|
||||
https://arxiv.org/abs/2303.11366
|
||||
|
||||
This module implements a self-reflection loop for LLM responses using groundedness evaluation.
|
||||
It loads prompts from a JSONL file, runs them through an LLM with self-reflection,
|
||||
@@ -123,8 +123,7 @@ def run_eval(
|
||||
print(f"Eval run failed. Run ID: {run.id}, Status: {run.status}, Error: {getattr(run, 'error', 'Unknown error')}")
|
||||
continue
|
||||
if run.status == "completed":
|
||||
output_items = list(client.evals.runs.output_items.list(run_id=run.id, eval_id=eval_object.id))
|
||||
return output_items
|
||||
return list(client.evals.runs.output_items.list(run_id=run.id, eval_id=eval_object.id))
|
||||
time.sleep(5)
|
||||
|
||||
print("Eval result retrieval timeout.")
|
||||
@@ -142,14 +141,14 @@ async def execute_query_with_self_reflection(
|
||||
) -> dict[str, Any]:
|
||||
"""
|
||||
Execute a query with self-reflection loop.
|
||||
|
||||
|
||||
Args:
|
||||
agent: ChatAgent instance to use for generating responses
|
||||
full_user_query: Complete prompt including system prompt, user request, and context
|
||||
context: Context document for groundedness evaluation
|
||||
evaluator: Groundedness evaluator function
|
||||
max_self_reflections: Maximum number of self-reflection iterations
|
||||
|
||||
|
||||
Returns:
|
||||
Dictionary containing:
|
||||
- best_response: The best response achieved
|
||||
|
||||
@@ -10,6 +10,7 @@ from agent_framework import (
|
||||
ChatMessage,
|
||||
ChatMiddleware,
|
||||
ChatResponse,
|
||||
MiddlewareTermination,
|
||||
chat_middleware,
|
||||
tool,
|
||||
)
|
||||
@@ -127,8 +128,7 @@ async def security_and_override_middleware(
|
||||
)
|
||||
|
||||
# Set terminate flag to stop execution
|
||||
context.terminate = True
|
||||
return
|
||||
raise MiddlewareTermination
|
||||
|
||||
# Continue to next middleware or AI execution
|
||||
await next(context)
|
||||
|
||||
@@ -10,6 +10,7 @@ from agent_framework import (
|
||||
AgentMiddleware,
|
||||
AgentResponse,
|
||||
ChatMessage,
|
||||
MiddlewareTermination,
|
||||
tool,
|
||||
)
|
||||
from agent_framework.azure import AzureAIAgentClient
|
||||
@@ -72,8 +73,7 @@ class PreTerminationMiddleware(AgentMiddleware):
|
||||
)
|
||||
|
||||
# Set terminate flag to prevent further processing
|
||||
context.terminate = True
|
||||
break
|
||||
raise MiddlewareTermination
|
||||
|
||||
await next(context)
|
||||
|
||||
@@ -98,7 +98,7 @@ class PostTerminationMiddleware(AgentMiddleware):
|
||||
f"[PostTerminationMiddleware] Maximum responses ({self.max_responses}) reached. "
|
||||
"Terminating further processing."
|
||||
)
|
||||
context.terminate = True
|
||||
raise MiddlewareTermination
|
||||
|
||||
# Allow the agent to process normally
|
||||
await next(context)
|
||||
|
||||
@@ -15,7 +15,6 @@ from agent_framework import (
|
||||
ChatResponse,
|
||||
ChatResponseUpdate,
|
||||
ResponseStream,
|
||||
Role,
|
||||
tool,
|
||||
)
|
||||
from agent_framework.openai import OpenAIResponsesClient
|
||||
@@ -76,12 +75,12 @@ async def weather_override_middleware(context: ChatContext, next: Callable[[Chat
|
||||
index["value"] += 1
|
||||
return update
|
||||
|
||||
context.result.with_update_hook(_update_hook)
|
||||
context.result.with_transform_hook(_update_hook)
|
||||
else:
|
||||
# For non-streaming: just replace with a new message
|
||||
current_text = context.result.text or ""
|
||||
current_text = context.result.text or "" # type: ignore
|
||||
custom_message = f"Weather Advisory: [0] {''.join(chunks)} Original message was: {current_text}"
|
||||
context.result = ChatResponse(messages=[ChatMessage(role=Role.ASSISTANT, text=custom_message)])
|
||||
context.result = ChatResponse(messages=[ChatMessage(role="assistant", text=custom_message)])
|
||||
|
||||
|
||||
async def validate_weather_middleware(context: ChatContext, next: Callable[[ChatContext], Awaitable[None]]) -> None:
|
||||
@@ -96,12 +95,12 @@ async def validate_weather_middleware(context: ChatContext, next: Callable[[Chat
|
||||
if context.stream and isinstance(context.result, ResponseStream):
|
||||
|
||||
def _append_validation_note(response: ChatResponse) -> ChatResponse:
|
||||
response.messages.append(ChatMessage(role=Role.ASSISTANT, text=validation_note))
|
||||
response.messages.append(ChatMessage(role="assistant", text=validation_note))
|
||||
return response
|
||||
|
||||
context.result.with_finalizer(_append_validation_note)
|
||||
context.result.with_result_hook(_append_validation_note)
|
||||
elif isinstance(context.result, ChatResponse):
|
||||
context.result.messages.append(ChatMessage(role=Role.ASSISTANT, text=validation_note))
|
||||
context.result.messages.append(ChatMessage(role="assistant", text=validation_note))
|
||||
|
||||
|
||||
async def agent_cleanup_middleware(context: AgentContext, next: Callable[[AgentContext], Awaitable[None]]) -> None:
|
||||
@@ -154,7 +153,7 @@ async def agent_cleanup_middleware(context: AgentContext, next: Callable[[AgentC
|
||||
if not found_validation:
|
||||
raise RuntimeError("Expected validation note not found in agent response.")
|
||||
|
||||
cleaned_messages.append(ChatMessage(role=Role.ASSISTANT, text=" Agent: OK"))
|
||||
cleaned_messages.append(ChatMessage(role="assistant", text=" Agent: OK"))
|
||||
response.messages = cleaned_messages
|
||||
return response
|
||||
|
||||
@@ -172,8 +171,8 @@ async def agent_cleanup_middleware(context: AgentContext, next: Callable[[AgentC
|
||||
content.text = text
|
||||
return update
|
||||
|
||||
context.result.with_update_hook(_clean_update)
|
||||
context.result.with_finalizer(_sanitize)
|
||||
context.result.with_transform_hook(_clean_update)
|
||||
context.result.with_result_hook(_sanitize)
|
||||
elif isinstance(context.result, AgentResponse):
|
||||
context.result = _sanitize(context.result)
|
||||
|
||||
@@ -192,6 +191,19 @@ async def main() -> None:
|
||||
tools=get_weather,
|
||||
middleware=[agent_cleanup_middleware],
|
||||
)
|
||||
# Streaming example
|
||||
print("\n--- Streaming Example ---")
|
||||
query = "What's the weather like in Portland?"
|
||||
print(f"User: {query}")
|
||||
print("Agent: ", end="", flush=True)
|
||||
response = agent.run(query, stream=True)
|
||||
# add the hooks to print what you want to see
|
||||
response.with_transform_hook(lambda chunk: print(chunk.text, end="", flush=True)).with_result_hook(
|
||||
lambda final: print(f"\nFinal streamed response: {final.text}", flush=True)
|
||||
)
|
||||
# consume the stream to trigger the hooks
|
||||
await response.get_final_response()
|
||||
|
||||
# Non-streaming example
|
||||
print("\n--- Non-streaming Example ---")
|
||||
query = "What's the weather like in Seattle?"
|
||||
@@ -199,18 +211,6 @@ async def main() -> None:
|
||||
result = await agent.run(query)
|
||||
print(f"Agent: {result}")
|
||||
|
||||
# Streaming example
|
||||
print("\n--- Streaming Example ---")
|
||||
query = "What's the weather like in Portland?"
|
||||
print(f"User: {query}")
|
||||
print("Agent: ", end="", flush=True)
|
||||
response = agent.run(query, stream=True)
|
||||
async for chunk in response:
|
||||
if chunk.text:
|
||||
print(chunk.text, end="", flush=True)
|
||||
print("\n")
|
||||
print(f"Final Result: {(await response.get_final_response()).text}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
|
||||
@@ -6,7 +6,6 @@ from agent_framework import (
|
||||
Executor,
|
||||
WorkflowBuilder,
|
||||
WorkflowContext,
|
||||
|
||||
handler,
|
||||
)
|
||||
from agent_framework.observability import configure_otel_providers, get_tracer
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
from typing import Any, Never
|
||||
from typing import Any
|
||||
|
||||
from agent_framework import (
|
||||
ChatAgent,
|
||||
@@ -14,6 +14,7 @@ from agent_framework import (
|
||||
from agent_framework.azure import AzureOpenAIChatClient
|
||||
from agent_framework.orchestrations import ConcurrentBuilder
|
||||
from azure.identity import AzureCliCredential
|
||||
from typing_extensions import Never
|
||||
|
||||
"""
|
||||
Sample: Concurrent Orchestration with participant factories and Custom Aggregator
|
||||
|
||||
@@ -150,11 +150,10 @@ def _handle_events(events: list[WorkflowEvent]) -> list[WorkflowEvent[HandoffAge
|
||||
speaker = message.author_name or message.role
|
||||
print(f"- {speaker}: {message.text or [content.type for content in message.contents]}")
|
||||
print("===================================")
|
||||
elif event.type == "request_info":
|
||||
elif event.type == "request_info" and isinstance(event.data, HandoffAgentUserRequest):
|
||||
# Request info event: Workflow is requesting user input
|
||||
if isinstance(event.data, HandoffAgentUserRequest):
|
||||
_print_handoff_agent_user_request(event.data.agent_response)
|
||||
requests.append(cast(WorkflowEvent[HandoffAgentUserRequest], event))
|
||||
_print_handoff_agent_user_request(event.data.agent_response)
|
||||
requests.append(cast(WorkflowEvent[HandoffAgentUserRequest], event))
|
||||
|
||||
return requests
|
||||
|
||||
|
||||
@@ -25,10 +25,9 @@ def add(
|
||||
|
||||
async def main():
|
||||
client = OpenAIResponsesClient()
|
||||
if client.function_invocation_configuration is not None:
|
||||
client.function_invocation_configuration.include_detailed_errors = True
|
||||
client.function_invocation_configuration.max_iterations = 40
|
||||
print(f"Function invocation configured as: \n{client.function_invocation_configuration.to_json(indent=2)}")
|
||||
client.function_invocation_configuration["include_detailed_errors"] = True
|
||||
client.function_invocation_configuration["max_iterations"] = 40
|
||||
print(f"Function invocation configured as: \n{client.function_invocation_configuration}")
|
||||
|
||||
agent = client.as_agent(name="ToolAgent", instructions="Use the provided tools.", tools=add)
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
from agent_framework import FunctionTool
|
||||
from agent_framework.openai import OpenAIResponsesClient
|
||||
|
||||
@@ -70,6 +72,5 @@ Result: {
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import asyncio
|
||||
|
||||
asyncio.run(main())
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import asyncio
|
||||
from typing import Annotated
|
||||
|
||||
from agent_framework import FunctionCallContent, FunctionResultContent, tool
|
||||
from agent_framework import tool
|
||||
from agent_framework.openai import OpenAIResponsesClient
|
||||
|
||||
"""
|
||||
@@ -21,7 +21,6 @@ def greet(name: Annotated[str, "Name to greet"]) -> str:
|
||||
return f"Hello, {name}!"
|
||||
|
||||
|
||||
@tool(approval_mode="never_require")
|
||||
# we trick the AI into calling this function with 0 as denominator to trigger the exception
|
||||
@tool(approval_mode="never_require")
|
||||
def safe_divide(
|
||||
@@ -62,11 +61,11 @@ async def main():
|
||||
if msg.text:
|
||||
print(f"{idx + 1} {msg.author_name or msg.role}: {msg.text} ")
|
||||
for content in msg.contents:
|
||||
if isinstance(content, FunctionCallContent):
|
||||
if content.type == "function_call":
|
||||
print(
|
||||
f"{idx + 1} {msg.author_name}: calling function: {content.name} with arguments: {content.arguments}"
|
||||
)
|
||||
if isinstance(content, FunctionResultContent):
|
||||
if content.type == "function_result":
|
||||
print(f"{idx + 1} {msg.role}: {content.result if content.result else content.exception}")
|
||||
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import asyncio
|
||||
from typing import Annotated
|
||||
|
||||
from agent_framework import FunctionCallContent, FunctionResultContent, tool
|
||||
from agent_framework import tool
|
||||
from agent_framework.openai import OpenAIResponsesClient
|
||||
|
||||
"""
|
||||
@@ -55,11 +55,11 @@ async def main():
|
||||
if msg.text:
|
||||
print(f"{idx + 1} {msg.author_name or msg.role}: {msg.text} ")
|
||||
for content in msg.contents:
|
||||
if isinstance(content, FunctionCallContent):
|
||||
if content.type == "function_call":
|
||||
print(
|
||||
f"{idx + 1} {msg.author_name}: calling function: {content.name} with arguments: {content.arguments}"
|
||||
)
|
||||
if isinstance(content, FunctionResultContent):
|
||||
if content.type == "function_result":
|
||||
print(f"{idx + 1} {msg.role}: {content.result if content.result else content.exception}")
|
||||
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import asyncio
|
||||
from typing import Annotated
|
||||
|
||||
from agent_framework import FunctionCallContent, FunctionResultContent, tool
|
||||
from agent_framework import tool
|
||||
from agent_framework.openai import OpenAIResponsesClient
|
||||
|
||||
"""
|
||||
@@ -44,11 +44,11 @@ async def main():
|
||||
if msg.text:
|
||||
print(f"{idx + 1} {msg.author_name or msg.role}: {msg.text} ")
|
||||
for content in msg.contents:
|
||||
if isinstance(content, FunctionCallContent):
|
||||
if content.type == "function_call":
|
||||
print(
|
||||
f"{idx + 1} {msg.author_name}: calling function: {content.name} with arguments: {content.arguments}"
|
||||
)
|
||||
if isinstance(content, FunctionResultContent):
|
||||
if content.type == "function_result":
|
||||
print(f"{idx + 1} {msg.role}: {content.result if content.result else content.exception}")
|
||||
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ The second reverses the text and yields the workflow output. Events are printed
|
||||
Purpose:
|
||||
Show how to declare executors with the @executor decorator, connect them with WorkflowBuilder,
|
||||
pass intermediate values using ctx.send_message, and yield final output using ctx.yield_output().
|
||||
Demonstrate how streaming exposes executor_invoked events (type='executor_invoked') and
|
||||
Demonstrate how streaming exposes executor_invoked events (type='executor_invoked') and
|
||||
executor_completed events (type='executor_completed') for observability.
|
||||
|
||||
Prerequisites:
|
||||
|
||||
@@ -28,7 +28,7 @@ Pipeline layout:
|
||||
writer_agent -> Coordinator -> writer_agent -> Coordinator -> final_editor_agent -> Coordinator -> output
|
||||
|
||||
The writer agent drafts marketing copy. A custom executor emits a request_info event (type='request_info') so a
|
||||
human can comment, then relays the human guidance back into the conversation before the final editor agent
|
||||
human can comment, then relays the human guidance back into the conversation before the final editor agent
|
||||
produces the polished output.
|
||||
|
||||
Demonstrates:
|
||||
|
||||
+3
-1
@@ -43,7 +43,9 @@ Prerequisites:
|
||||
|
||||
|
||||
# 1. Define tools for different agents
|
||||
# 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.
|
||||
# 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 run_tests(test_suite: Annotated[str, "Name of the test suite to run"]) -> str:
|
||||
"""Run automated tests for the application."""
|
||||
|
||||
Generated
+107
-113
@@ -916,7 +916,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "anthropic"
|
||||
version = "0.77.1"
|
||||
version = "0.78.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "anyio", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
@@ -928,9 +928,9 @@ dependencies = [
|
||||
{ name = "sniffio", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
{ name = "typing-extensions", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/88/61/50aef0587acd9dd8bf1b8b7fd7fbb25ba4c6ec5387a6ffc195a697951fcc/anthropic-0.77.1.tar.gz", hash = "sha256:a19d78ff6fff9e05d211e3a936051cd5b9462f0eac043d2d45b2372f455d11cd", size = 504691, upload-time = "2026-02-03T17:44:22.667Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ec/51/32849a48f9b1cfe80a508fd269b20bd8f0b1357c70ba092890fde5a6a10b/anthropic-0.78.0.tar.gz", hash = "sha256:55fd978ab9b049c61857463f4c4e9e092b24f892519c6d8078cee1713d8af06e", size = 509136, upload-time = "2026-02-05T17:52:04.986Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/2b/54/e83babf9833547c5548b4e25230ef3d62492e45925b0d104a43e501918a0/anthropic-0.77.1-py3-none-any.whl", hash = "sha256:76fd6f2ab36033a5294d58182a5f712dab9573c3a54413a275ecdf29e727c1e0", size = 397856, upload-time = "2026-02-03T17:44:20.962Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3b/03/2f50931a942e5e13f80e24d83406714672c57964be593fc046d81369335b/anthropic-0.78.0-py3-none-any.whl", hash = "sha256:2a9887d2e99d1b0f9fe08857a1e9fe5d2d4030455dbf9ac65aab052e2efaeac4", size = 405485, upload-time = "2026-02-05T17:52:03.674Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1426,19 +1426,19 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "claude-agent-sdk"
|
||||
version = "0.1.29"
|
||||
version = "0.1.31"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "anyio", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
{ name = "mcp", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
{ name = "typing-extensions", marker = "(python_full_version < '3.11' and sys_platform == 'darwin') or (python_full_version < '3.11' and sys_platform == 'linux') or (python_full_version < '3.11' and sys_platform == 'win32')" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/f2/a7/e1449285606b98119729249394ad0e93e75ea6d25fa3006d734b21f73044/claude_agent_sdk-0.1.29.tar.gz", hash = "sha256:ece32436a81fc015ca325d4121edeb5627ae9af15b5079f7b42d5eda9dcdb7a3", size = 59801, upload-time = "2026-02-04T00:53:54.099Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/6d/df/071dce5803c4db8cd53708bcda3b6022c1c4b68fc00e9007593309515286/claude_agent_sdk-0.1.31.tar.gz", hash = "sha256:b68c681083d7cc985dd3e48f73aabf459f056c1a7e1c5b9c47033c6af94da1a1", size = 61191, upload-time = "2026-02-06T02:01:51.043Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/41/98/8915e3bb6acccf2b62b101545b286f30fd63e5421e9a3483b88a0c88f49b/claude_agent_sdk-0.1.29-py3-none-macosx_11_0_arm64.whl", hash = "sha256:811de31c92bd90250ebbfd79758c538766c672abde244ae0f7dec2d02ed5a1f7", size = 54225884, upload-time = "2026-02-04T00:53:38.169Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/91/a7/9a8801ae25e453877bc71b5dc4f4818171bc9c04319e0681d3950fbe0232/claude_agent_sdk-0.1.29-py3-none-manylinux_2_17_aarch64.whl", hash = "sha256:6279360d251ce8b8e9d922b03e3492c88736648e7f5e7c9f301fde0eef37928f", size = 68426447, upload-time = "2026-02-04T00:53:42.539Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/87/9c/aab63fe82c7cba80ee5234b0a928a032340cdaba0e48d23544e592b6f9ca/claude_agent_sdk-0.1.29-py3-none-manylinux_2_17_x86_64.whl", hash = "sha256:4d1f01fe5f7252126f35808e2887a40125b784ac0dbf73b9509a4065a4766149", size = 70124488, upload-time = "2026-02-04T00:53:46.675Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/63/30/135575231e53c10d4a99f1fa7b0b548f2ae89b907e41d0b2d158bde1896e/claude_agent_sdk-0.1.29-py3-none-win_amd64.whl", hash = "sha256:67fb58a72f0dd54d079c538078130cc8c888bc60652d3d396768ffaee6716467", size = 72305314, upload-time = "2026-02-04T00:53:51.045Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0c/7c/e249a3b4215e28a9722b3d9ab6057bceeeaa2b948530f022065ef2154555/claude_agent_sdk-0.1.31-py3-none-macosx_11_0_arm64.whl", hash = "sha256:801bacfe4192782a7cc7b61b0d23a57f061c069993dd3dfa8109aa2e7050a530", size = 54284257, upload-time = "2026-02-06T02:01:35.61Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d6/a8/1a8288736aeafcc48e3dcb3326ec7f487dbf89ebba77d526e9464786a299/claude_agent_sdk-0.1.31-py3-none-manylinux_2_17_aarch64.whl", hash = "sha256:0b608e0cbfcedcb827427e6d16a73fe573d58e7f93e15f95435066feacbe6511", size = 68462461, upload-time = "2026-02-06T02:01:40.074Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/26/7a/7dcd0b77263ed55b17554fa3a67a6772b788e7048a524fd06c9baa970564/claude_agent_sdk-0.1.31-py3-none-manylinux_2_17_x86_64.whl", hash = "sha256:d0cb30e026a22246e84d9237d23bb4df20be5146913a04d2802ddd37d4f8b8c9", size = 70173234, upload-time = "2026-02-06T02:01:44.486Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/37/a5/4a8de7a9738f454b54aa97557f0fba9c74b0901ea418597008c668243fea/claude_agent_sdk-0.1.31-py3-none-win_amd64.whl", hash = "sha256:8ceca675c2770ad739bd1208362059a830e91c74efcf128045b5a7af14d36f2b", size = 72366975, upload-time = "2026-02-06T02:01:48.647Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1458,7 +1458,7 @@ name = "clr-loader"
|
||||
version = "0.2.10"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "cffi", marker = "(python_full_version < '3.14' and sys_platform == 'darwin') or (python_full_version < '3.14' and sys_platform == 'linux') or (python_full_version < '3.14' and sys_platform == 'win32')" },
|
||||
{ name = "cffi", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/18/24/c12faf3f61614b3131b5c98d3bf0d376b49c7feaa73edca559aeb2aee080/clr_loader-0.2.10.tar.gz", hash = "sha256:81f114afbc5005bafc5efe5af1341d400e22137e275b042a8979f3feb9fc9446", size = 83605, upload-time = "2026-01-03T23:13:06.984Z" }
|
||||
wheels = [
|
||||
@@ -1921,7 +1921,7 @@ source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "asyncio", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
{ name = "grpcio", version = "1.67.1", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version < '3.14' and sys_platform == 'darwin') or (python_full_version < '3.14' and sys_platform == 'linux') or (python_full_version < '3.14' and sys_platform == 'win32')" },
|
||||
{ name = "grpcio", version = "1.76.0", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.14' and sys_platform == 'darwin') or (python_full_version >= '3.14' and sys_platform == 'linux') or (python_full_version >= '3.14' and sys_platform == 'win32')" },
|
||||
{ name = "grpcio", version = "1.78.0", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.14' and sys_platform == 'darwin') or (python_full_version >= '3.14' and sys_platform == 'linux') or (python_full_version >= '3.14' and sys_platform == 'win32')" },
|
||||
{ name = "packaging", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
{ name = "protobuf", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
]
|
||||
@@ -1961,7 +1961,7 @@ name = "exceptiongroup"
|
||||
version = "1.3.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "typing-extensions", marker = "(python_full_version < '3.11' and sys_platform == 'darwin') or (python_full_version < '3.11' and sys_platform == 'linux') or (python_full_version < '3.11' and sys_platform == 'win32')" },
|
||||
{ name = "typing-extensions", marker = "(python_full_version < '3.13' and sys_platform == 'darwin') or (python_full_version < '3.13' and sys_platform == 'linux') or (python_full_version < '3.13' and sys_platform == 'win32')" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" }
|
||||
wheels = [
|
||||
@@ -1979,17 +1979,18 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "fastapi"
|
||||
version = "0.128.1"
|
||||
version = "0.128.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "annotated-doc", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
{ name = "pydantic", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
{ name = "starlette", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
{ name = "typing-extensions", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
{ name = "typing-inspection", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/f6/59/28bde150415783ff084334e3de106eb7461a57864cf69f343950ad5a5ddd/fastapi-0.128.1.tar.gz", hash = "sha256:ce5be4fa26d4ce6f54debcc873d1fb8e0e248f5c48d7502ba6c61457ab2dc766", size = 374260, upload-time = "2026-02-04T17:35:10.542Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/4f/6e/45fb5390d46d7918426ea1c1ec4b06c1d3fd70be4a47a690ccb4f1f9438a/fastapi-0.128.2.tar.gz", hash = "sha256:7db9eb891866ac3a08e03f844b99e343a2c1cc41247e68e006c90b38d2464ea1", size = 376129, upload-time = "2026-02-05T19:48:33.957Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/1a/08/3953db1979ea131c68279b997c6465080118b407f0800445b843f8e164b3/fastapi-0.128.1-py3-none-any.whl", hash = "sha256:ee82146bbf91ea5bbf2bb8629e4c6e056c4fbd997ea6068501b11b15260b50fb", size = 103810, upload-time = "2026-02-04T17:35:08.02Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c1/f2/80df24108572630bb2adef3d97f1e774b18ec25bfbab5528f36cba6478c0/fastapi-0.128.2-py3-none-any.whl", hash = "sha256:55bfd9490ca0125707d80e785583c2dc57840bb66e3a0bbc087d20c364964dc0", size = 104032, upload-time = "2026-02-05T19:48:32.118Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2328,11 +2329,11 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "fsspec"
|
||||
version = "2026.1.0"
|
||||
version = "2026.2.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d5/7d/5df2650c57d47c57232af5ef4b4fdbff182070421e405e0d62c6cdbfaa87/fsspec-2026.1.0.tar.gz", hash = "sha256:e987cb0496a0d81bba3a9d1cee62922fb395e7d4c3b575e57f547953334fe07b", size = 310496, upload-time = "2026-01-09T15:21:35.562Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/51/7c/f60c259dcbf4f0c47cc4ddb8f7720d2dcdc8888c8e5ad84c73ea4531cc5b/fsspec-2026.2.0.tar.gz", hash = "sha256:6544e34b16869f5aacd5b90bdf1a71acb37792ea3ddf6125ee69a22a53fb8bff", size = 313441, upload-time = "2026-02-05T21:50:53.743Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/01/c9/97cc5aae1648dcb851958a3ddf73ccd7dbe5650d95203ecb4d7720b4cdbf/fsspec-2026.1.0-py3-none-any.whl", hash = "sha256:cb76aa913c2285a3b49bdd5fc55b1d7c708d7208126b60f2eb8194fe1b4cbdcc", size = 201838, upload-time = "2026-01-09T15:21:34.041Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e6/ab/fb21f4c939bb440104cc2b396d3be1d9b7a9fd3c6c2a53d98c45b3d7c954/fsspec-2026.2.0-py3-none-any.whl", hash = "sha256:98de475b5cb3bd66bedd5c4679e87b4fdfe1a3bf4d707b151b3c07e58c9a2437", size = 202505, upload-time = "2026-02-05T21:50:51.819Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2350,16 +2351,16 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "github-copilot-sdk"
|
||||
version = "0.1.21"
|
||||
version = "0.1.22"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "pydantic", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
{ name = "python-dateutil", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
{ name = "typing-extensions", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/95/d0/f1b55044e1a3e3f368c867cbf91e68e36282efa9f53eb03532cf761a84e8/github_copilot_sdk-0.1.21.tar.gz", hash = "sha256:1c8572d1155fcedb1c3c4f02b4d4fe0aec97ccba63ab0c1b87f8f871da4922ea", size = 96353, upload-time = "2026-02-03T23:15:26.627Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/cf/b7/ae720a503c9b329f8c95036a04fae8e023db8dcdce9d24382259865f0760/github_copilot_sdk-0.1.22.tar.gz", hash = "sha256:8ea4534f0c8ab0fa04e0fec4c3ebd42d737cf7772277e4f8eb58a9fadac6bdb5", size = 97324, upload-time = "2026-02-05T17:33:33.726Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/ba/39/b8107ca00e42c44bd964e187aa81a60ae2e09fcbae9f255f7e50d7c0cead/github_copilot_sdk-0.1.21-py3-none-any.whl", hash = "sha256:c09d4004d14171474680c6d9279c0f10d6b4636c370f574828da6181aafb6b34", size = 43732, upload-time = "2026-02-03T23:15:25.377Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7e/2e/68aa28018778fa86a8392b37c6a883d7a9a24b715ba5baa470ce018f1542/github_copilot_sdk-0.1.22-py3-none-any.whl", hash = "sha256:f75d84dd2633138834330597400b28fefbf8bd75541f78083831f58c9bdde81a", size = 44149, upload-time = "2026-02-05T17:33:31.948Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2422,7 +2423,6 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/fe/65/5b235b40581ad75ab97dcd8b4218022ae8e3ab77c13c919f1a1dfe9171fd/greenlet-3.3.1-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:04bee4775f40ecefcdaa9d115ab44736cd4b9c5fba733575bfe9379419582e13", size = 273723, upload-time = "2026-01-23T15:30:37.521Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ce/ad/eb4729b85cba2d29499e0a04ca6fbdd8f540afd7be142fd571eea43d712f/greenlet-3.3.1-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:50e1457f4fed12a50e427988a07f0f9df53cf0ee8da23fab16e6732c2ec909d4", size = 574874, upload-time = "2026-01-23T16:00:54.551Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/87/32/57cad7fe4c8b82fdaa098c89498ef85ad92dfbb09d5eb713adedfc2ae1f5/greenlet-3.3.1-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:070472cd156f0656f86f92e954591644e158fd65aa415ffbe2d44ca77656a8f5", size = 586309, upload-time = "2026-01-23T16:05:25.18Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/66/66/f041005cb87055e62b0d68680e88ec1a57f4688523d5e2fb305841bc8307/greenlet-3.3.1-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1108b61b06b5224656121c3c8ee8876161c491cbe74e5c519e0634c837cf93d5", size = 597461, upload-time = "2026-01-23T16:15:51.943Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/87/eb/8a1ec2da4d55824f160594a75a9d8354a5fe0a300fb1c48e7944265217e1/greenlet-3.3.1-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3a300354f27dd86bae5fbf7002e6dd2b3255cd372e9242c933faf5e859b703fe", size = 586985, upload-time = "2026-01-23T15:32:47.968Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/15/1c/0621dd4321dd8c351372ee8f9308136acb628600658a49be1b7504208738/greenlet-3.3.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e84b51cbebf9ae573b5fbd15df88887815e3253fc000a7d0ff95170e8f7e9729", size = 1547271, upload-time = "2026-01-23T16:04:18.977Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9d/53/24047f8924c83bea7a59c8678d9571209c6bfe5f4c17c94a78c06024e9f2/greenlet-3.3.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e0093bd1a06d899892427217f0ff2a3c8f306182b8c754336d32e2d587c131b4", size = 1613427, upload-time = "2026-01-23T15:33:44.428Z" },
|
||||
@@ -2430,7 +2430,6 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/ec/e8/2e1462c8fdbe0f210feb5ac7ad2d9029af8be3bf45bd9fa39765f821642f/greenlet-3.3.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:5fd23b9bc6d37b563211c6abbb1b3cab27db385a4449af5c32e932f93017080c", size = 274974, upload-time = "2026-01-23T15:31:02.891Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7e/a8/530a401419a6b302af59f67aaf0b9ba1015855ea7e56c036b5928793c5bd/greenlet-3.3.1-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:09f51496a0bfbaa9d74d36a52d2580d1ef5ed4fdfcff0a73730abfbbbe1403dd", size = 577175, upload-time = "2026-01-23T16:00:56.213Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8e/89/7e812bb9c05e1aaef9b597ac1d0962b9021d2c6269354966451e885c4e6b/greenlet-3.3.1-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cb0feb07fe6e6a74615ee62a880007d976cf739b6669cce95daa7373d4fc69c5", size = 590401, upload-time = "2026-01-23T16:05:26.365Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/70/ae/e2d5f0e59b94a2269b68a629173263fa40b63da32f5c231307c349315871/greenlet-3.3.1-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:67ea3fc73c8cd92f42467a72b75e8f05ed51a0e9b1d15398c913416f2dafd49f", size = 601161, upload-time = "2026-01-23T16:15:53.456Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5c/ae/8d472e1f5ac5efe55c563f3eabb38c98a44b832602e12910750a7c025802/greenlet-3.3.1-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:39eda9ba259cc9801da05351eaa8576e9aa83eb9411e8f0c299e05d712a210f2", size = 590272, upload-time = "2026-01-23T15:32:49.411Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a8/51/0fde34bebfcadc833550717eade64e35ec8738e6b097d5d248274a01258b/greenlet-3.3.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e2e7e882f83149f0a71ac822ebf156d902e7a5d22c9045e3e0d1daf59cee2cc9", size = 1550729, upload-time = "2026-01-23T16:04:20.867Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/16/c9/2fb47bee83b25b119d5a35d580807bb8b92480a54b68fef009a02945629f/greenlet-3.3.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:80aa4d79eb5564f2e0a6144fcc744b5a37c56c4a92d60920720e99210d88db0f", size = 1615552, upload-time = "2026-01-23T15:33:45.743Z" },
|
||||
@@ -2439,7 +2438,6 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/f9/c8/9d76a66421d1ae24340dfae7e79c313957f6e3195c144d2c73333b5bfe34/greenlet-3.3.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:7e806ca53acf6d15a888405880766ec84721aa4181261cd11a457dfe9a7a4975", size = 276443, upload-time = "2026-01-23T15:30:10.066Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/81/99/401ff34bb3c032d1f10477d199724f5e5f6fbfb59816ad1455c79c1eb8e7/greenlet-3.3.1-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d842c94b9155f1c9b3058036c24ffb8ff78b428414a19792b2380be9cecf4f36", size = 597359, upload-time = "2026-01-23T16:00:57.394Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2b/bc/4dcc0871ed557792d304f50be0f7487a14e017952ec689effe2180a6ff35/greenlet-3.3.1-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:20fedaadd422fa02695f82093f9a98bad3dab5fcda793c658b945fcde2ab27ba", size = 607805, upload-time = "2026-01-23T16:05:28.068Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3b/cd/7a7ca57588dac3389e97f7c9521cb6641fd8b6602faf1eaa4188384757df/greenlet-3.3.1-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c620051669fd04ac6b60ebc70478210119c56e2d5d5df848baec4312e260e4ca", size = 622363, upload-time = "2026-01-23T16:15:54.754Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/cf/05/821587cf19e2ce1f2b24945d890b164401e5085f9d09cbd969b0c193cd20/greenlet-3.3.1-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:14194f5f4305800ff329cbf02c5fcc88f01886cadd29941b807668a45f0d2336", size = 609947, upload-time = "2026-01-23T15:32:51.004Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a4/52/ee8c46ed9f8babaa93a19e577f26e3d28a519feac6350ed6f25f1afee7e9/greenlet-3.3.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7b2fe4150a0cf59f847a67db8c155ac36aed89080a6a639e9f16df5d6c6096f1", size = 1567487, upload-time = "2026-01-23T16:04:22.125Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8f/7c/456a74f07029597626f3a6db71b273a3632aecb9afafeeca452cfa633197/greenlet-3.3.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:49f4ad195d45f4a66a0eb9c1ba4832bb380570d361912fa3554746830d332149", size = 1636087, upload-time = "2026-01-23T15:33:47.486Z" },
|
||||
@@ -2448,7 +2446,6 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/ec/ab/d26750f2b7242c2b90ea2ad71de70cfcd73a948a49513188a0fc0d6fc15a/greenlet-3.3.1-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:7ab327905cabb0622adca5971e488064e35115430cec2c35a50fd36e72a315b3", size = 275205, upload-time = "2026-01-23T15:30:24.556Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/10/d3/be7d19e8fad7c5a78eeefb2d896a08cd4643e1e90c605c4be3b46264998f/greenlet-3.3.1-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:65be2f026ca6a176f88fb935ee23c18333ccea97048076aef4db1ef5bc0713ac", size = 599284, upload-time = "2026-01-23T16:00:58.584Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ae/21/fe703aaa056fdb0f17e5afd4b5c80195bbdab701208918938bd15b00d39b/greenlet-3.3.1-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7a3ae05b3d225b4155bda56b072ceb09d05e974bc74be6c3fc15463cf69f33fd", size = 610274, upload-time = "2026-01-23T16:05:29.312Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/06/00/95df0b6a935103c0452dad2203f5be8377e551b8466a29650c4c5a5af6cc/greenlet-3.3.1-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:12184c61e5d64268a160226fb4818af4df02cfead8379d7f8b99a56c3a54ff3e", size = 624375, upload-time = "2026-01-23T16:15:55.915Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/cb/86/5c6ab23bb3c28c21ed6bebad006515cfe08b04613eb105ca0041fecca852/greenlet-3.3.1-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6423481193bbbe871313de5fd06a082f2649e7ce6e08015d2a76c1e9186ca5b3", size = 612904, upload-time = "2026-01-23T15:32:52.317Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c2/f3/7949994264e22639e40718c2daf6f6df5169bf48fb038c008a489ec53a50/greenlet-3.3.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:33a956fe78bbbda82bfc95e128d61129b32d66bcf0a20a1f0c08aa4839ffa951", size = 1567316, upload-time = "2026-01-23T16:04:23.316Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8d/6e/d73c94d13b6465e9f7cd6231c68abde838bb22408596c05d9059830b7872/greenlet-3.3.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b065d3284be43728dd280f6f9a13990b56470b81be20375a207cdc814a983f2", size = 1636549, upload-time = "2026-01-23T15:33:48.643Z" },
|
||||
@@ -2457,7 +2454,6 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/ae/fb/011c7c717213182caf78084a9bea51c8590b0afda98001f69d9f853a495b/greenlet-3.3.1-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:bd59acd8529b372775cd0fcbc5f420ae20681c5b045ce25bd453ed8455ab99b5", size = 275737, upload-time = "2026-01-23T15:32:16.889Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/41/2e/a3a417d620363fdbb08a48b1dd582956a46a61bf8fd27ee8164f9dfe87c2/greenlet-3.3.1-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b31c05dd84ef6871dd47120386aed35323c944d86c3d91a17c4b8d23df62f15b", size = 646422, upload-time = "2026-01-23T16:01:00.354Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b4/09/c6c4a0db47defafd2d6bab8ddfe47ad19963b4e30f5bed84d75328059f8c/greenlet-3.3.1-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:02925a0bfffc41e542c70aa14c7eda3593e4d7e274bfcccca1827e6c0875902e", size = 658219, upload-time = "2026-01-23T16:05:30.956Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e2/89/b95f2ddcc5f3c2bc09c8ee8d77be312df7f9e7175703ab780f2014a0e781/greenlet-3.3.1-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3e0f3878ca3a3ff63ab4ea478585942b53df66ddde327b59ecb191b19dbbd62d", size = 671455, upload-time = "2026-01-23T16:15:57.232Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/80/38/9d42d60dffb04b45f03dbab9430898352dba277758640751dc5cc316c521/greenlet-3.3.1-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:34a729e2e4e4ffe9ae2408d5ecaf12f944853f40ad724929b7585bca808a9d6f", size = 660237, upload-time = "2026-01-23T15:32:53.967Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/96/61/373c30b7197f9e756e4c81ae90a8d55dc3598c17673f91f4d31c3c689c3f/greenlet-3.3.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:aec9ab04e82918e623415947921dea15851b152b822661cce3f8e4393c3df683", size = 1615261, upload-time = "2026-01-23T16:04:25.066Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fd/d3/ca534310343f5945316f9451e953dcd89b36fe7a19de652a1dc5a0eeef3f/greenlet-3.3.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:71c767cf281a80d02b6c1bdc41c9468e1f5a494fb11bc8688c360524e273d7b1", size = 1683719, upload-time = "2026-01-23T15:33:50.61Z" },
|
||||
@@ -2466,7 +2462,6 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/28/24/cbbec49bacdcc9ec652a81d3efef7b59f326697e7edf6ed775a5e08e54c2/greenlet-3.3.1-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:3e63252943c921b90abb035ebe9de832c436401d9c45f262d80e2d06cc659242", size = 282706, upload-time = "2026-01-23T15:33:05.525Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/86/2e/4f2b9323c144c4fe8842a4e0d92121465485c3c2c5b9e9b30a52e80f523f/greenlet-3.3.1-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:76e39058e68eb125de10c92524573924e827927df5d3891fbc97bd55764a8774", size = 651209, upload-time = "2026-01-23T16:01:01.517Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d9/87/50ca60e515f5bb55a2fbc5f0c9b5b156de7d2fc51a0a69abc9d23914a237/greenlet-3.3.1-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c9f9d5e7a9310b7a2f416dd13d2e3fd8b42d803968ea580b7c0f322ccb389b97", size = 654300, upload-time = "2026-01-23T16:05:32.199Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7c/25/c51a63f3f463171e09cb586eb64db0861eb06667ab01a7968371a24c4f3b/greenlet-3.3.1-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4b9721549a95db96689458a1e0ae32412ca18776ed004463df3a9299c1b257ab", size = 662574, upload-time = "2026-01-23T16:15:58.364Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1d/94/74310866dfa2b73dd08659a3d18762f83985ad3281901ba0ee9a815194fb/greenlet-3.3.1-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:92497c78adf3ac703b57f1e3813c2d874f27f71a178f9ea5887855da413cd6d2", size = 653842, upload-time = "2026-01-23T15:32:55.671Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/97/43/8bf0ffa3d498eeee4c58c212a3905dd6146c01c8dc0b0a046481ca29b18c/greenlet-3.3.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ed6b402bc74d6557a705e197d47f9063733091ed6357b3de33619d8a8d93ac53", size = 1614917, upload-time = "2026-01-23T16:04:26.276Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/89/90/a3be7a5f378fc6e84abe4dcfb2ba32b07786861172e502388b4c90000d1b/greenlet-3.3.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:59913f1e5ada20fde795ba906916aea25d442abcc0593fba7e26c92b7ad76249", size = 1676092, upload-time = "2026-01-23T15:33:52.176Z" },
|
||||
@@ -2545,7 +2540,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "grpcio"
|
||||
version = "1.76.0"
|
||||
version = "1.78.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
resolution-markers = [
|
||||
"python_full_version >= '3.14' and sys_platform == 'darwin'",
|
||||
@@ -2555,58 +2550,58 @@ resolution-markers = [
|
||||
dependencies = [
|
||||
{ name = "typing-extensions", marker = "(python_full_version >= '3.14' and sys_platform == 'darwin') or (python_full_version >= '3.14' and sys_platform == 'linux') or (python_full_version >= '3.14' and sys_platform == 'win32')" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b6/e0/318c1ce3ae5a17894d5791e87aea147587c9e702f24122cc7a5c8bbaeeb1/grpcio-1.76.0.tar.gz", hash = "sha256:7be78388d6da1a25c0d5ec506523db58b18be22d9c37d8d3a32c08be4987bd73", size = 12785182, upload-time = "2025-10-21T16:23:12.106Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/06/8a/3d098f35c143a89520e568e6539cc098fcd294495910e359889ce8741c84/grpcio-1.78.0.tar.gz", hash = "sha256:7382b95189546f375c174f53a5fa873cef91c4b8005faa05cc5b3beea9c4f1c5", size = 12852416, upload-time = "2026-02-06T09:57:18.093Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/88/17/ff4795dc9a34b6aee6ec379f1b66438a3789cd1315aac0cbab60d92f74b3/grpcio-1.76.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:65a20de41e85648e00305c1bb09a3598f840422e522277641145a32d42dcefcc", size = 5840037, upload-time = "2025-10-21T16:20:25.069Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4e/ff/35f9b96e3fa2f12e1dcd58a4513a2e2294a001d64dec81677361b7040c9a/grpcio-1.76.0-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:40ad3afe81676fd9ec6d9d406eda00933f218038433980aa19d401490e46ecde", size = 11836482, upload-time = "2025-10-21T16:20:30.113Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3e/1c/8374990f9545e99462caacea5413ed783014b3b66ace49e35c533f07507b/grpcio-1.76.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:035d90bc79eaa4bed83f524331d55e35820725c9fbb00ffa1904d5550ed7ede3", size = 6407178, upload-time = "2025-10-21T16:20:32.733Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1e/77/36fd7d7c75a6c12542c90a6d647a27935a1ecaad03e0ffdb7c42db6b04d2/grpcio-1.76.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:4215d3a102bd95e2e11b5395c78562967959824156af11fa93d18fdd18050990", size = 7075684, upload-time = "2025-10-21T16:20:35.435Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/38/f7/e3cdb252492278e004722306c5a8935eae91e64ea11f0af3437a7de2e2b7/grpcio-1.76.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:49ce47231818806067aea3324d4bf13825b658ad662d3b25fada0bdad9b8a6af", size = 6611133, upload-time = "2025-10-21T16:20:37.541Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7e/20/340db7af162ccd20a0893b5f3c4a5d676af7b71105517e62279b5b61d95a/grpcio-1.76.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8cc3309d8e08fd79089e13ed4819d0af72aa935dd8f435a195fd152796752ff2", size = 7195507, upload-time = "2025-10-21T16:20:39.643Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/10/f0/b2160addc1487bd8fa4810857a27132fb4ce35c1b330c2f3ac45d697b106/grpcio-1.76.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:971fd5a1d6e62e00d945423a567e42eb1fa678ba89072832185ca836a94daaa6", size = 8160651, upload-time = "2025-10-21T16:20:42.492Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2c/2c/ac6f98aa113c6ef111b3f347854e99ebb7fb9d8f7bb3af1491d438f62af4/grpcio-1.76.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9d9adda641db7207e800a7f089068f6f645959f2df27e870ee81d44701dd9db3", size = 7620568, upload-time = "2025-10-21T16:20:45.995Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/90/84/7852f7e087285e3ac17a2703bc4129fafee52d77c6c82af97d905566857e/grpcio-1.76.0-cp310-cp310-win32.whl", hash = "sha256:063065249d9e7e0782d03d2bca50787f53bd0fb89a67de9a7b521c4a01f1989b", size = 3998879, upload-time = "2025-10-21T16:20:48.592Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/10/30/d3d2adcbb6dd3ff59d6ac3df6ef830e02b437fb5c90990429fd180e52f30/grpcio-1.76.0-cp310-cp310-win_amd64.whl", hash = "sha256:a6ae758eb08088d36812dd5d9af7a9859c05b1e0f714470ea243694b49278e7b", size = 4706892, upload-time = "2025-10-21T16:20:50.697Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a0/00/8163a1beeb6971f66b4bbe6ac9457b97948beba8dd2fc8e1281dce7f79ec/grpcio-1.76.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:2e1743fbd7f5fa713a1b0a8ac8ebabf0ec980b5d8809ec358d488e273b9cf02a", size = 5843567, upload-time = "2025-10-21T16:20:52.829Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/10/c1/934202f5cf335e6d852530ce14ddb0fef21be612ba9ecbbcbd4d748ca32d/grpcio-1.76.0-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:a8c2cf1209497cf659a667d7dea88985e834c24b7c3b605e6254cbb5076d985c", size = 11848017, upload-time = "2025-10-21T16:20:56.705Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/11/0b/8dec16b1863d74af6eb3543928600ec2195af49ca58b16334972f6775663/grpcio-1.76.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:08caea849a9d3c71a542827d6df9d5a69067b0a1efbea8a855633ff5d9571465", size = 6412027, upload-time = "2025-10-21T16:20:59.3Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d7/64/7b9e6e7ab910bea9d46f2c090380bab274a0b91fb0a2fe9b0cd399fffa12/grpcio-1.76.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:f0e34c2079d47ae9f6188211db9e777c619a21d4faba6977774e8fa43b085e48", size = 7075913, upload-time = "2025-10-21T16:21:01.645Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/68/86/093c46e9546073cefa789bd76d44c5cb2abc824ca62af0c18be590ff13ba/grpcio-1.76.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8843114c0cfce61b40ad48df65abcfc00d4dba82eae8718fab5352390848c5da", size = 6615417, upload-time = "2025-10-21T16:21:03.844Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f7/b6/5709a3a68500a9c03da6fb71740dcdd5ef245e39266461a03f31a57036d8/grpcio-1.76.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8eddfb4d203a237da6f3cc8a540dad0517d274b5a1e9e636fd8d2c79b5c1d397", size = 7199683, upload-time = "2025-10-21T16:21:06.195Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/91/d3/4b1f2bf16ed52ce0b508161df3a2d186e4935379a159a834cb4a7d687429/grpcio-1.76.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:32483fe2aab2c3794101c2a159070584e5db11d0aa091b2c0ea9c4fc43d0d749", size = 8163109, upload-time = "2025-10-21T16:21:08.498Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5c/61/d9043f95f5f4cf085ac5dd6137b469d41befb04bd80280952ffa2a4c3f12/grpcio-1.76.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:dcfe41187da8992c5f40aa8c5ec086fa3672834d2be57a32384c08d5a05b4c00", size = 7626676, upload-time = "2025-10-21T16:21:10.693Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/36/95/fd9a5152ca02d8881e4dd419cdd790e11805979f499a2e5b96488b85cf27/grpcio-1.76.0-cp311-cp311-win32.whl", hash = "sha256:2107b0c024d1b35f4083f11245c0e23846ae64d02f40b2b226684840260ed054", size = 3997688, upload-time = "2025-10-21T16:21:12.746Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/60/9c/5c359c8d4c9176cfa3c61ecd4efe5affe1f38d9bae81e81ac7186b4c9cc8/grpcio-1.76.0-cp311-cp311-win_amd64.whl", hash = "sha256:522175aba7af9113c48ec10cc471b9b9bd4f6ceb36aeb4544a8e2c80ed9d252d", size = 4709315, upload-time = "2025-10-21T16:21:15.26Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bf/05/8e29121994b8d959ffa0afd28996d452f291b48cfc0875619de0bde2c50c/grpcio-1.76.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:81fd9652b37b36f16138611c7e884eb82e0cec137c40d3ef7c3f9b3ed00f6ed8", size = 5799718, upload-time = "2025-10-21T16:21:17.939Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d9/75/11d0e66b3cdf998c996489581bdad8900db79ebd83513e45c19548f1cba4/grpcio-1.76.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:04bbe1bfe3a68bbfd4e52402ab7d4eb59d72d02647ae2042204326cf4bbad280", size = 11825627, upload-time = "2025-10-21T16:21:20.466Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/28/50/2f0aa0498bc188048f5d9504dcc5c2c24f2eb1a9337cd0fa09a61a2e75f0/grpcio-1.76.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d388087771c837cdb6515539f43b9d4bf0b0f23593a24054ac16f7a960be16f4", size = 6359167, upload-time = "2025-10-21T16:21:23.122Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/66/e5/bbf0bb97d29ede1d59d6588af40018cfc345b17ce979b7b45424628dc8bb/grpcio-1.76.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:9f8f757bebaaea112c00dba718fc0d3260052ce714e25804a03f93f5d1c6cc11", size = 7044267, upload-time = "2025-10-21T16:21:25.995Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f5/86/f6ec2164f743d9609691115ae8ece098c76b894ebe4f7c94a655c6b03e98/grpcio-1.76.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:980a846182ce88c4f2f7e2c22c56aefd515daeb36149d1c897f83cf57999e0b6", size = 6573963, upload-time = "2025-10-21T16:21:28.631Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/60/bc/8d9d0d8505feccfdf38a766d262c71e73639c165b311c9457208b56d92ae/grpcio-1.76.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f92f88e6c033db65a5ae3d97905c8fea9c725b63e28d5a75cb73b49bda5024d8", size = 7164484, upload-time = "2025-10-21T16:21:30.837Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/67/e6/5d6c2fc10b95edf6df9b8f19cf10a34263b7fd48493936fffd5085521292/grpcio-1.76.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4baf3cbe2f0be3289eb68ac8ae771156971848bb8aaff60bad42005539431980", size = 8127777, upload-time = "2025-10-21T16:21:33.577Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3f/c8/dce8ff21c86abe025efe304d9e31fdb0deaaa3b502b6a78141080f206da0/grpcio-1.76.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:615ba64c208aaceb5ec83bfdce7728b80bfeb8be97562944836a7a0a9647d882", size = 7594014, upload-time = "2025-10-21T16:21:41.882Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e0/42/ad28191ebf983a5d0ecef90bab66baa5a6b18f2bfdef9d0a63b1973d9f75/grpcio-1.76.0-cp312-cp312-win32.whl", hash = "sha256:45d59a649a82df5718fd9527ce775fd66d1af35e6d31abdcdc906a49c6822958", size = 3984750, upload-time = "2025-10-21T16:21:44.006Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9e/00/7bd478cbb851c04a48baccaa49b75abaa8e4122f7d86da797500cccdd771/grpcio-1.76.0-cp312-cp312-win_amd64.whl", hash = "sha256:c088e7a90b6017307f423efbb9d1ba97a22aa2170876223f9709e9d1de0b5347", size = 4704003, upload-time = "2025-10-21T16:21:46.244Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fc/ed/71467ab770effc9e8cef5f2e7388beb2be26ed642d567697bb103a790c72/grpcio-1.76.0-cp313-cp313-linux_armv7l.whl", hash = "sha256:26ef06c73eb53267c2b319f43e6634c7556ea37672029241a056629af27c10e2", size = 5807716, upload-time = "2025-10-21T16:21:48.475Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2c/85/c6ed56f9817fab03fa8a111ca91469941fb514e3e3ce6d793cb8f1e1347b/grpcio-1.76.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:45e0111e73f43f735d70786557dc38141185072d7ff8dc1829d6a77ac1471468", size = 11821522, upload-time = "2025-10-21T16:21:51.142Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ac/31/2b8a235ab40c39cbc141ef647f8a6eb7b0028f023015a4842933bc0d6831/grpcio-1.76.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:83d57312a58dcfe2a3a0f9d1389b299438909a02db60e2f2ea2ae2d8034909d3", size = 6362558, upload-time = "2025-10-21T16:21:54.213Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bd/64/9784eab483358e08847498ee56faf8ff6ea8e0a4592568d9f68edc97e9e9/grpcio-1.76.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:3e2a27c89eb9ac3d81ec8835e12414d73536c6e620355d65102503064a4ed6eb", size = 7049990, upload-time = "2025-10-21T16:21:56.476Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2b/94/8c12319a6369434e7a184b987e8e9f3b49a114c489b8315f029e24de4837/grpcio-1.76.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:61f69297cba3950a524f61c7c8ee12e55c486cb5f7db47ff9dcee33da6f0d3ae", size = 6575387, upload-time = "2025-10-21T16:21:59.051Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/15/0f/f12c32b03f731f4a6242f771f63039df182c8b8e2cf8075b245b409259d4/grpcio-1.76.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6a15c17af8839b6801d554263c546c69c4d7718ad4321e3166175b37eaacca77", size = 7166668, upload-time = "2025-10-21T16:22:02.049Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ff/2d/3ec9ce0c2b1d92dd59d1c3264aaec9f0f7c817d6e8ac683b97198a36ed5a/grpcio-1.76.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:25a18e9810fbc7e7f03ec2516addc116a957f8cbb8cbc95ccc80faa072743d03", size = 8124928, upload-time = "2025-10-21T16:22:04.984Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1a/74/fd3317be5672f4856bcdd1a9e7b5e17554692d3db9a3b273879dc02d657d/grpcio-1.76.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:931091142fd8cc14edccc0845a79248bc155425eee9a98b2db2ea4f00a235a42", size = 7589983, upload-time = "2025-10-21T16:22:07.881Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/45/bb/ca038cf420f405971f19821c8c15bcbc875505f6ffadafe9ffd77871dc4c/grpcio-1.76.0-cp313-cp313-win32.whl", hash = "sha256:5e8571632780e08526f118f74170ad8d50fb0a48c23a746bef2a6ebade3abd6f", size = 3984727, upload-time = "2025-10-21T16:22:10.032Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/41/80/84087dc56437ced7cdd4b13d7875e7439a52a261e3ab4e06488ba6173b0a/grpcio-1.76.0-cp313-cp313-win_amd64.whl", hash = "sha256:f9f7bd5faab55f47231ad8dba7787866b69f5e93bc306e3915606779bbfb4ba8", size = 4702799, upload-time = "2025-10-21T16:22:12.709Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b4/46/39adac80de49d678e6e073b70204091e76631e03e94928b9ea4ecf0f6e0e/grpcio-1.76.0-cp314-cp314-linux_armv7l.whl", hash = "sha256:ff8a59ea85a1f2191a0ffcc61298c571bc566332f82e5f5be1b83c9d8e668a62", size = 5808417, upload-time = "2025-10-21T16:22:15.02Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9c/f5/a4531f7fb8b4e2a60b94e39d5d924469b7a6988176b3422487be61fe2998/grpcio-1.76.0-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:06c3d6b076e7b593905d04fdba6a0525711b3466f43b3400266f04ff735de0cd", size = 11828219, upload-time = "2025-10-21T16:22:17.954Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4b/1c/de55d868ed7a8bd6acc6b1d6ddc4aa36d07a9f31d33c912c804adb1b971b/grpcio-1.76.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fd5ef5932f6475c436c4a55e4336ebbe47bd3272be04964a03d316bbf4afbcbc", size = 6367826, upload-time = "2025-10-21T16:22:20.721Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/59/64/99e44c02b5adb0ad13ab3adc89cb33cb54bfa90c74770f2607eea629b86f/grpcio-1.76.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:b331680e46239e090f5b3cead313cc772f6caa7d0fc8de349337563125361a4a", size = 7049550, upload-time = "2025-10-21T16:22:23.637Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/43/28/40a5be3f9a86949b83e7d6a2ad6011d993cbe9b6bd27bea881f61c7788b6/grpcio-1.76.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2229ae655ec4e8999599469559e97630185fdd53ae1e8997d147b7c9b2b72cba", size = 6575564, upload-time = "2025-10-21T16:22:26.016Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4b/a9/1be18e6055b64467440208a8559afac243c66a8b904213af6f392dc2212f/grpcio-1.76.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:490fa6d203992c47c7b9e4a9d39003a0c2bcc1c9aa3c058730884bbbb0ee9f09", size = 7176236, upload-time = "2025-10-21T16:22:28.362Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0f/55/dba05d3fcc151ce6e81327541d2cc8394f442f6b350fead67401661bf041/grpcio-1.76.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:479496325ce554792dba6548fae3df31a72cef7bad71ca2e12b0e58f9b336bfc", size = 8125795, upload-time = "2025-10-21T16:22:31.075Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4a/45/122df922d05655f63930cf42c9e3f72ba20aadb26c100ee105cad4ce4257/grpcio-1.76.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:1c9b93f79f48b03ada57ea24725d83a30284a012ec27eab2cf7e50a550cbbbcc", size = 7592214, upload-time = "2025-10-21T16:22:33.831Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4a/6e/0b899b7f6b66e5af39e377055fb4a6675c9ee28431df5708139df2e93233/grpcio-1.76.0-cp314-cp314-win32.whl", hash = "sha256:747fa73efa9b8b1488a95d0ba1039c8e2dca0f741612d80415b1e1c560febf4e", size = 4062961, upload-time = "2025-10-21T16:22:36.468Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/19/41/0b430b01a2eb38ee887f88c1f07644a1df8e289353b78e82b37ef988fb64/grpcio-1.76.0-cp314-cp314-win_amd64.whl", hash = "sha256:922fa70ba549fce362d2e2871ab542082d66e2aaf0c19480ea453905b01f384e", size = 4834462, upload-time = "2025-10-21T16:22:39.772Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5a/a8/690a085b4d1fe066130de97a87de32c45062cf2ecd218df9675add895550/grpcio-1.78.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:7cc47943d524ee0096f973e1081cb8f4f17a4615f2116882a5f1416e4cfe92b5", size = 5946986, upload-time = "2026-02-06T09:54:34.043Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c7/1b/e5213c5c0ced9d2d92778d30529ad5bb2dcfb6c48c4e2d01b1f302d33d64/grpcio-1.78.0-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:c3f293fdc675ccba4db5a561048cca627b5e7bd1c8a6973ffedabe7d116e22e2", size = 11816533, upload-time = "2026-02-06T09:54:37.04Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/18/37/1ba32dccf0a324cc5ace744c44331e300b000a924bf14840f948c559ede7/grpcio-1.78.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:10a9a644b5dd5aec3b82b5b0b90d41c0fa94c85ef42cb42cf78a23291ddb5e7d", size = 6519964, upload-time = "2026-02-06T09:54:40.268Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ed/f5/c0e178721b818072f2e8b6fde13faaba942406c634009caf065121ce246b/grpcio-1.78.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:4c5533d03a6cbd7f56acfc9cfb44ea64f63d29091e40e44010d34178d392d7eb", size = 7198058, upload-time = "2026-02-06T09:54:42.389Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5b/b2/40d43c91ae9cd667edc960135f9f08e58faa1576dc95af29f66ec912985f/grpcio-1.78.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ff870aebe9a93a85283837801d35cd5f8814fe2ad01e606861a7fb47c762a2b7", size = 6727212, upload-time = "2026-02-06T09:54:44.91Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ed/88/9da42eed498f0efcfcd9156e48ae63c0cde3bea398a16c99fb5198c885b6/grpcio-1.78.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:391e93548644e6b2726f1bb84ed60048d4bcc424ce5e4af0843d28ca0b754fec", size = 7300845, upload-time = "2026-02-06T09:54:47.562Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/23/3f/1c66b7b1b19a8828890e37868411a6e6925df5a9030bfa87ab318f34095d/grpcio-1.78.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:df2c8f3141f7cbd112a6ebbd760290b5849cda01884554f7c67acc14e7b1758a", size = 8284605, upload-time = "2026-02-06T09:54:50.475Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/94/c4/ca1bd87394f7b033e88525384b4d1e269e8424ab441ea2fba1a0c5b50986/grpcio-1.78.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:bd8cb8026e5f5b50498a3c4f196f57f9db344dad829ffae16b82e4fdbaea2813", size = 7726672, upload-time = "2026-02-06T09:54:53.11Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/41/09/f16e487d4cc65ccaf670f6ebdd1a17566b965c74fc3d93999d3b2821e052/grpcio-1.78.0-cp310-cp310-win32.whl", hash = "sha256:f8dff3d9777e5d2703a962ee5c286c239bf0ba173877cc68dc02c17d042e29de", size = 4076715, upload-time = "2026-02-06T09:54:55.549Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2a/32/4ce60d94e242725fd3bcc5673c04502c82a8e87b21ea411a63992dc39f8f/grpcio-1.78.0-cp310-cp310-win_amd64.whl", hash = "sha256:94f95cf5d532d0e717eed4fc1810e8e6eded04621342ec54c89a7c2f14b581bf", size = 4799157, upload-time = "2026-02-06T09:54:59.838Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/86/c7/d0b780a29b0837bf4ca9580904dfb275c1fc321ded7897d620af7047ec57/grpcio-1.78.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:2777b783f6c13b92bd7b716667452c329eefd646bfb3f2e9dabea2e05dbd34f6", size = 5951525, upload-time = "2026-02-06T09:55:01.989Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c5/b1/96920bf2ee61df85a9503cb6f733fe711c0ff321a5a697d791b075673281/grpcio-1.78.0-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:9dca934f24c732750389ce49d638069c3892ad065df86cb465b3fa3012b70c9e", size = 11830418, upload-time = "2026-02-06T09:55:04.462Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/83/0c/7c1528f098aeb75a97de2bae18c530f56959fb7ad6c882db45d9884d6edc/grpcio-1.78.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:459ab414b35f4496138d0ecd735fed26f1318af5e52cb1efbc82a09f0d5aa911", size = 6524477, upload-time = "2026-02-06T09:55:07.111Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8d/52/e7c1f3688f949058e19a011c4e0dec973da3d0ae5e033909677f967ae1f4/grpcio-1.78.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:082653eecbdf290e6e3e2c276ab2c54b9e7c299e07f4221872380312d8cf395e", size = 7198266, upload-time = "2026-02-06T09:55:10.016Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e5/61/8ac32517c1e856677282c34f2e7812d6c328fa02b8f4067ab80e77fdc9c9/grpcio-1.78.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:85f93781028ec63f383f6bc90db785a016319c561cc11151fbb7b34e0d012303", size = 6730552, upload-time = "2026-02-06T09:55:12.207Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bd/98/b8ee0158199250220734f620b12e4a345955ac7329cfd908d0bf0fda77f0/grpcio-1.78.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f12857d24d98441af6a1d5c87442d624411db486f7ba12550b07788f74b67b04", size = 7304296, upload-time = "2026-02-06T09:55:15.044Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bd/0f/7b72762e0d8840b58032a56fdbd02b78fc645b9fa993d71abf04edbc54f4/grpcio-1.78.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5397fff416b79e4b284959642a4e95ac4b0f1ece82c9993658e0e477d40551ec", size = 8288298, upload-time = "2026-02-06T09:55:17.276Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/24/ae/ae4ce56bc5bb5caa3a486d60f5f6083ac3469228faa734362487176c15c5/grpcio-1.78.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:fbe6e89c7ffb48518384068321621b2a69cab509f58e40e4399fdd378fa6d074", size = 7730953, upload-time = "2026-02-06T09:55:19.545Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b5/6e/8052e3a28eb6a820c372b2eb4b5e32d195c661e137d3eca94d534a4cfd8a/grpcio-1.78.0-cp311-cp311-win32.whl", hash = "sha256:6092beabe1966a3229f599d7088b38dfc8ffa1608b5b5cdda31e591e6500f856", size = 4076503, upload-time = "2026-02-06T09:55:21.521Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/08/62/f22c98c5265dfad327251fa2f840b591b1df5f5e15d88b19c18c86965b27/grpcio-1.78.0-cp311-cp311-win_amd64.whl", hash = "sha256:1afa62af6e23f88629f2b29ec9e52ec7c65a7176c1e0a83292b93c76ca882558", size = 4799767, upload-time = "2026-02-06T09:55:24.107Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4e/f4/7384ed0178203d6074446b3c4f46c90a22ddf7ae0b3aee521627f54cfc2a/grpcio-1.78.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:f9ab915a267fc47c7e88c387a3a28325b58c898e23d4995f765728f4e3dedb97", size = 5913985, upload-time = "2026-02-06T09:55:26.832Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/81/ed/be1caa25f06594463f685b3790b320f18aea49b33166f4141bfdc2bfb236/grpcio-1.78.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:3f8904a8165ab21e07e58bf3e30a73f4dffc7a1e0dbc32d51c61b5360d26f43e", size = 11811853, upload-time = "2026-02-06T09:55:29.224Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/24/a7/f06d151afc4e64b7e3cc3e872d331d011c279aaab02831e40a81c691fb65/grpcio-1.78.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:859b13906ce098c0b493af92142ad051bf64c7870fa58a123911c88606714996", size = 6475766, upload-time = "2026-02-06T09:55:31.825Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8a/a8/4482922da832ec0082d0f2cc3a10976d84a7424707f25780b82814aafc0a/grpcio-1.78.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:b2342d87af32790f934a79c3112641e7b27d63c261b8b4395350dad43eff1dc7", size = 7170027, upload-time = "2026-02-06T09:55:34.7Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/54/bf/f4a3b9693e35d25b24b0b39fa46d7d8a3c439e0a3036c3451764678fec20/grpcio-1.78.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:12a771591ae40bc65ba67048fa52ef4f0e6db8279e595fd349f9dfddeef571f9", size = 6690766, upload-time = "2026-02-06T09:55:36.902Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c7/b9/521875265cc99fe5ad4c5a17010018085cae2810a928bf15ebe7d8bcd9cc/grpcio-1.78.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:185dea0d5260cbb2d224c507bf2a5444d5abbb1fa3594c1ed7e4c709d5eb8383", size = 7266161, upload-time = "2026-02-06T09:55:39.824Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/05/86/296a82844fd40a4ad4a95f100b55044b4f817dece732bf686aea1a284147/grpcio-1.78.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:51b13f9aed9d59ee389ad666b8c2214cc87b5de258fa712f9ab05f922e3896c6", size = 8253303, upload-time = "2026-02-06T09:55:42.353Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f3/e4/ea3c0caf5468537f27ad5aab92b681ed7cc0ef5f8c9196d3fd42c8c2286b/grpcio-1.78.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fd5f135b1bd58ab088930b3c613455796dfa0393626a6972663ccdda5b4ac6ce", size = 7698222, upload-time = "2026-02-06T09:55:44.629Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d7/47/7f05f81e4bb6b831e93271fb12fd52ba7b319b5402cbc101d588f435df00/grpcio-1.78.0-cp312-cp312-win32.whl", hash = "sha256:94309f498bcc07e5a7d16089ab984d42ad96af1d94b5a4eb966a266d9fcabf68", size = 4066123, upload-time = "2026-02-06T09:55:47.644Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ad/e7/d6914822c88aa2974dbbd10903d801a28a19ce9cd8bad7e694cbbcf61528/grpcio-1.78.0-cp312-cp312-win_amd64.whl", hash = "sha256:9566fe4ababbb2610c39190791e5b829869351d14369603702e890ef3ad2d06e", size = 4797657, upload-time = "2026-02-06T09:55:49.86Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/05/a9/8f75894993895f361ed8636cd9237f4ab39ef87fd30db17467235ed1c045/grpcio-1.78.0-cp313-cp313-linux_armv7l.whl", hash = "sha256:ce3a90455492bf8bfa38e56fbbe1dbd4f872a3d8eeaf7337dc3b1c8aa28c271b", size = 5920143, upload-time = "2026-02-06T09:55:52.035Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/55/06/0b78408e938ac424100100fd081189451b472236e8a3a1f6500390dc4954/grpcio-1.78.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:2bf5e2e163b356978b23652c4818ce4759d40f4712ee9ec5a83c4be6f8c23a3a", size = 11803926, upload-time = "2026-02-06T09:55:55.494Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/88/93/b59fe7832ff6ae3c78b813ea43dac60e295fa03606d14d89d2e0ec29f4f3/grpcio-1.78.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8f2ac84905d12918e4e55a16da17939eb63e433dc11b677267c35568aa63fc84", size = 6478628, upload-time = "2026-02-06T09:55:58.533Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ed/df/e67e3734527f9926b7d9c0dde6cd998d1d26850c3ed8eeec81297967ac67/grpcio-1.78.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:b58f37edab4a3881bc6c9bca52670610e0c9ca14e2ea3cf9debf185b870457fb", size = 7173574, upload-time = "2026-02-06T09:56:01.786Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a6/62/cc03fffb07bfba982a9ec097b164e8835546980aec25ecfa5f9c1a47e022/grpcio-1.78.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:735e38e176a88ce41840c21bb49098ab66177c64c82426e24e0082500cc68af5", size = 6692639, upload-time = "2026-02-06T09:56:04.529Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bf/9a/289c32e301b85bdb67d7ec68b752155e674ee3ba2173a1858f118e399ef3/grpcio-1.78.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2045397e63a7a0ee7957c25f7dbb36ddc110e0cfb418403d110c0a7a68a844e9", size = 7268838, upload-time = "2026-02-06T09:56:08.397Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0e/79/1be93f32add280461fa4773880196572563e9c8510861ac2da0ea0f892b6/grpcio-1.78.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a9f136fbafe7ccf4ac7e8e0c28b31066e810be52d6e344ef954a3a70234e1702", size = 8251878, upload-time = "2026-02-06T09:56:10.914Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/65/65/793f8e95296ab92e4164593674ae6291b204bb5f67f9d4a711489cd30ffa/grpcio-1.78.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:748b6138585379c737adc08aeffd21222abbda1a86a0dca2a39682feb9196c20", size = 7695412, upload-time = "2026-02-06T09:56:13.593Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1c/9f/1e233fe697ecc82845942c2822ed06bb522e70d6771c28d5528e4c50f6a4/grpcio-1.78.0-cp313-cp313-win32.whl", hash = "sha256:271c73e6e5676afe4fc52907686670c7cea22ab2310b76a59b678403ed40d670", size = 4064899, upload-time = "2026-02-06T09:56:15.601Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4d/27/d86b89e36de8a951501fb06a0f38df19853210f341d0b28f83f4aa0ffa08/grpcio-1.78.0-cp313-cp313-win_amd64.whl", hash = "sha256:f2d4e43ee362adfc05994ed479334d5a451ab7bc3f3fee1b796b8ca66895acb4", size = 4797393, upload-time = "2026-02-06T09:56:17.882Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/29/f2/b56e43e3c968bfe822fa6ce5bca10d5c723aa40875b48791ce1029bb78c7/grpcio-1.78.0-cp314-cp314-linux_armv7l.whl", hash = "sha256:e87cbc002b6f440482b3519e36e1313eb5443e9e9e73d6a52d43bd2004fcfd8e", size = 5920591, upload-time = "2026-02-06T09:56:20.758Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5d/81/1f3b65bd30c334167bfa8b0d23300a44e2725ce39bba5b76a2460d85f745/grpcio-1.78.0-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:c41bc64626db62e72afec66b0c8a0da76491510015417c127bfc53b2fe6d7f7f", size = 11813685, upload-time = "2026-02-06T09:56:24.315Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0e/1c/bbe2f8216a5bd3036119c544d63c2e592bdf4a8ec6e4a1867592f4586b26/grpcio-1.78.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8dfffba826efcf366b1e3ccc37e67afe676f290e13a3b48d31a46739f80a8724", size = 6487803, upload-time = "2026-02-06T09:56:27.367Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/16/5c/a6b2419723ea7ddce6308259a55e8e7593d88464ce8db9f4aa857aba96fa/grpcio-1.78.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:74be1268d1439eaaf552c698cdb11cd594f0c49295ae6bb72c34ee31abbe611b", size = 7173206, upload-time = "2026-02-06T09:56:29.876Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/df/1e/b8801345629a415ea7e26c83d75eb5dbe91b07ffe5210cc517348a8d4218/grpcio-1.78.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:be63c88b32e6c0f1429f1398ca5c09bc64b0d80950c8bb7807d7d7fb36fb84c7", size = 6693826, upload-time = "2026-02-06T09:56:32.305Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/34/84/0de28eac0377742679a510784f049738a80424b17287739fc47d63c2439e/grpcio-1.78.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:3c586ac70e855c721bda8f548d38c3ca66ac791dc49b66a8281a1f99db85e452", size = 7277897, upload-time = "2026-02-06T09:56:34.915Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ca/9c/ad8685cfe20559a9edb66f735afdcb2b7d3de69b13666fdfc542e1916ebd/grpcio-1.78.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:35eb275bf1751d2ffbd8f57cdbc46058e857cf3971041521b78b7db94bdaf127", size = 8252404, upload-time = "2026-02-06T09:56:37.553Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3c/05/33a7a4985586f27e1de4803887c417ec7ced145ebd069bc38a9607059e2b/grpcio-1.78.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:207db540302c884b8848036b80db352a832b99dfdf41db1eb554c2c2c7800f65", size = 7696837, upload-time = "2026-02-06T09:56:40.173Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/73/77/7382241caf88729b106e49e7d18e3116216c778e6a7e833826eb96de22f7/grpcio-1.78.0-cp314-cp314-win32.whl", hash = "sha256:57bab6deef2f4f1ca76cc04565df38dc5713ae6c17de690721bdf30cb1e0545c", size = 4142439, upload-time = "2026-02-06T09:56:43.258Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/48/b2/b096ccce418882fbfda4f7496f9357aaa9a5af1896a9a7f60d9f2b275a06/grpcio-1.78.0-cp314-cp314-win_amd64.whl", hash = "sha256:dce09d6116df20a96acfdbf85e4866258c3758180e8c49845d6ba8248b6d0bbb", size = 4929852, upload-time = "2026-02-06T09:56:45.885Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2734,7 +2729,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "huggingface-hub"
|
||||
version = "1.4.0"
|
||||
version = "1.4.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "filelock", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
@@ -2748,9 +2743,9 @@ dependencies = [
|
||||
{ name = "typer-slim", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
{ name = "typing-extensions", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d9/0e/e73927175162b8a4702b9f59268860f441fbe037c3960b1b6791eeb1deb7/huggingface_hub-1.4.0.tar.gz", hash = "sha256:dd8ca29409be10f544b624265f7ffe13a1a5c3f049f493b5dc9816ef3c6bd57b", size = 641608, upload-time = "2026-02-04T13:48:55.341Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/c4/fc/eb9bc06130e8bbda6a616e1b80a7aa127681c448d6b49806f61db2670b61/huggingface_hub-1.4.1.tar.gz", hash = "sha256:b41131ec35e631e7383ab26d6146b8d8972abc8b6309b963b306fbcca87f5ed5", size = 642156, upload-time = "2026-02-06T09:20:03.013Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/3f/74/f0fb3a54fbca7c0aeff85f41d93b90ca3f6a36d918459401a3890763c54b/huggingface_hub-1.4.0-py3-none-any.whl", hash = "sha256:49d380ffddb31d9d4b6acc0792691f8fa077e1ed51980ed42c7abca62ec1b3b6", size = 553202, upload-time = "2026-02-04T13:48:53.545Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d5/ae/2f6d96b4e6c5478d87d606a1934b5d436c4a2bce6bb7c6fdece891c128e3/huggingface_hub-1.4.1-py3-none-any.whl", hash = "sha256:9931d075fb7a79af5abc487106414ec5fba2c0ae86104c0c62fd6cae38873d18", size = 553326, upload-time = "2026-02-06T09:20:00.728Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4032,7 +4027,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "openai"
|
||||
version = "2.16.0"
|
||||
version = "2.17.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "anyio", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
@@ -4044,9 +4039,9 @@ dependencies = [
|
||||
{ name = "tqdm", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
{ name = "typing-extensions", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b1/6c/e4c964fcf1d527fdf4739e7cc940c60075a4114d50d03871d5d5b1e13a88/openai-2.16.0.tar.gz", hash = "sha256:42eaa22ca0d8ded4367a77374104d7a2feafee5bd60a107c3c11b5243a11cd12", size = 629649, upload-time = "2026-01-27T23:28:02.579Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/9c/a2/677f22c4b487effb8a09439fb6134034b5f0a39ca27df8b95fac23a93720/openai-2.17.0.tar.gz", hash = "sha256:47224b74bd20f30c6b0a6a329505243cb2f26d5cf84d9f8d0825ff8b35e9c999", size = 631445, upload-time = "2026-02-05T16:27:40.953Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/16/83/0315bf2cfd75a2ce8a7e54188e9456c60cec6c0cf66728ed07bd9859ff26/openai-2.16.0-py3-none-any.whl", hash = "sha256:5f46643a8f42899a84e80c38838135d7038e7718333ce61396994f887b09a59b", size = 1068612, upload-time = "2026-01-27T23:28:00.356Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/44/97/284535aa75e6e84ab388248b5a323fc296b1f70530130dee37f7f4fbe856/openai-2.17.0-py3-none-any.whl", hash = "sha256:4f393fd886ca35e113aac7ff239bcd578b81d8f104f5aedc7d3693eb2af1d338", size = 1069524, upload-time = "2026-02-05T16:27:38.941Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4128,7 +4123,7 @@ source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "googleapis-common-protos", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
{ name = "grpcio", version = "1.67.1", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version < '3.14' and sys_platform == 'darwin') or (python_full_version < '3.14' and sys_platform == 'linux') or (python_full_version < '3.14' and sys_platform == 'win32')" },
|
||||
{ name = "grpcio", version = "1.76.0", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.14' and sys_platform == 'darwin') or (python_full_version >= '3.14' and sys_platform == 'linux') or (python_full_version >= '3.14' and sys_platform == 'win32')" },
|
||||
{ name = "grpcio", version = "1.78.0", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.14' and sys_platform == 'darwin') or (python_full_version >= '3.14' and sys_platform == 'linux') or (python_full_version >= '3.14' and sys_platform == 'win32')" },
|
||||
{ name = "opentelemetry-api", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
{ name = "opentelemetry-exporter-otlp-proto-common", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
{ name = "opentelemetry-proto", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
@@ -4702,7 +4697,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "posthog"
|
||||
version = "7.8.2"
|
||||
version = "7.8.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "backoff", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
@@ -4712,9 +4707,9 @@ dependencies = [
|
||||
{ name = "six", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
{ name = "typing-extensions", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/9c/5c/35edae017d92b2f7625a2b3be45dc36c8e6e14acbe5dbeeaa5a20a932ccf/posthog-7.8.2.tar.gz", hash = "sha256:d36472763750d8da60ebc3cbf6349a91222ba6a43dfdbdcdb6a9f03796514239", size = 166995, upload-time = "2026-02-04T15:10:31.251Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d1/ad/2f116cd9b83dc83ece4328a4efe0bcb80e5c2993837f89a788467d261da8/posthog-7.8.3.tar.gz", hash = "sha256:2b85e818bf818ac2768a890b772b7c12d4f909797226acd9327d66a319dbcf83", size = 167083, upload-time = "2026-02-06T13:16:22.938Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/53/d9/8f2374c559a6e50d2e92601b42540aae296f6e0a2066e913fed8bd603f23/posthog-7.8.2-py3-none-any.whl", hash = "sha256:d3fa69f7e15830a8e19cd4de4e7b40982838efa5d0f448133be3115bd556feef", size = 192440, upload-time = "2026-02-04T15:10:29.767Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e7/e5/5a4b060cbb9aa9defb8bfd55d15899b3146fece14147f4d66be80e81955a/posthog-7.8.3-py3-none-any.whl", hash = "sha256:1840796e4f7e14dd91ec5fdeb939712c3383fe9e758cfcdeb0317d8f30f7b901", size = 192528, upload-time = "2026-02-06T13:16:21.385Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4722,8 +4717,8 @@ name = "powerfx"
|
||||
version = "0.0.34"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "cffi", marker = "(python_full_version < '3.14' and sys_platform == 'darwin') or (python_full_version < '3.14' and sys_platform == 'linux') or (python_full_version < '3.14' and sys_platform == 'win32')" },
|
||||
{ name = "pythonnet", marker = "(python_full_version < '3.14' and sys_platform == 'darwin') or (python_full_version < '3.14' and sys_platform == 'linux') or (python_full_version < '3.14' and sys_platform == 'win32')" },
|
||||
{ name = "cffi", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
{ name = "pythonnet", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/9f/fb/6c4bf87e0c74ca1c563921ce89ca1c5785b7576bca932f7255cdf81082a7/powerfx-0.0.34.tar.gz", hash = "sha256:956992e7afd272657ed16d80f4cad24ec95d9e4a79fb9dfa4a068a09e136af32", size = 3237555, upload-time = "2025-12-22T15:50:59.682Z" }
|
||||
wheels = [
|
||||
@@ -5390,7 +5385,7 @@ name = "pythonnet"
|
||||
version = "3.0.5"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "clr-loader", marker = "(python_full_version < '3.14' and sys_platform == 'darwin') or (python_full_version < '3.14' and sys_platform == 'linux') or (python_full_version < '3.14' and sys_platform == 'win32')" },
|
||||
{ name = "clr-loader", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/9a/d6/1afd75edd932306ae9bd2c2d961d603dc2b52fcec51b04afea464f1f6646/pythonnet-3.0.5.tar.gz", hash = "sha256:48e43ca463941b3608b32b4e236db92d8d40db4c58a75ace902985f76dac21cf", size = 239212, upload-time = "2024-12-13T08:30:44.393Z" }
|
||||
wheels = [
|
||||
@@ -5498,7 +5493,7 @@ version = "1.16.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "grpcio", version = "1.67.1", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version < '3.14' and sys_platform == 'darwin') or (python_full_version < '3.14' and sys_platform == 'linux') or (python_full_version < '3.14' and sys_platform == 'win32')" },
|
||||
{ name = "grpcio", version = "1.76.0", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.14' and sys_platform == 'darwin') or (python_full_version >= '3.14' and sys_platform == 'linux') or (python_full_version >= '3.14' and sys_platform == 'win32')" },
|
||||
{ name = "grpcio", version = "1.78.0", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.14' and sys_platform == 'darwin') or (python_full_version >= '3.14' and sys_platform == 'linux') or (python_full_version >= '3.14' and sys_platform == 'win32')" },
|
||||
{ name = "httpx", extra = ["http2"], marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||
{ name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version < '3.11' and sys_platform == 'darwin') or (python_full_version < '3.11' and sys_platform == 'linux') or (python_full_version < '3.11' and sys_platform == 'win32')" },
|
||||
{ name = "numpy", version = "2.4.2", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.11' and sys_platform == 'darwin') or (python_full_version >= '3.11' and sys_platform == 'linux') or (python_full_version >= '3.11' and sys_platform == 'win32')" },
|
||||
@@ -6830,28 +6825,27 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "uv"
|
||||
version = "0.9.30"
|
||||
version = "0.10.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/4e/a0/63cea38fe839fb89592728b91928ee6d15705f1376a7940fee5bbc77fea0/uv-0.9.30.tar.gz", hash = "sha256:03ebd4b22769e0a8d825fa09d038e31cbab5d3d48edf755971cb0cec7920ab95", size = 3846526, upload-time = "2026-02-04T21:45:37.58Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/09/36/f7fe4de0ad81234ac43938fe39c6ba84595c6b3a1868d786a4d7ad19e670/uv-0.10.0.tar.gz", hash = "sha256:ad01dd614a4bb8eb732da31ade41447026427397c5ad171cc98bd59579ef57ea", size = 3854103, upload-time = "2026-02-05T20:57:55.248Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/a3/3c/71be72f125f0035348b415468559cc3b335ec219376d17a3d242d2bd9b23/uv-0.9.30-py3-none-linux_armv6l.whl", hash = "sha256:a5467dddae1cd5f4e093f433c0f0d9a0df679b92696273485ec91bbb5a8620e6", size = 21927585, upload-time = "2026-02-04T21:46:14.935Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0f/fd/8070b5423a77d4058d14e48a970aa075762bbff4c812dda3bb3171543e44/uv-0.9.30-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6ec38ae29aa83a37c6e50331707eac8ecc90cf2b356d60ea6382a94de14973be", size = 21050392, upload-time = "2026-02-04T21:45:55.649Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/42/5f/3ccc9415ef62969ed01829572338ea7bdf4c5cf1ffb9edc1f8cb91b571f3/uv-0.9.30-py3-none-macosx_11_0_arm64.whl", hash = "sha256:777ecd117cf1d8d6bb07de8c9b7f6c5f3e802415b926cf059d3423699732eb8c", size = 19817085, upload-time = "2026-02-04T21:45:40.881Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8b/3f/76b44e2a224f4c4a8816fc92686ef6d4c2656bc5fc9d4f673816162c994d/uv-0.9.30-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:93049ba3c41fa2cc38b467cb78ef61b2ddedca34b6be924a5481d7750c8111c6", size = 21620537, upload-time = "2026-02-04T21:45:47.846Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/60/2a/50f7e8c6d532af8dd327f77bdc75ce4652322ac34f5e29f79a8e04ea3cc8/uv-0.9.30-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.musllinux_1_1_armv7l.whl", hash = "sha256:f295604fee71224ebe2685a0f1f4ff7a45c77211a60bd57133a4a02056d7c775", size = 21550855, upload-time = "2026-02-04T21:46:26.269Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0e/10/f823d4af1125fae559194b356757dc7d4a8ac79d10d11db32c2d4c9e2f63/uv-0.9.30-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2faf84e1f3b6fc347a34c07f1291d11acf000b0dd537a61d541020f22b17ccd9", size = 21516576, upload-time = "2026-02-04T21:46:03.494Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/91/f3/64b02db11f38226ed34458c7fbdb6f16b6d4fd951de24c3e51acf02b30f8/uv-0.9.30-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0b3b3700ecf64a09a07fd04d10ec35f0973ec15595d38bbafaa0318252f7e31f", size = 22718097, upload-time = "2026-02-04T21:45:51.875Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/28/21/a48d1872260f04a68bb5177b0f62ddef62ab892d544ed1922f2d19fd2b00/uv-0.9.30-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:b176fc2937937dd81820445cb7e7e2e3cd1009a003c512f55fa0ae10064c8a38", size = 24107844, upload-time = "2026-02-04T21:46:19.032Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1c/c6/d7e5559bfe1ab7a215a7ad49c58c8a5701728f2473f7f436ef00b4664e88/uv-0.9.30-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:180e8070b8c438b9a3fb3fde8a37b365f85c3c06e17090f555dc68fdebd73333", size = 23685378, upload-time = "2026-02-04T21:46:07.166Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a8/bf/b937bbd50d14c6286e353fd4c7bdc09b75f6b3a26bd4e2f3357e99891f28/uv-0.9.30-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4125a9aa2a751e1589728f6365cfe204d1be41499148ead44b6180b7df576f27", size = 22848471, upload-time = "2026-02-04T21:45:18.728Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6a/57/12a67c569e69b71508ad669adad266221f0b1d374be88eaf60109f551354/uv-0.9.30-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4366dd740ac9ad3ec50a58868a955b032493bb7d7e6ed368289e6ced8bbc70f3", size = 22774258, upload-time = "2026-02-04T21:46:10.798Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3d/b8/a26cc64685dddb9fb13f14c3dc1b12009f800083405f854f84eb8c86b494/uv-0.9.30-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:33e50f208e01a0c20b3c5f87d453356a5cbcfd68f19e47a28b274cd45618881c", size = 21699573, upload-time = "2026-02-04T21:45:44.365Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c8/59/995af0c5f0740f8acb30468e720269e720352df1d204e82c2d52d9a8c586/uv-0.9.30-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:5e7a6fa7a3549ce893cf91fe4b06629e3e594fc1dca0a6050aba2ea08722e964", size = 22460799, upload-time = "2026-02-04T21:45:26.658Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bb/0b/6affe815ecbaebf38b35d6230fbed2f44708c67d5dd5720f81f2ec8f96ff/uv-0.9.30-py3-none-musllinux_1_1_i686.whl", hash = "sha256:62d7e408d41e392b55ffa4cf9b07f7bbd8b04e0929258a42e19716c221ac0590", size = 22001777, upload-time = "2026-02-04T21:45:34.656Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f3/b6/47a515171c891b0d29f8e90c8a1c0e233e4813c95a011799605cfe04c74c/uv-0.9.30-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:6dc65c24f5b9cdc78300fa6631368d3106e260bbffa66fb1e831a318374da2df", size = 22968416, upload-time = "2026-02-04T21:45:22.863Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3d/3a/c1df8615385138bb7c43342586431ca32b77466c5fb086ac0ed14ab6ca28/uv-0.9.30-py3-none-win32.whl", hash = "sha256:74e94c65d578657db94a753d41763d0364e5468ec0d368fb9ac8ddab0fb6e21f", size = 20889232, upload-time = "2026-02-04T21:46:22.617Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f2/a8/e8761c8414a880d70223723946576069e042765475f73b4436d78b865dba/uv-0.9.30-py3-none-win_amd64.whl", hash = "sha256:88a2190810684830a1ba4bb1cf8fb06b0308988a1589559404259d295260891c", size = 23432208, upload-time = "2026-02-04T21:45:30.85Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/49/e8/6f2ebab941ec559f97110bbbae1279cd0333d6bc352b55f6fa3fefb020d9/uv-0.9.30-py3-none-win_arm64.whl", hash = "sha256:7fde83a5b5ea027315223c33c30a1ab2f2186910b933d091a1b7652da879e230", size = 21887273, upload-time = "2026-02-04T21:45:59.787Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f4/69/33fb64aee6ba138b1aaf957e20778e94a8c23732e41cdf68e6176aa2cf4e/uv-0.10.0-py3-none-linux_armv6l.whl", hash = "sha256:38dc0ccbda6377eb94095688c38e5001b8b40dfce14b9654949c1f0b6aa889df", size = 21984662, upload-time = "2026-02-05T20:57:19.076Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1a/5a/e3ff8a98cfbabc5c2d09bf304d2d9d2d7b2e7d60744241ac5ed762015e5c/uv-0.10.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:a165582c1447691109d49d09dccb065d2a23852ff42bf77824ff169909aa85da", size = 21057249, upload-time = "2026-02-05T20:56:48.921Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ee/77/ec8f24f8d0f19c4fda0718d917bb78b9e6f02a4e1963b401f1c4f4614a54/uv-0.10.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:aefea608971f4f23ac3dac2006afb8eb2b2c1a2514f5fee1fac18e6c45fd70c4", size = 19827174, upload-time = "2026-02-05T20:57:10.581Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c6/7e/09b38b93208906728f591f66185a425be3acdb97c448460137d0e6ecb30a/uv-0.10.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:d4b621bcc5d0139502789dc299bae8bf55356d07b95cb4e57e50e2afcc5f43e1", size = 21629522, upload-time = "2026-02-05T20:57:29.959Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/89/f3/48d92c90e869331306979efaa29a44c3e7e8376ae343edc729df0d534dfb/uv-0.10.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.musllinux_1_1_armv7l.whl", hash = "sha256:b4bea728a6b64826d0091f95f28de06dd2dc786384b3d336a90297f123b4da0e", size = 21614812, upload-time = "2026-02-05T20:56:58.103Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ff/43/d0dedfcd4fe6e36cabdbeeb43425cd788604db9d48425e7b659d0f7ba112/uv-0.10.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bc0cc2a4bcf9efbff9a57e2aed21c2d4b5a7ec2cc0096e0c33d7b53da17f6a3b", size = 21577072, upload-time = "2026-02-05T20:57:45.455Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c5/90/b8c9320fd8d86f356e37505a02aa2978ed28f9c63b59f15933e98bce97e5/uv-0.10.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:070ca2f0e8c67ca9a8f70ce403c956b7ed9d51e0c2e9dbbcc4efa5e0a2483f79", size = 22829664, upload-time = "2026-02-05T20:57:22.689Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/56/9c/2c36b30b05c74b2af0e663e0e68f1d10b91a02a145e19b6774c121120c0b/uv-0.10.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8070c66149c06f9b39092a06f593a2241345ea2b1d42badc6f884c2cc089a1b1", size = 23705815, upload-time = "2026-02-05T20:57:37.604Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6c/a1/8c7fdb14ab72e26ca872e07306e496a6b8cf42353f9bf6251b015be7f535/uv-0.10.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3db1d5390b3a624de672d7b0f9c9d8197693f3b2d3d9c4d9e34686dcbc34197a", size = 22890313, upload-time = "2026-02-05T20:57:26.35Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f3/f8/5c152350b1a6d0af019801f91a1bdeac854c33deb36275f6c934f0113cb5/uv-0.10.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82b46db718763bf742e986ebbc7a30ca33648957a0dcad34382970b992f5e900", size = 22769440, upload-time = "2026-02-05T20:56:53.859Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/87/44/980e5399c6f4943b81754be9b7deb87bd56430e035c507984e17267d6a97/uv-0.10.0-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:eb95d28590edd73b8fdd80c27d699c45c52f8305170c6a90b830caf7f36670a4", size = 21695296, upload-time = "2026-02-05T20:57:06.732Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ae/e7/f44ad40275be2087b3910df4678ed62cf0c82eeb3375c4a35037a79747db/uv-0.10.0-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:5871eef5046a81df3f1636a3d2b4ccac749c23c7f4d3a4bae5496cb2876a1814", size = 22424291, upload-time = "2026-02-05T20:57:49.067Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c2/81/31c0c0a8673140756e71a1112bf8f0fcbb48a4cf4587a7937f5bd55256b6/uv-0.10.0-py3-none-musllinux_1_1_i686.whl", hash = "sha256:1af0ec125a07edb434dfaa98969f6184c1313dbec2860c3c5ce2d533b257132a", size = 22109479, upload-time = "2026-02-05T20:57:02.258Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d7/d1/2eb51bc233bad3d13ad64a0c280fd4d1ebebf5c2939b3900a46670fa2b91/uv-0.10.0-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:45909b9a734250da05b10101e0a067e01ffa2d94bbb07de4b501e3cee4ae0ff3", size = 22972087, upload-time = "2026-02-05T20:57:52.847Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d2/f7/49987207b87b5c21e1f0e81c52892813e8cdf7e318b6373d6585773ebcdd/uv-0.10.0-py3-none-win32.whl", hash = "sha256:d5498851b1f07aa9c9af75578b2029a11743cb933d741f84dcbb43109a968c29", size = 20896746, upload-time = "2026-02-05T20:57:33.426Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/80/b2/1370049596c6ff7fa1fe22fccf86a093982eac81017b8c8aff541d7263b2/uv-0.10.0-py3-none-win_amd64.whl", hash = "sha256:edd469425cd62bcd8c8cc0226c5f9043a94e37ed869da8268c80fdbfd3e5015e", size = 23433041, upload-time = "2026-02-05T20:57:41.41Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e3/76/1034c46244feafec2c274ac52b094f35d47c94cdb11461c24cf4be8a0c0c/uv-0.10.0-py3-none-win_arm64.whl", hash = "sha256:e90c509749b3422eebb54057434b7119892330d133b9690a88f8a6b0f3116be3", size = 21880261, upload-time = "2026-02-05T20:57:14.724Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
Reference in New Issue
Block a user