From 3df90c5305eeca8a260c1966916c5f1a05de4bd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radek=20Je=C5=BEek?= Date: Wed, 11 Feb 2026 16:24:14 +0100 Subject: [PATCH 1/6] chore(sdk): refactor dependency management MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Radek Ježek --- apps/agentstack-cli/uv.lock | 2 +- apps/agentstack-sdk-py/pyproject.toml | 2 +- .../src/agentstack_sdk/a2a/extensions/base.py | 48 ++- .../a2a/extensions/services/mcp.py | 16 +- .../a2a/extensions/services/platform.py | 15 +- .../src/agentstack_sdk/a2a/types.py | 2 +- .../src/agentstack_sdk/server/agent.py | 368 +++++++++++------- .../src/agentstack_sdk/server/app.py | 29 +- .../src/agentstack_sdk/server/constants.py | 9 +- .../src/agentstack_sdk/server/context.py | 7 +- .../src/agentstack_sdk/server/dependencies.py | 16 +- .../middleware/platform_auth_backend.py | 26 +- .../src/agentstack_sdk/server/server.py | 61 ++- .../server/store/context_store.py | 12 +- .../server/store/memory_context_store.py | 3 +- .../server/store/platform_context_store.py | 45 +-- .../src/agentstack_sdk/types.py | 11 +- apps/agentstack-server/uv.lock | 2 +- 18 files changed, 391 insertions(+), 283 deletions(-) diff --git a/apps/agentstack-cli/uv.lock b/apps/agentstack-cli/uv.lock index 323d4d3f92..5be9055cf2 100644 --- a/apps/agentstack-cli/uv.lock +++ b/apps/agentstack-cli/uv.lock @@ -141,7 +141,7 @@ dev = [ { name = "pytest", specifier = ">=8.4.1" }, { name = "pytest-asyncio", specifier = ">=1.1.0" }, { name = "pytest-httpx", specifier = ">=0.35.0" }, - { name = "ruff", specifier = ">=0.12.3" }, + { name = "ruff", specifier = ">=0.15.0" }, ] [[package]] diff --git a/apps/agentstack-sdk-py/pyproject.toml b/apps/agentstack-sdk-py/pyproject.toml index 5d4fdf7242..6cea7491dc 100644 --- a/apps/agentstack-sdk-py/pyproject.toml +++ b/apps/agentstack-sdk-py/pyproject.toml @@ -37,7 +37,7 @@ dev = [ "pytest>=8.4.1", "pytest-asyncio>=1.1.0", "pytest-httpx>=0.35.0", - "ruff>=0.12.3", + "ruff>=0.15.0", ] [build-system] diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/base.py b/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/base.py index b5af3f52a2..f77d95288f 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/base.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/base.py @@ -8,7 +8,9 @@ import typing from collections.abc import AsyncIterator from contextlib import asynccontextmanager +from contextvars import ContextVar from types import NoneType +from typing import Self import pydantic from a2a.server.agent_execution.context import RequestContext @@ -32,7 +34,6 @@ if typing.TYPE_CHECKING: from agentstack_sdk.server.context import RunContext - from agentstack_sdk.server.dependencies import Dependency A2A_EXTENSION_URI = "a2a_extension.uri" @@ -74,27 +75,26 @@ def __init_subclass__(cls, **kwargs): Params from the agent card. """ - def __init__(self, params: ParamsT) -> None: + def __init__(self, params: ParamsT, required: bool = False) -> None: """ Agent should construct an extension instance using the constructor. """ self.params = params + self.required = required @classmethod def from_agent_card(cls: type["BaseExtensionSpec"], agent: AgentCard) -> typing.Self | None: """ Client should construct an extension instance using this classmethod. """ - try: + if extensions := [x for x in agent.capabilities.extensions or [] if x.uri == cls.URI]: return cls( - params=pydantic.TypeAdapter(cls.Params).validate_python( - next(x for x in agent.capabilities.extensions or [] if x.uri == cls.URI).params - ), + params=pydantic.TypeAdapter(cls.Params).validate_python(extensions[0].params), + required=extensions[0].required or False, ) - except StopIteration: - return None + return None - def to_agent_card_extensions(self, *, required: bool = False) -> list[AgentExtension]: + def to_agent_card_extensions(self, *, required: bool | None = None) -> list[AgentExtension]: """ Agent should use this method to obtain extension definitions to advertise on the agent card. This returns a list, as it's possible to support multiple A2A extensions within a single class. @@ -108,20 +108,20 @@ def to_agent_card_extensions(self, *, required: bool = False) -> list[AgentExten dict[str, typing.Any] | None, pydantic.TypeAdapter(self.Params).dump_python(self.params, mode="json"), ), - required=required, + required=required if required is not None else self.required, ) ] class NoParamsBaseExtensionSpec(BaseExtensionSpec[NoneType]): - def __init__(self): - super().__init__(None) + def __init__(self, required: bool = False): + super().__init__(None, required) @classmethod @override def from_agent_card(cls, agent: AgentCard) -> typing.Self | None: - if any(e.uri == cls.URI for e in agent.capabilities.extensions or []): - return cls() + if extensions := [e for e in agent.capabilities.extensions or [] if e.uri == cls.URI]: + return cls(required=extensions[0].required or False) return None @@ -133,7 +133,7 @@ class BaseExtensionServer(abc.ABC, typing.Generic[ExtensionSpecT, MetadataFromCl Type of the extension metadata, attached to messages. """ - def __init_subclass__(cls, **kwargs): + def __init_subclass__(cls: type[Self], **kwargs): super().__init_subclass__(**kwargs) generic_args = _get_generic_args(cls, BaseExtensionServer) @@ -143,12 +143,16 @@ def __init_subclass__(cls, **kwargs): attributes={A2A_EXTENSION_URI: generic_args[0].URI}, )(cls) cls.MetadataFromClient = generic_args[1] + cls._context_var = ContextVar(f"extension_{cls.__name__}", default=None) _metadata_from_client: MetadataFromClientT | None = None - _dependencies: dict[str, Dependency] = {} # noqa: RUF012 + + @classmethod + def current(cls) -> Self | None: + return cls._context_var.get() @property - def data(self): + def data(self) -> MetadataFromClientT | None: return self._metadata_from_client def __bool__(self): @@ -182,16 +186,10 @@ def _fork(self) -> typing.Self: """Creates a clone of this instance with the same arguments as the original""" return type(self)(self.spec, *self._args, **self._kwargs) - def __call__( - self, - message: A2AMessage, - run_context: RunContext, - request_context: RequestContext, - dependencies: dict[str, Dependency], - ) -> typing.Self: + def __call__(self, message: A2AMessage, run_context: RunContext, request_context: RequestContext) -> typing.Self: """Works as a dependency constructor - create a private instance for the request""" instance = self._fork() - instance._dependencies = dependencies + instance._context_var.set(instance) # type: ignore instance.handle_incoming_message(message, run_context, request_context) return instance diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/services/mcp.py b/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/services/mcp.py index 6d4fa58d38..c4e713536d 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/services/mcp.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/services/mcp.py @@ -159,18 +159,6 @@ def parse_client_metadata(self, message: A2AMessage) -> MCPServiceExtensionMetad raise ValueError(f'Transport "{fulfillment.transport.type}" not allowed for demand "{name}"') return metadata - def _get_oauth_server(self): - for dependency in self._dependencies.values(): - if isinstance(dependency, OAuthExtensionServer): - return dependency - return None - - def _get_platform_server(self): - for dependency in self._dependencies.values(): - if isinstance(dependency, PlatformApiExtensionServer): - return dependency - return None - @asynccontextmanager async def create_client(self, demand: str = _DEFAULT_DEMAND_NAME): fulfillment = self.data.mcp_fulfillments.get(demand) if self.data else None @@ -205,7 +193,7 @@ async def create_client(self, demand: str = _DEFAULT_DEMAND_NAME): raise NotImplementedError("Unsupported transport") async def _create_auth(self, transport: StreamableHTTPTransport): - platform = self._get_platform_server() + platform = PlatformApiExtensionServer.current() if ( platform and platform.data @@ -213,7 +201,7 @@ async def _create_auth(self, transport: StreamableHTTPTransport): and str(transport.url).startswith(str(platform.data.base_url)) ): return await platform.create_httpx_auth() - oauth = self._get_oauth_server() + oauth = OAuthExtensionServer.current() if oauth: return await oauth.create_httpx_auth(resource_url=pydantic.AnyUrl(transport.url)) return None diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/services/platform.py b/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/services/platform.py index 6f717705ae..c7c5e6b36a 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/services/platform.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/services/platform.py @@ -25,7 +25,6 @@ from agentstack_sdk.a2a.extensions.exceptions import ExtensionError from agentstack_sdk.platform import use_platform_client from agentstack_sdk.platform.client import PlatformClient -from agentstack_sdk.server.middleware.platform_auth_backend import PlatformAuthenticatedUser from agentstack_sdk.util.httpx import BearerAuth from agentstack_sdk.util.pydantic import REVEAL_SECRETS, SecureBaseModel @@ -71,14 +70,15 @@ class PlatformApiExtensionServer(BaseExtensionServer[PlatformApiExtensionSpec, P @asynccontextmanager @override async def lifespan(self) -> AsyncIterator[None]: - """Called when entering the agent context after the first message was parsed (__call__ was already called)""" - if self.data and self.spec.params.auto_use: + if self.data and self.data.auth_token and self.spec.params.auto_use: async with self.use_client(): yield else: yield def _get_header_token(self, request_context: RequestContext) -> pydantic.Secret[str] | None: + from agentstack_sdk.server.middleware.platform_auth_backend import PlatformAuthenticatedUser + header_token = None call_context = request_context.call_context assert call_context @@ -101,9 +101,6 @@ def handle_incoming_message(self, message: A2AMessage, run_context: RunContext, auth_token = data.auth_token or self._get_header_token(request_context) data.auth_token = pydantic.SecretStr(auth_token.get_secret_value()) if auth_token else None - if not data.auth_token: - raise ExtensionError(self.spec, "Platform extension metadata was not provided") - @asynccontextmanager async def use_client(self) -> AsyncIterator[PlatformClient]: if not self.data or not self.data.auth_token: @@ -148,3 +145,9 @@ class _PlatformSelfRegistrationExtensionParams(pydantic.BaseModel): class _PlatformSelfRegistrationExtensionSpec(BaseExtensionSpec[_PlatformSelfRegistrationExtensionParams]): URI: str = "https://a2a-extensions.agentstack.beeai.dev/services/platform-self-registration/v1" + + +class _PlatformSelfRegistrationExtensionServer( + BaseExtensionServer[_PlatformSelfRegistrationExtensionSpec, _PlatformSelfRegistrationExtension] +): + pass diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/types.py b/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/types.py index cd0626a3fc..ec8cc6569c 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/types.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/types.py @@ -39,8 +39,8 @@ class Metadata(dict[str, JsonValue]): ... | FileWithUri | Metadata | DataPart - | TaskStatusUpdateEvent | TaskArtifactUpdateEvent + | TaskStatusUpdateEvent | str | JsonDict | Exception diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/server/agent.py b/apps/agentstack-sdk-py/src/agentstack_sdk/server/agent.py index 07d88e8c46..66dc3d6699 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/server/agent.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/server/agent.py @@ -10,7 +10,7 @@ from collections.abc import AsyncGenerator, AsyncIterator, Callable, Generator from contextlib import AbstractAsyncContextManager, AsyncExitStack, asynccontextmanager, suppress from datetime import datetime, timedelta -from typing import Any, NamedTuple, TypeAlias, TypeVar, cast +from typing import Any, Final, TypeAlias, TypeVar, cast import janus from a2a.server.agent_execution import AgentExecutor, RequestContext @@ -35,26 +35,26 @@ TaskStatus, TaskStatusUpdateEvent, TextPart, + TransportProtocol, ) from typing_extensions import override +from agentstack_sdk.a2a.extensions import AgentDetailExtensionSpec, BaseExtensionServer from agentstack_sdk.a2a.extensions.ui.agent_detail import ( AgentDetail, AgentDetailExtensionSpec, AgentDetailTool, ) from agentstack_sdk.a2a.extensions.ui.error import ( - ErrorExtensionParams, - ErrorExtensionServer, - ErrorExtensionSpec, get_error_extension_context, ) from agentstack_sdk.a2a.types import ArtifactChunk, Metadata, RunYield, RunYieldResume -from agentstack_sdk.server.constants import _IMPLICIT_DEPENDENCY_PREFIX +from agentstack_sdk.server.constants import DEFAULT_IMPLICIT_EXTENSIONS from agentstack_sdk.server.context import RunContext from agentstack_sdk.server.dependencies import Dependency, Depends, extract_dependencies from agentstack_sdk.server.store.context_store import ContextStore from agentstack_sdk.server.utils import cancel_task +from agentstack_sdk.types import A2ASecurity from agentstack_sdk.util.logging import logger AgentFunction: TypeAlias = Callable[[], AsyncGenerator[RunYield, RunYieldResume]] @@ -62,18 +62,142 @@ OriginalFnType = TypeVar("OriginalFnType", bound=Callable[..., Any]) +_IMPLICIT_DEPENDENCY_PREFIX: Final = "___server_dep" + class AgentExecuteFn(typing.Protocol): async def __call__(self, _ctx: RunContext, **kwargs: Any) -> None: ... -class Agent(NamedTuple): - card: AgentCard - dependencies: dict[str, Depends] +class ActiveDependenciesContainer: + def __init__(self, active_dependencies: dict[str, Dependency], run_context: RunContext): + self._dependencies = active_dependencies + self._run_context = run_context + + @property + def user_dependency_args(self): + return {k: v for k, v in self._dependencies.items() if not k.startswith(_IMPLICIT_DEPENDENCY_PREFIX)} + + def handle_incoming_message(self, message: Message, request_context: RequestContext): + for dependency in self._dependencies.values(): + if isinstance(dependency, BaseExtensionServer): + dependency.handle_incoming_message(message, self._run_context, request_context) + + +class Agent: execute_fn: AgentExecuteFn + def __init__( + self, + initial_card: AgentCard, + detail: AgentDetail, + dependency_args: dict[str, Depends], + execute_fn: AgentExecuteFn, + ) -> None: + self.execute_fn = execute_fn + self.initial_card = initial_card + self._card = initial_card + self._detail = detail + self._dependency_args = dependency_args + self._implicit_extensions: dict[str, BaseExtensionServer] = {} + self._required_extensions: set[str] = set() + self._initialized = False + + def initialize( + self, + url: str, + a2a_security: A2ASecurity | None = None, + preferred_transport: TransportProtocol | str | None = None, + additional_interfaces: list[AgentInterface] | None = None, + implicit_extensions: dict[str, BaseExtensionServer] = DEFAULT_IMPLICIT_EXTENSIONS, + required_extensions: set[str] | None = None, + ) -> None: + if self._initialized: + raise RuntimeError("Agent already initialized") + + self._implicit_extensions = implicit_extensions + self._required_extensions = required_extensions or set() + + user_sdk_extensions = { + dep.extension.spec.URI: dep.extension for dep in self._dependency_args.values() if dep.extension is not None + } + + self._all_dependencies = { + **self._dependency_args, + **{ + f"{_IMPLICIT_DEPENDENCY_PREFIX}{uri}": Depends(dep) + for uri, dep in self._implicit_extensions.items() + if uri not in user_sdk_extensions + }, + } + + self._initialized = True + + capabilities = ( + self.initial_card.capabilities.model_copy() if self.initial_card.capabilities else AgentCapabilities() + ) + capabilities.extensions = [ + *(capabilities.extensions or []), + *(AgentDetailExtensionSpec(self._detail).to_agent_card_extensions()), + *( + e_card + for ext in self._sdk_extensions + for e_card in ext.spec.to_agent_card_extensions( + required=True if ext.spec.URI in self._required_extensions else None + ) + ), + ] + a2a_security = a2a_security or A2ASecurity( + security=self.initial_card.security, + security_schemes=self.initial_card.security_schemes, + ) + preferred_transport = preferred_transport or self.initial_card.preferred_transport + additional_interfaces = additional_interfaces or self.initial_card.additional_interfaces + self._card = self.initial_card.model_copy( + update={ + "capabilities": capabilities, + "url": url, + "security": a2a_security["security"], + "security_schemes": a2a_security["security_schemes"], + "preferred_transport": preferred_transport, + "additional_interfaces": additional_interfaces, + } + ) -AgentFactory: TypeAlias = Callable[[Callable[[dict[str, Depends]], None]], Agent] + @property + def card(self) -> AgentCard: + if not self._initialized: + raise RuntimeError("Agent not initialized") + return self._card + + @property + def _sdk_extensions(self) -> list[BaseExtensionServer]: + return [dep.extension for dep in self._all_dependencies.values() if dep.extension is not None] + + @asynccontextmanager + async def dependency_container( + self, message: Message, run_context: RunContext, request_context: RequestContext + ) -> AsyncIterator[ActiveDependenciesContainer]: + async with AsyncExitStack() as stack: + initialized_dependencies: dict[str, Dependency] = {} + initialize_deps_exceptions: list[Exception] = [] + for pname, depends in self._all_dependencies.items(): + # call dependencies with the first message and initialize their lifespan + try: + initialized_dependencies[pname] = await stack.enter_async_context( + depends(message, run_context, request_context) + ) + except Exception as e: + initialize_deps_exceptions.append(e) + + if initialize_deps_exceptions: + raise ( + ExceptionGroup("Failed to initialize dependencies", initialize_deps_exceptions) + if len(initialize_deps_exceptions) > 1 + else initialize_deps_exceptions[0] + ) + + yield ActiveDependenciesContainer(initialized_dependencies, run_context) def agent( @@ -95,7 +219,7 @@ def agent( skills: list[AgentSkill] | None = None, supports_authenticated_extended_card: bool | None = None, version: str | None = None, -) -> Callable[[OriginalFnType], AgentFactory]: +) -> Callable[[OriginalFnType], Agent]: """ Create an Agent function. @@ -127,22 +251,19 @@ def agent( """ capabilities = capabilities.model_copy(deep=True) if capabilities else AgentCapabilities(streaming=True) - detail = detail or AgentDetail() - - def decorator(fn: OriginalFnType) -> AgentFactory: - def agent_factory(modify_dependencies: Callable[[dict[str, Depends]], None]): - dependencies = extract_dependencies(fn) - modify_dependencies(dependencies) - sdk_extensions = [dep.extension for dep in dependencies.values() if dep.extension is not None] + def decorator(fn: OriginalFnType) -> Agent: + signature = inspect.signature(fn) + dependencies = extract_dependencies(signature) - resolved_name = name or fn.__name__ - resolved_description = description or fn.__doc__ or "" + resolved_name = name or fn.__name__ + resolved_description = description or fn.__doc__ or "" - # Check if user has provided an ErrorExtensionServer, if not add default - has_error_extension = any(isinstance(ext, ErrorExtensionServer) for ext in sdk_extensions) - error_extension_spec = ErrorExtensionSpec(ErrorExtensionParams()) if not has_error_extension else None + # Check if user has provided an ErrorExtensionServer, if not add default + has_error_extension = any(isinstance(ext, ErrorExtensionServer) for ext in sdk_extensions) + error_extension_spec = ErrorExtensionSpec(ErrorExtensionParams()) if not has_error_extension else None + if detail: if detail.tools is None and skills: detail.tools = [ AgentDetailTool(name=skill.name, description=skill.description or "") for skill in skills @@ -154,91 +275,94 @@ def agent_factory(modify_dependencies: Callable[[dict[str, Depends]], None]): if detail.input_placeholder is None: detail.input_placeholder = "What is your task?" - capabilities.extensions = [ - *(capabilities.extensions or []), - *(AgentDetailExtensionSpec(detail).to_agent_card_extensions()), - *(error_extension_spec.to_agent_card_extensions() if error_extension_spec else []), - *(e_card for ext in sdk_extensions for e_card in ext.spec.to_agent_card_extensions()), - ] - - card = AgentCard( - url=url, - preferred_transport=preferred_transport, - additional_interfaces=additional_interfaces, - capabilities=capabilities, - default_input_modes=default_input_modes or ["text"], - default_output_modes=default_output_modes or ["text"], - description=resolved_description, - documentation_url=documentation_url, - icon_url=icon_url, - name=resolved_name, - provider=provider, - security=security, - security_schemes=security_schemes, - skills=skills or [], - supports_authenticated_extended_card=supports_authenticated_extended_card, - version=version or "1.0.0", - ) + capabilities.extensions = [ + *(capabilities.extensions or []), + *(AgentDetailExtensionSpec(detail).to_agent_card_extensions()), + *(error_extension_spec.to_agent_card_extensions() if error_extension_spec else []), + *(e_card for ext in sdk_extensions for e_card in ext.spec.to_agent_card_extensions()), + ] + + card = AgentCard( + url=url, + preferred_transport=preferred_transport, + additional_interfaces=additional_interfaces, + capabilities=capabilities, + default_input_modes=default_input_modes or ["text"], + default_output_modes=default_output_modes or ["text"], + description=resolved_description, + documentation_url=documentation_url, + icon_url=icon_url, + name=resolved_name, + provider=provider, + security=security, + security_schemes=security_schemes, + skills=skills or [], + supports_authenticated_extended_card=supports_authenticated_extended_card, + version=version or "1.0.0", + ) - if inspect.isasyncgenfunction(fn): + if inspect.isasyncgenfunction(fn): - async def execute_fn(_ctx: RunContext, *args, **kwargs) -> None: - try: - gen: AsyncGenerator[RunYield, RunYieldResume] = fn(*args, **kwargs) - value: RunYieldResume = None - while True: - value = await _ctx.yield_async(await gen.asend(value)) - except StopAsyncIteration: - pass - except Exception as e: - await _ctx.yield_async(e) - finally: - _ctx.shutdown() - - elif inspect.iscoroutinefunction(fn): - - async def execute_fn(_ctx: RunContext, *args, **kwargs) -> None: - try: - await _ctx.yield_async(await fn(*args, **kwargs)) - except Exception as e: - await _ctx.yield_async(e) - finally: - _ctx.shutdown() - - elif inspect.isgeneratorfunction(fn): - - def _execute_fn_sync(_ctx: RunContext, *args, **kwargs) -> None: - try: - gen: Generator[RunYield, RunYieldResume] = fn(*args, **kwargs) - value = None - while True: - value = _ctx.yield_sync(gen.send(value)) - except StopIteration: - pass - except Exception as e: - _ctx.yield_sync(e) - finally: - _ctx.shutdown() + async def execute_fn(_ctx: RunContext, *args, **kwargs) -> None: + try: + gen: AsyncGenerator[RunYield, RunYieldResume] = fn(*args, **kwargs) + value: RunYieldResume = None + while True: + value = await _ctx.yield_async(await gen.asend(value)) + except StopAsyncIteration: + pass + except Exception as e: + await _ctx.yield_async(e) + finally: + _ctx.shutdown() - async def execute_fn(_ctx: RunContext, *args, **kwargs) -> None: - await asyncio.to_thread(_execute_fn_sync, _ctx, *args, **kwargs) + elif inspect.iscoroutinefunction(fn): - else: + async def execute_fn(_ctx: RunContext, *args, **kwargs) -> None: + try: + await _ctx.yield_async(await fn(*args, **kwargs)) + except Exception as e: + await _ctx.yield_async(e) + finally: + _ctx.shutdown() - def _execute_fn_sync(_ctx: RunContext, *args, **kwargs) -> None: - try: - _ctx.yield_sync(fn(*args, **kwargs)) - except Exception as e: - _ctx.yield_sync(e) - finally: - _ctx.shutdown() + elif inspect.isgeneratorfunction(fn): - async def execute_fn(_ctx: RunContext, *args, **kwargs) -> None: - await asyncio.to_thread(_execute_fn_sync, _ctx, *args, **kwargs) + def _execute_fn_sync(_ctx: RunContext, *args, **kwargs) -> None: + try: + gen: Generator[RunYield, RunYieldResume] = fn(*args, **kwargs) + value = None + while True: + value = _ctx.yield_sync(gen.send(value)) + except StopIteration: + pass + except Exception as e: + _ctx.yield_sync(e) + finally: + _ctx.shutdown() - return Agent(card=card, dependencies=dependencies, execute_fn=execute_fn) + async def execute_fn(_ctx: RunContext, *args, **kwargs) -> None: + await asyncio.to_thread(_execute_fn_sync, _ctx, *args, **kwargs) - return agent_factory + else: + + def _execute_fn_sync(_ctx: RunContext, *args, **kwargs) -> None: + try: + _ctx.yield_sync(fn(*args, **kwargs)) + except Exception as e: + _ctx.yield_sync(e) + finally: + _ctx.shutdown() + + async def execute_fn(_ctx: RunContext, *args, **kwargs) -> None: + await asyncio.to_thread(_execute_fn_sync, _ctx, *args, **kwargs) + + return Agent( + initial_card=card, + detail=detail or AgentDetail(), + dependency_args=dependencies, + execute_fn=execute_fn, + ) return decorator @@ -256,6 +380,7 @@ def __init__(self, agent: Agent, context_store: ContextStore, on_finish: Callabl self._lock: asyncio.Lock = asyncio.Lock() self._on_finish: Callable[[], None] | None = on_finish self._working: bool = False + self._dependency_container: ActiveDependenciesContainer | None = None @property def run_context(self) -> RunContext: @@ -289,12 +414,14 @@ async def start(self, request_context: RequestContext, event_queue: EventQueue): raise RuntimeError("Attempting to start a run that is already executing or done") task_id, context_id, message = request_context.task_id, request_context.context_id, request_context.message assert task_id and context_id and message + context_store = await self._context_store.create(context_id) self._run_context = RunContext( configuration=request_context.configuration, context_id=context_id, task_id=task_id, current_task=request_context.current_task, related_tasks=request_context.related_tasks, + _store=context_store, ) self._request_context = request_context self._task_updater = TaskUpdater(event_queue, task_id, context_id) @@ -310,13 +437,11 @@ async def resume(self, request_context: RequestContext, event_queue: EventQueue) if self._working or self.done: raise RuntimeError("Attempting to resume a run that is already executing or done") task_id, context_id, message = request_context.task_id, request_context.context_id, request_context.message - assert task_id and context_id and message + assert task_id and context_id and message and self._dependency_container self._request_context = request_context self._task_updater = TaskUpdater(event_queue, task_id, context_id) - for dependency in self._agent.dependencies.values(): - if dependency.extension: - dependency.extension.handle_incoming_message(message, self.run_context, request_context) + self._dependency_container.handle_incoming_message(message, request_context) self._working = True await self.resume_queue.put(message) @@ -334,34 +459,6 @@ async def cancel(self, request_context: RequestContext, event_queue: EventQueue) finally: await cancel_task(self._task) - @asynccontextmanager - async def _dependencies_lifespan(self, message: Message) -> AsyncIterator[dict[str, Dependency]]: - async with AsyncExitStack() as stack: - dependency_args: dict[str, Dependency] = {} - initialize_deps_exceptions: list[Exception] = [] - for pname, depends in self._agent.dependencies.items(): - # call dependencies with the first message and initialize their lifespan - try: - dependency_args[pname] = await stack.enter_async_context( - depends(message, self.run_context, self.request_context, dependency_args) - ) - except Exception as e: - initialize_deps_exceptions.append(e) - - if initialize_deps_exceptions: - raise ( - ExceptionGroup("Failed to initialize dependencies", initialize_deps_exceptions) - if len(initialize_deps_exceptions) > 1 - else initialize_deps_exceptions[0] - ) - - self.run_context._store = await self._context_store.create( - context_id=self.run_context.context_id, - initialized_dependencies=list(dependency_args.values()), - ) - - yield {k: v for k, v in dependency_args.items() if not k.startswith(_IMPLICIT_DEPENDENCY_PREFIX)} - def _with_context(self, message: Message | None = None) -> Message | None: if message is None: return None @@ -380,8 +477,13 @@ async def _run_agent_function(self, initial_message: Message) -> None: yield_resume_queue = self.run_context._yield_resume_queue try: - async with self._dependencies_lifespan(initial_message) as dependency_args: - task = asyncio.create_task(self._agent.execute_fn(self.run_context, **dependency_args)) + async with self._agent.dependency_container( + initial_message, self.run_context, self.request_context + ) as dependency_container: + self._dependency_container = dependency_container + task = asyncio.create_task( + self._agent.execute_fn(self.run_context, **dependency_container.user_dependency_args) + ) try: resume_value: RunYieldResume = None opened_artifacts: set[str] = set() diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/server/app.py b/apps/agentstack-sdk-py/src/agentstack_sdk/server/app.py index 134de0c012..13918fcbb3 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/server/app.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/server/app.py @@ -23,15 +23,22 @@ from fastapi.params import Depends from starlette.types import Lifespan +from agentstack_sdk.a2a.extensions import BaseExtensionServer from agentstack_sdk.server.agent import Agent, Executor +from agentstack_sdk.server.constants import DEFAULT_IMPLICIT_EXTENSIONS from agentstack_sdk.server.store.context_store import ContextStore from agentstack_sdk.server.store.memory_context_store import InMemoryContextStore +from agentstack_sdk.types import SdkAuthenticationBackend def create_app( agent: Agent, + url: str, task_store: TaskStore | None = None, context_store: ContextStore | None = None, + implicit_extensions: dict[str, BaseExtensionServer] = DEFAULT_IMPLICIT_EXTENSIONS, + required_extensions: set[str] | None = None, + auth_backend: SdkAuthenticationBackend | None = None, queue_manager: QueueManager | None = None, push_config_store: PushNotificationConfigStore | None = None, push_sender: PushNotificationSender | None = None, @@ -60,13 +67,25 @@ def create_app( request_context_builder=request_context_builder, ) + preferred_transport = None + additional_interfaces = None if override_interfaces: - agent.card.additional_interfaces = [ - AgentInterface(url=agent.card.url, transport=TransportProtocol.http_json), - AgentInterface(url=agent.card.url + "/jsonrpc/", transport=TransportProtocol.jsonrpc), + jsonrpc_url = url + "/jsonrpc/" + preferred_transport = TransportProtocol.jsonrpc + additional_interfaces = [ + AgentInterface(url=url, transport=TransportProtocol.http_json), + AgentInterface(url=jsonrpc_url, transport=TransportProtocol.jsonrpc), ] - agent.card.url = agent.card.url + "/jsonrpc/" - agent.card.preferred_transport = TransportProtocol.jsonrpc + url = jsonrpc_url + + agent.initialize( + url=url, + a2a_security=auth_backend.get_card_security_schemes() if auth_backend else None, + preferred_transport=preferred_transport, + additional_interfaces=additional_interfaces, + implicit_extensions=implicit_extensions, + required_extensions=(required_extensions or set()) | context_store.required_extensions, + ) jsonrpc_app = A2AFastAPIApplication(agent_card=agent.card, http_handler=http_handler).build( dependencies=dependencies, diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/server/constants.py b/apps/agentstack-sdk-py/src/agentstack_sdk/server/constants.py index c730004ebe..0695898873 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/server/constants.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/server/constants.py @@ -5,7 +5,14 @@ from typing import Final -_IMPLICIT_DEPENDENCY_PREFIX: Final = "___server_dep" +from agentstack_sdk.a2a.extensions import BaseExtensionServer +from agentstack_sdk.a2a.extensions.services.platform import PlatformApiExtensionServer, PlatformApiExtensionSpec +from agentstack_sdk.a2a.extensions.ui.error import ErrorExtensionParams, ErrorExtensionServer, ErrorExtensionSpec + +DEFAULT_IMPLICIT_EXTENSIONS: Final[dict[str, BaseExtensionServer]] = { + ErrorExtensionSpec.URI: ErrorExtensionServer(ErrorExtensionSpec(ErrorExtensionParams())), + PlatformApiExtensionSpec.URI: PlatformApiExtensionServer(PlatformApiExtensionSpec()), +} __all__ = [] diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/server/context.py b/apps/agentstack-sdk-py/src/agentstack_sdk/server/context.py index 3992ee649f..e7a0f10477 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/server/context.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/server/context.py @@ -23,8 +23,13 @@ class RunContext(BaseModel, arbitrary_types_allowed=True): current_task: Task | None = None related_tasks: list[Task] | None = None - _store: ContextStoreInstance | None = PrivateAttr(None) + _store: ContextStoreInstance _yield_queue: janus.Queue[RunYield] = PrivateAttr(default_factory=janus.Queue) + + def __init__(self, _store: ContextStoreInstance, **data): + super().__init__(**data) + self._store = _store + _yield_resume_queue: janus.Queue[RunYieldResume] = PrivateAttr(default_factory=janus.Queue) async def store(self, data: Message | Artifact): diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/server/dependencies.py b/apps/agentstack-sdk-py/src/agentstack_sdk/server/dependencies.py index f965c876cd..286808d8df 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/server/dependencies.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/server/dependencies.py @@ -19,9 +19,7 @@ from agentstack_sdk.a2a.extensions.base import BaseExtensionServer, BaseExtensionSpec from agentstack_sdk.server.context import RunContext -Dependency: TypeAlias = ( - Callable[[Message, RunContext, RequestContext, dict[str, "Dependency"]], Any] | BaseExtensionServer[Any, Any] -) +Dependency: TypeAlias = Callable[[Message, RunContext, RequestContext], Any] | BaseExtensionServer[Any, Any] # Inspired by fastapi.Depends @@ -45,9 +43,9 @@ def __init__( self.extension = dependency def __call__( - self, message: Message, context: RunContext, request_context: RequestContext, dependencies: dict[str, Any] + self, message: Message, context: RunContext, request_context: RequestContext ) -> AbstractAsyncContextManager[Dependency]: - instance = self._dependency_callable(message, context, request_context, dependencies) + instance = self._dependency_callable(message, context, request_context) @asynccontextmanager async def lifespan() -> AsyncIterator[Dependency]: @@ -89,14 +87,14 @@ def process_args(name: str, args: tuple[Any, ...]) -> None: elif inspect.isclass(annotation): # message: Message if annotation == Message: - dependencies[name] = Depends(lambda message, _run_context, _request_context, _dependencies: message) + dependencies[name] = Depends(lambda message, _run_context, _request_context: message) # context: Context elif annotation == RunContext: - dependencies[name] = Depends(lambda _message, run_context, _request_context, _dependencies: run_context) + dependencies[name] = Depends(lambda _message, run_context, _request_context: run_context) # extension: BaseExtensionServer = BaseExtensionSpec() # TODO: this does not get past linters, should we enable it or somehow fix the typing? - # elif issubclass(param.annotation, BaseExtensionServer) and isinstance(param.default, BaseExtensionSpec): - # dependencies[name] = Depends(param.annotation(param.default)) + # elif issubclass(annotation, BaseExtensionServer) and isinstance(param.default, BaseExtensionSpec): + # dependencies[name] = Depends(annotation(param.default)) elif param.kind is inspect.Parameter.VAR_KEYWORD: origin = get_origin(annotation) if origin is Unpack: diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/server/middleware/platform_auth_backend.py b/apps/agentstack-sdk-py/src/agentstack_sdk/server/middleware/platform_auth_backend.py index 3099eec029..178bfb9d31 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/server/middleware/platform_auth_backend.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/server/middleware/platform_auth_backend.py @@ -9,7 +9,7 @@ from urllib.parse import urljoin from a2a.auth.user import User -from a2a.types import AgentCard, HTTPAuthSecurityScheme, SecurityScheme +from a2a.types import HTTPAuthSecurityScheme, SecurityScheme from async_lru import alru_cache from authlib.jose import JsonWebKey, JWTClaims, KeySet, jwt from authlib.jose.errors import JoseError @@ -25,7 +25,7 @@ from typing_extensions import override from agentstack_sdk.platform import use_platform_client -from agentstack_sdk.types import JsonValue, SdkAuthenticationBackend +from agentstack_sdk.types import A2ASecurity, JsonValue, SdkAuthenticationBackend logger = logging.getLogger(__name__) @@ -133,14 +133,16 @@ async def authenticate(self, conn: HTTPConnection) -> tuple[AuthCredentials, Bas raise AuthenticationError(f"Authentication failed: {e}") from e @override - def update_card_security_schemes(self, agent_card: AgentCard) -> None: - agent_card.security_schemes = { - "platform_context_token": SecurityScheme( - HTTPAuthSecurityScheme( - scheme="bearer", - bearer_format="JWT", - description="Platform context token, issued by the AgentStack server using POST /api/v1/context/{context_id}/token.", + def get_card_security_schemes(self) -> A2ASecurity: + return A2ASecurity( + security=[{"platform_context_token": []}], + security_schemes={ + "platform_context_token": SecurityScheme( + HTTPAuthSecurityScheme( + scheme="bearer", + bearer_format="JWT", + description="Platform context token, issued by the AgentStack server using POST /api/v1/context/{context_id}/token.", + ) ) - ), - } - agent_card.security = [{"platform_context_token": []}] + }, + ) diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/server/server.py b/apps/agentstack-sdk-py/src/agentstack_sdk/server/server.py index 736553e974..bca05cfa17 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/server/server.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/server/server.py @@ -25,7 +25,6 @@ from fastapi.applications import AppType from fastapi.responses import PlainTextResponse from httpx import HTTPError, HTTPStatusError -from pydantic import AnyUrl from starlette.authentication import AuthenticationError from starlette.middleware.authentication import AuthenticationMiddleware from starlette.requests import HTTPConnection @@ -35,10 +34,10 @@ from agentstack_sdk.platform import get_platform_client from agentstack_sdk.platform.client import PlatformClient from agentstack_sdk.platform.provider import Provider -from agentstack_sdk.server.agent import Agent, AgentFactory +from agentstack_sdk.server.agent import Agent from agentstack_sdk.server.agent import agent as agent_decorator +from agentstack_sdk.server.constants import DEFAULT_IMPLICIT_EXTENSIONS from agentstack_sdk.server.store.context_store import ContextStore -from agentstack_sdk.server.store.memory_context_store import InMemoryContextStore from agentstack_sdk.server.telemetry import configure_telemetry as configure_telemetry_func from agentstack_sdk.server.utils import cancel_task from agentstack_sdk.types import SdkAuthenticationBackend @@ -48,7 +47,6 @@ class Server: def __init__(self) -> None: - self._agent_factory: AgentFactory | None = None self._agent: Agent | None = None self.server: uvicorn.Server | None = None self._context_store: ContextStore | None = None @@ -59,11 +57,11 @@ def __init__(self) -> None: @functools.wraps(agent_decorator) def agent(self, *args, **kwargs) -> Callable: - if self._agent_factory: + if self._agent: raise ValueError("Server can have only one agent.") def decorator(fn: Callable) -> Callable: - self._agent_factory = agent_decorator(*args, **kwargs)(fn) + self._agent = agent_decorator(*args, **kwargs)(fn) return fn return decorator @@ -137,18 +135,29 @@ async def serve( ) -> None: if self.server: raise RuntimeError("The server is already running") - if not self._agent_factory: + if not self._agent: raise ValueError("Agent is not registered") - context_store = context_store or InMemoryContextStore() - self._agent = self._agent_factory(context_store.modify_dependencies) - card_url = url and url.strip() - self._agent.card.url = card_url.rstrip("/") if card_url else f"http://{host}:{port}" + implicit_extensions = DEFAULT_IMPLICIT_EXTENSIONS.copy() - self._self_registration_client = ( - self_registration_client_factory() if self_registration_client_factory else None - ) - self._self_registration_id = urllib.parse.quote(self_registration_id or self._agent.card.name) + self_registration = False if self._production_mode else self_registration + if self_registration: + from agentstack_sdk.a2a.extensions.services.platform import _PlatformSelfRegistrationExtensionServer + + self._self_registration_client = ( + self_registration_client_factory() if self_registration_client_factory else None + ) + self._self_registration_id = urllib.parse.quote(self_registration_id or self._agent.initial_card.name) + from agentstack_sdk.a2a.extensions.services.platform import ( + _PlatformSelfRegistrationExtensionParams, + _PlatformSelfRegistrationExtensionSpec, + ) + + implicit_extensions[_PlatformSelfRegistrationExtensionSpec.URI] = _PlatformSelfRegistrationExtensionServer( + _PlatformSelfRegistrationExtensionSpec( + _PlatformSelfRegistrationExtensionParams(self_registration_id=self._self_registration_id) + ) + ) if headers is None: headers = [("server", "a2a")] @@ -159,8 +168,6 @@ async def serve( from agentstack_sdk.server.app import create_app - self_registration = False if self._production_mode else self_registration - @asynccontextmanager async def _lifespan_fn(app: FastAPI) -> AsyncGenerator[None, None]: async with self._self_registration_client or nullcontext(): @@ -179,26 +186,11 @@ async def _lifespan_fn(app: FastAPI) -> AsyncGenerator[None, None]: with suppress(Exception): await cancel_task(reload_task) - card_url = AnyUrl(self._agent.card.url) - if card_url.host == "invalid": - self._agent.card.url = f"http://{host}:{port}" - - if self_registration: - from agentstack_sdk.a2a.extensions.services.platform import ( - _PlatformSelfRegistrationExtensionParams, - _PlatformSelfRegistrationExtensionSpec, - ) - - self._agent.card.capabilities.extensions = [ - *(self._agent.card.capabilities.extensions or []), - *_PlatformSelfRegistrationExtensionSpec( - _PlatformSelfRegistrationExtensionParams(self_registration_id=self._self_registration_id) - ).to_agent_card_extensions(), - ] - app = create_app( self._agent, + url=url.strip().rstrip("/") if url else f"http://{host}:{port}", lifespan=_lifespan_fn, + implicit_extensions=implicit_extensions, task_store=task_store, context_store=context_store, queue_manager=queue_manager, @@ -210,7 +202,6 @@ async def _lifespan_fn(app: FastAPI) -> AsyncGenerator[None, None]: ) if auth_backend: - auth_backend.update_card_security_schemes(self._agent.card) def on_error(connection: HTTPConnection, error: AuthenticationError) -> PlainTextResponse: return PlainTextResponse("Unauthorized", status_code=401) diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/server/store/context_store.py b/apps/agentstack-sdk-py/src/agentstack_sdk/server/store/context_store.py index be38882978..fbf47a4412 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/server/store/context_store.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/server/store/context_store.py @@ -6,7 +6,7 @@ import abc from collections.abc import AsyncIterator -from typing import TYPE_CHECKING, Protocol +from typing import Protocol from uuid import UUID from a2a.types import Artifact, Message @@ -18,9 +18,6 @@ "ContextStoreInstance", ] -if TYPE_CHECKING: - from agentstack_sdk.server.dependencies import Dependency, Depends - class ContextStoreInstance(Protocol): def load_history( @@ -31,8 +28,9 @@ async def delete_history_from_id(self, from_id: UUID) -> None: ... class ContextStore(abc.ABC): - def modify_dependencies(self, dependencies: dict[str, Depends]) -> None: - return + @property + def required_extensions(self) -> set[str]: + return set() @abc.abstractmethod - async def create(self, context_id: str, initialized_dependencies: list[Dependency]) -> ContextStoreInstance: ... + async def create(self, context_id: str) -> ContextStoreInstance: ... diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/server/store/memory_context_store.py b/apps/agentstack-sdk-py/src/agentstack_sdk/server/store/memory_context_store.py index e2a23a9e78..04a320a958 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/server/store/memory_context_store.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/server/store/memory_context_store.py @@ -11,7 +11,6 @@ from cachetools import TTLCache from agentstack_sdk.platform.context import ContextHistoryItem -from agentstack_sdk.server.dependencies import Dependency from agentstack_sdk.server.store.context_store import ContextStore, ContextStoreInstance @@ -55,7 +54,7 @@ def __init__(self, max_contexts: int = 1000, context_ttl: timedelta = timedelta( maxsize=max_contexts, ttl=context_ttl.total_seconds() ) - async def create(self, context_id: str, initialized_dependencies: list[Dependency]) -> ContextStoreInstance: + async def create(self, context_id: str) -> ContextStoreInstance: if context_id not in self._instances: self._instances[context_id] = MemoryContextStoreInstance(context_id) return self._instances[context_id] diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/server/store/platform_context_store.py b/apps/agentstack-sdk-py/src/agentstack_sdk/server/store/platform_context_store.py index 0ce9566518..3b33425c16 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/server/store/platform_context_store.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/server/store/platform_context_store.py @@ -4,47 +4,40 @@ from __future__ import annotations from collections.abc import AsyncIterator +from contextlib import asynccontextmanager from uuid import UUID from a2a.types import Artifact, Message -from agentstack_sdk.a2a.extensions.services.platform import ( - PlatformApiExtensionServer, - PlatformApiExtensionSpec, -) +from agentstack_sdk.a2a.extensions.services.platform import PlatformApiExtensionServer, PlatformApiExtensionSpec from agentstack_sdk.platform.context import Context, ContextHistoryItem -from agentstack_sdk.server.constants import _IMPLICIT_DEPENDENCY_PREFIX -from agentstack_sdk.server.dependencies import Dependency, Depends from agentstack_sdk.server.store.context_store import ContextStore, ContextStoreInstance class PlatformContextStore(ContextStore): - def modify_dependencies(self, dependencies: dict[str, Depends]) -> None: - for dependency in dependencies.values(): - if dependency.extension is None: - continue - if dependency.extension.spec.URI == PlatformApiExtensionSpec.URI: - dependency.extension.spec.required = True - break - else: - dependencies[f"{_IMPLICIT_DEPENDENCY_PREFIX}_{PlatformApiExtensionSpec.URI}"] = Depends( - PlatformApiExtensionServer(PlatformApiExtensionSpec()) - ) - - async def create(self, context_id: str, initialized_dependencies: list[Dependency]) -> ContextStoreInstance: - [platform_ext] = [d for d in initialized_dependencies if isinstance(d, PlatformApiExtensionServer)] - return PlatformContextStoreInstance(context_id=context_id, platform_extension=platform_ext) + @property + def required_extensions(self) -> set[str]: + return {PlatformApiExtensionSpec.URI} + + async def create(self, context_id: str) -> ContextStoreInstance: + return PlatformContextStoreInstance(context_id=context_id) class PlatformContextStoreInstance(ContextStoreInstance): - def __init__(self, context_id: str, platform_extension: PlatformApiExtensionServer): + def __init__(self, context_id: str): self._context_id = context_id - self._platform_extension = platform_extension + + @asynccontextmanager + async def client(self): + if not (ext := PlatformApiExtensionServer.current()): + raise RuntimeError("PlatformApiExtensionServer is not initialized") + async with ext.use_client(): + yield async def load_history( self, load_history_items: bool = False ) -> AsyncIterator[ContextHistoryItem | Message | Artifact]: - async with self._platform_extension.use_client(): + async with self.client(): async for history_item in Context.list_all_history(self._context_id): if load_history_items: yield history_item @@ -52,9 +45,9 @@ async def load_history( yield history_item.data async def store(self, data: Message | Artifact) -> None: - async with self._platform_extension.use_client(): + async with self.client(): await Context.add_history_item(self._context_id, data=data) async def delete_history_from_id(self, from_id: UUID) -> None: - async with self._platform_extension.use_client(): + async with self.client(): await Context.delete_history_from_id(self._context_id, from_id=from_id) diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/types.py b/apps/agentstack-sdk-py/src/agentstack_sdk/types.py index ba63efe4f0..f69d445d28 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/types.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/types.py @@ -4,9 +4,9 @@ from __future__ import annotations import abc -from typing import TYPE_CHECKING, TypeAlias +from typing import TYPE_CHECKING, TypeAlias, TypedDict -from a2a.types import AgentCard +from a2a.types import SecurityScheme from starlette.authentication import AuthenticationBackend __all__ = [ @@ -27,6 +27,11 @@ JsonDict = TypeAliasType("JsonDict", "dict[str, JsonValue]") +class A2ASecurity(TypedDict): + security: list[dict[str, list[str]]] | None + security_schemes: dict[str, SecurityScheme] | None + + class SdkAuthenticationBackend(AuthenticationBackend, abc.ABC): @abc.abstractmethod - def update_card_security_schemes(self, agent_card: AgentCard) -> None: ... + def get_card_security_schemes(self) -> A2ASecurity: ... diff --git a/apps/agentstack-server/uv.lock b/apps/agentstack-server/uv.lock index cb13c9d1a4..01ffbec36e 100644 --- a/apps/agentstack-server/uv.lock +++ b/apps/agentstack-server/uv.lock @@ -80,7 +80,7 @@ dev = [ { name = "pytest", specifier = ">=8.4.1" }, { name = "pytest-asyncio", specifier = ">=1.1.0" }, { name = "pytest-httpx", specifier = ">=0.35.0" }, - { name = "ruff", specifier = ">=0.12.3" }, + { name = "ruff", specifier = ">=0.15.0" }, ] [[package]] From 87332b41ddfb1f980045767ae34efcccd4e602e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radek=20Je=C5=BEek?= Date: Thu, 19 Feb 2026 16:25:35 +0100 Subject: [PATCH 2/6] chore(sdk): upgrade to a2a v1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Radek Ježek --- agents/chat/src/chat/agent.py | 4 +- agents/chat/uv.lock | 23 +- apps/agentstack-cli/uv.lock | 21 +- apps/agentstack-sdk-py/.vscode/launch.json | 26 + apps/agentstack-sdk-py/a2a.proto | 807 ++++++++++++++++++ .../examples/check_validation.py | 28 + apps/agentstack-sdk-py/examples/experiment.py | 6 + apps/agentstack-sdk-py/pyproject.toml | 3 + .../src/agentstack_sdk/__init__.py | 5 + .../a2a/extensions/auth/oauth/oauth.py | 10 +- .../src/agentstack_sdk/a2a/extensions/base.py | 8 +- .../a2a/extensions/ui/canvas.py | 15 +- .../a2a/extensions/ui/citation.py | 6 +- .../agentstack_sdk/a2a/extensions/ui/error.py | 6 +- .../a2a/extensions/ui/trajectory.py | 6 +- .../src/agentstack_sdk/a2a/types.py | 286 +++++-- .../src/agentstack_sdk/platform/context.py | 12 +- .../src/agentstack_sdk/platform/file.py | 6 +- .../src/agentstack_sdk/platform/provider.py | 16 +- .../platform/provider_discovery.py | 11 +- .../src/agentstack_sdk/server/agent.py | 242 +++--- .../src/agentstack_sdk/server/app.py | 26 +- .../src/agentstack_sdk/server/constants.py | 9 +- .../src/agentstack_sdk/server/context.py | 9 +- .../middleware/platform_auth_backend.py | 6 +- .../server/store/memory_context_store.py | 7 +- .../src/agentstack_sdk/types.py | 6 +- .../src/agentstack_sdk/util/file.py | 58 +- apps/agentstack-sdk-py/tests/e2e/conftest.py | 43 +- .../tests/e2e/test_extensions.py | 31 +- .../tests/e2e/test_history.py | 8 +- apps/agentstack-sdk-py/tests/e2e/test_runs.py | 119 ++- .../tests/e2e/test_yields.py | 176 ++-- .../tests/unit/a2a/test_types.py | 118 +++ apps/agentstack-sdk-py/uv.lock | 23 +- .../tests/e2e/agents/conftest.py | 4 +- 36 files changed, 1670 insertions(+), 520 deletions(-) create mode 100644 apps/agentstack-sdk-py/.vscode/launch.json create mode 100644 apps/agentstack-sdk-py/a2a.proto create mode 100644 apps/agentstack-sdk-py/examples/check_validation.py create mode 100644 apps/agentstack-sdk-py/examples/experiment.py create mode 100644 apps/agentstack-sdk-py/tests/unit/a2a/test_types.py diff --git a/agents/chat/src/chat/agent.py b/agents/chat/src/chat/agent.py index 36a2e3d175..1d1dd55d46 100644 --- a/agents/chat/src/chat/agent.py +++ b/agents/chat/src/chat/agent.py @@ -259,7 +259,9 @@ async def chat( input=last_step.input, output=last_step.output, error=last_step.error ) metadata = trajectory.trajectory_metadata( - title=last_step.tool.name if last_step.tool else None, content=trajectory_content.model_dump_json(), group_id=last_step.id + title=last_step.tool.name if last_step.tool else None, + content=trajectory_content.model_dump_json(), + group_id=last_step.id, ) yield metadata await context.store(AgentMessage(metadata=metadata)) diff --git a/agents/chat/uv.lock b/agents/chat/uv.lock index 1a82f6e17d..3884f26e96 100644 --- a/agents/chat/uv.lock +++ b/agents/chat/uv.lock @@ -4,19 +4,17 @@ requires-python = "==3.14.*" [[package]] name = "a2a-sdk" -version = "0.3.24" -source = { registry = "https://pypi.org/simple" } +version = "0.3.24.post37.dev0+dce3650" +source = { git = "https://github.com/a2aproject/a2a-python.git?rev=1.0-dev#dce36502b51f671ae0e0a926cc0ad8c208393329" } dependencies = [ { name = "google-api-core" }, + { name = "googleapis-common-protos" }, { name = "httpx" }, { name = "httpx-sse" }, + { name = "json-rpc" }, { name = "protobuf" }, { name = "pydantic" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ad/76/cefa956fb2d3911cb91552a1da8ce2dbb339f1759cb475e2982f0ae2332b/a2a_sdk-0.3.24.tar.gz", hash = "sha256:3581e6e8a854cd725808f5732f90b7978e661b6d4e227a4755a8f063a3c1599d", size = 255550, upload-time = "2026-02-20T10:05:43.423Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/10/6e/cae5f0caea527b39c0abd7204d9416768764573c76649ca03cc345a372be/a2a_sdk-0.3.24-py3-none-any.whl", hash = "sha256:7b248767096bb55311f57deebf6b767349388d94c1b376c60cb8f6b715e053f6", size = 145752, upload-time = "2026-02-20T10:05:41.729Z" }, -] [package.optional-dependencies] grpc = [ @@ -65,7 +63,7 @@ dependencies = [ [package.metadata] requires-dist = [ - { name = "a2a-sdk", specifier = "==0.3.24" }, + { name = "a2a-sdk", git = "https://github.com/a2aproject/a2a-python.git?rev=1.0-dev" }, { name = "anyio", specifier = ">=4.9.0" }, { name = "async-lru", specifier = ">=2.0.4" }, { name = "asyncclick", specifier = ">=8.1.8" }, @@ -96,7 +94,7 @@ dev = [ { name = "pytest", specifier = ">=8.4.1" }, { name = "pytest-asyncio", specifier = ">=1.1.0" }, { name = "pytest-httpx", specifier = ">=0.35.0" }, - { name = "ruff", specifier = ">=0.12.3" }, + { name = "ruff", specifier = ">=0.15.0" }, ] [[package]] @@ -998,6 +996,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/29/c1/7cad04a5d6248a38656b0cdb267697e67b174fe21c61fb9bbfe0995591f4/json_repair-0.52.5-py3-none-any.whl", hash = "sha256:031a84536c93df1de3fb8c8554393da69111e375109cac3ff3d7c68158d68633", size = 26733, upload-time = "2025-11-06T16:09:26.532Z" }, ] +[[package]] +name = "json-rpc" +version = "1.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6d/9e/59f4a5b7855ced7346ebf40a2e9a8942863f644378d956f68bcef2c88b90/json-rpc-1.15.0.tar.gz", hash = "sha256:e6441d56c1dcd54241c937d0a2dcd193bdf0bdc539b5316524713f554b7f85b9", size = 28854, upload-time = "2023-06-11T09:45:49.078Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/9e/820c4b086ad01ba7d77369fb8b11470a01fac9b4977f02e18659cf378b6b/json_rpc-1.15.0-py2.py3-none-any.whl", hash = "sha256:4a4668bbbe7116feb4abbd0f54e64a4adcf4b8f648f19ffa0848ad0f6606a9bf", size = 39450, upload-time = "2023-06-11T09:45:47.136Z" }, +] + [[package]] name = "jsonref" version = "1.1.0" diff --git a/apps/agentstack-cli/uv.lock b/apps/agentstack-cli/uv.lock index 5be9055cf2..1ea8b9b150 100644 --- a/apps/agentstack-cli/uv.lock +++ b/apps/agentstack-cli/uv.lock @@ -4,19 +4,17 @@ requires-python = ">=3.13, <3.15" [[package]] name = "a2a-sdk" -version = "0.3.24" -source = { registry = "https://pypi.org/simple" } +version = "0.3.24.post37.dev0+dce3650" +source = { git = "https://github.com/a2aproject/a2a-python.git?rev=1.0-dev#dce36502b51f671ae0e0a926cc0ad8c208393329" } dependencies = [ { name = "google-api-core" }, + { name = "googleapis-common-protos" }, { name = "httpx" }, { name = "httpx-sse" }, + { name = "json-rpc" }, { name = "protobuf" }, { name = "pydantic" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ad/76/cefa956fb2d3911cb91552a1da8ce2dbb339f1759cb475e2982f0ae2332b/a2a_sdk-0.3.24.tar.gz", hash = "sha256:3581e6e8a854cd725808f5732f90b7978e661b6d4e227a4755a8f063a3c1599d", size = 255550, upload-time = "2026-02-20T10:05:43.423Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/10/6e/cae5f0caea527b39c0abd7204d9416768764573c76649ca03cc345a372be/a2a_sdk-0.3.24-py3-none-any.whl", hash = "sha256:7b248767096bb55311f57deebf6b767349388d94c1b376c60cb8f6b715e053f6", size = 145752, upload-time = "2026-02-20T10:05:41.729Z" }, -] [[package]] name = "agentstack-cli" @@ -110,7 +108,7 @@ dependencies = [ [package.metadata] requires-dist = [ - { name = "a2a-sdk", specifier = "==0.3.24" }, + { name = "a2a-sdk", git = "https://github.com/a2aproject/a2a-python.git?rev=1.0-dev" }, { name = "anyio", specifier = ">=4.9.0" }, { name = "async-lru", specifier = ">=2.0.4" }, { name = "asyncclick", specifier = ">=8.1.8" }, @@ -672,6 +670,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/0a/ae/7435288ab8b3059823afa48508ddf658c27d96deb8a978498103ccd71ca8/jsf-0.11.2-py3-none-any.whl", hash = "sha256:b4472c8c2d776eb3e0bb08368caa6ae0ead7ea78b20653facc07b6d93768612c", size = 49322, upload-time = "2024-03-26T02:04:37.013Z" }, ] +[[package]] +name = "json-rpc" +version = "1.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6d/9e/59f4a5b7855ced7346ebf40a2e9a8942863f644378d956f68bcef2c88b90/json-rpc-1.15.0.tar.gz", hash = "sha256:e6441d56c1dcd54241c937d0a2dcd193bdf0bdc539b5316524713f554b7f85b9", size = 28854, upload-time = "2023-06-11T09:45:49.078Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/9e/820c4b086ad01ba7d77369fb8b11470a01fac9b4977f02e18659cf378b6b/json_rpc-1.15.0-py2.py3-none-any.whl", hash = "sha256:4a4668bbbe7116feb4abbd0f54e64a4adcf4b8f648f19ffa0848ad0f6606a9bf", size = 39450, upload-time = "2023-06-11T09:45:47.136Z" }, +] + [[package]] name = "jsonschema" version = "4.26.0" diff --git a/apps/agentstack-sdk-py/.vscode/launch.json b/apps/agentstack-sdk-py/.vscode/launch.json new file mode 100644 index 0000000000..603ed379e5 --- /dev/null +++ b/apps/agentstack-sdk-py/.vscode/launch.json @@ -0,0 +1,26 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "debug-file", + "type": "debugpy", + "justMyCode": false, + "request": "launch", + "program": "${file}", + }, + { + "name": "Python: Debug Tests", + "type": "debugpy", + "request": "launch", + "program": "${file}", + "purpose": [ + "debug-test" + ], + "console": "integratedTerminal", + "justMyCode": false, + "presentation": { + "hidden": true, // keep original launch order in 'run and debug' tab + } + } + ] +} \ No newline at end of file diff --git a/apps/agentstack-sdk-py/a2a.proto b/apps/agentstack-sdk-py/a2a.proto new file mode 100644 index 0000000000..92b76187a4 --- /dev/null +++ b/apps/agentstack-sdk-py/a2a.proto @@ -0,0 +1,807 @@ +// Older protoc compilers don't understand edition yet. +syntax = "proto3"; +package lf.a2a.v1; + +import "google/api/annotations.proto"; +import "google/api/client.proto"; +import "google/api/field_behavior.proto"; +import "google/protobuf/empty.proto"; +import "google/protobuf/struct.proto"; +import "google/protobuf/timestamp.proto"; + +option csharp_namespace = "Lf.A2a.V1"; +option go_package = "google.golang.org/lf/a2a/v1"; +option java_multiple_files = true; +option java_outer_classname = "A2A"; +option java_package = "com.google.lf.a2a.v1"; + +// Provides operations for interacting with agents using the A2A protocol. +service A2AService { + // Sends a message to an agent. + rpc SendMessage(SendMessageRequest) returns (SendMessageResponse) { + option (google.api.http) = { + post: "/message:send" + body: "*" + additional_bindings: { + post: "/{tenant}/message:send" + body: "*" + } + }; + } + // Sends a streaming message to an agent, allowing for real-time interaction and status updates. + // Streaming version of `SendMessage` + rpc SendStreamingMessage(SendMessageRequest) returns (stream StreamResponse) { + option (google.api.http) = { + post: "/message:stream" + body: "*" + additional_bindings: { + post: "/{tenant}/message:stream" + body: "*" + } + }; + } + + // Gets the latest state of a task. + rpc GetTask(GetTaskRequest) returns (Task) { + option (google.api.http) = { + get: "/tasks/{id=*}" + additional_bindings: { + get: "/{tenant}/tasks/{id=*}" + } + }; + option (google.api.method_signature) = "id"; + } + // Lists tasks that match the specified filter. + rpc ListTasks(ListTasksRequest) returns (ListTasksResponse) { + option (google.api.http) = { + get: "/tasks" + additional_bindings: { + get: "/{tenant}/tasks" + } + }; + } + // Cancels a task in progress. + rpc CancelTask(CancelTaskRequest) returns (Task) { + option (google.api.http) = { + post: "/tasks/{id=*}:cancel" + body: "*" + additional_bindings: { + post: "/{tenant}/tasks/{id=*}:cancel" + body: "*" + } + }; + } + // Subscribes to task updates for tasks not in a terminal state. + // Returns `UnsupportedOperationError` if the task is already in a terminal state (completed, failed, canceled, rejected). + rpc SubscribeToTask(SubscribeToTaskRequest) returns (stream StreamResponse) { + option (google.api.http) = { + get: "/tasks/{id=*}:subscribe" + additional_bindings: { + get: "/{tenant}/tasks/{id=*}:subscribe" + } + }; + } + + // (-- api-linter: client-libraries::4232::required-fields=disabled + // api-linter: core::0133::method-signature=disabled + // aip.dev/not-precedent: method_signature preserved for backwards compatibility --) + // Creates a push notification config for a task. + rpc CreateTaskPushNotificationConfig(CreateTaskPushNotificationConfigRequest) returns (TaskPushNotificationConfig) { + option (google.api.http) = { + post: "/tasks/{task_id=*}/pushNotificationConfigs" + body: "config" + additional_bindings: { + post: "/{tenant}/tasks/{task_id=*}/pushNotificationConfigs" + body: "config" + } + }; + option (google.api.method_signature) = "task_id,config"; + } + // Gets a push notification config for a task. + rpc GetTaskPushNotificationConfig(GetTaskPushNotificationConfigRequest) returns (TaskPushNotificationConfig) { + option (google.api.http) = { + get: "/tasks/{task_id=*}/pushNotificationConfigs/{id=*}" + additional_bindings: { + get: "/{tenant}/tasks/{task_id=*}/pushNotificationConfigs/{id=*}" + } + }; + option (google.api.method_signature) = "task_id,id"; + } + // Get a list of push notifications configured for a task. + rpc ListTaskPushNotificationConfigs(ListTaskPushNotificationConfigsRequest) returns (ListTaskPushNotificationConfigsResponse) { + option (google.api.http) = { + get: "/tasks/{task_id=*}/pushNotificationConfigs" + additional_bindings: { + get: "/{tenant}/tasks/{task_id=*}/pushNotificationConfigs" + } + }; + option (google.api.method_signature) = "task_id"; + } + // Gets the extended agent card for the authenticated agent. + rpc GetExtendedAgentCard(GetExtendedAgentCardRequest) returns (AgentCard) { + option (google.api.http) = { + get: "/extendedAgentCard" + additional_bindings: { + get: "/{tenant}/extendedAgentCard" + } + }; + } + // Deletes a push notification config for a task. + rpc DeleteTaskPushNotificationConfig(DeleteTaskPushNotificationConfigRequest) returns (google.protobuf.Empty) { + option (google.api.http) = { + delete: "/tasks/{task_id=*}/pushNotificationConfigs/{id=*}" + additional_bindings: { + delete: "/{tenant}/tasks/{task_id=*}/pushNotificationConfigs/{id=*}" + } + }; + option (google.api.method_signature) = "task_id,id"; + } +} + +// Configuration of a send message request. +message SendMessageConfiguration { + // A list of media types the client is prepared to accept for response parts. + // Agents SHOULD use this to tailor their output. + repeated string accepted_output_modes = 1; + // Configuration for the agent to send push notifications for task updates. + PushNotificationConfig push_notification_config = 2; + // The maximum number of most recent messages from the task's history to retrieve in + // the response. An unset value means the client does not impose any limit. A + // value of zero is a request to not include any messages. The server MUST NOT + // return more messages than the provided value, but MAY apply a lower limit. + optional int32 history_length = 3; + // If `true`, the operation MUST wait until the task reaches a terminal state + // (`COMPLETED`, `FAILED`, `CANCELED`, `REJECTED`) or an interrupted state + // (`INPUT_REQUIRED`, `AUTH_REQUIRED`) before returning. Default is `false`. + bool blocking = 4; +} + +// `Task` is the core unit of action for A2A. It has a current status +// and when results are created for the task they are stored in the +// artifact. If there are multiple turns for a task, these are stored in +// history. +message Task { + // Unique identifier (e.g. UUID) for the task, generated by the server for a + // new task. + string id = 1 [(google.api.field_behavior) = REQUIRED]; + // Unique identifier (e.g. UUID) for the contextual collection of interactions + // (tasks and messages). Created by the A2A server. + string context_id = 2 [(google.api.field_behavior) = REQUIRED]; + // The current status of a `Task`, including `state` and a `message`. + TaskStatus status = 3 [(google.api.field_behavior) = REQUIRED]; + // A set of output artifacts for a `Task`. + repeated Artifact artifacts = 4; + // protolint:disable REPEATED_FIELD_NAMES_PLURALIZED + // The history of interactions from a `Task`. + repeated Message history = 5; + // protolint:enable REPEATED_FIELD_NAMES_PLURALIZED + // A key/value object to store custom metadata about a task. + google.protobuf.Struct metadata = 6; +} + +// Defines the possible lifecycle states of a `Task`. +enum TaskState { + // The task is in an unknown or indeterminate state. + TASK_STATE_UNSPECIFIED = 0; + // Indicates that a task has been successfully submitted and acknowledged. + TASK_STATE_SUBMITTED = 1; + // Indicates that a task is actively being processed by the agent. + TASK_STATE_WORKING = 2; + // Indicates that a task has finished successfully. This is a terminal state. + TASK_STATE_COMPLETED = 3; + // Indicates that a task has finished with an error. This is a terminal state. + TASK_STATE_FAILED = 4; + // Indicates that a task was canceled before completion. This is a terminal state. + TASK_STATE_CANCELED = 5; + // Indicates that the agent requires additional user input to proceed. This is an interrupted state. + TASK_STATE_INPUT_REQUIRED = 6; + // Indicates that the agent has decided to not perform the task. + // This may be done during initial task creation or later once an agent + // has determined it can't or won't proceed. This is a terminal state. + TASK_STATE_REJECTED = 7; + // Indicates that authentication is required to proceed. This is an interrupted state. + TASK_STATE_AUTH_REQUIRED = 8; +} + +// A container for the status of a task +message TaskStatus { + // The current state of this task. + TaskState state = 1 [(google.api.field_behavior) = REQUIRED]; + // A message associated with the status. + Message message = 2; + // ISO 8601 Timestamp when the status was recorded. + // Example: "2023-10-27T10:00:00Z" + google.protobuf.Timestamp timestamp = 3; +} + +// `Part` represents a container for a section of communication content. +// Parts can be purely textual, some sort of file (image, video, etc) or +// a structured data blob (i.e. JSON). +message Part { + oneof content { + // The string content of the `text` part. + string text = 1; + // The `raw` byte content of a file. In JSON serialization, this is encoded as a base64 string. + bytes raw = 2; + // A `url` pointing to the file's content. + string url = 3; + // Arbitrary structured `data` as a JSON value (object, array, string, number, boolean, or null). + google.protobuf.Value data = 4; + } + // Optional. metadata associated with this part. + google.protobuf.Struct metadata = 5; + // An optional `filename` for the file (e.g., "document.pdf"). + string filename = 6; + // The `media_type` (MIME type) of the part content (e.g., "text/plain", "application/json", "image/png"). + // This field is available for all part types. + string media_type = 7; +} + +// Defines the sender of a message in A2A protocol communication. +enum Role { + // The role is unspecified. + ROLE_UNSPECIFIED = 0; + // The message is from the client to the server. + ROLE_USER = 1; + // The message is from the server to the client. + ROLE_AGENT = 2; +} + +// `Message` is one unit of communication between client and server. It can be +// associated with a context and/or a task. For server messages, `context_id` must +// be provided, and `task_id` only if a task was created. For client messages, both +// fields are optional, with the caveat that if both are provided, they have to +// match (the `context_id` has to be the one that is set on the task). If only +// `task_id` is provided, the server will infer `context_id` from it. +message Message { + // The unique identifier (e.g. UUID) of the message. This is created by the message creator. + string message_id = 1 [(google.api.field_behavior) = REQUIRED]; + // Optional. The context id of the message. If set, the message will be associated with the given context. + string context_id = 2; + // Optional. The task id of the message. If set, the message will be associated with the given task. + string task_id = 3; + // Identifies the sender of the message. + Role role = 4 [(google.api.field_behavior) = REQUIRED]; + // Parts is the container of the message content. + repeated Part parts = 5 [(google.api.field_behavior) = REQUIRED]; + // Optional. Any metadata to provide along with the message. + google.protobuf.Struct metadata = 6; + // The URIs of extensions that are present or contributed to this Message. + repeated string extensions = 7; + // A list of task IDs that this message references for additional context. + repeated string reference_task_ids = 8; +} + +// Artifacts represent task outputs. +message Artifact { + // Unique identifier (e.g. UUID) for the artifact. It must be unique within a task. + string artifact_id = 1 [(google.api.field_behavior) = REQUIRED]; + // A human readable name for the artifact. + string name = 2; + // Optional. A human readable description of the artifact. + string description = 3; + // The content of the artifact. Must contain at least one part. + repeated Part parts = 4 [(google.api.field_behavior) = REQUIRED]; + // Optional. Metadata included with the artifact. + google.protobuf.Struct metadata = 5; + // The URIs of extensions that are present or contributed to this Artifact. + repeated string extensions = 6; +} + +// An event sent by the agent to notify the client of a change in a task's status. +message TaskStatusUpdateEvent { + // The ID of the task that has changed. + string task_id = 1 [(google.api.field_behavior) = REQUIRED]; + // The ID of the context that the task belongs to. + string context_id = 2 [(google.api.field_behavior) = REQUIRED]; + // The new status of the task. + TaskStatus status = 3 [(google.api.field_behavior) = REQUIRED]; + // Optional. Metadata associated with the task update. + google.protobuf.Struct metadata = 4; +} + +// A task delta where an artifact has been generated. +message TaskArtifactUpdateEvent { + // The ID of the task for this artifact. + string task_id = 1 [(google.api.field_behavior) = REQUIRED]; + // The ID of the context that this task belongs to. + string context_id = 2 [(google.api.field_behavior) = REQUIRED]; + // The artifact that was generated or updated. + Artifact artifact = 3 [(google.api.field_behavior) = REQUIRED]; + // If true, the content of this artifact should be appended to a previously + // sent artifact with the same ID. + bool append = 4; + // If true, this is the final chunk of the artifact. + bool last_chunk = 5; + // Optional. Metadata associated with the artifact update. + google.protobuf.Struct metadata = 6; +} + +// Configuration for setting up push notifications for task updates. +message PushNotificationConfig { + // A unique identifier (e.g. UUID) for this push notification configuration. + string id = 1; + // The URL where the notification should be sent. + string url = 2 [(google.api.field_behavior) = REQUIRED]; + // A token unique for this task or session. + string token = 3; + // Authentication information required to send the notification. + AuthenticationInfo authentication = 4; +} + +// Defines authentication details, used for push notifications. +message AuthenticationInfo { + // HTTP Authentication Scheme from the [IANA registry](https://www.iana.org/assignments/http-authschemes/). + // Examples: `Bearer`, `Basic`, `Digest`. + // Scheme names are case-insensitive per [RFC 9110 Section 11.1](https://www.rfc-editor.org/rfc/rfc9110#section-11.1). + string scheme = 1 [(google.api.field_behavior) = REQUIRED]; + // Push Notification credentials. Format depends on the scheme (e.g., token for Bearer). + string credentials = 2; +} + +// Declares a combination of a target URL, transport and protocol version for interacting with the agent. +// This allows agents to expose the same functionality over multiple protocol binding mechanisms. +message AgentInterface { + // The URL where this interface is available. Must be a valid absolute HTTPS URL in production. + // Example: "https://api.example.com/a2a/v1", "https://grpc.example.com/a2a" + string url = 1 [(google.api.field_behavior) = REQUIRED]; + // The protocol binding supported at this URL. This is an open form string, to be + // easily extended for other protocol bindings. The core ones officially + // supported are `JSONRPC`, `GRPC` and `HTTP+JSON`. + string protocol_binding = 2 [(google.api.field_behavior) = REQUIRED]; + // Tenant ID to be used in the request when calling the agent. + string tenant = 3; + // The version of the A2A protocol this interface exposes. + // Use the latest supported minor version per major version. + // Examples: "0.3", "1.0" + string protocol_version = 4 [(google.api.field_behavior) = REQUIRED]; +} + +// A self-describing manifest for an agent. It provides essential +// metadata including the agent's identity, capabilities, skills, supported +// communication methods, and security requirements. +// Next ID: 20 +message AgentCard { + // A human readable name for the agent. + // Example: "Recipe Agent" + string name = 1 [(google.api.field_behavior) = REQUIRED]; + // A human-readable description of the agent, assisting users and other agents + // in understanding its purpose. + // Example: "Agent that helps users with recipes and cooking." + string description = 2 [(google.api.field_behavior) = REQUIRED]; + // Ordered list of supported interfaces. The first entry is preferred. + repeated AgentInterface supported_interfaces = 3 [(google.api.field_behavior) = REQUIRED]; + // The service provider of the agent. + AgentProvider provider = 4; + // The version of the agent. + // Example: "1.0.0" + string version = 5 [(google.api.field_behavior) = REQUIRED]; + // A URL providing additional documentation about the agent. + optional string documentation_url = 6; + // A2A Capability set supported by the agent. + AgentCapabilities capabilities = 7 [(google.api.field_behavior) = REQUIRED]; + // The security scheme details used for authenticating with this agent. + map security_schemes = 8; + // Security requirements for contacting the agent. + repeated SecurityRequirement security_requirements = 9; + // protolint:enable REPEATED_FIELD_NAMES_PLURALIZED + // The set of interaction modes that the agent supports across all skills. + // This can be overridden per skill. Defined as media types. + repeated string default_input_modes = 10 [(google.api.field_behavior) = REQUIRED]; + // The media types supported as outputs from this agent. + repeated string default_output_modes = 11 [(google.api.field_behavior) = REQUIRED]; + // Skills represent the abilities of an agent. + // It is largely a descriptive concept but represents a more focused set of behaviors that the + // agent is likely to succeed at. + repeated AgentSkill skills = 12 [(google.api.field_behavior) = REQUIRED]; + // JSON Web Signatures computed for this `AgentCard`. + repeated AgentCardSignature signatures = 13; + // Optional. A URL to an icon for the agent. + optional string icon_url = 14; +} + +// Represents the service provider of an agent. +message AgentProvider { + // A URL for the agent provider's website or relevant documentation. + // Example: "https://ai.google.dev" + string url = 1 [(google.api.field_behavior) = REQUIRED]; + // The name of the agent provider's organization. + // Example: "Google" + string organization = 2 [(google.api.field_behavior) = REQUIRED]; +} + +// Defines optional capabilities supported by an agent. +message AgentCapabilities { + // Indicates if the agent supports streaming responses. + optional bool streaming = 1; + // Indicates if the agent supports sending push notifications for asynchronous task updates. + optional bool push_notifications = 2; + // A list of protocol extensions supported by the agent. + repeated AgentExtension extensions = 3; + // Indicates if the agent supports providing an extended agent card when authenticated. + optional bool extended_agent_card = 4; +} + +// A declaration of a protocol extension supported by an Agent. +message AgentExtension { + // The unique URI identifying the extension. + string uri = 1; + // A human-readable description of how this agent uses the extension. + string description = 2; + // If true, the client must understand and comply with the extension's requirements. + bool required = 3; + // Optional. Extension-specific configuration parameters. + google.protobuf.Struct params = 4; +} + +// Represents a distinct capability or function that an agent can perform. +message AgentSkill { + // A unique identifier for the agent's skill. + string id = 1 [(google.api.field_behavior) = REQUIRED]; + // A human-readable name for the skill. + string name = 2 [(google.api.field_behavior) = REQUIRED]; + // A detailed description of the skill. + string description = 3 [(google.api.field_behavior) = REQUIRED]; + // A set of keywords describing the skill's capabilities. + repeated string tags = 4 [(google.api.field_behavior) = REQUIRED]; + // Example prompts or scenarios that this skill can handle. + repeated string examples = 5; + // The set of supported input media types for this skill, overriding the agent's defaults. + repeated string input_modes = 6; + // The set of supported output media types for this skill, overriding the agent's defaults. + repeated string output_modes = 7; + // Security schemes necessary for this skill. + repeated SecurityRequirement security_requirements = 8; +} + +// AgentCardSignature represents a JWS signature of an AgentCard. +// This follows the JSON format of an RFC 7515 JSON Web Signature (JWS). +message AgentCardSignature { + // (-- api-linter: core::0140::reserved-words=disabled + // aip.dev/not-precedent: Backwards compatibility --) + // Required. The protected JWS header for the signature. This is always a + // base64url-encoded JSON object. + string protected = 1 [(google.api.field_behavior) = REQUIRED]; + // Required. The computed signature, base64url-encoded. + string signature = 2 [(google.api.field_behavior) = REQUIRED]; + // The unprotected JWS header values. + google.protobuf.Struct header = 3; +} + +// A container associating a push notification configuration with a specific task. +message TaskPushNotificationConfig { + // Optional. Tenant ID. + string tenant = 1; + // The ID of the task this configuration is associated with. + string task_id = 2 [(google.api.field_behavior) = REQUIRED]; + // The push notification configuration details. + PushNotificationConfig push_notification_config = 3 [(google.api.field_behavior) = REQUIRED]; +} + +// protolint:disable REPEATED_FIELD_NAMES_PLURALIZED +// A list of strings. +message StringList { + // The individual string values. + repeated string list = 1; +} +// protolint:enable REPEATED_FIELD_NAMES_PLURALIZED + +// Defines the security requirements for an agent. +message SecurityRequirement { + // A map of security schemes to the required scopes. + map schemes = 1; +} + +// Defines a security scheme that can be used to secure an agent's endpoints. +// This is a discriminated union type based on the OpenAPI 3.2 Security Scheme Object. +// See: https://spec.openapis.org/oas/v3.2.0.html#security-scheme-object +message SecurityScheme { + oneof scheme { + // API key-based authentication. + APIKeySecurityScheme api_key_security_scheme = 1; + // HTTP authentication (Basic, Bearer, etc.). + HTTPAuthSecurityScheme http_auth_security_scheme = 2; + // OAuth 2.0 authentication. + OAuth2SecurityScheme oauth2_security_scheme = 3; + // OpenID Connect authentication. + OpenIdConnectSecurityScheme open_id_connect_security_scheme = 4; + // Mutual TLS authentication. + MutualTlsSecurityScheme mtls_security_scheme = 5; + } +} + +// Defines a security scheme using an API key. +message APIKeySecurityScheme { + // An optional description for the security scheme. + string description = 1; + // The location of the API key. Valid values are "query", "header", or "cookie". + string location = 2 [(google.api.field_behavior) = REQUIRED]; + // The name of the header, query, or cookie parameter to be used. + string name = 3 [(google.api.field_behavior) = REQUIRED]; +} + +// Defines a security scheme using HTTP authentication. +message HTTPAuthSecurityScheme { + // An optional description for the security scheme. + string description = 1; + // The name of the HTTP Authentication scheme to be used in the Authorization header, + // as defined in RFC7235 (e.g., "Bearer"). + // This value should be registered in the IANA Authentication Scheme registry. + string scheme = 2 [(google.api.field_behavior) = REQUIRED]; + // A hint to the client to identify how the bearer token is formatted (e.g., "JWT"). + // Primarily for documentation purposes. + string bearer_format = 3; +} + +// Defines a security scheme using OAuth 2.0. +message OAuth2SecurityScheme { + // An optional description for the security scheme. + string description = 1; + // An object containing configuration information for the supported OAuth 2.0 flows. + OAuthFlows flows = 2 [(google.api.field_behavior) = REQUIRED]; + // URL to the OAuth2 authorization server metadata [RFC 8414](https://datatracker.ietf.org/doc/html/rfc8414). + // TLS is required. + string oauth2_metadata_url = 3; +} + +// Defines a security scheme using OpenID Connect. +message OpenIdConnectSecurityScheme { + // An optional description for the security scheme. + string description = 1; + // The [OpenID Connect Discovery URL](https://openid.net/specs/openid-connect-discovery-1_0.html) for the OIDC provider's metadata. + string open_id_connect_url = 2 [(google.api.field_behavior) = REQUIRED]; +} + +// Defines a security scheme using mTLS authentication. +message MutualTlsSecurityScheme { + // An optional description for the security scheme. + string description = 1; +} + +// Defines the configuration for the supported OAuth 2.0 flows. +message OAuthFlows { + oneof flow { + // Configuration for the OAuth Authorization Code flow. + AuthorizationCodeOAuthFlow authorization_code = 1; + // Configuration for the OAuth Client Credentials flow. + ClientCredentialsOAuthFlow client_credentials = 2; + // Deprecated: Use Authorization Code + PKCE instead. + ImplicitOAuthFlow implicit = 3 [deprecated = true]; + // Deprecated: Use Authorization Code + PKCE or Device Code. + PasswordOAuthFlow password = 4 [deprecated = true]; + // Configuration for the OAuth Device Code flow. + DeviceCodeOAuthFlow device_code = 5; + } +} + +// Defines configuration details for the OAuth 2.0 Authorization Code flow. +message AuthorizationCodeOAuthFlow { + // The authorization URL to be used for this flow. + string authorization_url = 1 [(google.api.field_behavior) = REQUIRED]; + // The token URL to be used for this flow. + string token_url = 2 [(google.api.field_behavior) = REQUIRED]; + // The URL to be used for obtaining refresh tokens. + string refresh_url = 3; + // The available scopes for the OAuth2 security scheme. + map scopes = 4 [(google.api.field_behavior) = REQUIRED]; + // Indicates if PKCE (RFC 7636) is required for this flow. + // PKCE should always be used for public clients and is recommended for all clients. + bool pkce_required = 5; +} + +// Defines configuration details for the OAuth 2.0 Client Credentials flow. +message ClientCredentialsOAuthFlow { + // The token URL to be used for this flow. + string token_url = 1 [(google.api.field_behavior) = REQUIRED]; + // The URL to be used for obtaining refresh tokens. + string refresh_url = 2; + // The available scopes for the OAuth2 security scheme. + map scopes = 3 [(google.api.field_behavior) = REQUIRED]; +} + +// Deprecated: Use Authorization Code + PKCE instead. +message ImplicitOAuthFlow { + // The authorization URL to be used for this flow. This MUST be in the + // form of a URL. The OAuth2 standard requires the use of TLS + string authorization_url = 1; + // The URL to be used for obtaining refresh tokens. This MUST be in the + // form of a URL. The OAuth2 standard requires the use of TLS. + string refresh_url = 2; + // The available scopes for the OAuth2 security scheme. A map between the + // scope name and a short description for it. The map MAY be empty. + map scopes = 3; +} + +// Deprecated: Use Authorization Code + PKCE or Device Code. +message PasswordOAuthFlow { + // The token URL to be used for this flow. This MUST be in the form of a URL. + // The OAuth2 standard requires the use of TLS. + string token_url = 1; + // The URL to be used for obtaining refresh tokens. This MUST be in the + // form of a URL. The OAuth2 standard requires the use of TLS. + string refresh_url = 2; + // The available scopes for the OAuth2 security scheme. A map between the + // scope name and a short description for it. The map MAY be empty. + map scopes = 3; +} + +// Defines configuration details for the OAuth 2.0 Device Code flow (RFC 8628). +// This flow is designed for input-constrained devices such as IoT devices, +// and CLI tools where the user authenticates on a separate device. +message DeviceCodeOAuthFlow { + // The device authorization endpoint URL. + string device_authorization_url = 1 [(google.api.field_behavior) = REQUIRED]; + // The token URL to be used for this flow. + string token_url = 2 [(google.api.field_behavior) = REQUIRED]; + // The URL to be used for obtaining refresh tokens. + string refresh_url = 3; + // The available scopes for the OAuth2 security scheme. + map scopes = 4 [(google.api.field_behavior) = REQUIRED]; +} + +// Represents a request for the `SendMessage` method. +message SendMessageRequest { + // Optional. Tenant ID, provided as a path parameter. + string tenant = 1; + // The message to send to the agent. + Message message = 2 [(google.api.field_behavior) = REQUIRED]; + // Configuration for the send request. + SendMessageConfiguration configuration = 3; + // A flexible key-value map for passing additional context or parameters. + google.protobuf.Struct metadata = 4; +} + +// Represents a request for the `GetTask` method. +message GetTaskRequest { + // Optional. Tenant ID, provided as a path parameter. + string tenant = 1; + // The resource ID of the task to retrieve. + string id = 2 [(google.api.field_behavior) = REQUIRED]; + // The maximum number of most recent messages from the task's history to retrieve. An + // unset value means the client does not impose any limit. A value of zero is + // a request to not include any messages. The server MUST NOT return more + // messages than the provided value, but MAY apply a lower limit. + optional int32 history_length = 3; +} + +// Parameters for listing tasks with optional filtering criteria. +message ListTasksRequest { + // Tenant ID, provided as a path parameter. + string tenant = 1; + // Filter tasks by context ID to get tasks from a specific conversation or session. + string context_id = 2; + // Filter tasks by their current status state. + TaskState status = 3; + // The maximum number of tasks to return. The service may return fewer than this value. + // If unspecified, at most 50 tasks will be returned. + // The minimum value is 1. + // The maximum value is 100. + optional int32 page_size = 4; + // A page token, received from a previous `ListTasks` call. + // `ListTasksResponse.next_page_token`. + // Provide this to retrieve the subsequent page. + string page_token = 5; + // The maximum number of messages to include in each task's history. + optional int32 history_length = 6; + // Filter tasks which have a status updated after the provided timestamp in ISO 8601 format (e.g., "2023-10-27T10:00:00Z"). + // Only tasks with a status timestamp time greater than or equal to this value will be returned. + google.protobuf.Timestamp status_timestamp_after = 7; + // Whether to include artifacts in the returned tasks. + // Defaults to false to reduce payload size. + optional bool include_artifacts = 8; +} + +// Result object for `ListTasks` method containing an array of tasks and pagination information. +message ListTasksResponse { + // Array of tasks matching the specified criteria. + repeated Task tasks = 1 [(google.api.field_behavior) = REQUIRED]; + // A token to retrieve the next page of results, or empty if there are no more results in the list. + string next_page_token = 2 [(google.api.field_behavior) = REQUIRED]; + // The page size used for this response. + int32 page_size = 3 [(google.api.field_behavior) = REQUIRED]; + // Total number of tasks available (before pagination). + int32 total_size = 4 [(google.api.field_behavior) = REQUIRED]; +} + +// Represents a request for the `CancelTask` method. +message CancelTaskRequest { + // Optional. Tenant ID, provided as a path parameter. + string tenant = 1; + // The resource ID of the task to cancel. + string id = 2 [(google.api.field_behavior) = REQUIRED]; + // A flexible key-value map for passing additional context or parameters. + google.protobuf.Struct metadata = 3; +} + +// Represents a request for the `GetTaskPushNotificationConfig` method. +message GetTaskPushNotificationConfigRequest { + // Optional. Tenant ID, provided as a path parameter. + string tenant = 1; + // The parent task resource ID. + string task_id = 2 [(google.api.field_behavior) = REQUIRED]; + // The resource ID of the configuration to retrieve. + string id = 3 [(google.api.field_behavior) = REQUIRED]; +} + +// Represents a request for the `DeleteTaskPushNotificationConfig` method. +message DeleteTaskPushNotificationConfigRequest { + // Optional. Tenant ID, provided as a path parameter. + string tenant = 1; + // The parent task resource ID. + string task_id = 2 [(google.api.field_behavior) = REQUIRED]; + // The resource ID of the configuration to delete. + string id = 3 [(google.api.field_behavior) = REQUIRED]; +} + +// Represents a request for the `CreateTaskPushNotificationConfig` method. +message CreateTaskPushNotificationConfigRequest { + // Optional. Tenant ID, provided as a path parameter. + string tenant = 1; + // The parent task resource ID. + string task_id = 2 [(google.api.field_behavior) = REQUIRED]; + // The configuration to create. + PushNotificationConfig config = 3 [(google.api.field_behavior) = REQUIRED]; +} + +// Represents a request for the `SubscribeToTask` method. +message SubscribeToTaskRequest { + // Optional. Tenant ID, provided as a path parameter. + string tenant = 1; + // The resource ID of the task to subscribe to. + string id = 2 [(google.api.field_behavior) = REQUIRED]; +} + +// Represents a request for the `ListTaskPushNotificationConfigs` method. +message ListTaskPushNotificationConfigsRequest { + // Optional. Tenant ID, provided as a path parameter. + string tenant = 4; + // The parent task resource ID. + string task_id = 1 [(google.api.field_behavior) = REQUIRED]; + + // The maximum number of configurations to return. + int32 page_size = 2; + + // A page token received from a previous `ListTaskPushNotificationConfigsRequest` call. + string page_token = 3; +} + +// Represents a request for the `GetExtendedAgentCard` method. +message GetExtendedAgentCardRequest { + // Optional. Tenant ID, provided as a path parameter. + string tenant = 1; +} + +// Represents the response for the `SendMessage` method. +message SendMessageResponse { + // The payload of the response. + oneof payload { + // The task created or updated by the message. + Task task = 1; + // A message from the agent. + Message message = 2; + } +} + +// A wrapper object used in streaming operations to encapsulate different types of response data. +message StreamResponse { + // The payload of the stream response. + oneof payload { + // A Task object containing the current state of the task. + Task task = 1; + // A Message object containing a message from the agent. + Message message = 2; + // An event indicating a task status update. + TaskStatusUpdateEvent status_update = 3; + // An event indicating a task artifact update. + TaskArtifactUpdateEvent artifact_update = 4; + } +} + +// Represents a successful response for the `ListTaskPushNotificationConfigs` +// method. +message ListTaskPushNotificationConfigsResponse { + // The list of push notification configurations. + repeated TaskPushNotificationConfig configs = 1; + // A token to retrieve the next page of results, or empty if there are no more results in the list. + string next_page_token = 2; +} diff --git a/apps/agentstack-sdk-py/examples/check_validation.py b/apps/agentstack-sdk-py/examples/check_validation.py new file mode 100644 index 0000000000..486be41521 --- /dev/null +++ b/apps/agentstack-sdk-py/examples/check_validation.py @@ -0,0 +1,28 @@ +from a2a.types import Message, Part +from google.protobuf import descriptor + +print("Is Message a protobuf message?", hasattr(Message, "DESCRIPTOR")) +if hasattr(Message, "DESCRIPTOR"): + desc = Message.DESCRIPTOR + try: + print(f"Syntax: {desc.file.syntax}") + except AttributeError: + print("Syntax: Unknown") + + field = desc.fields_by_name.get("message_id") + if field: + # LABEL_OPTIONAL = 1, LABEL_REQUIRED = 2, LABEL_REPEATED = 3 + print(f"Field message_id label: {field.label}") + is_required = field.label == descriptor.FieldDescriptor.LABEL_REQUIRED + print(f"Is required? {is_required}") + else: + print("Field message_id not found") + + msg = Message(parts=[Part(text="hello")]) + print(f"Message initialized: {msg}") + print(f"IsInitialized: {msg.IsInitialized()}") + try: + msg.SerializeToString() + print("Serialization successful") + except Exception as e: + print(f"Serialization failed: {e}") diff --git a/apps/agentstack-sdk-py/examples/experiment.py b/apps/agentstack-sdk-py/examples/experiment.py new file mode 100644 index 0000000000..9b25377649 --- /dev/null +++ b/apps/agentstack-sdk-py/examples/experiment.py @@ -0,0 +1,6 @@ +from google.protobuf.json_format import MessageToDict +from a2a.types import Message, Part + +if __name__ == "__main__": + msg = Message(parts=[Part(text="hello")]) + print(MessageToDict(msg)) diff --git a/apps/agentstack-sdk-py/pyproject.toml b/apps/agentstack-sdk-py/pyproject.toml index 6cea7491dc..afbb53371f 100644 --- a/apps/agentstack-sdk-py/pyproject.toml +++ b/apps/agentstack-sdk-py/pyproject.toml @@ -82,3 +82,6 @@ project-includes = [ "**/*.py*", "**/*.ipynb", ] + +[tool.uv.sources] +a2a-sdk = { git = "https://github.com/a2aproject/a2a-python.git", rev = "1.0-dev" } diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/__init__.py b/apps/agentstack-sdk-py/src/agentstack_sdk/__init__.py index a1da4c8720..59e7c1932a 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/__init__.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/__init__.py @@ -3,6 +3,7 @@ from __future__ import annotations +import os from importlib.metadata import version from agentstack_sdk.util.pydantic import apply_compatibility_monkey_patching @@ -10,3 +11,7 @@ __version__ = version("agentstack-sdk") apply_compatibility_monkey_patching() +if os.getenv("AGENTSTACK_DONT_INJECT_A2A_VALIDATION", "").lower() not in {"true", "1"}: + from agentstack_sdk.a2a.types import _inject_validation + + _inject_validation() diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/auth/oauth/oauth.py b/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/auth/oauth/oauth.py index d974d27ed6..b038f062fc 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/auth/oauth/oauth.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/auth/oauth/oauth.py @@ -12,14 +12,14 @@ import pydantic from a2a.server.agent_execution import RequestContext from a2a.types import Message as A2AMessage -from a2a.types import Role, TextPart +from a2a.types import Part, Role from mcp.client.auth import OAuthClientProvider from mcp.shared.auth import OAuthClientMetadata from typing_extensions import override from agentstack_sdk.a2a.extensions.auth.oauth.storage import MemoryTokenStorageFactory, TokenStorageFactory from agentstack_sdk.a2a.extensions.base import BaseExtensionClient, BaseExtensionServer, BaseExtensionSpec -from agentstack_sdk.a2a.types import AgentMessage, AuthRequired, RunYieldResume +from agentstack_sdk.a2a.types import AgentMessage, AuthRequired, Metadata, RunYieldResume from agentstack_sdk.util.pydantic import REVEAL_SECRETS, SecureBaseModel __all__ = [ @@ -139,7 +139,7 @@ def create_auth_request(self, *, authorization_endpoint_url: pydantic.AnyUrl): data = AuthRequest(authorization_endpoint_url=authorization_endpoint_url) return AgentMessage( text="Authorization required", - metadata={self.spec.URI: data.model_dump(mode="json", context={REVEAL_SECRETS: True})}, + metadata=Metadata({self.spec.URI: data.model_dump(mode="json", context={REVEAL_SECRETS: True})}), ) def parse_auth_response(self, *, message: A2AMessage): @@ -162,8 +162,8 @@ def create_auth_response(self, *, task_id: str, redirect_uri: pydantic.AnyUrl): return A2AMessage( message_id=str(uuid.uuid4()), - role=Role.user, - parts=[TextPart(text="Authorization completed")], + role=Role.ROLE_USER, + parts=[Part(text="Authorization completed")], task_id=task_id, metadata={self.spec.URI: data.model_dump(mode="json", context={REVEAL_SECRETS: True})}, ) diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/base.py b/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/base.py index f77d95288f..22f83a7852 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/base.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/base.py @@ -16,6 +16,7 @@ from a2a.server.agent_execution.context import RequestContext from a2a.types import AgentCard, AgentExtension from a2a.types import Message as A2AMessage +from google.protobuf.json_format import MessageToDict from opentelemetry import trace from opentelemetry.trace import SpanKind from pydantic import BaseModel @@ -89,7 +90,7 @@ def from_agent_card(cls: type["BaseExtensionSpec"], agent: AgentCard) -> typing. """ if extensions := [x for x in agent.capabilities.extensions or [] if x.uri == cls.URI]: return cls( - params=pydantic.TypeAdapter(cls.Params).validate_python(extensions[0].params), + params=pydantic.TypeAdapter(cls.Params).validate_python(MessageToDict(extensions[0].params)), required=extensions[0].required or False, ) return None @@ -167,10 +168,11 @@ def parse_client_metadata(self, message: A2AMessage) -> MetadataFromClientT | No """ Server should use this method to retrieve extension-associated metadata from a message. """ + metadata = MessageToDict(message.metadata) return ( None - if not message.metadata or self.spec.URI not in message.metadata - else pydantic.TypeAdapter(self.MetadataFromClient).validate_python(message.metadata[self.spec.URI]) + if not metadata or self.spec.URI not in metadata + else pydantic.TypeAdapter(self.MetadataFromClient).validate_python(metadata[self.spec.URI]) ) def handle_incoming_message(self, message: A2AMessage, run_context: RunContext, request_context: RequestContext): diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/ui/canvas.py b/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/ui/canvas.py index 235987f11f..5b23731d39 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/ui/canvas.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/ui/canvas.py @@ -8,8 +8,9 @@ import pydantic from a2a.server.agent_execution.context import RequestContext -from a2a.types import Artifact, TextPart +from a2a.types import Artifact from a2a.types import Message as A2AMessage +from google.protobuf.json_format import ParseDict from typing_extensions import override if TYPE_CHECKING: @@ -35,12 +36,19 @@ class CanvasEditRequestMetadata(pydantic.BaseModel): artifact_id: str -class CanvasEditRequest(pydantic.BaseModel): +class CanvasEditRequest(pydantic.BaseModel, arbitrary_types_allowed=True): start_index: int end_index: int description: str artifact: Artifact + @pydantic.field_validator("artifact", mode="before") + @classmethod + def parse_artifact(cls, v): + if isinstance(v, dict): + return ParseDict(v, Artifact()) + return v + class CanvasExtensionSpec(NoParamsBaseExtensionSpec): URI: str = "https://a2a-extensions.agentstack.beeai.dev/ui/canvas/v1" @@ -50,7 +58,8 @@ class CanvasExtensionServer(BaseExtensionServer[CanvasExtensionSpec, CanvasEditR @override def handle_incoming_message(self, message: A2AMessage, run_context: RunContext, request_context: RequestContext): if message.metadata and self.spec.URI in message.metadata and message.parts: - message.parts = [part for part in message.parts if not isinstance(part.root, TextPart)] + message.parts.clear() + message.parts.extend([part for part in message.parts if "text" not in part]) super().handle_incoming_message(message, run_context, request_context) self.context = run_context diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/ui/citation.py b/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/ui/citation.py index 7adf1fe88e..0ca321b0dc 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/ui/citation.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/ui/citation.py @@ -7,7 +7,7 @@ from types import NoneType import pydantic -from a2a.types import DataPart, FilePart, Part, TextPart +from a2a.types import Part, Message from agentstack_sdk.a2a.extensions.base import ( BaseExtensionClient, @@ -65,10 +65,10 @@ def citation_metadata(self, *, citations: list[Citation]) -> Metadata: def message( self, text: str | None = None, - parts: list[Part | TextPart | FilePart | DataPart] | None = None, + parts: list[Part] | None = None, *, citations: list[Citation], - ) -> AgentMessage: + ) -> Message: return AgentMessage( text=text, parts=parts or [], diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/ui/error.py b/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/ui/error.py index dd3d8ebff5..50336901e8 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/ui/error.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/ui/error.py @@ -13,6 +13,7 @@ from typing import Any, Final import pydantic +from a2a.types import Message from agentstack_sdk.a2a.extensions.base import ( BaseExtensionClient, @@ -168,10 +169,7 @@ def error_metadata(self, error: BaseException) -> Metadata: } ) - def message( - self, - error: BaseException, - ) -> AgentMessage: + def message(self, error: BaseException) -> Message: """ Create an AgentMessage with error metadata and serialized text representation. diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/ui/trajectory.py b/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/ui/trajectory.py index 29fdbd19f2..eaf8b7c321 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/ui/trajectory.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/ui/trajectory.py @@ -7,7 +7,7 @@ from types import NoneType import pydantic -from a2a.types import DataPart, FilePart, Part, TextPart +from a2a.types import Part, Message from agentstack_sdk.a2a.extensions.base import ( BaseExtensionClient, @@ -57,10 +57,10 @@ def trajectory_metadata( def message( self, text: str | None = None, - parts: list[Part | TextPart | FilePart | DataPart] | None = None, + parts: list[Part] | None = None, trajectory_title: str | None = None, trajectory_content: str | None = None, - ) -> AgentMessage: + ) -> Message: return AgentMessage( text=text, parts=parts or [], diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/types.py b/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/types.py index ec8cc6569c..7ade5275b4 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/types.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/types.py @@ -2,15 +2,13 @@ # SPDX-License-Identifier: Apache-2.0 from __future__ import annotations +import functools +import sys import uuid -from typing import Literal, TypeAlias +from typing import TypeAlias from a2a.types import ( Artifact, - DataPart, - FilePart, - FileWithBytes, - FileWithUri, Message, Part, Role, @@ -18,9 +16,10 @@ TaskState, TaskStatus, TaskStatusUpdateEvent, - TextPart, ) -from pydantic import Field, model_validator +from google.api import field_behavior_pb2 +from google.protobuf import descriptor +from google.protobuf import message as _message from agentstack_sdk.types import JsonDict, JsonValue @@ -33,14 +32,9 @@ class Metadata(dict[str, JsonValue]): ... | Part | TaskStatus # includes InputRequired and AuthRequired (subclasses) | Artifact - | TextPart - | FilePart - | FileWithBytes - | FileWithUri | Metadata - | DataPart - | TaskArtifactUpdateEvent | TaskStatusUpdateEvent + | TaskArtifactUpdateEvent | str | JsonDict | Exception @@ -48,65 +42,207 @@ class Metadata(dict[str, JsonValue]): ... RunYieldResume: TypeAlias = Message | None -class AgentArtifact(Artifact): - artifact_id: str = Field(default_factory=lambda: str(uuid.uuid4())) - # pyrefly: ignore [bad-override] -- we intentionally broaden the base type - parts: list[Part | TextPart | FilePart | DataPart] - - @model_validator(mode="after") - def text_message_validate(self): - self.parts = [part if isinstance(part, Part) else Part(root=part) for part in self.parts] - return self - - -class ArtifactChunk(Artifact): - last_chunk: bool = False - # pyrefly: ignore [bad-override] -- we intentionally broaden the base type - parts: list[Part | TextPart | FilePart | DataPart] - - @model_validator(mode="after") - def text_message_validate(self): - self.parts = [part if isinstance(part, Part) else Part(root=part) for part in self.parts] - return self - - -class AgentMessage(Message): - message_id: str = Field(default_factory=lambda: str(uuid.uuid4())) - # pyrefly: ignore [bad-override] -- we treat this as read-only - role: Literal[Role.agent] = Role.agent - text: str | None = Field(default=None, exclude=True) - # pyrefly: ignore [bad-override] -- we intentionally broaden the base type - parts: list[Part | TextPart | FilePart | DataPart] = Field(default_factory=list) - - @model_validator(mode="after") - def text_message_validate(self): - self.parts = [part if isinstance(part, Part) else Part(root=part) for part in self.parts] - if self.parts and self.text is not None: - raise ValueError("Message cannot have both parts and text") - if self.text is not None: - self.parts.append(Part(root=TextPart(text=self.text))) - return self - - -class InputRequired(TaskStatus): - message: Message | None = None - # pyrefly: ignore [bad-override] -- we treat this as read-only - state: Literal[TaskState.input_required] = TaskState.input_required - text: str | None = Field(default=None, exclude=True) - parts: list[Part | TextPart | DataPart | FilePart] = Field(exclude=True, default_factory=list) - - @model_validator(mode="after") - def text_message_validate(self): - self.parts = [part if isinstance(part, Part) else Part(root=part) for part in self.parts] - if sum((self.message is not None, self.text is not None, bool(self.parts))) != 1: - raise ValueError("At most one of message, text, or parts must be provided.") - if self.text is not None: - self.message = AgentMessage(text=self.text) - elif self.parts: - self.message = AgentMessage(parts=self.parts) - return self - - -class AuthRequired(InputRequired): - # pyrefly: ignore [bad-override] -- we treat this as read-only - state: Literal[TaskState.auth_required] = TaskState.auth_required +def AgentArtifact( # noqa: N802 + parts: list[Part], + artifact_id: str | None = None, + name: str | None = None, + description: str | None = None, + metadata: Metadata | dict[str, JsonValue] | None = None, + extensions: list[str] | None = None, +) -> Artifact: + return Artifact( + artifact_id=artifact_id or str(uuid.uuid4()), + name=name, + description=description, + parts=parts, + metadata=metadata, + extensions=extensions, + ) + + +def ArtifactChunk( # noqa: N802 + parts: list[Part], + artifact_id: str, + name: str | None = None, + description: str | None = None, + metadata: Metadata | dict[str, JsonValue] | None = None, + extensions: list[str] | None = None, + last_chunk: bool = False, +) -> Artifact: + return Artifact( + artifact_id=artifact_id, + name=name, + description=description, + parts=parts, + metadata={"_last_chunk": last_chunk} | (metadata or Metadata()), + extensions=extensions, + ) + + +def AgentMessage( # noqa: N802 + text: str | None = None, + message_id: str | None = None, + parts: list[Part] | None = None, + metadata: Metadata | dict[str, JsonValue] | None = None, + extensions: list[str] | None = None, + reference_task_ids: list[str] | None = None, + role: Role = Role.ROLE_AGENT, + **kwargs, +) -> Message: + if text is not None and parts is not None: + raise ValueError("At most one of text or parts must be provided.") + + if text is not None: + parts = [*(parts or []), Part(text=text)] + return Message( + message_id=message_id or str(uuid.uuid4()), + parts=parts, + role=role, + metadata=metadata, + extensions=extensions, + reference_task_ids=reference_task_ids, + **kwargs, + ) + + +def InputRequired(message: Message | None = None, text: str | None = None, **kwargs) -> TaskStatus: # noqa: N802 + if message and text: + raise ValueError("At most one of message or text must be provided.") + if text is not None: + message = AgentMessage(text=text) + return TaskStatus(state=TaskState.TASK_STATE_INPUT_REQUIRED, message=message, **kwargs) + + +def AuthRequired(message: Message | None = None, text: str | None = None, **kwargs) -> TaskStatus: # noqa: N802 + if message and text: + raise ValueError("At most one of message or text must be provided.") + if text is not None: + message = AgentMessage(text=text) + return TaskStatus(state=TaskState.TASK_STATE_AUTH_REQUIRED, message=message, **kwargs) + + +def validate_message(message: _message.Message): + if problems := _validate_message(message): + raise ValueError("Invalid message:\n" + "\n".join(problems)) + + +def _validate_message(message: _message.Message, path: str = "") -> list[str]: + """ + Validates that fields marked as REQUIRED in the protobuf definition are set. + + Args: + message: The protobuf message to validate. + path: The path to the message (used for recursive validation). + + Returns: + A list of error strings describing missing required fields. + """ + problems = [] + + # helper to format field name with path + def _get_path(field_name): + return f"{path}.{field_name}" if path else field_name + + for field in message.DESCRIPTOR.fields: + # Check if the field has the REQUIRED behavior + options = field.GetOptions() + if options.Extensions[field_behavior_pb2.field_behavior]: + behaviors = options.Extensions[field_behavior_pb2.field_behavior] + if field_behavior_pb2.FieldBehavior.REQUIRED in behaviors: + value = getattr(message, field.name) + + # Repeated fields: Check if empty + if field.is_repeated: + # TODO: This triggers validation error for empty arrays (e.g. message with no parts). + # Enable once streaming is refactored + # if not value: + # problems.append(f"{_get_path(field.name)} is required but empty") + if field.type == descriptor.FieldDescriptor.TYPE_MESSAGE: + is_map = getattr(field.message_type.GetOptions(), "map_entry", False) + if is_map: + for k, v in value.items(): + if isinstance(v, _message.Message): + problems.extend(_validate_message(v, f"{_get_path(field.name)}[{k}]")) + else: + for i, item in enumerate(value): + problems.extend(_validate_message(item, f"{_get_path(field.name)}[{i}]")) + continue + + # Scalar/Message fields + if field.type == descriptor.FieldDescriptor.TYPE_MESSAGE: + if not message.HasField(field.name): + problems.append(f"{_get_path(field.name)} is required") + else: + # Recursive validation + problems.extend(_validate_message(value, _get_path(field.name))) + elif ( + field.type == descriptor.FieldDescriptor.TYPE_STRING + or field.type == descriptor.FieldDescriptor.TYPE_BYTES + ): + if not value: + problems.append(f"{_get_path(field.name)} is required") + elif field.type == descriptor.FieldDescriptor.TYPE_ENUM and value == 0: + problems.append(f"{_get_path(field.name)} is required") + + else: + # Even if the field itself isn't required, if it IS set and is a message, we should validate it recursively. + if field.type == descriptor.FieldDescriptor.TYPE_MESSAGE: + if field.is_repeated: + value = getattr(message, field.name) + is_map = getattr(field.message_type.GetOptions(), "map_entry", False) + if is_map: + for k, v in value.items(): + if isinstance(v, _message.Message): + problems.extend(_validate_message(v, f"{_get_path(field.name)}[{k}]")) + else: + for i, item in enumerate(value): + problems.extend(_validate_message(item, f"{_get_path(field.name)}[{i}]")) + elif message.HasField(field.name): + value = getattr(message, field.name) + problems.extend(_validate_message(value, _get_path(field.name))) + + return problems + + +def _inject_validation(): + # TODO: brainstorm options + return + + import inspect + + import a2a.types + from google.protobuf import message as _message + + for name, klass in inspect.getmembers(a2a.types): + if inspect.isclass(klass) and issubclass(klass, _message.Message) and klass is not _message.Message: + original_init = klass.__init__ + original_list_fields = klass.ListFields + original_copy_from = klass.CopyFrom + + def _validate_in_user_scope(message): + # TODO: is this a good idea? + caller_module = sys._getframe(2).f_globals.get("__name__", "") + if caller_module.startswith("a2a.") or caller_module.startswith("google."): + return [] + return validate_message(message) + + @functools.wraps(original_init) + def new_init(self, *args, _name=name, _init=original_init, **kwargs): + _init(self, *args, **kwargs) + if errors := _validate_in_user_scope(self): + raise ValueError(f"Validation failed for {_name}: {', '.join(errors)}") + + @functools.wraps(original_list_fields) + def new_list_fields(self, _name=name, _list_fields=original_list_fields): + if errors := _validate_in_user_scope(self): + raise ValueError(f"Validation failed for {_name}: {', '.join(errors)}") + return _list_fields(self) + + @functools.wraps(original_copy_from) + def new_copy_from(self, other, _name=name, _copy_from=original_copy_from): + if errors := _validate_in_user_scope(self): + raise ValueError(f"Validation failed for {_name}: {', '.join(errors)}") + return _copy_from(self, other) + + klass.__init__ = new_init + klass.ListFields = new_list_fields diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/platform/context.py b/apps/agentstack-sdk-py/src/agentstack_sdk/platform/context.py index 6ee648ec6a..a291adecb4 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/platform/context.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/platform/context.py @@ -6,11 +6,12 @@ import builtins from collections.abc import AsyncIterator -from typing import Literal +from typing import Any, Literal, Self from uuid import UUID, uuid4 import pydantic from a2a.types import Artifact, Message +from google.protobuf.json_format import MessageToDict, ParseDict from pydantic import AwareDatetime, BaseModel, Field, SerializeAsAny, computed_field from agentstack_sdk.platform.client import PlatformClient, get_platform_client @@ -20,7 +21,7 @@ from agentstack_sdk.util.utils import filter_dict, utc_now -class ContextHistoryItem(BaseModel): +class ContextHistoryItem(BaseModel, arbitrary_types_allowed=True): id: UUID = Field(default_factory=uuid4) data: Artifact | Message created_at: AwareDatetime = Field(default_factory=utc_now) @@ -31,6 +32,11 @@ class ContextHistoryItem(BaseModel): def kind(self) -> Literal["message", "artifact"]: return getattr(self.data, "kind", "artifact") + @pydantic.field_validator("data", mode="before") + @classmethod + def parse_data(cls: Self, value: dict[str, Any]) -> Artifact | Message: + return ParseDict(value, Artifact() if "artifact_id" in value else Message()) + class ContextToken(pydantic.BaseModel): context_id: str @@ -237,7 +243,7 @@ async def add_history_item( async with client or get_platform_client() as platform_client: _ = ( await platform_client.post( - url=f"/api/v1/contexts/{target_context_id}/history", json=data.model_dump(mode="json") + url=f"/api/v1/contexts/{target_context_id}/history", json=MessageToDict(data) ) ).raise_for_status() diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/platform/file.py b/apps/agentstack-sdk-py/src/agentstack_sdk/platform/file.py index d544c76bb2..c5288f5a79 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/platform/file.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/platform/file.py @@ -11,7 +11,7 @@ from typing import Literal import pydantic -from a2a.types import FilePart, FileWithUri +from a2a.types import Part from agentstack_sdk.platform.client import PlatformClient, get_platform_client from agentstack_sdk.platform.common import PaginatedResult @@ -257,8 +257,8 @@ async def delete_extraction( ) ).raise_for_status() - def to_file_part(self: "File") -> FilePart: - return FilePart(file=FileWithUri(name=self.filename, uri=f"agentstack://{self.id}")) + def to_file_part(self: File) -> Part: + return Part(filename=self.filename, url=f"agentstack://{self.id}") @staticmethod async def list( diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/platform/provider.py b/apps/agentstack-sdk-py/src/agentstack_sdk/platform/provider.py index 1d12bc3b02..0f48e2eaf9 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/platform/provider.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/platform/provider.py @@ -9,11 +9,13 @@ import urllib.parse from contextlib import asynccontextmanager from datetime import timedelta +from typing import Any, Self from uuid import UUID import pydantic from a2a.client import ClientConfig, ClientFactory from a2a.types import AgentCard +from google.protobuf.json_format import MessageToDict, ParseDict from agentstack_sdk.platform.client import PlatformClient, get_platform_client from agentstack_sdk.platform.common import ResolvedDockerImageID, ResolvedGithubUrl @@ -35,7 +37,8 @@ class VersionInfo(pydantic.BaseModel): github: ResolvedGithubUrl | None = None -class Provider(pydantic.BaseModel): +class Provider(pydantic.BaseModel, arbitrary_types_allowed=True): + model_config = pydantic.ConfigDict(arbitrary_types_allowed=True) id: str auto_stop_timeout: timedelta source: str @@ -52,6 +55,11 @@ class Provider(pydantic.BaseModel): created_by: UUID missing_configuration: builtins.list[EnvVar] = pydantic.Field(default_factory=list) + @pydantic.field_validator("agent_card", mode="before") + @classmethod + def parse_card(cls: Self, value: dict[str, Any]) -> AgentCard: + return ParseDict(value, AgentCard()) + @staticmethod async def create( *, @@ -72,7 +80,7 @@ async def create( json=filter_dict( { "location": location, - "agent_card": agent_card.model_dump(mode="json") if agent_card else None, + "agent_card": MessageToDict(agent_card) if agent_card else None, "origin": origin, "variables": variables, "auto_stop_timeout_sec": auto_stop_timeout_sec, @@ -100,7 +108,7 @@ async def patch( payload = filter_dict( { "location": location, - "agent_card": agent_card.model_dump(mode="json") if agent_card else None, + "agent_card": MessageToDict(agent_card) if agent_card else None, "variables": variables, "auto_stop_timeout_sec": None if auto_stop_timeout is None else auto_stop_timeout.total_seconds(), "origin": origin, @@ -133,7 +141,7 @@ async def preview( url="/api/v1/providers/preview", json={ "location": location, - "agent_card": agent_card.model_dump(mode="json") if agent_card else None, + "agent_card": MessageToDict(agent_card) if agent_card else None, }, ) ) diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/platform/provider_discovery.py b/apps/agentstack-sdk-py/src/agentstack_sdk/platform/provider_discovery.py index bda939deeb..8416d7ee6f 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/platform/provider_discovery.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/platform/provider_discovery.py @@ -4,10 +4,12 @@ from __future__ import annotations from enum import StrEnum +from typing import Any, Self from uuid import UUID import pydantic from a2a.types import AgentCard +from google.protobuf.json_format import ParseDict from agentstack_sdk.platform.client import PlatformClient, get_platform_client @@ -19,7 +21,7 @@ class DiscoveryState(StrEnum): FAILED = "failed" -class ProviderDiscovery(pydantic.BaseModel): +class ProviderDiscovery(pydantic.BaseModel, arbitrary_types_allowed=True): id: UUID created_at: pydantic.AwareDatetime status: DiscoveryState @@ -28,6 +30,13 @@ class ProviderDiscovery(pydantic.BaseModel): agent_card: AgentCard | None = None error_message: str | None = None + @pydantic.field_validator("agent_card", mode="before") + @classmethod + def parse_card(cls: Self, value: dict[str, Any] | None) -> AgentCard | None: + if value is not None: + return ParseDict(value, AgentCard(skip_verify=True)) + return None + @staticmethod async def create( *, diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/server/agent.py b/apps/agentstack-sdk-py/src/agentstack_sdk/server/agent.py index 66dc3d6699..7d337d477a 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/server/agent.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/server/agent.py @@ -1,6 +1,5 @@ # Copyright 2025 © BeeAI a Series of LF Projects, LLC # SPDX-License-Identifier: Apache-2.0 - from __future__ import annotations import asyncio @@ -10,7 +9,7 @@ from collections.abc import AsyncGenerator, AsyncIterator, Callable, Generator from contextlib import AbstractAsyncContextManager, AsyncExitStack, asynccontextmanager, suppress from datetime import datetime, timedelta -from typing import Any, Final, TypeAlias, TypeVar, cast +from typing import Any, Final, TypeAlias, TypeVar import janus from a2a.server.agent_execution import AgentExecutor, RequestContext @@ -19,14 +18,11 @@ from a2a.types import ( AgentCapabilities, AgentCard, + AgentCardSignature, AgentInterface, AgentProvider, AgentSkill, Artifact, - DataPart, - FilePart, - FileWithBytes, - FileWithUri, Message, Part, SecurityScheme, @@ -34,9 +30,9 @@ TaskState, TaskStatus, TaskStatusUpdateEvent, - TextPart, - TransportProtocol, ) +from a2a.types.a2a_pb2 import SecurityRequirement +from google.protobuf import message as _message from typing_extensions import override from agentstack_sdk.a2a.extensions import AgentDetailExtensionSpec, BaseExtensionServer @@ -48,8 +44,8 @@ from agentstack_sdk.a2a.extensions.ui.error import ( get_error_extension_context, ) -from agentstack_sdk.a2a.types import ArtifactChunk, Metadata, RunYield, RunYieldResume -from agentstack_sdk.server.constants import DEFAULT_IMPLICIT_EXTENSIONS +from agentstack_sdk.a2a.types import Metadata, RunYield, RunYieldResume, validate_message +from agentstack_sdk.server.constants import _DEFAULT_AGENT_INTERFACE, _DEFAULT_AGENT_SKILL, DEFAULT_IMPLICIT_EXTENSIONS from agentstack_sdk.server.context import RunContext from agentstack_sdk.server.dependencies import Dependency, Depends, extract_dependencies from agentstack_sdk.server.store.context_store import ContextStore @@ -105,10 +101,8 @@ def __init__( def initialize( self, - url: str, a2a_security: A2ASecurity | None = None, - preferred_transport: TransportProtocol | str | None = None, - additional_interfaces: list[AgentInterface] | None = None, + supported_interfaces: list[AgentInterface] | None = None, implicit_extensions: dict[str, BaseExtensionServer] = DEFAULT_IMPLICIT_EXTENSIONS, required_extensions: set[str] | None = None, ) -> None: @@ -133,37 +127,33 @@ def initialize( self._initialized = True - capabilities = ( - self.initial_card.capabilities.model_copy() if self.initial_card.capabilities else AgentCapabilities() - ) - capabilities.extensions = [ - *(capabilities.extensions or []), - *(AgentDetailExtensionSpec(self._detail).to_agent_card_extensions()), - *( - e_card - for ext in self._sdk_extensions - for e_card in ext.spec.to_agent_card_extensions( - required=True if ext.spec.URI in self._required_extensions else None - ) - ), - ] - a2a_security = a2a_security or A2ASecurity( - security=self.initial_card.security, - security_schemes=self.initial_card.security_schemes, - ) - preferred_transport = preferred_transport or self.initial_card.preferred_transport - additional_interfaces = additional_interfaces or self.initial_card.additional_interfaces - self._card = self.initial_card.model_copy( - update={ - "capabilities": capabilities, - "url": url, - "security": a2a_security["security"], - "security_schemes": a2a_security["security_schemes"], - "preferred_transport": preferred_transport, - "additional_interfaces": additional_interfaces, - } + capabilities = AgentCapabilities() + if self.initial_card.HasField("capabilities"): + capabilities.CopyFrom(self.initial_card.capabilities) + + capabilities.extensions.extend(AgentDetailExtensionSpec(self._detail).to_agent_card_extensions()) + capabilities.extensions.extend( + e_card + for ext in self._sdk_extensions + for e_card in ext.spec.to_agent_card_extensions( + required=True if ext.spec.URI in self._required_extensions else None + ) ) + self._card = AgentCard() + self._card.CopyFrom(self.initial_card) + self._card.capabilities.CopyFrom(capabilities) + + if len(self._card.supported_interfaces) == 1 and self._card.supported_interfaces[0] == _DEFAULT_AGENT_INTERFACE: + if not supported_interfaces: + raise ValueError("supported_interfaces must be provided when using default agent interface") + self._card.supported_interfaces.clear() # type: ignore [attr-defined] + if supported_interfaces: + self._card.supported_interfaces.extend(supported_interfaces) + if a2a_security: + self._card.security_requirements.extend(a2a_security["security_requirements"]) + self._card.security_schemes.update(a2a_security["security_schemes"]) + @property def card(self) -> AgentCard: if not self._initialized: @@ -204,21 +194,19 @@ def agent( name: str | None = None, description: str | None = None, *, - url: str = "http://invalid", # Default will be replaced by the server - additional_interfaces: list[AgentInterface] | None = None, + supported_interfaces: list[AgentInterface] | None = None, + provider: AgentProvider | None = None, + version: str | None = None, + documentation_url: str | None = None, capabilities: AgentCapabilities | None = None, + security_schemes: dict[str, SecurityScheme] | None = None, + security_requirements: list[SecurityRequirement] | None = None, default_input_modes: list[str] | None = None, default_output_modes: list[str] | None = None, detail: AgentDetail | None = None, - documentation_url: str | None = None, icon_url: str | None = None, - preferred_transport: str | None = None, - provider: AgentProvider | None = None, - security: list[dict[str, list[str]]] | None = None, - security_schemes: dict[str, SecurityScheme] | None = None, skills: list[AgentSkill] | None = None, - supports_authenticated_extended_card: bool | None = None, - version: str | None = None, + signatures: list[AgentCardSignature] | None = None, ) -> Callable[[OriginalFnType], Agent]: """ Create an Agent function. @@ -250,14 +238,19 @@ def agent( :param version: The agent's own version number. The format is defined by the provider. """ - capabilities = capabilities.model_copy(deep=True) if capabilities else AgentCapabilities(streaming=True) + if capabilities: + _caps = AgentCapabilities() + _caps.CopyFrom(capabilities) + capabilities = _caps + else: + capabilities = AgentCapabilities(streaming=True) def decorator(fn: OriginalFnType) -> Agent: signature = inspect.signature(fn) dependencies = extract_dependencies(signature) resolved_name = name or fn.__name__ - resolved_description = description or fn.__doc__ or "" + resolved_description = description or fn.__doc__ or "Description not provided" # Check if user has provided an ErrorExtensionServer, if not add default has_error_extension = any(isinstance(ext, ErrorExtensionServer) for ext in sdk_extensions) @@ -283,21 +276,19 @@ def decorator(fn: OriginalFnType) -> Agent: ] card = AgentCard( - url=url, - preferred_transport=preferred_transport, - additional_interfaces=additional_interfaces, + name=resolved_name, + description=resolved_description, + supported_interfaces=supported_interfaces or [_DEFAULT_AGENT_INTERFACE], + provider=provider, capabilities=capabilities, + security_schemes=security_schemes, + security_requirements=security_requirements, default_input_modes=default_input_modes or ["text"], default_output_modes=default_output_modes or ["text"], - description=resolved_description, documentation_url=documentation_url, icon_url=icon_url, - name=resolved_name, - provider=provider, - security=security, - security_schemes=security_schemes, - skills=skills or [], - supports_authenticated_extended_card=supports_authenticated_extended_card, + skills=skills or [_DEFAULT_AGENT_SKILL], + signatures=signatures, version=version or "1.0.0", ) @@ -460,17 +451,10 @@ async def cancel(self, request_context: RequestContext, event_queue: EventQueue) await cancel_task(self._task) def _with_context(self, message: Message | None = None) -> Message | None: - if message is None: - return None - # Note: This check would require extra handling in agents just forwarding messages from other agents - # Instead, we just silently replace it. - # if message.task_id and message.task_id != task_updater.task_id: - # raise ValueError("Message must have the same task_id as the task") - # if message.context_id and message.context_id != task_updater.context_id: - # raise ValueError("Message must have the same context_id as the task") - return message.model_copy( - deep=True, update={"context_id": self.task_updater.context_id, "task_id": self.task_updater.task_id} - ) + if message: + message.context_id = self.task_updater.context_id + message.task_id = self.task_updater.task_id + return message async def _run_agent_function(self, initial_message: Message) -> None: yield_queue = self.run_context._yield_queue @@ -490,79 +474,63 @@ async def _run_agent_function(self, initial_message: Message) -> None: while not task.done() or yield_queue.async_q.qsize() > 0: yielded_value = await yield_queue.async_q.get() + if isinstance(yielded_value, _message.Message): + validate_message(yielded_value) + self.last_invocation = datetime.now() match yielded_value: case str(text): await self.task_updater.update_status( - TaskState.working, - message=self.task_updater.new_agent_message(parts=[Part(root=TextPart(text=text))]), - ) - case Part(root=part) | (TextPart() | FilePart() | DataPart() as part): - await self.task_updater.update_status( - TaskState.working, - message=self.task_updater.new_agent_message(parts=[Part(root=part)]), + TaskState.TASK_STATE_WORKING, + message=self.task_updater.new_agent_message(parts=[Part(text=text)]), ) - case FileWithBytes() | FileWithUri() as file: + case Part() as part: await self.task_updater.update_status( - TaskState.working, - message=self.task_updater.new_agent_message(parts=[Part(root=FilePart(file=file))]), + TaskState.TASK_STATE_WORKING, + message=self.task_updater.new_agent_message(parts=[part]), ) case Message() as message: await self.task_updater.update_status( - TaskState.working, message=self._with_context(message) - ) - case ArtifactChunk( - parts=parts, - artifact_id=artifact_id, - name=name, - metadata=metadata, - last_chunk=last_chunk, - ): - await self.task_updater.add_artifact( - parts=cast(list[Part], parts), - artifact_id=artifact_id, - name=name, - metadata=metadata, - append=artifact_id in opened_artifacts, - last_chunk=last_chunk, + TaskState.TASK_STATE_WORKING, message=self._with_context(message) ) - opened_artifacts.add(artifact_id) case Artifact(parts=parts, artifact_id=artifact_id, name=name, metadata=metadata): + last_chunk = True + if "_last_chunk" in metadata: + last_chunk = bool(metadata["_last_chunk"]) + del metadata["_last_chunk"] + append = artifact_id in opened_artifacts + if not last_chunk: + opened_artifacts.add(artifact_id) + elif artifact_id in opened_artifacts: + opened_artifacts.remove(artifact_id) + await self.task_updater.add_artifact( - parts=parts, + parts=list(parts), artifact_id=artifact_id, name=name, - metadata=metadata, - last_chunk=True, - append=False, + metadata=dict(metadata), + last_chunk=last_chunk, + append=append, ) case TaskStatus( - state=(TaskState.auth_required | TaskState.input_required) as state, + state=( + TaskState.TASK_STATE_AUTH_REQUIRED | TaskState.TASK_STATE_INPUT_REQUIRED + ) as state, message=message, - timestamp=timestamp, ): - await self.task_updater.update_status( - state=state, message=self._with_context(message), final=True, timestamp=timestamp - ) + await self.task_updater.update_status(state=state, message=self._with_context(message)) self._working = False resume_value = await self.resume_queue.get() self.resume_queue.task_done() - case TaskStatus(state=state, message=message, timestamp=timestamp): - await self.task_updater.update_status( - state=state, message=self._with_context(message), timestamp=timestamp - ) + case TaskStatus(state=state, message=message): + await self.task_updater.update_status(state=state, message=self._with_context(message)) case TaskStatusUpdateEvent( - status=TaskStatus(state=state, message=message, timestamp=timestamp), - final=final, + status=TaskStatus(state=state, message=message), metadata=metadata, ): await self.task_updater.update_status( - state=state, - message=self._with_context(message), - timestamp=timestamp, - final=final, - metadata=metadata, + state=state, message=self._with_context(message), metadata=dict(metadata) ) case TaskArtifactUpdateEvent( artifact=Artifact(artifact_id=artifact_id, name=name, metadata=metadata, parts=parts), @@ -570,22 +538,28 @@ async def _run_agent_function(self, initial_message: Message) -> None: last_chunk=last_chunk, ): await self.task_updater.add_artifact( - parts=parts, + parts=list(parts), artifact_id=artifact_id, name=name, - metadata=metadata, + metadata=dict(metadata), append=append, last_chunk=last_chunk, ) case Metadata() as metadata: await self.task_updater.update_status( - state=TaskState.working, + state=TaskState.TASK_STATE_WORKING, message=self.task_updater.new_agent_message(parts=[], metadata=metadata), ) case dict() as data: + from google.protobuf.struct_pb2 import Struct, Value + + s = Struct() + s.update(data) await self.task_updater.update_status( - state=TaskState.working, - message=self.task_updater.new_agent_message(parts=[Part(root=DataPart(data=data))]), + state=TaskState.TASK_STATE_WORKING, + message=self.task_updater.new_agent_message( + parts=[Part(data=Value(struct_value=s))] + ), ) case Exception() as ex: raise ex @@ -648,7 +622,16 @@ async def execute(self, context: RequestContext, event_queue: EventQueue) -> Non tapped_queue = event_queue.tap() while True: match await tapped_queue.dequeue_event(): - case TaskStatusUpdateEvent(final=True): + case TaskStatusUpdateEvent( + status=TaskStatus( + state=TaskState.TASK_STATE_INPUT_REQUIRED + | TaskState.TASK_STATE_AUTH_REQUIRED + | TaskState.TASK_STATE_COMPLETED + | TaskState.TASK_STATE_FAILED + | TaskState.TASK_STATE_CANCELED + | TaskState.TASK_STATE_REJECTED + ) + ): break case _: pass @@ -698,7 +681,10 @@ async def cleanup_fn(): task_id=task_id, context_id=context_id, task_store=self._task_store, initial_message=None ) event = await queue.dequeue_event(no_wait=True) - if not isinstance(event, TaskStatusUpdateEvent) or event.status.state != TaskState.canceled: + if ( + not isinstance(event, TaskStatusUpdateEvent) + or event.status.state != TaskState.TASK_STATE_CANCELED + ): raise RuntimeError(f"Something strange occured during scheduled cancel, event: {event}") await manager.save_task_event(event) break diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/server/app.py b/apps/agentstack-sdk-py/src/agentstack_sdk/server/app.py index 13918fcbb3..e8cff97c56 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/server/app.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/server/app.py @@ -1,11 +1,11 @@ # Copyright 2025 © BeeAI a Series of LF Projects, LLC # SPDX-License-Identifier: Apache-2.0 - - from __future__ import annotations from datetime import timedelta +import importlib_metadata +import packaging.version from a2a.server.agent_execution import RequestContextBuilder from a2a.server.apps.jsonrpc import A2AFastAPIApplication from a2a.server.apps.rest import A2ARESTFastAPIApplication @@ -17,7 +17,7 @@ PushNotificationSender, TaskStore, ) -from a2a.types import AgentInterface, TransportProtocol +from a2a.types import AgentInterface from fastapi import APIRouter, FastAPI from fastapi.applications import AppType from fastapi.params import Depends @@ -45,7 +45,6 @@ def create_app( request_context_builder: RequestContextBuilder | None = None, lifespan: Lifespan[AppType] | None = None, dependencies: list[Depends] | None = None, - override_interfaces: bool = True, task_timeout: timedelta = timedelta(minutes=10), **kwargs, ) -> FastAPI: @@ -66,23 +65,14 @@ def create_app( push_sender=push_sender, request_context_builder=request_context_builder, ) - - preferred_transport = None - additional_interfaces = None - if override_interfaces: - jsonrpc_url = url + "/jsonrpc/" - preferred_transport = TransportProtocol.jsonrpc - additional_interfaces = [ - AgentInterface(url=url, transport=TransportProtocol.http_json), - AgentInterface(url=jsonrpc_url, transport=TransportProtocol.jsonrpc), - ] - url = jsonrpc_url + protocol_version = packaging.version.parse(importlib_metadata.version("a2a-sdk")).base_version agent.initialize( - url=url, a2a_security=auth_backend.get_card_security_schemes() if auth_backend else None, - preferred_transport=preferred_transport, - additional_interfaces=additional_interfaces, + supported_interfaces=[ + AgentInterface(url=url, protocol_binding="HTTP+JSON", protocol_version=protocol_version), + AgentInterface(url=url + "/jsonrpc/", protocol_binding="JSONRPC", protocol_version=protocol_version), + ], implicit_extensions=implicit_extensions, required_extensions=(required_extensions or set()) | context_store.required_extensions, ) diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/server/constants.py b/apps/agentstack-sdk-py/src/agentstack_sdk/server/constants.py index 0695898873..0d24695ec0 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/server/constants.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/server/constants.py @@ -1,10 +1,11 @@ # Copyright 2025 © BeeAI a Series of LF Projects, LLC # SPDX-License-Identifier: Apache-2.0 - from __future__ import annotations from typing import Final +from a2a.types import AgentInterface, AgentSkill + from agentstack_sdk.a2a.extensions import BaseExtensionServer from agentstack_sdk.a2a.extensions.services.platform import PlatformApiExtensionServer, PlatformApiExtensionSpec from agentstack_sdk.a2a.extensions.ui.error import ErrorExtensionParams, ErrorExtensionServer, ErrorExtensionSpec @@ -14,5 +15,11 @@ PlatformApiExtensionSpec.URI: PlatformApiExtensionServer(PlatformApiExtensionSpec()), } +_IMPLICIT_DEPENDENCY_PREFIX: Final = "___server_dep" +_DEFAULT_AGENT_INTERFACE: Final = AgentInterface( + url="http://invalid", protocol_binding="invalid", protocol_version="1.0.0" +) +_DEFAULT_AGENT_SKILL: Final = AgentSkill(id="default", name="default", description="generic agent", tags=["default"]) + __all__ = [] diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/server/context.py b/apps/agentstack-sdk-py/src/agentstack_sdk/server/context.py index e7a0f10477..4ac76dc384 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/server/context.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/server/context.py @@ -8,7 +8,7 @@ from uuid import UUID import janus -from a2a.types import Artifact, Message, MessageSendConfiguration, Task +from a2a.types import Artifact, Message, Task from pydantic import BaseModel, PrivateAttr from agentstack_sdk.a2a.types import RunYield, RunYieldResume @@ -17,7 +17,6 @@ class RunContext(BaseModel, arbitrary_types_allowed=True): - configuration: MessageSendConfiguration | None = None task_id: str context_id: str current_task: Task | None = None @@ -36,7 +35,11 @@ async def store(self, data: Message | Artifact): if not self._store: raise RuntimeError("Context store is not initialized") if isinstance(data, Message): - data = data.model_copy(deep=True, update={"context_id": self.context_id, "task_id": self.task_id}) + msg = Message() + msg.CopyFrom(data) + msg.context_id = self.context_id + msg.task_id = self.task_id + data = msg await self._store.store(data) @overload diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/server/middleware/platform_auth_backend.py b/apps/agentstack-sdk-py/src/agentstack_sdk/server/middleware/platform_auth_backend.py index 178bfb9d31..bb3fb56857 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/server/middleware/platform_auth_backend.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/server/middleware/platform_auth_backend.py @@ -9,7 +9,7 @@ from urllib.parse import urljoin from a2a.auth.user import User -from a2a.types import HTTPAuthSecurityScheme, SecurityScheme +from a2a.types import HTTPAuthSecurityScheme, SecurityRequirement, SecurityScheme, StringList from async_lru import alru_cache from authlib.jose import JsonWebKey, JWTClaims, KeySet, jwt from authlib.jose.errors import JoseError @@ -135,10 +135,10 @@ async def authenticate(self, conn: HTTPConnection) -> tuple[AuthCredentials, Bas @override def get_card_security_schemes(self) -> A2ASecurity: return A2ASecurity( - security=[{"platform_context_token": []}], + security_requirements=[SecurityRequirement(schemes={"platform_context_token": StringList()})], security_schemes={ "platform_context_token": SecurityScheme( - HTTPAuthSecurityScheme( + http_auth_security_scheme=HTTPAuthSecurityScheme( scheme="bearer", bearer_format="JWT", description="Platform context token, issued by the AgentStack server using POST /api/v1/context/{context_id}/token.", diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/server/store/memory_context_store.py b/apps/agentstack-sdk-py/src/agentstack_sdk/server/store/memory_context_store.py index 04a320a958..56cc65c564 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/server/store/memory_context_store.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/server/store/memory_context_store.py @@ -9,6 +9,7 @@ from a2a.types import Artifact, Message from cachetools import TTLCache +from google.protobuf.json_format import MessageToDict from agentstack_sdk.platform.context import ContextHistoryItem from agentstack_sdk.server.store.context_store import ContextStore, ContextStoreInstance @@ -24,12 +25,12 @@ async def load_history( ) -> AsyncIterator[ContextHistoryItem | Message | Artifact]: for item in self._history.copy(): if load_history_items: - yield item.model_copy(deep=True) + yield item else: - yield item.data.model_copy(deep=True) + yield item.data async def store(self, data: Message | Artifact) -> None: - self._history.append(ContextHistoryItem(data=data.model_copy(deep=True), context_id=self.context_id)) + self._history.append(ContextHistoryItem(data=MessageToDict(data), context_id=self.context_id)) async def delete_history_from_id(self, from_id: UUID) -> None: # Does not allow to delete from an artifact onwards diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/types.py b/apps/agentstack-sdk-py/src/agentstack_sdk/types.py index f69d445d28..e8a044d477 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/types.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/types.py @@ -6,7 +6,7 @@ import abc from typing import TYPE_CHECKING, TypeAlias, TypedDict -from a2a.types import SecurityScheme +from a2a.types import SecurityRequirement, SecurityScheme from starlette.authentication import AuthenticationBackend __all__ = [ @@ -28,8 +28,8 @@ class A2ASecurity(TypedDict): - security: list[dict[str, list[str]]] | None - security_schemes: dict[str, SecurityScheme] | None + security_requirements: list[SecurityRequirement] + security_schemes: dict[str, SecurityScheme] class SdkAuthenticationBackend(AuthenticationBackend, abc.ABC): diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/util/file.py b/apps/agentstack-sdk-py/src/agentstack_sdk/util/file.py index ebacbc34aa..0e257abede 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/util/file.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/util/file.py @@ -3,7 +3,6 @@ from __future__ import annotations -import base64 import typing from collections.abc import AsyncIterator, Iterator from contextlib import AsyncExitStack, asynccontextmanager @@ -11,7 +10,7 @@ from typing import Protocol import httpx -from a2a.types import FilePart, FileWithBytes, FileWithUri +from a2a.types import Part from httpx._decoders import LineDecoder from pydantic import AnyUrl, HttpUrl, RootModel, UrlConstraints @@ -226,7 +225,7 @@ def file_id(self) -> str: @asynccontextmanager async def load_file( - part: FilePart, + part: Part, stream: bool = False, client: httpx.AsyncClient | None = None, ) -> AsyncIterator[LoadedFile]: @@ -234,29 +233,32 @@ async def load_file( :param stream: if stream is set to False, 'content' and 'text' fields are immediately available. Otherwise, they are only available after calling the '(a)read' method. """ - match part.file: - case FileWithUri(mime_type=content_type, name=filename, uri=uri): - match UriType.model_validate(uri).root: - case PlatformFileUrl() as url: - from agentstack_sdk.platform import File - - async with File.load_content(url.file_id, stream=stream) as file: - # override filename and content_type from part - if filename: - file.filename = filename - if content_type: - file.content_type = content_type + if part.url: + match UriType.model_validate(part.url).root: + case PlatformFileUrl() as url: + from agentstack_sdk.platform import File + + async with File.load_content(url.file_id, stream=stream) as file: + # override filename and content_type from part + if part.filename: + file.filename = part.filename + if part.media_type: + file.content_type = part.media_type + yield file + case HttpUrl(): + async with AsyncExitStack() as stack: + if client is None: + client = await stack.enter_async_context(httpx.AsyncClient()) + async with client.stream("GET", part.url) as response: + response.raise_for_status() + file = LoadedFileWithUri( + response=response, filename=part.filename, content_type=part.media_type + ) + if not stream: + await file.aread() yield file - case HttpUrl(): - async with AsyncExitStack() as stack: - if client is None: - client = await stack.enter_async_context(httpx.AsyncClient()) - async with client.stream("GET", uri) as response: - response.raise_for_status() - file = LoadedFileWithUri(response=response, filename=filename, content_type=content_type) - if not stream: - await file.aread() - yield file - - case FileWithBytes(bytes=content, name=filename, mime_type=content_type): - yield LoadedFileWithBytes(content=base64.b64decode(content), filename=filename, content_type=content_type) + + elif "raw" in part: # pyrefly: ignore [not-iterable] + yield LoadedFileWithBytes(content=part.raw, filename=part.filename, content_type=part.media_type) + else: + raise ValueError("Part must have either url or raw set to be loaded as a file.") diff --git a/apps/agentstack-sdk-py/tests/e2e/conftest.py b/apps/agentstack-sdk-py/tests/e2e/conftest.py index 8f9d31699e..71882bc17d 100644 --- a/apps/agentstack-sdk-py/tests/e2e/conftest.py +++ b/apps/agentstack-sdk-py/tests/e2e/conftest.py @@ -1,5 +1,7 @@ # Copyright 2025 © BeeAI a Series of LF Projects, LLC # SPDX-License-Identifier: Apache-2.0 +from ddgs.cli import cli +from typing import AsyncIterator from __future__ import annotations @@ -16,14 +18,13 @@ from a2a.types import ( AgentCard, Artifact, - DataPart, - FilePart, - FileWithBytes, Message, + Part, TaskStatus, - TextPart, ) from a2a.utils.constants import AGENT_CARD_WELL_KNOWN_PATH +from google.protobuf.json_format import ParseDict +from google.protobuf.struct_pb2 import Value from tenacity import AsyncRetrying, stop_after_attempt, wait_fixed from agentstack_sdk.a2a.extensions.ui.agent_detail import AgentDetail @@ -66,9 +67,9 @@ async def run_server( card_resp = await httpx_client.get(f"{base_url}{AGENT_CARD_WELL_KNOWN_PATH}") card_resp.raise_for_status() - card = AgentCard.model_validate(card_resp.json()) + card = ParseDict(card_resp.json(), AgentCard(), ignore_unknown_fields=True) client = ClientFactory(ClientConfig(httpx_client=httpx_client)).create(card=card) - yield server, client + yield server, client finally: server.should_exit = True @@ -80,7 +81,7 @@ def create_server_with_agent(): @asynccontextmanager async def _create_server( agent_fn, context_store: ContextStore | None = None, task_timeout: timedelta | None = None - ): + ) -> AsyncIterator[tuple[Server, Client]]: server = Server() server.agent(detail=AgentDetail(interaction_mode="multi-turn"))(agent_fn) async with run_server( @@ -98,8 +99,7 @@ async def _create_server( async def echo(create_server_with_agent) -> AsyncGenerator[tuple[Server, Client]]: async def echo(message: Message, context: RunContext) -> AsyncGenerator[str, Message]: for part in message.parts: - if hasattr(part.root, "text"): - yield part.root.text + yield part.text async with create_server_with_agent(echo) as (server, test_client): yield server, test_client @@ -110,9 +110,8 @@ async def slow_echo(create_server_with_agent) -> AsyncGenerator[tuple[Server, Cl async def slow_echo(message: Message, context: RunContext) -> AsyncGenerator[str, Message]: # Slower version with delay for part in message.parts: - if hasattr(part.root, "text"): - await asyncio.sleep(1) - yield part.root.text + await asyncio.sleep(1) + yield part.text async with create_server_with_agent(slow_echo) as (server, test_client): yield server, test_client @@ -125,7 +124,7 @@ async def awaiter(message: Message, context: RunContext) -> AsyncGenerator[TaskS yield "Processing initial message..." resume_message = yield InputRequired(text="need input") - yield f"Received resume: {resume_message.parts[0].root.text if resume_message.parts else 'empty'}" + yield f"Received resume: {resume_message.parts[0].text if resume_message.parts else 'empty'}" async with create_server_with_agent(awaiter) as (server, test_client): yield server, test_client @@ -138,7 +137,7 @@ async def awaiter(message: Message, context: RunContext) -> AsyncGenerator[TaskS yield "Processing initial message..." resume_message = yield InputRequired(text="need input") - yield f"Received resume: {resume_message.parts[0].root.text if resume_message.parts else 'empty'}" + yield f"Received resume: {resume_message.parts[0].text if resume_message.parts else 'empty'}" async with create_server_with_agent(awaiter, task_timeout=timedelta(seconds=1)) as (server, test_client): yield server, test_client @@ -173,21 +172,19 @@ async def artifact_producer(message: Message, context: RunContext) -> AsyncGener # Create artifacts with proper parts structure yield AgentArtifact( name="text-result.txt", - parts=[TextPart(text="This is a text artifact result")], + parts=[Part(text="This is a text artifact result")], ) yield AgentArtifact( name="data.json", - parts=[DataPart(data={"results": [1, 2, 3], "status": "complete"})], + parts=[Part(data=ParseDict({"results": [1, 2, 3], "status": "complete"}, Value()))], ) png_bytes = b"\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x01\x00\x00\x00\x01\x08\x06\x00\x00\x00\x1f\x15\xc4\x89\x00\x00\x00\nIDATx\x9cc\x00\x01\x00\x00\x05\x00\x01\r\n-\xb4\x00\x00\x00\x00IEND\xaeB`\x82" yield AgentArtifact( name="image.png", - parts=[ - FilePart(file=FileWithBytes(bytes=base64.b64encode(png_bytes).decode("utf-8"), mime_type="image/png")) - ], + parts=[Part(raw=base64.b64encode(png_bytes), media_type="image/png")], ) async with create_server_with_agent(artifact_producer) as (server, test_client): @@ -198,7 +195,7 @@ async def artifact_producer(message: Message, context: RunContext) -> AsyncGener async def chunked_artifact_producer(create_server_with_agent) -> AsyncGenerator[tuple[Server, Client]]: async def chunked_artifact_producer( message: Message, context: RunContext - ) -> AsyncGenerator[str | ArtifactChunk, Message]: + ) -> AsyncGenerator[str | Artifact, Message]: # Agent producing chunked artifacts yield "Processing chunked artifacts" @@ -206,19 +203,19 @@ async def chunked_artifact_producer( yield ArtifactChunk( artifact_id="1", name="large-file.txt", - parts=[TextPart(text="This is the first chunk of data.\n")], + parts=[Part(text="This is the first chunk of data.\n")], ) yield ArtifactChunk( artifact_id="1", name="large-file.txt", - parts=[TextPart(text="This is the second chunk of data.\n")], + parts=[Part(text="This is the second chunk of data.\n")], ) yield ArtifactChunk( artifact_id="1", name="large-file.txt", - parts=[TextPart(text="This is the final chunk of data.\n")], + parts=[Part(text="This is the final chunk of data.\n")], last_chunk=True, ) diff --git a/apps/agentstack-sdk-py/tests/e2e/test_extensions.py b/apps/agentstack-sdk-py/tests/e2e/test_extensions.py index 780273c23c..2284f2cd67 100644 --- a/apps/agentstack-sdk-py/tests/e2e/test_extensions.py +++ b/apps/agentstack-sdk-py/tests/e2e/test_extensions.py @@ -12,6 +12,7 @@ from a2a.client import Client, ClientEvent from a2a.client.helpers import create_text_message_object from a2a.types import Message, Task +from google.protobuf.json_format import MessageToDict from agentstack_sdk.a2a.extensions import ( ErrorExtensionParams, @@ -33,7 +34,7 @@ async def get_final_task_from_stream(stream: AsyncIterator[ClientEvent | Message final_task = None async for event in stream: match event: - case (task, _): + case (_, task): final_task = task return final_task @@ -55,8 +56,7 @@ async def chunked_artifact_producer( async def test_extension_is_not_reused(llm_extension_agent): _, client = llm_extension_agent - card = await client.get_card() - llm_spec = LLMServiceExtensionSpec.from_agent_card(card) + llm_spec = LLMServiceExtensionSpec.from_agent_card(client._card) # pyrefly: ignore [bad-argument-type] extension_client = LLMServiceExtensionClient(llm_spec) @@ -72,7 +72,7 @@ async def test_extension_is_not_reused(llm_extension_agent): results = await asyncio.gather(*tasks) for i, task in enumerate(results): # pyrefly: ignore [missing-attribute, unsupported-operation] - assert task.history[-1].parts[0].root.text == str(i) + assert task.history[-1].parts[0].text == str(i) @pytest.fixture @@ -104,8 +104,7 @@ async def exception_group_agent( async def test_error_extension_without_stacktrace(error_agent_without_stacktrace): """Test that errors are properly handled without stack trace.""" _, client = error_agent_without_stacktrace - card = await client.get_card() - error_spec = ErrorExtensionSpec.from_agent_card(card) + error_spec = ErrorExtensionSpec.from_agent_card(client._card) message = create_text_message_object() task = await get_final_task_from_stream(client.send_message(message)) @@ -122,7 +121,7 @@ async def test_error_extension_without_stacktrace(error_agent_without_stacktrace # Validate error metadata # pyrefly: ignore [missing-attribute, unsupported-operation] - error_metadata = ErrorMetadata.model_validate(error_message.metadata[error_spec.URI]) + error_metadata = ErrorMetadata.model_validate(MessageToDict(error_message.metadata)[error_spec.URI]) assert error_metadata.error.title == "ValueError" assert error_metadata.error.message == "Something went wrong!" @@ -130,7 +129,7 @@ async def test_error_extension_without_stacktrace(error_agent_without_stacktrace # Check message text - message_text = error_message.parts[0].root.text + message_text = error_message.parts[0].text assert "## ValueError" in message_text assert "Something went wrong!" in message_text assert "```" not in message_text # No stack trace code block @@ -139,8 +138,7 @@ async def test_error_extension_without_stacktrace(error_agent_without_stacktrace async def test_error_extension_exception_group_with_stacktrace(exception_group_agent_with_stacktrace): """Test that exception groups include single stack trace when configured.""" _, client = exception_group_agent_with_stacktrace - card = await client.get_card() - error_spec = ErrorExtensionSpec.from_agent_card(card) + error_spec = ErrorExtensionSpec.from_agent_card(client._card) message = create_text_message_object() task = await get_final_task_from_stream(client.send_message(message)) @@ -157,7 +155,7 @@ async def test_error_extension_exception_group_with_stacktrace(exception_group_a # Validate error metadata - should have 2 errors in the group # pyrefly: ignore [missing-attribute, unsupported-operation] - error_metadata = ErrorMetadata.model_validate(error_message.metadata[error_spec.URI]) + error_metadata = ErrorMetadata.model_validate(MessageToDict(error_message.metadata)[error_spec.URI]) assert error_metadata.error.message.startswith("Multiple failures") assert len(error_metadata.error.errors) == 2 @@ -178,7 +176,7 @@ async def test_error_extension_exception_group_with_stacktrace(exception_group_a # Check message text - message_text = error_message.parts[0].root.text + message_text = error_message.parts[0].text assert "## Multiple failures" in message_text assert "### ValueError" in message_text assert "First error" in message_text @@ -199,8 +197,8 @@ async def error_agent( # Extract request_id from message text to set unique context text_content = "" for part in message.parts: - if hasattr(part.root, "text"): - text_content = part.root.text + if "text" in part: + text_content = part.text break # Set context based on the request @@ -222,8 +220,7 @@ async def error_agent( async def test_error_extension_context_isolation(context_isolation_agent): """Test that error context is isolated between parallel requests.""" _, client = context_isolation_agent - card = await client.get_card() - error_spec = ErrorExtensionSpec.from_agent_card(card) + error_spec = ErrorExtensionSpec.from_agent_card(client._card) # Send 3 parallel requests with different identifiers request_ids = ["request-1", "request-2", "request-3"] @@ -250,7 +247,7 @@ async def send_request(request_id: str) -> Task: # Validate error metadata # pyrefly: ignore [missing-attribute, unsupported-operation] - error_metadata = ErrorMetadata.model_validate(error_message.metadata[error_spec.URI]) + error_metadata = ErrorMetadata.model_validate(MessageToDict(error_message.metadata)[error_spec.URI]) assert error_metadata.error.title == "ValueError" assert error_metadata.error.message == f"Error for request {expected_id}" diff --git a/apps/agentstack-sdk-py/tests/e2e/test_history.py b/apps/agentstack-sdk-py/tests/e2e/test_history.py index 3f71fbff0b..a44871ae0d 100644 --- a/apps/agentstack-sdk-py/tests/e2e/test_history.py +++ b/apps/agentstack-sdk-py/tests/e2e/test_history.py @@ -25,7 +25,7 @@ async def get_final_task_from_stream(stream: AsyncIterator[ClientEvent | Message final_task = None async for event in stream: match event: - case (task, _): + case (_, task): final_task = task return final_task @@ -38,7 +38,7 @@ async def send_message_get_response( message.context_id = context_id final_task = await get_final_task_from_stream(client.send_message(message)) - agent_messages = [msg.parts[0].root.text for msg in final_task.history or []] + agent_messages = [msg.parts[0].text for msg in final_task.history or []] return agent_messages, final_task.context_id @@ -50,7 +50,7 @@ async def history_agent(create_server_with_agent) -> AsyncGenerator[tuple[Server async def history_agent(input: Message, context: RunContext) -> AsyncGenerator[RunYield, None]: await context.store(input) async for message in context.load_history(): - message.role = Role.agent + message.role = Role.ROLE_AGENT yield message await context.store(message) @@ -76,7 +76,7 @@ async def history_agent(input: Message, context: RunContext) -> AsyncGenerator[R break async for message in context.load_history(): - message.role = Role.agent + message.role = Role.ROLE_AGENT yield message async with create_server_with_agent(history_agent, context_store=context_store) as (server, client): diff --git a/apps/agentstack-sdk-py/tests/e2e/test_runs.py b/apps/agentstack-sdk-py/tests/e2e/test_runs.py index 3977247bf7..3891d134b3 100644 --- a/apps/agentstack-sdk-py/tests/e2e/test_runs.py +++ b/apps/agentstack-sdk-py/tests/e2e/test_runs.py @@ -4,24 +4,24 @@ from __future__ import annotations import asyncio -import uuid from collections.abc import AsyncIterator import pytest from a2a.client import Client, ClientEvent, create_text_message_object from a2a.client.errors import A2AClientJSONRPCError from a2a.types import ( + CancelTaskRequest, + GetTaskRequest, Message, - MessageSendParams, + Role, SendMessageRequest, - SendStreamingMessageRequest, + StreamResponse, Task, TaskArtifactUpdateEvent, - TaskIdParams, - TaskQueryParams, TaskState, TaskStatusUpdateEvent, ) +from google.protobuf.json_format import MessageToDict from agentstack_sdk.server import Server @@ -35,7 +35,7 @@ async def get_final_task_from_stream(stream: AsyncIterator[ClientEvent | Message final_task = None async for event in stream: match event: - case (task, _): + case (_, task): final_task = task return final_task @@ -44,20 +44,7 @@ def create_send_request_object(text: str | None = None, task_id: str | None = No message = create_text_message_object(content=text or input_text) if task_id: message.task_id = task_id - return SendMessageRequest( - id=str(uuid.uuid4()), - params=MessageSendParams(message=message), - ) - - -def create_streaming_request_object(text: str | None = None, task_id: str | None = None): - message = create_text_message_object(content=text or input_text) - if task_id: - message.task_id = task_id - return SendStreamingMessageRequest( - id=str(uuid.uuid4()), - params=MessageSendParams(message=message), - ) + return SendMessageRequest(message=message) async def test_run_sync(echo: tuple[Server, Client]) -> None: @@ -67,15 +54,15 @@ async def test_run_sync(echo: tuple[Server, Client]) -> None: final_task = await get_final_task_from_stream(client.send_message(message)) assert final_task is not None - assert final_task.status.state == TaskState.completed + assert final_task.status.state == TaskState.TASK_STATE_COMPLETED # pyrefly: ignore [bad-argument-type] assert len(final_task.history) >= 1 # The echo agent should return the same text as input # pyrefly: ignore [not-iterable] - agent_messages = [msg for msg in final_task.history if msg.role.value == "agent"] + agent_messages = [msg for msg in final_task.history if msg.role == Role.ROLE_AGENT] assert len(agent_messages) >= 1 - assert agent_messages[0].parts[0].root.text == message.parts[0].root.text + assert agent_messages[0].parts[0].text == message.parts[0].text async def test_run_stream(echo: tuple[Server, Client]) -> None: @@ -86,14 +73,14 @@ async def test_run_stream(echo: tuple[Server, Client]) -> None: # Should receive TaskStatusUpdateEvents status_events = [] - for event in events: + for event, _ in events: match event: - case (_, TaskStatusUpdateEvent() as update): + case StreamResponse(status_update=TaskStatusUpdateEvent() as update): status_events.append(update) assert len(status_events) > 0 # Final event should be completion - assert status_events[-1].status.state == TaskState.completed + assert status_events[-1].status.state == TaskState.TASK_STATE_COMPLETED async def test_run_status(echo: tuple[Server, Client]) -> None: @@ -106,10 +93,10 @@ async def test_run_status(echo: tuple[Server, Client]) -> None: task_id = final_task.id # Get current task status - should be completed for echo agent - task_params = TaskQueryParams(id=task_id) + task_params = GetTaskRequest(id=task_id) task_response = await client.get_task(task_params) assert hasattr(task_response, "status") - assert task_response.status.state == TaskState.completed + assert task_response.status.state == TaskState.TASK_STATE_COMPLETED async def test_failure_failer(failer: tuple[Server, Client]) -> None: @@ -120,7 +107,7 @@ async def test_failure_failer(failer: tuple[Server, Client]) -> None: assert final_task is not None # Failer agent should fail - assert final_task.status.state == TaskState.failed + assert final_task.status.state == TaskState.TASK_STATE_FAILED async def test_failure_raiser(raiser: tuple[Server, Client]) -> None: @@ -131,7 +118,7 @@ async def test_failure_raiser(raiser: tuple[Server, Client]) -> None: assert final_task is not None # Raiser agent should fail - assert final_task.status.state == TaskState.failed + assert final_task.status.state == TaskState.TASK_STATE_FAILED async def test_run_cancel_awaiter(awaiter: tuple[Server, Client]) -> None: @@ -145,13 +132,13 @@ async def test_run_cancel_awaiter(awaiter: tuple[Server, Client]) -> None: task_id = initial_task.id # Cancel the task - cancel_params = TaskIdParams(id=task_id) + cancel_params = CancelTaskRequest(id=task_id) await client.cancel_task(cancel_params) # Check final status - task_params = TaskQueryParams(id=task_id) + task_params = GetTaskRequest(id=task_id) task_response = await client.get_task(task_params) - assert task_response.status.state == TaskState.canceled + assert task_response.status.state == TaskState.TASK_STATE_CANCELED async def test_run_cancel_stream(slow_echo: tuple[Server, Client]) -> None: @@ -160,17 +147,17 @@ async def test_run_cancel_stream(slow_echo: tuple[Server, Client]) -> None: cancelled = False states = [] - async for event in client.send_message(create_text_message_object()): + async for event, _ in client.send_message(create_text_message_object()): match event: - case (_, TaskStatusUpdateEvent() as update): - if not cancelled and update.status.state == TaskState.working: + case StreamResponse(status_update=TaskStatusUpdateEvent() as update) if update.task_id: + if not cancelled and update.status.state == TaskState.TASK_STATE_WORKING: task_id = update.task_id - cancel_params = TaskIdParams(id=task_id) + cancel_params = CancelTaskRequest(id=task_id) await client.cancel_task(cancel_params) cancelled = True states.append(update.status.state) - assert states == [TaskState.submitted, TaskState.working, TaskState.canceled] + assert states == [TaskState.TASK_STATE_SUBMITTED, TaskState.TASK_STATE_WORKING, TaskState.TASK_STATE_CANCELED] async def test_run_resume_sync(awaiter: tuple[Server, Client]) -> None: @@ -179,7 +166,7 @@ async def test_run_resume_sync(awaiter: tuple[Server, Client]) -> None: initial_task = await get_final_task_from_stream(client.send_message(message)) - assert initial_task.status.state == TaskState.input_required + assert initial_task.status.state == TaskState.TASK_STATE_INPUT_REQUIRED resume_message = create_text_message_object(content="Resume input") resume_message.task_id = initial_task.id @@ -187,9 +174,9 @@ async def test_run_resume_sync(awaiter: tuple[Server, Client]) -> None: final_task = await get_final_task_from_stream(client.send_message(resume_message)) assert hasattr(final_task, "status") - assert final_task.status.state == TaskState.completed + assert final_task.status.state == TaskState.TASK_STATE_COMPLETED # pyrefly: ignore [missing-attribute, unsupported-operation] - assert "Received resume: Resume input" in final_task.history[-1].parts[0].root.text + assert "Received resume: Resume input" in final_task.history[-1].parts[0].text async def test_run_resume_stream(awaiter: tuple[Server, Client]) -> None: @@ -206,13 +193,13 @@ async def test_run_resume_stream(awaiter: tuple[Server, Client]) -> None: events.append(event) status_events = [] - for event in events: + for event, _ in events: match event: - case (_, TaskStatusUpdateEvent() as update): + case StreamResponse(status_update=TaskStatusUpdateEvent() as update): status_events.append(update) assert len(status_events) > 0 - assert status_events[-1].status.state == TaskState.completed + assert status_events[-1].status.state == TaskState.TASK_STATE_COMPLETED async def test_artifacts(artifact_producer: tuple[Server, Client]) -> None: @@ -222,7 +209,7 @@ async def test_artifacts(artifact_producer: tuple[Server, Client]) -> None: final_task = await get_final_task_from_stream(client.send_message(message)) assert hasattr(final_task, "status") - assert final_task.status.state == TaskState.completed + assert final_task.status.state == TaskState.TASK_STATE_COMPLETED # Check for artifacts in the task assert final_task.artifacts is not None @@ -242,22 +229,22 @@ async def test_artifacts(artifact_producer: tuple[Server, Client]) -> None: assert text_artifact is not None assert len(text_artifact.parts) > 0 - text_part = text_artifact.parts[0].root + text_part = text_artifact.parts[0] assert hasattr(text_part, "text") assert text_part.text == "This is a text artifact result" assert json_artifact is not None assert len(json_artifact.parts) > 0 - json_part = json_artifact.parts[0].root + json_part = json_artifact.parts[0] assert hasattr(json_part, "data") - assert json_part.data == {"results": [1, 2, 3], "status": "complete"} + assert MessageToDict(json_part.data) == {"results": [1, 2, 3], "status": "complete"} assert image_artifact is not None assert len(image_artifact.parts) > 0 - image_part = image_artifact.parts[0].root - assert hasattr(image_part, "file") + image_part = image_artifact.parts[0] + assert hasattr(image_part, "raw") # Verify it's valid PNG data by checking that it contains PNG in base64 - assert "iVBOR" in image_part.file.bytes # PNG header in base64 + assert b"iVBOR" in image_part.raw # PNG header in base64 async def test_artifact_streaming(artifact_producer: tuple[Server, Client]) -> None: @@ -270,15 +257,15 @@ async def test_artifact_streaming(artifact_producer: tuple[Server, Client]) -> N status_events = [] artifact_events = [] - for event in events: + for event, _ in events: match event: - case (_, TaskStatusUpdateEvent() as update): + case StreamResponse(status_update=TaskStatusUpdateEvent() as update) if update.task_id: status_events.append(update) - case (_, TaskArtifactUpdateEvent() as update): + case StreamResponse(artifact_update=TaskArtifactUpdateEvent() as update) if update.artifact.artifact_id: artifact_events.append(update) assert len(status_events) > 0 - assert status_events[-1].status.state == TaskState.completed + assert status_events[-1].status.state == TaskState.TASK_STATE_COMPLETED # Check for artifact events assert len(artifact_events) >= 3 # Should have text, json, and image artifacts @@ -294,7 +281,7 @@ async def test_artifact_streaming(artifact_producer: tuple[Server, Client]) -> N assert text_event is not None # Check artifact parts structure assert len(text_event.artifact.parts) > 0 - text_part = text_event.artifact.parts[0].root + text_part = text_event.artifact.parts[0] assert hasattr(text_part, "text") assert text_part.text == "This is a text artifact result" assert text_event.last_chunk is True # Should be complete artifacts @@ -311,15 +298,15 @@ async def test_chunked_artifacts(chunked_artifact_producer: tuple[Server, Client status_events = [] artifact_events = [] - for event in events: + for event, _ in events: match event: - case (_, TaskStatusUpdateEvent() as update): + case StreamResponse(status_update=TaskStatusUpdateEvent() as update) if update.task_id: status_events.append(update) - case (_, TaskArtifactUpdateEvent() as update): + case StreamResponse(artifact_update=TaskArtifactUpdateEvent() as update) if update.artifact.artifact_id: artifact_events.append(update) assert len(status_events) > 0 - assert status_events[-1].status.state == TaskState.completed + assert status_events[-1].status.state == TaskState.TASK_STATE_COMPLETED # Check for artifact events - should have 3 chunks for the same artifact chunked_events = [e for e in artifact_events if e.artifact.name == "large-file.txt"] @@ -344,11 +331,11 @@ async def test_chunked_artifacts(chunked_artifact_producer: tuple[Server, Client # Verify artifact content - assert "first chunk" in first_chunk.artifact.parts[0].root.text + assert "first chunk" in first_chunk.artifact.parts[0].text - assert "second chunk" in second_chunk.artifact.parts[0].root.text + assert "second chunk" in second_chunk.artifact.parts[0].text - assert "final chunk" in final_chunk.artifact.parts[0].root.text + assert "final chunk" in final_chunk.artifact.parts[0].text async def test_run_timeout(awaiter_with_1s_timeout: tuple[Server, Client]) -> None: @@ -356,11 +343,11 @@ async def test_run_timeout(awaiter_with_1s_timeout: tuple[Server, Client]) -> No message = create_text_message_object() initial_task = await get_final_task_from_stream(client.send_message(message)) - assert initial_task.status.state == TaskState.input_required + assert initial_task.status.state == TaskState.TASK_STATE_INPUT_REQUIRED await asyncio.sleep(3) - task = await client.get_task(request=TaskQueryParams(id=initial_task.id)) - assert task.status.state == TaskState.canceled + task = await client.get_task(request=GetTaskRequest(id=initial_task.id)) + assert task.status.state == TaskState.TASK_STATE_CANCELED resume_message = create_text_message_object(content="Resume input") resume_message.task_id = initial_task.id diff --git a/apps/agentstack-sdk-py/tests/e2e/test_yields.py b/apps/agentstack-sdk-py/tests/e2e/test_yields.py index 0d5045df80..5c54444abb 100644 --- a/apps/agentstack-sdk-py/tests/e2e/test_yields.py +++ b/apps/agentstack-sdk-py/tests/e2e/test_yields.py @@ -10,21 +10,20 @@ import pytest from a2a.client import Client, ClientEvent, create_text_message_object from a2a.types import ( - DataPart, - FilePart, - FileWithBytes, + Artifact, Message, - MessageSendParams, + Part, Role, SendMessageRequest, - SendStreamingMessageRequest, + StreamResponse, Task, TaskArtifactUpdateEvent, TaskState, TaskStatus, TaskStatusUpdateEvent, - TextPart, ) +from google.protobuf.json_format import MessageToDict, ParseDict +from google.protobuf.struct_pb2 import Value from agentstack_sdk.a2a.types import AgentArtifact, AgentMessage, InputRequired, Metadata, RunYield from agentstack_sdk.server import Server @@ -38,10 +37,10 @@ async def get_final_task_from_stream(stream: AsyncIterator[ClientEvent | Message final_task = None async for event in stream: match event: - case (task, None): + case (_, task): final_task = task - case (task, TaskStatusUpdateEvent(status=TaskStatus(state=state))): - if state in {TaskState.auth_required, TaskState.input_required}: + case (StreamResponse(status_update=TaskStatusUpdateEvent(status=TaskStatus(state=state))), task): + if state in {TaskState.TASK_STATE_AUTH_REQUIRED, TaskState.TASK_STATE_INPUT_REQUIRED}: break final_task = task return final_task @@ -52,18 +51,7 @@ def create_send_request_object(text: str | None = None, task_id: str | None = No if task_id: message.task_id = task_id return SendMessageRequest( - id=str(uuid.uuid4()), - params=MessageSendParams(message=message), - ) - - -def create_streaming_request_object(text: str | None = None, task_id: str | None = None): - message = create_text_message_object(content=text or "test") - if task_id: - message.task_id = task_id - return SendStreamingMessageRequest( - id=str(uuid.uuid4()), - params=MessageSendParams(message=message), + message=message, ) @@ -72,7 +60,7 @@ async def sync_function_agent(create_server_with_agent) -> AsyncGenerator[tuple[ def sync_function_agent(message: Message): """Synchronous function agent that returns a string directly.""" - return f"sync_function_agent: {message.parts[0].root.text}" + return f"sync_function_agent: {message.parts[0].text}" async with create_server_with_agent(sync_function_agent) as (server, client): yield server, client @@ -84,7 +72,7 @@ def sync_function_with_context_agent(message: Message, context: RunContext): """Synchronous function agent with context that uses context.yield_sync.""" context.yield_sync("first sync yield") - return f"sync_function_with_context_agent: {message.parts[0].root.text}" + return f"sync_function_with_context_agent: {message.parts[0].text}" async with create_server_with_agent(sync_function_with_context_agent) as (server, client): yield server, client @@ -109,7 +97,7 @@ def sync_generator_with_context_agent(message: Message, context: RunContext): context.yield_sync("sync_generator_with_context context yield") yield "sync_generator_with_context yield 2" - yield f"sync_generator_with_context_agent: {message.parts[0].root.text}" + yield f"sync_generator_with_context_agent: {message.parts[0].text}" async with create_server_with_agent(sync_generator_with_context_agent) as (server, client): yield server, client @@ -121,7 +109,7 @@ async def async_function_agent(message: Message): """Asynchronous function agent that returns a string directly.""" await asyncio.sleep(0.01) - return f"async_function_agent: {message.parts[0].root.text}" + return f"async_function_agent: {message.parts[0].text}" async with create_server_with_agent(async_function_agent) as (server, client): yield server, client @@ -134,7 +122,7 @@ async def async_function_with_context_agent(message: Message, context: RunContex await context.yield_async("first async yield") await asyncio.sleep(0.01) - return f"async_function_with_context_agent: {message.parts[0].root.text}" + return f"async_function_with_context_agent: {message.parts[0].text}" async with create_server_with_agent(async_function_with_context_agent) as (server, client): yield server, client @@ -148,7 +136,7 @@ async def async_generator_agent(message: Message): await asyncio.sleep(0.01) yield "async_generator yield 2" - yield f"async_generator_agent: {message.parts[0].root.text}" + yield f"async_generator_agent: {message.parts[0].text}" async with create_server_with_agent(async_generator_agent) as (server, client): yield server, client @@ -163,7 +151,7 @@ async def async_generator_with_context_agent(message: Message, context: RunConte await asyncio.sleep(0.01) yield "async_generator_with_context yield 2" - yield f"async_generator_with_context_agent: {message.parts[0].root.text}" + yield f"async_generator_with_context_agent: {message.parts[0].text}" async with create_server_with_agent(async_generator_with_context_agent) as (server, client): yield server, client @@ -175,12 +163,12 @@ def sync_function_resume_agent(message: Message, context: RunContext): """Synchronous function agent that requires input and handles resume.""" resume_message = context.yield_sync( TaskStatus( - state=TaskState.input_required, + state=TaskState.TASK_STATE_INPUT_REQUIRED, message=create_text_message_object(content="Need input"), ) ) - return f"sync_function_resume_agent: received {resume_message.parts[0].root.text}" + return f"sync_function_resume_agent: received {resume_message.parts[0].text}" async with create_server_with_agent(sync_function_resume_agent) as (server, client): yield server, client @@ -192,7 +180,7 @@ def sync_generator_resume_agent(message: Message, context: RunContext): """Synchronous generator agent that requires input and handles resume.""" yield "sync_generator_resume_agent: starting" resume_message = yield InputRequired(text="Need input") - yield f"sync_generator_resume_agent: received {resume_message.parts[0].root.text}" + yield f"sync_generator_resume_agent: received {resume_message.parts[0].text}" async with create_server_with_agent(sync_generator_resume_agent) as (server, client): yield server, client @@ -203,10 +191,12 @@ async def async_function_resume_agent(create_server_with_agent) -> AsyncGenerato async def async_function_resume_agent(message: Message, context: RunContext): """Asynchronous function agent that requires input and handles resume.""" resume_message = await context.yield_async( - TaskStatus(state=TaskState.input_required, message=create_text_message_object(content="Need input")) + TaskStatus( + state=TaskState.TASK_STATE_INPUT_REQUIRED, message=create_text_message_object(content="Need input") + ) ) - return f"async_function_resume_agent: received {resume_message.parts[0].root.text}" + return f"async_function_resume_agent: received {resume_message.parts[0].text}" async with create_server_with_agent(async_function_resume_agent) as (server, client): yield server, client @@ -218,7 +208,7 @@ async def async_generator_resume_agent(message: Message, context: RunContext): """Asynchronous generator agent that requires input and handles resume.""" yield "async_generator_resume_agent: starting" resume_message = yield InputRequired(text="Need input") - yield f"async_generator_resume_agent: received {resume_message.parts[0].root.text}" + yield f"async_generator_resume_agent: received {resume_message.parts[0].text}" async with create_server_with_agent(async_generator_resume_agent) as (server, client): yield server, client @@ -232,9 +222,9 @@ async def test_sync_function_agent(sync_function_agent): final_task = await get_final_task_from_stream(client.send_message(message)) assert final_task is not None - assert final_task.status.state == TaskState.completed + assert final_task.status.state == TaskState.TASK_STATE_COMPLETED # pyrefly: ignore [missing-attribute, unsupported-operation] - assert "sync_function_agent: hello" in final_task.history[-1].parts[0].root.text + assert "sync_function_agent: hello" in final_task.history[-1].parts[0].text async def test_sync_function_with_context_agent(sync_function_with_context_agent): @@ -245,10 +235,10 @@ async def test_sync_function_with_context_agent(sync_function_with_context_agent final_task = await get_final_task_from_stream(client.send_message(message)) assert final_task is not None - assert final_task.status.state == TaskState.completed + assert final_task.status.state == TaskState.TASK_STATE_COMPLETED # Should have intermediate yield and final result # pyrefly: ignore [missing-attribute, not-iterable] - messages = [msg.parts[0].root.text for msg in final_task.history if msg.role.value == "agent"] + messages = [msg.parts[0].text for msg in final_task.history if msg.role == Role.ROLE_AGENT] assert "first sync yield" in messages assert "sync_function_with_context_agent: hello" in messages @@ -261,9 +251,9 @@ async def test_sync_generator_agent(sync_generator_agent): final_task = await get_final_task_from_stream(client.send_message(message)) assert final_task is not None - assert final_task.status.state == TaskState.completed + assert final_task.status.state == TaskState.TASK_STATE_COMPLETED # pyrefly: ignore [missing-attribute, not-iterable] - messages = [msg.parts[0].root.text for msg in final_task.history if msg.role.value == "agent"] + messages = [msg.parts[0].text for msg in final_task.history if msg.role == Role.ROLE_AGENT] assert "sync_generator yield 1" in messages assert "sync_generator yield 2" in messages @@ -276,9 +266,9 @@ async def test_sync_generator_with_context_agent(sync_generator_with_context_age final_task = await get_final_task_from_stream(client.send_message(message)) assert final_task is not None - assert final_task.status.state == TaskState.completed + assert final_task.status.state == TaskState.TASK_STATE_COMPLETED # pyrefly: ignore [missing-attribute, not-iterable] - messages = [msg.parts[0].root.text for msg in final_task.history if msg.role.value == "agent"] + messages = [msg.parts[0].text for msg in final_task.history if msg.role == Role.ROLE_AGENT] assert "sync_generator_with_context yield 1" in messages assert "sync_generator_with_context context yield" in messages assert "sync_generator_with_context yield 2" in messages @@ -293,9 +283,9 @@ async def test_async_function_agent(async_function_agent): final_task = await get_final_task_from_stream(client.send_message(message)) assert final_task is not None - assert final_task.status.state == TaskState.completed + assert final_task.status.state == TaskState.TASK_STATE_COMPLETED # pyrefly: ignore [missing-attribute, unsupported-operation] - assert "async_function_agent: hello" in final_task.history[-1].parts[0].root.text + assert "async_function_agent: hello" in final_task.history[-1].parts[0].text async def test_async_function_with_context_agent(async_function_with_context_agent): @@ -306,9 +296,9 @@ async def test_async_function_with_context_agent(async_function_with_context_age final_task = await get_final_task_from_stream(client.send_message(message)) assert final_task is not None - assert final_task.status.state == TaskState.completed + assert final_task.status.state == TaskState.TASK_STATE_COMPLETED # pyrefly: ignore [missing-attribute, not-iterable] - messages = [msg.parts[0].root.text for msg in final_task.history if msg.role.value == "agent"] + messages = [msg.parts[0].text for msg in final_task.history if msg.role == Role.ROLE_AGENT] assert "first async yield" in messages assert "async_function_with_context_agent: hello" in messages @@ -321,9 +311,9 @@ async def test_async_generator_agent(async_generator_agent): final_task = await get_final_task_from_stream(client.send_message(message)) assert final_task is not None - assert final_task.status.state == TaskState.completed + assert final_task.status.state == TaskState.TASK_STATE_COMPLETED # pyrefly: ignore [missing-attribute, not-iterable] - messages = [msg.parts[0].root.text for msg in final_task.history if msg.role.value == "agent"] + messages = [msg.parts[0].text for msg in final_task.history if msg.role == Role.ROLE_AGENT] assert "async_generator yield 1" in messages assert "async_generator yield 2" in messages assert "async_generator_agent: hello" in messages @@ -337,9 +327,9 @@ async def test_async_generator_with_context_agent(async_generator_with_context_a final_task = await get_final_task_from_stream(client.send_message(message)) assert final_task is not None - assert final_task.status.state == TaskState.completed + assert final_task.status.state == TaskState.TASK_STATE_COMPLETED # pyrefly: ignore [missing-attribute, not-iterable] - messages = [msg.parts[0].root.text for msg in final_task.history if msg.role.value == "agent"] + messages = [msg.parts[0].text for msg in final_task.history if msg.role == Role.ROLE_AGENT] assert "async_generator_with_context yield 1" in messages assert "async_generator_with_context context yield" in messages assert "async_generator_with_context yield 2" in messages @@ -355,7 +345,7 @@ async def test_sync_function_resume_agent(sync_function_resume_agent): initial_task = await get_final_task_from_stream(client.send_message(message)) assert initial_task is not None - assert initial_task.status.state == TaskState.input_required + assert initial_task.status.state == TaskState.TASK_STATE_INPUT_REQUIRED # Resume with additional data resume_message = create_text_message_object(content="resume data") @@ -364,9 +354,9 @@ async def test_sync_function_resume_agent(sync_function_resume_agent): final_task = await get_final_task_from_stream(client.send_message(resume_message)) assert final_task is not None - assert final_task.status.state == TaskState.completed + assert final_task.status.state == TaskState.TASK_STATE_COMPLETED # pyrefly: ignore [missing-attribute, unsupported-operation] - assert "sync_function_resume_agent: received resume data" in final_task.history[-1].parts[0].root.text + assert "sync_function_resume_agent: received resume data" in final_task.history[-1].parts[0].text async def test_sync_generator_resume_agent(sync_generator_resume_agent): @@ -378,9 +368,9 @@ async def test_sync_generator_resume_agent(sync_generator_resume_agent): initial_task = await get_final_task_from_stream(client.send_message(message)) assert initial_task is not None - assert initial_task.status.state == TaskState.input_required + assert initial_task.status.state == TaskState.TASK_STATE_INPUT_REQUIRED # pyrefly: ignore [missing-attribute, not-iterable] - messages = [msg.parts[0].root.text for msg in initial_task.history if msg.role.value == "agent"] + messages = [msg.parts[0].text for msg in initial_task.history if msg.role == Role.ROLE_AGENT] assert "sync_generator_resume_agent: starting" in messages # Resume with additional data @@ -391,9 +381,9 @@ async def test_sync_generator_resume_agent(sync_generator_resume_agent): final_task = await get_final_task_from_stream(client.send_message(resume_message)) assert final_task is not None - assert final_task.status.state == TaskState.completed + assert final_task.status.state == TaskState.TASK_STATE_COMPLETED # pyrefly: ignore [missing-attribute, not-iterable] - messages = [msg.parts[0].root.text for msg in final_task.history if msg.role.value == "agent"] + messages = [msg.parts[0].text for msg in final_task.history if msg.role == Role.ROLE_AGENT] assert "sync_generator_resume_agent: received resume data" in messages @@ -406,7 +396,7 @@ async def test_async_function_resume_agent(async_function_resume_agent): initial_task = await get_final_task_from_stream(client.send_message(message)) assert initial_task is not None - assert initial_task.status.state == TaskState.input_required + assert initial_task.status.state == TaskState.TASK_STATE_INPUT_REQUIRED # Resume with additional data resume_message = create_text_message_object(content="resume data") @@ -416,9 +406,9 @@ async def test_async_function_resume_agent(async_function_resume_agent): final_task = await get_final_task_from_stream(client.send_message(resume_message)) assert final_task is not None - assert final_task.status.state == TaskState.completed + assert final_task.status.state == TaskState.TASK_STATE_COMPLETED # pyrefly: ignore [missing-attribute, unsupported-operation] - assert "async_function_resume_agent: received resume data" in final_task.history[-1].parts[0].root.text + assert "async_function_resume_agent: received resume data" in final_task.history[-1].parts[0].text async def test_async_generator_resume_agent(async_generator_resume_agent): @@ -430,9 +420,9 @@ async def test_async_generator_resume_agent(async_generator_resume_agent): initial_task = await get_final_task_from_stream(client.send_message(message)) assert initial_task is not None - assert initial_task.status.state == TaskState.input_required + assert initial_task.status.state == TaskState.TASK_STATE_INPUT_REQUIRED # pyrefly: ignore [missing-attribute, not-iterable] - messages = [msg.parts[0].root.text for msg in initial_task.history if msg.role.value == "agent"] + messages = [msg.parts[0].text for msg in initial_task.history if msg.role == Role.ROLE_AGENT] assert "async_generator_resume_agent: starting" in messages # Resume with additional data @@ -443,9 +433,9 @@ async def test_async_generator_resume_agent(async_generator_resume_agent): final_task = await get_final_task_from_stream(client.send_message(resume_message)) assert final_task is not None - assert final_task.status.state == TaskState.completed + assert final_task.status.state == TaskState.TASK_STATE_COMPLETED # pyrefly: ignore [missing-attribute, not-iterable] - messages = [msg.parts[0].root.text for msg in final_task.history if msg.role.value == "agent"] + messages = [msg.parts[0].text for msg in final_task.history if msg.role == Role.ROLE_AGENT] assert "async_generator_resume_agent: received resume data" in messages @@ -459,11 +449,11 @@ async def test_sync_function_streaming(sync_function_agent): status_events = [] for event in events: match event: - case (_, TaskStatusUpdateEvent() as update): - status_events.append(update) + case (StreamResponse(status_update=TaskStatusUpdateEvent() as status_update), _): + status_events.append(status_update) assert len(status_events) > 0 - assert status_events[-1].status.state == TaskState.completed + assert status_events[-1].status.state == TaskState.TASK_STATE_COMPLETED async def test_sync_generator_streaming(sync_generator_agent): @@ -476,14 +466,14 @@ async def test_sync_generator_streaming(sync_generator_agent): status_events = [] for event in events: match event: - case (_, TaskStatusUpdateEvent() as update): - status_events.append(update) + case (StreamResponse(status_update=TaskStatusUpdateEvent() as status_update), _): + status_events.append(status_update) assert len(status_events) > 0 - assert status_events[-1].status.state == TaskState.completed + assert status_events[-1].status.state == TaskState.TASK_STATE_COMPLETED # Should see multiple working state messages for each yield - working_events = [e for e in status_events if e.status.state == TaskState.working] + working_events = [e for e in status_events if e.status.state == TaskState.TASK_STATE_WORKING] assert len(working_events) >= 3 # At least 3 yields from the generator @@ -495,16 +485,15 @@ async def test_async_generator_streaming(async_generator_agent): events.append(event) status_events = [] - for event in events: - match event: - case (_, TaskStatusUpdateEvent() as update): - status_events.append(update) + for resp, _ in events: + if MessageToDict(resp.status_update.status): + status_events.append(resp.status_update) assert len(status_events) > 0 - assert status_events[-1].status.state == TaskState.completed + assert status_events[-1].status.state == TaskState.TASK_STATE_COMPLETED # Should see multiple working state messages for each yield - working_events = [e for e in status_events if e.status.state == TaskState.working] + working_events = [e for e in status_events if e.status.state == TaskState.TASK_STATE_WORKING] assert len(working_events) >= 2 # At least 2 yields from the generator @@ -523,13 +512,13 @@ async def yielder_of_meta_data() -> AsyncIterator[RunYield]: final_task = await get_final_task_from_stream(client.send_message(message)) assert final_task is not None - assert final_task.status.state == TaskState.completed + assert final_task.status.state == TaskState.TASK_STATE_COMPLETED # pyrefly: ignore [missing-attribute, unsupported-operation] - assert final_task.history[0].parts[0].root.data == {"data": "this should be datapart"} + assert MessageToDict(final_task.history[0].parts[0].data) == {"data": "this should be datapart"} # pyrefly: ignore [unsupported-operation] - assert final_task.history[1].metadata == {"metadata": "this should be metadata"} + assert MessageToDict(final_task.history[1].metadata) == {"metadata": "this should be metadata"} # pyrefly: ignore [unsupported-operation] - assert final_task.history[2].metadata == { + assert MessageToDict(final_task.history[2].metadata) == { "metadata": "this class still behaves as dict", "metadata2": "and can be used in union", } @@ -544,19 +533,18 @@ async def yielder_of_meta_data() -> AsyncIterator[RunYield]: async def test_yield_of_all_types(create_server_with_agent): async def yielder_of_all_types_agent(message: Message, context: RunContext) -> AsyncIterator[RunYield]: """Synchronous function agent that returns a string directly.""" - text_part = TextPart(text="text") - message = AgentMessage(parts=[text_part], role=Role.agent, message_id=str(uuid.uuid4())) + text_part = Part(text="text") + message = AgentMessage(parts=[text_part], role=Role.ROLE_AGENT, message_id=str(uuid.uuid4())) yield message yield text_part - yield TaskStatus(message=message, state=TaskState.working) + yield TaskStatus(message=message, state=TaskState.TASK_STATE_WORKING) yield AgentArtifact(parts=[text_part]) - yield FilePart(file=FileWithBytes(bytes="0", name="test.txt")) - yield DataPart(data={"a": 1}) + yield Part(raw=b"0", filename="test.txt") + yield Part(data=ParseDict({"a": 1}, Value())) yield TaskStatusUpdateEvent( - status=TaskStatus(state=TaskState.working, message=message), + status=TaskStatus(state=TaskState.TASK_STATE_WORKING, message=message), task_id=context.task_id, context_id=context.context_id, - final=False, ) yield TaskArtifactUpdateEvent( artifact=AgentArtifact(artifact_id=str(uuid.uuid4()), parts=[text_part]), @@ -571,9 +559,17 @@ async def yielder_of_all_types_agent(message: Message, context: RunContext) -> A message_cnt, artifact_cnt = 0, 0 async for event in client.send_message(create_text_message_object(content="hello")): match event: - case (Task(), TaskStatusUpdateEvent(status=TaskStatus(message=msg))) if msg: + case ( + StreamResponse( + status_update=TaskStatusUpdateEvent(status=TaskStatus(message=Message(message_id=message_id))) + ), + _, + ) if message_id: message_cnt += 1 - case (Task(), TaskArtifactUpdateEvent()): + case ( + StreamResponse(artifact_update=TaskArtifactUpdateEvent(artifact=Artifact(artifact_id=artifact_id))), + _, + ) if artifact_id: artifact_cnt += 1 assert message_cnt == 9 assert artifact_cnt == 2 diff --git a/apps/agentstack-sdk-py/tests/unit/a2a/test_types.py b/apps/agentstack-sdk-py/tests/unit/a2a/test_types.py new file mode 100644 index 0000000000..bae1919bc2 --- /dev/null +++ b/apps/agentstack-sdk-py/tests/unit/a2a/test_types.py @@ -0,0 +1,118 @@ +import uuid + +import pytest + +from agentstack_sdk.a2a.types import ( + AgentMessage, + Artifact, + ArtifactChunk, + Message, + Part, + Role, + TaskState, + TaskStatus, + validate_message, +) + +pytestmark = pytest.mark.unit + + +def valid_part(): + return Part(text="valid content") + + +def valid_message_kwargs(): + return {"message_id": str(uuid.uuid4()), "role": Role.ROLE_USER, "parts": [valid_part()]} + + +def test_artifact_chunk(): + artifact = ArtifactChunk( + parts=[valid_part()], + artifact_id=str(uuid.uuid4()), + ) + assert artifact.metadata["_last_chunk"] is False + + +def test_message_validation_required_fields(): + """Test that Message raises ValueError if required fields are missing.""" + + # 1. Missing message_id + with pytest.raises(ValueError, match="message_id is required"): + validate_message(Message(role=Role.ROLE_USER, parts=[valid_part()])) + + # 2. Missing role + with pytest.raises(ValueError, match="role is required"): + validate_message(Message(message_id=str(uuid.uuid4()), parts=[valid_part()])) + + # 3. Missing parts + # 4. Empty parts (Repeated field required check) + # TODO: enable when array length is checked + # with pytest.raises(ValueError, match="parts is required"): + # validate_message(Message(message_id=str(uuid.uuid4()), role=Role.ROLE_USER)) + + +def test_agent_message_wrapper(): + """Test AgentMessage wrapper class which provides defaults.""" + # Valid creation with text + am = AgentMessage(text="hello") + assert am.role == Role.ROLE_AGENT + assert am.parts[0].text == "hello" + assert am.message_id is not None + + # Valid creation with parts + am2 = AgentMessage(parts=[valid_part()]) + assert am2.parts[0].text == "valid content" + + # TODO: enable when array length is checked + # # Invalid: No content + # with pytest.raises(ValueError, match="parts is required"): + # validate_message(AgentMessage()) + + +def test_artifact_validation(): + """Test Artifact validation.""" + # Artifact requires artifact_id and parts + + # 1. Valid artifact + _ = Artifact(artifact_id=str(uuid.uuid4()), parts=[valid_part()]) + + # 2. Missing artifact_id + with pytest.raises(ValueError, match="artifact_id is required"): + validate_message(Artifact(parts=[valid_part()])) + + # 3. Missing parts + # TODO: enable when array length is checked + # # Invalid: No content + # with pytest.raises(ValueError, match="parts is required"): + # validate_message(Artifact(artifact_id=str(uuid.uuid4()))) + + +def test_task_status_validation(): + """Test TaskStatus validation.""" + # TaskStatus requires state + + # 1. Valid + ts = TaskStatus(state=TaskState.TASK_STATE_WORKING) + + # 2. Missing state (it's an enum, default is 0 which is UNSPECIFIED) + with pytest.raises(ValueError, match="state is required"): + validate_message(TaskStatus()) # Should default to 0 + + # Explicitly setting 0 + with pytest.raises(ValueError, match="state is required"): + validate_message(TaskStatus(state=TaskState.TASK_STATE_UNSPECIFIED)) + + +def test_struct_map_validation(): + """Test validation handles protobuf Struct/Map fields correctly without crashing.""" + # This specifically tests the fix for the AttributeError on Struct map fields. + a = Artifact( + artifact_id=str(uuid.uuid4()), + parts=[valid_part()], + metadata={"int_val": 1, "str_val": "test", "bool_val": True}, + ) + # Should not raise any validation errors + validate_message(a) + + # The metadata should be accessible and correctly populated + assert a.metadata["str_val"] == "test" diff --git a/apps/agentstack-sdk-py/uv.lock b/apps/agentstack-sdk-py/uv.lock index 2a6968bfc7..fa9d8a0fed 100644 --- a/apps/agentstack-sdk-py/uv.lock +++ b/apps/agentstack-sdk-py/uv.lock @@ -8,19 +8,17 @@ resolution-markers = [ [[package]] name = "a2a-sdk" -version = "0.3.24" -source = { registry = "https://pypi.org/simple" } +version = "0.3.24.post37.dev0+dce3650" +source = { git = "https://github.com/a2aproject/a2a-python.git?rev=1.0-dev#dce36502b51f671ae0e0a926cc0ad8c208393329" } dependencies = [ { name = "google-api-core" }, + { name = "googleapis-common-protos" }, { name = "httpx" }, { name = "httpx-sse" }, + { name = "json-rpc" }, { name = "protobuf" }, { name = "pydantic" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ad/76/cefa956fb2d3911cb91552a1da8ce2dbb339f1759cb475e2982f0ae2332b/a2a_sdk-0.3.24.tar.gz", hash = "sha256:3581e6e8a854cd725808f5732f90b7978e661b6d4e227a4755a8f063a3c1599d", size = 255550, upload-time = "2026-02-20T10:05:43.423Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/10/6e/cae5f0caea527b39c0abd7204d9416768764573c76649ca03cc345a372be/a2a_sdk-0.3.24-py3-none-any.whl", hash = "sha256:7b248767096bb55311f57deebf6b767349388d94c1b376c60cb8f6b715e053f6", size = 145752, upload-time = "2026-02-20T10:05:41.729Z" }, -] [[package]] name = "agentstack-sdk" @@ -63,7 +61,7 @@ dev = [ [package.metadata] requires-dist = [ - { name = "a2a-sdk", specifier = "==0.3.24" }, + { name = "a2a-sdk", git = "https://github.com/a2aproject/a2a-python.git?rev=1.0-dev" }, { name = "anyio", specifier = ">=4.9.0" }, { name = "async-lru", specifier = ">=2.0.4" }, { name = "asyncclick", specifier = ">=8.1.8" }, @@ -94,7 +92,7 @@ dev = [ { name = "pytest", specifier = ">=8.4.1" }, { name = "pytest-asyncio", specifier = ">=1.1.0" }, { name = "pytest-httpx", specifier = ">=0.35.0" }, - { name = "ruff", specifier = ">=0.12.3" }, + { name = "ruff", specifier = ">=0.15.0" }, ] [[package]] @@ -1222,6 +1220,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/29/c1/7cad04a5d6248a38656b0cdb267697e67b174fe21c61fb9bbfe0995591f4/json_repair-0.52.5-py3-none-any.whl", hash = "sha256:031a84536c93df1de3fb8c8554393da69111e375109cac3ff3d7c68158d68633", size = 26733, upload-time = "2025-11-06T16:09:26.532Z" }, ] +[[package]] +name = "json-rpc" +version = "1.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6d/9e/59f4a5b7855ced7346ebf40a2e9a8942863f644378d956f68bcef2c88b90/json-rpc-1.15.0.tar.gz", hash = "sha256:e6441d56c1dcd54241c937d0a2dcd193bdf0bdc539b5316524713f554b7f85b9", size = 28854, upload-time = "2023-06-11T09:45:49.078Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/9e/820c4b086ad01ba7d77369fb8b11470a01fac9b4977f02e18659cf378b6b/json_rpc-1.15.0-py2.py3-none-any.whl", hash = "sha256:4a4668bbbe7116feb4abbd0f54e64a4adcf4b8f648f19ffa0848ad0f6606a9bf", size = 39450, upload-time = "2023-06-11T09:45:47.136Z" }, +] + [[package]] name = "jsonref" version = "1.1.0" diff --git a/apps/agentstack-server/tests/e2e/agents/conftest.py b/apps/agentstack-server/tests/e2e/agents/conftest.py index 1710f0bfc0..5e9b875cfb 100644 --- a/apps/agentstack-server/tests/e2e/agents/conftest.py +++ b/apps/agentstack-server/tests/e2e/agents/conftest.py @@ -46,8 +46,8 @@ async def run_server( raise ConnectionError("Server hasn't started yet") providers = [p for p in await Provider.list() if f":{port}" in p.source] assert len(providers) == 1, "Provider not registered" - async with a2a_client_factory(providers[0].agent_card, context_token=context_token) as client: - yield server, client + async with a2a_client_factory(providers[0].agent_card, context_token=context_token) as client: + yield server, client finally: server.should_exit = True From 48fa8d8882e95398bc8ab36981c3f6902a0c7b3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radek=20Je=C5=BEek?= Date: Tue, 24 Feb 2026 15:04:19 +0100 Subject: [PATCH 3/6] chore(a2a): migrate server, cli MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Radek Ježek --- agents/chat/Dockerfile | 1 + agents/chat/src/chat/agent.py | 6 +- agents/chat/src/chat/tools/files/model.py | 6 +- agents/chat/src/chat/tools/files/utils.py | 21 +- agents/chat/uv.lock | 211 +++-- .../src/content_builder/agent.py | 2 +- agents/rag/src/rag/agent.py | 2 +- apps/agentstack-cli/.vscode/launch.json | 20 + .../src/agentstack_cli/__main__.py | 6 + apps/agentstack-cli/src/agentstack_cli/api.py | 5 +- .../src/agentstack_cli/commands/agent.py | 217 ++--- .../src/agentstack_cli/utils.py | 7 +- apps/agentstack-cli/uv.lock | 92 +- .../examples/check_validation.py | 3 + apps/agentstack-sdk-py/examples/experiment.py | 5 +- .../a2a/extensions/auth/oauth/oauth.py | 17 +- .../a2a/extensions/auth/secrets/secrets.py | 13 +- .../src/agentstack_sdk/a2a/extensions/base.py | 11 +- .../a2a/extensions/interactions/approval.py | 21 +- .../a2a/extensions/services/embedding.py | 10 + .../a2a/extensions/services/llm.py | 10 + .../a2a/extensions/services/mcp.py | 13 + .../a2a/extensions/services/platform.py | 9 + .../a2a/extensions/tools/call.py | 18 +- .../a2a/extensions/ui/canvas.py | 15 +- .../a2a/extensions/ui/citation.py | 2 +- .../a2a/extensions/ui/form_request.py | 8 +- .../a2a/extensions/ui/trajectory.py | 2 +- .../src/agentstack_sdk/platform/file.py | 2 +- .../src/agentstack_sdk/platform/provider.py | 1 - .../platform/provider_discovery.py | 2 +- .../src/agentstack_sdk/server/agent.py | 36 +- .../middleware/platform_auth_backend.py | 13 +- .../src/agentstack_sdk/server/server.py | 8 +- .../src/agentstack_sdk/util/file.py | 2 +- apps/agentstack-sdk-py/tests/e2e/conftest.py | 4 +- .../tests/unit/a2a/test_types.py | 5 +- .../unit/test_agent_detail_population.py | 20 +- apps/agentstack-sdk-py/uv.lock | 238 +++-- apps/agentstack-server/Dockerfile | 1 + .../src/agentstack_server/api/auth/auth.py | 2 +- .../src/agentstack_server/api/routes/a2a.py | 66 +- .../agentstack_server/api/routes/providers.py | 14 +- .../agentstack_server/api/schema/provider.py | 6 +- .../domain/models/context.py | 7 +- .../domain/models/provider.py | 28 +- .../domain/models/provider_discovery.py | 4 +- .../persistence/repositories/context.py | 2 +- .../persistence/repositories/provider.py | 2 +- .../repositories/provider_discovery.py | 2 +- .../persistence/repositories/requests.py | 3 + .../agentstack_server/jobs/crons/provider.py | 7 +- .../service_layer/services/a2a.py | 203 +++-- .../service_layer/services/contexts.py | 36 +- .../services/provider_discovery.py | 30 +- .../service_layer/services/providers.py | 24 +- .../src/agentstack_server/utils/a2a.py | 9 +- apps/agentstack-server/tests/conftest.py | 6 +- .../tests/e2e/agents/test_agent_builds.py | 9 +- .../tests/e2e/agents/test_agent_starts.py | 49 +- .../tests/e2e/agents/test_context_store.py | 14 +- .../e2e/agents/test_platform_extensions.py | 35 +- apps/agentstack-server/tests/e2e/conftest.py | 16 +- .../agent-settings/test_basic_settings.py | 4 +- .../canvas/test_canvas_with_llm.py | 8 +- .../citations/test_citation_basic_usage.py | 4 +- .../test_basic_environment_variables.py | 4 +- .../error/test_adding_error_context.py | 2 +- .../error/test_advanced_error_reporting.py | 2 +- .../error/test_multiple_errors_handling.py | 2 +- .../error/test_standard_error_reporting.py | 2 +- .../files/test_file_processing.py | 8 +- .../forms/test_dynamic_form_requests.py | 6 +- .../forms/test_initial_form_rendering.py | 4 +- .../llm-proxy-service/test_llm_access.py | 4 +- .../mcp/test_custom_mcp_client_with_oauth.py | 10 +- .../mcp/test_github_mcp_agent.py | 2 +- .../multi-turn/test_advanced_history.py | 8 +- .../multi-turn/test_basic_history.py | 8 +- .../overview/test_advanced_server_wrapper.py | 6 +- .../overview/test_dependency_injection.py | 8 +- .../overview/test_server_wrapper.py | 4 +- .../rag/test_conversation_rag_agent.py | 22 +- .../rag/test_simple_rag_agent.py | 12 +- .../secrets/test_basic_secrets.py | 10 +- .../tool-calls/test_basic_approve.py | 16 +- .../trajectory/test_trajectory_basic_usage.py | 4 +- .../tests/e2e/examples/conftest.py | 14 +- .../test_implement_your_agent_logic.py | 4 +- .../tests/e2e/routes/test_a2a_proxy.py | 817 ++++++++++-------- .../tests/e2e/routes/test_contexts.py | 24 +- .../e2e/routes/test_provider_variables.py | 13 +- .../tests/e2e/routes/test_providers.py | 13 +- .../persistence/repositories/test_provider.py | 29 +- .../tests/integration/utils/test_docker.py | 11 +- apps/agentstack-server/uv.lock | 215 ++--- docs/development/agent-integration/files.mdx | 6 +- .../src/file_processing/agent.py | 2 +- 98 files changed, 1620 insertions(+), 1347 deletions(-) create mode 100644 apps/agentstack-cli/.vscode/launch.json create mode 100644 apps/agentstack-cli/src/agentstack_cli/__main__.py diff --git a/agents/chat/Dockerfile b/agents/chat/Dockerfile index b8f44c56fd..c1ce9b1fc4 100644 --- a/agents/chat/Dockerfile +++ b/agents/chat/Dockerfile @@ -3,6 +3,7 @@ ARG UV_VERSION=0.10.7 FROM ghcr.io/astral-sh/uv:${UV_VERSION} AS uv FROM python:3.14-alpine3.23@sha256:faee120f7885a06fcc9677922331391fa690d911c020abb9e8025ff3d908e510 ARG RELEASE_VERSION="main" +RUN apk add bash git nodejs npm COPY ./agents/chat/ /app/agents/chat COPY ./apps/agentstack-sdk-py/ /app/apps/agentstack-sdk-py/ WORKDIR /app/agents/chat diff --git a/agents/chat/src/chat/agent.py b/agents/chat/src/chat/agent.py index 1d1dd55d46..86c6bbbb73 100644 --- a/agents/chat/src/chat/agent.py +++ b/agents/chat/src/chat/agent.py @@ -24,8 +24,6 @@ LLMServiceExtensionSpec, TrajectoryExtensionServer, TrajectoryExtensionSpec, -) -from agentstack_sdk.a2a.extensions.services.platform import ( PlatformApiExtensionServer, PlatformApiExtensionSpec, ) @@ -268,8 +266,8 @@ async def chat( if isinstance(last_step.output, FileCreatorToolOutput): for file_info in last_step.output.result.files: - part = file_info.file.to_file_part() - part.file.name = file_info.display_filename + part = file_info.file.to_part() + part.filename = file_info.display_filename artifact = AgentArtifact(name=file_info.display_filename, parts=[part]) yield artifact await context.store(artifact) diff --git a/agents/chat/src/chat/tools/files/model.py b/agents/chat/src/chat/tools/files/model.py index de805033ae..dee512e57a 100644 --- a/agents/chat/src/chat/tools/files/model.py +++ b/agents/chat/src/chat/tools/files/model.py @@ -17,12 +17,12 @@ class OriginType(StrEnum): ORIGIN_TYPE_BY_ROLE = { - Role.user: OriginType.UPLOADED, - Role.agent: OriginType.GENERATED, + Role.ROLE_USER: OriginType.UPLOADED, + Role.ROLE_AGENT: OriginType.GENERATED, } -class FileChatInfo(BaseModel): +class FileChatInfo(BaseModel, arbitrary_types_allowed=True): file: File display_filename: str # A sanitized version of the filename used for display, in case of naming conflicts. role: Role diff --git a/agents/chat/src/chat/tools/files/utils.py b/agents/chat/src/chat/tools/files/utils.py index 729ec0062f..b0c3dfbe67 100644 --- a/agents/chat/src/chat/tools/files/utils.py +++ b/agents/chat/src/chat/tools/files/utils.py @@ -8,7 +8,7 @@ from typing import Iterable import pydantic -from a2a.types import FilePart, FileWithUri, Message, Role +from a2a.types import Message, Role from beeai_framework.backend import AnyMessage, AssistantMessage, UserMessage from agentstack_sdk.platform import File @@ -17,14 +17,14 @@ def to_framework_message(message: Message, all_attachments: list[FileChatInfo]) -> AnyMessage: - message_text = "".join(part.root.text for part in message.parts if part.root.kind == "text") + message_text = "".join(part.text for part in message.parts if part.HasField("text")) if attachments := [file for file in all_attachments if file.message_id == message.message_id]: message_text += "\nAttached files:\n" + "\n".join([file.description for file in attachments]) match message.role: - case Role.agent: + case Role.ROLE_AGENT: return AssistantMessage(message_text) - case Role.user: + case Role.ROLE_USER: return UserMessage(message_text) case _: raise ValueError(f"Invalid message role: {message.role}") @@ -46,13 +46,12 @@ async def extract_files(history: list[Message]) -> list[FileChatInfo]: for item in history: for part in item.parts: - match part.root: - case FilePart(file=FileWithUri(uri=uri)): - with suppress(ValueError): - url = pydantic.type_adapter.TypeAdapter(PlatformFileUrl).validate_python(uri) - if url.file_id not in seen: - seen.add(url.file_id) - files[url.file_id] = item + if part.HasField("url"): + with suppress(ValueError): + url = pydantic.type_adapter.TypeAdapter(PlatformFileUrl).validate_python(part.url) + if url.file_id not in seen: + seen.add(url.file_id) + files[url.file_id] = item # TODO: N+1 query issue, add bulk endpoint file_objects = await asyncio.gather(*(File.get(file_id) for file_id in files)) diff --git a/agents/chat/uv.lock b/agents/chat/uv.lock index 3884f26e96..9646b58a64 100644 --- a/agents/chat/uv.lock +++ b/agents/chat/uv.lock @@ -341,11 +341,11 @@ wheels = [ [[package]] name = "certifi" -version = "2026.1.4" +version = "2026.2.25" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e0/2d/a891ca51311197f6ad14a7ef42e2399f36cf2f9bd44752b3dc4eab60fdc5/certifi-2026.1.4.tar.gz", hash = "sha256:ac726dd470482006e014ad384921ed6438c457018f4b3d204aea4281258b2120", size = 154268, upload-time = "2026-01-04T02:42:41.825Z" } +sdist = { url = "https://files.pythonhosted.org/packages/af/2d/7bf41579a8986e348fa033a31cdd0e4121114f6bce2457e8876010b092dd/certifi-2026.2.25.tar.gz", hash = "sha256:e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7", size = 155029, upload-time = "2026-02-25T02:54:17.342Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c", size = 152900, upload-time = "2026-01-04T02:42:40.15Z" }, + { url = "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl", hash = "sha256:027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa", size = 153684, upload-time = "2026-02-25T02:54:15.766Z" }, ] [[package]] @@ -576,7 +576,7 @@ wheels = [ [[package]] name = "fastapi" -version = "0.131.0" +version = "0.133.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "annotated-doc" }, @@ -585,9 +585,9 @@ dependencies = [ { name = "typing-extensions" }, { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/91/32/158cbf685b7d5a26f87131069da286bf10fc9fbf7fc968d169d48a45d689/fastapi-0.131.0.tar.gz", hash = "sha256:6531155e52bee2899a932c746c9a8250f210e3c3303a5f7b9f8a808bfe0548ff", size = 369612, upload-time = "2026-02-22T16:38:11.252Z" } +sdist = { url = "https://files.pythonhosted.org/packages/22/6f/0eafed8349eea1fa462238b54a624c8b408cd1ba2795c8e64aa6c34f8ab7/fastapi-0.133.1.tar.gz", hash = "sha256:ed152a45912f102592976fde6cbce7dae1a8a1053da94202e51dd35d184fadd6", size = 378741, upload-time = "2026-02-25T18:18:17.398Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ff/94/b58ec24c321acc2ad1327f69b033cadc005e0f26df9a73828c9e9c7db7ce/fastapi-0.131.0-py3-none-any.whl", hash = "sha256:ed0e53decccf4459de78837ce1b867cd04fa9ce4579497b842579755d20b405a", size = 103854, upload-time = "2026-02-22T16:38:09.814Z" }, + { url = "https://files.pythonhosted.org/packages/d2/c9/a175a7779f3599dfa4adfc97a6ce0e157237b3d7941538604aadaf97bfb6/fastapi-0.133.1-py3-none-any.whl", hash = "sha256:658f34ba334605b1617a65adf2ea6461901bdb9af3a3080d63ff791ecf7dc2e2", size = 109029, upload-time = "2026-02-25T18:18:18.578Z" }, ] [[package]] @@ -712,72 +712,72 @@ wheels = [ [[package]] name = "grpcio" -version = "1.78.1" +version = "1.78.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/1f/de/de568532d9907552700f80dcec38219d8d298ad9e71f5e0a095abaf2761e/grpcio-1.78.1.tar.gz", hash = "sha256:27c625532d33ace45d57e775edf1982e183ff8641c72e4e91ef7ba667a149d72", size = 12835760, upload-time = "2026-02-20T01:16:10.869Z" } +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/96/3a/2d2ec4d2ce2eb9d6a2b862630a0d9d4ff4239ecf1474ecff21442a78612a/grpcio-1.78.1-cp314-cp314-linux_armv7l.whl", hash = "sha256:d101fe49b1e0fb4a7aa36ed0c3821a0f67a5956ef572745452d2cd790d723a3f", size = 5920256, upload-time = "2026-02-20T01:15:00.23Z" }, - { url = "https://files.pythonhosted.org/packages/9c/92/dccb7d087a1220ed358753945230c1ddeeed13684b954cb09db6758f1271/grpcio-1.78.1-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:5ce1855e8cfc217cdf6bcfe0cf046d7cf81ddcc3e6894d6cfd075f87a2d8f460", size = 11813749, upload-time = "2026-02-20T01:15:03.312Z" }, - { url = "https://files.pythonhosted.org/packages/ef/47/c20e87f87986da9998f30f14776ce27e61f02482a3a030ffe265089342c6/grpcio-1.78.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cd26048d066b51f39fe9206e2bcc2cea869a5e5b2d13c8d523f4179193047ebd", size = 6488739, upload-time = "2026-02-20T01:15:14.349Z" }, - { url = "https://files.pythonhosted.org/packages/a6/c2/088bd96e255133d7d87c3eed0d598350d16cde1041bdbe2bb065967aaf91/grpcio-1.78.1-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:4b8d7fda614cf2af0f73bbb042f3b7fee2ecd4aea69ec98dbd903590a1083529", size = 7173096, upload-time = "2026-02-20T01:15:17.687Z" }, - { url = "https://files.pythonhosted.org/packages/60/ce/168db121073a03355ce3552b3b1f790b5ded62deffd7d98c5f642b9d3d81/grpcio-1.78.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:656a5bd142caeb8b1efe1fe0b4434ecc7781f44c97cfc7927f6608627cf178c0", size = 6693861, upload-time = "2026-02-20T01:15:20.911Z" }, - { url = "https://files.pythonhosted.org/packages/ae/d0/90b30ec2d9425215dd56922d85a90babbe6ee7e8256ba77d866b9c0d3aba/grpcio-1.78.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:99550e344482e3c21950c034f74668fccf8a546d50c1ecb4f717543bbdc071ba", size = 7278083, upload-time = "2026-02-20T01:15:23.698Z" }, - { url = "https://files.pythonhosted.org/packages/c1/fb/73f9ba0b082bcd385d46205095fd9c917754685885b28fce3741e9f54529/grpcio-1.78.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:8f27683ca68359bd3f0eb4925824d71e538f84338b3ae337ead2ae43977d7541", size = 8252546, upload-time = "2026-02-20T01:15:26.517Z" }, - { url = "https://files.pythonhosted.org/packages/85/c5/6a89ea3cb5db6c3d9ed029b0396c49f64328c0cf5d2630ffeed25711920a/grpcio-1.78.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:a40515b69ac50792f9b8ead260f194ba2bb3285375b6c40c7ff938f14c3df17d", size = 7696289, upload-time = "2026-02-20T01:15:29.718Z" }, - { url = "https://files.pythonhosted.org/packages/3d/05/63a7495048499ef437b4933d32e59b7f737bd5368ad6fb2479e2bd83bf2c/grpcio-1.78.1-cp314-cp314-win32.whl", hash = "sha256:2c473b54ef1618f4fb85e82ff4994de18143b74efc088b91b5a935a3a45042ba", size = 4142186, upload-time = "2026-02-20T01:15:32.786Z" }, - { url = "https://files.pythonhosted.org/packages/1c/ce/adfe7e5f701d503be7778291757452e3fab6b19acf51917c79f5d1cf7f8a/grpcio-1.78.1-cp314-cp314-win_amd64.whl", hash = "sha256:e2a6b33d1050dce2c6f563c5caf7f7cbeebf7fba8cde37ffe3803d50526900d1", size = 4932000, upload-time = "2026-02-20T01:15:36.127Z" }, + { 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]] name = "grpcio-health-checking" -version = "1.78.1" +version = "1.78.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "grpcio" }, { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/3f/c8/4eb8869ec990cdd5a4b50803c2e89826c99eab69d438d79d07ce171a9bf0/grpcio_health_checking-1.78.1.tar.gz", hash = "sha256:563cba3cfa776ae739153dc89b14ddd75d49dba317f82c23eaf20e5b3a01f554", size = 17012, upload-time = "2026-02-20T01:21:47.791Z" } +sdist = { url = "https://files.pythonhosted.org/packages/8e/ac/8eb871f4e47b11abfe45497e6187a582ec680ccd7232706d228474a8c7a5/grpcio_health_checking-1.78.0.tar.gz", hash = "sha256:78526d5c60b9b99fd18954b89f86d70033c702e96ad6ccc9749baf16136979b3", size = 17008, upload-time = "2026-02-06T10:01:47.269Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2d/57/17bc23636e8891eebb164a7c14e2b2d9b778dad9551dcc09df254e036b48/grpcio_health_checking-1.78.1-py3-none-any.whl", hash = "sha256:9e9d3f6edbf11ebbf8aaceee1fc7aa831e667419ad567de288312c3d82fa8406", size = 19009, upload-time = "2026-02-20T01:21:32.789Z" }, + { url = "https://files.pythonhosted.org/packages/8e/30/dbaf47e2210697e2923b49eb62a6a2c07d5ee55bb40cff1e6cc0c5bb22e1/grpcio_health_checking-1.78.0-py3-none-any.whl", hash = "sha256:309798c098c5de72a9bff7172d788fdf309d246d231db9955b32e7c1c773fbeb", size = 19010, upload-time = "2026-02-06T10:01:37.949Z" }, ] [[package]] name = "grpcio-reflection" -version = "1.78.1" +version = "1.78.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "grpcio" }, { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/4d/f1/389fbbff18e84fdde609114eae37e74d8ae23e3f48266769d1fe2486b754/grpcio_reflection-1.78.1.tar.gz", hash = "sha256:224c0d604207954923fd6f8dbec541e0976a64ab1be65d2ee40844ce16c762ab", size = 19116, upload-time = "2026-02-20T01:21:49.703Z" } +sdist = { url = "https://files.pythonhosted.org/packages/31/06/337546aae558675f79cae2a8c1ce0c9b1952cbc5c28b01878f68d040f5bb/grpcio_reflection-1.78.0.tar.gz", hash = "sha256:e6e60c0b85dbcdf963b4d4d150c0f1d238ba891d805b575c52c0365d07fc0c40", size = 19098, upload-time = "2026-02-06T10:01:52.225Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/29/8f3ad00c7cfd97decd0a9b1c0e5422adf684736c639c7a9d840a1f9166e6/grpcio_reflection-1.78.1-py3-none-any.whl", hash = "sha256:222c4c3d1367fc4c6bf53d556229e3735f54ab4710b4aee541f7f741de069ba0", size = 22801, upload-time = "2026-02-20T01:21:34.143Z" }, + { url = "https://files.pythonhosted.org/packages/df/6d/4d095d27ccd049865ecdafc467754e9e47ad0f677a30dda969c3590f6582/grpcio_reflection-1.78.0-py3-none-any.whl", hash = "sha256:06fcfde9e6888cdd12e9dd1cf6dc7c440c2e9acf420f696ccbe008672ed05b60", size = 22800, upload-time = "2026-02-06T10:01:33.822Z" }, ] [[package]] name = "grpcio-tools" -version = "1.78.1" +version = "1.78.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "grpcio" }, { name = "protobuf" }, { name = "setuptools" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c9/e5/311efa9278a451291e317286babf3f69b1479f8e6fd244836e3803e4b81d/grpcio_tools-1.78.1.tar.gz", hash = "sha256:f47b746b06a940954b9aa86b1824aa4874f068a7ec2d4b407980d202c86a691a", size = 5392610, upload-time = "2026-02-20T01:19:44.109Z" } +sdist = { url = "https://files.pythonhosted.org/packages/8b/d1/cbefe328653f746fd319c4377836a25ba64226e41c6a1d7d5cdbc87a459f/grpcio_tools-1.78.0.tar.gz", hash = "sha256:4b0dd86560274316e155d925158276f8564508193088bc43e20d3f5dff956b2b", size = 5393026, upload-time = "2026-02-06T09:59:59.53Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5e/5b/76d7969539159a22dfa20c23c3885ce9024a12d88e23d76063a1e1df566d/grpcio_tools-1.78.1-cp314-cp314-linux_armv7l.whl", hash = "sha256:11c6a338c227e5aab76954f35959682d59c432a5b6d7db053fa1a99c7124bbde", size = 2546269, upload-time = "2026-02-20T01:18:30.673Z" }, - { url = "https://files.pythonhosted.org/packages/3f/8a/a1d180e7165bbdd30d109a448c95d6077eaa9afe40a2ed159f40bec64ce3/grpcio_tools-1.78.1-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:090aeaa053f728539d0f84658bb5d88411a913cbcc49e990b5a80acd3c46dc94", size = 5705752, upload-time = "2026-02-20T01:18:33.396Z" }, - { url = "https://files.pythonhosted.org/packages/43/5c/067b95424eee7cb980a2237c3ecd23935ea742b17acf4411064a727ec9b0/grpcio_tools-1.78.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:203347a50b00e6a1793c35af437a39449b247b9461a9f1f9b9baf954b4255cd8", size = 2593895, upload-time = "2026-02-20T01:18:36.746Z" }, - { url = "https://files.pythonhosted.org/packages/01/1f/6edd882a7c47f74321aeec98ef20b7c54c4fa61c81bb08039b14c1777de2/grpcio_tools-1.78.1-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:7c3cef48b10cccfc039b5ae054d7ad8d7b907ff03a283b606b3999ce3843b5a5", size = 2905296, upload-time = "2026-02-20T01:18:41.875Z" }, - { url = "https://files.pythonhosted.org/packages/a4/15/2ecacd23670fd8bc945fa1a3ae5ad0916c95d9803ceda0b7427d9dfc4ee0/grpcio_tools-1.78.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:abb2aee19b91d619670a3598faaa8036b31dd96708ab82d8fb990da4b5c3fc01", size = 2656183, upload-time = "2026-02-20T01:18:44.556Z" }, - { url = "https://files.pythonhosted.org/packages/60/36/ec4b0172f803f7add82bcc16346b47a80ca983539dc5bf779da1d44f3b4a/grpcio_tools-1.78.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b6307ce936cd5f7714bba75e8b7c71f4e6a4da625b907960227568022ee812fa", size = 3109860, upload-time = "2026-02-20T01:18:47.218Z" }, - { url = "https://files.pythonhosted.org/packages/79/85/6fb37b10667764505f9bc6baab9bccaaa0777bfe07aa786f9e1d4f482253/grpcio_tools-1.78.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:40aad3da94bf261792ff998084117f6ce092b7b137dcea257628def834b91e96", size = 3657914, upload-time = "2026-02-20T01:18:59.138Z" }, - { url = "https://files.pythonhosted.org/packages/42/11/da86c93b0d00f5180d283740c89aa998f955c7389ff268128b99c5bebdb9/grpcio_tools-1.78.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:36dbd00415376a3db03cd57a8063dfb5506c3ec69737945488f6c28a3e8b5cf1", size = 3324719, upload-time = "2026-02-20T01:19:01.55Z" }, - { url = "https://files.pythonhosted.org/packages/9d/b6/6a00609300fbfe2163183522005911f4676bc80db374d55c2a9d9e70997e/grpcio_tools-1.78.1-cp314-cp314-win32.whl", hash = "sha256:6d284037ff456842324fa12b0a6455fce0b3ab92f218677b34c33cf4787a54c4", size = 1015537, upload-time = "2026-02-20T01:19:04.289Z" }, - { url = "https://files.pythonhosted.org/packages/05/76/ef3d2f5a86da2b3a2abcef7141bc4d2d8d119b0da389029811a4507b499b/grpcio_tools-1.78.1-cp314-cp314-win_amd64.whl", hash = "sha256:acb9849783dc7cf0e7359cbd60c6bf3154008bf9aeff12c696ec7289599eb3a8", size = 1190123, upload-time = "2026-02-20T01:19:06.831Z" }, + { url = "https://files.pythonhosted.org/packages/cf/5e/278f3831c8d56bae02e3acc570465648eccf0a6bbedcb1733789ac966803/grpcio_tools-1.78.0-cp314-cp314-linux_armv7l.whl", hash = "sha256:8b080d0d072e6032708a3a91731b808074d7ab02ca8fb9847b6a011fdce64cd9", size = 2546270, upload-time = "2026-02-06T09:59:07.426Z" }, + { url = "https://files.pythonhosted.org/packages/a3/d9/68582f2952b914b60dddc18a2e3f9c6f09af9372b6f6120d6cf3ec7f8b4e/grpcio_tools-1.78.0-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:8c0ad8f8f133145cd7008b49cb611a5c6a9d89ab276c28afa17050516e801f79", size = 5705731, upload-time = "2026-02-06T09:59:09.856Z" }, + { url = "https://files.pythonhosted.org/packages/70/68/feb0f9a48818ee1df1e8b644069379a1e6ef5447b9b347c24e96fd258e5d/grpcio_tools-1.78.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2f8ea092a7de74c6359335d36f0674d939a3c7e1a550f4c2c9e80e0226de8fe4", size = 2593896, upload-time = "2026-02-06T09:59:12.23Z" }, + { url = "https://files.pythonhosted.org/packages/1f/08/a430d8d06e1b8d33f3e48d3f0cc28236723af2f35e37bd5c8db05df6c3aa/grpcio_tools-1.78.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:da422985e0cac822b41822f43429c19ecb27c81ffe3126d0b74e77edec452608", size = 2905298, upload-time = "2026-02-06T09:59:14.458Z" }, + { url = "https://files.pythonhosted.org/packages/71/0a/348c36a3eae101ca0c090c9c3bc96f2179adf59ee0c9262d11cdc7bfe7db/grpcio_tools-1.78.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4fab1faa3fbcb246263e68da7a8177d73772283f9db063fb8008517480888d26", size = 2656186, upload-time = "2026-02-06T09:59:16.949Z" }, + { url = "https://files.pythonhosted.org/packages/1d/3f/18219f331536fad4af6207ade04142292faa77b5cb4f4463787988963df8/grpcio_tools-1.78.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:dd9c094f73f734becae3f20f27d4944d3cd8fb68db7338ee6c58e62fc5c3d99f", size = 3109859, upload-time = "2026-02-06T09:59:19.202Z" }, + { url = "https://files.pythonhosted.org/packages/5b/d9/341ea20a44c8e5a3a18acc820b65014c2e3ea5b4f32a53d14864bcd236bc/grpcio_tools-1.78.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:2ed51ce6b833068f6c580b73193fc2ec16468e6bc18354bc2f83a58721195a58", size = 3657915, upload-time = "2026-02-06T09:59:21.839Z" }, + { url = "https://files.pythonhosted.org/packages/fb/f4/5978b0f91611a64371424c109dd0027b247e5b39260abad2eaee66b6aa37/grpcio_tools-1.78.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:05803a5cdafe77c8bdf36aa660ad7a6a1d9e49bc59ce45c1bade2a4698826599", size = 3324724, upload-time = "2026-02-06T09:59:24.402Z" }, + { url = "https://files.pythonhosted.org/packages/b2/80/96a324dba99cfbd20e291baf0b0ae719dbb62b76178c5ce6c788e7331cb1/grpcio_tools-1.78.0-cp314-cp314-win32.whl", hash = "sha256:f7c722e9ce6f11149ac5bddd5056e70aaccfd8168e74e9d34d8b8b588c3f5c7c", size = 1015505, upload-time = "2026-02-06T09:59:26.3Z" }, + { url = "https://files.pythonhosted.org/packages/3b/d1/909e6a05bfd44d46327dc4b8a78beb2bae4fb245ffab2772e350081aaf7e/grpcio_tools-1.78.0-cp314-cp314-win_amd64.whl", hash = "sha256:7d58ade518b546120ec8f0a8e006fc8076ae5df151250ebd7e82e9b5e152c229", size = 1190196, upload-time = "2026-02-06T09:59:28.359Z" }, ] [[package]] @@ -804,24 +804,26 @@ wheels = [ [[package]] name = "hf-xet" -version = "1.2.0" +version = "1.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5e/6e/0f11bacf08a67f7fb5ee09740f2ca54163863b07b70d579356e9222ce5d8/hf_xet-1.2.0.tar.gz", hash = "sha256:a8c27070ca547293b6890c4bf389f713f80e8c478631432962bb7f4bc0bd7d7f", size = 506020, upload-time = "2025-10-24T19:04:32.129Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a6/d0/73454ef7ca885598a3194d07d5c517d91a840753c5b35d272600d7907f64/hf_xet-1.3.1.tar.gz", hash = "sha256:513aa75f8dc39a63cc44dbc8d635ccf6b449e07cdbd8b2e2d006320d2e4be9bb", size = 641393, upload-time = "2026-02-25T00:57:56.701Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e2/51/f7e2caae42f80af886db414d4e9885fac959330509089f97cccb339c6b87/hf_xet-1.2.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:10bfab528b968c70e062607f663e21e34e2bba349e8038db546646875495179e", size = 2861861, upload-time = "2025-10-24T19:04:19.01Z" }, - { url = "https://files.pythonhosted.org/packages/6e/1d/a641a88b69994f9371bd347f1dd35e5d1e2e2460a2e350c8d5165fc62005/hf_xet-1.2.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2a212e842647b02eb6a911187dc878e79c4aa0aa397e88dd3b26761676e8c1f8", size = 2717699, upload-time = "2025-10-24T19:04:17.306Z" }, - { url = "https://files.pythonhosted.org/packages/df/e0/e5e9bba7d15f0318955f7ec3f4af13f92e773fbb368c0b8008a5acbcb12f/hf_xet-1.2.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:30e06daccb3a7d4c065f34fc26c14c74f4653069bb2b194e7f18f17cbe9939c0", size = 3314885, upload-time = "2025-10-24T19:04:07.642Z" }, - { url = "https://files.pythonhosted.org/packages/21/90/b7fe5ff6f2b7b8cbdf1bd56145f863c90a5807d9758a549bf3d916aa4dec/hf_xet-1.2.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:29c8fc913a529ec0a91867ce3d119ac1aac966e098cf49501800c870328cc090", size = 3221550, upload-time = "2025-10-24T19:04:05.55Z" }, - { url = "https://files.pythonhosted.org/packages/6f/cb/73f276f0a7ce46cc6a6ec7d6c7d61cbfe5f2e107123d9bbd0193c355f106/hf_xet-1.2.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e159cbfcfbb29f920db2c09ed8b660eb894640d284f102ada929b6e3dc410a", size = 3408010, upload-time = "2025-10-24T19:04:28.598Z" }, - { url = "https://files.pythonhosted.org/packages/b8/1e/d642a12caa78171f4be64f7cd9c40e3ca5279d055d0873188a58c0f5fbb9/hf_xet-1.2.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9c91d5ae931510107f148874e9e2de8a16052b6f1b3ca3c1b12f15ccb491390f", size = 3503264, upload-time = "2025-10-24T19:04:30.397Z" }, - { url = "https://files.pythonhosted.org/packages/17/b5/33764714923fa1ff922770f7ed18c2daae034d21ae6e10dbf4347c854154/hf_xet-1.2.0-cp314-cp314t-win_amd64.whl", hash = "sha256:210d577732b519ac6ede149d2f2f34049d44e8622bf14eb3d63bbcd2d4b332dc", size = 2901071, upload-time = "2025-10-24T19:04:37.463Z" }, - { url = "https://files.pythonhosted.org/packages/96/2d/22338486473df5923a9ab7107d375dbef9173c338ebef5098ef593d2b560/hf_xet-1.2.0-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:46740d4ac024a7ca9b22bebf77460ff43332868b661186a8e46c227fdae01848", size = 2866099, upload-time = "2025-10-24T19:04:15.366Z" }, - { url = "https://files.pythonhosted.org/packages/7f/8c/c5becfa53234299bc2210ba314eaaae36c2875e0045809b82e40a9544f0c/hf_xet-1.2.0-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:27df617a076420d8845bea087f59303da8be17ed7ec0cd7ee3b9b9f579dff0e4", size = 2722178, upload-time = "2025-10-24T19:04:13.695Z" }, - { url = "https://files.pythonhosted.org/packages/9a/92/cf3ab0b652b082e66876d08da57fcc6fa2f0e6c70dfbbafbd470bb73eb47/hf_xet-1.2.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3651fd5bfe0281951b988c0facbe726aa5e347b103a675f49a3fa8144c7968fd", size = 3320214, upload-time = "2025-10-24T19:04:03.596Z" }, - { url = "https://files.pythonhosted.org/packages/46/92/3f7ec4a1b6a65bf45b059b6d4a5d38988f63e193056de2f420137e3c3244/hf_xet-1.2.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d06fa97c8562fb3ee7a378dd9b51e343bc5bc8190254202c9771029152f5e08c", size = 3229054, upload-time = "2025-10-24T19:04:01.949Z" }, - { url = "https://files.pythonhosted.org/packages/0b/dd/7ac658d54b9fb7999a0ccb07ad863b413cbaf5cf172f48ebcd9497ec7263/hf_xet-1.2.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:4c1428c9ae73ec0939410ec73023c4f842927f39db09b063b9482dac5a3bb737", size = 3413812, upload-time = "2025-10-24T19:04:24.585Z" }, - { url = "https://files.pythonhosted.org/packages/92/68/89ac4e5b12a9ff6286a12174c8538a5930e2ed662091dd2572bbe0a18c8a/hf_xet-1.2.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a55558084c16b09b5ed32ab9ed38421e2d87cf3f1f89815764d1177081b99865", size = 3508920, upload-time = "2025-10-24T19:04:26.927Z" }, - { url = "https://files.pythonhosted.org/packages/cb/44/870d44b30e1dcfb6a65932e3e1506c103a8a5aea9103c337e7a53180322c/hf_xet-1.2.0-cp37-abi3-win_amd64.whl", hash = "sha256:e6584a52253f72c9f52f9e549d5895ca7a471608495c4ecaa6cc73dba2b24d69", size = 2905735, upload-time = "2025-10-24T19:04:35.928Z" }, + { url = "https://files.pythonhosted.org/packages/e7/f5/66adbb1f54a1b3c6da002fa36d4405901ddbcb7d927d780db17ce18ab99d/hf_xet-1.3.1-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:6517a245e41df3eae5adc5f9e8c86fa52abd548de798cbcd989f0082152860aa", size = 3759781, upload-time = "2026-02-25T00:57:47.017Z" }, + { url = "https://files.pythonhosted.org/packages/1e/75/189d91a90480c142cc710c1baa35ece20e8652d5fe5c9b2364a13573d827/hf_xet-1.3.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:4a322d506c513f98fdc1aa2aaa825daefd535b686e80ca789e6d33fcb146f524", size = 3517533, upload-time = "2026-02-25T00:57:45.812Z" }, + { url = "https://files.pythonhosted.org/packages/c6/52/52dd1ab6c29661e29585f3c10d14572e2535a3a472f27a0a46215b0f4659/hf_xet-1.3.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8f16ec9d26badec46334a798e01b5d86af536924789c95b1a1ec6a05f26523e0", size = 4174082, upload-time = "2026-02-25T00:57:38.171Z" }, + { url = "https://files.pythonhosted.org/packages/14/03/460add181c79e2ea1527d2ad27788ecccaee1d5a82563f9402e25ee627e4/hf_xet-1.3.1-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:e1f5d72bd5b73e61530fff573bcff34bdb64af2bf4862cdd516e6c1dab4dc75b", size = 3952874, upload-time = "2026-02-25T00:57:36.942Z" }, + { url = "https://files.pythonhosted.org/packages/01/56/bf78f18890dfc8caa907830e95424dce0887d5c45efde13f23c9ebbaa8ef/hf_xet-1.3.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:4bc71afd853508b2ddf123b8fc9de71b0afa4c956ec730b69fb76103781e94cd", size = 4152325, upload-time = "2026-02-25T00:57:54.081Z" }, + { url = "https://files.pythonhosted.org/packages/3c/94/91685c6a4a7f513097a6a73b1e879024304cd0eae78080e3d737622f2fd9/hf_xet-1.3.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:541b4b00ed294ae6cfd9416de9506e58971013714d7316189c9638ed54e362d4", size = 4390499, upload-time = "2026-02-25T00:57:55.258Z" }, + { url = "https://files.pythonhosted.org/packages/79/1b/1e72c8ea1f31ef94640d1f265630d35b97b2ef31fe12696bbcc32dbcdc95/hf_xet-1.3.1-cp314-cp314t-win_amd64.whl", hash = "sha256:f85480b4fe3e8e4cdbc59ef1d235152b732fd57ca439cc983c291892945ae818", size = 3634352, upload-time = "2026-02-25T00:58:04.749Z" }, + { url = "https://files.pythonhosted.org/packages/cf/61/b59e87a7a10b95c4578a6ce555339b2f002035569dfd366662b9f59975a8/hf_xet-1.3.1-cp314-cp314t-win_arm64.whl", hash = "sha256:83a8830160392ef4bea78d443ea2cf1febe65783b3843a8f12c64b368981e7e2", size = 3494371, upload-time = "2026-02-25T00:58:03.422Z" }, + { url = "https://files.pythonhosted.org/packages/75/f8/c2da4352c0335df6ae41750cf5bab09fdbfc30d3b4deeed9d621811aa835/hf_xet-1.3.1-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:581d1809a016f7881069d86a072168a8199a46c839cf394ff53970a47e4f1ca1", size = 3761755, upload-time = "2026-02-25T00:57:43.621Z" }, + { url = "https://files.pythonhosted.org/packages/c0/e5/a2f3eaae09da57deceb16a96ebe9ae1f6f7b9b94145a9cd3c3f994e7782a/hf_xet-1.3.1-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:329c80c86f2dda776bafd2e4813a46a3ee648dce3ac0c84625902c70d7a6ddba", size = 3523677, upload-time = "2026-02-25T00:57:42.3Z" }, + { url = "https://files.pythonhosted.org/packages/61/cd/acbbf9e51f17d8cef2630e61741228e12d4050716619353efc1ac119f902/hf_xet-1.3.1-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2973c3ff594c3a8da890836308cae1444c8af113c6f10fe6824575ddbc37eca7", size = 4178557, upload-time = "2026-02-25T00:57:35.399Z" }, + { url = "https://files.pythonhosted.org/packages/df/4f/014c14c4ae3461d9919008d0bed2f6f35ba1741e28b31e095746e8dac66f/hf_xet-1.3.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ed4bfd2e6d10cb86c9b0f3483df1d7dd2d0220f75f27166925253bacbc1c2dbe", size = 3958975, upload-time = "2026-02-25T00:57:34.004Z" }, + { url = "https://files.pythonhosted.org/packages/86/50/043f5c5a26f3831c3fa2509c17fcd468fd02f1f24d363adc7745fbe661cb/hf_xet-1.3.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:713913387cc76e300116030705d843a9f15aee86158337eeffb9eb8d26f47fcd", size = 4158298, upload-time = "2026-02-25T00:57:51.14Z" }, + { url = "https://files.pythonhosted.org/packages/08/9c/b667098a636a88358dbeb2caf90e3cb9e4b961f61f6c55bb312793424def/hf_xet-1.3.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:e5063789c9d21f51e9ed4edbee8539655d3486e9cad37e96b7af967da20e8b16", size = 4395743, upload-time = "2026-02-25T00:57:52.783Z" }, + { url = "https://files.pythonhosted.org/packages/70/37/4db0e4e1534270800cfffd5a7e0b338f2137f8ceb5768000147650d34ea9/hf_xet-1.3.1-cp37-abi3-win_amd64.whl", hash = "sha256:607d5bbc2730274516714e2e442a26e40e3330673ac0d0173004461409147dee", size = 3638145, upload-time = "2026-02-25T00:58:02.167Z" }, + { url = "https://files.pythonhosted.org/packages/4e/46/1ba8d36f8290a4b98f78898bdce2b0e8fe6d9a59df34a1399eb61a8d877f/hf_xet-1.3.1-cp37-abi3-win_arm64.whl", hash = "sha256:851b1be6597a87036fe7258ce7578d5df3c08176283b989c3b165f94125c5097", size = 3500490, upload-time = "2026-02-25T00:58:00.667Z" }, ] [[package]] @@ -884,7 +886,7 @@ wheels = [ [[package]] name = "huggingface-hub" -version = "1.4.1" +version = "1.5.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "filelock" }, @@ -893,14 +895,13 @@ dependencies = [ { name = "httpx" }, { name = "packaging" }, { name = "pyyaml" }, - { name = "shellingham" }, { name = "tqdm" }, - { name = "typer-slim" }, + { name = "typer" }, { name = "typing-extensions" }, ] -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" } +sdist = { url = "https://files.pythonhosted.org/packages/ae/76/b5efb3033d8499b17f9386beaf60f64c461798e1ee16d10bc9c0077beba5/huggingface_hub-1.5.0.tar.gz", hash = "sha256:f281838db29265880fb543de7a23b0f81d3504675de82044307ea3c6c62f799d", size = 695872, upload-time = "2026-02-26T15:35:32.745Z" } wheels = [ - { 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" }, + { url = "https://files.pythonhosted.org/packages/ec/74/2bc951622e2dbba1af9a460d93c51d15e458becd486e62c29cc0ccb08178/huggingface_hub-1.5.0-py3-none-any.whl", hash = "sha256:c9c0b3ab95a777fc91666111f3b3ede71c0cdced3614c553a64e98920585c4ee", size = 596261, upload-time = "2026-02-26T15:35:31.1Z" }, ] [[package]] @@ -1043,7 +1044,7 @@ wheels = [ [[package]] name = "litellm" -version = "1.81.14" +version = "1.81.16" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohttp" }, @@ -1059,9 +1060,9 @@ dependencies = [ { name = "tiktoken" }, { name = "tokenizers" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c8/ab/4fe5517ac55f72ca90119cd0d894a7b4e394ae76e1ccdeb775bd50154b0d/litellm-1.81.14.tar.gz", hash = "sha256:445efb92ae359e8f40ee984753c5ae752535eb18a2aeef00d3089922de5676b7", size = 16541822, upload-time = "2026-02-22T00:33:35.281Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/36/3cbb22d6ef88c10f3fa4f04664c2a37e93a2e6f9c51899cd9fd025cb0a50/litellm-1.81.16.tar.gz", hash = "sha256:264a3868942e722cd6c19c2d625524fe624a1b6961c37c22d299dc7ea99823b3", size = 16668405, upload-time = "2026-02-26T13:01:48.429Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d8/b3/e8fe151c1b81666575552835a3a79127c5aa6bd460fcecc51e032d2f4019/litellm-1.81.14-py3-none-any.whl", hash = "sha256:6394e61bbdef7121e5e3800349f6b01e9369e7cf611e034f1832750c481abfed", size = 14603260, upload-time = "2026-02-22T00:33:32.464Z" }, + { url = "https://files.pythonhosted.org/packages/1f/1e/0022cde913bac87a493e4a182b8768f75e7ae90b64d4e11acb009b18311f/litellm-1.81.16-py3-none-any.whl", hash = "sha256:d6bcc13acbd26719e07bfa6b9923740e88409cbf1f9d626d85fc9ae0e0eec88c", size = 14774277, upload-time = "2026-02-26T13:01:45.652Z" }, ] [[package]] @@ -1259,7 +1260,7 @@ wheels = [ [[package]] name = "openinference-instrumentation" -version = "0.1.44" +version = "0.1.45" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "openinference-semantic-conventions" }, @@ -1267,9 +1268,9 @@ dependencies = [ { name = "opentelemetry-sdk" }, { name = "wrapt" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/41/d9/c0d3040c0b5dc2b97ad20c35fb3fc1e3f2006bb4b08741ff325efcf3a96a/openinference_instrumentation-0.1.44.tar.gz", hash = "sha256:141953d2da33d54d428dfba2bfebb27ce0517dc43d52e1449a09db72ec7d318e", size = 23959, upload-time = "2026-02-01T01:45:55.88Z" } +sdist = { url = "https://files.pythonhosted.org/packages/89/25/26db627b2d1d13030fdfb23cfa4437d6bb7e9c7ee42a8ec22b50e64edb6d/openinference_instrumentation-0.1.45.tar.gz", hash = "sha256:71d58cf4a9849351ed2dccfcd023277e80d2c9326d7cb67017c8ec2062df4c9b", size = 23989, upload-time = "2026-02-24T05:59:42.222Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5e/6d/6a19587b26ffa273eb27ba7dd2482013afe3b47c8d9f1f39295216975f9f/openinference_instrumentation-0.1.44-py3-none-any.whl", hash = "sha256:86b2a8931e0f39ecfb739901f8987c654961da03baf3cfa5d5b4f45a96897b2d", size = 30093, upload-time = "2026-02-01T01:45:54.932Z" }, + { url = "https://files.pythonhosted.org/packages/41/a3/f652a6ae71f33800bce4dffb727e8e5b3b0061d4ac9b6b166f0fc3ca4ed7/openinference_instrumentation-0.1.45-py3-none-any.whl", hash = "sha256:ee4bf930b8133210d6a5eb5577ca097dd9926035676e8a3a5b2ebb7e4a1129da", size = 30118, upload-time = "2026-02-24T05:59:40.456Z" }, ] [[package]] @@ -1407,7 +1408,7 @@ wheels = [ [[package]] name = "opentelemetry-instrumentation-openai" -version = "0.52.4" +version = "0.52.6" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, @@ -1415,9 +1416,9 @@ dependencies = [ { name = "opentelemetry-semantic-conventions" }, { name = "opentelemetry-semantic-conventions-ai" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/37/91/1f72807c84cfaf5b3386011f56357ea304f9e6c0039857d3fa38a13e4d03/opentelemetry_instrumentation_openai-0.52.4.tar.gz", hash = "sha256:690b9c14d68b50c87f24006122165e97819557c13ff7f520e2043e2f69f2789c", size = 6978369, upload-time = "2026-02-19T13:22:02.051Z" } +sdist = { url = "https://files.pythonhosted.org/packages/37/86/1fe5008f3714118fdc1024cd141140a5f204d5ac7016e87a0f07a834efb2/opentelemetry_instrumentation_openai-0.52.6.tar.gz", hash = "sha256:0eb23dc90804a726e516fcbd649cb99f10dfdb5e31d29e44c4b1b8f402dd905d", size = 6978397, upload-time = "2026-02-26T15:40:17.154Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a3/5a/0a0d6cf2b93cd1ec6f7c84f8731ad2d20e6313564362690eee6bbde9b989/opentelemetry_instrumentation_openai-0.52.4-py3-none-any.whl", hash = "sha256:73e6837a5ea44f61439c937f7116c623ccdf390034e3393d501e82f9d6298922", size = 43082, upload-time = "2026-02-19T13:21:18.997Z" }, + { url = "https://files.pythonhosted.org/packages/2c/4a/4623d0adc0187cc45bce631f891c30cd01cf2562d37b918b79561200d985/opentelemetry_instrumentation_openai-0.52.6-py3-none-any.whl", hash = "sha256:5e174388520f294f648f9732471c1b9919c71e5d09649a64ab8ff81714c1278b", size = 43084, upload-time = "2026-02-26T15:39:35.584Z" }, ] [[package]] @@ -1492,40 +1493,40 @@ wheels = [ [[package]] name = "primp" -version = "1.0.0" +version = "1.1.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f4/60/ea0822d275847ed266d694662cef1863c37d3c1752f4286c4baae5297d3f/primp-1.0.0.tar.gz", hash = "sha256:09fc1ff6009220247d723792794e514782e1ab7e9ba5e2547272a07afed5ca86", size = 973426, upload-time = "2026-02-13T15:32:49.846Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/ae/443244fb49e2f421dafadd689361777d48b07f0ea7d18b34e72a38a3ef44/primp-1.0.0-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:6af2343ac655d409ec70c3eeb7c2283de509b663aeb6b3e34e39e1331c82daf6", size = 3893122, upload-time = "2026-02-13T15:33:07.596Z" }, - { url = "https://files.pythonhosted.org/packages/92/02/aa765143ce632bcf5e3cfa8bd41e2032f8d12695754564b5059821b2b41a/primp-1.0.0-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:25f21400ff236b0e1db5d4db7db66965f63b64898103384e916ecef575ab3395", size = 3655128, upload-time = "2026-02-13T15:32:41.147Z" }, - { url = "https://files.pythonhosted.org/packages/c3/d7/5e9e320441a7c0ffef24ce55fd2922aacd003e6713633d1d0732fe964ff6/primp-1.0.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:abd09660db079903031be91e04af2dcf42457bd739e6f328c7b2364e38061876", size = 3792951, upload-time = "2026-02-13T15:32:56.186Z" }, - { url = "https://files.pythonhosted.org/packages/36/f2/1130fad846f08bbf104a64232ef4f58ae5b5c4b2c64d6a73b1f4245607e0/primp-1.0.0-cp310-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6e756480c9dd585b20927c2a0c1d0c42cbcb5866ed1e741a8f93163e6f905e6c", size = 3440111, upload-time = "2026-02-13T15:32:57.523Z" }, - { url = "https://files.pythonhosted.org/packages/c4/e5/a3e0ba7f4a0409ba615098bda35a1276ebf992d2bd7a8f635c8349e77276/primp-1.0.0-cp310-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b75a10ead2872dee9be9c60c07e8fce5328c88ed251e3fdbd29a7d2d73ab512a", size = 3651920, upload-time = "2026-02-13T15:32:48.511Z" }, - { url = "https://files.pythonhosted.org/packages/80/02/10cfc095e958e498171977068ebcabddaa8dabd7835725482b8c0eefec19/primp-1.0.0-cp310-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2ea1a0b1d4c2a65efd5f22bc42bc0133ebf359f70dd155847cbebf8015fb05a1", size = 3922305, upload-time = "2026-02-13T15:33:23.231Z" }, - { url = "https://files.pythonhosted.org/packages/89/00/947c74646825d38d7f5c5fc5a7f2474f30767ea9817f9a7742f95ac99e45/primp-1.0.0-cp310-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1abd58a2bf0a2f062edc51a3684f8b9d0170348a96afdd3915f02f498c661228", size = 3811925, upload-time = "2026-02-13T15:33:04.976Z" }, - { url = "https://files.pythonhosted.org/packages/65/34/0f788310dd2903be8b49d9396ad4fa7deb1f5ab6419a2a7ea9014380f52f/primp-1.0.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:52506249b8132eb386e90349f9fbbcf6b39e36523d61f92a0e8c557e32f71ef2", size = 4009948, upload-time = "2026-02-13T15:32:43.88Z" }, - { url = "https://files.pythonhosted.org/packages/44/35/9a3147377764380fa9940d4cfc328b5a31a1a1c72d2cbbdaa188ab8ea296/primp-1.0.0-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:b7f24c3a67aab0517ba4f6e743dfced331198062ff8e31df692381e60a17b775", size = 3970643, upload-time = "2026-02-13T15:33:06.248Z" }, - { url = "https://files.pythonhosted.org/packages/df/a9/396511a300bc44de4213198f10a21337fcb3f43e4553ece9a17b1a48e1df/primp-1.0.0-cp310-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:0cf76f39d5820a2607a2dd25c074ceb8efa741bc311552218156c53b1002ec25", size = 3668236, upload-time = "2026-02-13T15:33:00.299Z" }, - { url = "https://files.pythonhosted.org/packages/2b/44/f1f4a6223dbfa8c72d37286b4bf9a2bb06241c9bac7ce95c5acc03069fec/primp-1.0.0-cp310-abi3-musllinux_1_2_i686.whl", hash = "sha256:3414a4bbe37e909a45c0fea04104bd23165d81b94f3d68bfe9a11ba18c462b39", size = 3776956, upload-time = "2026-02-13T15:33:08.969Z" }, - { url = "https://files.pythonhosted.org/packages/d7/9e/b6cb2c19abaeea0ade9256c296340b79dee0084bffcbaadceeebaf75c691/primp-1.0.0-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:3487e5269dc6d840035d59a8e5afbba99b5736da848664b71356681a837c3a8b", size = 4262036, upload-time = "2026-02-13T15:33:21.939Z" }, - { url = "https://files.pythonhosted.org/packages/6b/80/bf5a730384f338be7a52e5976c0f7ea8e00f8f078a80bd51fa15a61cd35a/primp-1.0.0-cp310-abi3-win32.whl", hash = "sha256:0c44e8dccfcd2dd3fb3467d44836445039a013704ea869340bf67a444cbf3f36", size = 3185054, upload-time = "2026-02-13T15:33:15.486Z" }, - { url = "https://files.pythonhosted.org/packages/8f/0b/92d644fbbf97f8fca2959c388f0ed50abd9ea1d17c3ad9b5b0e364fa8d37/primp-1.0.0-cp310-abi3-win_amd64.whl", hash = "sha256:705fb755f5461b551925de7546f3fea5b657fc44fee136498bed492bf5051864", size = 3512508, upload-time = "2026-02-13T15:32:52.646Z" }, - { url = "https://files.pythonhosted.org/packages/c3/6e/efd595743e3b8b0477f44194f6a22fe0d7118b76e9b01167b0921a160d91/primp-1.0.0-cp310-abi3-win_arm64.whl", hash = "sha256:4e080ad054df4c325c434acf613d9cae54278e8141fa116452ec18bf576672a8", size = 3560136, upload-time = "2026-02-13T15:32:50.901Z" }, - { url = "https://files.pythonhosted.org/packages/29/62/e3ee3836154f849086e5a29db7ec95bf805c0143266d59868c2eff0528df/primp-1.0.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:6853b719f511ed09dc3673e54cd489b4ed35b0f769428dc79b3c54c446aafd22", size = 3890886, upload-time = "2026-02-13T15:33:12.447Z" }, - { url = "https://files.pythonhosted.org/packages/23/12/4ea190b844557e919a84d3851d49407303d145dfe93cab67d2ed7268c6fa/primp-1.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:3d072d1e3c84068b5727426500210e33241ef97844fe781d9817094fdfc6b128", size = 3653937, upload-time = "2026-02-13T15:33:13.803Z" }, - { url = "https://files.pythonhosted.org/packages/be/51/bb861bcc45b6761b4dcc3b41a1ce6eecea9ccf4e9786d545f28313540259/primp-1.0.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ef28f8d6b89c5daf651dc7c7560b4914647bfe73b9a3847e2ae5ed0ff7d8bcf", size = 3792475, upload-time = "2026-02-13T15:33:27.419Z" }, - { url = "https://files.pythonhosted.org/packages/88/87/f87d652aa13a1b1bba9f576c04732319ecf75075e3b26bf91ad47eab00d3/primp-1.0.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:04a0d9d88cdce7ab685b4657cfe07d603a85118ec48a09015fa66eadad156c44", size = 3443247, upload-time = "2026-02-13T15:32:46.793Z" }, - { url = "https://files.pythonhosted.org/packages/31/f5/623885d04702523201639af3d011efb2eaed0dff9200a78db609b570c4c6/primp-1.0.0-cp314-cp314t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0ad2255403b155d93cf5cb7f6e807e26dc10c49071e0bac888c2c0e14801b82", size = 3651674, upload-time = "2026-02-13T15:33:24.577Z" }, - { url = "https://files.pythonhosted.org/packages/0b/17/b45e7e79cf3c5de7aaf23bf38167243c4df017997d954dd903a479f474d8/primp-1.0.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c3e7ccbe4746163f14b984523ac49ce3eed923fbe672c4c08480fa13217c2357", size = 3918929, upload-time = "2026-02-13T15:32:42.615Z" }, - { url = "https://files.pythonhosted.org/packages/fb/00/f5f58ef9856d99cf52e59f9034b27dc2659430be3257ecb890f1b4fccb17/primp-1.0.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:63a1d34732c2e6282e5e30f5d425eaa28ca417d74accda92908fdb8c944ff319", size = 3814485, upload-time = "2026-02-13T15:33:16.917Z" }, - { url = "https://files.pythonhosted.org/packages/b0/93/5e82f1fb2fd026d21c645b80da90f29f3afb6f1990120dcff8662c4f4b6e/primp-1.0.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d90e61f173e661ed8e21d8cd6534c586ad1d25565a0bac539a6a2d5e990439e0", size = 4014672, upload-time = "2026-02-13T15:33:26.083Z" }, - { url = "https://files.pythonhosted.org/packages/03/d7/6f1739043c84e772b45c51d2a1ab8c32727f0db6d41beb1b092a7baa2c02/primp-1.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:fcb28e07bc250b8c4762312e952bd84b6b983554fba6cd067f83018bd39a0488", size = 3971122, upload-time = "2026-02-13T15:32:53.944Z" }, - { url = "https://files.pythonhosted.org/packages/74/9a/47d7101034a36e73bb6976c566c56b54ec46efff1d64ebc07dccf05e51d8/primp-1.0.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:8e5b8fa46130d3db33192784d4935fc3f9574f030d0e78d281e90c37cf2507ee", size = 3669273, upload-time = "2026-02-13T15:33:10.267Z" }, - { url = "https://files.pythonhosted.org/packages/48/15/86878a9b46fc4bafba454e63b293e779c1ba6f9bf5ffc221f2f3dc70d60e/primp-1.0.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:984ab730449fd2e5f794fd6fad37fed3596432a24435ce2d0363b454503b7846", size = 3776747, upload-time = "2026-02-13T15:33:03.156Z" }, - { url = "https://files.pythonhosted.org/packages/9c/52/7afaf2a232987711863fa1e994cb6908c9dcd550d436578bb6cb63e53a83/primp-1.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:2abd6d47ca60028bcc33dc47dd33f355237be80d7889518e44cc4d730c9e45e0", size = 4266058, upload-time = "2026-02-13T15:32:59.084Z" }, - { url = "https://files.pythonhosted.org/packages/67/c2/fd1365ab28c4e15bebd291215c152c9787185a4fade0df780bb5e53d5866/primp-1.0.0-cp314-cp314t-win32.whl", hash = "sha256:39c27d84fd597a43bb291b6928fbaa46d4a7aff0c31ae1a361dccbbd109118a1", size = 3184230, upload-time = "2026-02-13T15:32:45.437Z" }, - { url = "https://files.pythonhosted.org/packages/30/2f/fcb4935ef1b2ba19bafbf050775f402ef30d19c9ba0d83a6328b453436a4/primp-1.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:bc8bac0288fb7ed541c8db4be46c5f2779e4c1b023bf01e46fe4c1405150dbeb", size = 3514652, upload-time = "2026-02-13T15:33:01.694Z" }, - { url = "https://files.pythonhosted.org/packages/49/88/2dbeee5a6c914c36b5dfca6e77913f4a190ac0137db0ea386b9632c16ef0/primp-1.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:117d3eb9c556fe88c8ed0533be80c2495922671e977e3e0e78a6b841014380eb", size = 3553319, upload-time = "2026-02-13T15:33:19.67Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/de/25/1113a87a693121f4eb18d2df3a99d8ad43984f4068e31a5765c03e4b8b96/primp-1.1.1.tar.gz", hash = "sha256:58775e74f86cc58f9abe4b1dacea399fa6367c1959e591ad9345f151ad38d259", size = 311388, upload-time = "2026-02-24T16:12:53.452Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bf/0f/027fc0394f70721c6dc5054fb3efff6479753da0b272e15b16cefba958b8/primp-1.1.1-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:691215c5a514a7395c1ee775cd03a94a41497941e17291e1a71f5356142c61e6", size = 3997489, upload-time = "2026-02-24T16:12:49.154Z" }, + { url = "https://files.pythonhosted.org/packages/af/ea/0f23fbfef2a550c420eaa73fd3e21176acb0ddf0d50028d8bc8d937441be/primp-1.1.1-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:17ace56cd24a894236121bf37d3616ec15d5299a6fa2d2a30fbbf9c22b946a03", size = 3734591, upload-time = "2026-02-24T16:12:45.629Z" }, + { url = "https://files.pythonhosted.org/packages/0a/63/c5669652446a981dd5faad8a8255e5567db5818b951dbe74e81968f672cb/primp-1.1.1-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cfec08ae15f6d86b2bcaaee3358d5cc349a843c8be164502ea73658a817c5cf2", size = 3875508, upload-time = "2026-02-24T16:12:59.403Z" }, + { url = "https://files.pythonhosted.org/packages/14/79/19e4d19a445b39c930a317e4ea4d1eff07ef0661b4e7397ad425f7ff0bd8/primp-1.1.1-cp310-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c3cf7e93e8ff4842eee9c6d4ac47d638a5c981752b19f458877a3536c1da6671", size = 3510461, upload-time = "2026-02-24T16:12:37.908Z" }, + { url = "https://files.pythonhosted.org/packages/50/39/091282d624067958b42a087976c0da80eecc5ade03acfc732389be3af723/primp-1.1.1-cp310-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:db6f3f18855bf25dca14f6d121d214e5c922275f49cdadd248eff28abb779edb", size = 3727644, upload-time = "2026-02-24T16:12:16.671Z" }, + { url = "https://files.pythonhosted.org/packages/33/ae/ca4e4a5d0cbd35684a228fd1f7c1425db0860a7bd74ce8f40835f6184834/primp-1.1.1-cp310-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2d8363faadb1d07fa8ae73de6ed2ca4666b36c77ea3990714164b8ee7ab1aa1d", size = 4004689, upload-time = "2026-02-24T16:12:57.957Z" }, + { url = "https://files.pythonhosted.org/packages/3a/ed/b3cf17bcac4914aa63cd83d763c9e347aab6e0b9285645b0015b036f914d/primp-1.1.1-cp310-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:302241ee447c185417e93e3a3e5a2801fdd710b1a5cc63c01a26ee7dc634e9b1", size = 3918084, upload-time = "2026-02-24T16:12:30.283Z" }, + { url = "https://files.pythonhosted.org/packages/6a/9f/f563eaeb654749fa519c627b1f1ab93cf875537c56123fba507f74b647fc/primp-1.1.1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a37ad318f1b8295d414e1c32ca407efcb92e664c5ff41f06901bd3ee03bab1fa", size = 4108648, upload-time = "2026-02-24T16:12:15.269Z" }, + { url = "https://files.pythonhosted.org/packages/1c/b9/2df5376900c293238cf641591952979f689ea3f009195df4cce15786afb9/primp-1.1.1-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e46829d9d86caf18b2b40829655d470e0ce2eebb061f2ee973451b2509f1c5a2", size = 4055747, upload-time = "2026-02-24T16:12:42.925Z" }, + { url = "https://files.pythonhosted.org/packages/a1/e9/eaaea488b4ae445059bd99559649402c77ddd9dfdda01528daa9ee11d8fe/primp-1.1.1-cp310-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:8ef9cb971915d2db3fbb1a512777261e5267c95d4717b18aff453f5e3dbb9bda", size = 3742046, upload-time = "2026-02-24T16:12:19.945Z" }, + { url = "https://files.pythonhosted.org/packages/0a/92/0607dd9d01840e0c007519d69cdcbb6f1358d6d7f8e739fc3359773b50d2/primp-1.1.1-cp310-abi3-musllinux_1_2_i686.whl", hash = "sha256:1a350656142772b5d6afc0dfaf9172c69449fbfafb9b6590af7ba116d32554d7", size = 3857103, upload-time = "2026-02-24T16:12:39.338Z" }, + { url = "https://files.pythonhosted.org/packages/e5/b6/5d574a7a84afd38df03c5535a9bb1052090bd0289760dcca24188510dd09/primp-1.1.1-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:ec71a66750befd219f29cb6ff01bc1c26671040fc76b4115bf045c85f84da041", size = 4357972, upload-time = "2026-02-24T16:12:12.159Z" }, + { url = "https://files.pythonhosted.org/packages/8b/f3/34ba2deba36de0a6041a61c16f2097e0bd2e74114f8d85096b3911288b4c/primp-1.1.1-cp310-abi3-win32.whl", hash = "sha256:901dc1e40b99ba5925463ab120af14afb8a66f4ac7eb2cdf87aaf21047f6db39", size = 3259840, upload-time = "2026-02-24T16:12:31.762Z" }, + { url = "https://files.pythonhosted.org/packages/a8/c6/fa3c17e5b6e4cff5bbdfd6bed1d0e8f81e17708dd8106906a031a2432b61/primp-1.1.1-cp310-abi3-win_amd64.whl", hash = "sha256:6bedd91451ec9ac46203ccb5c2c9925e9206e33abec7c791a2b39e3f86530bf0", size = 3596643, upload-time = "2026-02-24T16:12:21.554Z" }, + { url = "https://files.pythonhosted.org/packages/94/3d/a5b391107ba1c72dc8eb4f603c5764067449e1445438d71e093a72d5eda1/primp-1.1.1-cp310-abi3-win_arm64.whl", hash = "sha256:fd22a10164536374262e32fccbf81736b20798ac7582f159d5ffdef01a755579", size = 3606836, upload-time = "2026-02-24T16:12:28.579Z" }, + { url = "https://files.pythonhosted.org/packages/5d/77/b7df4f1776ae2e7cb5cf123b977167709c120712c7a4f968dc93b28d05ac/primp-1.1.1-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:e6b0fdeb12cc60b0fa756191118cec8ede8d26f869b83fa501aed722984a964b", size = 3981048, upload-time = "2026-02-24T16:12:24.396Z" }, + { url = "https://files.pythonhosted.org/packages/9a/c8/f198cd6ad9f232a171739a69c534c684237362af8e55f0cc2fc452377aa8/primp-1.1.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:fc473e87adc88f6ce94b7f3edeb2ca6c973f4ceb2d4199d0e707544f71c639c4", size = 3729293, upload-time = "2026-02-24T16:12:18.07Z" }, + { url = "https://files.pythonhosted.org/packages/e7/ce/bd8e564f8233ab0213a296dda2e04b484e0c4b9975702c7ba712e96ead8c/primp-1.1.1-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e85f2aea74b8683611c76958de8827322bd800e1b51aec88130da68d00a20462", size = 3873474, upload-time = "2026-02-24T16:12:40.749Z" }, + { url = "https://files.pythonhosted.org/packages/e7/ab/d3ee13de657cb068e81008eedc2d61103094497d9edc054997b85d85163e/primp-1.1.1-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ca535dfbc5a8290975f4bd8ce38922b26cf4fefc737aa2116bcb1a5795c14309", size = 3509513, upload-time = "2026-02-24T16:12:44.251Z" }, + { url = "https://files.pythonhosted.org/packages/6f/5d/3ed38dd94ae503977329976dbe00831e66d22f0f298c026f8d7493be2b39/primp-1.1.1-cp314-cp314t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d94073e9ecbf97f6d1538d4678df1bb662fd418ad5fd09da4040fe46623e2ec5", size = 3728743, upload-time = "2026-02-24T16:12:33.277Z" }, + { url = "https://files.pythonhosted.org/packages/bc/15/19af65a35b2189d6f2267148ea5b7cbb266aa36891acd641388b7a0f6022/primp-1.1.1-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7e639441bd36e582feec7033e4b8661e0979a61bff65af5f476d33e02ebb3c4d", size = 3999650, upload-time = "2026-02-24T16:12:36.157Z" }, + { url = "https://files.pythonhosted.org/packages/22/cb/aa635a9903a1ee3b0ffe5dd9218a2e2d8880828a1eaba9d0035f967d118a/primp-1.1.1-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd770ca4f73a700da0911d1300a952e4d9a4a3321e205aa5a8644ae81cbd4d7d", size = 3896990, upload-time = "2026-02-24T16:12:13.66Z" }, + { url = "https://files.pythonhosted.org/packages/25/98/916916ec3bd5dab4125bf17b28d1959883a831dc4f9757f915e509c43ec2/primp-1.1.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7dccb605997c918b7abbdd163303d789d63eb03d7cd0440184f34b06a8522fc1", size = 4096157, upload-time = "2026-02-24T16:12:27.163Z" }, + { url = "https://files.pythonhosted.org/packages/ff/57/219c44bf21896a3f2132821ea00bbc9af36b194449ee5083791f690daf7d/primp-1.1.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:1ada94c7f9f047b1c5ba339f62effd44f4c4943d4d8bb96447e9c84ab3bd874d", size = 4052968, upload-time = "2026-02-24T16:12:34.574Z" }, + { url = "https://files.pythonhosted.org/packages/6a/ce/dfdd734c7372faef4a26ecb0267a724e19f78b76a9a92440b8ca824e8f5a/primp-1.1.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:21ac92542f378a21fba8093dbeb7e093851e00da2bdfd9bc6aa63f81cff035d0", size = 3744522, upload-time = "2026-02-24T16:12:25.726Z" }, + { url = "https://files.pythonhosted.org/packages/d6/9c/3eb9e484c17784eac6549c505a68d82b6e5959a0af6efbcf28a773450a81/primp-1.1.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:adaa5d7e8d2ca089cbf41a837a301da605c21ff0ea5fecac8a8b1eead4bc563f", size = 3855298, upload-time = "2026-02-24T16:12:54.518Z" }, + { url = "https://files.pythonhosted.org/packages/1d/ca/80924591ec24f9341982e4d74251f6bfeda44cbb90f6f792403d0737a390/primp-1.1.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b041ab0019e0fb21c24de542e80056775508e5d1d0f0333fb661185bdb359138", size = 4348887, upload-time = "2026-02-24T16:12:47.376Z" }, + { url = "https://files.pythonhosted.org/packages/95/4b/0edc62583af9a03fd1eb34ffd865245c921919f374b0e72b1bb73dc9adf6/primp-1.1.1-cp314-cp314t-win32.whl", hash = "sha256:b7270b9755a931e7667854ad5d9b2aeb88068f0add4fb741529e8c25d953f21b", size = 3252145, upload-time = "2026-02-24T16:12:52.335Z" }, + { url = "https://files.pythonhosted.org/packages/01/b7/9784b93d252e4c2a50f7a46908d91110b7ce9d04e1adb47227fc212576ff/primp-1.1.1-cp314-cp314t-win_amd64.whl", hash = "sha256:19a48f4e91256ec661e022976a75e6a0621522244ac928e8c632d829adb929ce", size = 3591097, upload-time = "2026-02-24T16:12:22.898Z" }, + { url = "https://files.pythonhosted.org/packages/db/d5/3b34601cb2da1cec7aec88f447af9de1e8e3bb3101f26351aa8570b5b7af/primp-1.1.1-cp314-cp314t-win_arm64.whl", hash = "sha256:c97b951afb203b9528f36524e96b1e37ce42f3a7eb0cd77cd053ad5bdfc93d81", size = 3603917, upload-time = "2026-02-24T16:12:55.859Z" }, ] [[package]] @@ -2064,18 +2065,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/4a/91/48db081e7a63bb37284f9fbcefda7c44c277b18b0e13fbc36ea2335b71e6/typer-0.24.1-py3-none-any.whl", hash = "sha256:112c1f0ce578bfb4cab9ffdabc68f031416ebcc216536611ba21f04e9aa84c9e", size = 56085, upload-time = "2026-02-21T16:54:41.616Z" }, ] -[[package]] -name = "typer-slim" -version = "0.24.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typer" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a7/a7/e6aecc4b4eb59598829a3b5076a93aff291b4fdaa2ded25efc4e1f4d219c/typer_slim-0.24.0.tar.gz", hash = "sha256:f0ed36127183f52ae6ced2ecb2521789995992c521a46083bfcdbb652d22ad34", size = 4776, upload-time = "2026-02-16T22:08:51.2Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a7/24/5480c20380dfd18cf33d14784096dca45a24eae6102e91d49a718d3b6855/typer_slim-0.24.0-py3-none-any.whl", hash = "sha256:d5d7ee1ee2834d5020c7c616ed5e0d0f29b9a4b1dd283bdebae198ec09778d0e", size = 3394, upload-time = "2026-02-16T22:08:49.92Z" }, -] - [[package]] name = "types-grpcio" version = "1.0.0.20251009" diff --git a/agents/deepagents_content_builder/src/content_builder/agent.py b/agents/deepagents_content_builder/src/content_builder/agent.py index 7639d9ebf3..b94a5f3595 100644 --- a/agents/deepagents_content_builder/src/content_builder/agent.py +++ b/agents/deepagents_content_builder/src/content_builder/agent.py @@ -160,7 +160,7 @@ async def content_builder_agent( updated_files = await agent_stack_backend.alist(order_by="created_at", order="asc", created_after=started_at) for updated_file in updated_files: - yield updated_file.to_file_part() + yield updated_file.to_part() def serve(): diff --git a/agents/rag/src/rag/agent.py b/agents/rag/src/rag/agent.py index 15b3b33172..c49fdd8c04 100644 --- a/agents/rag/src/rag/agent.py +++ b/agents/rag/src/rag/agent.py @@ -267,7 +267,7 @@ async def handle_tool_success(event, meta): if isinstance(event.output, FileCreatorToolOutput): result = event.output.result for file in result.files: - artifact = AgentArtifact(name=file.filename, parts=[file.to_file_part()]) + artifact = AgentArtifact(name=file.filename, parts=[file.to_part()]) await context.yield_async(artifact) response = ( diff --git a/apps/agentstack-cli/.vscode/launch.json b/apps/agentstack-cli/.vscode/launch.json new file mode 100644 index 0000000000..0108ac1860 --- /dev/null +++ b/apps/agentstack-cli/.vscode/launch.json @@ -0,0 +1,20 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "agentstack cli", + "type": "debugpy", + "env": { + "AGENTSTACK__DEBUG": "true" + }, + "request": "launch", + "module": "agentstack_cli", + "justMyCode": false, + "console": "integratedTerminal", + "args": "${command:pickArgs}" + } + ] +} \ No newline at end of file diff --git a/apps/agentstack-cli/src/agentstack_cli/__main__.py b/apps/agentstack-cli/src/agentstack_cli/__main__.py new file mode 100644 index 0000000000..d654593a0c --- /dev/null +++ b/apps/agentstack-cli/src/agentstack_cli/__main__.py @@ -0,0 +1,6 @@ +# Copyright 2025 © BeeAI a Series of LF Projects, LLC +# SPDX-License-Identifier: Apache-2.0 + +from agentstack_cli import app + +app() diff --git a/apps/agentstack-cli/src/agentstack_cli/api.py b/apps/agentstack-cli/src/agentstack_cli/api.py index 1adbcdf15e..8e73910baa 100644 --- a/apps/agentstack-cli/src/agentstack_cli/api.py +++ b/apps/agentstack-cli/src/agentstack_cli/api.py @@ -19,11 +19,13 @@ from a2a.client import A2AClientHTTPError, Client, ClientConfig, ClientFactory from a2a.types import AgentCard from agentstack_sdk.platform.context import ContextToken +from google.protobuf.json_format import MessageToDict from httpx import HTTPStatusError from httpx._types import RequestFiles from agentstack_cli import configuration from agentstack_cli.configuration import Configuration +from agentstack_cli.utils import pick logger = logging.getLogger(__name__) @@ -142,7 +144,8 @@ async def a2a_client(agent_card: AgentCard, context_token: ContextToken) -> Asyn ) except A2AClientHTTPError as ex: card_data = json.dumps( - agent_card.model_dump(include={"url", "additional_interfaces", "preferred_transport"}), indent=2 + pick(MessageToDict(agent_card), {"url", "additional_interfaces", "preferred_transport"}), + indent=2, ) raise RuntimeError( f"The agent is not reachable, please check that the agent card is configured properly.\n" diff --git a/apps/agentstack-cli/src/agentstack_cli/commands/agent.py b/apps/agentstack-cli/src/agentstack_cli/commands/agent.py index b28701142a..a2fb4ca564 100644 --- a/apps/agentstack-cli/src/agentstack_cli/commands/agent.py +++ b/apps/agentstack-cli/src/agentstack_cli/commands/agent.py @@ -5,7 +5,6 @@ import abc import asyncio -import base64 import calendar import inspect import json @@ -14,26 +13,16 @@ import sys import typing from enum import StrEnum -from textwrap import dedent from uuid import uuid4 import httpx from a2a.client import Client from a2a.types import ( AgentCard, - DataPart, - FilePart, - FileWithBytes, - FileWithUri, Message, Part, Role, - Task, - TaskArtifactUpdateEvent, TaskState, - TaskStatus, - TaskStatusUpdateEvent, - TextPart, ) from agentstack_sdk.a2a.extensions import ( EmbeddingFulfillment, @@ -95,6 +84,7 @@ from agentstack_sdk.platform import BuildState, File, ModelProvider, Provider, UserFeedback from agentstack_sdk.platform.context import Context, ContextPermissions, ContextToken, Permissions from agentstack_sdk.platform.model_provider import ModelCapability +from google.protobuf.json_format import MessageToDict from InquirerPy import inquirer from InquirerPy.base.control import Choice from InquirerPy.validator import EmptyInputValidator @@ -102,7 +92,6 @@ from rich.box import HORIZONTALS from rich.console import ConsoleRenderable, Group, NewLine from rich.panel import Panel -from rich.text import Text from agentstack_cli.commands.build import _server_side_build from agentstack_cli.commands.model import ensure_llm_provider @@ -153,9 +142,11 @@ class ProviderUtils(BaseModel): @staticmethod def detail(provider: Provider) -> dict[str, str] | None: ui_extension = [ - ext for ext in provider.agent_card.capabilities.extensions or [] if "ui/agent-detail" in ext.uri + MessageToDict(ext) + for ext in provider.agent_card.capabilities.extensions or [] + if "ui/agent-detail" in ext.uri ] - return ui_extension[0].params if ui_extension else None + return ui_extension[0]["params"] if ui_extension else None @staticmethod def last_error(provider: Provider) -> str | None: @@ -697,7 +688,7 @@ def _get_settings_from_agent_card(agent_card: AgentCard) -> tuple[SettingsFormRe async def _run_agent( client: Client, - input: str | DataPart | FormResponse, + input: str | Part | FormResponse, agent_card: AgentCard, context_token: ContextToken, settings: AgentRunSettings | SettingsFormResponse | None = None, @@ -796,15 +787,15 @@ async def _run_agent( msg = Message( message_id=str(uuid4()), parts=[ - Part( - root=TextPart(text=input) + ( + Part(text=input) if isinstance(input, str) - else TextPart(text="") + else Part(text="") if isinstance(input, FormResponse) else input ) ], - role=Role.user, + role=Role.ROLE_USER, task_id=task_id, context_id=context_token.context_id, metadata=metadata, @@ -813,34 +804,24 @@ async def _run_agent( stream = client.send_message(msg) while True: - async for event in stream: + async for response, task in stream: if not console_status_stopped: console_status_stopped = True console_status.stop() - match event: - case Message(task_id=task_id) as message: - console.print( - dedent( - """\ - ⚠️ [yellow]Warning[/yellow]: - Receiving message event outside of task is not supported. - Please use agentstack-sdk for writing your agents or ensure you always create a task first - using TaskUpdater() from a2a SDK: see https://a2a-protocol.org/v0.3.0/topics/life-of-a-task - """ - ) - ) - # Basic fallback - for part in message.parts: - if isinstance(part.root, TextPart): - console.print(part.root.text) - case Task(id=task_id), TaskStatusUpdateEvent( - status=TaskStatus(state=TaskState.completed, message=message) - ): + + task_id = task.id if task else task_id + + if response.HasField("status_update"): + update = response.status_update + status = update.status + state = status.state + message = status.message if status.HasField("message") else None + + if state == TaskState.TASK_STATE_COMPLETED: console.print() # Add newline after completion return - case Task(id=task_id), TaskStatusUpdateEvent( - status=TaskStatus(state=TaskState.working | TaskState.submitted, message=message) - ): + + elif state in (TaskState.TASK_STATE_WORKING, TaskState.TASK_STATE_SUBMITTED): # Handle streaming content during working state if message: if trajectory_extension and (trajectory := trajectory_extension.parse_server_metadata(message)): @@ -857,22 +838,23 @@ async def _run_agent( console.print() log_type = None for part in message.parts: - if isinstance(part.root, TextPart): - console.print(part.root.text, end="") - case Task(id=task_id), TaskStatusUpdateEvent( - status=TaskStatus(state=TaskState.input_required, message=message) - ): + if part.HasField("text"): + console.print(part.text, end="") + + elif state == TaskState.TASK_STATE_INPUT_REQUIRED: if handle_input is None: raise ValueError("Agent requires input but no input handler provided") if form_metadata := ( - message.metadata.get(FormRequestExtensionSpec.URI) if message and message.metadata else None + MessageToDict(message.metadata).get(FormRequestExtensionSpec.URI) + if message and message.metadata + else None ): stream = client.send_message( Message( message_id=str(uuid4()), parts=[], - role=Role.user, + role=Role.ROLE_USER, task_id=task_id, context_id=context_token.context_id, metadata={ @@ -886,70 +868,73 @@ async def _run_agent( text = "" for part in message.parts if message else []: - if isinstance(part.root, TextPart): - text = part.root.text + if part.HasField("text"): + text = part.text console.print(f"\n[bold]Agent requires your input[/bold]: {text}\n") user_input = handle_input() stream = client.send_message( Message( message_id=str(uuid4()), - parts=[Part(root=TextPart(text=user_input))], - role=Role.user, + parts=[Part(text=user_input)], + role=Role.ROLE_USER, task_id=task_id, context_id=context_token.context_id, ) ) break - case Task(id=task_id), TaskStatusUpdateEvent( - status=TaskStatus( - state=TaskState.canceled | TaskState.failed | TaskState.rejected as status, - message=message, - ) + + elif state in ( + TaskState.TASK_STATE_CANCELED, + TaskState.TASK_STATE_FAILED, + TaskState.TASK_STATE_REJECTED, ): error = "" - if message and message.parts and isinstance(message.parts[0].root, TextPart): - error = message.parts[0].root.text - console.print(f"\n:boom: [red][bold]Task {status.value}[/bold][/red]") + if message and message.parts and message.parts[0].HasField("text"): + error = message.parts[0].text + console.print(f"\n:boom: [red][bold]Task {TaskState.Name(state)}[/bold][/red]") console.print(Markdown(error)) return - case Task(id=task_id), TaskStatusUpdateEvent( - status=TaskStatus(state=TaskState.auth_required, message=message) - ): + + elif state == TaskState.TASK_STATE_AUTH_REQUIRED: console.print("[yellow]Authentication required[/yellow]") return - case Task(id=task_id), TaskStatusUpdateEvent(status=TaskStatus(state=state, message=message)): + + else: console.print(f"[yellow]Unknown task status: {state}[/yellow]") - case Task(id=task_id), TaskArtifactUpdateEvent(artifact=artifact): - if dump_files_path is None: - continue - dump_files_path.mkdir(parents=True, exist_ok=True) # noqa: ASYNC240 - full_path = dump_files_path / (artifact.name or "unnamed").lstrip("/") - full_path.resolve().relative_to(dump_files_path.resolve()) # noqa: ASYNC240 - full_path.parent.mkdir(parents=True, exist_ok=True) - try: - for part in artifact.parts[:1]: - match part.root: - case FilePart(): - match part.root.file: - case FileWithBytes(bytes=bytes_str): - full_path.write_bytes(base64.b64decode(bytes_str)) - case FileWithUri(uri=uri): - if uri.startswith("agentstack://"): - async with File.load_content(uri.removeprefix("agentstack://")) as file: - full_path.write_bytes(file.content) - else: - async with httpx.AsyncClient() as httpx_client: - full_path.write_bytes((await httpx_client.get(uri)).content) - console.print(f"📁 Saved {full_path}") - case TextPart(text=text): - full_path.write_text(text) - case _: - console.print(f"⚠️ Artifact part {type(part).__name__} is not supported") - if len(artifact.parts) > 1: - console.print("⚠️ Artifact with more than 1 part are not supported.") - except ValueError: - console.print(f"⚠️ Skipping artifact {artifact.name} - outside dump directory") + elif response.HasField("artifact_update"): + artifact = response.artifact_update.artifact + if dump_files_path is None: + continue + dump_files_path.mkdir(parents=True, exist_ok=True) + full_path = dump_files_path / (artifact.name or "unnamed").lstrip("/") + full_path.resolve().relative_to(dump_files_path.resolve()) + full_path.parent.mkdir(parents=True, exist_ok=True) + try: + for part in artifact.parts[:1]: + if part.HasField("raw"): + full_path.write_bytes(part.raw) + console.print(f"📁 Saved {full_path}") + elif part.HasField("url"): + uri = part.url + if uri.startswith("agentstack://"): + async with File.load_content(uri.removeprefix("agentstack://")) as file: + full_path.write_bytes(file.content) + else: + async with httpx.AsyncClient() as httpx_client: + full_path.write_bytes((await httpx_client.get(uri)).content) + console.print(f"📁 Saved {full_path}") + elif part.HasField("text"): + full_path.write_text(part.text) + else: + console.print(f"⚠️ Artifact part {type(part).__name__} is not supported") + if len(artifact.parts) > 1: + console.print("⚠️ Artifact with more than 1 part are not supported.") + except ValueError: + console.print(f"⚠️ Skipping artifact {artifact.name} - outside dump directory") + + else: + print(response) else: break # Stream ended normally @@ -1217,15 +1202,14 @@ async def run_agent( f"Agent {agent.name} does not use any supported UIs.\n" + "Please use the agent according to the following examples and schema:" ) - err_console.print(_render_examples(agent)) exit(1) initial_form_render = next( ( - FormRender.model_validate(ext.params["form_demands"]["initial_form"]) + FormRender.model_validate(MessageToDict(ext.params)["form_demands"]["initial_form"]) for ext in agent.capabilities.extensions or () if ext.uri == FormServiceExtensionSpec.URI and ext.params - and ext.params.get("form_demands", {}).get("initial_form") + and MessageToDict(ext.params).get("form_demands", {}).get("initial_form") ), None, ) @@ -1354,37 +1338,6 @@ def _render_schema(schema: dict[str, Any] | None): return "No schema provided." if not schema else rich.json.JSON.from_data(schema) -def _render_examples(agent: AgentCard): - # TODO - return Text() - # md = "## Examples" - # for i, example in enumerate(examples): - # processing_steps = "\n".join( - # f"{i + 1}. {step}" for i, step in enumerate(example.get("processing_steps", []) or []) - # ) - # name = example.get("name", None) or f"Example #{i + 1}" - # output = f""" - # ### Output - # ``` - # {example.get("output", "")} - # ``` - # """ - # md += f""" - # ### {name} - # {example.get("description", None) or ""} - # - # #### Command - # ```sh - # {example["command"]} - # ``` - # {output if example.get("output", None) else ""} - # - # #### Processing steps - # {processing_steps} - # """ - # return Markdown(md) - - @app.command("info") async def agent_detail( search_path: typing.Annotated[ @@ -1405,11 +1358,9 @@ async def agent_detail( for skill in agent.skills: console.print(Markdown(f"**{skill.name}** \n{skill.description}")) - console.print(_render_examples(agent)) - with create_table(Column("Key", ratio=1), Column("Value", ratio=5), title="Extra information") as table: - for key, value in agent.model_dump(exclude={"description", "examples"}).items(): - if value: + for key, value in MessageToDict(agent).items(): + if key not in ["description", "examples"] and value: table.add_row(key, str(value)) console.print() console.print(table) diff --git a/apps/agentstack-cli/src/agentstack_cli/utils.py b/apps/agentstack-cli/src/agentstack_cli/utils.py index 12b7e4a8fb..dd8e06ace1 100644 --- a/apps/agentstack-cli/src/agentstack_cli/utils.py +++ b/apps/agentstack-cli/src/agentstack_cli/utils.py @@ -1,7 +1,6 @@ # Copyright 2025 © BeeAI a Series of LF Projects, LLC # SPDX-License-Identifier: Apache-2.0 - from __future__ import annotations import contextlib @@ -13,7 +12,7 @@ import sys import time from collections import Counter -from collections.abc import AsyncIterator, Mapping, MutableMapping +from collections.abc import AsyncIterator, Iterable, Mapping, MutableMapping from contextlib import asynccontextmanager from contextvars import ContextVar from copy import deepcopy @@ -476,3 +475,7 @@ def merge(destination: MutableMapping[str, Any], *sources: Mapping[str, Any]) -> :return: """ return functools.reduce(_deepmerge, sources, destination) + + +def pick(dict: Mapping[str, Any], keys: Iterable[str]) -> dict[str, Any]: + return {key: value for key, value in dict.items() if key in keys} diff --git a/apps/agentstack-cli/uv.lock b/apps/agentstack-cli/uv.lock index 1ea8b9b150..5bc4f84d3d 100644 --- a/apps/agentstack-cli/uv.lock +++ b/apps/agentstack-cli/uv.lock @@ -234,11 +234,11 @@ wheels = [ [[package]] name = "certifi" -version = "2026.1.4" +version = "2026.2.25" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e0/2d/a891ca51311197f6ad14a7ef42e2399f36cf2f9bd44752b3dc4eab60fdc5/certifi-2026.1.4.tar.gz", hash = "sha256:ac726dd470482006e014ad384921ed6438c457018f4b3d204aea4281258b2120", size = 154268, upload-time = "2026-01-04T02:42:41.825Z" } +sdist = { url = "https://files.pythonhosted.org/packages/af/2d/7bf41579a8986e348fa033a31cdd0e4121114f6bce2457e8876010b092dd/certifi-2026.2.25.tar.gz", hash = "sha256:e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7", size = 155029, upload-time = "2026-02-25T02:54:17.342Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c", size = 152900, upload-time = "2026-01-04T02:42:40.15Z" }, + { url = "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl", hash = "sha256:027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa", size = 153684, upload-time = "2026-02-25T02:54:15.766Z" }, ] [[package]] @@ -412,19 +412,19 @@ wheels = [ [[package]] name = "faker" -version = "40.4.0" +version = "40.5.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "tzdata", marker = "sys_platform == 'win32'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fc/7e/dccb7013c9f3d66f2e379383600629fec75e4da2698548bdbf2041ea4b51/faker-40.4.0.tar.gz", hash = "sha256:76f8e74a3df28c3e2ec2caafa956e19e37a132fdc7ea067bc41783affcfee364", size = 1952221, upload-time = "2026-02-06T23:30:15.515Z" } +sdist = { url = "https://files.pythonhosted.org/packages/03/2a/96fff3edcb10f6505143448a4b91535f77b74865cec45be52690ee280443/faker-40.5.1.tar.gz", hash = "sha256:70222361cd82aa10cb86066d1a4e8f47f2bcdc919615c412045a69c4e6da0cd3", size = 1952684, upload-time = "2026-02-23T21:34:38.362Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ac/63/58efa67c10fb27810d34351b7a10f85f109a7f7e2a07dc3773952459c47b/faker-40.4.0-py3-none-any.whl", hash = "sha256:486d43c67ebbb136bc932406418744f9a0bdf2c07f77703ea78b58b77e9aa443", size = 1987060, upload-time = "2026-02-06T23:30:13.44Z" }, + { url = "https://files.pythonhosted.org/packages/4d/a9/1eed4db92d0aec2f9bfdf1faae0ab0418b5e121dda5701f118a7a4f0cd6a/faker-40.5.1-py3-none-any.whl", hash = "sha256:c69640c1e13bad49b4bcebcbf1b52f9f1a872b6ea186c248ada34d798f1661bf", size = 1987053, upload-time = "2026-02-23T21:34:36.418Z" }, ] [[package]] name = "fastapi" -version = "0.131.0" +version = "0.133.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "annotated-doc" }, @@ -433,9 +433,9 @@ dependencies = [ { name = "typing-extensions" }, { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/91/32/158cbf685b7d5a26f87131069da286bf10fc9fbf7fc968d169d48a45d689/fastapi-0.131.0.tar.gz", hash = "sha256:6531155e52bee2899a932c746c9a8250f210e3c3303a5f7b9f8a808bfe0548ff", size = 369612, upload-time = "2026-02-22T16:38:11.252Z" } +sdist = { url = "https://files.pythonhosted.org/packages/22/6f/0eafed8349eea1fa462238b54a624c8b408cd1ba2795c8e64aa6c34f8ab7/fastapi-0.133.1.tar.gz", hash = "sha256:ed152a45912f102592976fde6cbce7dae1a8a1053da94202e51dd35d184fadd6", size = 378741, upload-time = "2026-02-25T18:18:17.398Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ff/94/b58ec24c321acc2ad1327f69b033cadc005e0f26df9a73828c9e9c7db7ce/fastapi-0.131.0-py3-none-any.whl", hash = "sha256:ed0e53decccf4459de78837ce1b867cd04fa9ce4579497b842579755d20b405a", size = 103854, upload-time = "2026-02-22T16:38:09.814Z" }, + { url = "https://files.pythonhosted.org/packages/d2/c9/a175a7779f3599dfa4adfc97a6ce0e157237b3d7941538604aadaf97bfb6/fastapi-0.133.1-py3-none-any.whl", hash = "sha256:658f34ba334605b1617a65adf2ea6461901bdb9af3a3080d63ff791ecf7dc2e2", size = 109029, upload-time = "2026-02-25T18:18:18.578Z" }, ] [[package]] @@ -763,7 +763,7 @@ wheels = [ [[package]] name = "openai" -version = "2.21.0" +version = "2.24.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, @@ -775,9 +775,9 @@ dependencies = [ { name = "tqdm" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/92/e5/3d197a0947a166649f566706d7a4c8f7fe38f1fa7b24c9bcffe4c7591d44/openai-2.21.0.tar.gz", hash = "sha256:81b48ce4b8bbb2cc3af02047ceb19561f7b1dc0d4e52d1de7f02abfd15aa59b7", size = 644374, upload-time = "2026-02-14T00:12:01.577Z" } +sdist = { url = "https://files.pythonhosted.org/packages/55/13/17e87641b89b74552ed408a92b231283786523edddc95f3545809fab673c/openai-2.24.0.tar.gz", hash = "sha256:1e5769f540dbd01cb33bc4716a23e67b9d695161a734aff9c5f925e2bf99a673", size = 658717, upload-time = "2026-02-24T20:02:07.958Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cc/56/0a89092a453bb2c676d66abee44f863e742b2110d4dbb1dbcca3f7e5fc33/openai-2.21.0-py3-none-any.whl", hash = "sha256:0bc1c775e5b1536c294eded39ee08f8407656537ccc71b1004104fe1602e267c", size = 1103065, upload-time = "2026-02-14T00:11:59.603Z" }, + { url = "https://files.pythonhosted.org/packages/c9/30/844dc675ee6902579b8eef01ed23917cc9319a1c9c0c14ec6e39340c96d0/openai-2.24.0-py3-none-any.whl", hash = "sha256:fed30480d7d6c884303287bde864980a4b137b60553ffbcf9ab4a233b7a73d94", size = 1120122, upload-time = "2026-02-24T20:02:05.669Z" }, ] [[package]] @@ -888,7 +888,7 @@ wheels = [ [[package]] name = "opentelemetry-instrumentation-openai" -version = "0.52.4" +version = "0.52.6" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, @@ -896,9 +896,9 @@ dependencies = [ { name = "opentelemetry-semantic-conventions" }, { name = "opentelemetry-semantic-conventions-ai" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/37/91/1f72807c84cfaf5b3386011f56357ea304f9e6c0039857d3fa38a13e4d03/opentelemetry_instrumentation_openai-0.52.4.tar.gz", hash = "sha256:690b9c14d68b50c87f24006122165e97819557c13ff7f520e2043e2f69f2789c", size = 6978369, upload-time = "2026-02-19T13:22:02.051Z" } +sdist = { url = "https://files.pythonhosted.org/packages/37/86/1fe5008f3714118fdc1024cd141140a5f204d5ac7016e87a0f07a834efb2/opentelemetry_instrumentation_openai-0.52.6.tar.gz", hash = "sha256:0eb23dc90804a726e516fcbd649cb99f10dfdb5e31d29e44c4b1b8f402dd905d", size = 6978397, upload-time = "2026-02-26T15:40:17.154Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a3/5a/0a0d6cf2b93cd1ec6f7c84f8731ad2d20e6313564362690eee6bbde9b989/opentelemetry_instrumentation_openai-0.52.4-py3-none-any.whl", hash = "sha256:73e6837a5ea44f61439c937f7116c623ccdf390034e3393d501e82f9d6298922", size = 43082, upload-time = "2026-02-19T13:21:18.997Z" }, + { url = "https://files.pythonhosted.org/packages/2c/4a/4623d0adc0187cc45bce631f891c30cd01cf2562d37b918b79561200d985/opentelemetry_instrumentation_openai-0.52.6-py3-none-any.whl", hash = "sha256:5e174388520f294f648f9732471c1b9919c71e5d09649a64ab8ff81714c1278b", size = 43084, upload-time = "2026-02-26T15:39:35.584Z" }, ] [[package]] @@ -1193,18 +1193,18 @@ crypto = [ [[package]] name = "pyrefly" -version = "0.53.0" +version = "0.54.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/3a/73/262196c4ea5afec6389366a4b3d49f67655c6396efa1a4053cca37be7c8d/pyrefly-0.53.0.tar.gz", hash = "sha256:aef117e8abb9aa4cf17fc64fbf450d825d3c65fc9de3c02ed20129ebdd57aa74", size = 5040338, upload-time = "2026-02-17T21:15:44.877Z" } +sdist = { url = "https://files.pythonhosted.org/packages/81/44/c10b16a302fda90d0af1328f880b232761b510eab546616a7be2fdf35a57/pyrefly-0.54.0.tar.gz", hash = "sha256:c6663be64d492f0d2f2a411ada9f28a6792163d34133639378b7f3dd9a8dca94", size = 5098893, upload-time = "2026-02-23T15:44:35.111Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e5/9b/3af46ac06dcfd7b27f15e991d2d4f0082519e6906b1f304f511e4db3ad5f/pyrefly-0.53.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:79d7fb35dff0988b3943c26f74cc752fad54357a0bc33f7db665f02d1c9a5bcc", size = 12041081, upload-time = "2026-02-17T21:15:24.769Z" }, - { url = "https://files.pythonhosted.org/packages/79/4f/23422479153f8f88d1699461bf8f22e32320bb0fc1272774ea8a17463302/pyrefly-0.53.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e1d98b1e86f3c38db44860695b7986e731238e1b19c3cad7a3050476a8f6f84d", size = 11604301, upload-time = "2026-02-17T21:15:27.23Z" }, - { url = "https://files.pythonhosted.org/packages/d8/9a/f4cc6b81a464c31c3112b46abbd44ccd569f01c71a0abf39eeccf6ace914/pyrefly-0.53.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb9f2440f7e0c70aa18400f44aed994c326a1ab00f2b01cf7253a63fc62d7c6b", size = 32674148, upload-time = "2026-02-17T21:15:29.762Z" }, - { url = "https://files.pythonhosted.org/packages/4c/cc/fa98606a628380b7ae4623dbc30843e8fed6b7a631c89503bdf123e47453/pyrefly-0.53.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e4e826a5ff2aba2c41e02e6094580751c512db7916e60728cd8612dbcf178d7b", size = 35099098, upload-time = "2026-02-17T21:15:32.383Z" }, - { url = "https://files.pythonhosted.org/packages/71/d2/ab4105ee90495314a8ad6be4d6736c9f20e4b0ceb49cf015ddc84c394c25/pyrefly-0.53.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf4c69410c7a96b417a390a0e3d340f4370fdab02f9d3eaa222c4bd42e3ce24a", size = 37777824, upload-time = "2026-02-17T21:15:35.474Z" }, - { url = "https://files.pythonhosted.org/packages/38/99/0779b7202d801cdf67f08159cf7dd318d23114661143689a767d9b8a98f1/pyrefly-0.53.0-py3-none-win32.whl", hash = "sha256:00687bb6be6e366b8c0137a89625da40ced3b9212a65e561857ff888fe88e6e8", size = 11111961, upload-time = "2026-02-17T21:15:38.455Z" }, - { url = "https://files.pythonhosted.org/packages/bd/71/dc7e59f0acb81dcf3f56e7ad30e740a08527403cb1d657caca9d44fef803/pyrefly-0.53.0-py3-none-win_amd64.whl", hash = "sha256:e0512e6f7af44ae01cfddba096ff7740e15cbd1d0497a3d34a7afcb504e2b300", size = 11888648, upload-time = "2026-02-17T21:15:40.471Z" }, - { url = "https://files.pythonhosted.org/packages/5d/72/2a7c00a439c6593430289a4581426efe0bee73f6e5a443f501969e104300/pyrefly-0.53.0-py3-none-win_arm64.whl", hash = "sha256:5066e2102769683749102421b8b8667cae26abe1827617f04e8df4317e0a94af", size = 11368150, upload-time = "2026-02-17T21:15:42.74Z" }, + { url = "https://files.pythonhosted.org/packages/5f/99/8fdcdb4e55f0227fdd9f6abce36b619bab1ecb0662b83b66adc8cba3c788/pyrefly-0.54.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:58a3f092b6dc25ef79b2dc6c69a40f36784ca157c312bfc0baea463926a9db6d", size = 12223973, upload-time = "2026-02-23T15:44:14.278Z" }, + { url = "https://files.pythonhosted.org/packages/90/35/c2aaf87a76003ad27b286594d2e5178f811eaa15bfe3d98dba2b47d56dd1/pyrefly-0.54.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:615081414106dd95873bc39c3a4bed68754c6cc24a8177ac51d22f88f88d3eb3", size = 11785585, upload-time = "2026-02-23T15:44:17.468Z" }, + { url = "https://files.pythonhosted.org/packages/c4/4a/ced02691ed67e5a897714979196f08ad279ec7ec7f63c45e00a75a7f3c0e/pyrefly-0.54.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cbcaf20f5fe585079079a95205c1f3cd4542d17228cdf1df560288880623b70", size = 33381977, upload-time = "2026-02-23T15:44:19.736Z" }, + { url = "https://files.pythonhosted.org/packages/0b/ce/72a117ed437c8f6950862181014b41e36f3c3997580e29b772b71e78d587/pyrefly-0.54.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66d5da116c0d34acfbd66663addd3ca8aa78a636f6692a66e078126d3620a883", size = 35962821, upload-time = "2026-02-23T15:44:22.357Z" }, + { url = "https://files.pythonhosted.org/packages/85/de/89013f5ae0a35d2b6b01274a92a35ee91431ea001050edf0a16748d39875/pyrefly-0.54.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ef3ac27f1a4baaf67aead64287d3163350844794aca6315ad1a9650b16ec26a", size = 38496689, upload-time = "2026-02-23T15:44:25.236Z" }, + { url = "https://files.pythonhosted.org/packages/9f/9a/33b097c7bf498b924742dca32dd5d9c6a3fa6c2b52b63a58eb9e1980ca89/pyrefly-0.54.0-py3-none-win32.whl", hash = "sha256:7d607d72200a8afbd2db10bfefb40160a7a5d709d207161c21649cedd5cfc09a", size = 11295268, upload-time = "2026-02-23T15:44:27.551Z" }, + { url = "https://files.pythonhosted.org/packages/d4/21/9263fd1144d2a3d7342b474f183f7785b3358a1565c864089b780110b933/pyrefly-0.54.0-py3-none-win_amd64.whl", hash = "sha256:fd416f04f89309385696f685bd5c9141011f18c8072f84d31ca20c748546e791", size = 12081810, upload-time = "2026-02-23T15:44:29.461Z" }, + { url = "https://files.pythonhosted.org/packages/ea/5b/fad062a196c064cbc8564de5b2f4d3cb6315f852e3b31e8a1ce74c69a1ea/pyrefly-0.54.0-py3-none-win_arm64.whl", hash = "sha256:f06ab371356c7b1925e0bffe193b738797e71e5dbbff7fb5a13f90ee7521211d", size = 11564930, upload-time = "2026-02-23T15:44:33.053Z" }, ] [[package]] @@ -1420,27 +1420,27 @@ wheels = [ [[package]] name = "ruff" -version = "0.15.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/06/04/eab13a954e763b0606f460443fcbf6bb5a0faf06890ea3754ff16523dce5/ruff-0.15.2.tar.gz", hash = "sha256:14b965afee0969e68bb871eba625343b8673375f457af4abe98553e8bbb98342", size = 4558148, upload-time = "2026-02-19T22:32:20.271Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2f/70/3a4dc6d09b13cb3e695f28307e5d889b2e1a66b7af9c5e257e796695b0e6/ruff-0.15.2-py3-none-linux_armv6l.whl", hash = "sha256:120691a6fdae2f16d65435648160f5b81a9625288f75544dc40637436b5d3c0d", size = 10430565, upload-time = "2026-02-19T22:32:41.824Z" }, - { url = "https://files.pythonhosted.org/packages/71/0b/bb8457b56185ece1305c666dc895832946d24055be90692381c31d57466d/ruff-0.15.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:a89056d831256099658b6bba4037ac6dd06f49d194199215befe2bb10457ea5e", size = 10820354, upload-time = "2026-02-19T22:32:07.366Z" }, - { url = "https://files.pythonhosted.org/packages/2d/c1/e0532d7f9c9e0b14c46f61b14afd563298b8b83f337b6789ddd987e46121/ruff-0.15.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e36dee3a64be0ebd23c86ffa3aa3fd3ac9a712ff295e192243f814a830b6bd87", size = 10170767, upload-time = "2026-02-19T22:32:13.188Z" }, - { url = "https://files.pythonhosted.org/packages/47/e8/da1aa341d3af017a21c7a62fb5ec31d4e7ad0a93ab80e3a508316efbcb23/ruff-0.15.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9fb47b6d9764677f8c0a193c0943ce9a05d6763523f132325af8a858eadc2b9", size = 10529591, upload-time = "2026-02-19T22:32:02.547Z" }, - { url = "https://files.pythonhosted.org/packages/93/74/184fbf38e9f3510231fbc5e437e808f0b48c42d1df9434b208821efcd8d6/ruff-0.15.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f376990f9d0d6442ea9014b19621d8f2aaf2b8e39fdbfc79220b7f0c596c9b80", size = 10260771, upload-time = "2026-02-19T22:32:36.938Z" }, - { url = "https://files.pythonhosted.org/packages/05/ac/605c20b8e059a0bc4b42360414baa4892ff278cec1c91fff4be0dceedefd/ruff-0.15.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2dcc987551952d73cbf5c88d9fdee815618d497e4df86cd4c4824cc59d5dd75f", size = 11045791, upload-time = "2026-02-19T22:32:31.642Z" }, - { url = "https://files.pythonhosted.org/packages/fd/52/db6e419908f45a894924d410ac77d64bdd98ff86901d833364251bd08e22/ruff-0.15.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:42a47fd785cbe8c01b9ff45031af875d101b040ad8f4de7bbb716487c74c9a77", size = 11879271, upload-time = "2026-02-19T22:32:29.305Z" }, - { url = "https://files.pythonhosted.org/packages/3e/d8/7992b18f2008bdc9231d0f10b16df7dda964dbf639e2b8b4c1b4e91b83af/ruff-0.15.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cbe9f49354866e575b4c6943856989f966421870e85cd2ac94dccb0a9dcb2fea", size = 11303707, upload-time = "2026-02-19T22:32:22.492Z" }, - { url = "https://files.pythonhosted.org/packages/d7/02/849b46184bcfdd4b64cde61752cc9a146c54759ed036edd11857e9b8443b/ruff-0.15.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b7a672c82b5f9887576087d97be5ce439f04bbaf548ee987b92d3a7dede41d3a", size = 11149151, upload-time = "2026-02-19T22:32:44.234Z" }, - { url = "https://files.pythonhosted.org/packages/70/04/f5284e388bab60d1d3b99614a5a9aeb03e0f333847e2429bebd2aaa1feec/ruff-0.15.2-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:72ecc64f46f7019e2bcc3cdc05d4a7da958b629a5ab7033195e11a438403d956", size = 11091132, upload-time = "2026-02-19T22:32:24.691Z" }, - { url = "https://files.pythonhosted.org/packages/fa/ae/88d844a21110e14d92cf73d57363fab59b727ebeabe78009b9ccb23500af/ruff-0.15.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:8dcf243b15b561c655c1ef2f2b0050e5d50db37fe90115507f6ff37d865dc8b4", size = 10504717, upload-time = "2026-02-19T22:32:26.75Z" }, - { url = "https://files.pythonhosted.org/packages/64/27/867076a6ada7f2b9c8292884ab44d08fd2ba71bd2b5364d4136f3cd537e1/ruff-0.15.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:dab6941c862c05739774677c6273166d2510d254dac0695c0e3f5efa1b5585de", size = 10263122, upload-time = "2026-02-19T22:32:10.036Z" }, - { url = "https://files.pythonhosted.org/packages/e7/ef/faf9321d550f8ebf0c6373696e70d1758e20ccdc3951ad7af00c0956be7c/ruff-0.15.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:1b9164f57fc36058e9a6806eb92af185b0697c9fe4c7c52caa431c6554521e5c", size = 10735295, upload-time = "2026-02-19T22:32:39.227Z" }, - { url = "https://files.pythonhosted.org/packages/2f/55/e8089fec62e050ba84d71b70e7834b97709ca9b7aba10c1a0b196e493f97/ruff-0.15.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:80d24fcae24d42659db7e335b9e1531697a7102c19185b8dc4a028b952865fd8", size = 11241641, upload-time = "2026-02-19T22:32:34.617Z" }, - { url = "https://files.pythonhosted.org/packages/23/01/1c30526460f4d23222d0fabd5888868262fd0e2b71a00570ca26483cd993/ruff-0.15.2-py3-none-win32.whl", hash = "sha256:fd5ff9e5f519a7e1bd99cbe8daa324010a74f5e2ebc97c6242c08f26f3714f6f", size = 10507885, upload-time = "2026-02-19T22:32:15.635Z" }, - { url = "https://files.pythonhosted.org/packages/5c/10/3d18e3bbdf8fc50bbb4ac3cc45970aa5a9753c5cb51bf9ed9a3cd8b79fa3/ruff-0.15.2-py3-none-win_amd64.whl", hash = "sha256:d20014e3dfa400f3ff84830dfb5755ece2de45ab62ecea4af6b7262d0fb4f7c5", size = 11623725, upload-time = "2026-02-19T22:32:04.947Z" }, - { url = "https://files.pythonhosted.org/packages/6d/78/097c0798b1dab9f8affe73da9642bb4500e098cb27fd8dc9724816ac747b/ruff-0.15.2-py3-none-win_arm64.whl", hash = "sha256:cabddc5822acdc8f7b5527b36ceac55cc51eec7b1946e60181de8fe83ca8876e", size = 10941649, upload-time = "2026-02-19T22:32:18.108Z" }, +version = "0.15.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/da/31/d6e536cdebb6568ae75a7f00e4b4819ae0ad2640c3604c305a0428680b0c/ruff-0.15.4.tar.gz", hash = "sha256:3412195319e42d634470cc97aa9803d07e9d5c9223b99bcb1518f0c725f26ae1", size = 4569550, upload-time = "2026-02-26T20:04:14.959Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f2/82/c11a03cfec3a4d26a0ea1e571f0f44be5993b923f905eeddfc397c13d360/ruff-0.15.4-py3-none-linux_armv6l.whl", hash = "sha256:a1810931c41606c686bae8b5b9a8072adac2f611bb433c0ba476acba17a332e0", size = 10453333, upload-time = "2026-02-26T20:04:20.093Z" }, + { url = "https://files.pythonhosted.org/packages/ce/5d/6a1f271f6e31dffb31855996493641edc3eef8077b883eaf007a2f1c2976/ruff-0.15.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:5a1632c66672b8b4d3e1d1782859e98d6e0b4e70829530666644286600a33992", size = 10853356, upload-time = "2026-02-26T20:04:05.808Z" }, + { url = "https://files.pythonhosted.org/packages/b1/d8/0fab9f8842b83b1a9c2bf81b85063f65e93fb512e60effa95b0be49bfc54/ruff-0.15.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:a4386ba2cd6c0f4ff75252845906acc7c7c8e1ac567b7bc3d373686ac8c222ba", size = 10187434, upload-time = "2026-02-26T20:03:54.656Z" }, + { url = "https://files.pythonhosted.org/packages/85/cc/cc220fd9394eff5db8d94dec199eec56dd6c9f3651d8869d024867a91030/ruff-0.15.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2496488bdfd3732747558b6f95ae427ff066d1fcd054daf75f5a50674411e75", size = 10535456, upload-time = "2026-02-26T20:03:52.738Z" }, + { url = "https://files.pythonhosted.org/packages/fa/0f/bced38fa5cf24373ec767713c8e4cadc90247f3863605fb030e597878661/ruff-0.15.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3f1c4893841ff2d54cbda1b2860fa3260173df5ddd7b95d370186f8a5e66a4ac", size = 10287772, upload-time = "2026-02-26T20:04:08.138Z" }, + { url = "https://files.pythonhosted.org/packages/2b/90/58a1802d84fed15f8f281925b21ab3cecd813bde52a8ca033a4de8ab0e7a/ruff-0.15.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:820b8766bd65503b6c30aaa6331e8ef3a6e564f7999c844e9a547c40179e440a", size = 11049051, upload-time = "2026-02-26T20:04:03.53Z" }, + { url = "https://files.pythonhosted.org/packages/d2/ac/b7ad36703c35f3866584564dc15f12f91cb1a26a897dc2fd13d7cb3ae1af/ruff-0.15.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9fb74bab47139c1751f900f857fa503987253c3ef89129b24ed375e72873e85", size = 11890494, upload-time = "2026-02-26T20:04:10.497Z" }, + { url = "https://files.pythonhosted.org/packages/93/3d/3eb2f47a39a8b0da99faf9c54d3eb24720add1e886a5309d4d1be73a6380/ruff-0.15.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f80c98765949c518142b3a50a5db89343aa90f2c2bf7799de9986498ae6176db", size = 11326221, upload-time = "2026-02-26T20:04:12.84Z" }, + { url = "https://files.pythonhosted.org/packages/ff/90/bf134f4c1e5243e62690e09d63c55df948a74084c8ac3e48a88468314da6/ruff-0.15.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:451a2e224151729b3b6c9ffb36aed9091b2996fe4bdbd11f47e27d8f2e8888ec", size = 11168459, upload-time = "2026-02-26T20:04:00.969Z" }, + { url = "https://files.pythonhosted.org/packages/b5/e5/a64d27688789b06b5d55162aafc32059bb8c989c61a5139a36e1368285eb/ruff-0.15.4-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:a8f157f2e583c513c4f5f896163a93198297371f34c04220daf40d133fdd4f7f", size = 11104366, upload-time = "2026-02-26T20:03:48.099Z" }, + { url = "https://files.pythonhosted.org/packages/f1/f6/32d1dcb66a2559763fc3027bdd65836cad9eb09d90f2ed6a63d8e9252b02/ruff-0.15.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:917cc68503357021f541e69b35361c99387cdbbf99bd0ea4aa6f28ca99ff5338", size = 10510887, upload-time = "2026-02-26T20:03:45.771Z" }, + { url = "https://files.pythonhosted.org/packages/ff/92/22d1ced50971c5b6433aed166fcef8c9343f567a94cf2b9d9089f6aa80fe/ruff-0.15.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:e9737c8161da79fd7cfec19f1e35620375bd8b2a50c3e77fa3d2c16f574105cc", size = 10285939, upload-time = "2026-02-26T20:04:22.42Z" }, + { url = "https://files.pythonhosted.org/packages/e6/f4/7c20aec3143837641a02509a4668fb146a642fd1211846634edc17eb5563/ruff-0.15.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:291258c917539e18f6ba40482fe31d6f5ac023994ee11d7bdafd716f2aab8a68", size = 10765471, upload-time = "2026-02-26T20:03:58.924Z" }, + { url = "https://files.pythonhosted.org/packages/d0/09/6d2f7586f09a16120aebdff8f64d962d7c4348313c77ebb29c566cefc357/ruff-0.15.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:3f83c45911da6f2cd5936c436cf86b9f09f09165f033a99dcf7477e34041cbc3", size = 11263382, upload-time = "2026-02-26T20:04:24.424Z" }, + { url = "https://files.pythonhosted.org/packages/1b/fa/2ef715a1cd329ef47c1a050e10dee91a9054b7ce2fcfdd6a06d139afb7ec/ruff-0.15.4-py3-none-win32.whl", hash = "sha256:65594a2d557d4ee9f02834fcdf0a28daa8b3b9f6cb2cb93846025a36db47ef22", size = 10506664, upload-time = "2026-02-26T20:03:50.56Z" }, + { url = "https://files.pythonhosted.org/packages/d0/a8/c688ef7e29983976820d18710f955751d9f4d4eb69df658af3d006e2ba3e/ruff-0.15.4-py3-none-win_amd64.whl", hash = "sha256:04196ad44f0df220c2ece5b0e959c2f37c777375ec744397d21d15b50a75264f", size = 11651048, upload-time = "2026-02-26T20:04:17.191Z" }, + { url = "https://files.pythonhosted.org/packages/3e/0a/9e1be9035b37448ce2e68c978f0591da94389ade5a5abafa4cf99985d1b2/ruff-0.15.4-py3-none-win_arm64.whl", hash = "sha256:60d5177e8cfc70e51b9c5fad936c634872a74209f934c1e79107d11787ad5453", size = 10966776, upload-time = "2026-02-26T20:03:56.908Z" }, ] [[package]] diff --git a/apps/agentstack-sdk-py/examples/check_validation.py b/apps/agentstack-sdk-py/examples/check_validation.py index 486be41521..25df117b34 100644 --- a/apps/agentstack-sdk-py/examples/check_validation.py +++ b/apps/agentstack-sdk-py/examples/check_validation.py @@ -1,3 +1,6 @@ +# Copyright 2026 © BeeAI a Series of LF Projects, LLC +# SPDX-License-Identifier: Apache-2.0 + from a2a.types import Message, Part from google.protobuf import descriptor diff --git a/apps/agentstack-sdk-py/examples/experiment.py b/apps/agentstack-sdk-py/examples/experiment.py index 9b25377649..ecd22e06e6 100644 --- a/apps/agentstack-sdk-py/examples/experiment.py +++ b/apps/agentstack-sdk-py/examples/experiment.py @@ -1,5 +1,8 @@ -from google.protobuf.json_format import MessageToDict +# Copyright 2026 © BeeAI a Series of LF Projects, LLC +# SPDX-License-Identifier: Apache-2.0 + from a2a.types import Message, Part +from google.protobuf.json_format import MessageToDict if __name__ == "__main__": msg = Message(parts=[Part(text="hello")]) diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/auth/oauth/oauth.py b/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/auth/oauth/oauth.py index b038f062fc..e4fb21ff79 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/auth/oauth/oauth.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/auth/oauth/oauth.py @@ -13,6 +13,7 @@ from a2a.server.agent_execution import RequestContext from a2a.types import Message as A2AMessage from a2a.types import Part, Role +from google.protobuf.json_format import MessageToDict from mcp.client.auth import OAuthClientProvider from mcp.shared.auth import OAuthClientMetadata from typing_extensions import override @@ -37,6 +38,18 @@ if TYPE_CHECKING: from agentstack_sdk.server.context import RunContext +__all__ = [ + "AuthRequest", + "AuthResponse", + "OAuthDemand", + "OAuthExtensionClient", + "OAuthExtensionMetadata", + "OAuthExtensionParams", + "OAuthExtensionServer", + "OAuthExtensionSpec", + "OAuthFulfillment", +] + _DEFAULT_DEMAND_NAME = "default" @@ -143,7 +156,7 @@ def create_auth_request(self, *, authorization_endpoint_url: pydantic.AnyUrl): ) def parse_auth_response(self, *, message: A2AMessage): - if not message or not message.metadata or not (data := message.metadata.get(self.spec.URI)): + if not (data := MessageToDict(message.metadata).get(self.spec.URI)): raise RuntimeError("Invalid auth response") return AuthResponse.model_validate(data) @@ -153,7 +166,7 @@ def fulfillment_metadata(self, *, oauth_fulfillments: dict[str, Any]) -> dict[st return {self.spec.URI: OAuthExtensionMetadata(oauth_fulfillments=oauth_fulfillments).model_dump(mode="json")} def parse_auth_request(self, *, message: A2AMessage): - if not message or not message.metadata or not (data := message.metadata.get(self.spec.URI)): + if not (data := MessageToDict(message.metadata).get(self.spec.URI)): raise ValueError("Invalid auth request") return AuthRequest.model_validate(data) diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/auth/secrets/secrets.py b/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/auth/secrets/secrets.py index ff5ccca4f6..719b6e5873 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/auth/secrets/secrets.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/auth/secrets/secrets.py @@ -9,6 +9,7 @@ import pydantic from a2a.server.agent_execution.context import RequestContext from a2a.types import Message as A2AMessage +from google.protobuf.json_format import MessageToDict from opentelemetry import trace from typing_extensions import override @@ -32,6 +33,16 @@ if TYPE_CHECKING: from agentstack_sdk.server.context import RunContext +__all__ = [ + "SecretDemand", + "SecretFulfillment", + "SecretsExtensionClient", + "SecretsExtensionServer", + "SecretsExtensionSpec", + "SecretsServiceExtensionMetadata", + "SecretsServiceExtensionParams", +] + A2A_EXTENSION_SECRETS_REQUESTED = "a2a_extension.secrets.requested" A2A_EXTENSION_SECRETS_RESOLVED = "a2a_extension.secrets.resolved" @@ -74,7 +85,7 @@ def handle_incoming_message(self, message: A2AMessage, run_context: RunContext, self.context = run_context def parse_secret_response(self, message: A2AMessage) -> SecretsServiceExtensionMetadata: - if not message or not message.metadata or not (data := message.metadata.get(self.spec.URI)): + if not (data := MessageToDict(message.metadata).get(self.spec.URI)): raise ValueError("Secrets has not been provided in response.") return SecretsServiceExtensionMetadata.model_validate(data) diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/base.py b/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/base.py index 22f83a7852..b3af6e0848 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/base.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/base.py @@ -84,15 +84,12 @@ def __init__(self, params: ParamsT, required: bool = False) -> None: self.required = required @classmethod - def from_agent_card(cls: type["BaseExtensionSpec"], agent: AgentCard) -> typing.Self | None: + def from_agent_card(cls: type[typing.Self], agent: AgentCard) -> typing.Self | None: """ Client should construct an extension instance using this classmethod. """ if extensions := [x for x in agent.capabilities.extensions or [] if x.uri == cls.URI]: - return cls( - params=pydantic.TypeAdapter(cls.Params).validate_python(MessageToDict(extensions[0].params)), - required=extensions[0].required or False, - ) + return cls(params=pydantic.TypeAdapter(cls.Params).validate_python(MessageToDict(extensions[0].params))) return None def to_agent_card_extensions(self, *, required: bool | None = None) -> list[AgentExtension]: @@ -223,5 +220,7 @@ def parse_server_metadata(self, message: A2AMessage) -> MetadataFromServerT | No return ( None if not message.metadata or self.spec.URI not in message.metadata - else pydantic.TypeAdapter(self.MetadataFromServer).validate_python(message.metadata[self.spec.URI]) + else pydantic.TypeAdapter(self.MetadataFromServer).validate_python( + MessageToDict(message.metadata)[self.spec.URI] + ) ) diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/interactions/approval.py b/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/interactions/approval.py index e12187ba75..8764a3c4dd 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/interactions/approval.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/interactions/approval.py @@ -9,6 +9,7 @@ from typing import TYPE_CHECKING, Annotated, Any, Literal import a2a.types +from google.protobuf.json_format import MessageToDict from mcp import Implementation, Tool from opentelemetry import trace from pydantic import BaseModel, Discriminator, Field, TypeAdapter @@ -37,6 +38,20 @@ if TYPE_CHECKING: from agentstack_sdk.server.context import RunContext +__all__ = [ + "ApprovalExtensionClient", + "ApprovalExtensionMetadata", + "ApprovalExtensionParams", + "ApprovalExtensionServer", + "ApprovalExtensionSpec", + "ApprovalRejectionError", + "ApprovalRequest", + "ApprovalResponse", + "GenericApprovalRequest", + "ToolCallApprovalRequest", + "ToolCallServer", +] + A2A_EXTENSION_APPROVAL_REQUESTED = "a2a_extension.approval.requested" A2A_EXTENSION_APPROVAL_RESOLVED = "a2a_extension.approval.resolved" @@ -116,7 +131,7 @@ def create_request_message(self, *, request: ApprovalRequest): ) def parse_response(self, *, message: a2a.types.Message): - if not message.metadata or not (data := message.metadata.get(self.spec.URI)): + if not (data := MessageToDict(message.metadata).get(self.spec.URI)): raise ValueError("Approval response data is missing") return ApprovalResponse.model_validate(data) @@ -147,14 +162,14 @@ class ApprovalExtensionClient(BaseExtensionClient[ApprovalExtensionSpec, NoneTyp def create_response_message(self, *, response: ApprovalResponse, task_id: str | None): return a2a.types.Message( message_id=str(uuid.uuid4()), - role=a2a.types.Role.user, + role=a2a.types.Role.ROLE_USER, parts=[], task_id=task_id, metadata={self.spec.URI: response.model_dump(mode="json", context={REVEAL_SECRETS: True})}, ) def parse_request(self, *, message: a2a.types.Message): - if not message.metadata or not (data := message.metadata.get(self.spec.URI)): + if not (data := MessageToDict(message.metadata).get(self.spec.URI)): raise ValueError("Approval request data is missing") return TypeAdapter(ApprovalRequest).validate_python(data) diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/services/embedding.py b/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/services/embedding.py index f154d1e327..94b55298b0 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/services/embedding.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/services/embedding.py @@ -29,6 +29,16 @@ if TYPE_CHECKING: from agentstack_sdk.server.context import RunContext +__all__ = [ + "EmbeddingDemand", + "EmbeddingFulfillment", + "EmbeddingServiceExtensionClient", + "EmbeddingServiceExtensionMetadata", + "EmbeddingServiceExtensionParams", + "EmbeddingServiceExtensionServer", + "EmbeddingServiceExtensionSpec", +] + class EmbeddingFulfillment(SecureBaseModel): identifier: str | None = None diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/services/llm.py b/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/services/llm.py index f397278042..877d4407b0 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/services/llm.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/services/llm.py @@ -29,6 +29,16 @@ if TYPE_CHECKING: from agentstack_sdk.server.context import RunContext +__all__ = [ + "LLMDemand", + "LLMFulfillment", + "LLMServiceExtensionClient", + "LLMServiceExtensionMetadata", + "LLMServiceExtensionParams", + "LLMServiceExtensionServer", + "LLMServiceExtensionSpec", +] + class LLMFulfillment(SecureBaseModel): identifier: str | None = None diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/services/mcp.py b/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/services/mcp.py index c4e713536d..13c2d8b2a2 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/services/mcp.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/services/mcp.py @@ -40,6 +40,19 @@ if TYPE_CHECKING: from agentstack_sdk.server.context import RunContext +__all__ = [ + "MCPDemand", + "MCPFulfillment", + "MCPServiceExtensionClient", + "MCPServiceExtensionMetadata", + "MCPServiceExtensionParams", + "MCPServiceExtensionServer", + "MCPServiceExtensionSpec", + "MCPTransport", + "StdioTransport", + "StreamableHTTPTransport", +] + _TRANSPORT_TYPES = Literal["streamable_http", "stdio"] _DEFAULT_DEMAND_NAME = "default" diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/services/platform.py b/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/services/platform.py index c7c5e6b36a..ec1e79c44b 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/services/platform.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/services/platform.py @@ -40,6 +40,15 @@ if TYPE_CHECKING: from agentstack_sdk.server.context import RunContext +__all__ = [ + "PlatformApiExtension", + "PlatformApiExtensionClient", + "PlatformApiExtensionMetadata", + "PlatformApiExtensionParams", + "PlatformApiExtensionServer", + "PlatformApiExtensionSpec", +] + class PlatformApiExtensionMetadata(SecureBaseModel): base_url: HttpUrl | None = None diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/tools/call.py b/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/tools/call.py index e21c75699d..c6dc29b034 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/tools/call.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/tools/call.py @@ -9,6 +9,7 @@ from typing import TYPE_CHECKING, Any, Literal import a2a.types +from google.protobuf.json_format import MessageToDict from mcp import Tool from mcp.types import Implementation from pydantic import BaseModel, Field @@ -32,6 +33,17 @@ if TYPE_CHECKING: from agentstack_sdk.server.context import RunContext +__all__ = [ + "ToolCallExtensionClient", + "ToolCallExtensionMetadata", + "ToolCallExtensionParams", + "ToolCallExtensionServer", + "ToolCallExtensionSpec", + "ToolCallRequest", + "ToolCallResponse", + "ToolCallServer", +] + class ToolCallServer(BaseModel): name: str = Field(description="The programmatic name of the server.") @@ -85,7 +97,7 @@ def create_request_message(self, *, request: ToolCallRequest): ) def parse_response(self, *, message: a2a.types.Message): - if not message or not message.metadata or not (data := message.metadata.get(self.spec.URI)): + if not (data := MessageToDict(message.metadata).get(self.spec.URI)): raise RuntimeError("Invalid mcp response") return ToolCallResponse.model_validate(data) @@ -113,14 +125,14 @@ class ToolCallExtensionClient(BaseExtensionClient[ToolCallExtensionSpec, NoneTyp def create_response_message(self, *, response: ToolCallResponse, task_id: str | None): return a2a.types.Message( message_id=str(uuid.uuid4()), - role=a2a.types.Role.user, + role=a2a.types.Role.ROLE_USER, parts=[], task_id=task_id, metadata={self.spec.URI: response.model_dump(mode="json", context={REVEAL_SECRETS: True})}, ) def parse_request(self, *, message: a2a.types.Message): - if not message or not message.metadata or not (data := message.metadata.get(self.spec.URI)): + if not (data := MessageToDict(message.metadata).get(self.spec.URI)): raise ValueError("Invalid tool call request") return ToolCallRequest.model_validate(data) diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/ui/canvas.py b/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/ui/canvas.py index 5b23731d39..3e98de0cec 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/ui/canvas.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/ui/canvas.py @@ -10,12 +10,19 @@ from a2a.server.agent_execution.context import RequestContext from a2a.types import Artifact from a2a.types import Message as A2AMessage -from google.protobuf.json_format import ParseDict +from google.protobuf.json_format import MessageToDict, ParseDict from typing_extensions import override if TYPE_CHECKING: from agentstack_sdk.server.context import RunContext +__all__ = [ + "CanvasEditRequest", + "CanvasEditRequestMetadata", + "CanvasExtensionServer", + "CanvasExtensionSpec", +] + from agentstack_sdk.a2a.extensions.base import ( BaseExtensionServer, NoParamsBaseExtensionSpec, @@ -58,14 +65,14 @@ class CanvasExtensionServer(BaseExtensionServer[CanvasExtensionSpec, CanvasEditR @override def handle_incoming_message(self, message: A2AMessage, run_context: RunContext, request_context: RequestContext): if message.metadata and self.spec.URI in message.metadata and message.parts: - message.parts.clear() - message.parts.extend([part for part in message.parts if "text" not in part]) + message.parts.clear() # pyrefly: ignore[missing-attribute] + message.parts.extend([part for part in message.parts if not part.HasField("text")]) super().handle_incoming_message(message, run_context, request_context) self.context = run_context async def parse_canvas_edit_request(self, *, message: A2AMessage) -> CanvasEditRequest | None: - if not message or not message.metadata or not (data := message.metadata.get(self.spec.URI)): + if not (data := MessageToDict(message.metadata).get(self.spec.URI)): return None metadata = CanvasEditRequestMetadata.model_validate(data) diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/ui/citation.py b/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/ui/citation.py index 0ca321b0dc..59efecf424 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/ui/citation.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/ui/citation.py @@ -7,7 +7,7 @@ from types import NoneType import pydantic -from a2a.types import Part, Message +from a2a.types import Message, Part from agentstack_sdk.a2a.extensions.base import ( BaseExtensionClient, diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/ui/form_request.py b/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/ui/form_request.py index 776c3bc30d..c9da9837fe 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/ui/form_request.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/ui/form_request.py @@ -28,6 +28,12 @@ if TYPE_CHECKING: from agentstack_sdk.server.context import RunContext +__all__ = [ + "FormRequestExtensionClient", + "FormRequestExtensionServer", + "FormRequestExtensionSpec", +] + T = TypeVar("T") @@ -47,7 +53,7 @@ async def request_form(self, *, form: FormRender, model: None = None) -> FormRes async def request_form(self, *, form: FormRender, model: type[T]) -> T | None: ... async def request_form(self, *, form: FormRender, model: type[T] | None = None) -> T | FormResponse | None: message = await self.context.yield_async( - InputRequired(message=AgentMessage(text=form.title, metadata={self.spec.URI: form})) + InputRequired(message=AgentMessage(text=form.title, metadata={self.spec.URI: form.model_dump()})) ) return self.parse_form_response(message=message, model=model or FormResponse) if message else None diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/ui/trajectory.py b/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/ui/trajectory.py index eaf8b7c321..485fbfd65e 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/ui/trajectory.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/a2a/extensions/ui/trajectory.py @@ -7,7 +7,7 @@ from types import NoneType import pydantic -from a2a.types import Part, Message +from a2a.types import Message, Part from agentstack_sdk.a2a.extensions.base import ( BaseExtensionClient, diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/platform/file.py b/apps/agentstack-sdk-py/src/agentstack_sdk/platform/file.py index c5288f5a79..43a77ce6ac 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/platform/file.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/platform/file.py @@ -257,7 +257,7 @@ async def delete_extraction( ) ).raise_for_status() - def to_file_part(self: File) -> Part: + def to_part(self: File) -> Part: return Part(filename=self.filename, url=f"agentstack://{self.id}") @staticmethod diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/platform/provider.py b/apps/agentstack-sdk-py/src/agentstack_sdk/platform/provider.py index 0f48e2eaf9..2e1696a7ed 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/platform/provider.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/platform/provider.py @@ -38,7 +38,6 @@ class VersionInfo(pydantic.BaseModel): class Provider(pydantic.BaseModel, arbitrary_types_allowed=True): - model_config = pydantic.ConfigDict(arbitrary_types_allowed=True) id: str auto_stop_timeout: timedelta source: str diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/platform/provider_discovery.py b/apps/agentstack-sdk-py/src/agentstack_sdk/platform/provider_discovery.py index 8416d7ee6f..b51d369348 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/platform/provider_discovery.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/platform/provider_discovery.py @@ -34,7 +34,7 @@ class ProviderDiscovery(pydantic.BaseModel, arbitrary_types_allowed=True): @classmethod def parse_card(cls: Self, value: dict[str, Any] | None) -> AgentCard | None: if value is not None: - return ParseDict(value, AgentCard(skip_verify=True)) + return ParseDict(value, AgentCard()) return None @staticmethod diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/server/agent.py b/apps/agentstack-sdk-py/src/agentstack_sdk/server/agent.py index 7d337d477a..953b8c3f69 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/server/agent.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/server/agent.py @@ -152,7 +152,8 @@ def initialize( self._card.supported_interfaces.extend(supported_interfaces) if a2a_security: self._card.security_requirements.extend(a2a_security["security_requirements"]) - self._card.security_schemes.update(a2a_security["security_schemes"]) + for security_key, security_value in a2a_security["security_schemes"].items(): + self._card.security_schemes[security_key].CopyFrom(security_value) @property def card(self) -> AgentCard: @@ -246,34 +247,23 @@ def agent( capabilities = AgentCapabilities(streaming=True) def decorator(fn: OriginalFnType) -> Agent: - signature = inspect.signature(fn) - dependencies = extract_dependencies(signature) + dependencies = extract_dependencies(fn) resolved_name = name or fn.__name__ resolved_description = description or fn.__doc__ or "Description not provided" - # Check if user has provided an ErrorExtensionServer, if not add default - has_error_extension = any(isinstance(ext, ErrorExtensionServer) for ext in sdk_extensions) - error_extension_spec = ErrorExtensionSpec(ErrorExtensionParams()) if not has_error_extension else None + final_detail = detail or AgentDetail() - if detail: - if detail.tools is None and skills: - detail.tools = [ - AgentDetailTool(name=skill.name, description=skill.description or "") for skill in skills - ] + if final_detail.tools is None and skills: + final_detail.tools = [ + AgentDetailTool(name=skill.name, description=skill.description or "") for skill in skills + ] - if detail.user_greeting is None: - detail.user_greeting = resolved_description + if final_detail.user_greeting is None: + final_detail.user_greeting = resolved_description - if detail.input_placeholder is None: - detail.input_placeholder = "What is your task?" - - capabilities.extensions = [ - *(capabilities.extensions or []), - *(AgentDetailExtensionSpec(detail).to_agent_card_extensions()), - *(error_extension_spec.to_agent_card_extensions() if error_extension_spec else []), - *(e_card for ext in sdk_extensions for e_card in ext.spec.to_agent_card_extensions()), - ] + if final_detail.input_placeholder is None: + final_detail.input_placeholder = "What is your task?" card = AgentCard( name=resolved_name, @@ -350,7 +340,7 @@ async def execute_fn(_ctx: RunContext, *args, **kwargs) -> None: return Agent( initial_card=card, - detail=detail or AgentDetail(), + detail=final_detail, dependency_args=dependencies, execute_fn=execute_fn, ) diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/server/middleware/platform_auth_backend.py b/apps/agentstack-sdk-py/src/agentstack_sdk/server/middleware/platform_auth_backend.py index bb3fb56857..deff917554 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/server/middleware/platform_auth_backend.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/server/middleware/platform_auth_backend.py @@ -106,12 +106,21 @@ async def authenticate(self, conn: HTTPConnection) -> tuple[AuthCredentials, Bas else: audiences = [str(request.url.replace(path=path)) for path in ["/", "/jsonrpc"]] + # all variants with and without ending slash are valid + audiences = list( + { + *(aud.rstrip("/") for aud in audiences), + *(aud + "/" for aud in audiences if not aud.endswith("/")), + } + ) + + claims: JWTClaims | None = None try: # check only hostname urljoin("http://host:port/a/b", "/") -> "http://host:port/" jwks = await discover_jwks() # Verify signature - claims: JWTClaims = jwt.decode( + claims = jwt.decode( auth.credentials, jwks, claims_options={ @@ -126,6 +135,8 @@ async def authenticate(self, conn: HTTPConnection) -> tuple[AuthCredentials, Bas return AuthCredentials(["authenticated"]), PlatformAuthenticatedUser(claims, auth.credentials) except (ValueError, JoseError) as e: + if "aud" in str(e) and claims: + logger.warning(f"Invalid audience: {claims.get('aud')}, expected: {audiences}") logger.warning(f"Authentication failed: {e}") raise AuthenticationError("Invalid token") from e except Exception as e: diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/server/server.py b/apps/agentstack-sdk-py/src/agentstack_sdk/server/server.py index bca05cfa17..22edf5236e 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/server/server.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/server/server.py @@ -24,6 +24,7 @@ from fastapi import FastAPI from fastapi.applications import AppType from fastapi.responses import PlainTextResponse +from google.protobuf.json_format import MessageToDict from httpx import HTTPError, HTTPStatusError from starlette.authentication import AuthenticationError from starlette.middleware.authentication import AuthenticationMiddleware @@ -293,7 +294,10 @@ def _production_mode(self) -> bool: async def _reload_variables_periodically(self): while True: await asyncio.sleep(5) - await self._load_variables() + try: + await self._load_variables() + except Exception as e: + logger.error(f"Failed to reload variables: {e}") async def _load_variables(self, first_run: bool = False) -> None: from agentstack_sdk.a2a.extensions import AgentDetail, AgentDetailExtensionSpec @@ -319,7 +323,7 @@ async def _load_variables(self, first_run: bool = False) -> None: for extension in self._agent.card.capabilities.extensions or []: match extension: case AgentExtension(uri=AgentDetailExtensionSpec.URI, params=params): - variables = AgentDetail.model_validate(params).variables or [] + variables = AgentDetail.model_validate(MessageToDict(params)).variables or [] if missing_keys := [env for env in variables if env.required and os.getenv(env.name) is None]: logger.warning( f"Missing required env variables: {missing_keys}, " diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/util/file.py b/apps/agentstack-sdk-py/src/agentstack_sdk/util/file.py index 0e257abede..24e4595dbb 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/util/file.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/util/file.py @@ -258,7 +258,7 @@ async def load_file( await file.aread() yield file - elif "raw" in part: # pyrefly: ignore [not-iterable] + elif part.HasField("raw"): yield LoadedFileWithBytes(content=part.raw, filename=part.filename, content_type=part.media_type) else: raise ValueError("Part must have either url or raw set to be loaded as a file.") diff --git a/apps/agentstack-sdk-py/tests/e2e/conftest.py b/apps/agentstack-sdk-py/tests/e2e/conftest.py index 71882bc17d..e530e2ca34 100644 --- a/apps/agentstack-sdk-py/tests/e2e/conftest.py +++ b/apps/agentstack-sdk-py/tests/e2e/conftest.py @@ -1,14 +1,12 @@ # Copyright 2025 © BeeAI a Series of LF Projects, LLC # SPDX-License-Identifier: Apache-2.0 -from ddgs.cli import cli -from typing import AsyncIterator from __future__ import annotations import asyncio import base64 import socket -from collections.abc import AsyncGenerator +from collections.abc import AsyncGenerator, AsyncIterator from contextlib import asynccontextmanager, closing from datetime import timedelta diff --git a/apps/agentstack-sdk-py/tests/unit/a2a/test_types.py b/apps/agentstack-sdk-py/tests/unit/a2a/test_types.py index bae1919bc2..9b241d4836 100644 --- a/apps/agentstack-sdk-py/tests/unit/a2a/test_types.py +++ b/apps/agentstack-sdk-py/tests/unit/a2a/test_types.py @@ -1,3 +1,6 @@ +# Copyright 2026 © BeeAI a Series of LF Projects, LLC +# SPDX-License-Identifier: Apache-2.0 + import uuid import pytest @@ -92,7 +95,7 @@ def test_task_status_validation(): # TaskStatus requires state # 1. Valid - ts = TaskStatus(state=TaskState.TASK_STATE_WORKING) + _ = TaskStatus(state=TaskState.TASK_STATE_WORKING) # 2. Missing state (it's an enum, default is 0 which is UNSPECIFIED) with pytest.raises(ValueError, match="state is required"): diff --git a/apps/agentstack-sdk-py/tests/unit/test_agent_detail_population.py b/apps/agentstack-sdk-py/tests/unit/test_agent_detail_population.py index 37b8c3fb84..c8ad9e2fac 100644 --- a/apps/agentstack-sdk-py/tests/unit/test_agent_detail_population.py +++ b/apps/agentstack-sdk-py/tests/unit/test_agent_detail_population.py @@ -4,7 +4,7 @@ from __future__ import annotations import pytest -from a2a.types import AgentSkill +from a2a.types import AgentSkill, AgentInterface from agentstack_sdk.a2a.extensions.ui.agent_detail import AgentDetailExtensionSpec from agentstack_sdk.server.agent import agent @@ -26,11 +26,9 @@ def test_agent_detail_population(): def test_agent_fn(): pass - def mock_modify_dependencies(deps): - pass - # test_agent_fn is now the agent_factory - agent_instance = test_agent_fn(mock_modify_dependencies) + agent_instance = test_agent_fn + agent_instance.initialize(supported_interfaces=[AgentInterface()]) extensions = agent_instance.card.capabilities.extensions assert extensions is not None @@ -77,10 +75,8 @@ def test_agent_detail_population_override(): def test_agent_fn(): pass - def mock_modify_dependencies(deps): - pass - - agent_instance = test_agent_fn(mock_modify_dependencies) + agent_instance = test_agent_fn + agent_instance.initialize(supported_interfaces=[AgentInterface()]) extensions = agent_instance.card.capabilities.extensions assert extensions @@ -123,10 +119,8 @@ def test_agent_detail_explicit_empty_values(): def test_agent_fn(): pass - def mock_modify_dependencies(deps): - pass - - agent_instance = test_agent_fn(mock_modify_dependencies) + agent_instance = test_agent_fn + agent_instance.initialize(supported_interfaces=[AgentInterface()]) extensions = agent_instance.card.capabilities.extensions detail_extension = next((ext for ext in extensions if ext.uri == AgentDetailExtensionSpec.URI), None) diff --git a/apps/agentstack-sdk-py/uv.lock b/apps/agentstack-sdk-py/uv.lock index fa9d8a0fed..3e49156b33 100644 --- a/apps/agentstack-sdk-py/uv.lock +++ b/apps/agentstack-sdk-py/uv.lock @@ -312,7 +312,7 @@ wheels = [ [[package]] name = "beeai-framework" -version = "0.1.77" +version = "0.1.78" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiofiles" }, @@ -326,9 +326,9 @@ dependencies = [ { name = "pydantic-settings" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d4/b5/c2fd0b8154a99cc30066d54143ccd0e53792f47a09fa9905a1e0760c15ef/beeai_framework-0.1.77.tar.gz", hash = "sha256:3c7db852fa2d62ef4100fc65b685417e8362e60a9a7127d7a12b0432c05cc77e", size = 198879, upload-time = "2026-02-11T14:09:09.152Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c4/da/646ecb929e6e47e072e05a0b30b1da5adb369a37cebe0c03958ad2b34f42/beeai_framework-0.1.78.tar.gz", hash = "sha256:5e696705def4b5205da179488b66db306466dc1cfdcf2bcac928a320000d84ad", size = 199187, upload-time = "2026-02-26T12:25:38.671Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/72/73/a904622564667429b0c2c44eac85186583845357aab18737c3114331aff4/beeai_framework-0.1.77-py3-none-any.whl", hash = "sha256:f8bbf792d2856d39f8809a6254e1635ff3a61f7492c9ea3671f38829f4b71aca", size = 360523, upload-time = "2026-02-11T14:09:07.476Z" }, + { url = "https://files.pythonhosted.org/packages/ab/9d/380212575e02d8a3bf9090290e6a770833e33e7aecdccfab2592ec6af80d/beeai_framework-0.1.78-py3-none-any.whl", hash = "sha256:8575c34a3ffdca75438ed5ef8e3a7c719fe9db94c4ec1bde49a883352cd4415d", size = 360652, upload-time = "2026-02-26T12:25:37.308Z" }, ] [package.optional-dependencies] @@ -418,11 +418,11 @@ wheels = [ [[package]] name = "certifi" -version = "2026.1.4" +version = "2026.2.25" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e0/2d/a891ca51311197f6ad14a7ef42e2399f36cf2f9bd44752b3dc4eab60fdc5/certifi-2026.1.4.tar.gz", hash = "sha256:ac726dd470482006e014ad384921ed6438c457018f4b3d204aea4281258b2120", size = 154268, upload-time = "2026-01-04T02:42:41.825Z" } +sdist = { url = "https://files.pythonhosted.org/packages/af/2d/7bf41579a8986e348fa033a31cdd0e4121114f6bce2457e8876010b092dd/certifi-2026.2.25.tar.gz", hash = "sha256:e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7", size = 155029, upload-time = "2026-02-25T02:54:17.342Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c", size = 152900, upload-time = "2026-01-04T02:42:40.15Z" }, + { url = "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl", hash = "sha256:027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa", size = 153684, upload-time = "2026-02-25T02:54:15.766Z" }, ] [[package]] @@ -705,7 +705,7 @@ wheels = [ [[package]] name = "fastapi" -version = "0.131.0" +version = "0.133.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "annotated-doc" }, @@ -714,9 +714,9 @@ dependencies = [ { name = "typing-extensions" }, { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/91/32/158cbf685b7d5a26f87131069da286bf10fc9fbf7fc968d169d48a45d689/fastapi-0.131.0.tar.gz", hash = "sha256:6531155e52bee2899a932c746c9a8250f210e3c3303a5f7b9f8a808bfe0548ff", size = 369612, upload-time = "2026-02-22T16:38:11.252Z" } +sdist = { url = "https://files.pythonhosted.org/packages/22/6f/0eafed8349eea1fa462238b54a624c8b408cd1ba2795c8e64aa6c34f8ab7/fastapi-0.133.1.tar.gz", hash = "sha256:ed152a45912f102592976fde6cbce7dae1a8a1053da94202e51dd35d184fadd6", size = 378741, upload-time = "2026-02-25T18:18:17.398Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ff/94/b58ec24c321acc2ad1327f69b033cadc005e0f26df9a73828c9e9c7db7ce/fastapi-0.131.0-py3-none-any.whl", hash = "sha256:ed0e53decccf4459de78837ce1b867cd04fa9ce4579497b842579755d20b405a", size = 103854, upload-time = "2026-02-22T16:38:09.814Z" }, + { url = "https://files.pythonhosted.org/packages/d2/c9/a175a7779f3599dfa4adfc97a6ce0e157237b3d7941538604aadaf97bfb6/fastapi-0.133.1-py3-none-any.whl", hash = "sha256:658f34ba334605b1617a65adf2ea6461901bdb9af3a3080d63ff791ecf7dc2e2", size = 109029, upload-time = "2026-02-25T18:18:18.578Z" }, ] [[package]] @@ -960,31 +960,34 @@ wheels = [ [[package]] name = "hf-xet" -version = "1.2.0" +version = "1.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5e/6e/0f11bacf08a67f7fb5ee09740f2ca54163863b07b70d579356e9222ce5d8/hf_xet-1.2.0.tar.gz", hash = "sha256:a8c27070ca547293b6890c4bf389f713f80e8c478631432962bb7f4bc0bd7d7f", size = 506020, upload-time = "2025-10-24T19:04:32.129Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/a5/85ef910a0aa034a2abcfadc360ab5ac6f6bc4e9112349bd40ca97551cff0/hf_xet-1.2.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:ceeefcd1b7aed4956ae8499e2199607765fbd1c60510752003b6cc0b8413b649", size = 2861870, upload-time = "2025-10-24T19:04:11.422Z" }, - { url = "https://files.pythonhosted.org/packages/ea/40/e2e0a7eb9a51fe8828ba2d47fe22a7e74914ea8a0db68a18c3aa7449c767/hf_xet-1.2.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b70218dd548e9840224df5638fdc94bd033552963cfa97f9170829381179c813", size = 2717584, upload-time = "2025-10-24T19:04:09.586Z" }, - { url = "https://files.pythonhosted.org/packages/a5/7d/daf7f8bc4594fdd59a8a596f9e3886133fdc68e675292218a5e4c1b7e834/hf_xet-1.2.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d40b18769bb9a8bc82a9ede575ce1a44c75eb80e7375a01d76259089529b5dc", size = 3315004, upload-time = "2025-10-24T19:04:00.314Z" }, - { url = "https://files.pythonhosted.org/packages/b1/ba/45ea2f605fbf6d81c8b21e4d970b168b18a53515923010c312c06cd83164/hf_xet-1.2.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:cd3a6027d59cfb60177c12d6424e31f4b5ff13d8e3a1247b3a584bf8977e6df5", size = 3222636, upload-time = "2025-10-24T19:03:58.111Z" }, - { url = "https://files.pythonhosted.org/packages/4a/1d/04513e3cab8f29ab8c109d309ddd21a2705afab9d52f2ba1151e0c14f086/hf_xet-1.2.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6de1fc44f58f6dd937956c8d304d8c2dea264c80680bcfa61ca4a15e7b76780f", size = 3408448, upload-time = "2025-10-24T19:04:20.951Z" }, - { url = "https://files.pythonhosted.org/packages/f0/7c/60a2756d7feec7387db3a1176c632357632fbe7849fce576c5559d4520c7/hf_xet-1.2.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f182f264ed2acd566c514e45da9f2119110e48a87a327ca271027904c70c5832", size = 3503401, upload-time = "2025-10-24T19:04:22.549Z" }, - { url = "https://files.pythonhosted.org/packages/4e/64/48fffbd67fb418ab07451e4ce641a70de1c40c10a13e25325e24858ebe5a/hf_xet-1.2.0-cp313-cp313t-win_amd64.whl", hash = "sha256:293a7a3787e5c95d7be1857358a9130694a9c6021de3f27fa233f37267174382", size = 2900866, upload-time = "2025-10-24T19:04:33.461Z" }, - { url = "https://files.pythonhosted.org/packages/e2/51/f7e2caae42f80af886db414d4e9885fac959330509089f97cccb339c6b87/hf_xet-1.2.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:10bfab528b968c70e062607f663e21e34e2bba349e8038db546646875495179e", size = 2861861, upload-time = "2025-10-24T19:04:19.01Z" }, - { url = "https://files.pythonhosted.org/packages/6e/1d/a641a88b69994f9371bd347f1dd35e5d1e2e2460a2e350c8d5165fc62005/hf_xet-1.2.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2a212e842647b02eb6a911187dc878e79c4aa0aa397e88dd3b26761676e8c1f8", size = 2717699, upload-time = "2025-10-24T19:04:17.306Z" }, - { url = "https://files.pythonhosted.org/packages/df/e0/e5e9bba7d15f0318955f7ec3f4af13f92e773fbb368c0b8008a5acbcb12f/hf_xet-1.2.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:30e06daccb3a7d4c065f34fc26c14c74f4653069bb2b194e7f18f17cbe9939c0", size = 3314885, upload-time = "2025-10-24T19:04:07.642Z" }, - { url = "https://files.pythonhosted.org/packages/21/90/b7fe5ff6f2b7b8cbdf1bd56145f863c90a5807d9758a549bf3d916aa4dec/hf_xet-1.2.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:29c8fc913a529ec0a91867ce3d119ac1aac966e098cf49501800c870328cc090", size = 3221550, upload-time = "2025-10-24T19:04:05.55Z" }, - { url = "https://files.pythonhosted.org/packages/6f/cb/73f276f0a7ce46cc6a6ec7d6c7d61cbfe5f2e107123d9bbd0193c355f106/hf_xet-1.2.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e159cbfcfbb29f920db2c09ed8b660eb894640d284f102ada929b6e3dc410a", size = 3408010, upload-time = "2025-10-24T19:04:28.598Z" }, - { url = "https://files.pythonhosted.org/packages/b8/1e/d642a12caa78171f4be64f7cd9c40e3ca5279d055d0873188a58c0f5fbb9/hf_xet-1.2.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9c91d5ae931510107f148874e9e2de8a16052b6f1b3ca3c1b12f15ccb491390f", size = 3503264, upload-time = "2025-10-24T19:04:30.397Z" }, - { url = "https://files.pythonhosted.org/packages/17/b5/33764714923fa1ff922770f7ed18c2daae034d21ae6e10dbf4347c854154/hf_xet-1.2.0-cp314-cp314t-win_amd64.whl", hash = "sha256:210d577732b519ac6ede149d2f2f34049d44e8622bf14eb3d63bbcd2d4b332dc", size = 2901071, upload-time = "2025-10-24T19:04:37.463Z" }, - { url = "https://files.pythonhosted.org/packages/96/2d/22338486473df5923a9ab7107d375dbef9173c338ebef5098ef593d2b560/hf_xet-1.2.0-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:46740d4ac024a7ca9b22bebf77460ff43332868b661186a8e46c227fdae01848", size = 2866099, upload-time = "2025-10-24T19:04:15.366Z" }, - { url = "https://files.pythonhosted.org/packages/7f/8c/c5becfa53234299bc2210ba314eaaae36c2875e0045809b82e40a9544f0c/hf_xet-1.2.0-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:27df617a076420d8845bea087f59303da8be17ed7ec0cd7ee3b9b9f579dff0e4", size = 2722178, upload-time = "2025-10-24T19:04:13.695Z" }, - { url = "https://files.pythonhosted.org/packages/9a/92/cf3ab0b652b082e66876d08da57fcc6fa2f0e6c70dfbbafbd470bb73eb47/hf_xet-1.2.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3651fd5bfe0281951b988c0facbe726aa5e347b103a675f49a3fa8144c7968fd", size = 3320214, upload-time = "2025-10-24T19:04:03.596Z" }, - { url = "https://files.pythonhosted.org/packages/46/92/3f7ec4a1b6a65bf45b059b6d4a5d38988f63e193056de2f420137e3c3244/hf_xet-1.2.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d06fa97c8562fb3ee7a378dd9b51e343bc5bc8190254202c9771029152f5e08c", size = 3229054, upload-time = "2025-10-24T19:04:01.949Z" }, - { url = "https://files.pythonhosted.org/packages/0b/dd/7ac658d54b9fb7999a0ccb07ad863b413cbaf5cf172f48ebcd9497ec7263/hf_xet-1.2.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:4c1428c9ae73ec0939410ec73023c4f842927f39db09b063b9482dac5a3bb737", size = 3413812, upload-time = "2025-10-24T19:04:24.585Z" }, - { url = "https://files.pythonhosted.org/packages/92/68/89ac4e5b12a9ff6286a12174c8538a5930e2ed662091dd2572bbe0a18c8a/hf_xet-1.2.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a55558084c16b09b5ed32ab9ed38421e2d87cf3f1f89815764d1177081b99865", size = 3508920, upload-time = "2025-10-24T19:04:26.927Z" }, - { url = "https://files.pythonhosted.org/packages/cb/44/870d44b30e1dcfb6a65932e3e1506c103a8a5aea9103c337e7a53180322c/hf_xet-1.2.0-cp37-abi3-win_amd64.whl", hash = "sha256:e6584a52253f72c9f52f9e549d5895ca7a471608495c4ecaa6cc73dba2b24d69", size = 2905735, upload-time = "2025-10-24T19:04:35.928Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/a6/d0/73454ef7ca885598a3194d07d5c517d91a840753c5b35d272600d7907f64/hf_xet-1.3.1.tar.gz", hash = "sha256:513aa75f8dc39a63cc44dbc8d635ccf6b449e07cdbd8b2e2d006320d2e4be9bb", size = 641393, upload-time = "2026-02-25T00:57:56.701Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/56/79/9b6a5614230d7a871442d8d8e1c270496821638ba3a9baac16a5b9166200/hf_xet-1.3.1-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:08b231260c68172c866f7aa7257c165d0c87887491aafc5efeee782731725366", size = 3759716, upload-time = "2026-02-25T00:57:41.052Z" }, + { url = "https://files.pythonhosted.org/packages/d4/de/72acb8d7702b3cf9b36a68e8380f3114bf04f9f21cf9e25317457fe31f00/hf_xet-1.3.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:0810b69c64e96dee849036193848007f665dca2311879c9ea8693f4fc37f1795", size = 3518075, upload-time = "2026-02-25T00:57:39.605Z" }, + { url = "https://files.pythonhosted.org/packages/1d/5c/ed728d8530fec28da88ee882b522fccf00dc98e9d7bae4cdb0493070cb17/hf_xet-1.3.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ecd38f98e7f0f41108e30fd4a9a5553ec30cf726df7473dd3e75a1b6d56728c2", size = 4174369, upload-time = "2026-02-25T00:57:32.697Z" }, + { url = "https://files.pythonhosted.org/packages/3c/db/785a0e20aa3086948a26573f1d4ff5c090e63564bf0a52d32eb5b4d82e8d/hf_xet-1.3.1-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:65411867d46700765018b1990eb1604c3bf0bf576d9e65fc57fdcc10797a2eb9", size = 3953249, upload-time = "2026-02-25T00:57:30.096Z" }, + { url = "https://files.pythonhosted.org/packages/c4/6a/51b669c1e3dbd9374b61356f554e8726b9e1c1d6a7bee5d727d3913b10ad/hf_xet-1.3.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:1684c840c60da12d76c2a031ba40e4b154fdbf9593836fcf5ff090d95a033c61", size = 4152989, upload-time = "2026-02-25T00:57:48.308Z" }, + { url = "https://files.pythonhosted.org/packages/df/31/de07e26e396f46d13a09251df69df9444190e93e06a9d30d639e96c8a0ed/hf_xet-1.3.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:b3012c0f2ce1f0863338491a2bc0fd3f84aded0e147ab25f230da1f5249547fd", size = 4390709, upload-time = "2026-02-25T00:57:49.845Z" }, + { url = "https://files.pythonhosted.org/packages/e3/c1/fcb010b54488c2c112224f55b71f80e44d1706d9b764a0966310b283f86e/hf_xet-1.3.1-cp313-cp313t-win_amd64.whl", hash = "sha256:4eb432e1aa707a65a7e1f8455e40c5b47431d44fe0fb1b0c5d53848c27469398", size = 3634142, upload-time = "2026-02-25T00:57:59.063Z" }, + { url = "https://files.pythonhosted.org/packages/da/a6/9ef49cc601c68209979661b3e0b6659fc5a47bfb40f3ebf29eae9ee09e5c/hf_xet-1.3.1-cp313-cp313t-win_arm64.whl", hash = "sha256:e56104c84b2a88b9c7b23ba11a2d7ed0ccbe96886b3f985a50cedd2f0e99853f", size = 3494918, upload-time = "2026-02-25T00:57:57.654Z" }, + { url = "https://files.pythonhosted.org/packages/e7/f5/66adbb1f54a1b3c6da002fa36d4405901ddbcb7d927d780db17ce18ab99d/hf_xet-1.3.1-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:6517a245e41df3eae5adc5f9e8c86fa52abd548de798cbcd989f0082152860aa", size = 3759781, upload-time = "2026-02-25T00:57:47.017Z" }, + { url = "https://files.pythonhosted.org/packages/1e/75/189d91a90480c142cc710c1baa35ece20e8652d5fe5c9b2364a13573d827/hf_xet-1.3.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:4a322d506c513f98fdc1aa2aaa825daefd535b686e80ca789e6d33fcb146f524", size = 3517533, upload-time = "2026-02-25T00:57:45.812Z" }, + { url = "https://files.pythonhosted.org/packages/c6/52/52dd1ab6c29661e29585f3c10d14572e2535a3a472f27a0a46215b0f4659/hf_xet-1.3.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8f16ec9d26badec46334a798e01b5d86af536924789c95b1a1ec6a05f26523e0", size = 4174082, upload-time = "2026-02-25T00:57:38.171Z" }, + { url = "https://files.pythonhosted.org/packages/14/03/460add181c79e2ea1527d2ad27788ecccaee1d5a82563f9402e25ee627e4/hf_xet-1.3.1-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:e1f5d72bd5b73e61530fff573bcff34bdb64af2bf4862cdd516e6c1dab4dc75b", size = 3952874, upload-time = "2026-02-25T00:57:36.942Z" }, + { url = "https://files.pythonhosted.org/packages/01/56/bf78f18890dfc8caa907830e95424dce0887d5c45efde13f23c9ebbaa8ef/hf_xet-1.3.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:4bc71afd853508b2ddf123b8fc9de71b0afa4c956ec730b69fb76103781e94cd", size = 4152325, upload-time = "2026-02-25T00:57:54.081Z" }, + { url = "https://files.pythonhosted.org/packages/3c/94/91685c6a4a7f513097a6a73b1e879024304cd0eae78080e3d737622f2fd9/hf_xet-1.3.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:541b4b00ed294ae6cfd9416de9506e58971013714d7316189c9638ed54e362d4", size = 4390499, upload-time = "2026-02-25T00:57:55.258Z" }, + { url = "https://files.pythonhosted.org/packages/79/1b/1e72c8ea1f31ef94640d1f265630d35b97b2ef31fe12696bbcc32dbcdc95/hf_xet-1.3.1-cp314-cp314t-win_amd64.whl", hash = "sha256:f85480b4fe3e8e4cdbc59ef1d235152b732fd57ca439cc983c291892945ae818", size = 3634352, upload-time = "2026-02-25T00:58:04.749Z" }, + { url = "https://files.pythonhosted.org/packages/cf/61/b59e87a7a10b95c4578a6ce555339b2f002035569dfd366662b9f59975a8/hf_xet-1.3.1-cp314-cp314t-win_arm64.whl", hash = "sha256:83a8830160392ef4bea78d443ea2cf1febe65783b3843a8f12c64b368981e7e2", size = 3494371, upload-time = "2026-02-25T00:58:03.422Z" }, + { url = "https://files.pythonhosted.org/packages/75/f8/c2da4352c0335df6ae41750cf5bab09fdbfc30d3b4deeed9d621811aa835/hf_xet-1.3.1-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:581d1809a016f7881069d86a072168a8199a46c839cf394ff53970a47e4f1ca1", size = 3761755, upload-time = "2026-02-25T00:57:43.621Z" }, + { url = "https://files.pythonhosted.org/packages/c0/e5/a2f3eaae09da57deceb16a96ebe9ae1f6f7b9b94145a9cd3c3f994e7782a/hf_xet-1.3.1-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:329c80c86f2dda776bafd2e4813a46a3ee648dce3ac0c84625902c70d7a6ddba", size = 3523677, upload-time = "2026-02-25T00:57:42.3Z" }, + { url = "https://files.pythonhosted.org/packages/61/cd/acbbf9e51f17d8cef2630e61741228e12d4050716619353efc1ac119f902/hf_xet-1.3.1-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2973c3ff594c3a8da890836308cae1444c8af113c6f10fe6824575ddbc37eca7", size = 4178557, upload-time = "2026-02-25T00:57:35.399Z" }, + { url = "https://files.pythonhosted.org/packages/df/4f/014c14c4ae3461d9919008d0bed2f6f35ba1741e28b31e095746e8dac66f/hf_xet-1.3.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ed4bfd2e6d10cb86c9b0f3483df1d7dd2d0220f75f27166925253bacbc1c2dbe", size = 3958975, upload-time = "2026-02-25T00:57:34.004Z" }, + { url = "https://files.pythonhosted.org/packages/86/50/043f5c5a26f3831c3fa2509c17fcd468fd02f1f24d363adc7745fbe661cb/hf_xet-1.3.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:713913387cc76e300116030705d843a9f15aee86158337eeffb9eb8d26f47fcd", size = 4158298, upload-time = "2026-02-25T00:57:51.14Z" }, + { url = "https://files.pythonhosted.org/packages/08/9c/b667098a636a88358dbeb2caf90e3cb9e4b961f61f6c55bb312793424def/hf_xet-1.3.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:e5063789c9d21f51e9ed4edbee8539655d3486e9cad37e96b7af967da20e8b16", size = 4395743, upload-time = "2026-02-25T00:57:52.783Z" }, + { url = "https://files.pythonhosted.org/packages/70/37/4db0e4e1534270800cfffd5a7e0b338f2137f8ceb5768000147650d34ea9/hf_xet-1.3.1-cp37-abi3-win_amd64.whl", hash = "sha256:607d5bbc2730274516714e2e442a26e40e3330673ac0d0173004461409147dee", size = 3638145, upload-time = "2026-02-25T00:58:02.167Z" }, + { url = "https://files.pythonhosted.org/packages/4e/46/1ba8d36f8290a4b98f78898bdce2b0e8fe6d9a59df34a1399eb61a8d877f/hf_xet-1.3.1-cp37-abi3-win_arm64.whl", hash = "sha256:851b1be6597a87036fe7258ce7578d5df3c08176283b989c3b165f94125c5097", size = 3500490, upload-time = "2026-02-25T00:58:00.667Z" }, ] [[package]] @@ -1047,7 +1050,7 @@ wheels = [ [[package]] name = "huggingface-hub" -version = "1.4.1" +version = "1.5.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "filelock" }, @@ -1056,14 +1059,13 @@ dependencies = [ { name = "httpx" }, { name = "packaging" }, { name = "pyyaml" }, - { name = "shellingham" }, { name = "tqdm" }, - { name = "typer-slim" }, + { name = "typer" }, { name = "typing-extensions" }, ] -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" } +sdist = { url = "https://files.pythonhosted.org/packages/ae/76/b5efb3033d8499b17f9386beaf60f64c461798e1ee16d10bc9c0077beba5/huggingface_hub-1.5.0.tar.gz", hash = "sha256:f281838db29265880fb543de7a23b0f81d3504675de82044307ea3c6c62f799d", size = 695872, upload-time = "2026-02-26T15:35:32.745Z" } wheels = [ - { 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" }, + { url = "https://files.pythonhosted.org/packages/ec/74/2bc951622e2dbba1af9a460d93c51d15e458becd486e62c29cc0ccb08178/huggingface_hub-1.5.0-py3-none-any.whl", hash = "sha256:c9c0b3ab95a777fc91666111f3b3ede71c0cdced3614c553a64e98920585c4ee", size = 596261, upload-time = "2026-02-26T15:35:31.1Z" }, ] [[package]] @@ -1267,7 +1269,7 @@ wheels = [ [[package]] name = "litellm" -version = "1.81.14" +version = "1.81.16" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohttp" }, @@ -1283,9 +1285,9 @@ dependencies = [ { name = "tiktoken" }, { name = "tokenizers" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c8/ab/4fe5517ac55f72ca90119cd0d894a7b4e394ae76e1ccdeb775bd50154b0d/litellm-1.81.14.tar.gz", hash = "sha256:445efb92ae359e8f40ee984753c5ae752535eb18a2aeef00d3089922de5676b7", size = 16541822, upload-time = "2026-02-22T00:33:35.281Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/36/3cbb22d6ef88c10f3fa4f04664c2a37e93a2e6f9c51899cd9fd025cb0a50/litellm-1.81.16.tar.gz", hash = "sha256:264a3868942e722cd6c19c2d625524fe624a1b6961c37c22d299dc7ea99823b3", size = 16668405, upload-time = "2026-02-26T13:01:48.429Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d8/b3/e8fe151c1b81666575552835a3a79127c5aa6bd460fcecc51e032d2f4019/litellm-1.81.14-py3-none-any.whl", hash = "sha256:6394e61bbdef7121e5e3800349f6b01e9369e7cf611e034f1832750c481abfed", size = 14603260, upload-time = "2026-02-22T00:33:32.464Z" }, + { url = "https://files.pythonhosted.org/packages/1f/1e/0022cde913bac87a493e4a182b8768f75e7ae90b64d4e11acb009b18311f/litellm-1.81.16-py3-none-any.whl", hash = "sha256:d6bcc13acbd26719e07bfa6b9923740e88409cbf1f9d626d85fc9ae0e0eec88c", size = 14774277, upload-time = "2026-02-26T13:01:45.652Z" }, ] [[package]] @@ -1638,7 +1640,7 @@ wheels = [ [[package]] name = "openai" -version = "2.21.0" +version = "2.24.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, @@ -1650,9 +1652,9 @@ dependencies = [ { name = "tqdm" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/92/e5/3d197a0947a166649f566706d7a4c8f7fe38f1fa7b24c9bcffe4c7591d44/openai-2.21.0.tar.gz", hash = "sha256:81b48ce4b8bbb2cc3af02047ceb19561f7b1dc0d4e52d1de7f02abfd15aa59b7", size = 644374, upload-time = "2026-02-14T00:12:01.577Z" } +sdist = { url = "https://files.pythonhosted.org/packages/55/13/17e87641b89b74552ed408a92b231283786523edddc95f3545809fab673c/openai-2.24.0.tar.gz", hash = "sha256:1e5769f540dbd01cb33bc4716a23e67b9d695161a734aff9c5f925e2bf99a673", size = 658717, upload-time = "2026-02-24T20:02:07.958Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cc/56/0a89092a453bb2c676d66abee44f863e742b2110d4dbb1dbcca3f7e5fc33/openai-2.21.0-py3-none-any.whl", hash = "sha256:0bc1c775e5b1536c294eded39ee08f8407656537ccc71b1004104fe1602e267c", size = 1103065, upload-time = "2026-02-14T00:11:59.603Z" }, + { url = "https://files.pythonhosted.org/packages/c9/30/844dc675ee6902579b8eef01ed23917cc9319a1c9c0c14ec6e39340c96d0/openai-2.24.0-py3-none-any.whl", hash = "sha256:fed30480d7d6c884303287bde864980a4b137b60553ffbcf9ab4a233b7a73d94", size = 1120122, upload-time = "2026-02-24T20:02:05.669Z" }, ] [[package]] @@ -1763,7 +1765,7 @@ wheels = [ [[package]] name = "opentelemetry-instrumentation-openai" -version = "0.52.4" +version = "0.52.6" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, @@ -1771,9 +1773,9 @@ dependencies = [ { name = "opentelemetry-semantic-conventions" }, { name = "opentelemetry-semantic-conventions-ai" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/37/91/1f72807c84cfaf5b3386011f56357ea304f9e6c0039857d3fa38a13e4d03/opentelemetry_instrumentation_openai-0.52.4.tar.gz", hash = "sha256:690b9c14d68b50c87f24006122165e97819557c13ff7f520e2043e2f69f2789c", size = 6978369, upload-time = "2026-02-19T13:22:02.051Z" } +sdist = { url = "https://files.pythonhosted.org/packages/37/86/1fe5008f3714118fdc1024cd141140a5f204d5ac7016e87a0f07a834efb2/opentelemetry_instrumentation_openai-0.52.6.tar.gz", hash = "sha256:0eb23dc90804a726e516fcbd649cb99f10dfdb5e31d29e44c4b1b8f402dd905d", size = 6978397, upload-time = "2026-02-26T15:40:17.154Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a3/5a/0a0d6cf2b93cd1ec6f7c84f8731ad2d20e6313564362690eee6bbde9b989/opentelemetry_instrumentation_openai-0.52.4-py3-none-any.whl", hash = "sha256:73e6837a5ea44f61439c937f7116c623ccdf390034e3393d501e82f9d6298922", size = 43082, upload-time = "2026-02-19T13:21:18.997Z" }, + { url = "https://files.pythonhosted.org/packages/2c/4a/4623d0adc0187cc45bce631f891c30cd01cf2562d37b918b79561200d985/opentelemetry_instrumentation_openai-0.52.6-py3-none-any.whl", hash = "sha256:5e174388520f294f648f9732471c1b9919c71e5d09649a64ab8ff81714c1278b", size = 43084, upload-time = "2026-02-26T15:39:35.584Z" }, ] [[package]] @@ -1857,40 +1859,40 @@ wheels = [ [[package]] name = "primp" -version = "1.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f4/60/ea0822d275847ed266d694662cef1863c37d3c1752f4286c4baae5297d3f/primp-1.0.0.tar.gz", hash = "sha256:09fc1ff6009220247d723792794e514782e1ab7e9ba5e2547272a07afed5ca86", size = 973426, upload-time = "2026-02-13T15:32:49.846Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/ae/443244fb49e2f421dafadd689361777d48b07f0ea7d18b34e72a38a3ef44/primp-1.0.0-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:6af2343ac655d409ec70c3eeb7c2283de509b663aeb6b3e34e39e1331c82daf6", size = 3893122, upload-time = "2026-02-13T15:33:07.596Z" }, - { url = "https://files.pythonhosted.org/packages/92/02/aa765143ce632bcf5e3cfa8bd41e2032f8d12695754564b5059821b2b41a/primp-1.0.0-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:25f21400ff236b0e1db5d4db7db66965f63b64898103384e916ecef575ab3395", size = 3655128, upload-time = "2026-02-13T15:32:41.147Z" }, - { url = "https://files.pythonhosted.org/packages/c3/d7/5e9e320441a7c0ffef24ce55fd2922aacd003e6713633d1d0732fe964ff6/primp-1.0.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:abd09660db079903031be91e04af2dcf42457bd739e6f328c7b2364e38061876", size = 3792951, upload-time = "2026-02-13T15:32:56.186Z" }, - { url = "https://files.pythonhosted.org/packages/36/f2/1130fad846f08bbf104a64232ef4f58ae5b5c4b2c64d6a73b1f4245607e0/primp-1.0.0-cp310-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6e756480c9dd585b20927c2a0c1d0c42cbcb5866ed1e741a8f93163e6f905e6c", size = 3440111, upload-time = "2026-02-13T15:32:57.523Z" }, - { url = "https://files.pythonhosted.org/packages/c4/e5/a3e0ba7f4a0409ba615098bda35a1276ebf992d2bd7a8f635c8349e77276/primp-1.0.0-cp310-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b75a10ead2872dee9be9c60c07e8fce5328c88ed251e3fdbd29a7d2d73ab512a", size = 3651920, upload-time = "2026-02-13T15:32:48.511Z" }, - { url = "https://files.pythonhosted.org/packages/80/02/10cfc095e958e498171977068ebcabddaa8dabd7835725482b8c0eefec19/primp-1.0.0-cp310-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2ea1a0b1d4c2a65efd5f22bc42bc0133ebf359f70dd155847cbebf8015fb05a1", size = 3922305, upload-time = "2026-02-13T15:33:23.231Z" }, - { url = "https://files.pythonhosted.org/packages/89/00/947c74646825d38d7f5c5fc5a7f2474f30767ea9817f9a7742f95ac99e45/primp-1.0.0-cp310-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1abd58a2bf0a2f062edc51a3684f8b9d0170348a96afdd3915f02f498c661228", size = 3811925, upload-time = "2026-02-13T15:33:04.976Z" }, - { url = "https://files.pythonhosted.org/packages/65/34/0f788310dd2903be8b49d9396ad4fa7deb1f5ab6419a2a7ea9014380f52f/primp-1.0.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:52506249b8132eb386e90349f9fbbcf6b39e36523d61f92a0e8c557e32f71ef2", size = 4009948, upload-time = "2026-02-13T15:32:43.88Z" }, - { url = "https://files.pythonhosted.org/packages/44/35/9a3147377764380fa9940d4cfc328b5a31a1a1c72d2cbbdaa188ab8ea296/primp-1.0.0-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:b7f24c3a67aab0517ba4f6e743dfced331198062ff8e31df692381e60a17b775", size = 3970643, upload-time = "2026-02-13T15:33:06.248Z" }, - { url = "https://files.pythonhosted.org/packages/df/a9/396511a300bc44de4213198f10a21337fcb3f43e4553ece9a17b1a48e1df/primp-1.0.0-cp310-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:0cf76f39d5820a2607a2dd25c074ceb8efa741bc311552218156c53b1002ec25", size = 3668236, upload-time = "2026-02-13T15:33:00.299Z" }, - { url = "https://files.pythonhosted.org/packages/2b/44/f1f4a6223dbfa8c72d37286b4bf9a2bb06241c9bac7ce95c5acc03069fec/primp-1.0.0-cp310-abi3-musllinux_1_2_i686.whl", hash = "sha256:3414a4bbe37e909a45c0fea04104bd23165d81b94f3d68bfe9a11ba18c462b39", size = 3776956, upload-time = "2026-02-13T15:33:08.969Z" }, - { url = "https://files.pythonhosted.org/packages/d7/9e/b6cb2c19abaeea0ade9256c296340b79dee0084bffcbaadceeebaf75c691/primp-1.0.0-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:3487e5269dc6d840035d59a8e5afbba99b5736da848664b71356681a837c3a8b", size = 4262036, upload-time = "2026-02-13T15:33:21.939Z" }, - { url = "https://files.pythonhosted.org/packages/6b/80/bf5a730384f338be7a52e5976c0f7ea8e00f8f078a80bd51fa15a61cd35a/primp-1.0.0-cp310-abi3-win32.whl", hash = "sha256:0c44e8dccfcd2dd3fb3467d44836445039a013704ea869340bf67a444cbf3f36", size = 3185054, upload-time = "2026-02-13T15:33:15.486Z" }, - { url = "https://files.pythonhosted.org/packages/8f/0b/92d644fbbf97f8fca2959c388f0ed50abd9ea1d17c3ad9b5b0e364fa8d37/primp-1.0.0-cp310-abi3-win_amd64.whl", hash = "sha256:705fb755f5461b551925de7546f3fea5b657fc44fee136498bed492bf5051864", size = 3512508, upload-time = "2026-02-13T15:32:52.646Z" }, - { url = "https://files.pythonhosted.org/packages/c3/6e/efd595743e3b8b0477f44194f6a22fe0d7118b76e9b01167b0921a160d91/primp-1.0.0-cp310-abi3-win_arm64.whl", hash = "sha256:4e080ad054df4c325c434acf613d9cae54278e8141fa116452ec18bf576672a8", size = 3560136, upload-time = "2026-02-13T15:32:50.901Z" }, - { url = "https://files.pythonhosted.org/packages/29/62/e3ee3836154f849086e5a29db7ec95bf805c0143266d59868c2eff0528df/primp-1.0.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:6853b719f511ed09dc3673e54cd489b4ed35b0f769428dc79b3c54c446aafd22", size = 3890886, upload-time = "2026-02-13T15:33:12.447Z" }, - { url = "https://files.pythonhosted.org/packages/23/12/4ea190b844557e919a84d3851d49407303d145dfe93cab67d2ed7268c6fa/primp-1.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:3d072d1e3c84068b5727426500210e33241ef97844fe781d9817094fdfc6b128", size = 3653937, upload-time = "2026-02-13T15:33:13.803Z" }, - { url = "https://files.pythonhosted.org/packages/be/51/bb861bcc45b6761b4dcc3b41a1ce6eecea9ccf4e9786d545f28313540259/primp-1.0.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ef28f8d6b89c5daf651dc7c7560b4914647bfe73b9a3847e2ae5ed0ff7d8bcf", size = 3792475, upload-time = "2026-02-13T15:33:27.419Z" }, - { url = "https://files.pythonhosted.org/packages/88/87/f87d652aa13a1b1bba9f576c04732319ecf75075e3b26bf91ad47eab00d3/primp-1.0.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:04a0d9d88cdce7ab685b4657cfe07d603a85118ec48a09015fa66eadad156c44", size = 3443247, upload-time = "2026-02-13T15:32:46.793Z" }, - { url = "https://files.pythonhosted.org/packages/31/f5/623885d04702523201639af3d011efb2eaed0dff9200a78db609b570c4c6/primp-1.0.0-cp314-cp314t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0ad2255403b155d93cf5cb7f6e807e26dc10c49071e0bac888c2c0e14801b82", size = 3651674, upload-time = "2026-02-13T15:33:24.577Z" }, - { url = "https://files.pythonhosted.org/packages/0b/17/b45e7e79cf3c5de7aaf23bf38167243c4df017997d954dd903a479f474d8/primp-1.0.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c3e7ccbe4746163f14b984523ac49ce3eed923fbe672c4c08480fa13217c2357", size = 3918929, upload-time = "2026-02-13T15:32:42.615Z" }, - { url = "https://files.pythonhosted.org/packages/fb/00/f5f58ef9856d99cf52e59f9034b27dc2659430be3257ecb890f1b4fccb17/primp-1.0.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:63a1d34732c2e6282e5e30f5d425eaa28ca417d74accda92908fdb8c944ff319", size = 3814485, upload-time = "2026-02-13T15:33:16.917Z" }, - { url = "https://files.pythonhosted.org/packages/b0/93/5e82f1fb2fd026d21c645b80da90f29f3afb6f1990120dcff8662c4f4b6e/primp-1.0.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d90e61f173e661ed8e21d8cd6534c586ad1d25565a0bac539a6a2d5e990439e0", size = 4014672, upload-time = "2026-02-13T15:33:26.083Z" }, - { url = "https://files.pythonhosted.org/packages/03/d7/6f1739043c84e772b45c51d2a1ab8c32727f0db6d41beb1b092a7baa2c02/primp-1.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:fcb28e07bc250b8c4762312e952bd84b6b983554fba6cd067f83018bd39a0488", size = 3971122, upload-time = "2026-02-13T15:32:53.944Z" }, - { url = "https://files.pythonhosted.org/packages/74/9a/47d7101034a36e73bb6976c566c56b54ec46efff1d64ebc07dccf05e51d8/primp-1.0.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:8e5b8fa46130d3db33192784d4935fc3f9574f030d0e78d281e90c37cf2507ee", size = 3669273, upload-time = "2026-02-13T15:33:10.267Z" }, - { url = "https://files.pythonhosted.org/packages/48/15/86878a9b46fc4bafba454e63b293e779c1ba6f9bf5ffc221f2f3dc70d60e/primp-1.0.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:984ab730449fd2e5f794fd6fad37fed3596432a24435ce2d0363b454503b7846", size = 3776747, upload-time = "2026-02-13T15:33:03.156Z" }, - { url = "https://files.pythonhosted.org/packages/9c/52/7afaf2a232987711863fa1e994cb6908c9dcd550d436578bb6cb63e53a83/primp-1.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:2abd6d47ca60028bcc33dc47dd33f355237be80d7889518e44cc4d730c9e45e0", size = 4266058, upload-time = "2026-02-13T15:32:59.084Z" }, - { url = "https://files.pythonhosted.org/packages/67/c2/fd1365ab28c4e15bebd291215c152c9787185a4fade0df780bb5e53d5866/primp-1.0.0-cp314-cp314t-win32.whl", hash = "sha256:39c27d84fd597a43bb291b6928fbaa46d4a7aff0c31ae1a361dccbbd109118a1", size = 3184230, upload-time = "2026-02-13T15:32:45.437Z" }, - { url = "https://files.pythonhosted.org/packages/30/2f/fcb4935ef1b2ba19bafbf050775f402ef30d19c9ba0d83a6328b453436a4/primp-1.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:bc8bac0288fb7ed541c8db4be46c5f2779e4c1b023bf01e46fe4c1405150dbeb", size = 3514652, upload-time = "2026-02-13T15:33:01.694Z" }, - { url = "https://files.pythonhosted.org/packages/49/88/2dbeee5a6c914c36b5dfca6e77913f4a190ac0137db0ea386b9632c16ef0/primp-1.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:117d3eb9c556fe88c8ed0533be80c2495922671e977e3e0e78a6b841014380eb", size = 3553319, upload-time = "2026-02-13T15:33:19.67Z" }, +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/de/25/1113a87a693121f4eb18d2df3a99d8ad43984f4068e31a5765c03e4b8b96/primp-1.1.1.tar.gz", hash = "sha256:58775e74f86cc58f9abe4b1dacea399fa6367c1959e591ad9345f151ad38d259", size = 311388, upload-time = "2026-02-24T16:12:53.452Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bf/0f/027fc0394f70721c6dc5054fb3efff6479753da0b272e15b16cefba958b8/primp-1.1.1-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:691215c5a514a7395c1ee775cd03a94a41497941e17291e1a71f5356142c61e6", size = 3997489, upload-time = "2026-02-24T16:12:49.154Z" }, + { url = "https://files.pythonhosted.org/packages/af/ea/0f23fbfef2a550c420eaa73fd3e21176acb0ddf0d50028d8bc8d937441be/primp-1.1.1-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:17ace56cd24a894236121bf37d3616ec15d5299a6fa2d2a30fbbf9c22b946a03", size = 3734591, upload-time = "2026-02-24T16:12:45.629Z" }, + { url = "https://files.pythonhosted.org/packages/0a/63/c5669652446a981dd5faad8a8255e5567db5818b951dbe74e81968f672cb/primp-1.1.1-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cfec08ae15f6d86b2bcaaee3358d5cc349a843c8be164502ea73658a817c5cf2", size = 3875508, upload-time = "2026-02-24T16:12:59.403Z" }, + { url = "https://files.pythonhosted.org/packages/14/79/19e4d19a445b39c930a317e4ea4d1eff07ef0661b4e7397ad425f7ff0bd8/primp-1.1.1-cp310-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c3cf7e93e8ff4842eee9c6d4ac47d638a5c981752b19f458877a3536c1da6671", size = 3510461, upload-time = "2026-02-24T16:12:37.908Z" }, + { url = "https://files.pythonhosted.org/packages/50/39/091282d624067958b42a087976c0da80eecc5ade03acfc732389be3af723/primp-1.1.1-cp310-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:db6f3f18855bf25dca14f6d121d214e5c922275f49cdadd248eff28abb779edb", size = 3727644, upload-time = "2026-02-24T16:12:16.671Z" }, + { url = "https://files.pythonhosted.org/packages/33/ae/ca4e4a5d0cbd35684a228fd1f7c1425db0860a7bd74ce8f40835f6184834/primp-1.1.1-cp310-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2d8363faadb1d07fa8ae73de6ed2ca4666b36c77ea3990714164b8ee7ab1aa1d", size = 4004689, upload-time = "2026-02-24T16:12:57.957Z" }, + { url = "https://files.pythonhosted.org/packages/3a/ed/b3cf17bcac4914aa63cd83d763c9e347aab6e0b9285645b0015b036f914d/primp-1.1.1-cp310-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:302241ee447c185417e93e3a3e5a2801fdd710b1a5cc63c01a26ee7dc634e9b1", size = 3918084, upload-time = "2026-02-24T16:12:30.283Z" }, + { url = "https://files.pythonhosted.org/packages/6a/9f/f563eaeb654749fa519c627b1f1ab93cf875537c56123fba507f74b647fc/primp-1.1.1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a37ad318f1b8295d414e1c32ca407efcb92e664c5ff41f06901bd3ee03bab1fa", size = 4108648, upload-time = "2026-02-24T16:12:15.269Z" }, + { url = "https://files.pythonhosted.org/packages/1c/b9/2df5376900c293238cf641591952979f689ea3f009195df4cce15786afb9/primp-1.1.1-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e46829d9d86caf18b2b40829655d470e0ce2eebb061f2ee973451b2509f1c5a2", size = 4055747, upload-time = "2026-02-24T16:12:42.925Z" }, + { url = "https://files.pythonhosted.org/packages/a1/e9/eaaea488b4ae445059bd99559649402c77ddd9dfdda01528daa9ee11d8fe/primp-1.1.1-cp310-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:8ef9cb971915d2db3fbb1a512777261e5267c95d4717b18aff453f5e3dbb9bda", size = 3742046, upload-time = "2026-02-24T16:12:19.945Z" }, + { url = "https://files.pythonhosted.org/packages/0a/92/0607dd9d01840e0c007519d69cdcbb6f1358d6d7f8e739fc3359773b50d2/primp-1.1.1-cp310-abi3-musllinux_1_2_i686.whl", hash = "sha256:1a350656142772b5d6afc0dfaf9172c69449fbfafb9b6590af7ba116d32554d7", size = 3857103, upload-time = "2026-02-24T16:12:39.338Z" }, + { url = "https://files.pythonhosted.org/packages/e5/b6/5d574a7a84afd38df03c5535a9bb1052090bd0289760dcca24188510dd09/primp-1.1.1-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:ec71a66750befd219f29cb6ff01bc1c26671040fc76b4115bf045c85f84da041", size = 4357972, upload-time = "2026-02-24T16:12:12.159Z" }, + { url = "https://files.pythonhosted.org/packages/8b/f3/34ba2deba36de0a6041a61c16f2097e0bd2e74114f8d85096b3911288b4c/primp-1.1.1-cp310-abi3-win32.whl", hash = "sha256:901dc1e40b99ba5925463ab120af14afb8a66f4ac7eb2cdf87aaf21047f6db39", size = 3259840, upload-time = "2026-02-24T16:12:31.762Z" }, + { url = "https://files.pythonhosted.org/packages/a8/c6/fa3c17e5b6e4cff5bbdfd6bed1d0e8f81e17708dd8106906a031a2432b61/primp-1.1.1-cp310-abi3-win_amd64.whl", hash = "sha256:6bedd91451ec9ac46203ccb5c2c9925e9206e33abec7c791a2b39e3f86530bf0", size = 3596643, upload-time = "2026-02-24T16:12:21.554Z" }, + { url = "https://files.pythonhosted.org/packages/94/3d/a5b391107ba1c72dc8eb4f603c5764067449e1445438d71e093a72d5eda1/primp-1.1.1-cp310-abi3-win_arm64.whl", hash = "sha256:fd22a10164536374262e32fccbf81736b20798ac7582f159d5ffdef01a755579", size = 3606836, upload-time = "2026-02-24T16:12:28.579Z" }, + { url = "https://files.pythonhosted.org/packages/5d/77/b7df4f1776ae2e7cb5cf123b977167709c120712c7a4f968dc93b28d05ac/primp-1.1.1-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:e6b0fdeb12cc60b0fa756191118cec8ede8d26f869b83fa501aed722984a964b", size = 3981048, upload-time = "2026-02-24T16:12:24.396Z" }, + { url = "https://files.pythonhosted.org/packages/9a/c8/f198cd6ad9f232a171739a69c534c684237362af8e55f0cc2fc452377aa8/primp-1.1.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:fc473e87adc88f6ce94b7f3edeb2ca6c973f4ceb2d4199d0e707544f71c639c4", size = 3729293, upload-time = "2026-02-24T16:12:18.07Z" }, + { url = "https://files.pythonhosted.org/packages/e7/ce/bd8e564f8233ab0213a296dda2e04b484e0c4b9975702c7ba712e96ead8c/primp-1.1.1-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e85f2aea74b8683611c76958de8827322bd800e1b51aec88130da68d00a20462", size = 3873474, upload-time = "2026-02-24T16:12:40.749Z" }, + { url = "https://files.pythonhosted.org/packages/e7/ab/d3ee13de657cb068e81008eedc2d61103094497d9edc054997b85d85163e/primp-1.1.1-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ca535dfbc5a8290975f4bd8ce38922b26cf4fefc737aa2116bcb1a5795c14309", size = 3509513, upload-time = "2026-02-24T16:12:44.251Z" }, + { url = "https://files.pythonhosted.org/packages/6f/5d/3ed38dd94ae503977329976dbe00831e66d22f0f298c026f8d7493be2b39/primp-1.1.1-cp314-cp314t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d94073e9ecbf97f6d1538d4678df1bb662fd418ad5fd09da4040fe46623e2ec5", size = 3728743, upload-time = "2026-02-24T16:12:33.277Z" }, + { url = "https://files.pythonhosted.org/packages/bc/15/19af65a35b2189d6f2267148ea5b7cbb266aa36891acd641388b7a0f6022/primp-1.1.1-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7e639441bd36e582feec7033e4b8661e0979a61bff65af5f476d33e02ebb3c4d", size = 3999650, upload-time = "2026-02-24T16:12:36.157Z" }, + { url = "https://files.pythonhosted.org/packages/22/cb/aa635a9903a1ee3b0ffe5dd9218a2e2d8880828a1eaba9d0035f967d118a/primp-1.1.1-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd770ca4f73a700da0911d1300a952e4d9a4a3321e205aa5a8644ae81cbd4d7d", size = 3896990, upload-time = "2026-02-24T16:12:13.66Z" }, + { url = "https://files.pythonhosted.org/packages/25/98/916916ec3bd5dab4125bf17b28d1959883a831dc4f9757f915e509c43ec2/primp-1.1.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7dccb605997c918b7abbdd163303d789d63eb03d7cd0440184f34b06a8522fc1", size = 4096157, upload-time = "2026-02-24T16:12:27.163Z" }, + { url = "https://files.pythonhosted.org/packages/ff/57/219c44bf21896a3f2132821ea00bbc9af36b194449ee5083791f690daf7d/primp-1.1.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:1ada94c7f9f047b1c5ba339f62effd44f4c4943d4d8bb96447e9c84ab3bd874d", size = 4052968, upload-time = "2026-02-24T16:12:34.574Z" }, + { url = "https://files.pythonhosted.org/packages/6a/ce/dfdd734c7372faef4a26ecb0267a724e19f78b76a9a92440b8ca824e8f5a/primp-1.1.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:21ac92542f378a21fba8093dbeb7e093851e00da2bdfd9bc6aa63f81cff035d0", size = 3744522, upload-time = "2026-02-24T16:12:25.726Z" }, + { url = "https://files.pythonhosted.org/packages/d6/9c/3eb9e484c17784eac6549c505a68d82b6e5959a0af6efbcf28a773450a81/primp-1.1.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:adaa5d7e8d2ca089cbf41a837a301da605c21ff0ea5fecac8a8b1eead4bc563f", size = 3855298, upload-time = "2026-02-24T16:12:54.518Z" }, + { url = "https://files.pythonhosted.org/packages/1d/ca/80924591ec24f9341982e4d74251f6bfeda44cbb90f6f792403d0737a390/primp-1.1.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b041ab0019e0fb21c24de542e80056775508e5d1d0f0333fb661185bdb359138", size = 4348887, upload-time = "2026-02-24T16:12:47.376Z" }, + { url = "https://files.pythonhosted.org/packages/95/4b/0edc62583af9a03fd1eb34ffd865245c921919f374b0e72b1bb73dc9adf6/primp-1.1.1-cp314-cp314t-win32.whl", hash = "sha256:b7270b9755a931e7667854ad5d9b2aeb88068f0add4fb741529e8c25d953f21b", size = 3252145, upload-time = "2026-02-24T16:12:52.335Z" }, + { url = "https://files.pythonhosted.org/packages/01/b7/9784b93d252e4c2a50f7a46908d91110b7ce9d04e1adb47227fc212576ff/primp-1.1.1-cp314-cp314t-win_amd64.whl", hash = "sha256:19a48f4e91256ec661e022976a75e6a0621522244ac928e8c632d829adb929ce", size = 3591097, upload-time = "2026-02-24T16:12:22.898Z" }, + { url = "https://files.pythonhosted.org/packages/db/d5/3b34601cb2da1cec7aec88f447af9de1e8e3bb3101f26351aa8570b5b7af/primp-1.1.1-cp314-cp314t-win_arm64.whl", hash = "sha256:c97b951afb203b9528f36524e96b1e37ce42f3a7eb0cd77cd053ad5bdfc93d81", size = 3603917, upload-time = "2026-02-24T16:12:55.859Z" }, ] [[package]] @@ -2200,18 +2202,18 @@ crypto = [ [[package]] name = "pyrefly" -version = "0.53.0" +version = "0.54.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/3a/73/262196c4ea5afec6389366a4b3d49f67655c6396efa1a4053cca37be7c8d/pyrefly-0.53.0.tar.gz", hash = "sha256:aef117e8abb9aa4cf17fc64fbf450d825d3c65fc9de3c02ed20129ebdd57aa74", size = 5040338, upload-time = "2026-02-17T21:15:44.877Z" } +sdist = { url = "https://files.pythonhosted.org/packages/81/44/c10b16a302fda90d0af1328f880b232761b510eab546616a7be2fdf35a57/pyrefly-0.54.0.tar.gz", hash = "sha256:c6663be64d492f0d2f2a411ada9f28a6792163d34133639378b7f3dd9a8dca94", size = 5098893, upload-time = "2026-02-23T15:44:35.111Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e5/9b/3af46ac06dcfd7b27f15e991d2d4f0082519e6906b1f304f511e4db3ad5f/pyrefly-0.53.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:79d7fb35dff0988b3943c26f74cc752fad54357a0bc33f7db665f02d1c9a5bcc", size = 12041081, upload-time = "2026-02-17T21:15:24.769Z" }, - { url = "https://files.pythonhosted.org/packages/79/4f/23422479153f8f88d1699461bf8f22e32320bb0fc1272774ea8a17463302/pyrefly-0.53.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e1d98b1e86f3c38db44860695b7986e731238e1b19c3cad7a3050476a8f6f84d", size = 11604301, upload-time = "2026-02-17T21:15:27.23Z" }, - { url = "https://files.pythonhosted.org/packages/d8/9a/f4cc6b81a464c31c3112b46abbd44ccd569f01c71a0abf39eeccf6ace914/pyrefly-0.53.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb9f2440f7e0c70aa18400f44aed994c326a1ab00f2b01cf7253a63fc62d7c6b", size = 32674148, upload-time = "2026-02-17T21:15:29.762Z" }, - { url = "https://files.pythonhosted.org/packages/4c/cc/fa98606a628380b7ae4623dbc30843e8fed6b7a631c89503bdf123e47453/pyrefly-0.53.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e4e826a5ff2aba2c41e02e6094580751c512db7916e60728cd8612dbcf178d7b", size = 35099098, upload-time = "2026-02-17T21:15:32.383Z" }, - { url = "https://files.pythonhosted.org/packages/71/d2/ab4105ee90495314a8ad6be4d6736c9f20e4b0ceb49cf015ddc84c394c25/pyrefly-0.53.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf4c69410c7a96b417a390a0e3d340f4370fdab02f9d3eaa222c4bd42e3ce24a", size = 37777824, upload-time = "2026-02-17T21:15:35.474Z" }, - { url = "https://files.pythonhosted.org/packages/38/99/0779b7202d801cdf67f08159cf7dd318d23114661143689a767d9b8a98f1/pyrefly-0.53.0-py3-none-win32.whl", hash = "sha256:00687bb6be6e366b8c0137a89625da40ced3b9212a65e561857ff888fe88e6e8", size = 11111961, upload-time = "2026-02-17T21:15:38.455Z" }, - { url = "https://files.pythonhosted.org/packages/bd/71/dc7e59f0acb81dcf3f56e7ad30e740a08527403cb1d657caca9d44fef803/pyrefly-0.53.0-py3-none-win_amd64.whl", hash = "sha256:e0512e6f7af44ae01cfddba096ff7740e15cbd1d0497a3d34a7afcb504e2b300", size = 11888648, upload-time = "2026-02-17T21:15:40.471Z" }, - { url = "https://files.pythonhosted.org/packages/5d/72/2a7c00a439c6593430289a4581426efe0bee73f6e5a443f501969e104300/pyrefly-0.53.0-py3-none-win_arm64.whl", hash = "sha256:5066e2102769683749102421b8b8667cae26abe1827617f04e8df4317e0a94af", size = 11368150, upload-time = "2026-02-17T21:15:42.74Z" }, + { url = "https://files.pythonhosted.org/packages/5f/99/8fdcdb4e55f0227fdd9f6abce36b619bab1ecb0662b83b66adc8cba3c788/pyrefly-0.54.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:58a3f092b6dc25ef79b2dc6c69a40f36784ca157c312bfc0baea463926a9db6d", size = 12223973, upload-time = "2026-02-23T15:44:14.278Z" }, + { url = "https://files.pythonhosted.org/packages/90/35/c2aaf87a76003ad27b286594d2e5178f811eaa15bfe3d98dba2b47d56dd1/pyrefly-0.54.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:615081414106dd95873bc39c3a4bed68754c6cc24a8177ac51d22f88f88d3eb3", size = 11785585, upload-time = "2026-02-23T15:44:17.468Z" }, + { url = "https://files.pythonhosted.org/packages/c4/4a/ced02691ed67e5a897714979196f08ad279ec7ec7f63c45e00a75a7f3c0e/pyrefly-0.54.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cbcaf20f5fe585079079a95205c1f3cd4542d17228cdf1df560288880623b70", size = 33381977, upload-time = "2026-02-23T15:44:19.736Z" }, + { url = "https://files.pythonhosted.org/packages/0b/ce/72a117ed437c8f6950862181014b41e36f3c3997580e29b772b71e78d587/pyrefly-0.54.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66d5da116c0d34acfbd66663addd3ca8aa78a636f6692a66e078126d3620a883", size = 35962821, upload-time = "2026-02-23T15:44:22.357Z" }, + { url = "https://files.pythonhosted.org/packages/85/de/89013f5ae0a35d2b6b01274a92a35ee91431ea001050edf0a16748d39875/pyrefly-0.54.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ef3ac27f1a4baaf67aead64287d3163350844794aca6315ad1a9650b16ec26a", size = 38496689, upload-time = "2026-02-23T15:44:25.236Z" }, + { url = "https://files.pythonhosted.org/packages/9f/9a/33b097c7bf498b924742dca32dd5d9c6a3fa6c2b52b63a58eb9e1980ca89/pyrefly-0.54.0-py3-none-win32.whl", hash = "sha256:7d607d72200a8afbd2db10bfefb40160a7a5d709d207161c21649cedd5cfc09a", size = 11295268, upload-time = "2026-02-23T15:44:27.551Z" }, + { url = "https://files.pythonhosted.org/packages/d4/21/9263fd1144d2a3d7342b474f183f7785b3358a1565c864089b780110b933/pyrefly-0.54.0-py3-none-win_amd64.whl", hash = "sha256:fd416f04f89309385696f685bd5c9141011f18c8072f84d31ca20c748546e791", size = 12081810, upload-time = "2026-02-23T15:44:29.461Z" }, + { url = "https://files.pythonhosted.org/packages/ea/5b/fad062a196c064cbc8564de5b2f4d3cb6315f852e3b31e8a1ce74c69a1ea/pyrefly-0.54.0-py3-none-win_arm64.whl", hash = "sha256:f06ab371356c7b1925e0bffe193b738797e71e5dbbff7fb5a13f90ee7521211d", size = 11564930, upload-time = "2026-02-23T15:44:33.053Z" }, ] [[package]] @@ -2616,27 +2618,27 @@ wheels = [ [[package]] name = "ruff" -version = "0.15.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/06/04/eab13a954e763b0606f460443fcbf6bb5a0faf06890ea3754ff16523dce5/ruff-0.15.2.tar.gz", hash = "sha256:14b965afee0969e68bb871eba625343b8673375f457af4abe98553e8bbb98342", size = 4558148, upload-time = "2026-02-19T22:32:20.271Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2f/70/3a4dc6d09b13cb3e695f28307e5d889b2e1a66b7af9c5e257e796695b0e6/ruff-0.15.2-py3-none-linux_armv6l.whl", hash = "sha256:120691a6fdae2f16d65435648160f5b81a9625288f75544dc40637436b5d3c0d", size = 10430565, upload-time = "2026-02-19T22:32:41.824Z" }, - { url = "https://files.pythonhosted.org/packages/71/0b/bb8457b56185ece1305c666dc895832946d24055be90692381c31d57466d/ruff-0.15.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:a89056d831256099658b6bba4037ac6dd06f49d194199215befe2bb10457ea5e", size = 10820354, upload-time = "2026-02-19T22:32:07.366Z" }, - { url = "https://files.pythonhosted.org/packages/2d/c1/e0532d7f9c9e0b14c46f61b14afd563298b8b83f337b6789ddd987e46121/ruff-0.15.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e36dee3a64be0ebd23c86ffa3aa3fd3ac9a712ff295e192243f814a830b6bd87", size = 10170767, upload-time = "2026-02-19T22:32:13.188Z" }, - { url = "https://files.pythonhosted.org/packages/47/e8/da1aa341d3af017a21c7a62fb5ec31d4e7ad0a93ab80e3a508316efbcb23/ruff-0.15.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9fb47b6d9764677f8c0a193c0943ce9a05d6763523f132325af8a858eadc2b9", size = 10529591, upload-time = "2026-02-19T22:32:02.547Z" }, - { url = "https://files.pythonhosted.org/packages/93/74/184fbf38e9f3510231fbc5e437e808f0b48c42d1df9434b208821efcd8d6/ruff-0.15.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f376990f9d0d6442ea9014b19621d8f2aaf2b8e39fdbfc79220b7f0c596c9b80", size = 10260771, upload-time = "2026-02-19T22:32:36.938Z" }, - { url = "https://files.pythonhosted.org/packages/05/ac/605c20b8e059a0bc4b42360414baa4892ff278cec1c91fff4be0dceedefd/ruff-0.15.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2dcc987551952d73cbf5c88d9fdee815618d497e4df86cd4c4824cc59d5dd75f", size = 11045791, upload-time = "2026-02-19T22:32:31.642Z" }, - { url = "https://files.pythonhosted.org/packages/fd/52/db6e419908f45a894924d410ac77d64bdd98ff86901d833364251bd08e22/ruff-0.15.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:42a47fd785cbe8c01b9ff45031af875d101b040ad8f4de7bbb716487c74c9a77", size = 11879271, upload-time = "2026-02-19T22:32:29.305Z" }, - { url = "https://files.pythonhosted.org/packages/3e/d8/7992b18f2008bdc9231d0f10b16df7dda964dbf639e2b8b4c1b4e91b83af/ruff-0.15.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cbe9f49354866e575b4c6943856989f966421870e85cd2ac94dccb0a9dcb2fea", size = 11303707, upload-time = "2026-02-19T22:32:22.492Z" }, - { url = "https://files.pythonhosted.org/packages/d7/02/849b46184bcfdd4b64cde61752cc9a146c54759ed036edd11857e9b8443b/ruff-0.15.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b7a672c82b5f9887576087d97be5ce439f04bbaf548ee987b92d3a7dede41d3a", size = 11149151, upload-time = "2026-02-19T22:32:44.234Z" }, - { url = "https://files.pythonhosted.org/packages/70/04/f5284e388bab60d1d3b99614a5a9aeb03e0f333847e2429bebd2aaa1feec/ruff-0.15.2-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:72ecc64f46f7019e2bcc3cdc05d4a7da958b629a5ab7033195e11a438403d956", size = 11091132, upload-time = "2026-02-19T22:32:24.691Z" }, - { url = "https://files.pythonhosted.org/packages/fa/ae/88d844a21110e14d92cf73d57363fab59b727ebeabe78009b9ccb23500af/ruff-0.15.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:8dcf243b15b561c655c1ef2f2b0050e5d50db37fe90115507f6ff37d865dc8b4", size = 10504717, upload-time = "2026-02-19T22:32:26.75Z" }, - { url = "https://files.pythonhosted.org/packages/64/27/867076a6ada7f2b9c8292884ab44d08fd2ba71bd2b5364d4136f3cd537e1/ruff-0.15.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:dab6941c862c05739774677c6273166d2510d254dac0695c0e3f5efa1b5585de", size = 10263122, upload-time = "2026-02-19T22:32:10.036Z" }, - { url = "https://files.pythonhosted.org/packages/e7/ef/faf9321d550f8ebf0c6373696e70d1758e20ccdc3951ad7af00c0956be7c/ruff-0.15.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:1b9164f57fc36058e9a6806eb92af185b0697c9fe4c7c52caa431c6554521e5c", size = 10735295, upload-time = "2026-02-19T22:32:39.227Z" }, - { url = "https://files.pythonhosted.org/packages/2f/55/e8089fec62e050ba84d71b70e7834b97709ca9b7aba10c1a0b196e493f97/ruff-0.15.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:80d24fcae24d42659db7e335b9e1531697a7102c19185b8dc4a028b952865fd8", size = 11241641, upload-time = "2026-02-19T22:32:34.617Z" }, - { url = "https://files.pythonhosted.org/packages/23/01/1c30526460f4d23222d0fabd5888868262fd0e2b71a00570ca26483cd993/ruff-0.15.2-py3-none-win32.whl", hash = "sha256:fd5ff9e5f519a7e1bd99cbe8daa324010a74f5e2ebc97c6242c08f26f3714f6f", size = 10507885, upload-time = "2026-02-19T22:32:15.635Z" }, - { url = "https://files.pythonhosted.org/packages/5c/10/3d18e3bbdf8fc50bbb4ac3cc45970aa5a9753c5cb51bf9ed9a3cd8b79fa3/ruff-0.15.2-py3-none-win_amd64.whl", hash = "sha256:d20014e3dfa400f3ff84830dfb5755ece2de45ab62ecea4af6b7262d0fb4f7c5", size = 11623725, upload-time = "2026-02-19T22:32:04.947Z" }, - { url = "https://files.pythonhosted.org/packages/6d/78/097c0798b1dab9f8affe73da9642bb4500e098cb27fd8dc9724816ac747b/ruff-0.15.2-py3-none-win_arm64.whl", hash = "sha256:cabddc5822acdc8f7b5527b36ceac55cc51eec7b1946e60181de8fe83ca8876e", size = 10941649, upload-time = "2026-02-19T22:32:18.108Z" }, +version = "0.15.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/da/31/d6e536cdebb6568ae75a7f00e4b4819ae0ad2640c3604c305a0428680b0c/ruff-0.15.4.tar.gz", hash = "sha256:3412195319e42d634470cc97aa9803d07e9d5c9223b99bcb1518f0c725f26ae1", size = 4569550, upload-time = "2026-02-26T20:04:14.959Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f2/82/c11a03cfec3a4d26a0ea1e571f0f44be5993b923f905eeddfc397c13d360/ruff-0.15.4-py3-none-linux_armv6l.whl", hash = "sha256:a1810931c41606c686bae8b5b9a8072adac2f611bb433c0ba476acba17a332e0", size = 10453333, upload-time = "2026-02-26T20:04:20.093Z" }, + { url = "https://files.pythonhosted.org/packages/ce/5d/6a1f271f6e31dffb31855996493641edc3eef8077b883eaf007a2f1c2976/ruff-0.15.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:5a1632c66672b8b4d3e1d1782859e98d6e0b4e70829530666644286600a33992", size = 10853356, upload-time = "2026-02-26T20:04:05.808Z" }, + { url = "https://files.pythonhosted.org/packages/b1/d8/0fab9f8842b83b1a9c2bf81b85063f65e93fb512e60effa95b0be49bfc54/ruff-0.15.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:a4386ba2cd6c0f4ff75252845906acc7c7c8e1ac567b7bc3d373686ac8c222ba", size = 10187434, upload-time = "2026-02-26T20:03:54.656Z" }, + { url = "https://files.pythonhosted.org/packages/85/cc/cc220fd9394eff5db8d94dec199eec56dd6c9f3651d8869d024867a91030/ruff-0.15.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2496488bdfd3732747558b6f95ae427ff066d1fcd054daf75f5a50674411e75", size = 10535456, upload-time = "2026-02-26T20:03:52.738Z" }, + { url = "https://files.pythonhosted.org/packages/fa/0f/bced38fa5cf24373ec767713c8e4cadc90247f3863605fb030e597878661/ruff-0.15.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3f1c4893841ff2d54cbda1b2860fa3260173df5ddd7b95d370186f8a5e66a4ac", size = 10287772, upload-time = "2026-02-26T20:04:08.138Z" }, + { url = "https://files.pythonhosted.org/packages/2b/90/58a1802d84fed15f8f281925b21ab3cecd813bde52a8ca033a4de8ab0e7a/ruff-0.15.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:820b8766bd65503b6c30aaa6331e8ef3a6e564f7999c844e9a547c40179e440a", size = 11049051, upload-time = "2026-02-26T20:04:03.53Z" }, + { url = "https://files.pythonhosted.org/packages/d2/ac/b7ad36703c35f3866584564dc15f12f91cb1a26a897dc2fd13d7cb3ae1af/ruff-0.15.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9fb74bab47139c1751f900f857fa503987253c3ef89129b24ed375e72873e85", size = 11890494, upload-time = "2026-02-26T20:04:10.497Z" }, + { url = "https://files.pythonhosted.org/packages/93/3d/3eb2f47a39a8b0da99faf9c54d3eb24720add1e886a5309d4d1be73a6380/ruff-0.15.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f80c98765949c518142b3a50a5db89343aa90f2c2bf7799de9986498ae6176db", size = 11326221, upload-time = "2026-02-26T20:04:12.84Z" }, + { url = "https://files.pythonhosted.org/packages/ff/90/bf134f4c1e5243e62690e09d63c55df948a74084c8ac3e48a88468314da6/ruff-0.15.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:451a2e224151729b3b6c9ffb36aed9091b2996fe4bdbd11f47e27d8f2e8888ec", size = 11168459, upload-time = "2026-02-26T20:04:00.969Z" }, + { url = "https://files.pythonhosted.org/packages/b5/e5/a64d27688789b06b5d55162aafc32059bb8c989c61a5139a36e1368285eb/ruff-0.15.4-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:a8f157f2e583c513c4f5f896163a93198297371f34c04220daf40d133fdd4f7f", size = 11104366, upload-time = "2026-02-26T20:03:48.099Z" }, + { url = "https://files.pythonhosted.org/packages/f1/f6/32d1dcb66a2559763fc3027bdd65836cad9eb09d90f2ed6a63d8e9252b02/ruff-0.15.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:917cc68503357021f541e69b35361c99387cdbbf99bd0ea4aa6f28ca99ff5338", size = 10510887, upload-time = "2026-02-26T20:03:45.771Z" }, + { url = "https://files.pythonhosted.org/packages/ff/92/22d1ced50971c5b6433aed166fcef8c9343f567a94cf2b9d9089f6aa80fe/ruff-0.15.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:e9737c8161da79fd7cfec19f1e35620375bd8b2a50c3e77fa3d2c16f574105cc", size = 10285939, upload-time = "2026-02-26T20:04:22.42Z" }, + { url = "https://files.pythonhosted.org/packages/e6/f4/7c20aec3143837641a02509a4668fb146a642fd1211846634edc17eb5563/ruff-0.15.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:291258c917539e18f6ba40482fe31d6f5ac023994ee11d7bdafd716f2aab8a68", size = 10765471, upload-time = "2026-02-26T20:03:58.924Z" }, + { url = "https://files.pythonhosted.org/packages/d0/09/6d2f7586f09a16120aebdff8f64d962d7c4348313c77ebb29c566cefc357/ruff-0.15.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:3f83c45911da6f2cd5936c436cf86b9f09f09165f033a99dcf7477e34041cbc3", size = 11263382, upload-time = "2026-02-26T20:04:24.424Z" }, + { url = "https://files.pythonhosted.org/packages/1b/fa/2ef715a1cd329ef47c1a050e10dee91a9054b7ce2fcfdd6a06d139afb7ec/ruff-0.15.4-py3-none-win32.whl", hash = "sha256:65594a2d557d4ee9f02834fcdf0a28daa8b3b9f6cb2cb93846025a36db47ef22", size = 10506664, upload-time = "2026-02-26T20:03:50.56Z" }, + { url = "https://files.pythonhosted.org/packages/d0/a8/c688ef7e29983976820d18710f955751d9f4d4eb69df658af3d006e2ba3e/ruff-0.15.4-py3-none-win_amd64.whl", hash = "sha256:04196ad44f0df220c2ece5b0e959c2f37c777375ec744397d21d15b50a75264f", size = 11651048, upload-time = "2026-02-26T20:04:17.191Z" }, + { url = "https://files.pythonhosted.org/packages/3e/0a/9e1be9035b37448ce2e68c978f0591da94389ade5a5abafa4cf99985d1b2/ruff-0.15.4-py3-none-win_arm64.whl", hash = "sha256:60d5177e8cfc70e51b9c5fad936c634872a74209f934c1e79107d11787ad5453", size = 10966776, upload-time = "2026-02-26T20:03:56.908Z" }, ] [[package]] @@ -2808,18 +2810,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/4a/91/48db081e7a63bb37284f9fbcefda7c44c277b18b0e13fbc36ea2335b71e6/typer-0.24.1-py3-none-any.whl", hash = "sha256:112c1f0ce578bfb4cab9ffdabc68f031416ebcc216536611ba21f04e9aa84c9e", size = 56085, upload-time = "2026-02-21T16:54:41.616Z" }, ] -[[package]] -name = "typer-slim" -version = "0.24.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typer" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a7/a7/e6aecc4b4eb59598829a3b5076a93aff291b4fdaa2ded25efc4e1f4d219c/typer_slim-0.24.0.tar.gz", hash = "sha256:f0ed36127183f52ae6ced2ecb2521789995992c521a46083bfcdbb652d22ad34", size = 4776, upload-time = "2026-02-16T22:08:51.2Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a7/24/5480c20380dfd18cf33d14784096dca45a24eae6102e91d49a718d3b6855/typer_slim-0.24.0-py3-none-any.whl", hash = "sha256:d5d7ee1ee2834d5020c7c616ed5e0d0f29b9a4b1dd283bdebae198ec09778d0e", size = 3394, upload-time = "2026-02-16T22:08:49.92Z" }, -] - [[package]] name = "typing-extensions" version = "4.15.0" diff --git a/apps/agentstack-server/Dockerfile b/apps/agentstack-server/Dockerfile index 41548eb141..4788a9fbe9 100644 --- a/apps/agentstack-server/Dockerfile +++ b/apps/agentstack-server/Dockerfile @@ -6,6 +6,7 @@ ENV UV_COMPILE_BYTECODE=1 \ UV_LINK_MODE=copy \ HOME="/tmp" \ AGENT_REGISTRY__LOCATIONS__FILE="file:///app/registry.yaml" +RUN apk add bash git nodejs npm RUN --mount=type=cache,target=/tmp/.cache/uv \ --mount=type=bind,source=dist/requirements.txt,target=/requirements.txt \ --mount=type=bind,from=uv,source=/uv,target=/bin/uv \ diff --git a/apps/agentstack-server/src/agentstack_server/api/auth/auth.py b/apps/agentstack-server/src/agentstack_server/api/auth/auth.py index b4924e2677..11da6afe47 100644 --- a/apps/agentstack-server/src/agentstack_server/api/auth/auth.py +++ b/apps/agentstack-server/src/agentstack_server/api/auth/auth.py @@ -246,7 +246,7 @@ async def validate_jwt(token: str, *, provider: OidcProvider, aud: Iterable[str] "aud": {"essential": True, "values": aud}, }, ) - claims.validate() + claims.validate(leeway=5) return claims except Exception as e: return e # Cache exception response diff --git a/apps/agentstack-server/src/agentstack_server/api/routes/a2a.py b/apps/agentstack-server/src/agentstack_server/api/routes/a2a.py index fc31db2adf..159e6f9386 100644 --- a/apps/agentstack-server/src/agentstack_server/api/routes/a2a.py +++ b/apps/agentstack-server/src/agentstack_server/api/routes/a2a.py @@ -3,7 +3,7 @@ from __future__ import annotations -from typing import Annotated +from typing import Annotated, Any from urllib.parse import urljoin from uuid import UUID @@ -11,9 +11,10 @@ import fastapi.responses from a2a.server.apps import A2AFastAPIApplication from a2a.server.apps.rest.rest_adapter import RESTAdapter -from a2a.types import AgentCard, AgentInterface, HTTPAuthSecurityScheme, SecurityScheme, TransportProtocol -from a2a.utils import AGENT_CARD_WELL_KNOWN_PATH +from a2a.types import AgentCard, AgentInterface, HTTPAuthSecurityScheme, SecurityRequirement, SecurityScheme +from a2a.utils.constants import AGENT_CARD_WELL_KNOWN_PATH from fastapi import Depends, HTTPException, Request, Response +from google.protobuf.json_format import MessageToDict, ParseDict from agentstack_server.api.dependencies import ( A2AProxyServiceDependency, @@ -29,13 +30,12 @@ def create_proxy_agent_card( - agent_card: AgentCard, *, provider_id: UUID, request: Request, configuration: Configuration + agent_card: dict[str, Any], *, provider_id: UUID, request: Request, configuration: Configuration ) -> AgentCard: proxy_base = str(request.url_for(a2a_proxy_jsonrpc_transport.__name__, provider_id=provider_id)) - proxy_security = [] proxy_security_schemes = { "platform_context_token": SecurityScheme( - HTTPAuthSecurityScheme( + http_auth_security_scheme=HTTPAuthSecurityScheme( scheme="bearer", bearer_format="JWT", description="Platform context token, issued by the AgentStack server using POST /api/v1/context/{context_id}/token.", @@ -43,29 +43,46 @@ def create_proxy_agent_card( ) } + proxy_security = [] + if not configuration.auth.disable_auth: # Note that we're purposefully not using oAuth but a more generic http scheme. # This is because we don't want to declare the auth metadata but prefer discovery through related RFCs # The http scheme also covers internal jwt tokens - proxy_security.append({"bearer": []}) - proxy_security_schemes["bearer"] = SecurityScheme(HTTPAuthSecurityScheme(scheme="bearer")) + req = SecurityRequirement() + req.schemes["bearer"].list.extend([]) + proxy_security.append(req) + proxy_security_schemes["bearer"] = SecurityScheme( + http_auth_security_scheme=HTTPAuthSecurityScheme(scheme="bearer") + ) if configuration.auth.basic.enabled: - proxy_security.append({"basic": []}) - proxy_security_schemes["basic"] = SecurityScheme(HTTPAuthSecurityScheme(scheme="basic")) - - return agent_card.model_copy( - update={ - "preferred_transport": TransportProtocol.jsonrpc, - "url": proxy_base, - "additional_interfaces": [ - AgentInterface(transport=TransportProtocol.http_json, url=urljoin(proxy_base, "http")), - AgentInterface(transport=TransportProtocol.jsonrpc, url=proxy_base), - ], - "security": proxy_security, - "security_schemes": proxy_security_schemes, - } + req_basic = SecurityRequirement() + req_basic.schemes["basic"].list.extend([]) + proxy_security.append(req_basic) + proxy_security_schemes["basic"] = SecurityScheme( + http_auth_security_scheme=HTTPAuthSecurityScheme(scheme="basic") + ) + + card_copy = AgentCard() + card_copy = ParseDict(agent_card, card_copy, ignore_unknown_fields=True) + + del card_copy.supported_interfaces[:] + card_copy.supported_interfaces.extend( + [ + AgentInterface(protocol_binding="HTTP+JSON", url=urljoin(proxy_base, "http")), + AgentInterface(protocol_binding="JSONRPC", url=proxy_base), + ] ) + del card_copy.security_requirements[:] + card_copy.security_requirements.extend(proxy_security) + + card_copy.security_schemes.clear() + for k, v in proxy_security_schemes.items(): + card_copy.security_schemes[k].CopyFrom(v) + + return card_copy + @router.get("/{provider_id}" + AGENT_CARD_WELL_KNOWN_PATH) async def get_agent_card( @@ -74,16 +91,17 @@ async def get_agent_card( provider_service: ProviderServiceDependency, configuration: ConfigurationDependency, user: Annotated[AuthorizedUser, Depends(authorized_user)], -) -> AgentCard: +) -> dict[str, Any]: try: user = RequiresPermissions(providers={"read"})(user) # try provider read permissions except HTTPException: user = RequiresPermissions(a2a_proxy={provider_id})(user) # try a2a proxy permissions provider = await provider_service.get_provider(provider_id=provider_id) - return create_proxy_agent_card( + card_copy = create_proxy_agent_card( provider.agent_card, provider_id=provider.id, request=request, configuration=configuration ) + return MessageToDict(card_copy, preserving_proto_field_name=True) @router.post("/{provider_id}") diff --git a/apps/agentstack-server/src/agentstack_server/api/routes/providers.py b/apps/agentstack-server/src/agentstack_server/api/routes/providers.py index c6756b0b57..b809c8ea22 100644 --- a/apps/agentstack-server/src/agentstack_server/api/routes/providers.py +++ b/apps/agentstack-server/src/agentstack_server/api/routes/providers.py @@ -2,13 +2,14 @@ # SPDX-License-Identifier: Apache-2.0 from __future__ import annotations -from typing import Annotated +from typing import Annotated, Any from uuid import UUID import fastapi from fastapi import HTTPException, status from fastapi.params import Depends, Query from fastapi.requests import Request +from google.protobuf.json_format import MessageToDict from pydantic import TypeAdapter from starlette.responses import StreamingResponse @@ -17,10 +18,11 @@ ProviderServiceDependency, RequiresPermissions, ) -from agentstack_server.api.routes.a2a import create_proxy_agent_card +from agentstack_server.api.routes.a2a import create_proxy_agent_card as create_proxy_agent_card_ from agentstack_server.api.schema.common import EntityModel from agentstack_server.api.schema.env import ListVariablesSchema, UpdateVariablesRequest from agentstack_server.api.schema.provider import CreateProviderRequest, PatchProviderRequest +from agentstack_server.configuration import Configuration from agentstack_server.domain.models.common import PaginatedResult from agentstack_server.domain.models.permissions import AuthorizedUser from agentstack_server.domain.models.provider import ProviderLocation, ProviderWithState @@ -29,6 +31,14 @@ router = fastapi.APIRouter() +def create_proxy_agent_card( + agent_card: dict[str, Any], provider_id: UUID, request: Request, configuration: Configuration +) -> dict[str, Any]: + return MessageToDict( + create_proxy_agent_card_(agent_card, provider_id=provider_id, request=request, configuration=configuration) + ) + + @router.post("") async def create_provider( user: Annotated[AuthorizedUser, Depends(RequiresPermissions(providers={"write"}))], diff --git a/apps/agentstack-server/src/agentstack_server/api/schema/provider.py b/apps/agentstack-server/src/agentstack_server/api/schema/provider.py index ca3f10078f..a17fabeb76 100644 --- a/apps/agentstack-server/src/agentstack_server/api/schema/provider.py +++ b/apps/agentstack-server/src/agentstack_server/api/schema/provider.py @@ -5,8 +5,8 @@ from __future__ import annotations from datetime import timedelta +from typing import Any -from a2a.types import AgentCard from pydantic import BaseModel, Field from agentstack_server.domain.constants import DEFAULT_AUTO_STOP_TIMEOUT @@ -15,7 +15,7 @@ class CreateProviderRequest(BaseModel): location: ProviderLocation - agent_card: AgentCard | None = None + agent_card: dict[str, Any] | None = None variables: dict[str, str] | None = None origin: str | None = Field( default=None, @@ -41,7 +41,7 @@ def auto_stop_timeout(self) -> timedelta: class PatchProviderRequest(BaseModel): location: ProviderLocation | None = None - agent_card: AgentCard | None = None + agent_card: dict[str, Any] | None = None variables: dict[str, str] | None = None origin: str | None = Field( default=None, diff --git a/apps/agentstack-server/src/agentstack_server/domain/models/context.py b/apps/agentstack-server/src/agentstack_server/domain/models/context.py index c150d139a6..89ccf80019 100644 --- a/apps/agentstack-server/src/agentstack_server/domain/models/context.py +++ b/apps/agentstack-server/src/agentstack_server/domain/models/context.py @@ -3,16 +3,15 @@ from __future__ import annotations from enum import StrEnum -from typing import Literal +from typing import Any, Literal from uuid import UUID, uuid4 -from a2a.types import Artifact, Message from pydantic import AwareDatetime, BaseModel, Field, computed_field from agentstack_server.domain.models.common import Metadata from agentstack_server.utils.utils import utc_now -type ContextHistoryItemData = Artifact | Message +ContextHistoryItemData = dict[str, Any] class ContextHistoryItem(BaseModel): @@ -24,7 +23,7 @@ class ContextHistoryItem(BaseModel): @computed_field @property def kind(self) -> Literal["message", "artifact"]: - return getattr(self.data, "kind", "artifact") + return "artifact" if "artifact_id" in self.data else "message" class Context(BaseModel): diff --git a/apps/agentstack-server/src/agentstack_server/domain/models/provider.py b/apps/agentstack-server/src/agentstack_server/domain/models/provider.py index 4cb9ae7972..a6efe44261 100644 --- a/apps/agentstack-server/src/agentstack_server/domain/models/provider.py +++ b/apps/agentstack-server/src/agentstack_server/domain/models/provider.py @@ -1,6 +1,5 @@ # Copyright 2025 © BeeAI a Series of LF Projects, LLC # SPDX-License-Identifier: Apache-2.0 - from __future__ import annotations import base64 @@ -15,6 +14,7 @@ from a2a.types import AgentCard from a2a.utils import AGENT_CARD_WELL_KNOWN_PATH +from google.protobuf.json_format import ParseDict from httpx import AsyncClient from kink import di from pydantic import ( @@ -80,14 +80,14 @@ async def get_resolved_version(self) -> ResolvedDockerImageID: async def get_version_info(self) -> VersionInfo: return VersionInfo(docker=await self.get_resolved_version()) - async def load_agent_card(self) -> AgentCard: - from a2a.types import AgentCard - + async def load_agent_card(self) -> dict[str, Any]: resolved_version = await self.get_resolved_version() labels = await resolved_version.get_labels() if DOCKER_MANIFEST_LABEL_NAME not in labels: raise MissingAgentCardLabelError(str(self.root)) - return AgentCard.model_validate(json.loads(base64.b64decode(labels[DOCKER_MANIFEST_LABEL_NAME]))) + data = json.loads(base64.b64decode(labels[DOCKER_MANIFEST_LABEL_NAME])) + ParseDict(data, AgentCard()) # try at least parsing card, TODO: validation of required fields + return data class NetworkProviderLocation(RootModel): @@ -135,18 +135,18 @@ def provider_id(self) -> UUID: location_digest = hashlib.sha256(str(self.root).encode()).digest() return UUID(bytes=location_digest[:16]) - async def load_agent_card(self) -> AgentCard: - from a2a.types import AgentCard - + async def load_agent_card(self) -> dict[str, Any]: async with AsyncClient() as client: try: response = await client.get(urljoin(str(self.a2a_url), AGENT_CARD_WELL_KNOWN_PATH), timeout=1) response.raise_for_status() - card = AgentCard.model_validate(response.json()) + card = response.json() if ext := get_extension(card, SELF_REGISTRATION_EXTENSION_URI): - assert ext.params - self_registration_id = ext.params["self_registration_id"] - if quote(self.root.fragment or "", safe="") != quote(self_registration_id, safe=""): + params = ext.get("params", {}) + self_registration_id = params.get("self_registration_id") + if self_registration_id and quote(self.root.fragment or "", safe="") != quote( + self_registration_id, safe="" + ): raise ValueError( f"Self registration id does not match: {self.root.fragment} != {self_registration_id}" ) @@ -185,7 +185,7 @@ class Provider(BaseModel): updated_at: AwareDatetime = Field(default_factory=utc_now) created_by: UUID last_active_at: AwareDatetime = Field(default_factory=utc_now) - agent_card: AgentCard + agent_card: dict[str, Any] unmanaged_state: UnmanagedState | None = Field(default=None, exclude=True) @computed_field @@ -208,7 +208,7 @@ def managed(self) -> bool: @property def env(self) -> list[EnvVar]: if agent_detail := get_extension(self.agent_card, AGENT_DETAIL_EXTENSION_URI): - variables = agent_detail.model_dump()["params"].get("variables") or [] + variables = agent_detail.get("params", {}).get("variables", []) or [] return [EnvVar.model_validate(v) for v in variables] return [] diff --git a/apps/agentstack-server/src/agentstack_server/domain/models/provider_discovery.py b/apps/agentstack-server/src/agentstack_server/domain/models/provider_discovery.py index f2af76f3bc..76a7afe562 100644 --- a/apps/agentstack-server/src/agentstack_server/domain/models/provider_discovery.py +++ b/apps/agentstack-server/src/agentstack_server/domain/models/provider_discovery.py @@ -4,9 +4,9 @@ from __future__ import annotations from enum import StrEnum +from typing import Any from uuid import UUID, uuid4 -from a2a.types import AgentCard from pydantic import AwareDatetime, BaseModel, Field from agentstack_server.utils.utils import utc_now @@ -25,5 +25,5 @@ class ProviderDiscovery(BaseModel): status: DiscoveryState docker_image: str created_by: UUID - agent_card: AgentCard | None = None + agent_card: dict[str, Any] | None = None error_message: str | None = None diff --git a/apps/agentstack-server/src/agentstack_server/infrastructure/persistence/repositories/context.py b/apps/agentstack-server/src/agentstack_server/infrastructure/persistence/repositories/context.py index a1a9c35af8..55cb78f525 100644 --- a/apps/agentstack-server/src/agentstack_server/infrastructure/persistence/repositories/context.py +++ b/apps/agentstack-server/src/agentstack_server/infrastructure/persistence/repositories/context.py @@ -186,7 +186,7 @@ async def add_history_item(self, *, context_id: UUID, history_item: ContextHisto id=uuid4(), context_id=history_item.context_id, created_at=history_item.created_at, - data=history_item.data.model_dump(), + data=history_item.data, ) await self._connection.execute(query) diff --git a/apps/agentstack-server/src/agentstack_server/infrastructure/persistence/repositories/provider.py b/apps/agentstack-server/src/agentstack_server/infrastructure/persistence/repositories/provider.py index 36b7caf313..e8e6eca9d4 100644 --- a/apps/agentstack-server/src/agentstack_server/infrastructure/persistence/repositories/provider.py +++ b/apps/agentstack-server/src/agentstack_server/infrastructure/persistence/repositories/provider.py @@ -69,7 +69,7 @@ def _to_row(self, provider: Provider) -> dict[str, Any]: "origin": provider.origin, "version_info": provider.version_info.model_dump(mode="json"), "registry": provider.registry and str(provider.registry.root), - "agent_card": provider.agent_card.model_dump(mode="json"), + "agent_card": provider.agent_card, "created_at": provider.created_at, "updated_at": provider.updated_at, "created_by": provider.created_by, diff --git a/apps/agentstack-server/src/agentstack_server/infrastructure/persistence/repositories/provider_discovery.py b/apps/agentstack-server/src/agentstack_server/infrastructure/persistence/repositories/provider_discovery.py index c027625e16..248658c35b 100644 --- a/apps/agentstack-server/src/agentstack_server/infrastructure/persistence/repositories/provider_discovery.py +++ b/apps/agentstack-server/src/agentstack_server/infrastructure/persistence/repositories/provider_discovery.py @@ -90,7 +90,7 @@ def _to_row(self, discovery: ProviderDiscovery) -> dict[str, Any]: "status": discovery.status, "docker_image": discovery.docker_image, "created_by": discovery.created_by, - "agent_card": discovery.agent_card.model_dump(mode="json") if discovery.agent_card else None, + "agent_card": discovery.agent_card, "error_message": discovery.error_message, } diff --git a/apps/agentstack-server/src/agentstack_server/infrastructure/persistence/repositories/requests.py b/apps/agentstack-server/src/agentstack_server/infrastructure/persistence/repositories/requests.py index 7fbbe318b9..540b529b98 100644 --- a/apps/agentstack-server/src/agentstack_server/infrastructure/persistence/repositories/requests.py +++ b/apps/agentstack-server/src/agentstack_server/infrastructure/persistence/repositories/requests.py @@ -79,6 +79,9 @@ async def track_request_ids_ownership( # - Existing owned by OTHER user: ON CONFLICT WHERE clause prevents update, returns false now = utc_now() + task_id = task_id or None + context_id = context_id or None + trace_id = trace_id or None query = text(""" WITH task_insert AS ( diff --git a/apps/agentstack-server/src/agentstack_server/jobs/crons/provider.py b/apps/agentstack-server/src/agentstack_server/jobs/crons/provider.py index 20b2a00b9b..a01fc7d87a 100644 --- a/apps/agentstack-server/src/agentstack_server/jobs/crons/provider.py +++ b/apps/agentstack-server/src/agentstack_server/jobs/crons/provider.py @@ -7,7 +7,6 @@ from datetime import timedelta import httpx -from a2a.types import AgentCard from a2a.utils import AGENT_CARD_WELL_KNOWN_PATH from httpx import HTTPError from kink import inject @@ -145,16 +144,14 @@ async def _check_provider(provider: Provider): try: assert isinstance(provider.source, NetworkProviderLocation) async with httpx.AsyncClient(base_url=str(provider.source.a2a_url), timeout=timeout_sec) as client: - resp_card = AgentCard.model_validate( - (await client.get(AGENT_CARD_WELL_KNOWN_PATH)).raise_for_status().json() - ) + resp_card = (await client.get(AGENT_CARD_WELL_KNOWN_PATH)).raise_for_status().json() # For self-registered provider we need to check their self-registration ID, because their URL # might overlap (more agents on the same URL, only one can be online) provider_self_reg_ext = get_extension(provider.agent_card, SELF_REGISTRATION_EXTENSION_URI) resp_self_reg_ext = get_extension(resp_card, SELF_REGISTRATION_EXTENSION_URI) if provider_self_reg_ext is not None and resp_self_reg_ext is not None: - if provider_self_reg_ext.params == resp_self_reg_ext.params: + if provider_self_reg_ext["params"] == resp_self_reg_ext["params"]: state = UnmanagedState.ONLINE else: # Different agent responding at the same URL, don't update this provider diff --git a/apps/agentstack-server/src/agentstack_server/service_layer/services/a2a.py b/apps/agentstack-server/src/agentstack_server/service_layer/services/a2a.py index b17e769869..8c0c7de715 100644 --- a/apps/agentstack-server/src/agentstack_server/service_layer/services/a2a.py +++ b/apps/agentstack-server/src/agentstack_server/service_layer/services/a2a.py @@ -10,7 +10,7 @@ from collections.abc import AsyncGenerator, AsyncIterable, AsyncIterator, Awaitable, Callable, Coroutine, Iterator from contextlib import asynccontextmanager, contextmanager from datetime import timedelta -from typing import Any, NamedTuple, cast, overload +from typing import Any, NamedTuple, cast, overload, override from urllib.parse import urljoin, urlparse from uuid import UUID @@ -21,26 +21,32 @@ from a2a.client.transports.base import ClientTransport from a2a.server.context import ServerCallContext from a2a.server.events import Event +from a2a.server.request_handlers.jsonrpc_handler import ERROR_CODE_MAP from a2a.server.request_handlers.request_handler import RequestHandler from a2a.types import ( AgentCard, - DeleteTaskPushNotificationConfigParams, - GetTaskPushNotificationConfigParams, + AgentInterface, + CancelTaskRequest, + CreateTaskPushNotificationConfigRequest, + DeleteTaskPushNotificationConfigRequest, + GetTaskPushNotificationConfigRequest, + GetTaskRequest, InternalError, InvalidRequestError, - ListTaskPushNotificationConfigParams, + ListTaskPushNotificationConfigsRequest, + ListTaskPushNotificationConfigsResponse, + ListTasksRequest, + ListTasksResponse, Message, - MessageSendParams, + SendMessageRequest, + StreamResponse, + SubscribeToTaskRequest, Task, - TaskArtifactUpdateEvent, - TaskIdParams, TaskNotFoundError, TaskPushNotificationConfig, - TaskQueryParams, - TaskStatusUpdateEvent, - TransportProtocol, ) from a2a.utils.errors import ServerError +from google.protobuf.json_format import ParseDict from kink import inject from opentelemetry import trace from pydantic import HttpUrl @@ -67,42 +73,33 @@ logger = logging.getLogger(__name__) -_SUPPORTED_TRANSPORTS = {TransportProtocol.http_json, TransportProtocol.jsonrpc} +_SUPPORTED_TRANSPORTS = {"HTTP+JSON", "JSONRPC"} def _create_deploy_a2a_url(url: str, *, deployment_base: str) -> str: return urljoin(deployment_base, urlparse(url).path.lstrip("/")) -def create_deployment_agent_card(agent_card: AgentCard, *, deployment_base: str) -> AgentCard: - proxy_interfaces = ( - [ - interface.model_copy(update={"url": _create_deploy_a2a_url(interface.url, deployment_base=deployment_base)}) - for interface in agent_card.additional_interfaces - if interface.transport in _SUPPORTED_TRANSPORTS - ] - if agent_card.additional_interfaces is not None - else None - ) - if agent_card.preferred_transport in _SUPPORTED_TRANSPORTS: - return agent_card.model_copy( - update={ - "url": _create_deploy_a2a_url(agent_card.url, deployment_base=deployment_base), - "additional_interfaces": proxy_interfaces, - } - ) - elif proxy_interfaces: - interface = proxy_interfaces[0] - return agent_card.model_copy( - update={ - "url": interface.url, - "preferred_transport": interface.transport, - "additional_interfaces": proxy_interfaces, - } - ) - else: +def create_deployment_agent_card(agent_card: dict[str, Any], *, deployment_base: str) -> AgentCard: + card_copy = AgentCard() + ParseDict(agent_card, card_copy, ignore_unknown_fields=True) + + new_interfaces = [] + for interface in card_copy.supported_interfaces: + if interface.protocol_binding in _SUPPORTED_TRANSPORTS: + new_interface = AgentInterface() + new_interface.CopyFrom(interface) + new_interface.url = _create_deploy_a2a_url(interface.url, deployment_base=deployment_base) + new_interfaces.append(new_interface) + + if not new_interfaces: raise RuntimeError("Provider doesn't have any transport supported by the proxy.") + del card_copy.supported_interfaces[:] + card_copy.supported_interfaces.extend(new_interfaces) + + return card_copy + class A2AServerResponse(NamedTuple): content: bytes | None @@ -134,6 +131,12 @@ def _handle_exception_impl() -> Iterator[None]: except ForbiddenUpdateError as e: raise ServerError(error=InvalidRequestError(message=str(e))) from e except A2AClientJSONRPCError as e: + if ( + isinstance(e.error, dict) + and "code" in e.error + and (error_cls := {v: k for k, v in ERROR_CODE_MAP.items()}.get(e.error["code"])) + ): + raise ServerError(error=error_cls(e.error.get("message"))) from e raise ServerError(error=e.error) from e except InvalidProviderCallError as e: raise ServerError(error=InvalidRequestError(message=f"Invalid request to agent: {e!r}")) from e @@ -194,7 +197,7 @@ async def _client_transport(self, context: ServerCallContext | None = None) -> A if auth_header := headers.get("authorization"): _scheme, header_token = get_authorization_scheme_param(auth_header) try: - audience = create_resource_uri(URL(self._agent_card.url)) + audience = create_resource_uri(URL(self._agent_card.supported_interfaces[0].url)) token, _ = exchange_internal_jwt(header_token, self._configuration, audience=[audience]) headers["authorization"] = f"Bearer {token}" except Exception: @@ -244,21 +247,45 @@ async def _check_and_record_request( def _forward_context(self, context: ServerCallContext | None = None) -> ClientCallContext: return ClientCallContext(state={**(context.state if context else {}), "user_id": self._user.id}) + def _response_to_event(self, response: StreamResponse) -> tuple[str, str, Event]: + if response.HasField("status_update"): + task_id = response.status_update.task_id + context_id = response.status_update.context_id + result_event = response.status_update + elif response.HasField("artifact_update"): + task_id = response.artifact_update.task_id + context_id = response.artifact_update.context_id + result_event = response.artifact_update + elif response.HasField("task"): + task_id = response.task.id + context_id = response.task.context_id + result_event = response.task + elif response.HasField("message"): + task_id = response.message.task_id + context_id = response.message.context_id + result_event = response.message + else: + raise ValueError("Unknown event type") + return task_id, context_id, result_event + @_handle_exception - async def on_get_task(self, params: TaskQueryParams, context: ServerCallContext | None = None) -> Task | None: + @override + async def on_get_task(self, params: GetTaskRequest, context: ServerCallContext | None = None) -> Task | None: await self._check_task(params.id) async with self._client_transport(context) as transport: return await transport.get_task(params, context=self._forward_context(context)) @_handle_exception - async def on_cancel_task(self, params: TaskIdParams, context: ServerCallContext | None = None) -> Task | None: + @override + async def on_cancel_task(self, params: CancelTaskRequest, context: ServerCallContext | None = None) -> Task | None: await self._check_task(params.id) async with self._client_transport(context) as transport: return await transport.cancel_task(params, context=self._forward_context(context)) @_handle_exception + @override async def on_message_send( - self, params: MessageSendParams, context: ServerCallContext | None = None + self, params: SendMessageRequest, context: ServerCallContext | None = None ) -> Task | Message: # we set task_id and context_id if not configured with trace.get_tracer(INSTRUMENTATION_NAME).start_as_current_span("on_message_send") as span: @@ -268,17 +295,18 @@ async def on_message_send( async with self._client_transport(context) as transport: response = await transport.send_message(params, context=self._forward_context(context)) - match response: - case Task(id=task_id) | Message(task_id=task_id): - if params.message.task_id is None and task_id: - await self._check_and_record_request( - task_id, params.message.context_id, allow_task_creation=True, trace_id=trace_id - ) - return response + if task_id := response.task.id or response.message.task_id: + await self._check_and_record_request( + task_id, params.message.context_id, allow_task_creation=True, trace_id=trace_id + ) + if response.HasField("task"): + return response.task + return response.message @_handle_exception + @override async def on_message_send_stream( - self, params: MessageSendParams, context: ServerCallContext | None = None + self, params: SendMessageRequest, context: ServerCallContext | None = None ) -> AsyncGenerator[Event]: with trace.get_tracer(INSTRUMENTATION_NAME).start_as_current_span("on_message_send_stream") as span: # we set task_id and context_id if not configured @@ -290,29 +318,24 @@ async def on_message_send_stream( async with self._client_transport(context) as transport: async for event in transport.send_message_streaming(params, context=self._forward_context(context)): - match event: - case ( - TaskStatusUpdateEvent(task_id=task_id, context_id=context_id) - | TaskArtifactUpdateEvent(task_id=task_id, context_id=context_id) - | Task(id=task_id, context_id=context_id) - | Message(task_id=task_id, context_id=context_id) - ): - if context_id != params.message.context_id: - raise RuntimeError(f"Unexpected context_id returned from the agent: {context_id}") - if task_id and task_id not in seen_tasks: - await self._check_and_record_request( - task_id=task_id, - context_id=context_id, - trace_id=trace_id, - allow_task_creation=True, - ) - seen_tasks.add(task_id) - yield event + task_id, context_id, result_event = self._response_to_event(event) + if context_id != params.message.context_id: + raise RuntimeError(f"Unexpected context_id returned from the agent: {context_id}") + if task_id and task_id not in seen_tasks: + await self._check_and_record_request( + task_id=task_id, + trace_id=trace_id, + context_id=context_id, + allow_task_creation=True, + ) + seen_tasks.add(task_id) + yield result_event @_handle_exception - async def on_set_task_push_notification_config( + @override + async def on_create_task_push_notification_config( self, - params: TaskPushNotificationConfig, + params: CreateTaskPushNotificationConfigRequest, context: ServerCallContext | None = None, ) -> TaskPushNotificationConfig: await self._check_task(params.task_id) @@ -320,41 +343,57 @@ async def on_set_task_push_notification_config( return await transport.set_task_callback(params) @_handle_exception + @override async def on_get_task_push_notification_config( self, - params: TaskIdParams | GetTaskPushNotificationConfigParams, + params: GetTaskPushNotificationConfigRequest, context: ServerCallContext | None = None, ) -> TaskPushNotificationConfig: - await self._check_task(params.id) + await self._check_task(params.task_id) async with self._client_transport(context) as transport: - if isinstance(params, TaskIdParams): - params = GetTaskPushNotificationConfigParams(id=params.id, metadata=params.metadata) return await transport.get_task_callback(params, context=self._forward_context(context)) @_handle_exception - async def on_resubscribe_to_task( - self, params: TaskIdParams, context: ServerCallContext | None = None + @override + async def on_subscribe_to_task( + self, + params: SubscribeToTaskRequest, + context: ServerCallContext | None = None, ) -> AsyncGenerator[Event]: await self._check_task(params.id) async with self._client_transport(context) as transport: - async for event in transport.resubscribe(params): - yield event + async for event in transport.subscribe(params): + _, _, result_event = self._response_to_event(event) + yield result_event @_handle_exception - async def on_list_task_push_notification_config( + @override + async def on_list_task_push_notification_configs( self, - params: ListTaskPushNotificationConfigParams, + params: ListTaskPushNotificationConfigsRequest, context: ServerCallContext | None = None, - ) -> list[TaskPushNotificationConfig]: + ) -> ListTaskPushNotificationConfigsResponse: raise NotImplementedError("This is not supported by the client transport yet") @_handle_exception async def on_delete_task_push_notification_config( self, - params: DeleteTaskPushNotificationConfigParams, + params: DeleteTaskPushNotificationConfigRequest, context: ServerCallContext | None = None, ) -> None: raise NotImplementedError("This is not supported by the client transport yet") + # await self._check_task(params.task_id) + # async with self._client_transport(context) as transport: + # await transport.delete_task_push_notification_config(params) + + @_handle_exception + @override + async def on_list_tasks( + self, + params: ListTasksRequest, + context: ServerCallContext | None = None, + ) -> ListTasksResponse: + raise NotImplementedError("This is not supported by the client transport yet") @inject diff --git a/apps/agentstack-server/src/agentstack_server/service_layer/services/contexts.py b/apps/agentstack-server/src/agentstack_server/service_layer/services/contexts.py index 187252007c..79f747a4b7 100644 --- a/apps/agentstack-server/src/agentstack_server/service_layer/services/contexts.py +++ b/apps/agentstack-server/src/agentstack_server/service_layer/services/contexts.py @@ -7,9 +7,9 @@ from collections.abc import Sequence from contextlib import suppress from datetime import timedelta +from typing import Any from uuid import UUID -from a2a.types import Artifact, DataPart, FilePart, FileWithBytes, FileWithUri, Message, Role, TextPart from fastapi import status from kink import inject from pydantic import TypeAdapter @@ -160,22 +160,22 @@ async def update_last_active(self, *, context_id: UUID) -> None: await uow.contexts.update_last_active(context_id=context_id) await uow.commit() - def _extract_content_for_title( - self, msg: Message | Artifact - ) -> tuple[str, str | None, Sequence[FileWithUri | FileWithBytes]]: + def _extract_content_for_title(self, msg: dict[str, Any]) -> tuple[str, str | None, Sequence[dict[str, Any]]]: title_hint: str | None = None text_parts: list[str] = [] - files: list[FileWithUri | FileWithBytes] = [] - for part in msg.parts: - match part.root: - case TextPart(text=text): - text_parts.append(text) - case DataPart(data={"title_hint": str(hint)}) if hint and not title_hint: - title_hint = hint - case FilePart(file=file): - files.append(file) - case _: - pass + files: list[dict[str, Any]] = [] + for part in msg.get("parts", []): + if "text" in part: + text_parts.append(part["text"]) + elif "data" in part: + data = part["data"] + if isinstance(data, dict): + hint = data.get("title_hint") + if isinstance(hint, str) and hint and not title_hint: + title_hint = hint + elif "file" in part: + files.append(part["file"]) + return "".join(text_parts), title_hint, files async def add_history_item(self, *, context_id: UUID, data: ContextHistoryItemData, user: User) -> None: @@ -186,7 +186,7 @@ async def add_history_item(self, *, context_id: UUID, data: ContextHistoryItemDa history_item=ContextHistoryItem(context_id=context_id, data=data), ) - if getattr(data, "role", None) == Role.user and not (context.metadata or {}).get("title"): + if data.get("role") == "ROLE_USER" and not (context.metadata or {}).get("title"): from agentstack_server.jobs.tasks.context import generate_conversation_title as task # Use simple text extraction for the initial title placeholder @@ -232,8 +232,8 @@ async def generate_conversation_title(self, *, context_id: UUID): prompt = template.render( text=text, titleHint=title_hint, - files=[file.model_dump(include={"name", "mime_type"}) for file in files], - rawMessage=raw_message.model_dump(), + files=[{"name": f.get("name"), "mime_type": f.get("mime_type")} for f in files], + rawMessage=raw_message, ) resp = await self._model_provider_service.create_chat_completion( request=ChatCompletionRequest( diff --git a/apps/agentstack-server/src/agentstack_server/service_layer/services/provider_discovery.py b/apps/agentstack-server/src/agentstack_server/service_layer/services/provider_discovery.py index 74479375a3..4d4c76f55b 100644 --- a/apps/agentstack-server/src/agentstack_server/service_layer/services/provider_discovery.py +++ b/apps/agentstack-server/src/agentstack_server/service_layer/services/provider_discovery.py @@ -7,9 +7,10 @@ import logging import uuid from datetime import timedelta +from typing import Any from uuid import UUID -from a2a.types import AgentCapabilities, AgentCard, AgentExtension +from a2a.types import AgentExtension from a2a.utils import AGENT_CARD_WELL_KNOWN_PATH from httpx import AsyncClient from kink import inject @@ -94,22 +95,12 @@ async def cleanup_expired_discoveries(self, *, max_age: timedelta | None = None) await uow.commit() return count - async def _fetch_agent_card_from_container(self, location: DockerImageProviderLocation) -> AgentCard: - placeholder_card = AgentCard( - name="discovery", - description="", - url="", - version="", - capabilities=AgentCapabilities(), - default_input_modes=["text"], - default_output_modes=["text"], - skills=[], - ) + async def _fetch_agent_card_from_container(self, location: DockerImageProviderLocation) -> dict[str, Any]: temp_provider = Provider( source=location, origin=str(location.root), created_by=uuid.UUID("00000000-0000-0000-0000-000000000000"), - agent_card=placeholder_card, + agent_card={"name": "placeholder"}, ) try: await self._deployment_manager.create_or_replace(provider=temp_provider) @@ -118,8 +109,7 @@ async def _fetch_agent_card_from_container(self, location: DockerImageProviderLo async with AsyncClient(base_url=str(url)) as client: response = await client.get(AGENT_CARD_WELL_KNOWN_PATH, timeout=10) response.raise_for_status() - agent_card = AgentCard.model_validate(response.json()) - return self._inject_default_agent_detail_extension(agent_card, location) + return self._inject_default_agent_detail_extension(response.json(), location) finally: try: await self._deployment_manager.delete(provider_id=temp_provider.id) @@ -127,8 +117,8 @@ async def _fetch_agent_card_from_container(self, location: DockerImageProviderLo logger.exception(f"Failed to delete temporary deployment for provider {temp_provider.id}") def _inject_default_agent_detail_extension( - self, agent_card: AgentCard, location: DockerImageProviderLocation - ) -> AgentCard: + self, agent_card: dict[str, Any], location: DockerImageProviderLocation + ) -> dict[str, Any]: if get_extension(agent_card, AGENT_DETAIL_EXTENSION_URI): return agent_card @@ -139,8 +129,6 @@ def _inject_default_agent_detail_extension( "container_image_url": str(location.root), }, ) - - extensions = list(agent_card.capabilities.extensions or []) - extensions.append(default_extension) - agent_card.capabilities.extensions = extensions + extensions = [*agent_card.get("capabilities", {}).get("extensions", []), default_extension] + agent_card.setdefault("capabilities", {})["extensions"] = extensions return agent_card diff --git a/apps/agentstack-server/src/agentstack_server/service_layer/services/providers.py b/apps/agentstack-server/src/agentstack_server/service_layer/services/providers.py index 0fecedde2b..da20bfbe37 100644 --- a/apps/agentstack-server/src/agentstack_server/service_layer/services/providers.py +++ b/apps/agentstack-server/src/agentstack_server/service_layer/services/providers.py @@ -10,10 +10,12 @@ import uuid from collections.abc import AsyncIterator, Callable from datetime import timedelta +from typing import Any from uuid import UUID -from a2a.types import AgentCard, AgentExtension +from a2a.types import AgentExtension from fastapi import HTTPException +from google.protobuf.json_format import MessageToDict from kink import inject from starlette.status import HTTP_400_BAD_REQUEST, HTTP_404_NOT_FOUND, HTTP_422_UNPROCESSABLE_CONTENT @@ -56,7 +58,7 @@ async def create_provider( origin: str | ResolvedGithubUrl | None = None, auto_stop_timeout: timedelta, registry: RegistryLocation | None = None, - agent_card: AgentCard | None = None, + agent_card: dict[str, Any] | None = None, variables: dict[str, str] | None = None, ) -> ProviderWithState: try: @@ -100,18 +102,20 @@ async def create_provider( [provider_response] = await self._get_providers_with_state(providers=[provider]) return provider_response - def _inject_default_agent_detail_extension(self, agent_card: AgentCard) -> AgentCard: + def _inject_default_agent_detail_extension(self, agent_card: dict[str, Any]) -> dict[str, Any]: if get_extension(agent_card, AGENT_DETAIL_EXTENSION_URI): return agent_card - default_extension = AgentExtension( - uri=AGENT_DETAIL_EXTENSION_URI, - params={"interaction_mode": "multi-turn"}, + default_extension = MessageToDict( + AgentExtension( + uri=AGENT_DETAIL_EXTENSION_URI, + params={"interaction_mode": "multi-turn"}, + ) ) - extensions = list(agent_card.capabilities.extensions or []) + extensions = list(agent_card.get("capabilities", {}).get("extensions", []) or []) extensions.append(default_extension) - agent_card.capabilities.extensions = extensions + agent_card.setdefault("capabilities", {})["extensions"] = extensions return agent_card async def patch_provider( @@ -122,7 +126,7 @@ async def patch_provider( location: ProviderLocation | None = None, auto_stop_timeout: timedelta | None = None, origin: str | ResolvedGithubUrl | None = None, - agent_card: AgentCard | None = None, + agent_card: dict[str, Any] | None = None, variables: dict[str, str] | None = None, allow_registry_update: bool = False, force: bool = False, @@ -211,7 +215,7 @@ async def patch_provider( return provider_response async def preview_provider( - self, location: ProviderLocation, agent_card: AgentCard | None = None + self, location: ProviderLocation, agent_card: dict[str, Any] | None = None ) -> ProviderWithState: try: if not agent_card: diff --git a/apps/agentstack-server/src/agentstack_server/utils/a2a.py b/apps/agentstack-server/src/agentstack_server/utils/a2a.py index a90fb51b96..55cc462bfe 100644 --- a/apps/agentstack-server/src/agentstack_server/utils/a2a.py +++ b/apps/agentstack-server/src/agentstack_server/utils/a2a.py @@ -3,12 +3,13 @@ from __future__ import annotations -from a2a.types import AgentCard, AgentExtension +from typing import Any -def get_extension(agent_card: AgentCard, uri: str) -> AgentExtension | None: +def get_extension(agent_card: dict[str, Any], uri: str) -> dict[str, Any] | None: try: - extensions = agent_card.capabilities.extensions or [] - return next(ext for ext in extensions if ext.uri == uri) + capabilities = agent_card.get("capabilities", {}) + extensions = capabilities.get("extensions", []) + return next(ext for ext in extensions if ext.get("uri") == uri) except StopIteration: return None diff --git a/apps/agentstack-server/tests/conftest.py b/apps/agentstack-server/tests/conftest.py index 21b861c91c..abc99e3e76 100644 --- a/apps/agentstack-server/tests/conftest.py +++ b/apps/agentstack-server/tests/conftest.py @@ -10,7 +10,6 @@ from pprint import pprint from typing import Any -import async_lru import kr8s import pytest from agentstack_sdk.platform import ModelProviderType @@ -22,9 +21,6 @@ from agentstack_server.infrastructure.persistence.repositories.db_metadata import metadata -# Disable async_lru event loop check in tests -async_lru._LRUCacheWrapper._check_loop = lambda self, loop: None - class Configuration(BaseSettings): model_config = SettingsConfigDict(extra="ignore") @@ -34,7 +30,7 @@ class Configuration(BaseSettings): embedding_model: str = "ollama:nomic-embed-text:latest" llm_api_key: Secret[str] = Secret("dummy") test_agent_image: str = "agentstack-registry-svc.default:5001/chat-test:latest" - test_agent_build_repo: str = "https://github.com/i-am-bee/agentstack-starter" + test_agent_build_repo: str = "https://github.com/i-am-bee/agentstack-starter@migrate-to-a2a-v1" server_url: str = "http://localhost:8333" db_url: str = "postgresql+asyncpg://agentstack-user:password@postgresql:5432/agentstack" keycloak_url: str = "http://localhost:8336" diff --git a/apps/agentstack-server/tests/e2e/agents/test_agent_builds.py b/apps/agentstack-server/tests/e2e/agents/test_agent_builds.py index 3034def427..9da9940aae 100644 --- a/apps/agentstack-server/tests/e2e/agents/test_agent_builds.py +++ b/apps/agentstack-server/tests/e2e/agents/test_agent_builds.py @@ -5,6 +5,7 @@ import asyncio import json import logging +import re import pytest from a2a.client.helpers import create_text_message_object @@ -48,7 +49,7 @@ async def test_remote_agent_build_and_start( assert provider.source == build.destination assert provider.id == build.provider_id assert provider.agent_card - assert test_configuration.test_agent_build_repo in provider.origin + assert re.sub(r"@.*$", "", test_configuration.test_agent_build_repo) in provider.origin context = await Context.create() context_token = await context.generate_token(providers={provider.id}) @@ -58,5 +59,7 @@ async def test_remote_agent_build_and_start( task = await get_final_task_from_stream(a2a_client.send_message(message)) # Verify response - assert task.status.state == TaskState.completed, f"Fail: {task.status.message.parts[0].root.text}" - assert "test of sirens" in task.history[-1].parts[0].root.text + assert task.status.state == TaskState.TASK_STATE_COMPLETED, ( + f"Fail: {task.status.message.parts[0].root.text}" + ) + assert "test of sirens" in task.history[-1].parts[0].text diff --git a/apps/agentstack-server/tests/e2e/agents/test_agent_starts.py b/apps/agentstack-server/tests/e2e/agents/test_agent_starts.py index 0eee19b2ef..065c9fd49e 100644 --- a/apps/agentstack-server/tests/e2e/agents/test_agent_starts.py +++ b/apps/agentstack-server/tests/e2e/agents/test_agent_starts.py @@ -9,7 +9,6 @@ import uuid from textwrap import dedent from threading import Thread -from typing import Any from unittest import mock import kr8s @@ -17,8 +16,11 @@ import uvicorn from a2a.client import A2AClientHTTPError from a2a.client.helpers import create_text_message_object +from a2a.server.agent_execution import AgentExecutor from a2a.server.apps import A2AStarletteApplication -from a2a.types import AgentCapabilities, AgentCard, Role, Task, TaskState +from a2a.server.request_handlers import DefaultRequestHandler +from a2a.server.tasks import InMemoryTaskStore +from a2a.types import AgentCapabilities, AgentCard, AgentInterface, AgentSkill, Role, Task, TaskState from agentstack_sdk.a2a.extensions import LLMFulfillment, LLMServiceExtensionClient, LLMServiceExtensionSpec from agentstack_sdk.platform import ModelProvider, Provider from agentstack_sdk.platform.context import Context, ContextPermissions, Permissions @@ -29,7 +31,7 @@ def extract_agent_text_from_stream(task: Task) -> str: assert task.history - return "".join(item.parts[0].root.text for item in task.history if item.role == Role.agent if item.parts) + return "".join(item.parts[0].text for item in task.history if item.role == Role.ROLE_AGENT if item.parts) @pytest.mark.usefixtures("clean_up", "setup_real_llm", "setup_platform_client") @@ -74,7 +76,7 @@ async def test_imported_agent( task = await get_final_task_from_stream(a2a_client.send_message(message)) # Verify response - assert task.status.state == TaskState.completed, f"Fail: {task.status.message.parts[0].root.text}" + assert task.status.state == TaskState.TASK_STATE_COMPLETED, f"Fail: {task.status.message.parts[0].text}" assert "ciao" in extract_agent_text_from_stream(task).lower() # Run 3 requests in parallel (test that each request waits) @@ -83,12 +85,12 @@ async def test_imported_agent( ) for task in run_results: - assert task.status.state == TaskState.completed, f"Fail: {task.status.message.parts[0].root.text}" + assert task.status.state == TaskState.TASK_STATE_COMPLETED, f"Fail: {task.status.message.parts[0].text}" assert "ciao" in extract_agent_text_from_stream(task).lower() with subtests.test("run chat agent for the second time"): task = await get_final_task_from_stream(a2a_client.send_message(message)) - assert task.status.state == TaskState.completed, f"Fail: {task.status.message.parts[0].root.text}" + assert task.status.state == TaskState.TASK_STATE_COMPLETED, f"Fail: {task.status.message.parts[0].text}" assert "ciao" in extract_agent_text_from_stream(task).lower() with subtests.test("the context token will not work with direct call to agent (server exchange is required)"): @@ -110,10 +112,9 @@ async def main(): "method": "message/send", "params": {{ "message": {{ - "role": "agent", - "parts": [{{"kind": "text", "text": "Hello"}}], + "role": "ROLE_AGENT", + "parts": [{{"text": "Hello"}}], "messageId": "1", - "kind": "message", }} }} }}) @@ -147,33 +148,29 @@ async def main(): await get_final_task_from_stream(a2a_client.send_message(message)) -UNMANAGED_AGENT_CARD: dict[str, Any] = { - "authentication": {"schemes": ["Bearer"]}, - "capabilities": AgentCapabilities(streaming=True), - "defaultInputModes": ["text/plain"], - "defaultOutputModes": ["text/plain"], - "description": "Test unmanaged A2A agent", - "name": "UnmanagedTestAgent", - "skills": [{"id": "skill-1", "name": "Echo", "description": "Echoes back", "tags": ["test"]}], - "url": "http://example.com/agent", - "version": "1.0", -} - - @pytest.fixture def unmanaged_a2a_server(free_port, setup_platform_client, clean_up_fn): server_instance: uvicorn.Server | None = None thread: Thread | None = None - agent_card = AgentCard(**UNMANAGED_AGENT_CARD) - agent_card.url = f"http://host.docker.internal:{free_port}" + agent_card = AgentCard( + name="UnmanagedTestAgent", + description="Test unmanaged A2A agent", + version="1.0", + default_input_modes=["text/plain"], + default_output_modes=["text/plain"], + capabilities=AgentCapabilities(streaming=True), + skills=[AgentSkill(id="skill-1", name="Echo", description="Echoes back", tags=["test"])], + supported_interfaces=[AgentInterface(url=f"http://host.docker.internal:{free_port}")], + ) - handler = mock.AsyncMock() + executor = mock.AsyncMock(spec=AgentExecutor) + http_handler = DefaultRequestHandler(agent_executor=executor, task_store=InMemoryTaskStore()) def start_server(): nonlocal server_instance, thread - app = A2AStarletteApplication(agent_card, handler) + app = A2AStarletteApplication(agent_card=agent_card, http_handler=http_handler) config = uvicorn.Config(app=app.build(), port=free_port, log_level="warning") server_instance = uvicorn.Server(config) diff --git a/apps/agentstack-server/tests/e2e/agents/test_context_store.py b/apps/agentstack-server/tests/e2e/agents/test_context_store.py index 2317b9c40a..3b060a7c07 100644 --- a/apps/agentstack-server/tests/e2e/agents/test_context_store.py +++ b/apps/agentstack-server/tests/e2e/agents/test_context_store.py @@ -18,11 +18,11 @@ pytestmark = pytest.mark.e2e -async def get_final_task_from_stream(stream: AsyncIterator[ClientEvent | Message]) -> Task: +async def get_final_task_from_stream(stream: AsyncIterator[ClientEvent | Message]) -> Task | None: final_task = None async for event in stream: match event: - case (task, _): + case (_, task): final_task = task return final_task @@ -35,7 +35,7 @@ async def history_agent(input: Message, context: RunContext) -> AsyncGenerator[R input.metadata = {"test": "metadata"} await context.store(input) async for message in context.load_history(): - message.role = Role.agent + message.role = Role.ROLE_AGENT assert message.metadata == {"test": "metadata"} yield message await context.store(message) @@ -70,17 +70,17 @@ async def test_agent_history(history_agent, subtests): ) final_task = await get_final_task_from_stream(client.send_message(create_message(token, "first message"))) - agent_messages = [msg.parts[0].root.text for msg in final_task.history] + agent_messages = [msg.parts[0].text for msg in final_task.history] assert all(msg.metadata == {"test": "metadata"} for msg in final_task.history) assert agent_messages == ["first message"] final_task = await get_final_task_from_stream(client.send_message(create_message(token, "second message"))) - agent_messages = [msg.parts[0].root.text for msg in final_task.history] + agent_messages = [msg.parts[0].text for msg in final_task.history] assert all(msg.metadata == {"test": "metadata"} for msg in final_task.history) assert agent_messages == ["first message", "first message", "second message"] final_task = await get_final_task_from_stream(client.send_message(create_message(token, "third message"))) - agent_messages = [msg.parts[0].root.text for msg in final_task.history] + agent_messages = [msg.parts[0].text for msg in final_task.history] assert all(msg.metadata == {"test": "metadata"} for msg in final_task.history) assert agent_messages == [ # first run @@ -105,7 +105,7 @@ async def test_agent_history(history_agent, subtests): grant_global_permissions=Permissions(a2a_proxy={"*"}), ) final_task = await get_final_task_from_stream(client.send_message(create_message(token, "first message"))) - agent_messages = [msg.parts[0].root.text for msg in final_task.history] + agent_messages = [msg.parts[0].text for msg in final_task.history] assert agent_messages == ["first message"] context1_history = await Context.list_history(context1.id) diff --git a/apps/agentstack-server/tests/e2e/agents/test_platform_extensions.py b/apps/agentstack-server/tests/e2e/agents/test_platform_extensions.py index fbe2ec6098..7f8b0a21c9 100644 --- a/apps/agentstack-server/tests/e2e/agents/test_platform_extensions.py +++ b/apps/agentstack-server/tests/e2e/agents/test_platform_extensions.py @@ -10,7 +10,7 @@ import pytest from a2a.client import Client, create_text_message_object -from a2a.types import FilePart, Message, Role, TaskState +from a2a.types import Message, Role, TaskState from agentstack_sdk.a2a.extensions.services.platform import ( PlatformApiExtensionClient, PlatformApiExtensionServer, @@ -37,14 +37,13 @@ async def file_reader_writer( _: Annotated[PlatformApiExtensionServer, PlatformApiExtensionSpec()], ) -> AsyncIterator[RunYield]: for part in message.parts: - match part.root: - case FilePart() as fp: - async with load_file(fp, stream=True) as open_file: - async for chunk in open_file.aiter_text(chunk_size=5): - yield chunk + if part.HasField("raw") or part.HasField("url"): + async with load_file(part, stream=True) as open_file: + async for chunk in open_file.aiter_text(chunk_size=5): + yield chunk file = await File.create(filename="1.txt", content=message.context_id.encode(), content_type="text/plain") - yield file.to_file_part() + yield file.to_part() async with create_server_with_agent(file_reader_writer, context_token=context_token) as (server, test_client): yield server, test_client @@ -76,8 +75,8 @@ async def test_platform_api_extension(file_reader_writer_factory, permissions, s api_extension_client = PlatformApiExtensionClient(PlatformApiExtensionSpec()) message = Message( - role=Role.user, - parts=[file.to_file_part()], + role=Role.ROLE_USER, + parts=[file.to_part()], message_id=str(uuid4()), context_id=context.id, metadata=api_extension_client.api_auth_metadata(auth_token=token.token, expires_at=token.expires_at), @@ -87,20 +86,20 @@ async def test_platform_api_extension(file_reader_writer_factory, permissions, s task = await get_final_task_from_stream(client.send_message(message)) if should_fail: - assert task.status.state == TaskState.failed - assert "403 Forbidden" in task.status.message.parts[0].root.text + assert task.status.state == TaskState.TASK_STATE_FAILED + assert "403 Forbidden" in task.status.message.parts[0].text else: - assert task.status.state == TaskState.completed, f"Fail: {task.status.message.parts[0].root.text}" + assert task.status.state == TaskState.TASK_STATE_COMPLETED, f"Fail: {task.status.message.parts[0].text}" # check that first message is the content of the first_file - first_message_text = task.history[0].parts[0].root.text + first_message_text = task.history[0].parts[0].text assert first_message_text == "01234" - second_message_text = task.history[1].parts[0].root.text + second_message_text = task.history[1].parts[0].text assert second_message_text == "56789" # check that the agent uploaded a new file with correct context_id as content - async with load_file(task.history[2].parts[0].root) as file: + async with load_file(task.history[2].parts[0]) as file: assert file.text == context.id @@ -125,7 +124,7 @@ async def test_self_registration_with_variables( os.environ.pop(SELF_REGISTRATION_TEST_VAR_NAME, None) _, client = self_registration_agent task = await get_final_task_from_stream(client.send_message(create_text_message_object(content="hi"))) - assert task.history[-1].parts[0].root.text == "empty" + assert task.history[-1].parts[0].text == "empty" with subtests.test("register provider"): async for attempt in AsyncRetrying(stop=stop_after_delay(6), wait=wait_fixed(0.5), reraise=True): @@ -143,7 +142,7 @@ async def test_self_registration_with_variables( async for attempt in AsyncRetrying(stop=stop_after_delay(6), wait=wait_fixed(0.5), reraise=True): with attempt: task = await get_final_task_from_stream(client.send_message(create_text_message_object(content="hi"))) - assert task.history[-1].parts[0].root.text == "test" + assert task.history[-1].parts[0].text == "test" with subtests.test("remove provider variable"): await provider.update_variables(variables={SELF_REGISTRATION_TEST_VAR_NAME: None}) @@ -151,4 +150,4 @@ async def test_self_registration_with_variables( async for attempt in AsyncRetrying(stop=stop_after_delay(6), wait=wait_fixed(0.5), reraise=True): with attempt: task = await get_final_task_from_stream(client.send_message(create_text_message_object(content="hi"))) - assert task.history[-1].parts[0].root.text == "empty" + assert task.history[-1].parts[0].text == "empty" diff --git a/apps/agentstack-server/tests/e2e/conftest.py b/apps/agentstack-server/tests/e2e/conftest.py index f617f6a928..d8c69d00bf 100644 --- a/apps/agentstack-server/tests/e2e/conftest.py +++ b/apps/agentstack-server/tests/e2e/conftest.py @@ -5,14 +5,14 @@ import json import logging import socket -from collections.abc import AsyncIterator, Awaitable, Callable +from collections.abc import AsyncIterator, Awaitable, Callable, Iterator from contextlib import asynccontextmanager, closing, suppress from typing import Any import httpx import pytest from a2a.client import Client, ClientConfig, ClientEvent, ClientFactory -from a2a.types import AgentCard, Message, Task +from a2a.types import AgentCard, Task from agentstack_sdk.platform import ModelProvider, SystemConfiguration, use_platform_client from agentstack_sdk.platform.context import ContextToken from keycloak import KeycloakAdmin @@ -21,15 +21,13 @@ @pytest.fixture -def get_final_task_from_stream() -> Callable[[AsyncIterator[ClientEvent | Message]], Awaitable[Task]]: - async def fn(stream: AsyncIterator[ClientEvent | Message]) -> Task: +def get_final_task_from_stream() -> Callable[[AsyncIterator[ClientEvent]], Awaitable[Task | None]]: + async def fn(stream: AsyncIterator[ClientEvent]) -> Task | None: """Helper to extract the final task from a client.send_message stream.""" final_task = None async for event in stream: match event: - case (task, None): - final_task = task - case (task, _): + case (_, task): final_task = task return final_task @@ -117,7 +115,7 @@ def _create_test_user(keycloak_admin: KeycloakAdmin, username: str, role: str | @pytest.fixture(scope="session") -def test_admin(keycloak_admin) -> tuple[str, str]: +def test_admin(keycloak_admin, test_configuration) -> Iterator[tuple[str, str]]: username = "testadmin" _create_test_user(keycloak_admin, username, "agentstack-admin") try: @@ -128,7 +126,7 @@ def test_admin(keycloak_admin) -> tuple[str, str]: @pytest.fixture(scope="session") -def test_user(keycloak_admin) -> tuple[str, str]: +def test_user(keycloak_admin) -> Iterator[tuple[str, str]]: username = "testuser" _create_test_user(keycloak_admin, username) try: diff --git a/apps/agentstack-server/tests/e2e/examples/agent-integration/agent-settings/test_basic_settings.py b/apps/agentstack-server/tests/e2e/examples/agent-integration/agent-settings/test_basic_settings.py index c971670030..dac9cd4740 100644 --- a/apps/agentstack-server/tests/e2e/examples/agent-integration/agent-settings/test_basic_settings.py +++ b/apps/agentstack-server/tests/e2e/examples/agent-integration/agent-settings/test_basic_settings.py @@ -39,7 +39,9 @@ async def test_basic_settings_example(subtests, get_final_task_from_stream, a2a_ task = await get_final_task_from_stream(running_example.client.send_message(message)) # Verify response - assert task.status.state == TaskState.completed, f"Fail: {task.status.message.parts[0].root.text}" + assert task.status.state == TaskState.TASK_STATE_COMPLETED, ( + f"Fail: {task.status.message.parts[0].root.text}" + ) assert "Thinking is enabled" in task.history[-1].parts[0].root.text assert "Memory is disabled" in task.history[-1].parts[0].root.text assert "Response style: humorous" in task.history[-1].parts[0].root.text diff --git a/apps/agentstack-server/tests/e2e/examples/agent-integration/canvas/test_canvas_with_llm.py b/apps/agentstack-server/tests/e2e/examples/agent-integration/canvas/test_canvas_with_llm.py index b3af1f2619..755cf0c221 100644 --- a/apps/agentstack-server/tests/e2e/examples/agent-integration/canvas/test_canvas_with_llm.py +++ b/apps/agentstack-server/tests/e2e/examples/agent-integration/canvas/test_canvas_with_llm.py @@ -25,7 +25,9 @@ async def test_canvas_with_llm_example(subtests, get_final_task_from_stream, a2a message.context_id = running_example.context.id task = await get_final_task_from_stream(running_example.client.send_message(message)) - assert task.status.state == TaskState.completed, f"Fail: {task.status.message.parts[0].root.text}" + assert task.status.state == TaskState.TASK_STATE_COMPLETED, ( + f"Fail: {task.status.message.parts[0].root.text}" + ) # Verify artifact is returned (the agent uses a mocked LLM response) assert len(task.artifacts) > 0 @@ -56,7 +58,9 @@ async def test_canvas_with_llm_example(subtests, get_final_task_from_stream, a2a } task = await get_final_task_from_stream(running_example.client.send_message(message)) - assert task.status.state == TaskState.completed, f"Fail: {task.status.message.parts[0].root.text}" + assert task.status.state == TaskState.TASK_STATE_COMPLETED, ( + f"Fail: {task.status.message.parts[0].root.text}" + ) # Verify updated artifact is returned assert len(task.artifacts) > 0 diff --git a/apps/agentstack-server/tests/e2e/examples/agent-integration/citations/test_citation_basic_usage.py b/apps/agentstack-server/tests/e2e/examples/agent-integration/citations/test_citation_basic_usage.py index 9abaa01d8d..0768216f32 100644 --- a/apps/agentstack-server/tests/e2e/examples/agent-integration/citations/test_citation_basic_usage.py +++ b/apps/agentstack-server/tests/e2e/examples/agent-integration/citations/test_citation_basic_usage.py @@ -23,7 +23,9 @@ async def test_citation_basic_usage_example(subtests, get_final_task_from_stream message.context_id = running_example.context.id task = await get_final_task_from_stream(running_example.client.send_message(message)) - assert task.status.state == TaskState.completed, f"Fail: {task.status.message.parts[0].root.text}" + assert task.status.state == TaskState.TASK_STATE_COMPLETED, ( + f"Fail: {task.status.message.parts[0].root.text}" + ) # Verify response text response_text = task.history[-1].parts[0].root.text diff --git a/apps/agentstack-server/tests/e2e/examples/agent-integration/env-variables/test_basic_environment_variables.py b/apps/agentstack-server/tests/e2e/examples/agent-integration/env-variables/test_basic_environment_variables.py index 572fb03548..fb5aeb159b 100644 --- a/apps/agentstack-server/tests/e2e/examples/agent-integration/env-variables/test_basic_environment_variables.py +++ b/apps/agentstack-server/tests/e2e/examples/agent-integration/env-variables/test_basic_environment_variables.py @@ -22,6 +22,8 @@ async def test_basic_environment_variables_example(subtests, get_final_task_from message.context_id = running_example.context.id task = await get_final_task_from_stream(running_example.client.send_message(message)) - assert task.status.state == TaskState.completed, f"Fail: {task.status.message.parts[0].root.text}" + assert task.status.state == TaskState.TASK_STATE_COMPLETED, ( + f"Fail: {task.status.message.parts[0].root.text}" + ) # THINKING_ENABLED defaults to false when not set assert "Thinking mode is disabled" in task.history[-1].parts[0].root.text diff --git a/apps/agentstack-server/tests/e2e/examples/agent-integration/error/test_adding_error_context.py b/apps/agentstack-server/tests/e2e/examples/agent-integration/error/test_adding_error_context.py index c86e143cd5..d3699409e8 100644 --- a/apps/agentstack-server/tests/e2e/examples/agent-integration/error/test_adding_error_context.py +++ b/apps/agentstack-server/tests/e2e/examples/agent-integration/error/test_adding_error_context.py @@ -23,7 +23,7 @@ async def test_adding_error_context_example(subtests, get_final_task_from_stream message.context_id = running_example.context.id task = await get_final_task_from_stream(running_example.client.send_message(message)) - assert task.status.state == TaskState.failed + assert task.status.state == TaskState.TASK_STATE_FAILED # Verify error metadata contains context error_uri = ErrorExtensionSpec.URI diff --git a/apps/agentstack-server/tests/e2e/examples/agent-integration/error/test_advanced_error_reporting.py b/apps/agentstack-server/tests/e2e/examples/agent-integration/error/test_advanced_error_reporting.py index 927a2986e9..40e60ffddf 100644 --- a/apps/agentstack-server/tests/e2e/examples/agent-integration/error/test_advanced_error_reporting.py +++ b/apps/agentstack-server/tests/e2e/examples/agent-integration/error/test_advanced_error_reporting.py @@ -23,7 +23,7 @@ async def test_advanced_error_reporting_example(subtests, get_final_task_from_st message.context_id = running_example.context.id task = await get_final_task_from_stream(running_example.client.send_message(message)) - assert task.status.state == TaskState.failed + assert task.status.state == TaskState.TASK_STATE_FAILED # Verify error message content error_text = task.status.message.parts[0].root.text diff --git a/apps/agentstack-server/tests/e2e/examples/agent-integration/error/test_multiple_errors_handling.py b/apps/agentstack-server/tests/e2e/examples/agent-integration/error/test_multiple_errors_handling.py index 57fb3ee43c..11c9cc0156 100644 --- a/apps/agentstack-server/tests/e2e/examples/agent-integration/error/test_multiple_errors_handling.py +++ b/apps/agentstack-server/tests/e2e/examples/agent-integration/error/test_multiple_errors_handling.py @@ -23,7 +23,7 @@ async def test_multiple_errors_handling_example(subtests, get_final_task_from_st message.context_id = running_example.context.id task = await get_final_task_from_stream(running_example.client.send_message(message)) - assert task.status.state == TaskState.failed + assert task.status.state == TaskState.TASK_STATE_FAILED # Verify error metadata contains structured error data error_uri = ErrorExtensionSpec.URI diff --git a/apps/agentstack-server/tests/e2e/examples/agent-integration/error/test_standard_error_reporting.py b/apps/agentstack-server/tests/e2e/examples/agent-integration/error/test_standard_error_reporting.py index 9819bfd7b5..54d1d641c1 100644 --- a/apps/agentstack-server/tests/e2e/examples/agent-integration/error/test_standard_error_reporting.py +++ b/apps/agentstack-server/tests/e2e/examples/agent-integration/error/test_standard_error_reporting.py @@ -22,5 +22,5 @@ async def test_standard_error_reporting_example(subtests, get_final_task_from_st message.context_id = running_example.context.id task = await get_final_task_from_stream(running_example.client.send_message(message)) - assert task.status.state == TaskState.failed + assert task.status.state == TaskState.TASK_STATE_FAILED assert "Something went wrong!" in task.status.message.parts[0].root.text diff --git a/apps/agentstack-server/tests/e2e/examples/agent-integration/files/test_file_processing.py b/apps/agentstack-server/tests/e2e/examples/agent-integration/files/test_file_processing.py index eacc552f75..516a41cf40 100644 --- a/apps/agentstack-server/tests/e2e/examples/agent-integration/files/test_file_processing.py +++ b/apps/agentstack-server/tests/e2e/examples/agent-integration/files/test_file_processing.py @@ -41,8 +41,8 @@ async def test_file_processing_example(subtests, get_final_task_from_stream, a2a ) message = Message( - role=Role.user, - parts=[file.to_file_part()], + role=Role.ROLE_USER, + parts=[file.to_part()], context_id=running_example.context.id, message_id=str(uuid4()), metadata=api_extension_client.api_auth_metadata(auth_token=token.token, expires_at=token.expires_at), @@ -52,7 +52,9 @@ async def test_file_processing_example(subtests, get_final_task_from_stream, a2a task = await get_final_task_from_stream(running_example.client.send_message(message)) # verify response - assert task.status.state == TaskState.completed, f"Fail: {task.status.message.parts[0].root.text}" + assert task.status.state == TaskState.TASK_STATE_COMPLETED, ( + f"Fail: {task.status.message.parts[0].root.text}" + ) # check that first message is the content of the first_file diff --git a/apps/agentstack-server/tests/e2e/examples/agent-integration/forms/test_dynamic_form_requests.py b/apps/agentstack-server/tests/e2e/examples/agent-integration/forms/test_dynamic_form_requests.py index d9a3399889..25ce8f0e41 100644 --- a/apps/agentstack-server/tests/e2e/examples/agent-integration/forms/test_dynamic_form_requests.py +++ b/apps/agentstack-server/tests/e2e/examples/agent-integration/forms/test_dynamic_form_requests.py @@ -28,7 +28,7 @@ async def test_dynamic_form_requests_example(subtests, get_final_task_from_strea # Get the task - should be in input_required state with form task = await get_final_task_from_stream(running_example.client.send_message(message)) - assert task.status.state == TaskState.input_required + assert task.status.state == TaskState.TASK_STATE_INPUT_REQUIRED # Parse the form request from the task status message spec = FormRequestExtensionSpec() @@ -46,7 +46,7 @@ async def test_dynamic_form_requests_example(subtests, get_final_task_from_strea } ) response_message = Message( - role=Role.user, + role=Role.ROLE_USER, message_id=str(uuid4()), task_id=task.id, context_id=running_example.context.id, @@ -57,7 +57,7 @@ async def test_dynamic_form_requests_example(subtests, get_final_task_from_strea # Send the form response and get final task final_task = await get_final_task_from_stream(running_example.client.send_message(response_message)) - assert final_task.status.state == TaskState.completed, ( + assert final_task.status.state == TaskState.TASK_STATE_COMPLETED, ( f"Fail: {final_task.status.message.parts[0].root.text}" ) assert "test@example.com" in final_task.history[-1].parts[0].root.text diff --git a/apps/agentstack-server/tests/e2e/examples/agent-integration/forms/test_initial_form_rendering.py b/apps/agentstack-server/tests/e2e/examples/agent-integration/forms/test_initial_form_rendering.py index fdcfa00164..508208685f 100644 --- a/apps/agentstack-server/tests/e2e/examples/agent-integration/forms/test_initial_form_rendering.py +++ b/apps/agentstack-server/tests/e2e/examples/agent-integration/forms/test_initial_form_rendering.py @@ -36,5 +36,7 @@ async def test_initial_form_rendering_example(subtests, get_final_task_from_stre task = await get_final_task_from_stream(running_example.client.send_message(message)) # Verify response - assert task.status.state == TaskState.completed, f"Fail: {task.status.message.parts[0].root.text}" + assert task.status.state == TaskState.TASK_STATE_COMPLETED, ( + f"Fail: {task.status.message.parts[0].root.text}" + ) assert "Hello Alice Smith! Nice to meet you." in task.history[-1].parts[0].root.text diff --git a/apps/agentstack-server/tests/e2e/examples/agent-integration/llm-proxy-service/test_llm_access.py b/apps/agentstack-server/tests/e2e/examples/agent-integration/llm-proxy-service/test_llm_access.py index abd4eef159..2a74271786 100644 --- a/apps/agentstack-server/tests/e2e/examples/agent-integration/llm-proxy-service/test_llm_access.py +++ b/apps/agentstack-server/tests/e2e/examples/agent-integration/llm-proxy-service/test_llm_access.py @@ -35,5 +35,7 @@ async def test_llm_access_example(subtests, get_final_task_from_stream, a2a_clie message.context_id = running_example.context.id task = await get_final_task_from_stream(running_example.client.send_message(message)) - assert task.status.state == TaskState.completed, f"Fail: {task.status.message.parts[0].root.text}" + assert task.status.state == TaskState.TASK_STATE_COMPLETED, ( + f"Fail: {task.status.message.parts[0].root.text}" + ) assert "LLM access configured for model: ibm/granite-3-3-8b-instruct" in task.history[-1].parts[0].root.text diff --git a/apps/agentstack-server/tests/e2e/examples/agent-integration/mcp/test_custom_mcp_client_with_oauth.py b/apps/agentstack-server/tests/e2e/examples/agent-integration/mcp/test_custom_mcp_client_with_oauth.py index 3a117c93ee..d7d0affdd4 100644 --- a/apps/agentstack-server/tests/e2e/examples/agent-integration/mcp/test_custom_mcp_client_with_oauth.py +++ b/apps/agentstack-server/tests/e2e/examples/agent-integration/mcp/test_custom_mcp_client_with_oauth.py @@ -15,7 +15,7 @@ import httpx import pytest import uvicorn -from a2a.types import Message, Part, Role, TaskState, TextPart +from a2a.types import Message, Part, Role, TaskState from agentstack_sdk.a2a.extensions import OAuthExtensionClient, OAuthFulfillment from agentstack_sdk.a2a.extensions.auth.oauth import OAuthExtensionSpec from mcp.server.auth.provider import ( @@ -160,8 +160,8 @@ async def test_custom_mcp_client_with_oauth_example( with subtests.test("agent authenticates via OAuth and calls MCP tool"): message = Message( - role=Role.user, - parts=[Part(root=TextPart(text="Get my Stripe account info"))], + role=Role.ROLE_USER, + parts=[Part(text="Get my Stripe account info")], context_id=running_example.context.id, message_id=str(uuid4()), metadata=oauth_metadata, @@ -174,7 +174,7 @@ async def test_custom_mcp_client_with_oauth_example( task, _ = event assert task is not None - assert task.status.state == TaskState.auth_required + assert task.status.state == TaskState.TASK_STATE_AUTH_REQUIRED # Parse the auth URL from the auth_required response auth_request = oauth_client.parse_auth_request(message=task.status.message) @@ -198,6 +198,6 @@ async def test_custom_mcp_client_with_oauth_example( if isinstance(event, tuple): task, _ = event - assert task.status.state == TaskState.completed + assert task.status.state == TaskState.TASK_STATE_COMPLETED result_text = task.history[-1].parts[0].root.text assert "acct_test123" in result_text diff --git a/apps/agentstack-server/tests/e2e/examples/agent-integration/mcp/test_github_mcp_agent.py b/apps/agentstack-server/tests/e2e/examples/agent-integration/mcp/test_github_mcp_agent.py index c4ee9a7b95..1b966c19e4 100644 --- a/apps/agentstack-server/tests/e2e/examples/agent-integration/mcp/test_github_mcp_agent.py +++ b/apps/agentstack-server/tests/e2e/examples/agent-integration/mcp/test_github_mcp_agent.py @@ -97,6 +97,6 @@ async def test_github_mcp_agent_example(subtests, get_final_task_from_stream, a2 task = await get_final_task_from_stream(running_example.client.send_message(message)) - assert task.status.state == TaskState.completed + assert task.status.state == TaskState.TASK_STATE_COMPLETED result_text = task.history[-1].parts[0].root.text assert "test-user" in result_text diff --git a/apps/agentstack-server/tests/e2e/examples/agent-integration/multi-turn/test_advanced_history.py b/apps/agentstack-server/tests/e2e/examples/agent-integration/multi-turn/test_advanced_history.py index e52b1e13eb..2d2a085411 100644 --- a/apps/agentstack-server/tests/e2e/examples/agent-integration/multi-turn/test_advanced_history.py +++ b/apps/agentstack-server/tests/e2e/examples/agent-integration/multi-turn/test_advanced_history.py @@ -37,8 +37,8 @@ async def test_advanced_history_example(subtests, get_final_task_from_stream, a2 task = await get_final_task_from_stream(running_example.client.send_message(message)) # Verify response - assert task.status.state == TaskState.completed, f"Fail: {task.status.message.parts[0].root.text}" - assert any(sub in task.history[-1].parts[0].root.text.lower() for sub in ["hello", "hi"]) + assert task.status.state == TaskState.TASK_STATE_COMPLETED, f"Fail: {task.status.message.parts[0].text}" + assert any(sub in task.history[-1].parts[0].text.lower() for sub in ["hello", "hi"]) with subtests.test("agent remembers user name from history"): message = create_text_message_object(content="Can you remind me my name?") @@ -47,5 +47,5 @@ async def test_advanced_history_example(subtests, get_final_task_from_stream, a2 task = await get_final_task_from_stream(running_example.client.send_message(message)) # Verify response - assert task.status.state == TaskState.completed, f"Fail: {task.status.message.parts[0].root.text}" - assert "john" in task.history[-1].parts[0].root.text.lower() + assert task.status.state == TaskState.TASK_STATE_COMPLETED, f"Fail: {task.status.message.parts[0].text}" + assert "john" in task.history[-1].parts[0].text.lower() diff --git a/apps/agentstack-server/tests/e2e/examples/agent-integration/multi-turn/test_basic_history.py b/apps/agentstack-server/tests/e2e/examples/agent-integration/multi-turn/test_basic_history.py index 39274cb17b..a100289608 100644 --- a/apps/agentstack-server/tests/e2e/examples/agent-integration/multi-turn/test_basic_history.py +++ b/apps/agentstack-server/tests/e2e/examples/agent-integration/multi-turn/test_basic_history.py @@ -22,7 +22,9 @@ async def test_basic_history_example(subtests, get_final_task_from_stream, a2a_c message.context_id = running_example.context.id task = await get_final_task_from_stream(running_example.client.send_message(message)) # Verify response - assert task.status.state == TaskState.completed, f"Fail: {task.status.message.parts[0].root.text}" + assert task.status.state == TaskState.TASK_STATE_COMPLETED, ( + f"Fail: {task.status.message.parts[0].root.text}" + ) assert "I can see we have 1 messages in our conversation." in task.history[-1].parts[0].root.text with subtests.test("agent reports 3 messages after second exchange"): @@ -31,5 +33,7 @@ async def test_basic_history_example(subtests, get_final_task_from_stream, a2a_c task = await get_final_task_from_stream(running_example.client.send_message(message)) # Verify response - assert task.status.state == TaskState.completed, f"Fail: {task.status.message.parts[0].root.text}" + assert task.status.state == TaskState.TASK_STATE_COMPLETED, ( + f"Fail: {task.status.message.parts[0].root.text}" + ) assert "I can see we have 3 messages in our conversation." in task.history[-1].parts[0].root.text diff --git a/apps/agentstack-server/tests/e2e/examples/agent-integration/overview/test_advanced_server_wrapper.py b/apps/agentstack-server/tests/e2e/examples/agent-integration/overview/test_advanced_server_wrapper.py index f78fddc59e..35925aae87 100644 --- a/apps/agentstack-server/tests/e2e/examples/agent-integration/overview/test_advanced_server_wrapper.py +++ b/apps/agentstack-server/tests/e2e/examples/agent-integration/overview/test_advanced_server_wrapper.py @@ -27,7 +27,7 @@ async def test_advanced_server_wrapper_example(subtests, get_final_task_from_str message.context_id = running_example.context.id task = await get_final_task_from_stream(running_example.client.send_message(message)) - assert task.status.state == TaskState.input_required + assert task.status.state == TaskState.TASK_STATE_INPUT_REQUIRED # Parse the form request from the task status message spec = FormRequestExtensionSpec() @@ -44,7 +44,7 @@ async def test_advanced_server_wrapper_example(subtests, get_final_task_from_str } ) response_message = Message( - role=Role.user, + role=Role.ROLE_USER, message_id=str(uuid4()), task_id=task.id, context_id=running_example.context.id, @@ -55,7 +55,7 @@ async def test_advanced_server_wrapper_example(subtests, get_final_task_from_str # Send form response and verify final task final_task = await get_final_task_from_stream(running_example.client.send_message(response_message)) - assert final_task.status.state == TaskState.completed, ( + assert final_task.status.state == TaskState.TASK_STATE_COMPLETED, ( f"Fail: {final_task.status.message.parts[0].root.text}" ) assert "Alice" in final_task.history[-1].parts[0].root.text diff --git a/apps/agentstack-server/tests/e2e/examples/agent-integration/overview/test_dependency_injection.py b/apps/agentstack-server/tests/e2e/examples/agent-integration/overview/test_dependency_injection.py index faa9f695f9..fbeba6de8b 100644 --- a/apps/agentstack-server/tests/e2e/examples/agent-integration/overview/test_dependency_injection.py +++ b/apps/agentstack-server/tests/e2e/examples/agent-integration/overview/test_dependency_injection.py @@ -38,7 +38,9 @@ async def test_dependency_injection_example( message.context_id = running_example.context.id task = await get_final_task_from_stream(running_example.client.send_message(message)) - assert task.status.state == TaskState.completed, f"Fail: {task.status.message.parts[0].root.text}" + assert task.status.state == TaskState.TASK_STATE_COMPLETED, ( + f"Fail: {task.status.message.parts[0].root.text}" + ) assert "LLM service is available" in task.history[-1].parts[0].root.text with subtests.test("agent reports LLM not available without fulfillment"): @@ -46,5 +48,7 @@ async def test_dependency_injection_example( message.context_id = running_example.context.id task = await get_final_task_from_stream(running_example.client.send_message(message)) - assert task.status.state == TaskState.completed, f"Fail: {task.status.message.parts[0].root.text}" + assert task.status.state == TaskState.TASK_STATE_COMPLETED, ( + f"Fail: {task.status.message.parts[0].root.text}" + ) assert "LLM service not available" in task.history[-1].parts[0].root.text diff --git a/apps/agentstack-server/tests/e2e/examples/agent-integration/overview/test_server_wrapper.py b/apps/agentstack-server/tests/e2e/examples/agent-integration/overview/test_server_wrapper.py index cd5c2bc856..744f338ae9 100644 --- a/apps/agentstack-server/tests/e2e/examples/agent-integration/overview/test_server_wrapper.py +++ b/apps/agentstack-server/tests/e2e/examples/agent-integration/overview/test_server_wrapper.py @@ -22,5 +22,7 @@ async def test_server_wrapper_example(subtests, get_final_task_from_stream, a2a_ message.context_id = running_example.context.id task = await get_final_task_from_stream(running_example.client.send_message(message)) - assert task.status.state == TaskState.completed, f"Fail: {task.status.message.parts[0].root.text}" + assert task.status.state == TaskState.TASK_STATE_COMPLETED, ( + f"Fail: {task.status.message.parts[0].root.text}" + ) assert "Hello from my agent!" in task.history[-1].parts[0].root.text diff --git a/apps/agentstack-server/tests/e2e/examples/agent-integration/rag/test_conversation_rag_agent.py b/apps/agentstack-server/tests/e2e/examples/agent-integration/rag/test_conversation_rag_agent.py index a730e0c901..6d50de235e 100644 --- a/apps/agentstack-server/tests/e2e/examples/agent-integration/rag/test_conversation_rag_agent.py +++ b/apps/agentstack-server/tests/e2e/examples/agent-integration/rag/test_conversation_rag_agent.py @@ -7,7 +7,7 @@ from uuid import uuid4 import pytest -from a2a.types import Message, Part, Role, TaskState, TextPart +from a2a.types import Message, Part, Role, TaskState from agentstack_sdk.a2a.extensions import ( EmbeddingFulfillment, EmbeddingServiceExtensionClient, @@ -82,10 +82,8 @@ async def test_conversation_rag_agent_example( with subtests.test("agent processes file without query"): # Send only a file (no text query) - should process and store in vector store message = Message( - role=Role.user, - parts=[ - Part(root=file.to_file_part()), - ], + role=Role.ROLE_USER, + parts=[file.to_part()], context_id=running_example.context.id, message_id=str(uuid4()), metadata=metadata, @@ -93,17 +91,17 @@ async def test_conversation_rag_agent_example( task = await get_final_task_from_stream(running_example.client.send_message(message)) - assert task.status.state == TaskState.completed, f"Fail: {task.status.message.parts[0].root.text}" + assert task.status.state == TaskState.TASK_STATE_COMPLETED, ( + f"Fail: {task.status.message.parts[0].root.text}" + ) result_text = task.history[-1].parts[0].root.text assert "1 file(s) processed" in result_text with subtests.test("agent answers query using previously processed file"): # Send only a query (no file) - should search the existing vector store message = Message( - role=Role.user, - parts=[ - Part(root=TextPart(text="How much power does the Zorblax engine need?")), - ], + role=Role.ROLE_USER, + parts=[Part(text="How much power does the Zorblax engine need?")], context_id=running_example.context.id, message_id=str(uuid4()), metadata=metadata, @@ -111,7 +109,9 @@ async def test_conversation_rag_agent_example( task = await get_final_task_from_stream(running_example.client.send_message(message)) - assert task.status.state == TaskState.completed, f"Fail: {task.status.message.parts[0].root.text}" + assert task.status.state == TaskState.TASK_STATE_COMPLETED, ( + f"Fail: {task.status.message.parts[0].root.text}" + ) result_text = task.history[-1].parts[0].root.text assert "Results" in result_text assert "42 gigawatts" in result_text diff --git a/apps/agentstack-server/tests/e2e/examples/agent-integration/rag/test_simple_rag_agent.py b/apps/agentstack-server/tests/e2e/examples/agent-integration/rag/test_simple_rag_agent.py index 0a32c37d71..8383acc414 100644 --- a/apps/agentstack-server/tests/e2e/examples/agent-integration/rag/test_simple_rag_agent.py +++ b/apps/agentstack-server/tests/e2e/examples/agent-integration/rag/test_simple_rag_agent.py @@ -7,7 +7,7 @@ from uuid import uuid4 import pytest -from a2a.types import Message, Part, Role, TaskState, TextPart +from a2a.types import Message, Part, Role, TaskState from agentstack_sdk.a2a.extensions import ( EmbeddingFulfillment, EmbeddingServiceExtensionClient, @@ -79,10 +79,10 @@ async def test_simple_rag_agent_example(subtests, get_final_task_from_stream, a2 # Create message with file and query message = Message( - role=Role.user, + role=Role.ROLE_USER, parts=[ - Part(root=file.to_file_part()), - Part(root=TextPart(text="How much power does the Zorblax engine need?")), + file.to_part(), + Part(text="How much power does the Zorblax engine need?"), ], context_id=running_example.context.id, message_id=str(uuid4()), @@ -93,7 +93,9 @@ async def test_simple_rag_agent_example(subtests, get_final_task_from_stream, a2 task = await get_final_task_from_stream(running_example.client.send_message(message)) # Verify response - assert task.status.state == TaskState.completed, f"Fail: {task.status.message.parts[0].root.text}" + assert task.status.state == TaskState.TASK_STATE_COMPLETED, ( + f"Fail: {task.status.message.parts[0].root.text}" + ) # Verify results contain the relevant chunk (Power Requirements) result_text = task.history[-1].parts[0].root.text diff --git a/apps/agentstack-server/tests/e2e/examples/agent-integration/secrets/test_basic_secrets.py b/apps/agentstack-server/tests/e2e/examples/agent-integration/secrets/test_basic_secrets.py index 2cfef66b1e..2724da11f5 100644 --- a/apps/agentstack-server/tests/e2e/examples/agent-integration/secrets/test_basic_secrets.py +++ b/apps/agentstack-server/tests/e2e/examples/agent-integration/secrets/test_basic_secrets.py @@ -30,7 +30,9 @@ async def test_basic_secrets_example(subtests, get_final_task_from_stream, a2a_c } task = await get_final_task_from_stream(running_example.client.send_message(message)) - assert task.status.state == TaskState.completed, f"Fail: {task.status.message.parts[0].root.text}" + assert task.status.state == TaskState.TASK_STATE_COMPLETED, ( + f"Fail: {task.status.message.parts[0].root.text}" + ) assert "Slack API key: test-slack-api-key-12345" in task.history[-1].parts[0].root.text with subtests.test("agent handles missing secret"): @@ -39,11 +41,11 @@ async def test_basic_secrets_example(subtests, get_final_task_from_stream, a2a_c message.context_id = running_example.context.id task = await get_final_task_from_stream(running_example.client.send_message(message)) - assert task.status.state == TaskState.auth_required + assert task.status.state == TaskState.TASK_STATE_AUTH_REQUIRED # Respond without providing the secret response_message = Message( - role=Role.user, + role=Role.ROLE_USER, message_id=str(uuid4()), task_id=task.id, context_id=running_example.context.id, @@ -51,7 +53,7 @@ async def test_basic_secrets_example(subtests, get_final_task_from_stream, a2a_c ) final_task = await get_final_task_from_stream(running_example.client.send_message(response_message)) - assert final_task.status.state == TaskState.completed, ( + assert final_task.status.state == TaskState.TASK_STATE_COMPLETED, ( f"Fail: {final_task.status.message.parts[0].root.text}" ) assert "No Slack API key provided" in final_task.history[-1].parts[0].root.text diff --git a/apps/agentstack-server/tests/e2e/examples/agent-integration/tool-calls/test_basic_approve.py b/apps/agentstack-server/tests/e2e/examples/agent-integration/tool-calls/test_basic_approve.py index 750c217d10..abfe03ddc2 100644 --- a/apps/agentstack-server/tests/e2e/examples/agent-integration/tool-calls/test_basic_approve.py +++ b/apps/agentstack-server/tests/e2e/examples/agent-integration/tool-calls/test_basic_approve.py @@ -42,10 +42,10 @@ async def test_basic_approve_example(subtests, a2a_client_factory, test_configur task, _ = event # If tool call needs approval, approve it - while task and task.status.state == TaskState.input_required: + while task and task.status.state == TaskState.TASK_STATE_INPUT_REQUIRED: response = ApprovalResponse(decision="approve") response_message = Message( - role=Role.user, + role=Role.ROLE_USER, message_id=str(uuid4()), task_id=task.id, context_id=running_example.context.id, @@ -57,7 +57,9 @@ async def test_basic_approve_example(subtests, a2a_client_factory, test_configur task, _ = event assert task is not None - assert task.status.state == TaskState.completed, f"Fail: {task.status.message.parts[0].root.text}" + assert task.status.state == TaskState.TASK_STATE_COMPLETED, ( + f"Fail: {task.status.message.parts[0].root.text}" + ) with subtests.test("tool call is rejected"): # Send message that should trigger the ThinkTool @@ -75,10 +77,12 @@ async def test_basic_approve_example(subtests, a2a_client_factory, test_configur # (agent may request approval for multiple tools after a rejection) max_rejections = 10 rejection_count = 0 - while task and task.status.state == TaskState.input_required and rejection_count < max_rejections: + while ( + task and task.status.state == TaskState.TASK_STATE_INPUT_REQUIRED and rejection_count < max_rejections + ): response = ApprovalResponse(decision="reject") response_message = Message( - role=Role.user, + role=Role.ROLE_USER, message_id=str(uuid4()), task_id=task.id, context_id=running_example.context.id, @@ -92,7 +96,7 @@ async def test_basic_approve_example(subtests, a2a_client_factory, test_configur assert task is not None # Task may fail or complete depending on how agent handles rejection - assert task.status.state in (TaskState.completed, TaskState.failed), ( + assert task.status.state in (TaskState.TASK_STATE_COMPLETED, TaskState.TASK_STATE_FAILED), ( f"Task still in {task.status.state} after {rejection_count} rejections. " f"Agent may be stuck in a loop requesting tool approvals." ) diff --git a/apps/agentstack-server/tests/e2e/examples/agent-integration/trajectory/test_trajectory_basic_usage.py b/apps/agentstack-server/tests/e2e/examples/agent-integration/trajectory/test_trajectory_basic_usage.py index 56cfe830f3..1597d60513 100644 --- a/apps/agentstack-server/tests/e2e/examples/agent-integration/trajectory/test_trajectory_basic_usage.py +++ b/apps/agentstack-server/tests/e2e/examples/agent-integration/trajectory/test_trajectory_basic_usage.py @@ -23,7 +23,9 @@ async def test_trajectory_basic_usage_example(subtests, get_final_task_from_stre message.context_id = running_example.context.id task = await get_final_task_from_stream(running_example.client.send_message(message)) - assert task.status.state == TaskState.completed, f"Fail: {task.status.message.parts[0].root.text}" + assert task.status.state == TaskState.TASK_STATE_COMPLETED, ( + f"Fail: {task.status.message.parts[0].root.text}" + ) # Verify trajectory metadata was yielded (should be in history) trajectory_uri = TrajectoryExtensionSpec.URI diff --git a/apps/agentstack-server/tests/e2e/examples/conftest.py b/apps/agentstack-server/tests/e2e/examples/conftest.py index af1e81253f..95f147a9e0 100644 --- a/apps/agentstack-server/tests/e2e/examples/conftest.py +++ b/apps/agentstack-server/tests/e2e/examples/conftest.py @@ -14,10 +14,11 @@ import httpx import pytest from a2a.client import Client, ClientEvent -from a2a.types import AgentCard, Message, Task +from a2a.types import AgentCard, Task from a2a.utils.constants import AGENT_CARD_WELL_KNOWN_PATH from agentstack_sdk.platform import Provider from agentstack_sdk.platform.context import Context, ContextPermissions, ContextToken, Permissions +from google.protobuf.json_format import ParseDict from pydantic import Secret from tenacity import retry, stop_after_delay, wait_fixed @@ -69,20 +70,17 @@ async def _get_agent_card(agent_url: str): async with httpx.AsyncClient(timeout=None) as httpx_client: card_resp = await httpx_client.get(f"{agent_url}{AGENT_CARD_WELL_KNOWN_PATH}") card_resp.raise_for_status() - card = AgentCard.model_validate(card_resp.json()) + card = ParseDict(card_resp.json(), AgentCard()) return card @pytest.fixture -def get_final_task_from_stream() -> Callable[[AsyncIterator[ClientEvent | Message]], Awaitable[Task]]: - async def fn(stream: AsyncIterator[ClientEvent | Message]) -> Task: - """Helper to extract the final task from a client.send_message stream.""" +def get_final_task_from_stream() -> Callable[[AsyncIterator[ClientEvent]], Awaitable[Task | None]]: + async def fn(stream: AsyncIterator[ClientEvent]) -> Task | None: final_task = None async for event in stream: match event: - case (task, None): - final_task = task - case (task, _): + case (_, task): final_task = task return final_task diff --git a/apps/agentstack-server/tests/e2e/examples/deploy-agents/building-agents/test_implement_your_agent_logic.py b/apps/agentstack-server/tests/e2e/examples/deploy-agents/building-agents/test_implement_your_agent_logic.py index 16c069f07a..d951ae0f35 100644 --- a/apps/agentstack-server/tests/e2e/examples/deploy-agents/building-agents/test_implement_your_agent_logic.py +++ b/apps/agentstack-server/tests/e2e/examples/deploy-agents/building-agents/test_implement_your_agent_logic.py @@ -23,5 +23,7 @@ async def test_implement_your_agent_logic_example(subtests, get_final_task_from_ task = await get_final_task_from_stream(running_example.client.send_message(message)) # Verify response - assert task.status.state == TaskState.completed, f"Fail: {task.status.message.parts[0].root.text}" + assert task.status.state == TaskState.TASK_STATE_COMPLETED, ( + f"Fail: {task.status.message.parts[0].root.text}" + ) assert "Ciao Pedro!" in task.history[-1].parts[0].root.text diff --git a/apps/agentstack-server/tests/e2e/routes/test_a2a_proxy.py b/apps/agentstack-server/tests/e2e/routes/test_a2a_proxy.py index 4cbcc57457..0f95c285c5 100644 --- a/apps/agentstack-server/tests/e2e/routes/test_a2a_proxy.py +++ b/apps/agentstack-server/tests/e2e/routes/test_a2a_proxy.py @@ -10,9 +10,8 @@ import socket import time import uuid -from contextlib import closing +from contextlib import closing, suppress from threading import Thread -from typing import Any from unittest import mock import pytest @@ -21,35 +20,39 @@ A2AFastAPIApplication, A2AStarletteApplication, ) -from a2a.types import ( - AgentCapabilities, - AgentCard, - Artifact, - DataPart, +from a2a.server.context import ServerCallContext +from a2a.server.jsonrpc_models import ( InternalError, InvalidParamsError, InvalidRequestError, JSONParseError, - Message, MethodNotFoundError, +) +from a2a.types.a2a_pb2 import ( + AgentCapabilities, + AgentCard, + AgentInterface, + AgentSkill, + Artifact, + Message, Part, PushNotificationConfig, Role, - SendMessageResponse, - SendMessageSuccessResponse, Task, TaskArtifactUpdateEvent, - TaskNotFoundError, TaskPushNotificationConfig, TaskState, TaskStatus, - TextPart, - UnsupportedOperationError, ) -from a2a.utils import AGENT_CARD_WELL_KNOWN_PATH +from a2a.utils import ( + AGENT_CARD_WELL_KNOWN_PATH, + EXTENDED_AGENT_CARD_PATH, + PREV_AGENT_CARD_WELL_KNOWN_PATH, +) from a2a.utils.errors import MethodNotImplementedError from fastapi import FastAPI -from httpx import Client +from google.protobuf.struct_pb2 import Struct, Value +from httpx import Client, ReadTimeout from sqlalchemy import text from starlette.applications import Starlette from starlette.authentication import ( @@ -63,6 +66,7 @@ from starlette.requests import HTTPConnection from starlette.responses import JSONResponse from starlette.routing import Route +from starlette.testclient import TestClient from agentstack_server.infrastructure.persistence.repositories.user import users_table @@ -70,71 +74,73 @@ # === TEST SETUP === -MINIMAL_AGENT_SKILL: dict[str, Any] = { - "id": "skill-123", - "name": "Recipe Finder", - "description": "Finds recipes", - "tags": ["cooking"], -} - -MINIMAL_AGENT_AUTH: dict[str, Any] = {"schemes": ["Bearer"]} - -AGENT_CAPS = AgentCapabilities(pushNotifications=True, stateTransitionHistory=False, streaming=True) - -MINIMAL_AGENT_CARD: dict[str, Any] = { - "authentication": MINIMAL_AGENT_AUTH, - "capabilities": AGENT_CAPS, # AgentCapabilities is required but can be empty - "defaultInputModes": ["text/plain"], - "defaultOutputModes": ["application/json"], - "description": "Test Agent", - "name": "TestAgent", - "skills": [MINIMAL_AGENT_SKILL], - "url": "http://example.com/agent", - "version": "1.0", -} - -EXTENDED_AGENT_CARD_DATA: dict[str, Any] = { - **MINIMAL_AGENT_CARD, - "name": "TestAgent Extended", - "description": "Test Agent with more details", - "skills": [ - MINIMAL_AGENT_SKILL, - { - "id": "skill-extended", - "name": "Extended Skill", - "description": "Does more things", - "tags": ["extended"], - }, - ], -} -TEXT_PART_DATA: dict[str, Any] = {"kind": "text", "text": "Hello"} +MINIMAL_AGENT_SKILL = AgentSkill( + id="skill-123", + name="Recipe Finder", + description="Finds recipes", + tags=["cooking"], +) + +AGENT_CAPS = AgentCapabilities(push_notifications=True, streaming=True) + +MINIMAL_AGENT_CARD_DATA = AgentCard( + capabilities=AGENT_CAPS, + default_input_modes=["text/plain"], + default_output_modes=["application/json"], + description="Test Agent", + name="TestAgent", + skills=[MINIMAL_AGENT_SKILL], + supported_interfaces=[AgentInterface(url="http://example.com/agent", protocol_binding="JSONRPC")], + version="1.0", +) + +EXTENDED_AGENT_SKILL = AgentSkill( + id="skill-extended", + name="Extended Skill", + description="Does more things", + tags=["extended"], +) -DATA_PART_DATA: dict[str, Any] = {"kind": "data", "data": {"key": "value"}} +EXTENDED_AGENT_CARD_DATA = AgentCard( + capabilities=AGENT_CAPS, + default_input_modes=["text/plain"], + default_output_modes=["application/json"], + description="Test Agent with more details", + name="TestAgent Extended", + skills=[MINIMAL_AGENT_SKILL, EXTENDED_AGENT_SKILL], + supported_interfaces=[AgentInterface(url="http://example.com/agent", protocol_binding="JSONRPC")], + version="1.0", +) + +TEXT_PART_DATA = Part(text="Hello") -MINIMAL_MESSAGE_USER: dict[str, Any] = { - "role": "user", - "parts": [TEXT_PART_DATA], - "messageId": "msg-123", - "kind": "message", -} +# For proto, Part.data takes a Value(struct_value=Struct) +_struct = Struct() +_struct.update({"key": "value"}) +DATA_PART = Part(data=Value(struct_value=_struct)) -MINIMAL_TASK_STATUS: dict[str, Any] = {"state": "submitted"} +MINIMAL_MESSAGE_USER = Message( + role=Role.ROLE_USER, + parts=[TEXT_PART_DATA], + message_id="msg-123", +) -FULL_TASK_STATUS: dict[str, Any] = { - "state": "working", - "message": MINIMAL_MESSAGE_USER, - "timestamp": "2023-10-27T10:00:00Z", -} +MINIMAL_TASK_STATUS = TaskStatus(state=TaskState.TASK_STATE_SUBMITTED) + +FULL_TASK_STATUS = TaskStatus( + state=TaskState.TASK_STATE_WORKING, + message=MINIMAL_MESSAGE_USER, +) @pytest.fixture def agent_card(): - return AgentCard(**MINIMAL_AGENT_CARD) + return MINIMAL_AGENT_CARD_DATA @pytest.fixture def extended_agent_card_fixture(): - return AgentCard(**EXTENDED_AGENT_CARD_DATA) + return EXTENDED_AGENT_CARD_DATA @pytest.fixture @@ -146,7 +152,7 @@ def handler(): handler.set_push_notification = mock.AsyncMock() handler.get_push_notification = mock.AsyncMock() handler.on_message_send_stream = mock.Mock() - handler.on_resubscribe_to_task = mock.Mock() + handler.on_subscribe_to_task = mock.Mock() return handler @@ -166,7 +172,8 @@ def free_port() -> int: def create_test_server(free_port: int, app: A2AStarletteApplication, test_admin, test_configuration, clean_up_fn): server_instance: uvicorn.Server | None = None thread: Thread | None = None - app.agent_card.url = f"http://host.docker.internal:{free_port}" + for interface in app.agent_card.supported_interfaces: + interface.url = f"http://host.docker.internal:{free_port}" def _create_test_server(custom_app: Starlette | FastAPI | None = None) -> Client: custom_app = custom_app or app.build() @@ -183,16 +190,17 @@ def run_server(): while not server_instance.started: time.sleep(0.1) - with Client(base_url=f"{test_configuration.server_url}/api/v1", auth=test_admin) as client: + with Client(base_url=f"{test_configuration.server_url}/api/v1", auth=test_admin, timeout=None) as client: for _attempt in range(20): - resp = client.post( - "providers", - json={"location": f"http://host.docker.internal:{free_port}"}, - timeout=1, - ) - if not resp.is_error: - provider_id = resp.json()["id"] - break + with suppress(ReadTimeout): + resp = client.post( + "providers", + json={"location": f"http://host.docker.internal:{free_port}"}, + timeout=2, + ) + if not resp.is_error: + provider_id = resp.json()["id"] + break time.sleep(0.5) else: error = "unknown error" @@ -231,8 +239,8 @@ async def ensure_mock_task(test_admin, db_transaction, clean_up): @pytest.fixture -def client(create_test_server, test_configuration): - """Create a test client with the Starlette app.""" +def client(create_test_server): + """Create a proxy client pointing at the registered agent server.""" return create_test_server() @@ -250,51 +258,69 @@ def test_agent_card_endpoint(client: Client, agent_card: AgentCard): assert "streaming" in data["capabilities"] -def test_authenticated_extended_agent_card_endpoint_not_supported( - create_test_server, agent_card: AgentCard, handler: mock.AsyncMock -): +@pytest.mark.skip(reason="Extended agent card endpoint routing is not supported through the proxy.") +def test_authenticated_extended_agent_card_endpoint_not_supported(agent_card: AgentCard, handler: mock.AsyncMock): """Test extended card endpoint returns 404 if not supported by main card.""" - # Ensure supportsAuthenticatedExtendedCard is False or None - agent_card.supports_authenticated_extended_card = False + agent_card.capabilities.extended_agent_card = False app_instance = A2AStarletteApplication(agent_card, handler) - # The route should not even be added if supportsAuthenticatedExtendedCard is false - # So, building the app and trying to hit it should result in 404 from Starlette itself - client = create_test_server(app_instance.build()) + client = TestClient(app_instance.build()) response = client.get("/agent/authenticatedExtendedCard") - assert response.status_code == 404 # Starlette's default for no route + assert response.status_code == 404 + + +@pytest.mark.skip(reason="Deprecated agent card routing is not applicable to the proxy.") +def test_agent_card_default_endpoint_has_deprecated_route(agent_card: AgentCard, handler: mock.AsyncMock): + """Test agent card deprecated route is available for default route.""" + app_instance = A2AStarletteApplication(agent_card, handler) + client = TestClient(app_instance.build()) + response = client.get(AGENT_CARD_WELL_KNOWN_PATH) + assert response.status_code == 200 + data = response.json() + assert data["name"] == agent_card.name + response = client.get(PREV_AGENT_CARD_WELL_KNOWN_PATH) + assert response.status_code == 200 + data = response.json() + assert data["name"] == agent_card.name +@pytest.mark.skip(reason="Deprecated agent card routing is not applicable to the proxy.") +def test_agent_card_custom_endpoint_has_no_deprecated_route(agent_card: AgentCard, handler: mock.AsyncMock): + """Test agent card deprecated route is not available for custom route.""" + app_instance = A2AStarletteApplication(agent_card, handler) + client = TestClient(app_instance.build(agent_card_url="/my-agent")) + response = client.get("/my-agent") + assert response.status_code == 200 + data = response.json() + assert data["name"] == agent_card.name + response = client.get(PREV_AGENT_CARD_WELL_KNOWN_PATH) + assert response.status_code == 404 + + +@pytest.mark.skip(reason="Extended agent card endpoint routing is not supported through the proxy.") def test_authenticated_extended_agent_card_endpoint_not_supported_fastapi( - create_test_server, agent_card: AgentCard, handler: mock.AsyncMock + agent_card: AgentCard, handler: mock.AsyncMock ): """Test extended card endpoint returns 404 if not supported by main card.""" - # Ensure supportsAuthenticatedExtendedCard is False or None - agent_card.supports_authenticated_extended_card = False + agent_card.capabilities.extended_agent_card = False app_instance = A2AFastAPIApplication(agent_card, handler) - # The route should not even be added if supportsAuthenticatedExtendedCard is false - # So, building the app and trying to hit it should result in 404 from FastAPI itself - client = create_test_server(app_instance.build()) + client = TestClient(app_instance.build()) response = client.get("/agent/authenticatedExtendedCard") - assert response.status_code == 404 # FastAPI's default for no route + assert response.status_code == 404 @pytest.mark.skip(reason="Extended agent card is not supported at the moment. # TODO") def test_authenticated_extended_agent_card_endpoint_supported_with_specific_extended_card_starlette( - create_test_server, agent_card: AgentCard, extended_agent_card_fixture: AgentCard, handler: mock.AsyncMock, ): """Test extended card endpoint returns the specific extended card when provided.""" - agent_card.supports_authenticated_extended_card = True # Main card must support it - print(agent_card) + agent_card.capabilities.extended_agent_card = True app_instance = A2AStarletteApplication(agent_card, handler, extended_agent_card=extended_agent_card_fixture) - client = create_test_server(app_instance.build()) - + client = TestClient(app_instance.build()) response = client.get("/agent/authenticatedExtendedCard") assert response.status_code == 200 data = response.json() - # Verify it's the extended card's data assert data["name"] == extended_agent_card_fixture.name assert data["version"] == extended_agent_card_fixture.version assert len(data["skills"]) == len(extended_agent_card_fixture.skills) @@ -303,157 +329,136 @@ def test_authenticated_extended_agent_card_endpoint_supported_with_specific_exte @pytest.mark.skip(reason="Extended agent card is not supported at the moment. # TODO") def test_authenticated_extended_agent_card_endpoint_supported_with_specific_extended_card_fastapi( - create_test_server, agent_card: AgentCard, extended_agent_card_fixture: AgentCard, handler: mock.AsyncMock, ): """Test extended card endpoint returns the specific extended card when provided.""" - agent_card.supports_authenticated_extended_card = True # Main card must support it + agent_card.capabilities.extended_agent_card = True app_instance = A2AFastAPIApplication(agent_card, handler, extended_agent_card=extended_agent_card_fixture) - client = create_test_server(app_instance.build()) - + client = TestClient(app_instance.build()) response = client.get("/agent/authenticatedExtendedCard") assert response.status_code == 200 data = response.json() - # Verify it's the extended card's data assert data["name"] == extended_agent_card_fixture.name assert data["version"] == extended_agent_card_fixture.version assert len(data["skills"]) == len(extended_agent_card_fixture.skills) assert any(skill["id"] == "skill-extended" for skill in data["skills"]), "Extended skill not found in served card" -@pytest.mark.skip(reason="Custom agent card urls are not supported at the moment.") -def test_agent_card_custom_url(create_test_server, app: A2AStarletteApplication, agent_card: AgentCard): +@pytest.mark.skip(reason="Custom agent card URLs are not supported through the proxy.") +def test_agent_card_custom_url(app: A2AStarletteApplication, agent_card: AgentCard): """Test the agent card endpoint with a custom URL.""" - client = create_test_server(app.build(agent_card_url="/my-agent")) + client = TestClient(app.build(agent_card_url="/my-agent")) response = client.get("/my-agent") assert response.status_code == 200 data = response.json() assert data["name"] == agent_card.name -@pytest.mark.skip(reason="Custom RPC urls are not supported at the moment.") -def test_starlette_rpc_endpoint_custom_url( - create_test_server, app: A2AStarletteApplication, handler: mock.AsyncMock, ensure_mock_task -): +@pytest.mark.skip(reason="Custom RPC URLs are not supported through the proxy.") +def test_starlette_rpc_endpoint_custom_url(app: A2AStarletteApplication, handler: mock.AsyncMock): """Test the RPC endpoint with a custom URL.""" - # Provide a valid Task object as the return value - task_status = TaskStatus(**MINIMAL_TASK_STATUS) - task = Task(id="task1", context_id="ctx1", state="completed", status=task_status) + task = Task(id="task1", context_id="ctx1", status=MINIMAL_TASK_STATUS) handler.on_get_task.return_value = task - client = create_test_server(app.build(rpc_url="/api/rpc")) + client = TestClient(app.build(rpc_url="/api/rpc")) response = client.post( "/api/rpc", - json={ - "jsonrpc": "2.0", - "id": "123", - "method": "tasks/get", - "params": {"id": "task1"}, - }, + json={"jsonrpc": "2.0", "id": "123", "method": "GetTask", "params": {"id": "task1"}}, ) assert response.status_code == 200 - data = response.json() - assert data["result"]["id"] == "task1" + assert response.json()["result"]["id"] == "task1" -@pytest.mark.skip(reason="Custom RPC urls are not supported at the moment.") -def test_fastapi_rpc_endpoint_custom_url(create_test_server, app: A2AFastAPIApplication, handler: mock.AsyncMock): +@pytest.mark.skip(reason="Custom RPC URLs are not supported through the proxy.") +def test_fastapi_rpc_endpoint_custom_url(app: A2AFastAPIApplication, handler: mock.AsyncMock): """Test the RPC endpoint with a custom URL.""" - # Provide a valid Task object as the return value - task_status = TaskStatus(**MINIMAL_TASK_STATUS) - task = Task(id="task1", context_id="ctx1", state="completed", status=task_status) + task = Task(id="task1", context_id="ctx1", status=MINIMAL_TASK_STATUS) handler.on_get_task.return_value = task - client = create_test_server(app.build(rpc_url="/api/rpc")) + client = TestClient(app.build(rpc_url="/api/rpc")) response = client.post( "/api/rpc", - json={ - "jsonrpc": "2.0", - "id": "123", - "method": "tasks/get", - "params": {"id": "task1"}, - }, + json={"jsonrpc": "2.0", "id": "123", "method": "GetTask", "params": {"id": "task1"}}, ) assert response.status_code == 200 - data = response.json() - assert data["result"]["id"] == "task1" + assert response.json()["result"]["id"] == "task1" -@pytest.mark.skip(reason="Custom routes are not supported by the proxy.") -def test_starlette_build_with_extra_routes(create_test_server, app: A2AStarletteApplication, agent_card: AgentCard): +@pytest.mark.skip(reason="Custom routes are not supported through the proxy.") +def test_starlette_build_with_extra_routes(app: A2AStarletteApplication, agent_card: AgentCard): """Test building the app with additional routes.""" def custom_handler(request): return JSONResponse({"message": "Hello"}) extra_route = Route("/hello", custom_handler, methods=["GET"]) - test_app = app.build(routes=[extra_route]) - client = create_test_server(test_app) - - # Test the added route + client = TestClient(app.build(routes=[extra_route])) response = client.get("/hello") assert response.status_code == 200 assert response.json() == {"message": "Hello"} - - # Ensure default routes still work response = client.get(AGENT_CARD_WELL_KNOWN_PATH) assert response.status_code == 200 - data = response.json() - assert data["name"] == agent_card.name + assert response.json()["name"] == agent_card.name -@pytest.mark.skip(reason="Custom routes are not supported by the proxy.") -def test_fastapi_build_with_extra_routes(create_test_server, app: A2AFastAPIApplication, agent_card: AgentCard): +@pytest.mark.skip(reason="Custom routes are not supported through the proxy.") +def test_fastapi_build_with_extra_routes(app: A2AFastAPIApplication, agent_card: AgentCard): """Test building the app with additional routes.""" def custom_handler(request): return JSONResponse({"message": "Hello"}) extra_route = Route("/hello", custom_handler, methods=["GET"]) - test_app = app.build(routes=[extra_route]) - client = create_test_server(test_app) - - # Test the added route + client = TestClient(app.build(routes=[extra_route])) response = client.get("/hello") assert response.status_code == 200 assert response.json() == {"message": "Hello"} - - # Ensure default routes still work response = client.get(AGENT_CARD_WELL_KNOWN_PATH) assert response.status_code == 200 - data = response.json() - assert data["name"] == agent_card.name + assert response.json()["name"] == agent_card.name + response = client.get(PREV_AGENT_CARD_WELL_KNOWN_PATH) + assert response.status_code == 200 + assert response.json()["name"] == agent_card.name + + +@pytest.mark.skip(reason="Custom agent card paths are not supported through the proxy.") +def test_fastapi_build_custom_agent_card_path(app: A2AFastAPIApplication, agent_card: AgentCard): + """Test building the app with a custom agent card path.""" + client = TestClient(app.build(agent_card_url="/agent-card")) + response = client.get("/agent-card") + assert response.status_code == 200 + assert response.json()["name"] == agent_card.name + response = client.get(AGENT_CARD_WELL_KNOWN_PATH) + assert response.status_code == 404 + response = client.get(PREV_AGENT_CARD_WELL_KNOWN_PATH) + assert response.status_code == 404 # === REQUEST METHODS TESTS === -def test_send_message(create_test_server, handler: mock.AsyncMock, agent_card, ensure_mock_task): +def test_send_message(client: Client, handler: mock.AsyncMock, ensure_mock_task): """Test sending a message.""" # Prepare mock response - task_status = TaskStatus(**MINIMAL_TASK_STATUS) mock_task = Task( id="task1", context_id="session-xyz", - status=task_status, + status=MINIMAL_TASK_STATUS, ) handler.on_message_send.return_value = mock_task # Send request - app_instance = A2AStarletteApplication(agent_card, handler) - client = create_test_server(app_instance.build()) response = client.post( "/", json={ "jsonrpc": "2.0", "id": "123", - "method": "message/send", + "method": "SendMessage", "params": { "message": { - "role": "agent", - "parts": [{"kind": "text", "text": "Hello"}], + "role": "ROLE_AGENT", + "parts": [{"text": "Hello"}], "messageId": "111", - "kind": "message", "taskId": "task1", "contextId": "session-xyz", } @@ -465,19 +470,17 @@ def test_send_message(create_test_server, handler: mock.AsyncMock, agent_card, e assert response.status_code == 200 data = response.json() assert "result" in data - assert data["result"]["id"] == "task1" - assert data["result"]["status"]["state"] == "submitted" + assert data["result"]["task"]["id"] == "task1" + assert data["result"]["task"]["status"]["state"] == "TASK_STATE_SUBMITTED" # Verify handler was called handler.on_message_send.assert_awaited_once() -async def test_cancel_task(client: Client, handler: mock.AsyncMock, ensure_mock_task): +def test_cancel_task(client: Client, handler: mock.AsyncMock, ensure_mock_task): """Test cancelling a task.""" # Setup mock response - task_status = TaskStatus(**MINIMAL_TASK_STATUS) - task_status.state = TaskState.canceled # 'cancelled' # - task = Task(id="task1", context_id="ctx1", state="cancelled", status=task_status) + task = Task(id="task1", context_id="ctx1", status=TaskStatus(state=TaskState.TASK_STATE_CANCELED)) handler.on_cancel_task.return_value = task # Send request @@ -486,7 +489,7 @@ async def test_cancel_task(client: Client, handler: mock.AsyncMock, ensure_mock_ json={ "jsonrpc": "2.0", "id": "123", - "method": "tasks/cancel", + "method": "CancelTask", "params": {"id": "task1"}, }, ) @@ -495,18 +498,17 @@ async def test_cancel_task(client: Client, handler: mock.AsyncMock, ensure_mock_ assert response.status_code == 200 data = response.json() assert data["result"]["id"] == "task1" - assert data["result"]["status"]["state"] == "canceled" + assert data["result"]["status"]["state"] == "TASK_STATE_CANCELED" # Verify handler was called handler.on_cancel_task.assert_awaited_once() -async def test_get_task(client: Client, handler: mock.AsyncMock, ensure_mock_task): +def test_get_task(client: Client, handler: mock.AsyncMock, ensure_mock_task): """Test getting a task.""" # Setup mock response - task_status = TaskStatus(**MINIMAL_TASK_STATUS) - task = Task(id="task1", context_id="ctx1", state="completed", status=task_status) - handler.on_get_task.return_value = task # JSONRPCResponse(root=task) + task = Task(id="task1", context_id="ctx1", status=MINIMAL_TASK_STATUS) + handler.on_get_task.return_value = task # Send request response = client.post( # noqa: ASYNC212 @@ -514,7 +516,7 @@ async def test_get_task(client: Client, handler: mock.AsyncMock, ensure_mock_tas json={ "jsonrpc": "2.0", "id": "123", - "method": "tasks/get", + "method": "GetTask", "params": {"id": "task1"}, }, ) @@ -532,10 +534,10 @@ def test_set_push_notification_config(client: Client, handler: mock.AsyncMock, e """Test setting push notification configuration.""" # Setup mock response task_push_config = TaskPushNotificationConfig( - task_id="task1", + task_id="t2", push_notification_config=PushNotificationConfig(url="https://example.com", token="secret-token"), ) - handler.on_set_task_push_notification_config.return_value = task_push_config + handler.on_create_task_push_notification_config.return_value = task_push_config # Send request response = client.post( @@ -543,10 +545,10 @@ def test_set_push_notification_config(client: Client, handler: mock.AsyncMock, e json={ "jsonrpc": "2.0", "id": "123", - "method": "tasks/pushNotificationConfig/set", + "method": "CreateTaskPushNotificationConfig", "params": { - "taskId": "task1", - "pushNotificationConfig": { + "task_id": "task1", + "config": { "url": "https://example.com", "token": "secret-token", }, @@ -560,7 +562,7 @@ def test_set_push_notification_config(client: Client, handler: mock.AsyncMock, e assert data["result"]["pushNotificationConfig"]["token"] == "secret-token" # Verify handler was called - handler.on_set_task_push_notification_config.assert_awaited_once() + handler.on_create_task_push_notification_config.assert_awaited_once() def test_get_push_notification_config(client: Client, handler: mock.AsyncMock, ensure_mock_task): @@ -579,8 +581,11 @@ def test_get_push_notification_config(client: Client, handler: mock.AsyncMock, e json={ "jsonrpc": "2.0", "id": "123", - "method": "tasks/pushNotificationConfig/get", - "params": {"id": "task1"}, + "method": "GetTaskPushNotificationConfig", + "params": { + "task_id": "task1", + "id": "pushNotificationConfig", + }, }, ) @@ -593,56 +598,40 @@ def test_get_push_notification_config(client: Client, handler: mock.AsyncMock, e handler.on_get_task_push_notification_config.assert_awaited_once() -def test_server_auth(create_test_server, app: A2AStarletteApplication, handler: mock.AsyncMock, ensure_mock_task): +@pytest.mark.skip(reason="Custom authentication middleware cannot be injected through the proxy.") +def test_server_auth(app: A2AStarletteApplication, handler: mock.AsyncMock): class TestAuthMiddleware(AuthenticationBackend): async def authenticate(self, conn: HTTPConnection) -> tuple[AuthCredentials, BaseUser] | None: - # For the purposes of this test, all requests are authenticated! return (AuthCredentials(["authenticated"]), SimpleUser("test_user")) - client = create_test_server( - app.build(middleware=[Middleware(AuthenticationMiddleware, backend=TestAuthMiddleware())]) - ) - - # Set the output message to be the authenticated user name + client = TestClient(app.build(middleware=[Middleware(AuthenticationMiddleware, backend=TestAuthMiddleware())])) handler.on_message_send.side_effect = lambda params, context: Message( context_id="session-xyz", message_id="112", - role=Role.agent, - parts=[ - Part(TextPart(text=context.user.user_name)), - ], + role=Role.ROLE_AGENT, + parts=[Part(text=context.user.user_name)], ) - - # Send request response = client.post( "/", json={ "jsonrpc": "2.0", "id": "123", - "method": "message/send", + "method": "SendMessage", "params": { "message": { - "role": "agent", - "parts": [{"kind": "text", "text": "Hello"}], + "role": "ROLE_AGENT", + "parts": [{"text": "Hello"}], "messageId": "111", - "kind": "message", "taskId": "task1", "contextId": "session-xyz", } }, }, ) - - # Verify response assert response.status_code == 200 - result = SendMessageResponse.model_validate(response.json()) - assert isinstance(result.root, SendMessageSuccessResponse) - assert isinstance(result.root.result, Message) - message = result.root.result - assert isinstance(message.parts[0].root, TextPart) - assert message.parts[0].root.text == "test_user" - - # Verify handler was called + data = response.json() + assert "result" in data + assert data["result"]["message"]["parts"][0]["text"] == "test_user" handler.on_message_send.assert_awaited_once() @@ -654,77 +643,62 @@ async def test_message_send_stream( ) -> None: """Test streaming message sending.""" - # Setup mock streaming response async def stream_generator(): for i in range(3): - text_part = TextPart(**TEXT_PART_DATA) - data_part = DataPart(**DATA_PART_DATA) artifact = Artifact( artifact_id=f"artifact-{i}", name="result_data", - parts=[Part(root=text_part), Part(root=data_part)], + parts=[TEXT_PART_DATA, DATA_PART], ) last = [False, False, True] - task_artifact_update_event_data: dict[str, Any] = { - "artifact": artifact, - "taskId": "task1", - "contextId": "session-xyz", - "append": False, - "lastChunk": last[i], - "kind": "artifact-update", - } - - yield TaskArtifactUpdateEvent.model_validate(task_artifact_update_event_data) + yield TaskArtifactUpdateEvent( + artifact=artifact, + task_id="task1", + context_id="session-xyz", + append=False, + last_chunk=last[i], + ) handler.on_message_send_stream.return_value = stream_generator() client = None try: - # Create client client = create_test_server(app.build()) - # Send request with client.stream( "POST", "/", json={ "jsonrpc": "2.0", "id": "123", - "method": "message/stream", + "method": "SendStreamingMessage", "params": { "message": { - "role": "agent", - "parts": [{"kind": "text", "text": "Hello"}], + "role": "ROLE_AGENT", + "parts": [{"text": "Hello"}], "messageId": "111", - "kind": "message", "taskId": "task1", "contextId": "session-xyz", } }, }, ) as response: - # Verify response is a stream assert response.status_code == 200 assert response.headers["content-type"].startswith("text/event-stream") - # Read some content to verify streaming works content = b"" event_count = 0 - for chunk in response.iter_bytes(): content += chunk - if b"data" in chunk: # Naive check for SSE data lines + if b"data" in chunk: event_count += 1 - # Check content has event data (e.g., part of the first event) - assert b'"artifactId":"artifact-0"' in content # Check for the actual JSON payload - assert b'"artifactId":"artifact-1"' in content # Check for the actual JSON payload - assert b'"artifactId":"artifact-2"' in content # Check for the actual JSON payload + assert b"artifact-0" in content + assert b"artifact-1" in content + assert b"artifact-2" in content assert event_count > 0 finally: - # Ensure the client is closed if client: client.close() - # Allow event loop to process any pending callbacks await asyncio.sleep(0.1) @@ -733,72 +707,53 @@ async def test_task_resubscription( ) -> None: """Test task resubscription streaming.""" - # Setup mock streaming response async def stream_generator(): for i in range(3): - text_part = TextPart(**TEXT_PART_DATA) - data_part = DataPart(**DATA_PART_DATA) artifact = Artifact( artifact_id=f"artifact-{i}", name="result_data", - parts=[Part(root=text_part), Part(root=data_part)], + parts=[TEXT_PART_DATA, DATA_PART], ) last = [False, False, True] - task_artifact_update_event_data: dict[str, Any] = { - "artifact": artifact, - "taskId": "task1", - "contextId": "session-xyz", - "append": False, - "lastChunk": last[i], - "kind": "artifact-update", - } - yield TaskArtifactUpdateEvent.model_validate(task_artifact_update_event_data) + yield TaskArtifactUpdateEvent( + artifact=artifact, + task_id="task1", + context_id="session-xyz", + append=False, + last_chunk=last[i], + ) - handler.on_resubscribe_to_task.return_value = stream_generator() + handler.on_subscribe_to_task.return_value = stream_generator() - # Create client client = create_test_server(app.build()) - try: - # Send request using client.stream() context manager - # Send request with client.stream( "POST", "/", json={ "jsonrpc": "2.0", - "id": "123", # This ID is used in the success_event above - "method": "tasks/resubscribe", + "id": "123", + "method": "SubscribeToTask", "params": {"id": "task1"}, }, ) as response: - # Verify response is a stream assert response.status_code == 200 assert response.headers["content-type"] == "text/event-stream; charset=utf-8" - # Read some content to verify streaming works content = b"" event_count = 0 for chunk in response.iter_bytes(): content += chunk - # A more robust check would be to parse each SSE event - if b"data:" in chunk: # Naive check for SSE data lines + if b"data:" in chunk: event_count += 1 - # TODO: WTF? processing just first event but checking all 3? - # if event_count >= 1 and len(content) > 20: # Ensure we've processed at least one event - # break - - # Check content has event data (e.g., part of the first event) - assert b'"artifactId":"artifact-0"' in content # Check for the actual JSON payload - assert b'"artifactId":"artifact-1"' in content # Check for the actual JSON payload - assert b'"artifactId":"artifact-2"' in content # Check for the actual JSON payload + assert b"artifact-0" in content + assert b"artifact-1" in content + assert b"artifact-2" in content assert event_count > 0 finally: - # Ensure the client is closed if client: client.close() - # Allow event loop to process any pending callbacks await asyncio.sleep(0.1) @@ -819,14 +774,16 @@ def test_invalid_request_structure(client: Client): response = client.post( "/", json={ - # Missing required fields - "id": "123" + "jsonrpc": "aaaa", # Missing or wrong required fields + "id": "123", + "method": "foo/bar", }, ) assert response.status_code == 200 data = response.json() assert "error" in data - assert data["error"]["code"] == InvalidRequestError().code + # The jsonrpc library returns MethodNotFoundError for unknown methods + assert data["error"]["code"] == MethodNotFoundError().code def test_method_not_implemented(client: Client, handler: mock.AsyncMock, ensure_mock_task): @@ -838,14 +795,14 @@ def test_method_not_implemented(client: Client, handler: mock.AsyncMock, ensure_ json={ "jsonrpc": "2.0", "id": "123", - "method": "tasks/get", + "method": "GetTask", "params": {"id": "task1"}, }, ) assert response.status_code == 200 data = response.json() assert "error" in data - assert data["error"]["code"] == UnsupportedOperationError().code + assert data["error"]["code"] == -32004 # UnsupportedOperationError def test_unknown_method(client: Client): @@ -874,7 +831,7 @@ def test_validation_error(client: Client): json={ "jsonrpc": "2.0", "id": "123", - "method": "message/send", + "method": "SendMessage", "params": { "message": { # Missing required fields @@ -898,7 +855,7 @@ def test_unhandled_exception(client: Client, handler: mock.AsyncMock, ensure_moc json={ "jsonrpc": "2.0", "id": "123", - "method": "tasks/get", + "method": "GetTask", "params": {"id": "task1"}, }, ) @@ -925,37 +882,210 @@ def test_non_dict_json(client: Client): assert data["error"]["code"] == InvalidRequestError().code +# === DYNAMIC CARD MODIFIER TESTS === + + +@pytest.mark.skip(reason="Dynamic card modifiers are not supported through the proxy.") +def test_dynamic_agent_card_modifier(agent_card: AgentCard, handler: mock.AsyncMock): + """Test that the card_modifier dynamically alters the public agent card.""" + + async def modifier(card: AgentCard) -> AgentCard: + modified_card = AgentCard() + modified_card.CopyFrom(card) + modified_card.name = "Dynamically Modified Agent" + return modified_card + + app_instance = A2AStarletteApplication(agent_card, handler, card_modifier=modifier) + client = TestClient(app_instance.build()) + + response = client.get(AGENT_CARD_WELL_KNOWN_PATH) + assert response.status_code == 200 + data = response.json() + assert data["name"] == "Dynamically Modified Agent" + assert data["version"] == agent_card.version # Ensure other fields are intact + + +@pytest.mark.skip(reason="Dynamic card modifiers are not supported through the proxy.") +def test_dynamic_agent_card_modifier_sync(agent_card: AgentCard, handler: mock.AsyncMock): + """Test that a synchronous card_modifier dynamically alters the public agent card.""" + + def modifier(card: AgentCard) -> AgentCard: + modified_card = AgentCard() + modified_card.CopyFrom(card) + modified_card.name = "Dynamically Modified Agent" + return modified_card + + app_instance = A2AStarletteApplication(agent_card, handler, card_modifier=modifier) + client = TestClient(app_instance.build()) + + response = client.get(AGENT_CARD_WELL_KNOWN_PATH) + assert response.status_code == 200 + data = response.json() + assert data["name"] == "Dynamically Modified Agent" + assert data["version"] == agent_card.version # Ensure other fields are intact + + +@pytest.mark.skip(reason="Dynamic card modifiers are not supported through the proxy.") +def test_dynamic_extended_agent_card_modifier( + agent_card: AgentCard, + extended_agent_card_fixture: AgentCard, + handler: mock.AsyncMock, +): + """Test that the extended_card_modifier dynamically alters the extended agent card.""" + agent_card.capabilities.extended_agent_card = True + + async def modifier(card: AgentCard, context: ServerCallContext) -> AgentCard: + modified_card = AgentCard() + modified_card.CopyFrom(card) + modified_card.description = "Dynamically Modified Extended Description" + return modified_card + + # Test with a base extended card + app_instance = A2AStarletteApplication( + agent_card, + handler, + extended_agent_card=extended_agent_card_fixture, + extended_card_modifier=modifier, + ) + client = TestClient(app_instance.build()) + + response = client.get(EXTENDED_AGENT_CARD_PATH) + assert response.status_code == 200 + data = response.json() + assert data["name"] == extended_agent_card_fixture.name + assert data["description"] == "Dynamically Modified Extended Description" + + # Test without a base extended card (modifier should receive public card) + app_instance_no_base = A2AStarletteApplication( + agent_card, + handler, + extended_agent_card=None, + extended_card_modifier=modifier, + ) + client_no_base = TestClient(app_instance_no_base.build()) + response_no_base = client_no_base.get(EXTENDED_AGENT_CARD_PATH) + assert response_no_base.status_code == 200 + data_no_base = response_no_base.json() + assert data_no_base["name"] == agent_card.name + assert data_no_base["description"] == "Dynamically Modified Extended Description" + + +@pytest.mark.skip(reason="Dynamic card modifiers are not supported through the proxy.") +def test_dynamic_extended_agent_card_modifier_sync( + agent_card: AgentCard, + extended_agent_card_fixture: AgentCard, + handler: mock.AsyncMock, +): + """Test that a synchronous extended_card_modifier dynamically alters the extended agent card.""" + agent_card.capabilities.extended_agent_card = True + + def modifier(card: AgentCard, context: ServerCallContext) -> AgentCard: + modified_card = AgentCard() + modified_card.CopyFrom(card) + modified_card.description = "Dynamically Modified Extended Description" + return modified_card + + # Test with a base extended card + app_instance = A2AStarletteApplication( + agent_card, + handler, + extended_agent_card=extended_agent_card_fixture, + extended_card_modifier=modifier, + ) + client = TestClient(app_instance.build()) + + response = client.get(EXTENDED_AGENT_CARD_PATH) + assert response.status_code == 200 + data = response.json() + assert data["name"] == extended_agent_card_fixture.name + assert data["description"] == "Dynamically Modified Extended Description" + + # Test without a base extended card (modifier should receive public card) + app_instance_no_base = A2AStarletteApplication( + agent_card, + handler, + extended_agent_card=None, + extended_card_modifier=modifier, + ) + client_no_base = TestClient(app_instance_no_base.build()) + response_no_base = client_no_base.get(EXTENDED_AGENT_CARD_PATH) + assert response_no_base.status_code == 200 + data_no_base = response_no_base.json() + assert data_no_base["name"] == agent_card.name + assert data_no_base["description"] == "Dynamically Modified Extended Description" + + +@pytest.mark.skip(reason="Dynamic card modifiers are not supported through the proxy.") +def test_fastapi_dynamic_agent_card_modifier(agent_card: AgentCard, handler: mock.AsyncMock): + """Test that the card_modifier dynamically alters the public agent card for FastAPI.""" + + async def modifier(card: AgentCard) -> AgentCard: + modified_card = AgentCard() + modified_card.CopyFrom(card) + modified_card.name = "Dynamically Modified Agent" + return modified_card + + app_instance = A2AFastAPIApplication(agent_card, handler, card_modifier=modifier) + client = TestClient(app_instance.build()) + + response = client.get(AGENT_CARD_WELL_KNOWN_PATH) + assert response.status_code == 200 + data = response.json() + assert data["name"] == "Dynamically Modified Agent" + + +@pytest.mark.skip(reason="Dynamic card modifiers are not supported through the proxy.") +def test_fastapi_dynamic_agent_card_modifier_sync(agent_card: AgentCard, handler: mock.AsyncMock): + """Test that a synchronous card_modifier dynamically alters the public agent card for FastAPI.""" + + def modifier(card: AgentCard) -> AgentCard: + modified_card = AgentCard() + modified_card.CopyFrom(card) + modified_card.name = "Dynamically Modified Agent" + return modified_card + + app_instance = A2AFastAPIApplication(agent_card, handler, card_modifier=modifier) + client = TestClient(app_instance.build()) + + response = client.get(AGENT_CARD_WELL_KNOWN_PATH) + assert response.status_code == 200 + data = response.json() + assert data["name"] == "Dynamically Modified Agent" + + # ------------------------------------- TESTS SPECIFIC TO PLATFORM PERMISSIONS ----------------------------------------- def test_task_ownership_different_user_cannot_access_task( - client: Client, handler: mock.AsyncMock, ensure_mock_task, test_user, test_admin + create_test_server, handler: mock.AsyncMock, ensure_mock_task, test_user, test_admin ): """Test that a task owned by admin cannot be accessed by default user.""" # Task is already created by ensure_mock_task for admin user # Setup mock response - task_status = TaskStatus(**MINIMAL_TASK_STATUS) - task = Task(id="task1", context_id="ctx1", state="completed", status=task_status) + task_status = MINIMAL_TASK_STATUS + task = Task(id="task1", context_id="ctx1", status=task_status) handler.on_get_task.return_value = task + client = create_test_server() + # Try to access as default user (without auth) client.auth = test_user response = client.post( "/", - json={"jsonrpc": "2.0", "id": "123", "method": "tasks/get", "params": {"id": "task1"}}, + json={"jsonrpc": "2.0", "id": "123", "method": "GetTask", "params": {"id": "task1"}}, ) # Should fail with error (forbidden or not found) assert response.status_code == 200 data = response.json() - assert data["error"]["code"] in [TaskNotFoundError().code] + assert data["error"]["code"] == -32001 # TaskNotFoundError # Now try as admin user (who owns it) client.auth = test_admin response = client.post( "/", - json={"jsonrpc": "2.0", "id": "123", "method": "tasks/get", "params": {"id": "task1"}}, + json={"jsonrpc": "2.0", "id": "123", "method": "GetTask", "params": {"id": "task1"}}, ) # Should succeed @@ -965,8 +1095,10 @@ def test_task_ownership_different_user_cannot_access_task( assert data["result"]["id"] == "task1" -async def test_unknown_task_raises_error(client: Client, handler: mock.AsyncMock, db_transaction, test_admin): +async def test_unknown_task_raises_error(create_test_server, handler: mock.AsyncMock, db_transaction, test_admin): """Test that sending a message creates a new task owned by the user.""" + client = create_test_server() + # Send message with non-existing task client.auth = test_admin response = client.post( # noqa: ASYNC212 @@ -974,14 +1106,13 @@ async def test_unknown_task_raises_error(client: Client, handler: mock.AsyncMock json={ "jsonrpc": "2.0", "id": "123", - "method": "message/send", + "method": "SendMessage", "params": { "message": { - "role": "agent", - "parts": [{"kind": "text", "text": "Hello"}], + "role": "ROLE_AGENT", + "parts": [{"text": "Hello"}], "taskId": "unknown-task", "messageId": "111", - "kind": "message", "contextId": "session-xyz", } }, @@ -990,15 +1121,15 @@ async def test_unknown_task_raises_error(client: Client, handler: mock.AsyncMock assert response.status_code == 200 data = response.json() - assert data["error"]["code"] in [TaskNotFoundError().code] + assert data["error"]["code"] == -32001 # TaskNotFoundError async def test_task_ownership_new_task_creation_via_message_send( - client: Client, handler: mock.AsyncMock, db_transaction, test_admin, test_user + create_test_server, handler: mock.AsyncMock, db_transaction, test_admin, test_user ): """Test that sending a message creates a new task owned by the user.""" # Setup mock response - server returns a new task - task_status = TaskStatus(**MINIMAL_TASK_STATUS) + task_status = MINIMAL_TASK_STATUS mock_task = Task( id="new-task-123", context_id="session-xyz", @@ -1006,6 +1137,8 @@ async def test_task_ownership_new_task_creation_via_message_send( ) handler.on_message_send.return_value = mock_task + client = create_test_server() + # Send message as admin which should create new task ownership client.auth = test_admin response = client.post( # noqa: ASYNC212 @@ -1013,13 +1146,12 @@ async def test_task_ownership_new_task_creation_via_message_send( json={ "jsonrpc": "2.0", "id": "123", - "method": "message/send", + "method": "SendMessage", "params": { "message": { - "role": "agent", - "parts": [{"kind": "text", "text": "Hello"}], + "role": "ROLE_AGENT", + "parts": [{"text": "Hello"}], "messageId": "111", - "kind": "message", "contextId": "session-xyz", } }, @@ -1028,7 +1160,7 @@ async def test_task_ownership_new_task_creation_via_message_send( assert response.status_code == 200 data = response.json() - assert data["result"]["id"] == "new-task-123" + assert data["result"]["task"]["id"] == "new-task-123" # Verify task was recorded in database for admin user result = await db_transaction.execute( @@ -1040,12 +1172,12 @@ async def test_task_ownership_new_task_creation_via_message_send( assert row.task_id == "new-task-123" # Verify we can access it as admin - task = Task(id="new-task-123", context_id="ctx1", state="completed", status=task_status) + task = Task(id="new-task-123", context_id="ctx1", status=task_status) handler.on_get_task.return_value = task response = client.post( # noqa: ASYNC212 "/", - json={"jsonrpc": "2.0", "id": "124", "method": "tasks/get", "params": {"id": "new-task-123"}}, + json={"jsonrpc": "2.0", "id": "124", "method": "GetTask", "params": {"id": "new-task-123"}}, ) assert response.status_code == 200 @@ -1055,19 +1187,21 @@ async def test_task_ownership_new_task_creation_via_message_send( client.auth = test_user response = client.post( # noqa: ASYNC212 "/", - json={"jsonrpc": "2.0", "id": "125", "method": "tasks/get", "params": {"id": "new-task-123"}}, + json={"jsonrpc": "2.0", "id": "125", "method": "GetTask", "params": {"id": "new-task-123"}}, ) assert response.status_code == 200 data = response.json() - assert data["error"]["code"] in [TaskNotFoundError().code] + assert data["error"]["code"] == -32001 # TaskNotFoundError async def test_context_ownership_cannot_be_claimed_by_different_user( - client: Client, handler: mock.AsyncMock, db_transaction, test_admin, test_user + create_test_server, handler: mock.AsyncMock, db_transaction, test_admin, test_user ): """Test that a context_id owned by one user cannot be used by another.""" - task_status = TaskStatus(**MINIMAL_TASK_STATUS) + task_status = MINIMAL_TASK_STATUS + + client = create_test_server() # Admin creates a message with a specific context client.auth = test_admin @@ -1079,13 +1213,12 @@ async def test_context_ownership_cannot_be_claimed_by_different_user( json={ "jsonrpc": "2.0", "id": "123", - "method": "message/send", + "method": "SendMessage", "params": { "message": { - "role": "agent", - "parts": [{"kind": "text", "text": "Hello"}], + "role": "ROLE_AGENT", + "parts": [{"text": "Hello"}], "messageId": "111", - "kind": "message", "contextId": "shared-context-789", } }, @@ -1116,13 +1249,12 @@ async def test_context_ownership_cannot_be_claimed_by_different_user( json={ "jsonrpc": "2.0", "id": "124", - "method": "message/send", + "method": "SendMessage", "params": { "message": { - "role": "agent", - "parts": [{"kind": "text", "text": "Hello"}], + "role": "ROLE_AGENT", + "parts": [{"text": "Hello"}], "messageId": "112", - "kind": "message", "contextId": "shared-context-789", } }, @@ -1136,22 +1268,24 @@ async def test_context_ownership_cannot_be_claimed_by_different_user( assert "insufficient permissions" in data["error"]["message"].lower() -async def test_task_update_last_accessed_at(client: Client, handler: mock.AsyncMock, db_transaction, test_admin): +async def test_task_update_last_accessed_at(create_test_server, handler: mock.AsyncMock, db_transaction, test_admin): """Test that accessing a task updates last_accessed_at timestamp.""" + client = create_test_server() client.auth = test_admin - mock_task = Task(id="task1", context_id="shared-context-789", status=TaskStatus(state=TaskState.submitted)) + mock_task = Task( + id="task1", context_id="shared-context-789", status=TaskStatus(state=TaskState.TASK_STATE_SUBMITTED) + ) handler.on_message_send.return_value = mock_task message_data = { "jsonrpc": "2.0", "id": "123", - "method": "message/send", + "method": "SendMessage", "params": { "message": { - "role": "agent", - "parts": [{"kind": "text", "text": "Hello"}], + "role": "ROLE_AGENT", + "parts": [{"text": "Hello"}], "messageId": "111", - "kind": "message", "contextId": "shared-context-789", } }, @@ -1168,8 +1302,8 @@ async def test_task_update_last_accessed_at(client: Client, handler: mock.AsyncM await asyncio.sleep(0.1) # Access the task - task_status = TaskStatus(**MINIMAL_TASK_STATUS) - task = Task(id="task1", context_id="ctx1", state="completed", status=task_status) + task_status = MINIMAL_TASK_STATUS + task = Task(id="task1", context_id="ctx1", status=task_status) handler.on_get_task.return_value = task response = client.post("/", json=message_data) # noqa: ASYNC212 @@ -1185,25 +1319,25 @@ async def test_task_update_last_accessed_at(client: Client, handler: mock.AsyncM async def test_task_and_context_both_specified_single_query( - client: Client, handler: mock.AsyncMock, db_transaction, test_admin + create_test_server, handler: mock.AsyncMock, db_transaction, test_admin ): """Test that both task_id and context_id are tracked in a single query when both are specified.""" + client = create_test_server() client.auth = test_admin - task_status = TaskStatus(**MINIMAL_TASK_STATUS) + task_status = MINIMAL_TASK_STATUS mock_task = Task(id="dual-task-123", context_id="dual-context-456", status=task_status) handler.on_message_send.return_value = mock_task message_data = { "jsonrpc": "2.0", "id": "123", - "method": "message/send", + "method": "SendMessage", "params": { "message": { - "role": "agent", - "parts": [{"kind": "text", "text": "Hello"}], + "role": "ROLE_AGENT", + "parts": [{"text": "Hello"}], "messageId": "111", - "kind": "message", "contextId": "dual-context-456", } }, @@ -1229,9 +1363,11 @@ async def test_task_and_context_both_specified_single_query( assert context_result.fetchone() is not None -async def test_invalid_request_raises_a2a_error(client: Client, handler: mock.AsyncMock, db_transaction): +async def test_invalid_request_raises_a2a_error(create_test_server, handler: mock.AsyncMock, db_transaction): """Test that an invalid request to an offline provider returns an A2A error.""" + client = create_test_server() + # set provider as offline provider_id = str(client.base_url).rstrip("/").split("/")[-1] await db_transaction.execute( @@ -1243,13 +1379,12 @@ async def test_invalid_request_raises_a2a_error(client: Client, handler: mock.As message_data = { "jsonrpc": "2.0", "id": "123", - "method": "message/send", + "method": "SendMessage", "params": { "message": { - "role": "agent", - "parts": [{"kind": "text", "text": "Hello"}], + "role": "ROLE_AGENT", + "parts": [{"text": "Hello"}], "messageId": "111", - "kind": "message", } }, } diff --git a/apps/agentstack-server/tests/e2e/routes/test_contexts.py b/apps/agentstack-server/tests/e2e/routes/test_contexts.py index db2457362c..b9e21b28fc 100644 --- a/apps/agentstack-server/tests/e2e/routes/test_contexts.py +++ b/apps/agentstack-server/tests/e2e/routes/test_contexts.py @@ -191,7 +191,7 @@ async def test_context_update_and_patch(subtests): @pytest.mark.usefixtures("clean_up", "setup_platform_client") async def test_context_provider_filtering(subtests): """Test creating contexts with provider_id and filtering by provider_id.""" - from a2a.types import AgentCapabilities, AgentCard + from a2a.types import AgentCard from agentstack_sdk.platform import Provider provider1 = None @@ -202,30 +202,12 @@ async def test_context_provider_filtering(subtests): with subtests.test("create dummy providers"): # Create first dummy provider with network URL - agent_card1 = AgentCard( - name="Test Provider 1", - description="First test provider", - url="http://localhost:9001/", - version="1.0.0", - default_input_modes=["text"], - default_output_modes=["text"], - capabilities=AgentCapabilities(), - skills=[], - ) + agent_card1 = AgentCard(name="Test Provider 1", description="First test provider") provider1 = await Provider.create(location="http://localhost:9001", agent_card=agent_card1) assert provider1.id is not None # Create second dummy provider with network URL - agent_card2 = AgentCard( - name="Test Provider 2", - description="Second test provider", - url="http://localhost:9002/", - version="1.0.0", - default_input_modes=["text"], - default_output_modes=["text"], - capabilities=AgentCapabilities(), - skills=[], - ) + agent_card2 = AgentCard(name="Test Provider 2", description="Second test provider") provider2 = await Provider.create(location="http://localhost:9002", agent_card=agent_card2) assert provider2.id is not None assert provider1.id != provider2.id diff --git a/apps/agentstack-server/tests/e2e/routes/test_provider_variables.py b/apps/agentstack-server/tests/e2e/routes/test_provider_variables.py index a1fea923d4..0b0dd780f9 100644 --- a/apps/agentstack-server/tests/e2e/routes/test_provider_variables.py +++ b/apps/agentstack-server/tests/e2e/routes/test_provider_variables.py @@ -4,7 +4,7 @@ from __future__ import annotations import pytest -from a2a.types import AgentCapabilities, AgentCard +from a2a.types import AgentCard from agentstack_sdk.platform import Provider from tests.conftest import Configuration @@ -19,16 +19,7 @@ async def test_provider_variables(subtests, test_configuration: Configuration): # First create a real test provider provider = await Provider.create( location=test_configuration.test_agent_image, - agent_card=AgentCard( - capabilities=AgentCapabilities(), - default_input_modes=[], - default_output_modes=[], - name="test_agent", - skills=[], - description="test agent", - url="http://localhost:8000", - version="0.0.1", - ), + agent_card=AgentCard(name="test_agent", description="test agent"), ) provider_id = provider.id diff --git a/apps/agentstack-server/tests/e2e/routes/test_providers.py b/apps/agentstack-server/tests/e2e/routes/test_providers.py index 282acd1ebb..3c97b9ddb3 100644 --- a/apps/agentstack-server/tests/e2e/routes/test_providers.py +++ b/apps/agentstack-server/tests/e2e/routes/test_providers.py @@ -5,7 +5,7 @@ import logging import pytest -from a2a.types import AgentCapabilities, AgentCard +from a2a.types import AgentCard from agentstack_sdk.platform import Provider from httpx import HTTPError @@ -23,16 +23,7 @@ async def test_provider_crud(subtests, test_configuration): with subtests.test("patch provider"): new_source = test_configuration.test_agent_image - new_agent_card = AgentCard( - name="test", - description="test", - url="http://localhost:8000/", - version="1.0.0", - default_input_modes=["text"], - default_output_modes=["text"], - capabilities=AgentCapabilities(), - skills=[], - ) + new_agent_card = AgentCard(name="test", description="test") provider = await provider.patch(location=new_source, agent_card=new_agent_card) assert provider.agent_card.name == new_agent_card.name assert provider.source == new_source diff --git a/apps/agentstack-server/tests/integration/persistence/repositories/test_provider.py b/apps/agentstack-server/tests/integration/persistence/repositories/test_provider.py index 11ebdf417c..dc6fea8292 100644 --- a/apps/agentstack-server/tests/integration/persistence/repositories/test_provider.py +++ b/apps/agentstack-server/tests/integration/persistence/repositories/test_provider.py @@ -6,10 +6,13 @@ import json import uuid from datetime import timedelta +from uuid import UUID import pytest from a2a.types import AgentCapabilities, AgentCard -from sqlalchemy import UUID, text +from google.protobuf.json_format import MessageToDict +from pydantic import HttpUrl +from sqlalchemy import text from sqlalchemy.ext.asyncio import AsyncConnection from agentstack_server.configuration import Configuration @@ -31,20 +34,21 @@ def set_di_configuration(override_global_dependency): @pytest.fixture async def test_provider(set_di_configuration, normal_user: UUID) -> Provider: """Create a test provider for use in tests.""" - source = NetworkProviderLocation(root="http://localhost:8000") + source = NetworkProviderLocation(root=HttpUrl("http://localhost:8000")) return Provider( source=source, origin=source.origin, registry=None, - agent_card=AgentCard( - name="Hello World Agent", - description="Just a hello world agent", - url="http://localhost:8000/", - version="1.0.0", - default_input_modes=["text"], - default_output_modes=["text"], - capabilities=AgentCapabilities(), - skills=[], + agent_card=MessageToDict( + AgentCard( + name="Hello World Agent", + description="Just a hello world agent", + version="1.0.0", + default_input_modes=["text"], + default_output_modes=["text"], + capabilities=AgentCapabilities(), + skills=[], + ) ), auto_stop_timeout=timedelta(minutes=5), created_by=normal_user, @@ -256,11 +260,12 @@ async def test_create_duplicate_provider(db_transaction: AsyncConnection, test_p # Try to create provider with same source (will generate same ID) duplicate_source = NetworkProviderLocation(root="http://localhost:8000") # Same source, will generate same ID + duplicate_card = {**test_provider.agent_card, "name": "NEW_AGENT"} duplicate_provider = Provider( source=duplicate_source, origin=duplicate_source.origin, registry=None, - agent_card=test_provider.agent_card.model_copy(update={"name": "NEW_AGENT"}), + agent_card=duplicate_card, auto_stop_timeout=timedelta(minutes=10), # Different timeout created_by=normal_user, ) diff --git a/apps/agentstack-server/tests/integration/utils/test_docker.py b/apps/agentstack-server/tests/integration/utils/test_docker.py index e6f7709c25..4ed017baac 100644 --- a/apps/agentstack-server/tests/integration/utils/test_docker.py +++ b/apps/agentstack-server/tests/integration/utils/test_docker.py @@ -29,13 +29,14 @@ def configuration(): @pytest.mark.parametrize( "image", [ - DockerImageID(root="ghcr.io/i-am-bee/agentstack/agents/chat:0.4.0-rc1"), - DockerImageID(root="redis:latest"), - DockerImageID(root="icr.io/ibm-messaging/mq:latest"), - DockerImageID(root="registry.goharbor.io/nightly/goharbor/harbor-log:v1.10.0"), + "ghcr.io/i-am-bee/agentstack/agents/chat:0.4.0-rc1", + "redis:latest", + "icr.io/ibm-messaging/mq:latest", + "registry.goharbor.io/nightly/goharbor/harbor-log:v1.10.0", ], ) +@pytest.mark.asyncio(loop_scope="session") async def test_get_image_labels(image, configuration): - resolved_image = await image.resolve_version() + resolved_image = await DockerImageID(root=image).resolve_version() assert resolved_image.digest await resolved_image.get_labels() diff --git a/apps/agentstack-server/uv.lock b/apps/agentstack-server/uv.lock index 01ffbec36e..1e2f88e0ee 100644 --- a/apps/agentstack-server/uv.lock +++ b/apps/agentstack-server/uv.lock @@ -4,19 +4,17 @@ requires-python = "==3.14.*" [[package]] name = "a2a-sdk" -version = "0.3.24" -source = { registry = "https://pypi.org/simple" } +version = "0.3.24.post37.dev0+dce3650" +source = { git = "https://github.com/a2aproject/a2a-python.git?rev=1.0-dev#dce36502b51f671ae0e0a926cc0ad8c208393329" } dependencies = [ { name = "google-api-core" }, + { name = "googleapis-common-protos" }, { name = "httpx" }, { name = "httpx-sse" }, + { name = "json-rpc" }, { name = "protobuf" }, { name = "pydantic" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ad/76/cefa956fb2d3911cb91552a1da8ce2dbb339f1759cb475e2982f0ae2332b/a2a_sdk-0.3.24.tar.gz", hash = "sha256:3581e6e8a854cd725808f5732f90b7978e661b6d4e227a4755a8f063a3c1599d", size = 255550, upload-time = "2026-02-20T10:05:43.423Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/10/6e/cae5f0caea527b39c0abd7204d9416768764573c76649ca03cc345a372be/a2a_sdk-0.3.24-py3-none-any.whl", hash = "sha256:7b248767096bb55311f57deebf6b767349388d94c1b376c60cb8f6b715e053f6", size = 145752, upload-time = "2026-02-20T10:05:41.729Z" }, -] [[package]] name = "agentstack-sdk" @@ -49,7 +47,7 @@ dependencies = [ [package.metadata] requires-dist = [ - { name = "a2a-sdk", specifier = "==0.3.24" }, + { name = "a2a-sdk", git = "https://github.com/a2aproject/a2a-python.git?rev=1.0-dev" }, { name = "anyio", specifier = ">=4.9.0" }, { name = "async-lru", specifier = ">=2.0.4" }, { name = "asyncclick", specifier = ">=8.1.8" }, @@ -518,11 +516,11 @@ wheels = [ [[package]] name = "certifi" -version = "2026.1.4" +version = "2026.2.25" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e0/2d/a891ca51311197f6ad14a7ef42e2399f36cf2f9bd44752b3dc4eab60fdc5/certifi-2026.1.4.tar.gz", hash = "sha256:ac726dd470482006e014ad384921ed6438c457018f4b3d204aea4281258b2120", size = 154268, upload-time = "2026-01-04T02:42:41.825Z" } +sdist = { url = "https://files.pythonhosted.org/packages/af/2d/7bf41579a8986e348fa033a31cdd0e4121114f6bce2457e8876010b092dd/certifi-2026.2.25.tar.gz", hash = "sha256:e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7", size = 155029, upload-time = "2026-02-25T02:54:17.342Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c", size = 152900, upload-time = "2026-01-04T02:42:40.15Z" }, + { url = "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl", hash = "sha256:027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa", size = 153684, upload-time = "2026-02-25T02:54:15.766Z" }, ] [[package]] @@ -752,7 +750,7 @@ wheels = [ [[package]] name = "fastapi" -version = "0.131.0" +version = "0.133.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "annotated-doc" }, @@ -761,9 +759,9 @@ dependencies = [ { name = "typing-extensions" }, { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/91/32/158cbf685b7d5a26f87131069da286bf10fc9fbf7fc968d169d48a45d689/fastapi-0.131.0.tar.gz", hash = "sha256:6531155e52bee2899a932c746c9a8250f210e3c3303a5f7b9f8a808bfe0548ff", size = 369612, upload-time = "2026-02-22T16:38:11.252Z" } +sdist = { url = "https://files.pythonhosted.org/packages/22/6f/0eafed8349eea1fa462238b54a624c8b408cd1ba2795c8e64aa6c34f8ab7/fastapi-0.133.1.tar.gz", hash = "sha256:ed152a45912f102592976fde6cbce7dae1a8a1053da94202e51dd35d184fadd6", size = 378741, upload-time = "2026-02-25T18:18:17.398Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ff/94/b58ec24c321acc2ad1327f69b033cadc005e0f26df9a73828c9e9c7db7ce/fastapi-0.131.0-py3-none-any.whl", hash = "sha256:ed0e53decccf4459de78837ce1b867cd04fa9ce4579497b842579755d20b405a", size = 103854, upload-time = "2026-02-22T16:38:09.814Z" }, + { url = "https://files.pythonhosted.org/packages/d2/c9/a175a7779f3599dfa4adfc97a6ce0e157237b3d7941538604aadaf97bfb6/fastapi-0.133.1-py3-none-any.whl", hash = "sha256:658f34ba334605b1617a65adf2ea6461901bdb9af3a3080d63ff791ecf7dc2e2", size = 109029, upload-time = "2026-02-25T18:18:18.578Z" }, ] [package.optional-dependencies] @@ -780,16 +778,16 @@ standard = [ [[package]] name = "fastapi-cli" -version = "0.0.23" +version = "0.0.24" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "rich-toolkit" }, { name = "typer" }, { name = "uvicorn", extra = ["standard"] }, ] -sdist = { url = "https://files.pythonhosted.org/packages/71/9f/cbd463e57de4e977b8ea0403f95347f9150441568b1d3fe3e4949ef80ef3/fastapi_cli-0.0.23.tar.gz", hash = "sha256:210ac280ea41e73aac5a57688781256beb23c2cba3a41266896fa43e6445c8e7", size = 19763, upload-time = "2026-02-16T19:45:53.358Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6e/58/74797ae9e4610cfa0c6b34c8309096d3b20bb29be3b8b5fbf1004d10fa5f/fastapi_cli-0.0.24.tar.gz", hash = "sha256:1afc9c9e21d7ebc8a3ca5e31790cd8d837742be7e4f8b9236e99cb3451f0de00", size = 19043, upload-time = "2026-02-24T10:45:10.476Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/68/89/19dcfd5cd289b306abdcabac68b88a4f54b7710a2c33adc16a337ecdcdfa/fastapi_cli-0.0.23-py3-none-any.whl", hash = "sha256:7e9634fc212da0b6cfc75bd3ac366cc9dfdb43b5e9ec12e58bfd1acdd2697f25", size = 12305, upload-time = "2026-02-16T19:45:52.554Z" }, + { url = "https://files.pythonhosted.org/packages/c7/4b/68f9fe268e535d79c76910519530026a4f994ce07189ac0dded45c6af825/fastapi_cli-0.0.24-py3-none-any.whl", hash = "sha256:4a1f78ed798f106b4fee85ca93b85d8fe33c0a3570f775964d37edb80b8f0edc", size = 12304, upload-time = "2026-02-24T10:45:09.552Z" }, ] [package.optional-dependencies] @@ -800,7 +798,7 @@ standard = [ [[package]] name = "fastapi-cloud-cli" -version = "0.13.0" +version = "0.14.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "fastar" }, @@ -812,9 +810,9 @@ dependencies = [ { name = "typer" }, { name = "uvicorn", extra = ["standard"] }, ] -sdist = { url = "https://files.pythonhosted.org/packages/de/0b/f07f4976784978ef159fd2e8f5c16f1f9d610578fb1fd976ff1315c11ea6/fastapi_cloud_cli-0.13.0.tar.gz", hash = "sha256:4d8f42337e8021c648f6cb0672de7d5b31b0fc7387a83d7b12f974600ac3f2fd", size = 38436, upload-time = "2026-02-17T05:18:19.033Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2b/eb/e78ebd05a714c62a0578cdce4339cb6cd138421a7d865fbddedd7242420b/fastapi_cloud_cli-0.14.0.tar.gz", hash = "sha256:d3ecb8c942685a71df0af7bd59f463b5eff76f5818b48e5a03c6159726831e68", size = 39822, upload-time = "2026-02-25T14:19:53.535Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b4/88/71a1e989d17b9edb483f32e28b7891ffdd3005271518c98ba6415987c430/fastapi_cloud_cli-0.13.0-py3-none-any.whl", hash = "sha256:874a9ed8dba34ec828f198c72de9f9a38de77ac1b15083d6bc3a4d772b0bc477", size = 27631, upload-time = "2026-02-17T05:18:18.094Z" }, + { url = "https://files.pythonhosted.org/packages/d9/18/7bf922ee0b6a737a9d88cf613182ecd6031f52298da893556f158eba763f/fastapi_cloud_cli-0.14.0-py3-none-any.whl", hash = "sha256:325fcb4b45e661184152da6db861d9fb718739fbcd561a4d334dbe78c026586f", size = 28350, upload-time = "2026-02-25T14:19:52.416Z" }, ] [[package]] @@ -1073,7 +1071,7 @@ sdist = { url = "https://files.pythonhosted.org/packages/f3/ff/c9baf0997266d398a [[package]] name = "ibm-watsonx-ai" -version = "1.5.2" +version = "1.5.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cachetools" }, @@ -1087,9 +1085,9 @@ dependencies = [ { name = "tabulate" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/bb/d7/5a4250bc0b4bde2aa9fb44289cd869c8b7df229759098d435ab169bc9eb9/ibm_watsonx_ai-1.5.2.tar.gz", hash = "sha256:c85ccf4eb79a03c8cc27ff891c24c3a9aebcc0da5887baa64bc9bb67d83aaf54", size = 710281, upload-time = "2026-02-12T08:20:37.855Z" } +sdist = { url = "https://files.pythonhosted.org/packages/50/a0/19e0bfefe4fe3409bb73821198a24eac931f12f8c2ea2eb05c98995dffaa/ibm_watsonx_ai-1.5.3.tar.gz", hash = "sha256:610c982416e18479e2029d16062e992d42a5454b6db5ed68541aa53b8f3bfa54", size = 710736, upload-time = "2026-02-26T09:18:03.628Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/18/06dd0320590189c77283315da5368a361cef6b9807f6e44b9a59773139e9/ibm_watsonx_ai-1.5.2-py3-none-any.whl", hash = "sha256:0b9e80128a726788412ca50d63461dcea22ac23caf2057b8a6e32a0c376da18d", size = 1079661, upload-time = "2026-02-12T08:20:36.223Z" }, + { url = "https://files.pythonhosted.org/packages/99/89/f6a113d08bd8796c8ed82b151009479fe7e8a7b4792a12c98918b806c0e6/ibm_watsonx_ai-1.5.3-py3-none-any.whl", hash = "sha256:a7a1af3bebd8271e0fb7a04b17792131ad7f3e697cd4aea0aae0687695cb884f", size = 1080316, upload-time = "2026-02-26T09:18:01.778Z" }, ] [[package]] @@ -1103,32 +1101,32 @@ wheels = [ [[package]] name = "ijson" -version = "3.4.0.post0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2d/30/7ab4b9e88e7946f6beef419f74edcc541df3ea562c7882257b4eaa82417d/ijson-3.4.0.post0.tar.gz", hash = "sha256:9aa02dc70bb245670a6ca7fba737b992aeeb4895360980622f7e568dbf23e41e", size = 67216, upload-time = "2025-10-10T05:29:25.62Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/af/0b/a4ce8524fd850302bbf5d9f38d07c0fa981fdbe44951d2fcd036935b67dd/ijson-3.4.0.post0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:da6a21b88cbf5ecbc53371283988d22c9643aa71ae2873bbeaefd2dea3b6160b", size = 88361, upload-time = "2025-10-10T05:28:43.73Z" }, - { url = "https://files.pythonhosted.org/packages/be/90/a5e5f33e46f28174a9c8142d12dcb3d26ce358d9a2230b9b15f5c987b3a5/ijson-3.4.0.post0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:cf24a48a1c3ca9d44a04feb59ccefeb9aa52bb49b9cb70ad30518c25cce74bb7", size = 59960, upload-time = "2025-10-10T05:28:44.585Z" }, - { url = "https://files.pythonhosted.org/packages/83/e2/551dd7037dda759aa0ce53f0d3d7be03b03c6b05c0b0a5d5ab7a47e6b4b1/ijson-3.4.0.post0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:d14427d366f95f21adcb97d0ed1f6d30f6fdc04d0aa1e4de839152c50c2b8d65", size = 59957, upload-time = "2025-10-10T05:28:45.748Z" }, - { url = "https://files.pythonhosted.org/packages/ac/b9/3006384f85cc26cf83dbbd542d362cc336f1e1ddd491e32147cfa46ea8ae/ijson-3.4.0.post0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:339d49f6c5d24051c85d9226be96d2d56e633cb8b7d09dd8099de8d8b51a97e2", size = 139967, upload-time = "2025-10-10T05:28:47.229Z" }, - { url = "https://files.pythonhosted.org/packages/77/3b/b5234add8115cbfe8635b6c152fb527327f45e4c0f0bf2e93844b36b5217/ijson-3.4.0.post0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7206afcb396aaef66c2b066997b4e9d9042c4b7d777f4d994e9cec6d322c2fe6", size = 149196, upload-time = "2025-10-10T05:28:48.226Z" }, - { url = "https://files.pythonhosted.org/packages/a2/d2/c4ae543e37d7a9fba09740c221976a63705dbad23a9cda9022fc9fa0f3de/ijson-3.4.0.post0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c8dd327da225887194fe8b93f2b3c9c256353e14a6b9eefc940ed17fde38f5b8", size = 148516, upload-time = "2025-10-10T05:28:49.237Z" }, - { url = "https://files.pythonhosted.org/packages/0d/a1/914b5fb1c26af2474cd04841626e0e95576499a4ca940661fb105ee12dd2/ijson-3.4.0.post0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4810546e66128af51fd4a0c9a640e84e8508e9c15c4f247d8a3e3253b20e1465", size = 149770, upload-time = "2025-10-10T05:28:50.501Z" }, - { url = "https://files.pythonhosted.org/packages/7a/c1/51c3584102d0d85d4aa10cc88dbbe431ecb9fe98160a9e2fad62a4456aed/ijson-3.4.0.post0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:103a0838061297d063bca81d724b0958b616f372bd893bbc278320152252c652", size = 143688, upload-time = "2025-10-10T05:28:51.823Z" }, - { url = "https://files.pythonhosted.org/packages/47/3d/a54f13d766332620bded8ee76bcdd274509ecc53cf99573450f95b3ad910/ijson-3.4.0.post0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:40007c977e230e04118b27322f25a72ae342a3d61464b2057fcd9b21eeb7427a", size = 150688, upload-time = "2025-10-10T05:28:52.757Z" }, - { url = "https://files.pythonhosted.org/packages/72/49/43d97cccf3266da7c044bd42e5083340ad1fd97fbb16d1bcd6791fd8918f/ijson-3.4.0.post0-cp314-cp314-win32.whl", hash = "sha256:f932969fc1fd4449ca141cf5f47ff357656a154a361f28d9ebca0badc5b02297", size = 52882, upload-time = "2025-10-10T05:28:53.708Z" }, - { url = "https://files.pythonhosted.org/packages/e9/f0/008f1ed4e0fc6f6dc7a5a82ecf08a59bb212514e158954374d440d700e6c/ijson-3.4.0.post0-cp314-cp314-win_amd64.whl", hash = "sha256:3ed19b1e4349240773a8ce4a4bfa450892d4a57949c02c515cd6be5a46b7696a", size = 55568, upload-time = "2025-10-10T05:28:54.79Z" }, - { url = "https://files.pythonhosted.org/packages/69/1c/8a199fded709e762aced89bb7086973c837e432dd714bbad78a6ac789c23/ijson-3.4.0.post0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:226447e40ca9340a39ed07d68ea02ee14b52cb4fe649425b256c1f0073531c83", size = 92345, upload-time = "2025-10-10T05:28:55.657Z" }, - { url = "https://files.pythonhosted.org/packages/be/60/04e97f6a403203bd2eb8849570bdce5719d696b5fb96aa2a62566fe7a1d9/ijson-3.4.0.post0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2c88f0669d45d4b1aa017c9b68d378e7cd15d188dfb6f0209adc78b7f45590a7", size = 62029, upload-time = "2025-10-10T05:28:56.561Z" }, - { url = "https://files.pythonhosted.org/packages/2a/97/e88295f9456ba939d90d4603af28fcabda3b443ef55e709e9381df3daa58/ijson-3.4.0.post0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:56b3089dc28c12492d92cc4896d2be585a89ecae34e25d08c1df88f21815cb50", size = 61776, upload-time = "2025-10-10T05:28:57.401Z" }, - { url = "https://files.pythonhosted.org/packages/1b/9f/0e9c236e720c2de887ab0d7cad8a15d2aa55fb449f792437fc99899957a9/ijson-3.4.0.post0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:c117321cfa7b749cc1213f9b4c80dc958f0a206df98ec038ae4bcbbdb8463a15", size = 199808, upload-time = "2025-10-10T05:28:58.62Z" }, - { url = "https://files.pythonhosted.org/packages/0e/70/c21de30e7013e074924cd82057acfc5760e7b2cc41180f80770621b0ad36/ijson-3.4.0.post0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8311f48db6a33116db5c81682f08b6e2405501a4b4e460193ae69fec3cd1f87a", size = 217152, upload-time = "2025-10-10T05:28:59.656Z" }, - { url = "https://files.pythonhosted.org/packages/64/78/63a0bcc0707037df4e22bb836451279d850592258c859685a402c27f5d6d/ijson-3.4.0.post0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:91c61a3e63e04da648737e6b4abd537df1b46fb8cdf3219b072e790bb3c1a46b", size = 207663, upload-time = "2025-10-10T05:29:00.73Z" }, - { url = "https://files.pythonhosted.org/packages/7d/85/834e9838d69893cb7567e1210be044444213c78f7414aaf1cd241df16078/ijson-3.4.0.post0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:1709171023ce82651b2f132575c2e6282e47f64ad67bd3260da476418d0e7895", size = 211157, upload-time = "2025-10-10T05:29:01.87Z" }, - { url = "https://files.pythonhosted.org/packages/2e/9b/9fda503799ebc30397710552e5dedc1d98d9ea6a694e5717415892623a94/ijson-3.4.0.post0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:5f0a72b1e3c0f78551670c12b2fdc1bf05f2796254d9c2055ba319bec2216020", size = 200231, upload-time = "2025-10-10T05:29:02.883Z" }, - { url = "https://files.pythonhosted.org/packages/15/f3/6419d1d5795a16591233d3aa3747b084e82c0c1d7184bdad9be638174560/ijson-3.4.0.post0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b982a3597b0439ce9c8f4cfc929d86c6ed43907908be1e8463a34dc35fe5b258", size = 204825, upload-time = "2025-10-10T05:29:04.242Z" }, - { url = "https://files.pythonhosted.org/packages/1f/8d/a520e6902129c55fa94428ea0a22e8547540d5e7ca30f18b39594a5feea2/ijson-3.4.0.post0-cp314-cp314t-win32.whl", hash = "sha256:4e39bfdc36b0b460ef15a06550a6a385c64c81f7ac205ccff39bd45147918912", size = 55559, upload-time = "2025-10-10T05:29:05.681Z" }, - { url = "https://files.pythonhosted.org/packages/20/67/0ac6dd0045957ba1270b7b1860864f7d8cea4062e70b1083134c587e5768/ijson-3.4.0.post0-cp314-cp314t-win_amd64.whl", hash = "sha256:17e45262a5ddef39894013fb1548ee7094e444c8389eb1a97f86708b19bea03e", size = 58238, upload-time = "2025-10-10T05:29:06.656Z" }, +version = "3.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f4/57/60d1a6a512f2f0508d0bc8b4f1cc5616fd3196619b66bd6a01f9155a1292/ijson-3.5.0.tar.gz", hash = "sha256:94688760720e3f5212731b3cb8d30267f9a045fb38fb3870254e7b9504246f31", size = 68658, upload-time = "2026-02-24T03:58:30.974Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7a/93/0868efe753dc1df80cc405cf0c1f2527a6991643607c741bff8dcb899b3b/ijson-3.5.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:25a5a6b2045c90bb83061df27cfa43572afa43ba9408611d7bfe237c20a731a9", size = 89094, upload-time = "2026-02-24T03:57:46.115Z" }, + { url = "https://files.pythonhosted.org/packages/24/94/fd5a832a0df52ef5e4e740f14ac8640725d61034a1b0c561e8b5fb424706/ijson-3.5.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:8976c54c0b864bc82b951bae06567566ac77ef63b90a773a69cd73aab47f4f4f", size = 60715, upload-time = "2026-02-24T03:57:47.552Z" }, + { url = "https://files.pythonhosted.org/packages/70/79/1b9a90af5732491f9eec751ee211b86b11011e1158c555c06576d52c3919/ijson-3.5.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:859eb2038f7f1b0664df4241957694cc35e6295992d71c98659b22c69b3cbc10", size = 60638, upload-time = "2026-02-24T03:57:48.428Z" }, + { url = "https://files.pythonhosted.org/packages/23/6f/2c551ea980fe56f68710a8d5389cfbd015fc45aaafd17c3c52c346db6aa1/ijson-3.5.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:c911aa02991c7c0d3639b6619b93a93210ff1e7f58bf7225d613abea10adc78e", size = 140667, upload-time = "2026-02-24T03:57:49.314Z" }, + { url = "https://files.pythonhosted.org/packages/25/0e/27b887879ba6a5bc29766e3c5af4942638c952220fd63e1e442674f7883a/ijson-3.5.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:903cbdc350173605220edc19796fbea9b2203c8b3951fb7335abfa8ed37afda8", size = 149850, upload-time = "2026-02-24T03:57:50.329Z" }, + { url = "https://files.pythonhosted.org/packages/da/1e/23e10e1bc04bf31193b21e2960dce14b17dbd5d0c62204e8401c59d62c08/ijson-3.5.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a4549d96ded5b8efa71639b2160235415f6bdb8c83367615e2dbabcb72755c33", size = 149206, upload-time = "2026-02-24T03:57:51.261Z" }, + { url = "https://files.pythonhosted.org/packages/8e/90/e552f6495063b235cf7fa2c592f6597c057077195e517b842a0374fd470c/ijson-3.5.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:6b2dcf6349e6042d83f3f8c39ce84823cf7577eba25bac5aae5e39bbbbbe9c1c", size = 150438, upload-time = "2026-02-24T03:57:52.198Z" }, + { url = "https://files.pythonhosted.org/packages/5c/18/45bf8f297c41b42a1c231d261141097babd953d2c28a07be57ae4c3a1a02/ijson-3.5.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:e44af39e6f8a17e5627dcd89715d8279bf3474153ff99aae031a936e5c5572e5", size = 144369, upload-time = "2026-02-24T03:57:53.22Z" }, + { url = "https://files.pythonhosted.org/packages/9b/3a/deb9772bb2c0cead7ad64f00c3598eec9072bdf511818e70e2c512eeabbe/ijson-3.5.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9260332304b7e7828db56d43f08fc970a3ab741bf84ff10189361ea1b60c395b", size = 151352, upload-time = "2026-02-24T03:57:54.375Z" }, + { url = "https://files.pythonhosted.org/packages/e4/51/67f4d80cd58ad7eab0cd1af5fe28b961886338956b2f88c0979e21914346/ijson-3.5.0-cp314-cp314-win32.whl", hash = "sha256:63bc8121bb422f6969ced270173a3fa692c29d4ae30c860a2309941abd81012a", size = 53610, upload-time = "2026-02-24T03:57:55.655Z" }, + { url = "https://files.pythonhosted.org/packages/70/d3/263672ea22983ba3940f1534316dbc9200952c1c2a2332d7a664e4eaa7ae/ijson-3.5.0-cp314-cp314-win_amd64.whl", hash = "sha256:01b6dad72b7b7df225ef970d334556dfad46c696a2c6767fb5d9ed8889728bca", size = 56301, upload-time = "2026-02-24T03:57:56.584Z" }, + { url = "https://files.pythonhosted.org/packages/9f/d9/86f7fac35e0835faa188085ae0579e813493d5261ce056484015ad533445/ijson-3.5.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:2ea4b676ec98e374c1df400a47929859e4fa1239274339024df4716e802aa7e4", size = 93069, upload-time = "2026-02-24T03:57:57.849Z" }, + { url = "https://files.pythonhosted.org/packages/33/d2/e7366ed9c6e60228d35baf4404bac01a126e7775ea8ce57f560125ed190a/ijson-3.5.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:014586eec043e23c80be9a923c56c3a0920a0f1f7d17478ce7bc20ba443968ef", size = 62767, upload-time = "2026-02-24T03:57:58.758Z" }, + { url = "https://files.pythonhosted.org/packages/35/8b/3e703e8cc4b3ada79f13b28070b51d9550c578f76d1968657905857b2ddd/ijson-3.5.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:d5b8b886b0248652d437f66e7c5ac318bbdcb2c7137a7e5327a68ca00b286f5f", size = 62467, upload-time = "2026-02-24T03:58:00.261Z" }, + { url = "https://files.pythonhosted.org/packages/21/42/0c91af32c1ee8a957fdac2e051b5780756d05fd34e4b60d94a08d51bac1d/ijson-3.5.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:498fd46ae2349297e43acf97cdc421e711dbd7198418677259393d2acdc62d78", size = 200447, upload-time = "2026-02-24T03:58:01.591Z" }, + { url = "https://files.pythonhosted.org/packages/f9/80/796ea0e391b7e2d45c5b1b451734bba03f81c2984cf955ea5eaa6c4920ad/ijson-3.5.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:22a51b4f9b81f12793731cf226266d1de2112c3c04ba4a04117ad4e466897e05", size = 217820, upload-time = "2026-02-24T03:58:02.598Z" }, + { url = "https://files.pythonhosted.org/packages/38/14/52b6613fdda4078c62eb5b4fe3efc724ddc55a4ad524c93de51830107aa3/ijson-3.5.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9636c710dc4ac4a281baa266a64f323b4cc165cec26836af702c44328b59a515", size = 208310, upload-time = "2026-02-24T03:58:04.759Z" }, + { url = "https://files.pythonhosted.org/packages/6a/ad/8b3105a78774fd4a65e534a21d975ef3a77e189489fe3029ebcaeba5e243/ijson-3.5.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:f7168a39e8211107666d71b25693fd1b2bac0b33735ef744114c403c6cac21e1", size = 211843, upload-time = "2026-02-24T03:58:05.836Z" }, + { url = "https://files.pythonhosted.org/packages/36/ab/a2739f6072d6e1160581bc3ed32da614c8cced023dcd519d9c5fa66e0425/ijson-3.5.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:8696454245415bc617ab03b0dc3ae4c86987df5dc6a90bad378fe72c5409d89e", size = 200906, upload-time = "2026-02-24T03:58:07.788Z" }, + { url = "https://files.pythonhosted.org/packages/6d/5e/e06c2de3c3d4a9cfb655c1ad08a68fb72838d271072cdd3196576ac4431a/ijson-3.5.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c21bfb61f71f191565885bf1bc29e0a186292d866b4880637b833848360bdc1b", size = 205495, upload-time = "2026-02-24T03:58:09.163Z" }, + { url = "https://files.pythonhosted.org/packages/7c/11/778201eb2e202ddd76b36b0fb29bf3d8e3c167389d8aa883c62524e49f47/ijson-3.5.0-cp314-cp314t-win32.whl", hash = "sha256:a2619460d6795b70d0155e5bf016200ac8a63ab5397aa33588bb02b6c21759e6", size = 56280, upload-time = "2026-02-24T03:58:10.116Z" }, + { url = "https://files.pythonhosted.org/packages/23/28/96711503245339084c8086b892c47415895eba49782d6cc52d9f4ee50301/ijson-3.5.0-cp314-cp314t-win_amd64.whl", hash = "sha256:4f24b78d4ef028d17eb57ad1b16c0aed4a17bdd9badbf232dc5d9305b7e13854", size = 58965, upload-time = "2026-02-24T03:58:11.278Z" }, ] [[package]] @@ -1215,6 +1213,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/31/b4/b9b800c45527aadd64d5b442f9b932b00648617eb5d63d2c7a6587b7cafc/jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980", size = 20256, upload-time = "2022-06-17T18:00:10.251Z" }, ] +[[package]] +name = "json-rpc" +version = "1.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6d/9e/59f4a5b7855ced7346ebf40a2e9a8942863f644378d956f68bcef2c88b90/json-rpc-1.15.0.tar.gz", hash = "sha256:e6441d56c1dcd54241c937d0a2dcd193bdf0bdc539b5316524713f554b7f85b9", size = 28854, upload-time = "2023-06-11T09:45:49.078Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/9e/820c4b086ad01ba7d77369fb8b11470a01fac9b4977f02e18659cf378b6b/json_rpc-1.15.0-py2.py3-none-any.whl", hash = "sha256:4a4668bbbe7116feb4abbd0f54e64a4adcf4b8f648f19ffa0848ad0f6606a9bf", size = 39450, upload-time = "2023-06-11T09:45:47.136Z" }, +] + [[package]] name = "jsonschema" version = "4.26.0" @@ -1491,7 +1498,7 @@ wheels = [ [[package]] name = "openai" -version = "2.21.0" +version = "2.24.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, @@ -1503,9 +1510,9 @@ dependencies = [ { name = "tqdm" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/92/e5/3d197a0947a166649f566706d7a4c8f7fe38f1fa7b24c9bcffe4c7591d44/openai-2.21.0.tar.gz", hash = "sha256:81b48ce4b8bbb2cc3af02047ceb19561f7b1dc0d4e52d1de7f02abfd15aa59b7", size = 644374, upload-time = "2026-02-14T00:12:01.577Z" } +sdist = { url = "https://files.pythonhosted.org/packages/55/13/17e87641b89b74552ed408a92b231283786523edddc95f3545809fab673c/openai-2.24.0.tar.gz", hash = "sha256:1e5769f540dbd01cb33bc4716a23e67b9d695161a734aff9c5f925e2bf99a673", size = 658717, upload-time = "2026-02-24T20:02:07.958Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cc/56/0a89092a453bb2c676d66abee44f863e742b2110d4dbb1dbcca3f7e5fc33/openai-2.21.0-py3-none-any.whl", hash = "sha256:0bc1c775e5b1536c294eded39ee08f8407656537ccc71b1004104fe1602e267c", size = 1103065, upload-time = "2026-02-14T00:11:59.603Z" }, + { url = "https://files.pythonhosted.org/packages/c9/30/844dc675ee6902579b8eef01ed23917cc9319a1c9c0c14ec6e39340c96d0/openai-2.24.0-py3-none-any.whl", hash = "sha256:fed30480d7d6c884303287bde864980a4b137b60553ffbcf9ab4a233b7a73d94", size = 1120122, upload-time = "2026-02-24T20:02:05.669Z" }, ] [[package]] @@ -1616,7 +1623,7 @@ wheels = [ [[package]] name = "opentelemetry-instrumentation-openai" -version = "0.52.4" +version = "0.52.6" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, @@ -1624,9 +1631,9 @@ dependencies = [ { name = "opentelemetry-semantic-conventions" }, { name = "opentelemetry-semantic-conventions-ai" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/37/91/1f72807c84cfaf5b3386011f56357ea304f9e6c0039857d3fa38a13e4d03/opentelemetry_instrumentation_openai-0.52.4.tar.gz", hash = "sha256:690b9c14d68b50c87f24006122165e97819557c13ff7f520e2043e2f69f2789c", size = 6978369, upload-time = "2026-02-19T13:22:02.051Z" } +sdist = { url = "https://files.pythonhosted.org/packages/37/86/1fe5008f3714118fdc1024cd141140a5f204d5ac7016e87a0f07a834efb2/opentelemetry_instrumentation_openai-0.52.6.tar.gz", hash = "sha256:0eb23dc90804a726e516fcbd649cb99f10dfdb5e31d29e44c4b1b8f402dd905d", size = 6978397, upload-time = "2026-02-26T15:40:17.154Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a3/5a/0a0d6cf2b93cd1ec6f7c84f8731ad2d20e6313564362690eee6bbde9b989/opentelemetry_instrumentation_openai-0.52.4-py3-none-any.whl", hash = "sha256:73e6837a5ea44f61439c937f7116c623ccdf390034e3393d501e82f9d6298922", size = 43082, upload-time = "2026-02-19T13:21:18.997Z" }, + { url = "https://files.pythonhosted.org/packages/2c/4a/4623d0adc0187cc45bce631f891c30cd01cf2562d37b918b79561200d985/opentelemetry_instrumentation_openai-0.52.6-py3-none-any.whl", hash = "sha256:5e174388520f294f648f9732471c1b9919c71e5d09649a64ab8ff81714c1278b", size = 43084, upload-time = "2026-02-26T15:39:35.584Z" }, ] [[package]] @@ -2106,18 +2113,18 @@ wheels = [ [[package]] name = "pyrefly" -version = "0.53.0" +version = "0.54.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/3a/73/262196c4ea5afec6389366a4b3d49f67655c6396efa1a4053cca37be7c8d/pyrefly-0.53.0.tar.gz", hash = "sha256:aef117e8abb9aa4cf17fc64fbf450d825d3c65fc9de3c02ed20129ebdd57aa74", size = 5040338, upload-time = "2026-02-17T21:15:44.877Z" } +sdist = { url = "https://files.pythonhosted.org/packages/81/44/c10b16a302fda90d0af1328f880b232761b510eab546616a7be2fdf35a57/pyrefly-0.54.0.tar.gz", hash = "sha256:c6663be64d492f0d2f2a411ada9f28a6792163d34133639378b7f3dd9a8dca94", size = 5098893, upload-time = "2026-02-23T15:44:35.111Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e5/9b/3af46ac06dcfd7b27f15e991d2d4f0082519e6906b1f304f511e4db3ad5f/pyrefly-0.53.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:79d7fb35dff0988b3943c26f74cc752fad54357a0bc33f7db665f02d1c9a5bcc", size = 12041081, upload-time = "2026-02-17T21:15:24.769Z" }, - { url = "https://files.pythonhosted.org/packages/79/4f/23422479153f8f88d1699461bf8f22e32320bb0fc1272774ea8a17463302/pyrefly-0.53.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e1d98b1e86f3c38db44860695b7986e731238e1b19c3cad7a3050476a8f6f84d", size = 11604301, upload-time = "2026-02-17T21:15:27.23Z" }, - { url = "https://files.pythonhosted.org/packages/d8/9a/f4cc6b81a464c31c3112b46abbd44ccd569f01c71a0abf39eeccf6ace914/pyrefly-0.53.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb9f2440f7e0c70aa18400f44aed994c326a1ab00f2b01cf7253a63fc62d7c6b", size = 32674148, upload-time = "2026-02-17T21:15:29.762Z" }, - { url = "https://files.pythonhosted.org/packages/4c/cc/fa98606a628380b7ae4623dbc30843e8fed6b7a631c89503bdf123e47453/pyrefly-0.53.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e4e826a5ff2aba2c41e02e6094580751c512db7916e60728cd8612dbcf178d7b", size = 35099098, upload-time = "2026-02-17T21:15:32.383Z" }, - { url = "https://files.pythonhosted.org/packages/71/d2/ab4105ee90495314a8ad6be4d6736c9f20e4b0ceb49cf015ddc84c394c25/pyrefly-0.53.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf4c69410c7a96b417a390a0e3d340f4370fdab02f9d3eaa222c4bd42e3ce24a", size = 37777824, upload-time = "2026-02-17T21:15:35.474Z" }, - { url = "https://files.pythonhosted.org/packages/38/99/0779b7202d801cdf67f08159cf7dd318d23114661143689a767d9b8a98f1/pyrefly-0.53.0-py3-none-win32.whl", hash = "sha256:00687bb6be6e366b8c0137a89625da40ced3b9212a65e561857ff888fe88e6e8", size = 11111961, upload-time = "2026-02-17T21:15:38.455Z" }, - { url = "https://files.pythonhosted.org/packages/bd/71/dc7e59f0acb81dcf3f56e7ad30e740a08527403cb1d657caca9d44fef803/pyrefly-0.53.0-py3-none-win_amd64.whl", hash = "sha256:e0512e6f7af44ae01cfddba096ff7740e15cbd1d0497a3d34a7afcb504e2b300", size = 11888648, upload-time = "2026-02-17T21:15:40.471Z" }, - { url = "https://files.pythonhosted.org/packages/5d/72/2a7c00a439c6593430289a4581426efe0bee73f6e5a443f501969e104300/pyrefly-0.53.0-py3-none-win_arm64.whl", hash = "sha256:5066e2102769683749102421b8b8667cae26abe1827617f04e8df4317e0a94af", size = 11368150, upload-time = "2026-02-17T21:15:42.74Z" }, + { url = "https://files.pythonhosted.org/packages/5f/99/8fdcdb4e55f0227fdd9f6abce36b619bab1ecb0662b83b66adc8cba3c788/pyrefly-0.54.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:58a3f092b6dc25ef79b2dc6c69a40f36784ca157c312bfc0baea463926a9db6d", size = 12223973, upload-time = "2026-02-23T15:44:14.278Z" }, + { url = "https://files.pythonhosted.org/packages/90/35/c2aaf87a76003ad27b286594d2e5178f811eaa15bfe3d98dba2b47d56dd1/pyrefly-0.54.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:615081414106dd95873bc39c3a4bed68754c6cc24a8177ac51d22f88f88d3eb3", size = 11785585, upload-time = "2026-02-23T15:44:17.468Z" }, + { url = "https://files.pythonhosted.org/packages/c4/4a/ced02691ed67e5a897714979196f08ad279ec7ec7f63c45e00a75a7f3c0e/pyrefly-0.54.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cbcaf20f5fe585079079a95205c1f3cd4542d17228cdf1df560288880623b70", size = 33381977, upload-time = "2026-02-23T15:44:19.736Z" }, + { url = "https://files.pythonhosted.org/packages/0b/ce/72a117ed437c8f6950862181014b41e36f3c3997580e29b772b71e78d587/pyrefly-0.54.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66d5da116c0d34acfbd66663addd3ca8aa78a636f6692a66e078126d3620a883", size = 35962821, upload-time = "2026-02-23T15:44:22.357Z" }, + { url = "https://files.pythonhosted.org/packages/85/de/89013f5ae0a35d2b6b01274a92a35ee91431ea001050edf0a16748d39875/pyrefly-0.54.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ef3ac27f1a4baaf67aead64287d3163350844794aca6315ad1a9650b16ec26a", size = 38496689, upload-time = "2026-02-23T15:44:25.236Z" }, + { url = "https://files.pythonhosted.org/packages/9f/9a/33b097c7bf498b924742dca32dd5d9c6a3fa6c2b52b63a58eb9e1980ca89/pyrefly-0.54.0-py3-none-win32.whl", hash = "sha256:7d607d72200a8afbd2db10bfefb40160a7a5d709d207161c21649cedd5cfc09a", size = 11295268, upload-time = "2026-02-23T15:44:27.551Z" }, + { url = "https://files.pythonhosted.org/packages/d4/21/9263fd1144d2a3d7342b474f183f7785b3358a1565c864089b780110b933/pyrefly-0.54.0-py3-none-win_amd64.whl", hash = "sha256:fd416f04f89309385696f685bd5c9141011f18c8072f84d31ca20c748546e791", size = 12081810, upload-time = "2026-02-23T15:44:29.461Z" }, + { url = "https://files.pythonhosted.org/packages/ea/5b/fad062a196c064cbc8564de5b2f4d3cb6315f852e3b31e8a1ce74c69a1ea/pyrefly-0.54.0-py3-none-win_arm64.whl", hash = "sha256:f06ab371356c7b1925e0bffe193b738797e71e5dbbff7fb5a13f90ee7521211d", size = 11564930, upload-time = "2026-02-23T15:44:33.053Z" }, ] [[package]] @@ -2367,16 +2374,16 @@ wheels = [ [[package]] name = "rich-toolkit" -version = "0.19.4" +version = "0.19.7" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, { name = "rich" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d0/c9/4bbf4bfee195ed1b7d7a6733cc523ca61dbfb4a3e3c12ea090aaffd97597/rich_toolkit-0.19.4.tar.gz", hash = "sha256:52e23d56f9dc30d1343eb3b3f6f18764c313fbfea24e52e6a1d6069bec9c18eb", size = 193951, upload-time = "2026-02-12T10:08:15.814Z" } +sdist = { url = "https://files.pythonhosted.org/packages/42/ba/dae9e3096651042754da419a4042bc1c75e07d615f9b15066d738838e4df/rich_toolkit-0.19.7.tar.gz", hash = "sha256:133c0915872da91d4c25d85342d5ec1dfacc69b63448af1a08a0d4b4f23ef46e", size = 195877, upload-time = "2026-02-24T16:06:20.555Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/28/31/97d39719def09c134385bfcfbedfed255168b571e7beb3ad7765aae660ca/rich_toolkit-0.19.4-py3-none-any.whl", hash = "sha256:34ac344de8862801644be8b703e26becf44b047e687f208d7829e8f7cfc311d6", size = 32757, upload-time = "2026-02-12T10:08:15.037Z" }, + { url = "https://files.pythonhosted.org/packages/fb/3c/c923619f6d2f5fafcc96fec0aaf9550a46cd5b6481f06e0c6b66a2a4fed0/rich_toolkit-0.19.7-py3-none-any.whl", hash = "sha256:0288e9203728c47c5a4eb60fd2f0692d9df7455a65901ab6f898437a2ba5989d", size = 32963, upload-time = "2026-02-24T16:06:22.066Z" }, ] [[package]] @@ -2468,27 +2475,27 @@ wheels = [ [[package]] name = "ruff" -version = "0.15.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/06/04/eab13a954e763b0606f460443fcbf6bb5a0faf06890ea3754ff16523dce5/ruff-0.15.2.tar.gz", hash = "sha256:14b965afee0969e68bb871eba625343b8673375f457af4abe98553e8bbb98342", size = 4558148, upload-time = "2026-02-19T22:32:20.271Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2f/70/3a4dc6d09b13cb3e695f28307e5d889b2e1a66b7af9c5e257e796695b0e6/ruff-0.15.2-py3-none-linux_armv6l.whl", hash = "sha256:120691a6fdae2f16d65435648160f5b81a9625288f75544dc40637436b5d3c0d", size = 10430565, upload-time = "2026-02-19T22:32:41.824Z" }, - { url = "https://files.pythonhosted.org/packages/71/0b/bb8457b56185ece1305c666dc895832946d24055be90692381c31d57466d/ruff-0.15.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:a89056d831256099658b6bba4037ac6dd06f49d194199215befe2bb10457ea5e", size = 10820354, upload-time = "2026-02-19T22:32:07.366Z" }, - { url = "https://files.pythonhosted.org/packages/2d/c1/e0532d7f9c9e0b14c46f61b14afd563298b8b83f337b6789ddd987e46121/ruff-0.15.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e36dee3a64be0ebd23c86ffa3aa3fd3ac9a712ff295e192243f814a830b6bd87", size = 10170767, upload-time = "2026-02-19T22:32:13.188Z" }, - { url = "https://files.pythonhosted.org/packages/47/e8/da1aa341d3af017a21c7a62fb5ec31d4e7ad0a93ab80e3a508316efbcb23/ruff-0.15.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9fb47b6d9764677f8c0a193c0943ce9a05d6763523f132325af8a858eadc2b9", size = 10529591, upload-time = "2026-02-19T22:32:02.547Z" }, - { url = "https://files.pythonhosted.org/packages/93/74/184fbf38e9f3510231fbc5e437e808f0b48c42d1df9434b208821efcd8d6/ruff-0.15.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f376990f9d0d6442ea9014b19621d8f2aaf2b8e39fdbfc79220b7f0c596c9b80", size = 10260771, upload-time = "2026-02-19T22:32:36.938Z" }, - { url = "https://files.pythonhosted.org/packages/05/ac/605c20b8e059a0bc4b42360414baa4892ff278cec1c91fff4be0dceedefd/ruff-0.15.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2dcc987551952d73cbf5c88d9fdee815618d497e4df86cd4c4824cc59d5dd75f", size = 11045791, upload-time = "2026-02-19T22:32:31.642Z" }, - { url = "https://files.pythonhosted.org/packages/fd/52/db6e419908f45a894924d410ac77d64bdd98ff86901d833364251bd08e22/ruff-0.15.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:42a47fd785cbe8c01b9ff45031af875d101b040ad8f4de7bbb716487c74c9a77", size = 11879271, upload-time = "2026-02-19T22:32:29.305Z" }, - { url = "https://files.pythonhosted.org/packages/3e/d8/7992b18f2008bdc9231d0f10b16df7dda964dbf639e2b8b4c1b4e91b83af/ruff-0.15.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cbe9f49354866e575b4c6943856989f966421870e85cd2ac94dccb0a9dcb2fea", size = 11303707, upload-time = "2026-02-19T22:32:22.492Z" }, - { url = "https://files.pythonhosted.org/packages/d7/02/849b46184bcfdd4b64cde61752cc9a146c54759ed036edd11857e9b8443b/ruff-0.15.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b7a672c82b5f9887576087d97be5ce439f04bbaf548ee987b92d3a7dede41d3a", size = 11149151, upload-time = "2026-02-19T22:32:44.234Z" }, - { url = "https://files.pythonhosted.org/packages/70/04/f5284e388bab60d1d3b99614a5a9aeb03e0f333847e2429bebd2aaa1feec/ruff-0.15.2-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:72ecc64f46f7019e2bcc3cdc05d4a7da958b629a5ab7033195e11a438403d956", size = 11091132, upload-time = "2026-02-19T22:32:24.691Z" }, - { url = "https://files.pythonhosted.org/packages/fa/ae/88d844a21110e14d92cf73d57363fab59b727ebeabe78009b9ccb23500af/ruff-0.15.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:8dcf243b15b561c655c1ef2f2b0050e5d50db37fe90115507f6ff37d865dc8b4", size = 10504717, upload-time = "2026-02-19T22:32:26.75Z" }, - { url = "https://files.pythonhosted.org/packages/64/27/867076a6ada7f2b9c8292884ab44d08fd2ba71bd2b5364d4136f3cd537e1/ruff-0.15.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:dab6941c862c05739774677c6273166d2510d254dac0695c0e3f5efa1b5585de", size = 10263122, upload-time = "2026-02-19T22:32:10.036Z" }, - { url = "https://files.pythonhosted.org/packages/e7/ef/faf9321d550f8ebf0c6373696e70d1758e20ccdc3951ad7af00c0956be7c/ruff-0.15.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:1b9164f57fc36058e9a6806eb92af185b0697c9fe4c7c52caa431c6554521e5c", size = 10735295, upload-time = "2026-02-19T22:32:39.227Z" }, - { url = "https://files.pythonhosted.org/packages/2f/55/e8089fec62e050ba84d71b70e7834b97709ca9b7aba10c1a0b196e493f97/ruff-0.15.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:80d24fcae24d42659db7e335b9e1531697a7102c19185b8dc4a028b952865fd8", size = 11241641, upload-time = "2026-02-19T22:32:34.617Z" }, - { url = "https://files.pythonhosted.org/packages/23/01/1c30526460f4d23222d0fabd5888868262fd0e2b71a00570ca26483cd993/ruff-0.15.2-py3-none-win32.whl", hash = "sha256:fd5ff9e5f519a7e1bd99cbe8daa324010a74f5e2ebc97c6242c08f26f3714f6f", size = 10507885, upload-time = "2026-02-19T22:32:15.635Z" }, - { url = "https://files.pythonhosted.org/packages/5c/10/3d18e3bbdf8fc50bbb4ac3cc45970aa5a9753c5cb51bf9ed9a3cd8b79fa3/ruff-0.15.2-py3-none-win_amd64.whl", hash = "sha256:d20014e3dfa400f3ff84830dfb5755ece2de45ab62ecea4af6b7262d0fb4f7c5", size = 11623725, upload-time = "2026-02-19T22:32:04.947Z" }, - { url = "https://files.pythonhosted.org/packages/6d/78/097c0798b1dab9f8affe73da9642bb4500e098cb27fd8dc9724816ac747b/ruff-0.15.2-py3-none-win_arm64.whl", hash = "sha256:cabddc5822acdc8f7b5527b36ceac55cc51eec7b1946e60181de8fe83ca8876e", size = 10941649, upload-time = "2026-02-19T22:32:18.108Z" }, +version = "0.15.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/da/31/d6e536cdebb6568ae75a7f00e4b4819ae0ad2640c3604c305a0428680b0c/ruff-0.15.4.tar.gz", hash = "sha256:3412195319e42d634470cc97aa9803d07e9d5c9223b99bcb1518f0c725f26ae1", size = 4569550, upload-time = "2026-02-26T20:04:14.959Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f2/82/c11a03cfec3a4d26a0ea1e571f0f44be5993b923f905eeddfc397c13d360/ruff-0.15.4-py3-none-linux_armv6l.whl", hash = "sha256:a1810931c41606c686bae8b5b9a8072adac2f611bb433c0ba476acba17a332e0", size = 10453333, upload-time = "2026-02-26T20:04:20.093Z" }, + { url = "https://files.pythonhosted.org/packages/ce/5d/6a1f271f6e31dffb31855996493641edc3eef8077b883eaf007a2f1c2976/ruff-0.15.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:5a1632c66672b8b4d3e1d1782859e98d6e0b4e70829530666644286600a33992", size = 10853356, upload-time = "2026-02-26T20:04:05.808Z" }, + { url = "https://files.pythonhosted.org/packages/b1/d8/0fab9f8842b83b1a9c2bf81b85063f65e93fb512e60effa95b0be49bfc54/ruff-0.15.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:a4386ba2cd6c0f4ff75252845906acc7c7c8e1ac567b7bc3d373686ac8c222ba", size = 10187434, upload-time = "2026-02-26T20:03:54.656Z" }, + { url = "https://files.pythonhosted.org/packages/85/cc/cc220fd9394eff5db8d94dec199eec56dd6c9f3651d8869d024867a91030/ruff-0.15.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2496488bdfd3732747558b6f95ae427ff066d1fcd054daf75f5a50674411e75", size = 10535456, upload-time = "2026-02-26T20:03:52.738Z" }, + { url = "https://files.pythonhosted.org/packages/fa/0f/bced38fa5cf24373ec767713c8e4cadc90247f3863605fb030e597878661/ruff-0.15.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3f1c4893841ff2d54cbda1b2860fa3260173df5ddd7b95d370186f8a5e66a4ac", size = 10287772, upload-time = "2026-02-26T20:04:08.138Z" }, + { url = "https://files.pythonhosted.org/packages/2b/90/58a1802d84fed15f8f281925b21ab3cecd813bde52a8ca033a4de8ab0e7a/ruff-0.15.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:820b8766bd65503b6c30aaa6331e8ef3a6e564f7999c844e9a547c40179e440a", size = 11049051, upload-time = "2026-02-26T20:04:03.53Z" }, + { url = "https://files.pythonhosted.org/packages/d2/ac/b7ad36703c35f3866584564dc15f12f91cb1a26a897dc2fd13d7cb3ae1af/ruff-0.15.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9fb74bab47139c1751f900f857fa503987253c3ef89129b24ed375e72873e85", size = 11890494, upload-time = "2026-02-26T20:04:10.497Z" }, + { url = "https://files.pythonhosted.org/packages/93/3d/3eb2f47a39a8b0da99faf9c54d3eb24720add1e886a5309d4d1be73a6380/ruff-0.15.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f80c98765949c518142b3a50a5db89343aa90f2c2bf7799de9986498ae6176db", size = 11326221, upload-time = "2026-02-26T20:04:12.84Z" }, + { url = "https://files.pythonhosted.org/packages/ff/90/bf134f4c1e5243e62690e09d63c55df948a74084c8ac3e48a88468314da6/ruff-0.15.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:451a2e224151729b3b6c9ffb36aed9091b2996fe4bdbd11f47e27d8f2e8888ec", size = 11168459, upload-time = "2026-02-26T20:04:00.969Z" }, + { url = "https://files.pythonhosted.org/packages/b5/e5/a64d27688789b06b5d55162aafc32059bb8c989c61a5139a36e1368285eb/ruff-0.15.4-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:a8f157f2e583c513c4f5f896163a93198297371f34c04220daf40d133fdd4f7f", size = 11104366, upload-time = "2026-02-26T20:03:48.099Z" }, + { url = "https://files.pythonhosted.org/packages/f1/f6/32d1dcb66a2559763fc3027bdd65836cad9eb09d90f2ed6a63d8e9252b02/ruff-0.15.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:917cc68503357021f541e69b35361c99387cdbbf99bd0ea4aa6f28ca99ff5338", size = 10510887, upload-time = "2026-02-26T20:03:45.771Z" }, + { url = "https://files.pythonhosted.org/packages/ff/92/22d1ced50971c5b6433aed166fcef8c9343f567a94cf2b9d9089f6aa80fe/ruff-0.15.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:e9737c8161da79fd7cfec19f1e35620375bd8b2a50c3e77fa3d2c16f574105cc", size = 10285939, upload-time = "2026-02-26T20:04:22.42Z" }, + { url = "https://files.pythonhosted.org/packages/e6/f4/7c20aec3143837641a02509a4668fb146a642fd1211846634edc17eb5563/ruff-0.15.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:291258c917539e18f6ba40482fe31d6f5ac023994ee11d7bdafd716f2aab8a68", size = 10765471, upload-time = "2026-02-26T20:03:58.924Z" }, + { url = "https://files.pythonhosted.org/packages/d0/09/6d2f7586f09a16120aebdff8f64d962d7c4348313c77ebb29c566cefc357/ruff-0.15.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:3f83c45911da6f2cd5936c436cf86b9f09f09165f033a99dcf7477e34041cbc3", size = 11263382, upload-time = "2026-02-26T20:04:24.424Z" }, + { url = "https://files.pythonhosted.org/packages/1b/fa/2ef715a1cd329ef47c1a050e10dee91a9054b7ce2fcfdd6a06d139afb7ec/ruff-0.15.4-py3-none-win32.whl", hash = "sha256:65594a2d557d4ee9f02834fcdf0a28daa8b3b9f6cb2cb93846025a36db47ef22", size = 10506664, upload-time = "2026-02-26T20:03:50.56Z" }, + { url = "https://files.pythonhosted.org/packages/d0/a8/c688ef7e29983976820d18710f955751d9f4d4eb69df658af3d006e2ba3e/ruff-0.15.4-py3-none-win_amd64.whl", hash = "sha256:04196ad44f0df220c2ece5b0e959c2f37c777375ec744397d21d15b50a75264f", size = 11651048, upload-time = "2026-02-26T20:04:17.191Z" }, + { url = "https://files.pythonhosted.org/packages/3e/0a/9e1be9035b37448ce2e68c978f0591da94389ade5a5abafa4cf99985d1b2/ruff-0.15.4-py3-none-win_arm64.whl", hash = "sha256:60d5177e8cfc70e51b9c5fad936c634872a74209f934c1e79107d11787ad5453", size = 10966776, upload-time = "2026-02-26T20:03:56.908Z" }, ] [[package]] @@ -2545,26 +2552,28 @@ wheels = [ [[package]] name = "sqlalchemy" -version = "2.0.46" +version = "2.0.47" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "greenlet", marker = "platform_machine == 'AMD64' or platform_machine == 'WIN32' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'ppc64le' or platform_machine == 'win32' or platform_machine == 'x86_64'" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/06/aa/9ce0f3e7a9829ead5c8ce549392f33a12c4555a6c0609bb27d882e9c7ddf/sqlalchemy-2.0.46.tar.gz", hash = "sha256:cf36851ee7219c170bb0793dbc3da3e80c582e04a5437bc601bfe8c85c9216d7", size = 9865393, upload-time = "2026-01-21T18:03:45.119Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e9/f8/5ecdfc73383ec496de038ed1614de9e740a82db9ad67e6e4514ebc0708a3/sqlalchemy-2.0.46-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:56bdd261bfd0895452006d5316cbf35739c53b9bb71a170a331fa0ea560b2ada", size = 2152079, upload-time = "2026-01-21T19:05:58.477Z" }, - { url = "https://files.pythonhosted.org/packages/e5/bf/eba3036be7663ce4d9c050bc3d63794dc29fbe01691f2bf5ccb64e048d20/sqlalchemy-2.0.46-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:33e462154edb9493f6c3ad2125931e273bbd0be8ae53f3ecd1c161ea9a1dd366", size = 3272216, upload-time = "2026-01-21T18:46:52.634Z" }, - { url = "https://files.pythonhosted.org/packages/05/45/1256fb597bb83b58a01ddb600c59fe6fdf0e5afe333f0456ed75c0f8d7bd/sqlalchemy-2.0.46-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9bcdce05f056622a632f1d44bb47dbdb677f58cad393612280406ce37530eb6d", size = 3277208, upload-time = "2026-01-21T18:40:16.38Z" }, - { url = "https://files.pythonhosted.org/packages/d9/a0/2053b39e4e63b5d7ceb3372cface0859a067c1ddbd575ea7e9985716f771/sqlalchemy-2.0.46-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:8e84b09a9b0f19accedcbeff5c2caf36e0dd537341a33aad8d680336152dc34e", size = 3221994, upload-time = "2026-01-21T18:46:54.622Z" }, - { url = "https://files.pythonhosted.org/packages/1e/87/97713497d9502553c68f105a1cb62786ba1ee91dea3852ae4067ed956a50/sqlalchemy-2.0.46-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:4f52f7291a92381e9b4de9050b0a65ce5d6a763333406861e33906b8aa4906bf", size = 3243990, upload-time = "2026-01-21T18:40:18.253Z" }, - { url = "https://files.pythonhosted.org/packages/a8/87/5d1b23548f420ff823c236f8bea36b1a997250fd2f892e44a3838ca424f4/sqlalchemy-2.0.46-cp314-cp314-win32.whl", hash = "sha256:70ed2830b169a9960193f4d4322d22be5c0925357d82cbf485b3369893350908", size = 2114215, upload-time = "2026-01-21T18:42:55.232Z" }, - { url = "https://files.pythonhosted.org/packages/3a/20/555f39cbcf0c10cf452988b6a93c2a12495035f68b3dbd1a408531049d31/sqlalchemy-2.0.46-cp314-cp314-win_amd64.whl", hash = "sha256:3c32e993bc57be6d177f7d5d31edb93f30726d798ad86ff9066d75d9bf2e0b6b", size = 2139867, upload-time = "2026-01-21T18:42:56.474Z" }, - { url = "https://files.pythonhosted.org/packages/3e/f0/f96c8057c982d9d8a7a68f45d69c674bc6f78cad401099692fe16521640a/sqlalchemy-2.0.46-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4dafb537740eef640c4d6a7c254611dca2df87eaf6d14d6a5fca9d1f4c3fc0fa", size = 3561202, upload-time = "2026-01-21T18:33:10.337Z" }, - { url = "https://files.pythonhosted.org/packages/d7/53/3b37dda0a5b137f21ef608d8dfc77b08477bab0fe2ac9d3e0a66eaeab6fc/sqlalchemy-2.0.46-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:42a1643dc5427b69aca967dae540a90b0fbf57eaf248f13a90ea5930e0966863", size = 3526296, upload-time = "2026-01-21T18:45:12.657Z" }, - { url = "https://files.pythonhosted.org/packages/33/75/f28622ba6dde79cd545055ea7bd4062dc934e0621f7b3be2891f8563f8de/sqlalchemy-2.0.46-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ff33c6e6ad006bbc0f34f5faf941cfc62c45841c64c0a058ac38c799f15b5ede", size = 3470008, upload-time = "2026-01-21T18:33:11.725Z" }, - { url = "https://files.pythonhosted.org/packages/a9/42/4afecbbc38d5e99b18acef446453c76eec6fbd03db0a457a12a056836e22/sqlalchemy-2.0.46-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:82ec52100ec1e6ec671563bbd02d7c7c8d0b9e71a0723c72f22ecf52d1755330", size = 3476137, upload-time = "2026-01-21T18:45:15.001Z" }, - { url = "https://files.pythonhosted.org/packages/fc/a1/9c4efa03300926601c19c18582531b45aededfb961ab3c3585f1e24f120b/sqlalchemy-2.0.46-py3-none-any.whl", hash = "sha256:f9c11766e7e7c0a2767dda5acb006a118640c9fc0a4104214b96269bfb78399e", size = 1937882, upload-time = "2026-01-21T18:22:10.456Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/cd/4b/1e00561093fe2cd8eef09d406da003c8a118ff02d6548498c1ae677d68d9/sqlalchemy-2.0.47.tar.gz", hash = "sha256:e3e7feb57b267fe897e492b9721ae46d5c7de6f9e8dee58aacf105dc4e154f3d", size = 9886323, upload-time = "2026-02-24T16:34:27.947Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/30/98243209aae58ed80e090ea988d5182244ca7ab3ff59e6d850c3dfc7651e/sqlalchemy-2.0.47-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:b03010a5a5dfe71676bc83f2473ebe082478e32d77e6f082c8fe15a31c3b42a6", size = 2154355, upload-time = "2026-02-24T17:05:48.959Z" }, + { url = "https://files.pythonhosted.org/packages/ab/62/12ca6ea92055fe486d6558a2a4efe93e194ff597463849c01f88e5adb99d/sqlalchemy-2.0.47-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f8e3371aa9024520883a415a09cc20c33cfd3eeccf9e0f4f4c367f940b9cbd44", size = 3274486, upload-time = "2026-02-24T17:18:13.659Z" }, + { url = "https://files.pythonhosted.org/packages/97/88/7dfbdeaa8d42b1584e65d6cc713e9d33b6fa563e0d546d5cb87e545bb0e5/sqlalchemy-2.0.47-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c9449f747e50d518c6e1b40cc379e48bfc796453c47b15e627ea901c201e48a6", size = 3279481, upload-time = "2026-02-24T17:27:26.491Z" }, + { url = "https://files.pythonhosted.org/packages/d0/b7/75e1c1970616a9dd64a8a6fd788248da2ddaf81c95f4875f2a1e8aee4128/sqlalchemy-2.0.47-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:21410f60d5cac1d6bfe360e05bd91b179be4fa0aa6eea6be46054971d277608f", size = 3224269, upload-time = "2026-02-24T17:18:15.078Z" }, + { url = "https://files.pythonhosted.org/packages/31/ac/eec1a13b891df9a8bc203334caf6e6aac60b02f61b018ef3b4124b8c4120/sqlalchemy-2.0.47-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:819841dd5bb4324c284c09e2874cf96fe6338bfb57a64548d9b81a4e39c9871f", size = 3246262, upload-time = "2026-02-24T17:27:27.986Z" }, + { url = "https://files.pythonhosted.org/packages/c9/b0/661b0245b06421058610da39f8ceb34abcc90b49f90f256380968d761dbe/sqlalchemy-2.0.47-cp314-cp314-win32.whl", hash = "sha256:e255ee44821a7ef45649c43064cf94e74f81f61b4df70547304b97a351e9b7db", size = 2116528, upload-time = "2026-02-24T17:22:59.363Z" }, + { url = "https://files.pythonhosted.org/packages/aa/ef/1035a90d899e61810791c052004958be622a2cf3eb3df71c3fe20778c5d0/sqlalchemy-2.0.47-cp314-cp314-win_amd64.whl", hash = "sha256:209467ff73ea1518fe1a5aaed9ba75bb9e33b2666e2553af9ccd13387bf192cb", size = 2142181, upload-time = "2026-02-24T17:23:01.001Z" }, + { url = "https://files.pythonhosted.org/packages/76/bb/17a1dd09cbba91258218ceb582225f14b5364d2683f9f5a274f72f2d764f/sqlalchemy-2.0.47-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e78fd9186946afaa287f8a1fe147ead06e5d566b08c0afcb601226e9c7322a64", size = 3563477, upload-time = "2026-02-24T17:12:18.46Z" }, + { url = "https://files.pythonhosted.org/packages/66/8f/1a03d24c40cc321ef2f2231f05420d140bb06a84f7047eaa7eaa21d230ba/sqlalchemy-2.0.47-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5740e2f31b5987ed9619d6912ae5b750c03637f2078850da3002934c9532f172", size = 3528568, upload-time = "2026-02-24T17:28:03.732Z" }, + { url = "https://files.pythonhosted.org/packages/fd/53/d56a213055d6b038a5384f0db5ece7343334aca230ff3f0fa1561106f22c/sqlalchemy-2.0.47-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:fb9ac00d03de93acb210e8ec7243fefe3e012515bf5fd2f0898c8dff38bc77a4", size = 3472284, upload-time = "2026-02-24T17:12:20.319Z" }, + { url = "https://files.pythonhosted.org/packages/ff/19/c235d81b9cfdd6130bf63143b7bade0dc4afa46c4b634d5d6b2a96bea233/sqlalchemy-2.0.47-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c72a0b9eb2672d70d112cb149fbaf172d466bc691014c496aaac594f1988e706", size = 3478410, upload-time = "2026-02-24T17:28:05.892Z" }, + { url = "https://files.pythonhosted.org/packages/0e/db/cafdeca5ecdaa3bb0811ba5449501da677ce0d83be8d05c5822da72d2e86/sqlalchemy-2.0.47-cp314-cp314t-win32.whl", hash = "sha256:c200db1128d72a71dc3c31c24b42eb9fd85b2b3e5a3c9ba1e751c11ac31250ff", size = 2147164, upload-time = "2026-02-24T17:14:40.783Z" }, + { url = "https://files.pythonhosted.org/packages/fc/5e/ff41a010e9e0f76418b02ad352060a4341bb15f0af66cedc924ab376c7c6/sqlalchemy-2.0.47-cp314-cp314t-win_amd64.whl", hash = "sha256:669837759b84e575407355dcff912835892058aea9b80bd1cb76d6a151cf37f7", size = 2182154, upload-time = "2026-02-24T17:14:43.205Z" }, + { url = "https://files.pythonhosted.org/packages/15/9f/7c378406b592fcf1fc157248607b495a40e3202ba4a6f1372a2ba6447717/sqlalchemy-2.0.47-py3-none-any.whl", hash = "sha256:e2647043599297a1ef10e720cf310846b7f31b6c841fee093d2b09d81215eb93", size = 1940159, upload-time = "2026-02-24T17:15:07.158Z" }, ] [package.optional-dependencies] diff --git a/docs/development/agent-integration/files.mdx b/docs/development/agent-integration/files.mdx index 7c46397820..5bca8f736c 100644 --- a/docs/development/agent-integration/files.mdx +++ b/docs/development/agent-integration/files.mdx @@ -66,7 +66,7 @@ async def file_processing_example( content_type=mime_type, content=content, ) - yield new_file.to_file_part() + yield new_file.to_part() yield "File processing complete" @@ -94,7 +94,7 @@ Iterate through message parts to find `FilePart` objects and load their content -Use the `File.create()` method to generate new files and yield them as `FilePart` objects with `to_file_part()`. +Use the `File.create()` method to generate new files and yield them as `Part` objects with `to_part()`. @@ -114,7 +114,7 @@ Here's what you need to know to add file processing capabilities to your agent: **Create new files**: Use `File.create()` to generate new files with custom names, content types, and content. -**Yield file outputs**: The `File` object created by the SDK can be easily converted to a `FilePart` using the `to_file_part()` method and then yielded as agent outputs. +**Yield file outputs**: The `File` object created by the SDK can be easily converted to a `Part` using the `to_part()` method and then yielded as agent outputs. ## File Upload Configuration diff --git a/examples/agent-integration/files/file-processing/src/file_processing/agent.py b/examples/agent-integration/files/file-processing/src/file_processing/agent.py index 67c48216c3..b5e851f147 100644 --- a/examples/agent-integration/files/file-processing/src/file_processing/agent.py +++ b/examples/agent-integration/files/file-processing/src/file_processing/agent.py @@ -53,7 +53,7 @@ async def file_processing_example( content_type=mime_type, content=content, ) - yield new_file.to_file_part() + yield new_file.to_part() yield "File processing complete" From c7341b4f1c95873e1a43f2fa432292711b763785 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radek=20Je=C5=BEek?= Date: Tue, 3 Mar 2026 13:42:59 +0100 Subject: [PATCH 4/6] minor fixes --- agents/chat/uv.lock | 395 +++++------ apps/agentstack-sdk-py/uv.lock | 739 +++++++++------------ apps/agentstack-server/.vscode/launch.json | 2 + apps/agentstack-server/uv.lock | 104 +-- 4 files changed, 517 insertions(+), 723 deletions(-) diff --git a/agents/chat/uv.lock b/agents/chat/uv.lock index 9646b58a64..e6887ea4d2 100644 --- a/agents/chat/uv.lock +++ b/agents/chat/uv.lock @@ -4,8 +4,8 @@ requires-python = "==3.14.*" [[package]] name = "a2a-sdk" -version = "0.3.24.post37.dev0+dce3650" -source = { git = "https://github.com/a2aproject/a2a-python.git?rev=1.0-dev#dce36502b51f671ae0e0a926cc0ad8c208393329" } +version = "0.3.24.post41.dev0+041f0f5" +source = { git = "https://github.com/a2aproject/a2a-python.git?rev=1.0-dev#041f0f53bcf5fc2e74545d653bfeeba8d2d85c79" } dependencies = [ { name = "google-api-core" }, { name = "googleapis-common-protos" }, @@ -249,14 +249,14 @@ wheels = [ [[package]] name = "authlib" -version = "1.6.8" +version = "1.6.9" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cryptography" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/6b/6c/c88eac87468c607f88bc24df1f3b31445ee6fc9ba123b09e666adf687cd9/authlib-1.6.8.tar.gz", hash = "sha256:41ae180a17cf672bc784e4a518e5c82687f1fe1e98b0cafaeda80c8e4ab2d1cb", size = 165074, upload-time = "2026-02-14T04:02:17.941Z" } +sdist = { url = "https://files.pythonhosted.org/packages/af/98/00d3dd826d46959ad8e32af2dbb2398868fd9fd0683c26e56d0789bd0e68/authlib-1.6.9.tar.gz", hash = "sha256:d8f2421e7e5980cc1ddb4e32d3f5fa659cfaf60d8eaf3281ebed192e4ab74f04", size = 165134, upload-time = "2026-03-02T07:44:01.998Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9b/73/f7084bf12755113cd535ae586782ff3a6e710bfbe6a0d13d1c2f81ffbbfa/authlib-1.6.8-py2.py3-none-any.whl", hash = "sha256:97286fd7a15e6cfefc32771c8ef9c54f0ed58028f1322de6a2a7c969c3817888", size = 244116, upload-time = "2026-02-14T04:02:15.579Z" }, + { url = "https://files.pythonhosted.org/packages/53/23/b65f568ed0c22f1efacb744d2db1a33c8068f384b8c9b482b52ebdbc3ef6/authlib-1.6.9-py2.py3-none-any.whl", hash = "sha256:f08b4c14e08f0861dc18a32357b33fbcfd2ea86cfe3fe149484b4d764c4a0ac3", size = 244197, upload-time = "2026-03-02T07:44:00.307Z" }, ] [[package]] @@ -296,40 +296,6 @@ wikipedia = [ { name = "wikipedia-api" }, ] -[[package]] -name = "brotli" -version = "1.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f7/16/c92ca344d646e71a43b8bb353f0a6490d7f6e06210f8554c8f874e454285/brotli-1.2.0.tar.gz", hash = "sha256:e310f77e41941c13340a95976fe66a8a95b01e783d430eeaf7a2f87e0a57dd0a", size = 7388632, upload-time = "2025-11-05T18:39:42.86Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/17/e1/298c2ddf786bb7347a1cd71d63a347a79e5712a7c0cba9e3c3458ebd976f/brotli-1.2.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:6c12dad5cd04530323e723787ff762bac749a7b256a5bece32b2243dd5c27b21", size = 863080, upload-time = "2025-11-05T18:38:45.503Z" }, - { url = "https://files.pythonhosted.org/packages/84/0c/aac98e286ba66868b2b3b50338ffbd85a35c7122e9531a73a37a29763d38/brotli-1.2.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:3219bd9e69868e57183316ee19c84e03e8f8b5a1d1f2667e1aa8c2f91cb061ac", size = 445453, upload-time = "2025-11-05T18:38:46.433Z" }, - { url = "https://files.pythonhosted.org/packages/ec/f1/0ca1f3f99ae300372635ab3fe2f7a79fa335fee3d874fa7f9e68575e0e62/brotli-1.2.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:963a08f3bebd8b75ac57661045402da15991468a621f014be54e50f53a58d19e", size = 1528168, upload-time = "2025-11-05T18:38:47.371Z" }, - { url = "https://files.pythonhosted.org/packages/d6/a6/2ebfc8f766d46df8d3e65b880a2e220732395e6d7dc312c1e1244b0f074a/brotli-1.2.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9322b9f8656782414b37e6af884146869d46ab85158201d82bab9abbcb971dc7", size = 1627098, upload-time = "2025-11-05T18:38:48.385Z" }, - { url = "https://files.pythonhosted.org/packages/f3/2f/0976d5b097ff8a22163b10617f76b2557f15f0f39d6a0fe1f02b1a53e92b/brotli-1.2.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cf9cba6f5b78a2071ec6fb1e7bd39acf35071d90a81231d67e92d637776a6a63", size = 1419861, upload-time = "2025-11-05T18:38:49.372Z" }, - { url = "https://files.pythonhosted.org/packages/9c/97/d76df7176a2ce7616ff94c1fb72d307c9a30d2189fe877f3dd99af00ea5a/brotli-1.2.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7547369c4392b47d30a3467fe8c3330b4f2e0f7730e45e3103d7d636678a808b", size = 1484594, upload-time = "2025-11-05T18:38:50.655Z" }, - { url = "https://files.pythonhosted.org/packages/d3/93/14cf0b1216f43df5609f5b272050b0abd219e0b54ea80b47cef9867b45e7/brotli-1.2.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:fc1530af5c3c275b8524f2e24841cbe2599d74462455e9bae5109e9ff42e9361", size = 1593455, upload-time = "2025-11-05T18:38:51.624Z" }, - { url = "https://files.pythonhosted.org/packages/b3/73/3183c9e41ca755713bdf2cc1d0810df742c09484e2e1ddd693bee53877c1/brotli-1.2.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d2d085ded05278d1c7f65560aae97b3160aeb2ea2c0b3e26204856beccb60888", size = 1488164, upload-time = "2025-11-05T18:38:53.079Z" }, - { url = "https://files.pythonhosted.org/packages/64/6a/0c78d8f3a582859236482fd9fa86a65a60328a00983006bcf6d83b7b2253/brotli-1.2.0-cp314-cp314-win32.whl", hash = "sha256:832c115a020e463c2f67664560449a7bea26b0c1fdd690352addad6d0a08714d", size = 339280, upload-time = "2025-11-05T18:38:54.02Z" }, - { url = "https://files.pythonhosted.org/packages/f5/10/56978295c14794b2c12007b07f3e41ba26acda9257457d7085b0bb3bb90c/brotli-1.2.0-cp314-cp314-win_amd64.whl", hash = "sha256:e7c0af964e0b4e3412a0ebf341ea26ec767fa0b4cf81abb5e897c9338b5ad6a3", size = 375639, upload-time = "2025-11-05T18:38:55.67Z" }, -] - -[[package]] -name = "brotlicffi" -version = "1.2.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cffi" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/84/85/57c314a6b35336efbbdc13e5fc9ae13f6b60a0647cfa7c1221178ac6d8ae/brotlicffi-1.2.0.0.tar.gz", hash = "sha256:34345d8d1f9d534fcac2249e57a4c3c8801a33c9942ff9f8574f67a175e17adb", size = 476682, upload-time = "2025-11-21T18:17:57.334Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e4/df/a72b284d8c7bef0ed5756b41c2eb7d0219a1dd6ac6762f1c7bdbc31ef3af/brotlicffi-1.2.0.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:9458d08a7ccde8e3c0afedbf2c70a8263227a68dea5ab13590593f4c0a4fd5f4", size = 432340, upload-time = "2025-11-21T18:17:42.277Z" }, - { url = "https://files.pythonhosted.org/packages/74/2b/cc55a2d1d6fb4f5d458fba44a3d3f91fb4320aa14145799fd3a996af0686/brotlicffi-1.2.0.0-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:84e3d0020cf1bd8b8131f4a07819edee9f283721566fe044a20ec792ca8fd8b7", size = 1534002, upload-time = "2025-11-21T18:17:43.746Z" }, - { url = "https://files.pythonhosted.org/packages/e4/9c/d51486bf366fc7d6735f0e46b5b96ca58dc005b250263525a1eea3cd5d21/brotlicffi-1.2.0.0-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:33cfb408d0cff64cd50bef268c0fed397c46fbb53944aa37264148614a62e990", size = 1536547, upload-time = "2025-11-21T18:17:45.729Z" }, - { url = "https://files.pythonhosted.org/packages/1b/37/293a9a0a7caf17e6e657668bebb92dfe730305999fe8c0e2703b8888789c/brotlicffi-1.2.0.0-cp38-abi3-win32.whl", hash = "sha256:23e5c912fdc6fd37143203820230374d24babd078fc054e18070a647118158f6", size = 343085, upload-time = "2025-11-21T18:17:48.887Z" }, - { url = "https://files.pythonhosted.org/packages/07/6b/6e92009df3b8b7272f85a0992b306b61c34b7ea1c4776643746e61c380ac/brotlicffi-1.2.0.0-cp38-abi3-win_amd64.whl", hash = "sha256:f139a7cdfe4ae7859513067b736eb44d19fae1186f9e99370092f6915216451b", size = 378586, upload-time = "2025-11-21T18:17:50.531Z" }, -] - [[package]] name = "cachetools" version = "7.0.1" @@ -530,18 +496,16 @@ wheels = [ [[package]] name = "ddgs" -version = "9.10.0" +version = "9.11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, - { name = "fake-useragent" }, - { name = "httpx", extra = ["brotli", "http2", "socks"] }, { name = "lxml" }, { name = "primp" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/07/76/8dc0323d1577037abad7a679f8af150ebb73a94995d3012de71a8898e6e6/ddgs-9.10.0.tar.gz", hash = "sha256:d9381ff75bdf1ad6691d3d1dc2be12be190d1d32ecd24f1002c492143c52c34f", size = 31491, upload-time = "2025-12-17T23:30:15.021Z" } +sdist = { url = "https://files.pythonhosted.org/packages/fa/06/b148a33eb074ef0cde6f82a83dc2af2ec60d2a63f3e39b049dd8abdfaf39/ddgs-9.11.1.tar.gz", hash = "sha256:f01aec85e59ffe73dbab4517628d24702fb6ce2c345d2f5e6dd4b120526b56c7", size = 34442, upload-time = "2026-03-02T06:45:23.341Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b5/0e/d4b7d6a8df5074cf67bc14adead39955b0bf847c947ff6cad0bb527887f4/ddgs-9.10.0-py3-none-any.whl", hash = "sha256:81233d79309836eb03e7df2a0d2697adc83c47c342713132c0ba618f1f2c6eee", size = 40311, upload-time = "2025-12-17T23:30:13.606Z" }, + { url = "https://files.pythonhosted.org/packages/92/6b/446ce962d40f243c90f704aceadaa1f577e35db11677323e35b7c4b55867/ddgs-9.11.1-py3-none-any.whl", hash = "sha256:404382a17c6055f28aa752809bd100ca23167611bb77368aa4c7012e254a16b8", size = 43304, upload-time = "2026-03-02T06:45:22.283Z" }, ] [[package]] @@ -565,18 +529,9 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277, upload-time = "2023-12-24T09:54:30.421Z" }, ] -[[package]] -name = "fake-useragent" -version = "2.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/41/43/948d10bf42735709edb5ae51e23297d034086f17fc7279fef385a7acb473/fake_useragent-2.2.0.tar.gz", hash = "sha256:4e6ab6571e40cc086d788523cf9e018f618d07f9050f822ff409a4dfe17c16b2", size = 158898, upload-time = "2025-04-14T15:32:19.238Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/51/37/b3ea9cd5558ff4cb51957caca2193981c6b0ff30bd0d2630ac62505d99d0/fake_useragent-2.2.0-py3-none-any.whl", hash = "sha256:67f35ca4d847b0d298187443aaf020413746e56acd985a611908c73dba2daa24", size = 161695, upload-time = "2025-04-14T15:32:17.732Z" }, -] - [[package]] name = "fastapi" -version = "0.133.1" +version = "0.135.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "annotated-doc" }, @@ -585,9 +540,9 @@ dependencies = [ { name = "typing-extensions" }, { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/22/6f/0eafed8349eea1fa462238b54a624c8b408cd1ba2795c8e64aa6c34f8ab7/fastapi-0.133.1.tar.gz", hash = "sha256:ed152a45912f102592976fde6cbce7dae1a8a1053da94202e51dd35d184fadd6", size = 378741, upload-time = "2026-02-25T18:18:17.398Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/7b/f8e0211e9380f7195ba3f3d40c292594fd81ba8ec4629e3854c353aaca45/fastapi-0.135.1.tar.gz", hash = "sha256:d04115b508d936d254cea545b7312ecaa58a7b3a0f84952535b4c9afae7668cd", size = 394962, upload-time = "2026-03-01T18:18:29.369Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/c9/a175a7779f3599dfa4adfc97a6ce0e157237b3d7941538604aadaf97bfb6/fastapi-0.133.1-py3-none-any.whl", hash = "sha256:658f34ba334605b1617a65adf2ea6461901bdb9af3a3080d63ff791ecf7dc2e2", size = 109029, upload-time = "2026-02-25T18:18:18.578Z" }, + { url = "https://files.pythonhosted.org/packages/e4/72/42e900510195b23a56bde950d26a51f8b723846bfcaa0286e90287f0422b/fastapi-0.135.1-py3-none-any.whl", hash = "sha256:46e2fc5745924b7c840f71ddd277382af29ce1cdb7d5eab5bf697e3fb9999c9e", size = 116999, upload-time = "2026-03-01T18:18:30.831Z" }, ] [[package]] @@ -611,11 +566,11 @@ wheels = [ [[package]] name = "filelock" -version = "3.24.3" +version = "3.25.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/73/92/a8e2479937ff39185d20dd6a851c1a63e55849e447a55e798cc2e1f49c65/filelock-3.24.3.tar.gz", hash = "sha256:011a5644dc937c22699943ebbfc46e969cdde3e171470a6e40b9533e5a72affa", size = 37935, upload-time = "2026-02-19T00:48:20.543Z" } +sdist = { url = "https://files.pythonhosted.org/packages/77/18/a1fd2231c679dcb9726204645721b12498aeac28e1ad0601038f94b42556/filelock-3.25.0.tar.gz", hash = "sha256:8f00faf3abf9dc730a1ffe9c354ae5c04e079ab7d3a683b7c32da5dd05f26af3", size = 40158, upload-time = "2026-03-01T15:08:45.916Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9c/0f/5d0c71a1aefeb08efff26272149e07ab922b64f46c63363756224bd6872e/filelock-3.24.3-py3-none-any.whl", hash = "sha256:426e9a4660391f7f8a810d71b0555bce9008b0a1cc342ab1f6947d37639e002d", size = 24331, upload-time = "2026-02-19T00:48:18.465Z" }, + { url = "https://files.pythonhosted.org/packages/f9/0b/de6f54d4a8bedfe8645c41497f3c18d749f0bd3218170c667bf4b81d0cdd/filelock-3.25.0-py3-none-any.whl", hash = "sha256:5ccf8069f7948f494968fc0713c10e5c182a9c9d9eef3a636307a20c2490f047", size = 26427, upload-time = "2026-03-01T15:08:44.593Z" }, ] [[package]] @@ -789,50 +744,28 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, ] -[[package]] -name = "h2" -version = "4.3.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "hpack" }, - { name = "hyperframe" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/1d/17/afa56379f94ad0fe8defd37d6eb3f89a25404ffc71d4d848893d270325fc/h2-4.3.0.tar.gz", hash = "sha256:6c59efe4323fa18b47a632221a1888bd7fde6249819beda254aeca909f221bf1", size = 2152026, upload-time = "2025-08-23T18:12:19.778Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/69/b2/119f6e6dcbd96f9069ce9a2665e0146588dc9f88f29549711853645e736a/h2-4.3.0-py3-none-any.whl", hash = "sha256:c438f029a25f7945c69e0ccf0fb951dc3f73a5f6412981daee861431b70e2bdd", size = 61779, upload-time = "2025-08-23T18:12:17.779Z" }, -] - [[package]] name = "hf-xet" -version = "1.3.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a6/d0/73454ef7ca885598a3194d07d5c517d91a840753c5b35d272600d7907f64/hf_xet-1.3.1.tar.gz", hash = "sha256:513aa75f8dc39a63cc44dbc8d635ccf6b449e07cdbd8b2e2d006320d2e4be9bb", size = 641393, upload-time = "2026-02-25T00:57:56.701Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/f5/66adbb1f54a1b3c6da002fa36d4405901ddbcb7d927d780db17ce18ab99d/hf_xet-1.3.1-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:6517a245e41df3eae5adc5f9e8c86fa52abd548de798cbcd989f0082152860aa", size = 3759781, upload-time = "2026-02-25T00:57:47.017Z" }, - { url = "https://files.pythonhosted.org/packages/1e/75/189d91a90480c142cc710c1baa35ece20e8652d5fe5c9b2364a13573d827/hf_xet-1.3.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:4a322d506c513f98fdc1aa2aaa825daefd535b686e80ca789e6d33fcb146f524", size = 3517533, upload-time = "2026-02-25T00:57:45.812Z" }, - { url = "https://files.pythonhosted.org/packages/c6/52/52dd1ab6c29661e29585f3c10d14572e2535a3a472f27a0a46215b0f4659/hf_xet-1.3.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8f16ec9d26badec46334a798e01b5d86af536924789c95b1a1ec6a05f26523e0", size = 4174082, upload-time = "2026-02-25T00:57:38.171Z" }, - { url = "https://files.pythonhosted.org/packages/14/03/460add181c79e2ea1527d2ad27788ecccaee1d5a82563f9402e25ee627e4/hf_xet-1.3.1-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:e1f5d72bd5b73e61530fff573bcff34bdb64af2bf4862cdd516e6c1dab4dc75b", size = 3952874, upload-time = "2026-02-25T00:57:36.942Z" }, - { url = "https://files.pythonhosted.org/packages/01/56/bf78f18890dfc8caa907830e95424dce0887d5c45efde13f23c9ebbaa8ef/hf_xet-1.3.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:4bc71afd853508b2ddf123b8fc9de71b0afa4c956ec730b69fb76103781e94cd", size = 4152325, upload-time = "2026-02-25T00:57:54.081Z" }, - { url = "https://files.pythonhosted.org/packages/3c/94/91685c6a4a7f513097a6a73b1e879024304cd0eae78080e3d737622f2fd9/hf_xet-1.3.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:541b4b00ed294ae6cfd9416de9506e58971013714d7316189c9638ed54e362d4", size = 4390499, upload-time = "2026-02-25T00:57:55.258Z" }, - { url = "https://files.pythonhosted.org/packages/79/1b/1e72c8ea1f31ef94640d1f265630d35b97b2ef31fe12696bbcc32dbcdc95/hf_xet-1.3.1-cp314-cp314t-win_amd64.whl", hash = "sha256:f85480b4fe3e8e4cdbc59ef1d235152b732fd57ca439cc983c291892945ae818", size = 3634352, upload-time = "2026-02-25T00:58:04.749Z" }, - { url = "https://files.pythonhosted.org/packages/cf/61/b59e87a7a10b95c4578a6ce555339b2f002035569dfd366662b9f59975a8/hf_xet-1.3.1-cp314-cp314t-win_arm64.whl", hash = "sha256:83a8830160392ef4bea78d443ea2cf1febe65783b3843a8f12c64b368981e7e2", size = 3494371, upload-time = "2026-02-25T00:58:03.422Z" }, - { url = "https://files.pythonhosted.org/packages/75/f8/c2da4352c0335df6ae41750cf5bab09fdbfc30d3b4deeed9d621811aa835/hf_xet-1.3.1-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:581d1809a016f7881069d86a072168a8199a46c839cf394ff53970a47e4f1ca1", size = 3761755, upload-time = "2026-02-25T00:57:43.621Z" }, - { url = "https://files.pythonhosted.org/packages/c0/e5/a2f3eaae09da57deceb16a96ebe9ae1f6f7b9b94145a9cd3c3f994e7782a/hf_xet-1.3.1-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:329c80c86f2dda776bafd2e4813a46a3ee648dce3ac0c84625902c70d7a6ddba", size = 3523677, upload-time = "2026-02-25T00:57:42.3Z" }, - { url = "https://files.pythonhosted.org/packages/61/cd/acbbf9e51f17d8cef2630e61741228e12d4050716619353efc1ac119f902/hf_xet-1.3.1-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2973c3ff594c3a8da890836308cae1444c8af113c6f10fe6824575ddbc37eca7", size = 4178557, upload-time = "2026-02-25T00:57:35.399Z" }, - { url = "https://files.pythonhosted.org/packages/df/4f/014c14c4ae3461d9919008d0bed2f6f35ba1741e28b31e095746e8dac66f/hf_xet-1.3.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ed4bfd2e6d10cb86c9b0f3483df1d7dd2d0220f75f27166925253bacbc1c2dbe", size = 3958975, upload-time = "2026-02-25T00:57:34.004Z" }, - { url = "https://files.pythonhosted.org/packages/86/50/043f5c5a26f3831c3fa2509c17fcd468fd02f1f24d363adc7745fbe661cb/hf_xet-1.3.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:713913387cc76e300116030705d843a9f15aee86158337eeffb9eb8d26f47fcd", size = 4158298, upload-time = "2026-02-25T00:57:51.14Z" }, - { url = "https://files.pythonhosted.org/packages/08/9c/b667098a636a88358dbeb2caf90e3cb9e4b961f61f6c55bb312793424def/hf_xet-1.3.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:e5063789c9d21f51e9ed4edbee8539655d3486e9cad37e96b7af967da20e8b16", size = 4395743, upload-time = "2026-02-25T00:57:52.783Z" }, - { url = "https://files.pythonhosted.org/packages/70/37/4db0e4e1534270800cfffd5a7e0b338f2137f8ceb5768000147650d34ea9/hf_xet-1.3.1-cp37-abi3-win_amd64.whl", hash = "sha256:607d5bbc2730274516714e2e442a26e40e3330673ac0d0173004461409147dee", size = 3638145, upload-time = "2026-02-25T00:58:02.167Z" }, - { url = "https://files.pythonhosted.org/packages/4e/46/1ba8d36f8290a4b98f78898bdce2b0e8fe6d9a59df34a1399eb61a8d877f/hf_xet-1.3.1-cp37-abi3-win_arm64.whl", hash = "sha256:851b1be6597a87036fe7258ce7578d5df3c08176283b989c3b165f94125c5097", size = 3500490, upload-time = "2026-02-25T00:58:00.667Z" }, -] - -[[package]] -name = "hpack" -version = "4.1.0" +version = "1.3.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2c/48/71de9ed269fdae9c8057e5a4c0aa7402e8bb16f2c6e90b3aa53327b113f8/hpack-4.1.0.tar.gz", hash = "sha256:ec5eca154f7056aa06f196a557655c5b009b382873ac8d1e66e79e87535f1dca", size = 51276, upload-time = "2025-01-22T21:44:58.347Z" } +sdist = { url = "https://files.pythonhosted.org/packages/8b/cb/9bb543bd987ffa1ee48202cc96a756951b734b79a542335c566148ade36c/hf_xet-1.3.2.tar.gz", hash = "sha256:e130ee08984783d12717444e538587fa2119385e5bd8fc2bb9f930419b73a7af", size = 643646, upload-time = "2026-02-27T17:26:08.051Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/07/c6/80c95b1b2b94682a72cbdbfb85b81ae2daffa4291fbfa1b1464502ede10d/hpack-4.1.0-py3-none-any.whl", hash = "sha256:157ac792668d995c657d93111f46b4535ed114f0c9c8d672271bbec7eae1b496", size = 34357, upload-time = "2025-01-22T21:44:56.92Z" }, + { url = "https://files.pythonhosted.org/packages/ba/75/9d54c1ae1d05fb704f977eca1671747babf1957f19f38ae75c5933bc2dc1/hf_xet-1.3.2-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:c34e2c7aefad15792d57067c1c89b2b02c1bbaeabd7f8456ae3d07b4bbaf4094", size = 3761076, upload-time = "2026-02-27T17:25:55.42Z" }, + { url = "https://files.pythonhosted.org/packages/f2/8a/08a24b6c6f52b5d26848c16e4b6d790bb810d1bf62c3505bed179f7032d3/hf_xet-1.3.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:4bc995d6c41992831f762096020dc14a65fdf3963f86ffed580b596d04de32e3", size = 3521745, upload-time = "2026-02-27T17:25:54.217Z" }, + { url = "https://files.pythonhosted.org/packages/b5/db/a75cf400dd8a1a8acf226a12955ff6ee999f272dfc0505bafd8079a61267/hf_xet-1.3.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:959083c89dee30f7d6f890b36cdadda823386c4de63b1a30384a75bfd2ae995d", size = 4176301, upload-time = "2026-02-27T17:25:46.044Z" }, + { url = "https://files.pythonhosted.org/packages/01/40/6c4c798ffdd83e740dd3925c4e47793b07442a9efa3bc3866ba141a82365/hf_xet-1.3.2-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:cfa760888633b08c01b398d212ce7e8c0d7adac6c86e4b20dfb2397d8acd78ee", size = 3955437, upload-time = "2026-02-27T17:25:44.703Z" }, + { url = "https://files.pythonhosted.org/packages/0c/09/9a3aa7c5f07d3e5cc57bb750d12a124ffa72c273a87164bd848f9ac5cc14/hf_xet-1.3.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:3155a02e083aa21fd733a7485c7c36025e49d5975c8d6bda0453d224dd0b0ac4", size = 4154535, upload-time = "2026-02-27T17:26:05.207Z" }, + { url = "https://files.pythonhosted.org/packages/ae/e0/831f7fa6d90cb47a230bc23284b502c700e1483bbe459437b3844cdc0776/hf_xet-1.3.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:91b1dc03c31cbf733d35dc03df7c5353686233d86af045e716f1e0ea4a2673cf", size = 4393891, upload-time = "2026-02-27T17:26:06.607Z" }, + { url = "https://files.pythonhosted.org/packages/ab/96/6ed472fdce7f8b70f5da6e3f05be76816a610063003bfd6d9cea0bbb58a3/hf_xet-1.3.2-cp314-cp314t-win_amd64.whl", hash = "sha256:211f30098512d95e85ad03ae63bd7dd2c4df476558a5095d09f9e38e78cbf674", size = 3637583, upload-time = "2026-02-27T17:26:17.349Z" }, + { url = "https://files.pythonhosted.org/packages/8b/e8/a069edc4570b3f8e123c0b80fadc94530f3d7b01394e1fc1bb223339366c/hf_xet-1.3.2-cp314-cp314t-win_arm64.whl", hash = "sha256:4a6817c41de7c48ed9270da0b02849347e089c5ece9a0e72ae4f4b3a57617f82", size = 3497977, upload-time = "2026-02-27T17:26:14.966Z" }, + { url = "https://files.pythonhosted.org/packages/d8/28/dbb024e2e3907f6f3052847ca7d1a2f7a3972fafcd53ff79018977fcb3e4/hf_xet-1.3.2-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:f93b7595f1d8fefddfede775c18b5c9256757824f7f6832930b49858483cd56f", size = 3763961, upload-time = "2026-02-27T17:25:52.537Z" }, + { url = "https://files.pythonhosted.org/packages/e4/71/b99aed3823c9d1795e4865cf437d651097356a3f38c7d5877e4ac544b8e4/hf_xet-1.3.2-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:a85d3d43743174393afe27835bde0cd146e652b5fcfdbcd624602daef2ef3259", size = 3526171, upload-time = "2026-02-27T17:25:50.968Z" }, + { url = "https://files.pythonhosted.org/packages/9d/ca/907890ce6ef5598b5920514f255ed0a65f558f820515b18db75a51b2f878/hf_xet-1.3.2-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7c2a054a97c44e136b1f7f5a78f12b3efffdf2eed3abc6746fc5ea4b39511633", size = 4180750, upload-time = "2026-02-27T17:25:43.125Z" }, + { url = "https://files.pythonhosted.org/packages/8c/ad/bc7f41f87173d51d0bce497b171c4ee0cbde1eed2d7b4216db5d0ada9f50/hf_xet-1.3.2-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:06b724a361f670ae557836e57801b82c75b534812e351a87a2c739f77d1e0635", size = 3961035, upload-time = "2026-02-27T17:25:41.837Z" }, + { url = "https://files.pythonhosted.org/packages/73/38/600f4dda40c4a33133404d9fe644f1d35ff2d9babb4d0435c646c63dd107/hf_xet-1.3.2-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:305f5489d7241a47e0458ef49334be02411d1d0f480846363c1c8084ed9916f7", size = 4161378, upload-time = "2026-02-27T17:26:00.365Z" }, + { url = "https://files.pythonhosted.org/packages/00/b3/7bc1ff91d1ac18420b7ad1e169b618b27c00001b96310a89f8a9294fe509/hf_xet-1.3.2-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:06cdbde243c85f39a63b28e9034321399c507bcd5e7befdd17ed2ccc06dfe14e", size = 4398020, upload-time = "2026-02-27T17:26:03.977Z" }, + { url = "https://files.pythonhosted.org/packages/2b/0b/99bfd948a3ed3620ab709276df3ad3710dcea61976918cce8706502927af/hf_xet-1.3.2-cp37-abi3-win_amd64.whl", hash = "sha256:9298b47cce6037b7045ae41482e703c471ce36b52e73e49f71226d2e8e5685a1", size = 3641624, upload-time = "2026-02-27T17:26:13.542Z" }, + { url = "https://files.pythonhosted.org/packages/cc/02/9a6e4ca1f3f73a164c0cd48e41b3cc56585dcc37e809250de443d673266f/hf_xet-1.3.2-cp37-abi3-win_arm64.whl", hash = "sha256:83d8ec273136171431833a6957e8f3af496bee227a0fe47c7b8b39c106d1749a", size = 3503976, upload-time = "2026-02-27T17:26:12.123Z" }, ] [[package]] @@ -863,18 +796,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, ] -[package.optional-dependencies] -brotli = [ - { name = "brotli", marker = "platform_python_implementation == 'CPython'" }, - { name = "brotlicffi", marker = "platform_python_implementation != 'CPython'" }, -] -http2 = [ - { name = "h2" }, -] -socks = [ - { name = "socksio" }, -] - [[package]] name = "httpx-sse" version = "0.4.3" @@ -904,15 +825,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ec/74/2bc951622e2dbba1af9a460d93c51d15e458becd486e62c29cc0ccb08178/huggingface_hub-1.5.0-py3-none-any.whl", hash = "sha256:c9c0b3ab95a777fc91666111f3b3ede71c0cdced3614c553a64e98920585c4ee", size = 596261, upload-time = "2026-02-26T15:35:31.1Z" }, ] -[[package]] -name = "hyperframe" -version = "6.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/02/e7/94f8232d4a74cc99514c13a9f995811485a6903d48e5d952771ef6322e30/hyperframe-6.1.0.tar.gz", hash = "sha256:f630908a00854a7adeabd6382b43923a4c4cd4b821fcb527e6ab9e15382a3b08", size = 26566, upload-time = "2025-01-22T21:41:49.302Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/48/30/47d0bf6072f7252e6521f3447ccfa40b421b6824517f82854703d0f5a98b/hyperframe-6.1.0-py3-none-any.whl", hash = "sha256:b03380493a519fce58ea5af42e4a42317bf9bd425596f7a0835ffce80f1a42e5", size = 13007, upload-time = "2025-01-22T21:41:47.295Z" }, -] - [[package]] name = "idna" version = "3.11" @@ -1044,7 +956,7 @@ wheels = [ [[package]] name = "litellm" -version = "1.81.16" +version = "1.82.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohttp" }, @@ -1060,9 +972,9 @@ dependencies = [ { name = "tiktoken" }, { name = "tokenizers" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d6/36/3cbb22d6ef88c10f3fa4f04664c2a37e93a2e6f9c51899cd9fd025cb0a50/litellm-1.81.16.tar.gz", hash = "sha256:264a3868942e722cd6c19c2d625524fe624a1b6961c37c22d299dc7ea99823b3", size = 16668405, upload-time = "2026-02-26T13:01:48.429Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6c/00/49bb5c28e0dea0f5086229a2a08d5fdc6c8dc0d8e2acb2a2d1f7dd9f4b70/litellm-1.82.0.tar.gz", hash = "sha256:d388f52447daccbcaafa19a3e68d17b75f1374b5bf2cde680d65e1cd86e50d22", size = 16800355, upload-time = "2026-03-01T02:35:30.363Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1f/1e/0022cde913bac87a493e4a182b8768f75e7ae90b64d4e11acb009b18311f/litellm-1.81.16-py3-none-any.whl", hash = "sha256:d6bcc13acbd26719e07bfa6b9923740e88409cbf1f9d626d85fc9ae0e0eec88c", size = 14774277, upload-time = "2026-02-26T13:01:45.652Z" }, + { url = "https://files.pythonhosted.org/packages/28/89/eb28bfcf97d6b045c400e72eb047c381594467048c237dbb6c227764084c/litellm-1.82.0-py3-none-any.whl", hash = "sha256:5496b5d4532cccdc7a095c21cbac4042f7662021c57bc1d17be4e39838929e80", size = 14911978, upload-time = "2026-03-01T02:35:26.844Z" }, ] [[package]] @@ -1493,40 +1405,40 @@ wheels = [ [[package]] name = "primp" -version = "1.1.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/de/25/1113a87a693121f4eb18d2df3a99d8ad43984f4068e31a5765c03e4b8b96/primp-1.1.1.tar.gz", hash = "sha256:58775e74f86cc58f9abe4b1dacea399fa6367c1959e591ad9345f151ad38d259", size = 311388, upload-time = "2026-02-24T16:12:53.452Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/bf/0f/027fc0394f70721c6dc5054fb3efff6479753da0b272e15b16cefba958b8/primp-1.1.1-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:691215c5a514a7395c1ee775cd03a94a41497941e17291e1a71f5356142c61e6", size = 3997489, upload-time = "2026-02-24T16:12:49.154Z" }, - { url = "https://files.pythonhosted.org/packages/af/ea/0f23fbfef2a550c420eaa73fd3e21176acb0ddf0d50028d8bc8d937441be/primp-1.1.1-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:17ace56cd24a894236121bf37d3616ec15d5299a6fa2d2a30fbbf9c22b946a03", size = 3734591, upload-time = "2026-02-24T16:12:45.629Z" }, - { url = "https://files.pythonhosted.org/packages/0a/63/c5669652446a981dd5faad8a8255e5567db5818b951dbe74e81968f672cb/primp-1.1.1-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cfec08ae15f6d86b2bcaaee3358d5cc349a843c8be164502ea73658a817c5cf2", size = 3875508, upload-time = "2026-02-24T16:12:59.403Z" }, - { url = "https://files.pythonhosted.org/packages/14/79/19e4d19a445b39c930a317e4ea4d1eff07ef0661b4e7397ad425f7ff0bd8/primp-1.1.1-cp310-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c3cf7e93e8ff4842eee9c6d4ac47d638a5c981752b19f458877a3536c1da6671", size = 3510461, upload-time = "2026-02-24T16:12:37.908Z" }, - { url = "https://files.pythonhosted.org/packages/50/39/091282d624067958b42a087976c0da80eecc5ade03acfc732389be3af723/primp-1.1.1-cp310-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:db6f3f18855bf25dca14f6d121d214e5c922275f49cdadd248eff28abb779edb", size = 3727644, upload-time = "2026-02-24T16:12:16.671Z" }, - { url = "https://files.pythonhosted.org/packages/33/ae/ca4e4a5d0cbd35684a228fd1f7c1425db0860a7bd74ce8f40835f6184834/primp-1.1.1-cp310-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2d8363faadb1d07fa8ae73de6ed2ca4666b36c77ea3990714164b8ee7ab1aa1d", size = 4004689, upload-time = "2026-02-24T16:12:57.957Z" }, - { url = "https://files.pythonhosted.org/packages/3a/ed/b3cf17bcac4914aa63cd83d763c9e347aab6e0b9285645b0015b036f914d/primp-1.1.1-cp310-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:302241ee447c185417e93e3a3e5a2801fdd710b1a5cc63c01a26ee7dc634e9b1", size = 3918084, upload-time = "2026-02-24T16:12:30.283Z" }, - { url = "https://files.pythonhosted.org/packages/6a/9f/f563eaeb654749fa519c627b1f1ab93cf875537c56123fba507f74b647fc/primp-1.1.1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a37ad318f1b8295d414e1c32ca407efcb92e664c5ff41f06901bd3ee03bab1fa", size = 4108648, upload-time = "2026-02-24T16:12:15.269Z" }, - { url = "https://files.pythonhosted.org/packages/1c/b9/2df5376900c293238cf641591952979f689ea3f009195df4cce15786afb9/primp-1.1.1-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e46829d9d86caf18b2b40829655d470e0ce2eebb061f2ee973451b2509f1c5a2", size = 4055747, upload-time = "2026-02-24T16:12:42.925Z" }, - { url = "https://files.pythonhosted.org/packages/a1/e9/eaaea488b4ae445059bd99559649402c77ddd9dfdda01528daa9ee11d8fe/primp-1.1.1-cp310-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:8ef9cb971915d2db3fbb1a512777261e5267c95d4717b18aff453f5e3dbb9bda", size = 3742046, upload-time = "2026-02-24T16:12:19.945Z" }, - { url = "https://files.pythonhosted.org/packages/0a/92/0607dd9d01840e0c007519d69cdcbb6f1358d6d7f8e739fc3359773b50d2/primp-1.1.1-cp310-abi3-musllinux_1_2_i686.whl", hash = "sha256:1a350656142772b5d6afc0dfaf9172c69449fbfafb9b6590af7ba116d32554d7", size = 3857103, upload-time = "2026-02-24T16:12:39.338Z" }, - { url = "https://files.pythonhosted.org/packages/e5/b6/5d574a7a84afd38df03c5535a9bb1052090bd0289760dcca24188510dd09/primp-1.1.1-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:ec71a66750befd219f29cb6ff01bc1c26671040fc76b4115bf045c85f84da041", size = 4357972, upload-time = "2026-02-24T16:12:12.159Z" }, - { url = "https://files.pythonhosted.org/packages/8b/f3/34ba2deba36de0a6041a61c16f2097e0bd2e74114f8d85096b3911288b4c/primp-1.1.1-cp310-abi3-win32.whl", hash = "sha256:901dc1e40b99ba5925463ab120af14afb8a66f4ac7eb2cdf87aaf21047f6db39", size = 3259840, upload-time = "2026-02-24T16:12:31.762Z" }, - { url = "https://files.pythonhosted.org/packages/a8/c6/fa3c17e5b6e4cff5bbdfd6bed1d0e8f81e17708dd8106906a031a2432b61/primp-1.1.1-cp310-abi3-win_amd64.whl", hash = "sha256:6bedd91451ec9ac46203ccb5c2c9925e9206e33abec7c791a2b39e3f86530bf0", size = 3596643, upload-time = "2026-02-24T16:12:21.554Z" }, - { url = "https://files.pythonhosted.org/packages/94/3d/a5b391107ba1c72dc8eb4f603c5764067449e1445438d71e093a72d5eda1/primp-1.1.1-cp310-abi3-win_arm64.whl", hash = "sha256:fd22a10164536374262e32fccbf81736b20798ac7582f159d5ffdef01a755579", size = 3606836, upload-time = "2026-02-24T16:12:28.579Z" }, - { url = "https://files.pythonhosted.org/packages/5d/77/b7df4f1776ae2e7cb5cf123b977167709c120712c7a4f968dc93b28d05ac/primp-1.1.1-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:e6b0fdeb12cc60b0fa756191118cec8ede8d26f869b83fa501aed722984a964b", size = 3981048, upload-time = "2026-02-24T16:12:24.396Z" }, - { url = "https://files.pythonhosted.org/packages/9a/c8/f198cd6ad9f232a171739a69c534c684237362af8e55f0cc2fc452377aa8/primp-1.1.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:fc473e87adc88f6ce94b7f3edeb2ca6c973f4ceb2d4199d0e707544f71c639c4", size = 3729293, upload-time = "2026-02-24T16:12:18.07Z" }, - { url = "https://files.pythonhosted.org/packages/e7/ce/bd8e564f8233ab0213a296dda2e04b484e0c4b9975702c7ba712e96ead8c/primp-1.1.1-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e85f2aea74b8683611c76958de8827322bd800e1b51aec88130da68d00a20462", size = 3873474, upload-time = "2026-02-24T16:12:40.749Z" }, - { url = "https://files.pythonhosted.org/packages/e7/ab/d3ee13de657cb068e81008eedc2d61103094497d9edc054997b85d85163e/primp-1.1.1-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ca535dfbc5a8290975f4bd8ce38922b26cf4fefc737aa2116bcb1a5795c14309", size = 3509513, upload-time = "2026-02-24T16:12:44.251Z" }, - { url = "https://files.pythonhosted.org/packages/6f/5d/3ed38dd94ae503977329976dbe00831e66d22f0f298c026f8d7493be2b39/primp-1.1.1-cp314-cp314t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d94073e9ecbf97f6d1538d4678df1bb662fd418ad5fd09da4040fe46623e2ec5", size = 3728743, upload-time = "2026-02-24T16:12:33.277Z" }, - { url = "https://files.pythonhosted.org/packages/bc/15/19af65a35b2189d6f2267148ea5b7cbb266aa36891acd641388b7a0f6022/primp-1.1.1-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7e639441bd36e582feec7033e4b8661e0979a61bff65af5f476d33e02ebb3c4d", size = 3999650, upload-time = "2026-02-24T16:12:36.157Z" }, - { url = "https://files.pythonhosted.org/packages/22/cb/aa635a9903a1ee3b0ffe5dd9218a2e2d8880828a1eaba9d0035f967d118a/primp-1.1.1-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd770ca4f73a700da0911d1300a952e4d9a4a3321e205aa5a8644ae81cbd4d7d", size = 3896990, upload-time = "2026-02-24T16:12:13.66Z" }, - { url = "https://files.pythonhosted.org/packages/25/98/916916ec3bd5dab4125bf17b28d1959883a831dc4f9757f915e509c43ec2/primp-1.1.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7dccb605997c918b7abbdd163303d789d63eb03d7cd0440184f34b06a8522fc1", size = 4096157, upload-time = "2026-02-24T16:12:27.163Z" }, - { url = "https://files.pythonhosted.org/packages/ff/57/219c44bf21896a3f2132821ea00bbc9af36b194449ee5083791f690daf7d/primp-1.1.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:1ada94c7f9f047b1c5ba339f62effd44f4c4943d4d8bb96447e9c84ab3bd874d", size = 4052968, upload-time = "2026-02-24T16:12:34.574Z" }, - { url = "https://files.pythonhosted.org/packages/6a/ce/dfdd734c7372faef4a26ecb0267a724e19f78b76a9a92440b8ca824e8f5a/primp-1.1.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:21ac92542f378a21fba8093dbeb7e093851e00da2bdfd9bc6aa63f81cff035d0", size = 3744522, upload-time = "2026-02-24T16:12:25.726Z" }, - { url = "https://files.pythonhosted.org/packages/d6/9c/3eb9e484c17784eac6549c505a68d82b6e5959a0af6efbcf28a773450a81/primp-1.1.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:adaa5d7e8d2ca089cbf41a837a301da605c21ff0ea5fecac8a8b1eead4bc563f", size = 3855298, upload-time = "2026-02-24T16:12:54.518Z" }, - { url = "https://files.pythonhosted.org/packages/1d/ca/80924591ec24f9341982e4d74251f6bfeda44cbb90f6f792403d0737a390/primp-1.1.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b041ab0019e0fb21c24de542e80056775508e5d1d0f0333fb661185bdb359138", size = 4348887, upload-time = "2026-02-24T16:12:47.376Z" }, - { url = "https://files.pythonhosted.org/packages/95/4b/0edc62583af9a03fd1eb34ffd865245c921919f374b0e72b1bb73dc9adf6/primp-1.1.1-cp314-cp314t-win32.whl", hash = "sha256:b7270b9755a931e7667854ad5d9b2aeb88068f0add4fb741529e8c25d953f21b", size = 3252145, upload-time = "2026-02-24T16:12:52.335Z" }, - { url = "https://files.pythonhosted.org/packages/01/b7/9784b93d252e4c2a50f7a46908d91110b7ce9d04e1adb47227fc212576ff/primp-1.1.1-cp314-cp314t-win_amd64.whl", hash = "sha256:19a48f4e91256ec661e022976a75e6a0621522244ac928e8c632d829adb929ce", size = 3591097, upload-time = "2026-02-24T16:12:22.898Z" }, - { url = "https://files.pythonhosted.org/packages/db/d5/3b34601cb2da1cec7aec88f447af9de1e8e3bb3101f26351aa8570b5b7af/primp-1.1.1-cp314-cp314t-win_arm64.whl", hash = "sha256:c97b951afb203b9528f36524e96b1e37ce42f3a7eb0cd77cd053ad5bdfc93d81", size = 3603917, upload-time = "2026-02-24T16:12:55.859Z" }, +version = "1.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/03/35/80be154508529f753fb82cb81298bdeb33e90f39f9901d7cfa0f488a581f/primp-1.1.2.tar.gz", hash = "sha256:c4707ab374a77c0cbead3d9a65605919fa4997fa910ef06e37b65df42a1d4d04", size = 313908, upload-time = "2026-03-01T05:52:49.773Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/13/dc9588356d983f988877ae065c842cdd6cf95073615b56b460cbe857f3dc/primp-1.1.2-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:181bb9a6d5544e0483592f693f33f5874a60726ea0da1f41685aa2267f084a4d", size = 4002669, upload-time = "2026-03-01T05:52:31.977Z" }, + { url = "https://files.pythonhosted.org/packages/70/af/6a6c26141583a5081bad69b9753c85df81b466939663742ef5bec35ee868/primp-1.1.2-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:f362424ffa83e1de55a7573300a416fa71dc5516829526a9bf77dc0cfa42256b", size = 3743010, upload-time = "2026-03-01T05:52:38.452Z" }, + { url = "https://files.pythonhosted.org/packages/a9/99/03db937e031a02885d8c80d073d7424967d629721b5044dcb4e80b6cbdcf/primp-1.1.2-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:736820326eb1ed19c6b0e971f852316c049c36bdd251a03757056a74182796df", size = 3889905, upload-time = "2026-03-01T05:52:20.616Z" }, + { url = "https://files.pythonhosted.org/packages/15/3c/faecef36238f464e2dd52056420676eb2d541cd20ff478d3b967815079e3/primp-1.1.2-cp310-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed37d1bc89fa8cad8b60481c81ea7b3bd42dc757868009ad3bb0b1e74c17fd22", size = 3524521, upload-time = "2026-03-01T05:52:08.403Z" }, + { url = "https://files.pythonhosted.org/packages/7f/d5/8954e5b5b454139ff35063d5a143a1570f865b736cfd8a46cc7ce9575a5a/primp-1.1.2-cp310-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78e78355b1c495bc7e3d92121067760c7e7a1d419519542ed9dd88688ce43aab", size = 3738228, upload-time = "2026-03-01T05:52:05.127Z" }, + { url = "https://files.pythonhosted.org/packages/26/e7/dc93dbeddb7642e12f4575aaf2c9fda7234b241050a112a9baa288971b16/primp-1.1.2-cp310-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c4c560d018dad4e3a3f17b07f9f5d894941e3acbbb5b566f6b6baf42786012f", size = 4013704, upload-time = "2026-03-01T05:52:48.529Z" }, + { url = "https://files.pythonhosted.org/packages/dd/3d/2cc2e0cd310f585df05a7008fd6de4542d7c0bc61e62b6797f28a9ede28b/primp-1.1.2-cp310-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2494b52cf3056d3e41c0746a11cbeca7f2f882a92a09d87383646cd75e2f3d8c", size = 3920174, upload-time = "2026-03-01T05:52:06.635Z" }, + { url = "https://files.pythonhosted.org/packages/35/60/dc4572ba96911374b43b4f5d1f012706c3f27fd2c12dd3e158fcf74ac3dd/primp-1.1.2-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c424a46f48ccd8fd309215a15bc098b47198b8f779c43ed8d95b3f53a382ffa8", size = 4113822, upload-time = "2026-03-01T05:52:51.061Z" }, + { url = "https://files.pythonhosted.org/packages/ec/2e/90f5f8e138f8bc6652c5134aa59a746775623a820f92164c6690217e49d6/primp-1.1.2-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ba51cf19f17fd4bab4567d96b4cd7dcb6a4e0f0d4721819180b46af9794ae310", size = 4068028, upload-time = "2026-03-01T05:52:13.843Z" }, + { url = "https://files.pythonhosted.org/packages/d4/ea/753d8edcb85c3c36d5731fbd2b215528738d917ae9cf3dce651ae0f1c529/primp-1.1.2-cp310-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:77ebae43c6735328051beb08e7e2360b6cf79d50f6cef77629beba880c99222d", size = 3754469, upload-time = "2026-03-01T05:52:15.671Z" }, + { url = "https://files.pythonhosted.org/packages/ae/51/b417cd741bf8eacea86debad358a6dc5821e2849a22e2c91cff926bebbb2/primp-1.1.2-cp310-abi3-musllinux_1_2_i686.whl", hash = "sha256:5f3252d47e9d0f4a567990c79cd388be43353fc7c78efea2a6a5734e8a425598", size = 3859330, upload-time = "2026-03-01T05:52:46.979Z" }, + { url = "https://files.pythonhosted.org/packages/3e/20/19db933c878748e9a7b9ad4057e9caf7ad9c91fd27d2a2692ac629453a66/primp-1.1.2-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:9e094417825df9748e179a1104b2df4459c3dbd1eea994f05a136860b847f0e1", size = 4365491, upload-time = "2026-03-01T05:52:35.007Z" }, + { url = "https://files.pythonhosted.org/packages/fc/0f/48a57ee744cc6dc64fb7daff7bc04e9ec3cefd0594d008a775496dddaeb1/primp-1.1.2-cp310-abi3-win32.whl", hash = "sha256:bc67112b61a8dc1d40ddcc81ff5c47a1cb7b620954fee01a529e28bebb359e20", size = 3266998, upload-time = "2026-03-01T05:52:02.059Z" }, + { url = "https://files.pythonhosted.org/packages/9c/0a/119d497fb098c739142d4a47b062a8a9cc0b4b87aca65334150066d075a0/primp-1.1.2-cp310-abi3-win_amd64.whl", hash = "sha256:4509850301c669c04e124762e953946ed10fe9039f059ec40b818c085697d9a4", size = 3601691, upload-time = "2026-03-01T05:52:12.34Z" }, + { url = "https://files.pythonhosted.org/packages/95/1f/2b8f218aebb4f236d94ae148b4f5c0471b3d00316b0ef5d0b7c2222d8417/primp-1.1.2-cp310-abi3-win_arm64.whl", hash = "sha256:de5958dc7ce78ce107dd776056a58f9da7a7164a912e908cb9b66b84f87967f6", size = 3613756, upload-time = "2026-03-01T05:52:28.279Z" }, + { url = "https://files.pythonhosted.org/packages/40/38/f77c5af1fd53658e04ae52decfab71349af43bdfdb32ddd8a622f6251842/primp-1.1.2-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:c3bbece26e8312e3e0df2ec222b954f9ac9f279422ffbbf47a6cad31ef8736cd", size = 3992311, upload-time = "2026-03-01T05:52:43.497Z" }, + { url = "https://files.pythonhosted.org/packages/77/f6/2e4504cfdeec5d39063173205ca10a281a2681fd9999da37b442ac7e6662/primp-1.1.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:78acdf43b57d984170e986be5fcae0a1537a245fafda970e92056dae42cd9545", size = 3736438, upload-time = "2026-03-01T05:52:22.505Z" }, + { url = "https://files.pythonhosted.org/packages/d3/6c/fe10c51b79cd407d3a1e08a0bb8a35ae53d79ce4156543ea4df7262581ef/primp-1.1.2-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89a2641441732f81e1876db2e18490d3210a8302290e4844b7f04159e02033d4", size = 3878622, upload-time = "2026-03-01T05:52:33.458Z" }, + { url = "https://files.pythonhosted.org/packages/fb/86/5c68dc877af9baf4fba3e5d2615fe0aefbdd4e1337d3b678b66769b434c9/primp-1.1.2-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a1df66deacb539efbca5730d0fc3dea19cd83c33422fa05445bbddc17aef3f71", size = 3520112, upload-time = "2026-03-01T05:52:45.214Z" }, + { url = "https://files.pythonhosted.org/packages/fd/aa/f8798a1c0fabbc9254e29330df61b93bdb54130e9d5e5d8495eff99fc658/primp-1.1.2-cp314-cp314t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78ea1f56dd3ac52f2d5375a084c7f31ce6ad274811bdb5d17ecaca6b4ddb8b6d", size = 3740187, upload-time = "2026-03-01T05:52:26.052Z" }, + { url = "https://files.pythonhosted.org/packages/90/e4/ea08359b6fbcda7b3ffcc15b4c1e0bf4f89680db126ba96889e7f8e1fe04/primp-1.1.2-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3c980527bd46c034ab9e06dca75b6237cea8d5b3fe1f5691904a2c35d92d143c", size = 4011825, upload-time = "2026-03-01T05:52:17.403Z" }, + { url = "https://files.pythonhosted.org/packages/01/4a/8cf516250cc97eab2d4c822478ab0037b9848bca844787196481b5691f25/primp-1.1.2-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0c0b4006a9a25c5f89a968f3bf67221fc19183890b8a1304873132d703697816", size = 3907535, upload-time = "2026-03-01T05:52:24.455Z" }, + { url = "https://files.pythonhosted.org/packages/90/00/e6fe4abf75012d05009abf22e9e1eb89b4bca06ad9f79c10876cebdf7271/primp-1.1.2-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2851bedc1598ed72f6a2016e391012744259c523dc5d27f2f02e3ae5ef020d4", size = 4108136, upload-time = "2026-03-01T05:52:42.007Z" }, + { url = "https://files.pythonhosted.org/packages/9d/8a/64cd76fee8b994f349c1a9c6541b4144dee64056dcaa8109bd352518b777/primp-1.1.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:f7340e34023dda2660bd02cb92ac8ed441f13a1afdc00487581d8b8b473f890b", size = 4060289, upload-time = "2026-03-01T05:52:40.4Z" }, + { url = "https://files.pythonhosted.org/packages/dd/7c/fbea74676def2ce1d21a53e86cdbb3ef9c7a12b2febfdd3961a8466449a7/primp-1.1.2-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:618a027bb45ac44e9b6c35d5758547ce5e73607de4fb54b52bb9d0dc896f11fa", size = 3749499, upload-time = "2026-03-01T05:51:59.988Z" }, + { url = "https://files.pythonhosted.org/packages/12/7a/36fc46a385141063e2ae4fd24dda308e75da8c6409c425a56ffceb6e4f71/primp-1.1.2-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:37e30ce1435142dd010f2ee1dd909f1e6e3a8cd3e32c8e22f3bb6703bf618209", size = 3858861, upload-time = "2026-03-01T05:52:10.621Z" }, + { url = "https://files.pythonhosted.org/packages/65/bb/d0319dbd2e20fb4f54d8b3f536b89431a9d1442f00fa11a874dfbe9d2de7/primp-1.1.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9b5d335d28eae65543b20c75911d71c5f89882a4598efade47abe92389f6da7f", size = 4358677, upload-time = "2026-03-01T05:52:18.978Z" }, + { url = "https://files.pythonhosted.org/packages/57/89/ab887a516dc83dbae12ea5b338f60c46a56966a972fed65f8de5bf05a9c2/primp-1.1.2-cp314-cp314t-win32.whl", hash = "sha256:b938cc2d033ac56be90c617836a60fb468f33ab630d3eacab2b36651b7ce106e", size = 3258062, upload-time = "2026-03-01T05:52:36.741Z" }, + { url = "https://files.pythonhosted.org/packages/df/ca/e870d65162f6c68da6d25afa3e01202ac500c8ad1b682dfd03e8c45e4d4a/primp-1.1.2-cp314-cp314t-win_amd64.whl", hash = "sha256:6378d55bbe8b722e7b39b6c0df1e46a1b767d2e4e8a7c1e60d9f8ec238bf48c4", size = 3599631, upload-time = "2026-03-01T05:52:03.595Z" }, + { url = "https://files.pythonhosted.org/packages/4e/cb/61667c710293d8007416130c9ad69f60a956393b52e82557c84ae8286aa7/primp-1.1.2-cp314-cp314t-win_arm64.whl", hash = "sha256:2431104658b86e7cf9bedbadabe6d2c4705c1c10b54f17ad0094cc927577adea", size = 3610624, upload-time = "2026-03-01T05:52:30.19Z" }, ] [[package]] @@ -1734,11 +1646,11 @@ wheels = [ [[package]] name = "python-dotenv" -version = "1.2.1" +version = "1.2.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f0/26/19cadc79a718c5edbec86fd4919a6b6d3f681039a2f6d66d14be94e75fb9/python_dotenv-1.2.1.tar.gz", hash = "sha256:42667e897e16ab0d66954af0e60a9caa94f0fd4ecf3aaf6d2d260eec1aa36ad6", size = 44221, upload-time = "2025-10-26T15:12:10.434Z" } +sdist = { url = "https://files.pythonhosted.org/packages/82/ed/0301aeeac3e5353ef3d94b6ec08bbcabd04a72018415dcb29e588514bba8/python_dotenv-1.2.2.tar.gz", hash = "sha256:2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3", size = 50135, upload-time = "2026-03-01T16:00:26.196Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61", size = 21230, upload-time = "2025-10-26T15:12:09.109Z" }, + { url = "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl", hash = "sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a", size = 22101, upload-time = "2026-03-01T16:00:25.09Z" }, ] [[package]] @@ -1801,42 +1713,42 @@ wheels = [ [[package]] name = "regex" -version = "2026.2.19" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ff/c0/d8079d4f6342e4cec5c3e7d7415b5cd3e633d5f4124f7a4626908dbe84c7/regex-2026.2.19.tar.gz", hash = "sha256:6fb8cb09b10e38f3ae17cc6dc04a1df77762bd0351b6ba9041438e7cc85ec310", size = 414973, upload-time = "2026-02-19T19:03:47.899Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2d/e2/7ad4e76a6dddefc0d64dbe12a4d3ca3947a19ddc501f864a5df2a8222ddd/regex-2026.2.19-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:03d191a9bcf94d31af56d2575210cb0d0c6a054dbcad2ea9e00aa4c42903b919", size = 489306, upload-time = "2026-02-19T19:02:29.058Z" }, - { url = "https://files.pythonhosted.org/packages/14/95/ee1736135733afbcf1846c58671046f99c4d5170102a150ebb3dd8d701d9/regex-2026.2.19-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:516ee067c6c721d0d0bfb80a2004edbd060fffd07e456d4e1669e38fe82f922e", size = 291218, upload-time = "2026-02-19T19:02:31.083Z" }, - { url = "https://files.pythonhosted.org/packages/ef/08/180d1826c3d7065200a5168c6b993a44947395c7bb6e04b2c2a219c34225/regex-2026.2.19-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:997862c619994c4a356cb7c3592502cbd50c2ab98da5f61c5c871f10f22de7e5", size = 289097, upload-time = "2026-02-19T19:02:33.485Z" }, - { url = "https://files.pythonhosted.org/packages/28/93/0651924c390c5740f5f896723f8ddd946a6c63083a7d8647231c343912ff/regex-2026.2.19-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:02b9e1b8a7ebe2807cd7bbdf662510c8e43053a23262b9f46ad4fc2dfc9d204e", size = 799147, upload-time = "2026-02-19T19:02:35.669Z" }, - { url = "https://files.pythonhosted.org/packages/a7/00/2078bd8bcd37d58a756989adbfd9f1d0151b7ca4085a9c2a07e917fbac61/regex-2026.2.19-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6c8fb3b19652e425ff24169dad3ee07f99afa7996caa9dfbb3a9106cd726f49a", size = 865239, upload-time = "2026-02-19T19:02:38.012Z" }, - { url = "https://files.pythonhosted.org/packages/2a/13/75195161ec16936b35a365fa8c1dd2ab29fd910dd2587765062b174d8cfc/regex-2026.2.19-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:50f1ee9488dd7a9fda850ec7c68cad7a32fa49fd19733f5403a3f92b451dcf73", size = 911904, upload-time = "2026-02-19T19:02:40.737Z" }, - { url = "https://files.pythonhosted.org/packages/96/72/ac42f6012179343d1c4bd0ffee8c948d841cb32ea188d37e96d80527fcc9/regex-2026.2.19-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ab780092b1424d13200aa5a62996e95f65ee3db8509be366437439cdc0af1a9f", size = 803518, upload-time = "2026-02-19T19:02:42.923Z" }, - { url = "https://files.pythonhosted.org/packages/bc/d1/75a08e2269b007b9783f0f86aa64488e023141219cb5f14dc1e69cda56c6/regex-2026.2.19-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:17648e1a88e72d88641b12635e70e6c71c5136ba14edba29bf8fc6834005a265", size = 775866, upload-time = "2026-02-19T19:02:45.189Z" }, - { url = "https://files.pythonhosted.org/packages/92/41/70e7d05faf6994c2ca7a9fcaa536da8f8e4031d45b0ec04b57040ede201f/regex-2026.2.19-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2f914ae8c804c8a8a562fe216100bc156bfb51338c1f8d55fe32cf407774359a", size = 788224, upload-time = "2026-02-19T19:02:47.804Z" }, - { url = "https://files.pythonhosted.org/packages/c8/83/34a2dd601f9deb13c20545c674a55f4a05c90869ab73d985b74d639bac43/regex-2026.2.19-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:c7e121a918bbee3f12ac300ce0a0d2f2c979cf208fb071ed8df5a6323281915c", size = 859682, upload-time = "2026-02-19T19:02:50.583Z" }, - { url = "https://files.pythonhosted.org/packages/8e/30/136db9a09a7f222d6e48b806f3730e7af6499a8cad9c72ac0d49d52c746e/regex-2026.2.19-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2fedd459c791da24914ecc474feecd94cf7845efb262ac3134fe27cbd7eda799", size = 764223, upload-time = "2026-02-19T19:02:52.777Z" }, - { url = "https://files.pythonhosted.org/packages/9e/ea/bb947743c78a16df481fa0635c50aa1a439bb80b0e6dc24cd4e49c716679/regex-2026.2.19-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:ea8dfc99689240e61fb21b5fc2828f68b90abf7777d057b62d3166b7c1543c4c", size = 850101, upload-time = "2026-02-19T19:02:55.87Z" }, - { url = "https://files.pythonhosted.org/packages/25/27/e3bfe6e97a99f7393665926be02fef772da7f8aa59e50bc3134e4262a032/regex-2026.2.19-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9fff45852160960f29e184ec8a5be5ab4063cfd0b168d439d1fc4ac3744bf29e", size = 789904, upload-time = "2026-02-19T19:02:58.523Z" }, - { url = "https://files.pythonhosted.org/packages/84/7b/7e2be6f00cea59d08761b027ad237002e90cac74b1607200ebaa2ba3d586/regex-2026.2.19-cp314-cp314-win32.whl", hash = "sha256:5390b130cce14a7d1db226a3896273b7b35be10af35e69f1cca843b6e5d2bb2d", size = 271784, upload-time = "2026-02-19T19:03:00.418Z" }, - { url = "https://files.pythonhosted.org/packages/f7/f6/639911530335773e7ec60bcaa519557b719586024c1d7eaad1daf87b646b/regex-2026.2.19-cp314-cp314-win_amd64.whl", hash = "sha256:e581f75d5c0b15669139ca1c2d3e23a65bb90e3c06ba9d9ea194c377c726a904", size = 280506, upload-time = "2026-02-19T19:03:02.302Z" }, - { url = "https://files.pythonhosted.org/packages/cd/ec/2582b56b4e036d46bb9b5d74a18548439ffa16c11cf59076419174d80f48/regex-2026.2.19-cp314-cp314-win_arm64.whl", hash = "sha256:7187fdee1be0896c1499a991e9bf7c78e4b56b7863e7405d7bb687888ac10c4b", size = 273557, upload-time = "2026-02-19T19:03:04.836Z" }, - { url = "https://files.pythonhosted.org/packages/49/0b/f901cfeb4efd83e4f5c3e9f91a6de77e8e5ceb18555698aca3a27e215ed3/regex-2026.2.19-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:5ec1d7c080832fdd4e150c6f5621fe674c70c63b3ae5a4454cebd7796263b175", size = 492196, upload-time = "2026-02-19T19:03:08.188Z" }, - { url = "https://files.pythonhosted.org/packages/94/0a/349b959e3da874e15eda853755567b4cde7e5309dbb1e07bfe910cfde452/regex-2026.2.19-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:8457c1bc10ee9b29cdfd897ccda41dce6bde0e9abd514bcfef7bcd05e254d411", size = 292878, upload-time = "2026-02-19T19:03:10.272Z" }, - { url = "https://files.pythonhosted.org/packages/98/b0/9d81b3c2c5ddff428f8c506713737278979a2c476f6e3675a9c51da0c389/regex-2026.2.19-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:cce8027010d1ffa3eb89a0b19621cdc78ae548ea2b49fea1f7bfb3ea77064c2b", size = 291235, upload-time = "2026-02-19T19:03:12.5Z" }, - { url = "https://files.pythonhosted.org/packages/04/e7/be7818df8691dbe9508c381ea2cc4c1153e4fdb1c4b06388abeaa93bd712/regex-2026.2.19-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:11c138febb40546ff9e026dbbc41dc9fb8b29e61013fa5848ccfe045f5b23b83", size = 807893, upload-time = "2026-02-19T19:03:15.064Z" }, - { url = "https://files.pythonhosted.org/packages/0c/b6/b898a8b983190cfa0276031c17beb73cfd1db07c03c8c37f606d80b655e2/regex-2026.2.19-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:74ff212aa61532246bb3036b3dfea62233414b0154b8bc3676975da78383cac3", size = 873696, upload-time = "2026-02-19T19:03:17.848Z" }, - { url = "https://files.pythonhosted.org/packages/1a/98/126ba671d54f19080ec87cad228fb4f3cc387fff8c4a01cb4e93f4ff9d94/regex-2026.2.19-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d00c95a2b6bfeb3ea1cb68d1751b1dfce2b05adc2a72c488d77a780db06ab867", size = 915493, upload-time = "2026-02-19T19:03:20.343Z" }, - { url = "https://files.pythonhosted.org/packages/b2/10/550c84a1a1a7371867fe8be2bea7df55e797cbca4709974811410e195c5d/regex-2026.2.19-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:311fcccb76af31be4c588d5a17f8f1a059ae8f4b097192896ebffc95612f223a", size = 813094, upload-time = "2026-02-19T19:03:23.287Z" }, - { url = "https://files.pythonhosted.org/packages/29/fb/ba221d2fc76a27b6b7d7a60f73a7a6a7bac21c6ba95616a08be2bcb434b0/regex-2026.2.19-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:77cfd6b5e7c4e8bf7a39d243ea05882acf5e3c7002b0ef4756de6606893b0ecd", size = 781583, upload-time = "2026-02-19T19:03:26.872Z" }, - { url = "https://files.pythonhosted.org/packages/26/f1/af79231301297c9e962679efc04a31361b58dc62dec1fc0cb4b8dd95956a/regex-2026.2.19-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:6380f29ff212ec922b6efb56100c089251940e0526a0d05aa7c2d9b571ddf2fe", size = 795875, upload-time = "2026-02-19T19:03:29.223Z" }, - { url = "https://files.pythonhosted.org/packages/a0/90/1e1d76cb0a2d0a4f38a039993e1c5cd971ae50435d751c5bae4f10e1c302/regex-2026.2.19-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:655f553a1fa3ab8a7fd570eca793408b8d26a80bfd89ed24d116baaf13a38969", size = 868916, upload-time = "2026-02-19T19:03:31.415Z" }, - { url = "https://files.pythonhosted.org/packages/9a/67/a1c01da76dbcfed690855a284c665cc0a370e7d02d1bd635cf9ff7dd74b8/regex-2026.2.19-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:015088b8558502f1f0bccd58754835aa154a7a5b0bd9d4c9b7b96ff4ae9ba876", size = 770386, upload-time = "2026-02-19T19:03:33.972Z" }, - { url = "https://files.pythonhosted.org/packages/49/6f/94842bf294f432ff3836bfd91032e2ecabea6d284227f12d1f935318c9c4/regex-2026.2.19-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:9e6693b8567a59459b5dda19104c4a4dbbd4a1c78833eacc758796f2cfef1854", size = 855007, upload-time = "2026-02-19T19:03:36.238Z" }, - { url = "https://files.pythonhosted.org/packages/ff/93/393cd203ca0d1d368f05ce12d2c7e91a324bc93c240db2e6d5ada05835f4/regex-2026.2.19-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:4071209fd4376ab5ceec72ad3507e9d3517c59e38a889079b98916477a871868", size = 799863, upload-time = "2026-02-19T19:03:38.497Z" }, - { url = "https://files.pythonhosted.org/packages/43/d9/35afda99bd92bf1a5831e55a4936d37ea4bed6e34c176a3c2238317faf4f/regex-2026.2.19-cp314-cp314t-win32.whl", hash = "sha256:2905ff4a97fad42f2d0834d8b1ea3c2f856ec209837e458d71a061a7d05f9f01", size = 274742, upload-time = "2026-02-19T19:03:40.804Z" }, - { url = "https://files.pythonhosted.org/packages/ae/42/7edc3344dcc87b698e9755f7f685d463852d481302539dae07135202d3ca/regex-2026.2.19-cp314-cp314t-win_amd64.whl", hash = "sha256:64128549b600987e0f335c2365879895f860a9161f283b14207c800a6ed623d3", size = 284443, upload-time = "2026-02-19T19:03:42.954Z" }, - { url = "https://files.pythonhosted.org/packages/3a/45/affdf2d851b42adf3d13fc5b3b059372e9bd299371fd84cf5723c45871fa/regex-2026.2.19-cp314-cp314t-win_arm64.whl", hash = "sha256:a09ae430e94c049dc6957f6baa35ee3418a3a77f3c12b6e02883bd80a2b679b0", size = 274932, upload-time = "2026-02-19T19:03:45.488Z" }, +version = "2026.2.28" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8b/71/41455aa99a5a5ac1eaf311f5d8efd9ce6433c03ac1e0962de163350d0d97/regex-2026.2.28.tar.gz", hash = "sha256:a729e47d418ea11d03469f321aaf67cdee8954cde3ff2cf8403ab87951ad10f2", size = 415184, upload-time = "2026-02-28T02:19:42.792Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cf/03/691015f7a7cb1ed6dacb2ea5de5682e4858e05a4c5506b2839cd533bbcd6/regex-2026.2.28-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:78454178c7df31372ea737996fb7f36b3c2c92cccc641d251e072478afb4babc", size = 489497, upload-time = "2026-02-28T02:18:30.889Z" }, + { url = "https://files.pythonhosted.org/packages/c6/ba/8db8fd19afcbfa0e1036eaa70c05f20ca8405817d4ad7a38a6b4c2f031ac/regex-2026.2.28-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:5d10303dd18cedfd4d095543998404df656088240bcfd3cd20a8f95b861f74bd", size = 291295, upload-time = "2026-02-28T02:18:33.426Z" }, + { url = "https://files.pythonhosted.org/packages/5a/79/9aa0caf089e8defef9b857b52fc53801f62ff868e19e5c83d4a96612eba1/regex-2026.2.28-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:19a9c9e0a8f24f39d575a6a854d516b48ffe4cbdcb9de55cb0570a032556ecff", size = 289275, upload-time = "2026-02-28T02:18:35.247Z" }, + { url = "https://files.pythonhosted.org/packages/eb/26/ee53117066a30ef9c883bf1127eece08308ccf8ccd45c45a966e7a665385/regex-2026.2.28-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:09500be324f49b470d907b3ef8af9afe857f5cca486f853853f7945ddbf75911", size = 797176, upload-time = "2026-02-28T02:18:37.15Z" }, + { url = "https://files.pythonhosted.org/packages/05/1b/67fb0495a97259925f343ae78b5d24d4a6624356ae138b57f18bd43006e4/regex-2026.2.28-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:fb1c4ff62277d87a7335f2c1ea4e0387b8f2b3ad88a64efd9943906aafad4f33", size = 863813, upload-time = "2026-02-28T02:18:39.478Z" }, + { url = "https://files.pythonhosted.org/packages/a0/1d/93ac9bbafc53618091c685c7ed40239a90bf9f2a82c983f0baa97cb7ae07/regex-2026.2.28-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b8b3f1be1738feadc69f62daa250c933e85c6f34fa378f54a7ff43807c1b9117", size = 908678, upload-time = "2026-02-28T02:18:41.619Z" }, + { url = "https://files.pythonhosted.org/packages/c7/7a/a8f5e0561702b25239846a16349feece59712ae20598ebb205580332a471/regex-2026.2.28-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dc8ed8c3f41c27acb83f7b6a9eb727a73fc6663441890c5cb3426a5f6a91ce7d", size = 801528, upload-time = "2026-02-28T02:18:43.624Z" }, + { url = "https://files.pythonhosted.org/packages/96/5d/ed6d4cbde80309854b1b9f42d9062fee38ade15f7eb4909f6ef2440403b5/regex-2026.2.28-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fa539be029844c0ce1114762d2952ab6cfdd7c7c9bd72e0db26b94c3c36dcc5a", size = 775373, upload-time = "2026-02-28T02:18:46.102Z" }, + { url = "https://files.pythonhosted.org/packages/6a/e9/6e53c34e8068b9deec3e87210086ecb5b9efebdefca6b0d3fa43d66dcecb/regex-2026.2.28-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7900157786428a79615a8264dac1f12c9b02957c473c8110c6b1f972dcecaddf", size = 784859, upload-time = "2026-02-28T02:18:48.269Z" }, + { url = "https://files.pythonhosted.org/packages/48/3c/736e1c7ca7f0dcd2ae33819888fdc69058a349b7e5e84bc3e2f296bbf794/regex-2026.2.28-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:0b1d2b07614d95fa2bf8a63fd1e98bd8fa2b4848dc91b1efbc8ba219fdd73952", size = 857813, upload-time = "2026-02-28T02:18:50.576Z" }, + { url = "https://files.pythonhosted.org/packages/6e/7c/48c4659ad9da61f58e79dbe8c05223e0006696b603c16eb6b5cbfbb52c27/regex-2026.2.28-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:b389c61aa28a79c2e0527ac36da579869c2e235a5b208a12c5b5318cda2501d8", size = 763705, upload-time = "2026-02-28T02:18:52.59Z" }, + { url = "https://files.pythonhosted.org/packages/cf/a1/bc1c261789283128165f71b71b4b221dd1b79c77023752a6074c102f18d8/regex-2026.2.28-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:f467cb602f03fbd1ab1908f68b53c649ce393fde056628dc8c7e634dab6bfc07", size = 848734, upload-time = "2026-02-28T02:18:54.595Z" }, + { url = "https://files.pythonhosted.org/packages/10/d8/979407faf1397036e25a5ae778157366a911c0f382c62501009f4957cf86/regex-2026.2.28-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e8c8cb2deba42f5ec1ede46374e990f8adc5e6456a57ac1a261b19be6f28e4e6", size = 789871, upload-time = "2026-02-28T02:18:57.34Z" }, + { url = "https://files.pythonhosted.org/packages/03/23/da716821277115fcb1f4e3de1e5dc5023a1e6533598c486abf5448612579/regex-2026.2.28-cp314-cp314-win32.whl", hash = "sha256:9036b400b20e4858d56d117108d7813ed07bb7803e3eed766675862131135ca6", size = 271825, upload-time = "2026-02-28T02:18:59.202Z" }, + { url = "https://files.pythonhosted.org/packages/91/ff/90696f535d978d5f16a52a419be2770a8d8a0e7e0cfecdbfc31313df7fab/regex-2026.2.28-cp314-cp314-win_amd64.whl", hash = "sha256:1d367257cd86c1cbb97ea94e77b373a0bbc2224976e247f173d19e8f18b4afa7", size = 280548, upload-time = "2026-02-28T02:19:01.049Z" }, + { url = "https://files.pythonhosted.org/packages/69/f9/5e1b5652fc0af3fcdf7677e7df3ad2a0d47d669b34ac29a63bb177bb731b/regex-2026.2.28-cp314-cp314-win_arm64.whl", hash = "sha256:5e68192bb3a1d6fb2836da24aa494e413ea65853a21505e142e5b1064a595f3d", size = 273444, upload-time = "2026-02-28T02:19:03.255Z" }, + { url = "https://files.pythonhosted.org/packages/d3/eb/8389f9e940ac89bcf58d185e230a677b4fd07c5f9b917603ad5c0f8fa8fe/regex-2026.2.28-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:a5dac14d0872eeb35260a8e30bac07ddf22adc1e3a0635b52b02e180d17c9c7e", size = 492546, upload-time = "2026-02-28T02:19:05.378Z" }, + { url = "https://files.pythonhosted.org/packages/7b/c7/09441d27ce2a6fa6a61ea3150ea4639c1dcda9b31b2ea07b80d6937b24dd/regex-2026.2.28-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:ec0c608b7a7465ffadb344ed7c987ff2f11ee03f6a130b569aa74d8a70e8333c", size = 292986, upload-time = "2026-02-28T02:19:07.24Z" }, + { url = "https://files.pythonhosted.org/packages/fb/69/4144b60ed7760a6bd235e4087041f487aa4aa62b45618ce018b0c14833ea/regex-2026.2.28-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c7815afb0ca45456613fdaf60ea9c993715511c8d53a83bc468305cbc0ee23c7", size = 291518, upload-time = "2026-02-28T02:19:09.698Z" }, + { url = "https://files.pythonhosted.org/packages/2d/be/77e5426cf5948c82f98c53582009ca9e94938c71f73a8918474f2e2990bb/regex-2026.2.28-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b059e71ec363968671693a78c5053bd9cb2fe410f9b8e4657e88377ebd603a2e", size = 809464, upload-time = "2026-02-28T02:19:12.494Z" }, + { url = "https://files.pythonhosted.org/packages/45/99/2c8c5ac90dc7d05c6e7d8e72c6a3599dc08cd577ac476898e91ca787d7f1/regex-2026.2.28-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b8cf76f1a29f0e99dcfd7aef1551a9827588aae5a737fe31442021165f1920dc", size = 869553, upload-time = "2026-02-28T02:19:15.151Z" }, + { url = "https://files.pythonhosted.org/packages/53/34/daa66a342f0271e7737003abf6c3097aa0498d58c668dbd88362ef94eb5d/regex-2026.2.28-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:180e08a435a0319e6a4821c3468da18dc7001987e1c17ae1335488dfe7518dd8", size = 915289, upload-time = "2026-02-28T02:19:17.331Z" }, + { url = "https://files.pythonhosted.org/packages/c5/c7/e22c2aaf0a12e7e22ab19b004bb78d32ca1ecc7ef245949935463c5567de/regex-2026.2.28-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1e496956106fd59ba6322a8ea17141a27c5040e5ee8f9433ae92d4e5204462a0", size = 812156, upload-time = "2026-02-28T02:19:20.011Z" }, + { url = "https://files.pythonhosted.org/packages/7f/bb/2dc18c1efd9051cf389cd0d7a3a4d90f6804b9fff3a51b5dc3c85b935f71/regex-2026.2.28-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bba2b18d70eeb7b79950f12f633beeecd923f7c9ad6f6bae28e59b4cb3ab046b", size = 782215, upload-time = "2026-02-28T02:19:22.047Z" }, + { url = "https://files.pythonhosted.org/packages/17/1e/9e4ec9b9013931faa32226ec4aa3c71fe664a6d8a2b91ac56442128b332f/regex-2026.2.28-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:6db7bfae0f8a2793ff1f7021468ea55e2699d0790eb58ee6ab36ae43aa00bc5b", size = 798925, upload-time = "2026-02-28T02:19:24.173Z" }, + { url = "https://files.pythonhosted.org/packages/71/57/a505927e449a9ccb41e2cc8d735e2abe3444b0213d1cf9cb364a8c1f2524/regex-2026.2.28-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:d0b02e8b7e5874b48ae0f077ecca61c1a6a9f9895e9c6dfb191b55b242862033", size = 864701, upload-time = "2026-02-28T02:19:26.376Z" }, + { url = "https://files.pythonhosted.org/packages/a6/ad/c62cb60cdd93e13eac5b3d9d6bd5d284225ed0e3329426f94d2552dd7cca/regex-2026.2.28-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:25b6eb660c5cf4b8c3407a1ed462abba26a926cc9965e164268a3267bcc06a43", size = 770899, upload-time = "2026-02-28T02:19:29.38Z" }, + { url = "https://files.pythonhosted.org/packages/3c/5a/874f861f5c3d5ab99633e8030dee1bc113db8e0be299d1f4b07f5b5ec349/regex-2026.2.28-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:5a932ea8ad5d0430351ff9c76c8db34db0d9f53c1d78f06022a21f4e290c5c18", size = 854727, upload-time = "2026-02-28T02:19:31.494Z" }, + { url = "https://files.pythonhosted.org/packages/6b/ca/d2c03b0efde47e13db895b975b2be6a73ed90b8ba963677927283d43bf74/regex-2026.2.28-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:1c2c95e1a2b0f89d01e821ff4de1be4b5d73d1f4b0bf679fa27c1ad8d2327f1a", size = 800366, upload-time = "2026-02-28T02:19:34.248Z" }, + { url = "https://files.pythonhosted.org/packages/14/bd/ee13b20b763b8989f7c75d592bfd5de37dc1181814a2a2747fedcf97e3ba/regex-2026.2.28-cp314-cp314t-win32.whl", hash = "sha256:bbb882061f742eb5d46f2f1bd5304055be0a66b783576de3d7eef1bed4778a6e", size = 274936, upload-time = "2026-02-28T02:19:36.313Z" }, + { url = "https://files.pythonhosted.org/packages/cb/e7/d8020e39414c93af7f0d8688eabcecece44abfd5ce314b21dfda0eebd3d8/regex-2026.2.28-cp314-cp314t-win_amd64.whl", hash = "sha256:6591f281cb44dc13de9585b552cec6fc6cf47fb2fe7a48892295ee9bc4a612f9", size = 284779, upload-time = "2026-02-28T02:19:38.625Z" }, + { url = "https://files.pythonhosted.org/packages/13/c0/ad225f4a405827486f1955283407cf758b6d2fb966712644c5f5aef33d1b/regex-2026.2.28-cp314-cp314t-win_arm64.whl", hash = "sha256:dee50f1be42222f89767b64b283283ef963189da0dda4a515aa54a5563c62dec", size = 275010, upload-time = "2026-02-28T02:19:40.65Z" }, ] [[package]] @@ -1943,26 +1855,17 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, ] -[[package]] -name = "socksio" -version = "1.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f8/5c/48a7d9495be3d1c651198fd99dbb6ce190e2274d0f28b9051307bdec6b85/socksio-1.0.0.tar.gz", hash = "sha256:f88beb3da5b5c38b9890469de67d0cb0f9d494b78b106ca1845f96c10b91c4ac", size = 19055, upload-time = "2020-04-17T15:50:34.664Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/37/c3/6eeb6034408dac0fa653d126c9204ade96b819c936e136c5e8a6897eee9c/socksio-1.0.0-py3-none-any.whl", hash = "sha256:95dc1f15f9b34e8d7b16f06d74b8ccf48f609af32ab33c608d08761c5dcbb1f3", size = 12763, upload-time = "2020-04-17T15:50:31.878Z" }, -] - [[package]] name = "sse-starlette" -version = "3.2.0" +version = "3.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, { name = "starlette" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/8b/8d/00d280c03ffd39aaee0e86ec81e2d3b9253036a0f93f51d10503adef0e65/sse_starlette-3.2.0.tar.gz", hash = "sha256:8127594edfb51abe44eac9c49e59b0b01f1039d0c7461c6fd91d4e03b70da422", size = 27253, upload-time = "2026-01-17T13:11:05.62Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/9f/c3695c2d2d4ef70072c3a06992850498b01c6bc9be531950813716b426fa/sse_starlette-3.3.2.tar.gz", hash = "sha256:678fca55a1945c734d8472a6cad186a55ab02840b4f6786f5ee8770970579dcd", size = 32326, upload-time = "2026-02-28T11:24:34.36Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/96/7f/832f015020844a8b8f7a9cbc103dd76ba8e3875004c41e08440ea3a2b41a/sse_starlette-3.2.0-py3-none-any.whl", hash = "sha256:5876954bd51920fc2cd51baee47a080eb88a37b5b784e615abb0b283f801cdbf", size = 12763, upload-time = "2026-01-17T13:11:03.775Z" }, + { url = "https://files.pythonhosted.org/packages/61/28/8cb142d3fe80c4a2d8af54ca0b003f47ce0ba920974e7990fa6e016402d1/sse_starlette-3.3.2-py3-none-any.whl", hash = "sha256:5c3ea3dad425c601236726af2f27689b74494643f57017cafcb6f8c9acfbb862", size = 14270, upload-time = "2026-02-28T11:24:32.984Z" }, ] [[package]] @@ -2226,48 +2129,52 @@ wheels = [ [[package]] name = "yarl" -version = "1.22.0" +version = "1.23.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "idna" }, { name = "multidict" }, { name = "propcache" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/57/63/0c6ebca57330cd313f6102b16dd57ffaf3ec4c83403dcb45dbd15c6f3ea1/yarl-1.22.0.tar.gz", hash = "sha256:bebf8557577d4401ba8bd9ff33906f1376c877aa78d1fe216ad01b4d6745af71", size = 187169, upload-time = "2025-10-06T14:12:55.963Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/46/b3/e20ef504049f1a1c54a814b4b9bed96d1ac0e0610c3b4da178f87209db05/yarl-1.22.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:34b36c2c57124530884d89d50ed2c1478697ad7473efd59cfd479945c95650e4", size = 140520, upload-time = "2025-10-06T14:11:15.465Z" }, - { url = "https://files.pythonhosted.org/packages/e4/04/3532d990fdbab02e5ede063676b5c4260e7f3abea2151099c2aa745acc4c/yarl-1.22.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:0dd9a702591ca2e543631c2a017e4a547e38a5c0f29eece37d9097e04a7ac683", size = 93504, upload-time = "2025-10-06T14:11:17.106Z" }, - { url = "https://files.pythonhosted.org/packages/11/63/ff458113c5c2dac9a9719ac68ee7c947cb621432bcf28c9972b1c0e83938/yarl-1.22.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:594fcab1032e2d2cc3321bb2e51271e7cd2b516c7d9aee780ece81b07ff8244b", size = 94282, upload-time = "2025-10-06T14:11:19.064Z" }, - { url = "https://files.pythonhosted.org/packages/a7/bc/315a56aca762d44a6aaaf7ad253f04d996cb6b27bad34410f82d76ea8038/yarl-1.22.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f3d7a87a78d46a2e3d5b72587ac14b4c16952dd0887dbb051451eceac774411e", size = 372080, upload-time = "2025-10-06T14:11:20.996Z" }, - { url = "https://files.pythonhosted.org/packages/3f/3f/08e9b826ec2e099ea6e7c69a61272f4f6da62cb5b1b63590bb80ca2e4a40/yarl-1.22.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:852863707010316c973162e703bddabec35e8757e67fcb8ad58829de1ebc8590", size = 338696, upload-time = "2025-10-06T14:11:22.847Z" }, - { url = "https://files.pythonhosted.org/packages/e3/9f/90360108e3b32bd76789088e99538febfea24a102380ae73827f62073543/yarl-1.22.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:131a085a53bfe839a477c0845acf21efc77457ba2bcf5899618136d64f3303a2", size = 387121, upload-time = "2025-10-06T14:11:24.889Z" }, - { url = "https://files.pythonhosted.org/packages/98/92/ab8d4657bd5b46a38094cfaea498f18bb70ce6b63508fd7e909bd1f93066/yarl-1.22.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:078a8aefd263f4d4f923a9677b942b445a2be970ca24548a8102689a3a8ab8da", size = 394080, upload-time = "2025-10-06T14:11:27.307Z" }, - { url = "https://files.pythonhosted.org/packages/f5/e7/d8c5a7752fef68205296201f8ec2bf718f5c805a7a7e9880576c67600658/yarl-1.22.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bca03b91c323036913993ff5c738d0842fc9c60c4648e5c8d98331526df89784", size = 372661, upload-time = "2025-10-06T14:11:29.387Z" }, - { url = "https://files.pythonhosted.org/packages/b6/2e/f4d26183c8db0bb82d491b072f3127fb8c381a6206a3a56332714b79b751/yarl-1.22.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:68986a61557d37bb90d3051a45b91fa3d5c516d177dfc6dd6f2f436a07ff2b6b", size = 364645, upload-time = "2025-10-06T14:11:31.423Z" }, - { url = "https://files.pythonhosted.org/packages/80/7c/428e5812e6b87cd00ee8e898328a62c95825bf37c7fa87f0b6bb2ad31304/yarl-1.22.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:4792b262d585ff0dff6bcb787f8492e40698443ec982a3568c2096433660c694", size = 355361, upload-time = "2025-10-06T14:11:33.055Z" }, - { url = "https://files.pythonhosted.org/packages/ec/2a/249405fd26776f8b13c067378ef4d7dd49c9098d1b6457cdd152a99e96a9/yarl-1.22.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:ebd4549b108d732dba1d4ace67614b9545b21ece30937a63a65dd34efa19732d", size = 381451, upload-time = "2025-10-06T14:11:35.136Z" }, - { url = "https://files.pythonhosted.org/packages/67/a8/fb6b1adbe98cf1e2dd9fad71003d3a63a1bc22459c6e15f5714eb9323b93/yarl-1.22.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:f87ac53513d22240c7d59203f25cc3beac1e574c6cd681bbfd321987b69f95fd", size = 383814, upload-time = "2025-10-06T14:11:37.094Z" }, - { url = "https://files.pythonhosted.org/packages/d9/f9/3aa2c0e480fb73e872ae2814c43bc1e734740bb0d54e8cb2a95925f98131/yarl-1.22.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:22b029f2881599e2f1b06f8f1db2ee63bd309e2293ba2d566e008ba12778b8da", size = 370799, upload-time = "2025-10-06T14:11:38.83Z" }, - { url = "https://files.pythonhosted.org/packages/50/3c/af9dba3b8b5eeb302f36f16f92791f3ea62e3f47763406abf6d5a4a3333b/yarl-1.22.0-cp314-cp314-win32.whl", hash = "sha256:6a635ea45ba4ea8238463b4f7d0e721bad669f80878b7bfd1f89266e2ae63da2", size = 82990, upload-time = "2025-10-06T14:11:40.624Z" }, - { url = "https://files.pythonhosted.org/packages/ac/30/ac3a0c5bdc1d6efd1b41fa24d4897a4329b3b1e98de9449679dd327af4f0/yarl-1.22.0-cp314-cp314-win_amd64.whl", hash = "sha256:0d6e6885777af0f110b0e5d7e5dda8b704efed3894da26220b7f3d887b839a79", size = 88292, upload-time = "2025-10-06T14:11:42.578Z" }, - { url = "https://files.pythonhosted.org/packages/df/0a/227ab4ff5b998a1b7410abc7b46c9b7a26b0ca9e86c34ba4b8d8bc7c63d5/yarl-1.22.0-cp314-cp314-win_arm64.whl", hash = "sha256:8218f4e98d3c10d683584cb40f0424f4b9fd6e95610232dd75e13743b070ee33", size = 82888, upload-time = "2025-10-06T14:11:44.863Z" }, - { url = "https://files.pythonhosted.org/packages/06/5e/a15eb13db90abd87dfbefb9760c0f3f257ac42a5cac7e75dbc23bed97a9f/yarl-1.22.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:45c2842ff0e0d1b35a6bf1cd6c690939dacb617a70827f715232b2e0494d55d1", size = 146223, upload-time = "2025-10-06T14:11:46.796Z" }, - { url = "https://files.pythonhosted.org/packages/18/82/9665c61910d4d84f41a5bf6837597c89e665fa88aa4941080704645932a9/yarl-1.22.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:d947071e6ebcf2e2bee8fce76e10faca8f7a14808ca36a910263acaacef08eca", size = 95981, upload-time = "2025-10-06T14:11:48.845Z" }, - { url = "https://files.pythonhosted.org/packages/5d/9a/2f65743589809af4d0a6d3aa749343c4b5f4c380cc24a8e94a3c6625a808/yarl-1.22.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:334b8721303e61b00019474cc103bdac3d7b1f65e91f0bfedeec2d56dfe74b53", size = 97303, upload-time = "2025-10-06T14:11:50.897Z" }, - { url = "https://files.pythonhosted.org/packages/b0/ab/5b13d3e157505c43c3b43b5a776cbf7b24a02bc4cccc40314771197e3508/yarl-1.22.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e7ce67c34138a058fd092f67d07a72b8e31ff0c9236e751957465a24b28910c", size = 361820, upload-time = "2025-10-06T14:11:52.549Z" }, - { url = "https://files.pythonhosted.org/packages/fb/76/242a5ef4677615cf95330cfc1b4610e78184400699bdda0acb897ef5e49a/yarl-1.22.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d77e1b2c6d04711478cb1c4ab90db07f1609ccf06a287d5607fcd90dc9863acf", size = 323203, upload-time = "2025-10-06T14:11:54.225Z" }, - { url = "https://files.pythonhosted.org/packages/8c/96/475509110d3f0153b43d06164cf4195c64d16999e0c7e2d8a099adcd6907/yarl-1.22.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4647674b6150d2cae088fc07de2738a84b8bcedebef29802cf0b0a82ab6face", size = 363173, upload-time = "2025-10-06T14:11:56.069Z" }, - { url = "https://files.pythonhosted.org/packages/c9/66/59db471aecfbd559a1fd48aedd954435558cd98c7d0da8b03cc6c140a32c/yarl-1.22.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:efb07073be061c8f79d03d04139a80ba33cbd390ca8f0297aae9cce6411e4c6b", size = 373562, upload-time = "2025-10-06T14:11:58.783Z" }, - { url = "https://files.pythonhosted.org/packages/03/1f/c5d94abc91557384719da10ff166b916107c1b45e4d0423a88457071dd88/yarl-1.22.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e51ac5435758ba97ad69617e13233da53908beccc6cfcd6c34bbed8dcbede486", size = 339828, upload-time = "2025-10-06T14:12:00.686Z" }, - { url = "https://files.pythonhosted.org/packages/5f/97/aa6a143d3afba17b6465733681c70cf175af89f76ec8d9286e08437a7454/yarl-1.22.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:33e32a0dd0c8205efa8e83d04fc9f19313772b78522d1bdc7d9aed706bfd6138", size = 347551, upload-time = "2025-10-06T14:12:02.628Z" }, - { url = "https://files.pythonhosted.org/packages/43/3c/45a2b6d80195959239a7b2a8810506d4eea5487dce61c2a3393e7fc3c52e/yarl-1.22.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:bf4a21e58b9cde0e401e683ebd00f6ed30a06d14e93f7c8fd059f8b6e8f87b6a", size = 334512, upload-time = "2025-10-06T14:12:04.871Z" }, - { url = "https://files.pythonhosted.org/packages/86/a0/c2ab48d74599c7c84cb104ebd799c5813de252bea0f360ffc29d270c2caa/yarl-1.22.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:e4b582bab49ac33c8deb97e058cd67c2c50dac0dd134874106d9c774fd272529", size = 352400, upload-time = "2025-10-06T14:12:06.624Z" }, - { url = "https://files.pythonhosted.org/packages/32/75/f8919b2eafc929567d3d8411f72bdb1a2109c01caaab4ebfa5f8ffadc15b/yarl-1.22.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:0b5bcc1a9c4839e7e30b7b30dd47fe5e7e44fb7054ec29b5bb8d526aa1041093", size = 357140, upload-time = "2025-10-06T14:12:08.362Z" }, - { url = "https://files.pythonhosted.org/packages/cf/72/6a85bba382f22cf78add705d8c3731748397d986e197e53ecc7835e76de7/yarl-1.22.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c0232bce2170103ec23c454e54a57008a9a72b5d1c3105dc2496750da8cfa47c", size = 341473, upload-time = "2025-10-06T14:12:10.994Z" }, - { url = "https://files.pythonhosted.org/packages/35/18/55e6011f7c044dc80b98893060773cefcfdbf60dfefb8cb2f58b9bacbd83/yarl-1.22.0-cp314-cp314t-win32.whl", hash = "sha256:8009b3173bcd637be650922ac455946197d858b3630b6d8787aa9e5c4564533e", size = 89056, upload-time = "2025-10-06T14:12:13.317Z" }, - { url = "https://files.pythonhosted.org/packages/f9/86/0f0dccb6e59a9e7f122c5afd43568b1d31b8ab7dda5f1b01fb5c7025c9a9/yarl-1.22.0-cp314-cp314t-win_amd64.whl", hash = "sha256:9fb17ea16e972c63d25d4a97f016d235c78dd2344820eb35bc034bc32012ee27", size = 96292, upload-time = "2025-10-06T14:12:15.398Z" }, - { url = "https://files.pythonhosted.org/packages/48/b7/503c98092fb3b344a179579f55814b613c1fbb1c23b3ec14a7b008a66a6e/yarl-1.22.0-cp314-cp314t-win_arm64.whl", hash = "sha256:9f6d73c1436b934e3f01df1e1b21ff765cd1d28c77dfb9ace207f746d4610ee1", size = 85171, upload-time = "2025-10-06T14:12:16.935Z" }, - { url = "https://files.pythonhosted.org/packages/73/ae/b48f95715333080afb75a4504487cbe142cae1268afc482d06692d605ae6/yarl-1.22.0-py3-none-any.whl", hash = "sha256:1380560bdba02b6b6c90de54133c81c9f2a453dee9912fe58c1dcced1edb7cff", size = 46814, upload-time = "2025-10-06T14:12:53.872Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/23/6e/beb1beec874a72f23815c1434518bfc4ed2175065173fb138c3705f658d4/yarl-1.23.0.tar.gz", hash = "sha256:53b1ea6ca88ebd4420379c330aea57e258408dd0df9af0992e5de2078dc9f5d5", size = 194676, upload-time = "2026-03-01T22:07:53.373Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/90/98/b85a038d65d1b92c3903ab89444f48d3cee490a883477b716d7a24b1a78c/yarl-1.23.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:21d1b7305a71a15b4794b5ff22e8eef96ff4a6d7f9657155e5aa419444b28912", size = 124455, upload-time = "2026-03-01T22:06:43.615Z" }, + { url = "https://files.pythonhosted.org/packages/39/54/bc2b45559f86543d163b6e294417a107bb87557609007c007ad889afec18/yarl-1.23.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:85610b4f27f69984932a7abbe52703688de3724d9f72bceb1cca667deff27474", size = 86752, upload-time = "2026-03-01T22:06:45.425Z" }, + { url = "https://files.pythonhosted.org/packages/24/f9/e8242b68362bffe6fb536c8db5076861466fc780f0f1b479fc4ffbebb128/yarl-1.23.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:23f371bd662cf44a7630d4d113101eafc0cfa7518a2760d20760b26021454719", size = 86291, upload-time = "2026-03-01T22:06:46.974Z" }, + { url = "https://files.pythonhosted.org/packages/ea/d8/d1cb2378c81dd729e98c716582b1ccb08357e8488e4c24714658cc6630e8/yarl-1.23.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c4a80f77dc1acaaa61f0934176fccca7096d9b1ff08c8ba9cddf5ae034a24319", size = 99026, upload-time = "2026-03-01T22:06:48.459Z" }, + { url = "https://files.pythonhosted.org/packages/0a/ff/7196790538f31debe3341283b5b0707e7feb947620fc5e8236ef28d44f72/yarl-1.23.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:bd654fad46d8d9e823afbb4f87c79160b5a374ed1ff5bde24e542e6ba8f41434", size = 92355, upload-time = "2026-03-01T22:06:50.306Z" }, + { url = "https://files.pythonhosted.org/packages/c1/56/25d58c3eddde825890a5fe6aa1866228377354a3c39262235234ab5f616b/yarl-1.23.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:682bae25f0a0dd23a056739f23a134db9f52a63e2afd6bfb37ddc76292bbd723", size = 106417, upload-time = "2026-03-01T22:06:52.1Z" }, + { url = "https://files.pythonhosted.org/packages/51/8a/882c0e7bc8277eb895b31bce0138f51a1ba551fc2e1ec6753ffc1e7c1377/yarl-1.23.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a82836cab5f197a0514235aaf7ffccdc886ccdaa2324bc0aafdd4ae898103039", size = 106422, upload-time = "2026-03-01T22:06:54.424Z" }, + { url = "https://files.pythonhosted.org/packages/42/2b/fef67d616931055bf3d6764885990a3ac647d68734a2d6a9e1d13de437a2/yarl-1.23.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1c57676bdedc94cd3bc37724cf6f8cd2779f02f6aba48de45feca073e714fe52", size = 101915, upload-time = "2026-03-01T22:06:55.895Z" }, + { url = "https://files.pythonhosted.org/packages/18/6a/530e16aebce27c5937920f3431c628a29a4b6b430fab3fd1c117b26ff3f6/yarl-1.23.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c7f8dc16c498ff06497c015642333219871effba93e4a2e8604a06264aca5c5c", size = 100690, upload-time = "2026-03-01T22:06:58.21Z" }, + { url = "https://files.pythonhosted.org/packages/88/08/93749219179a45e27b036e03260fda05190b911de8e18225c294ac95bbc9/yarl-1.23.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:5ee586fb17ff8f90c91cf73c6108a434b02d69925f44f5f8e0d7f2f260607eae", size = 98750, upload-time = "2026-03-01T22:06:59.794Z" }, + { url = "https://files.pythonhosted.org/packages/d9/cf/ea424a004969f5d81a362110a6ac1496d79efdc6d50c2c4b2e3ea0fc2519/yarl-1.23.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:17235362f580149742739cc3828b80e24029d08cbb9c4bda0242c7b5bc610a8e", size = 94685, upload-time = "2026-03-01T22:07:01.375Z" }, + { url = "https://files.pythonhosted.org/packages/e2/b7/14341481fe568e2b0408bcf1484c652accafe06a0ade9387b5d3fd9df446/yarl-1.23.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:0793e2bd0cf14234983bbb371591e6bea9e876ddf6896cdcc93450996b0b5c85", size = 106009, upload-time = "2026-03-01T22:07:03.151Z" }, + { url = "https://files.pythonhosted.org/packages/0a/e6/5c744a9b54f4e8007ad35bce96fbc9218338e84812d36f3390cea616881a/yarl-1.23.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:3650dc2480f94f7116c364096bc84b1d602f44224ef7d5c7208425915c0475dd", size = 100033, upload-time = "2026-03-01T22:07:04.701Z" }, + { url = "https://files.pythonhosted.org/packages/0c/23/e3bfc188d0b400f025bc49d99793d02c9abe15752138dcc27e4eaf0c4a9e/yarl-1.23.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:f40e782d49630ad384db66d4d8b73ff4f1b8955dc12e26b09a3e3af064b3b9d6", size = 106483, upload-time = "2026-03-01T22:07:06.231Z" }, + { url = "https://files.pythonhosted.org/packages/72/42/f0505f949a90b3f8b7a363d6cbdf398f6e6c58946d85c6d3a3bc70595b26/yarl-1.23.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:94f8575fbdf81749008d980c17796097e645574a3b8c28ee313931068dad14fe", size = 102175, upload-time = "2026-03-01T22:07:08.4Z" }, + { url = "https://files.pythonhosted.org/packages/aa/65/b39290f1d892a9dd671d1c722014ca062a9c35d60885d57e5375db0404b5/yarl-1.23.0-cp314-cp314-win32.whl", hash = "sha256:c8aa34a5c864db1087d911a0b902d60d203ea3607d91f615acd3f3108ac32169", size = 83871, upload-time = "2026-03-01T22:07:09.968Z" }, + { url = "https://files.pythonhosted.org/packages/a9/5b/9b92f54c784c26e2a422e55a8d2607ab15b7ea3349e28359282f84f01d43/yarl-1.23.0-cp314-cp314-win_amd64.whl", hash = "sha256:63e92247f383c85ab00dd0091e8c3fa331a96e865459f5ee80353c70a4a42d70", size = 89093, upload-time = "2026-03-01T22:07:11.501Z" }, + { url = "https://files.pythonhosted.org/packages/e0/7d/8a84dc9381fd4412d5e7ff04926f9865f6372b4c2fd91e10092e65d29eb8/yarl-1.23.0-cp314-cp314-win_arm64.whl", hash = "sha256:70efd20be968c76ece7baa8dafe04c5be06abc57f754d6f36f3741f7aa7a208e", size = 83384, upload-time = "2026-03-01T22:07:13.069Z" }, + { url = "https://files.pythonhosted.org/packages/dd/8d/d2fad34b1c08aa161b74394183daa7d800141aaaee207317e82c790b418d/yarl-1.23.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:9a18d6f9359e45722c064c97464ec883eb0e0366d33eda61cb19a244bf222679", size = 131019, upload-time = "2026-03-01T22:07:14.903Z" }, + { url = "https://files.pythonhosted.org/packages/19/ff/33009a39d3ccf4b94d7d7880dfe17fb5816c5a4fe0096d9b56abceea9ac7/yarl-1.23.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:2803ed8b21ca47a43da80a6fd1ed3019d30061f7061daa35ac54f63933409412", size = 89894, upload-time = "2026-03-01T22:07:17.372Z" }, + { url = "https://files.pythonhosted.org/packages/0c/f1/dab7ac5e7306fb79c0190766a3c00b4cb8d09a1f390ded68c85a5934faf5/yarl-1.23.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:394906945aa8b19fc14a61cf69743a868bb8c465efe85eee687109cc540b98f4", size = 89979, upload-time = "2026-03-01T22:07:19.361Z" }, + { url = "https://files.pythonhosted.org/packages/aa/b1/08e95f3caee1fad6e65017b9f26c1d79877b502622d60e517de01e72f95d/yarl-1.23.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:71d006bee8397a4a89f469b8deb22469fe7508132d3c17fa6ed871e79832691c", size = 95943, upload-time = "2026-03-01T22:07:21.266Z" }, + { url = "https://files.pythonhosted.org/packages/c0/cc/6409f9018864a6aa186c61175b977131f373f1988e198e031236916e87e4/yarl-1.23.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:62694e275c93d54f7ccedcfef57d42761b2aad5234b6be1f3e3026cae4001cd4", size = 88786, upload-time = "2026-03-01T22:07:23.129Z" }, + { url = "https://files.pythonhosted.org/packages/76/40/cc22d1d7714b717fde2006fad2ced5efe5580606cb059ae42117542122f3/yarl-1.23.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a31de1613658308efdb21ada98cbc86a97c181aa050ba22a808120bb5be3ab94", size = 101307, upload-time = "2026-03-01T22:07:24.689Z" }, + { url = "https://files.pythonhosted.org/packages/8f/0d/476c38e85ddb4c6ec6b20b815bdd779aa386a013f3d8b85516feee55c8dc/yarl-1.23.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fb1e8b8d66c278b21d13b0a7ca22c41dd757a7c209c6b12c313e445c31dd3b28", size = 100904, upload-time = "2026-03-01T22:07:26.287Z" }, + { url = "https://files.pythonhosted.org/packages/72/32/0abe4a76d59adf2081dcb0397168553ece4616ada1c54d1c49d8936c74f8/yarl-1.23.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50f9d8d531dfb767c565f348f33dd5139a6c43f5cbdf3f67da40d54241df93f6", size = 97728, upload-time = "2026-03-01T22:07:27.906Z" }, + { url = "https://files.pythonhosted.org/packages/b7/35/7b30f4810fba112f60f5a43237545867504e15b1c7647a785fbaf588fac2/yarl-1.23.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:575aa4405a656e61a540f4a80eaa5260f2a38fff7bfdc4b5f611840d76e9e277", size = 95964, upload-time = "2026-03-01T22:07:30.198Z" }, + { url = "https://files.pythonhosted.org/packages/2d/86/ed7a73ab85ef00e8bb70b0cb5421d8a2a625b81a333941a469a6f4022828/yarl-1.23.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:041b1a4cefacf65840b4e295c6985f334ba83c30607441ae3cf206a0eed1a2e4", size = 95882, upload-time = "2026-03-01T22:07:32.132Z" }, + { url = "https://files.pythonhosted.org/packages/19/90/d56967f61a29d8498efb7afb651e0b2b422a1e9b47b0ab5f4e40a19b699b/yarl-1.23.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:d38c1e8231722c4ce40d7593f28d92b5fc72f3e9774fe73d7e800ec32299f63a", size = 90797, upload-time = "2026-03-01T22:07:34.404Z" }, + { url = "https://files.pythonhosted.org/packages/72/00/8b8f76909259f56647adb1011d7ed8b321bcf97e464515c65016a47ecdf0/yarl-1.23.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:d53834e23c015ee83a99377db6e5e37d8484f333edb03bd15b4bc312cc7254fb", size = 101023, upload-time = "2026-03-01T22:07:35.953Z" }, + { url = "https://files.pythonhosted.org/packages/ac/e2/cab11b126fb7d440281b7df8e9ddbe4851e70a4dde47a202b6642586b8d9/yarl-1.23.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:2e27c8841126e017dd2a054a95771569e6070b9ee1b133366d8b31beb5018a41", size = 96227, upload-time = "2026-03-01T22:07:37.594Z" }, + { url = "https://files.pythonhosted.org/packages/c2/9b/2c893e16bfc50e6b2edf76c1a9eb6cb0c744346197e74c65e99ad8d634d0/yarl-1.23.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:76855800ac56f878847a09ce6dba727c93ca2d89c9e9d63002d26b916810b0a2", size = 100302, upload-time = "2026-03-01T22:07:39.334Z" }, + { url = "https://files.pythonhosted.org/packages/28/ec/5498c4e3a6d5f1003beb23405671c2eb9cdbf3067d1c80f15eeafe301010/yarl-1.23.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e09fd068c2e169a7070d83d3bde728a4d48de0549f975290be3c108c02e499b4", size = 98202, upload-time = "2026-03-01T22:07:41.717Z" }, + { url = "https://files.pythonhosted.org/packages/fe/c3/cd737e2d45e70717907f83e146f6949f20cc23cd4bf7b2688727763aa458/yarl-1.23.0-cp314-cp314t-win32.whl", hash = "sha256:73309162a6a571d4cbd3b6a1dcc703c7311843ae0d1578df6f09be4e98df38d4", size = 90558, upload-time = "2026-03-01T22:07:43.433Z" }, + { url = "https://files.pythonhosted.org/packages/e1/19/3774d162f6732d1cfb0b47b4140a942a35ca82bb19b6db1f80e9e7bdc8f8/yarl-1.23.0-cp314-cp314t-win_amd64.whl", hash = "sha256:4503053d296bc6e4cbd1fad61cf3b6e33b939886c4f249ba7c78b602214fabe2", size = 97610, upload-time = "2026-03-01T22:07:45.773Z" }, + { url = "https://files.pythonhosted.org/packages/51/47/3fa2286c3cb162c71cdb34c4224d5745a1ceceb391b2bd9b19b668a8d724/yarl-1.23.0-cp314-cp314t-win_arm64.whl", hash = "sha256:44bb7bef4ea409384e3f8bc36c063d77ea1b8d4a5b2706956c0d6695f07dcc25", size = 86041, upload-time = "2026-03-01T22:07:49.026Z" }, + { url = "https://files.pythonhosted.org/packages/69/68/c8739671f5699c7dc470580a4f821ef37c32c4cb0b047ce223a7f115757f/yarl-1.23.0-py3-none-any.whl", hash = "sha256:a2df6afe50dea8ae15fa34c9f824a3ee958d785fd5d089063d960bae1daa0a3f", size = 48288, upload-time = "2026-03-01T22:07:51.388Z" }, ] [[package]] diff --git a/apps/agentstack-sdk-py/uv.lock b/apps/agentstack-sdk-py/uv.lock index 3e49156b33..f09d0030b7 100644 --- a/apps/agentstack-sdk-py/uv.lock +++ b/apps/agentstack-sdk-py/uv.lock @@ -8,8 +8,8 @@ resolution-markers = [ [[package]] name = "a2a-sdk" -version = "0.3.24.post37.dev0+dce3650" -source = { git = "https://github.com/a2aproject/a2a-python.git?rev=1.0-dev#dce36502b51f671ae0e0a926cc0ad8c208393329" } +version = "0.3.24.post44.dev0+6086f96" +source = { git = "https://github.com/a2aproject/a2a-python.git?rev=1.0-dev#6086f96a2b32cc01f822836385d8d68b074e61d1" } dependencies = [ { name = "google-api-core" }, { name = "googleapis-common-protos" }, @@ -300,14 +300,14 @@ wheels = [ [[package]] name = "authlib" -version = "1.6.8" +version = "1.6.9" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cryptography" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/6b/6c/c88eac87468c607f88bc24df1f3b31445ee6fc9ba123b09e666adf687cd9/authlib-1.6.8.tar.gz", hash = "sha256:41ae180a17cf672bc784e4a518e5c82687f1fe1e98b0cafaeda80c8e4ab2d1cb", size = 165074, upload-time = "2026-02-14T04:02:17.941Z" } +sdist = { url = "https://files.pythonhosted.org/packages/af/98/00d3dd826d46959ad8e32af2dbb2398868fd9fd0683c26e56d0789bd0e68/authlib-1.6.9.tar.gz", hash = "sha256:d8f2421e7e5980cc1ddb4e32d3f5fa659cfaf60d8eaf3281ebed192e4ab74f04", size = 165134, upload-time = "2026-03-02T07:44:01.998Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9b/73/f7084bf12755113cd535ae586782ff3a6e710bfbe6a0d13d1c2f81ffbbfa/authlib-1.6.8-py2.py3-none-any.whl", hash = "sha256:97286fd7a15e6cfefc32771c8ef9c54f0ed58028f1322de6a2a7c969c3817888", size = 244116, upload-time = "2026-02-14T04:02:15.579Z" }, + { url = "https://files.pythonhosted.org/packages/53/23/b65f568ed0c22f1efacb744d2db1a33c8068f384b8c9b482b52ebdbc3ef6/authlib-1.6.9-py2.py3-none-any.whl", hash = "sha256:f08b4c14e08f0861dc18a32357b33fbcfd2ea86cfe3fe149484b4d764c4a0ac3", size = 244197, upload-time = "2026-03-02T07:44:00.307Z" }, ] [[package]] @@ -339,81 +339,13 @@ wikipedia = [ { name = "wikipedia-api" }, ] -[[package]] -name = "brotli" -version = "1.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f7/16/c92ca344d646e71a43b8bb353f0a6490d7f6e06210f8554c8f874e454285/brotli-1.2.0.tar.gz", hash = "sha256:e310f77e41941c13340a95976fe66a8a95b01e783d430eeaf7a2f87e0a57dd0a", size = 7388632, upload-time = "2025-11-05T18:39:42.86Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7a/ef/f285668811a9e1ddb47a18cb0b437d5fc2760d537a2fe8a57875ad6f8448/brotli-1.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:15b33fe93cedc4caaff8a0bd1eb7e3dab1c61bb22a0bf5bdfdfd97cd7da79744", size = 863110, upload-time = "2025-11-05T18:38:12.978Z" }, - { url = "https://files.pythonhosted.org/packages/50/62/a3b77593587010c789a9d6eaa527c79e0848b7b860402cc64bc0bc28a86c/brotli-1.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:898be2be399c221d2671d29eed26b6b2713a02c2119168ed914e7d00ceadb56f", size = 445438, upload-time = "2025-11-05T18:38:14.208Z" }, - { url = "https://files.pythonhosted.org/packages/cd/e1/7fadd47f40ce5549dc44493877db40292277db373da5053aff181656e16e/brotli-1.2.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:350c8348f0e76fff0a0fd6c26755d2653863279d086d3aa2c290a6a7251135dd", size = 1534420, upload-time = "2025-11-05T18:38:15.111Z" }, - { url = "https://files.pythonhosted.org/packages/12/8b/1ed2f64054a5a008a4ccd2f271dbba7a5fb1a3067a99f5ceadedd4c1d5a7/brotli-1.2.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2e1ad3fda65ae0d93fec742a128d72e145c9c7a99ee2fcd667785d99eb25a7fe", size = 1632619, upload-time = "2025-11-05T18:38:16.094Z" }, - { url = "https://files.pythonhosted.org/packages/89/5a/7071a621eb2d052d64efd5da2ef55ecdac7c3b0c6e4f9d519e9c66d987ef/brotli-1.2.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:40d918bce2b427a0c4ba189df7a006ac0c7277c180aee4617d99e9ccaaf59e6a", size = 1426014, upload-time = "2025-11-05T18:38:17.177Z" }, - { url = "https://files.pythonhosted.org/packages/26/6d/0971a8ea435af5156acaaccec1a505f981c9c80227633851f2810abd252a/brotli-1.2.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2a7f1d03727130fc875448b65b127a9ec5d06d19d0148e7554384229706f9d1b", size = 1489661, upload-time = "2025-11-05T18:38:18.41Z" }, - { url = "https://files.pythonhosted.org/packages/f3/75/c1baca8b4ec6c96a03ef8230fab2a785e35297632f402ebb1e78a1e39116/brotli-1.2.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:9c79f57faa25d97900bfb119480806d783fba83cd09ee0b33c17623935b05fa3", size = 1599150, upload-time = "2025-11-05T18:38:19.792Z" }, - { url = "https://files.pythonhosted.org/packages/0d/1a/23fcfee1c324fd48a63d7ebf4bac3a4115bdb1b00e600f80f727d850b1ae/brotli-1.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:844a8ceb8483fefafc412f85c14f2aae2fb69567bf2a0de53cdb88b73e7c43ae", size = 1493505, upload-time = "2025-11-05T18:38:20.913Z" }, - { url = "https://files.pythonhosted.org/packages/36/e5/12904bbd36afeef53d45a84881a4810ae8810ad7e328a971ebbfd760a0b3/brotli-1.2.0-cp311-cp311-win32.whl", hash = "sha256:aa47441fa3026543513139cb8926a92a8e305ee9c71a6209ef7a97d91640ea03", size = 334451, upload-time = "2025-11-05T18:38:21.94Z" }, - { url = "https://files.pythonhosted.org/packages/02/8b/ecb5761b989629a4758c394b9301607a5880de61ee2ee5fe104b87149ebc/brotli-1.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:022426c9e99fd65d9475dce5c195526f04bb8be8907607e27e747893f6ee3e24", size = 369035, upload-time = "2025-11-05T18:38:22.941Z" }, - { url = "https://files.pythonhosted.org/packages/11/ee/b0a11ab2315c69bb9b45a2aaed022499c9c24a205c3a49c3513b541a7967/brotli-1.2.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:35d382625778834a7f3061b15423919aa03e4f5da34ac8e02c074e4b75ab4f84", size = 861543, upload-time = "2025-11-05T18:38:24.183Z" }, - { url = "https://files.pythonhosted.org/packages/e1/2f/29c1459513cd35828e25531ebfcbf3e92a5e49f560b1777a9af7203eb46e/brotli-1.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7a61c06b334bd99bc5ae84f1eeb36bfe01400264b3c352f968c6e30a10f9d08b", size = 444288, upload-time = "2025-11-05T18:38:25.139Z" }, - { url = "https://files.pythonhosted.org/packages/3d/6f/feba03130d5fceadfa3a1bb102cb14650798c848b1df2a808356f939bb16/brotli-1.2.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:acec55bb7c90f1dfc476126f9711a8e81c9af7fb617409a9ee2953115343f08d", size = 1528071, upload-time = "2025-11-05T18:38:26.081Z" }, - { url = "https://files.pythonhosted.org/packages/2b/38/f3abb554eee089bd15471057ba85f47e53a44a462cfce265d9bf7088eb09/brotli-1.2.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:260d3692396e1895c5034f204f0db022c056f9e2ac841593a4cf9426e2a3faca", size = 1626913, upload-time = "2025-11-05T18:38:27.284Z" }, - { url = "https://files.pythonhosted.org/packages/03/a7/03aa61fbc3c5cbf99b44d158665f9b0dd3d8059be16c460208d9e385c837/brotli-1.2.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:072e7624b1fc4d601036ab3f4f27942ef772887e876beff0301d261210bca97f", size = 1419762, upload-time = "2025-11-05T18:38:28.295Z" }, - { url = "https://files.pythonhosted.org/packages/21/1b/0374a89ee27d152a5069c356c96b93afd1b94eae83f1e004b57eb6ce2f10/brotli-1.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:adedc4a67e15327dfdd04884873c6d5a01d3e3b6f61406f99b1ed4865a2f6d28", size = 1484494, upload-time = "2025-11-05T18:38:29.29Z" }, - { url = "https://files.pythonhosted.org/packages/cf/57/69d4fe84a67aef4f524dcd075c6eee868d7850e85bf01d778a857d8dbe0a/brotli-1.2.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7a47ce5c2288702e09dc22a44d0ee6152f2c7eda97b3c8482d826a1f3cfc7da7", size = 1593302, upload-time = "2025-11-05T18:38:30.639Z" }, - { url = "https://files.pythonhosted.org/packages/d5/3b/39e13ce78a8e9a621c5df3aeb5fd181fcc8caba8c48a194cd629771f6828/brotli-1.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:af43b8711a8264bb4e7d6d9a6d004c3a2019c04c01127a868709ec29962b6036", size = 1487913, upload-time = "2025-11-05T18:38:31.618Z" }, - { url = "https://files.pythonhosted.org/packages/62/28/4d00cb9bd76a6357a66fcd54b4b6d70288385584063f4b07884c1e7286ac/brotli-1.2.0-cp312-cp312-win32.whl", hash = "sha256:e99befa0b48f3cd293dafeacdd0d191804d105d279e0b387a32054c1180f3161", size = 334362, upload-time = "2025-11-05T18:38:32.939Z" }, - { url = "https://files.pythonhosted.org/packages/1c/4e/bc1dcac9498859d5e353c9b153627a3752868a9d5f05ce8dedd81a2354ab/brotli-1.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:b35c13ce241abdd44cb8ca70683f20c0c079728a36a996297adb5334adfc1c44", size = 369115, upload-time = "2025-11-05T18:38:33.765Z" }, - { url = "https://files.pythonhosted.org/packages/6c/d4/4ad5432ac98c73096159d9ce7ffeb82d151c2ac84adcc6168e476bb54674/brotli-1.2.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9e5825ba2c9998375530504578fd4d5d1059d09621a02065d1b6bfc41a8e05ab", size = 861523, upload-time = "2025-11-05T18:38:34.67Z" }, - { url = "https://files.pythonhosted.org/packages/91/9f/9cc5bd03ee68a85dc4bc89114f7067c056a3c14b3d95f171918c088bf88d/brotli-1.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0cf8c3b8ba93d496b2fae778039e2f5ecc7cff99df84df337ca31d8f2252896c", size = 444289, upload-time = "2025-11-05T18:38:35.6Z" }, - { url = "https://files.pythonhosted.org/packages/2e/b6/fe84227c56a865d16a6614e2c4722864b380cb14b13f3e6bef441e73a85a/brotli-1.2.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c8565e3cdc1808b1a34714b553b262c5de5fbda202285782173ec137fd13709f", size = 1528076, upload-time = "2025-11-05T18:38:36.639Z" }, - { url = "https://files.pythonhosted.org/packages/55/de/de4ae0aaca06c790371cf6e7ee93a024f6b4bb0568727da8c3de112e726c/brotli-1.2.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:26e8d3ecb0ee458a9804f47f21b74845cc823fd1bb19f02272be70774f56e2a6", size = 1626880, upload-time = "2025-11-05T18:38:37.623Z" }, - { url = "https://files.pythonhosted.org/packages/5f/16/a1b22cbea436642e071adcaf8d4b350a2ad02f5e0ad0da879a1be16188a0/brotli-1.2.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:67a91c5187e1eec76a61625c77a6c8c785650f5b576ca732bd33ef58b0dff49c", size = 1419737, upload-time = "2025-11-05T18:38:38.729Z" }, - { url = "https://files.pythonhosted.org/packages/46/63/c968a97cbb3bdbf7f974ef5a6ab467a2879b82afbc5ffb65b8acbb744f95/brotli-1.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4ecdb3b6dc36e6d6e14d3a1bdc6c1057c8cbf80db04031d566eb6080ce283a48", size = 1484440, upload-time = "2025-11-05T18:38:39.916Z" }, - { url = "https://files.pythonhosted.org/packages/06/9d/102c67ea5c9fc171f423e8399e585dabea29b5bc79b05572891e70013cdd/brotli-1.2.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3e1b35d56856f3ed326b140d3c6d9db91740f22e14b06e840fe4bb1923439a18", size = 1593313, upload-time = "2025-11-05T18:38:41.24Z" }, - { url = "https://files.pythonhosted.org/packages/9e/4a/9526d14fa6b87bc827ba1755a8440e214ff90de03095cacd78a64abe2b7d/brotli-1.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:54a50a9dad16b32136b2241ddea9e4df159b41247b2ce6aac0b3276a66a8f1e5", size = 1487945, upload-time = "2025-11-05T18:38:42.277Z" }, - { url = "https://files.pythonhosted.org/packages/5b/e8/3fe1ffed70cbef83c5236166acaed7bb9c766509b157854c80e2f766b38c/brotli-1.2.0-cp313-cp313-win32.whl", hash = "sha256:1b1d6a4efedd53671c793be6dd760fcf2107da3a52331ad9ea429edf0902f27a", size = 334368, upload-time = "2025-11-05T18:38:43.345Z" }, - { url = "https://files.pythonhosted.org/packages/ff/91/e739587be970a113b37b821eae8097aac5a48e5f0eca438c22e4c7dd8648/brotli-1.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:b63daa43d82f0cdabf98dee215b375b4058cce72871fd07934f179885aad16e8", size = 369116, upload-time = "2025-11-05T18:38:44.609Z" }, - { url = "https://files.pythonhosted.org/packages/17/e1/298c2ddf786bb7347a1cd71d63a347a79e5712a7c0cba9e3c3458ebd976f/brotli-1.2.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:6c12dad5cd04530323e723787ff762bac749a7b256a5bece32b2243dd5c27b21", size = 863080, upload-time = "2025-11-05T18:38:45.503Z" }, - { url = "https://files.pythonhosted.org/packages/84/0c/aac98e286ba66868b2b3b50338ffbd85a35c7122e9531a73a37a29763d38/brotli-1.2.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:3219bd9e69868e57183316ee19c84e03e8f8b5a1d1f2667e1aa8c2f91cb061ac", size = 445453, upload-time = "2025-11-05T18:38:46.433Z" }, - { url = "https://files.pythonhosted.org/packages/ec/f1/0ca1f3f99ae300372635ab3fe2f7a79fa335fee3d874fa7f9e68575e0e62/brotli-1.2.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:963a08f3bebd8b75ac57661045402da15991468a621f014be54e50f53a58d19e", size = 1528168, upload-time = "2025-11-05T18:38:47.371Z" }, - { url = "https://files.pythonhosted.org/packages/d6/a6/2ebfc8f766d46df8d3e65b880a2e220732395e6d7dc312c1e1244b0f074a/brotli-1.2.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9322b9f8656782414b37e6af884146869d46ab85158201d82bab9abbcb971dc7", size = 1627098, upload-time = "2025-11-05T18:38:48.385Z" }, - { url = "https://files.pythonhosted.org/packages/f3/2f/0976d5b097ff8a22163b10617f76b2557f15f0f39d6a0fe1f02b1a53e92b/brotli-1.2.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cf9cba6f5b78a2071ec6fb1e7bd39acf35071d90a81231d67e92d637776a6a63", size = 1419861, upload-time = "2025-11-05T18:38:49.372Z" }, - { url = "https://files.pythonhosted.org/packages/9c/97/d76df7176a2ce7616ff94c1fb72d307c9a30d2189fe877f3dd99af00ea5a/brotli-1.2.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7547369c4392b47d30a3467fe8c3330b4f2e0f7730e45e3103d7d636678a808b", size = 1484594, upload-time = "2025-11-05T18:38:50.655Z" }, - { url = "https://files.pythonhosted.org/packages/d3/93/14cf0b1216f43df5609f5b272050b0abd219e0b54ea80b47cef9867b45e7/brotli-1.2.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:fc1530af5c3c275b8524f2e24841cbe2599d74462455e9bae5109e9ff42e9361", size = 1593455, upload-time = "2025-11-05T18:38:51.624Z" }, - { url = "https://files.pythonhosted.org/packages/b3/73/3183c9e41ca755713bdf2cc1d0810df742c09484e2e1ddd693bee53877c1/brotli-1.2.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d2d085ded05278d1c7f65560aae97b3160aeb2ea2c0b3e26204856beccb60888", size = 1488164, upload-time = "2025-11-05T18:38:53.079Z" }, - { url = "https://files.pythonhosted.org/packages/64/6a/0c78d8f3a582859236482fd9fa86a65a60328a00983006bcf6d83b7b2253/brotli-1.2.0-cp314-cp314-win32.whl", hash = "sha256:832c115a020e463c2f67664560449a7bea26b0c1fdd690352addad6d0a08714d", size = 339280, upload-time = "2025-11-05T18:38:54.02Z" }, - { url = "https://files.pythonhosted.org/packages/f5/10/56978295c14794b2c12007b07f3e41ba26acda9257457d7085b0bb3bb90c/brotli-1.2.0-cp314-cp314-win_amd64.whl", hash = "sha256:e7c0af964e0b4e3412a0ebf341ea26ec767fa0b4cf81abb5e897c9338b5ad6a3", size = 375639, upload-time = "2025-11-05T18:38:55.67Z" }, -] - -[[package]] -name = "brotlicffi" -version = "1.2.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cffi" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/84/85/57c314a6b35336efbbdc13e5fc9ae13f6b60a0647cfa7c1221178ac6d8ae/brotlicffi-1.2.0.0.tar.gz", hash = "sha256:34345d8d1f9d534fcac2249e57a4c3c8801a33c9942ff9f8574f67a175e17adb", size = 476682, upload-time = "2025-11-21T18:17:57.334Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e4/df/a72b284d8c7bef0ed5756b41c2eb7d0219a1dd6ac6762f1c7bdbc31ef3af/brotlicffi-1.2.0.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:9458d08a7ccde8e3c0afedbf2c70a8263227a68dea5ab13590593f4c0a4fd5f4", size = 432340, upload-time = "2025-11-21T18:17:42.277Z" }, - { url = "https://files.pythonhosted.org/packages/74/2b/cc55a2d1d6fb4f5d458fba44a3d3f91fb4320aa14145799fd3a996af0686/brotlicffi-1.2.0.0-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:84e3d0020cf1bd8b8131f4a07819edee9f283721566fe044a20ec792ca8fd8b7", size = 1534002, upload-time = "2025-11-21T18:17:43.746Z" }, - { url = "https://files.pythonhosted.org/packages/e4/9c/d51486bf366fc7d6735f0e46b5b96ca58dc005b250263525a1eea3cd5d21/brotlicffi-1.2.0.0-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:33cfb408d0cff64cd50bef268c0fed397c46fbb53944aa37264148614a62e990", size = 1536547, upload-time = "2025-11-21T18:17:45.729Z" }, - { url = "https://files.pythonhosted.org/packages/1b/37/293a9a0a7caf17e6e657668bebb92dfe730305999fe8c0e2703b8888789c/brotlicffi-1.2.0.0-cp38-abi3-win32.whl", hash = "sha256:23e5c912fdc6fd37143203820230374d24babd078fc054e18070a647118158f6", size = 343085, upload-time = "2025-11-21T18:17:48.887Z" }, - { url = "https://files.pythonhosted.org/packages/07/6b/6e92009df3b8b7272f85a0992b306b61c34b7ea1c4776643746e61c380ac/brotlicffi-1.2.0.0-cp38-abi3-win_amd64.whl", hash = "sha256:f139a7cdfe4ae7859513067b736eb44d19fae1186f9e99370092f6915216451b", size = 378586, upload-time = "2025-11-21T18:17:50.531Z" }, - { url = "https://files.pythonhosted.org/packages/a4/ec/52488a0563f1663e2ccc75834b470650f4b8bcdea3132aef3bf67219c661/brotlicffi-1.2.0.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:fa102a60e50ddbd08de86a63431a722ea216d9bc903b000bf544149cc9b823dc", size = 402002, upload-time = "2025-11-21T18:17:51.76Z" }, - { url = "https://files.pythonhosted.org/packages/e4/63/d4aea4835fd97da1401d798d9b8ba77227974de565faea402f520b37b10f/brotlicffi-1.2.0.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7d3c4332fc808a94e8c1035950a10d04b681b03ab585ce897ae2a360d479037c", size = 406447, upload-time = "2025-11-21T18:17:53.614Z" }, - { url = "https://files.pythonhosted.org/packages/62/4e/5554ecb2615ff035ef8678d4e419549a0f7a28b3f096b272174d656749fb/brotlicffi-1.2.0.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fb4eb5830026b79a93bf503ad32b2c5257315e9ffc49e76b2715cffd07c8e3db", size = 402521, upload-time = "2025-11-21T18:17:54.875Z" }, - { url = "https://files.pythonhosted.org/packages/b5/d3/b07f8f125ac52bbee5dc00ef0d526f820f67321bf4184f915f17f50a4657/brotlicffi-1.2.0.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:3832c66e00d6d82087f20a972b2fc03e21cd99ef22705225a6f8f418a9158ecc", size = 374730, upload-time = "2025-11-21T18:17:56.334Z" }, -] - [[package]] name = "cachetools" -version = "7.0.1" +version = "7.0.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d4/07/56595285564e90777d758ebd383d6b0b971b87729bbe2184a849932a3736/cachetools-7.0.1.tar.gz", hash = "sha256:e31e579d2c5b6e2944177a0397150d312888ddf4e16e12f1016068f0c03b8341", size = 36126, upload-time = "2026-02-10T22:24:05.03Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6c/c7/342b33cc6877eebc6c9bb45cb9f78e170e575839699f6f3cc96050176431/cachetools-7.0.2.tar.gz", hash = "sha256:7e7f09a4ca8b791d8bb4864afc71e9c17e607a28e6839ca1a644253c97dbeae0", size = 36983, upload-time = "2026-03-02T19:45:16.926Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ed/9e/5faefbf9db1db466d633735faceda1f94aa99ce506ac450d232536266b32/cachetools-7.0.1-py3-none-any.whl", hash = "sha256:8f086515c254d5664ae2146d14fc7f65c9a4bce75152eb247e5a9c5e6d7b2ecf", size = 13484, upload-time = "2026-02-10T22:24:03.741Z" }, + { url = "https://files.pythonhosted.org/packages/ef/04/4b6968e77c110f12da96fdbfcb39c6557c2e5e81bd7afcf8ed893d5bc588/cachetools-7.0.2-py3-none-any.whl", hash = "sha256:938dcad184827c5e94928c4fd5526e2b46692b7fb1ae94472da9131d0299343c", size = 13793, upload-time = "2026-03-02T19:45:15.495Z" }, ] [[package]] @@ -659,18 +591,16 @@ wheels = [ [[package]] name = "ddgs" -version = "9.10.0" +version = "9.11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, - { name = "fake-useragent" }, - { name = "httpx", extra = ["brotli", "http2", "socks"] }, { name = "lxml" }, { name = "primp" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/07/76/8dc0323d1577037abad7a679f8af150ebb73a94995d3012de71a8898e6e6/ddgs-9.10.0.tar.gz", hash = "sha256:d9381ff75bdf1ad6691d3d1dc2be12be190d1d32ecd24f1002c492143c52c34f", size = 31491, upload-time = "2025-12-17T23:30:15.021Z" } +sdist = { url = "https://files.pythonhosted.org/packages/fa/06/b148a33eb074ef0cde6f82a83dc2af2ec60d2a63f3e39b049dd8abdfaf39/ddgs-9.11.1.tar.gz", hash = "sha256:f01aec85e59ffe73dbab4517628d24702fb6ce2c345d2f5e6dd4b120526b56c7", size = 34442, upload-time = "2026-03-02T06:45:23.341Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b5/0e/d4b7d6a8df5074cf67bc14adead39955b0bf847c947ff6cad0bb527887f4/ddgs-9.10.0-py3-none-any.whl", hash = "sha256:81233d79309836eb03e7df2a0d2697adc83c47c342713132c0ba618f1f2c6eee", size = 40311, upload-time = "2025-12-17T23:30:13.606Z" }, + { url = "https://files.pythonhosted.org/packages/92/6b/446ce962d40f243c90f704aceadaa1f577e35db11677323e35b7c4b55867/ddgs-9.11.1-py3-none-any.whl", hash = "sha256:404382a17c6055f28aa752809bd100ca23167611bb77368aa4c7012e254a16b8", size = 43304, upload-time = "2026-03-02T06:45:22.283Z" }, ] [[package]] @@ -694,18 +624,9 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277, upload-time = "2023-12-24T09:54:30.421Z" }, ] -[[package]] -name = "fake-useragent" -version = "2.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/41/43/948d10bf42735709edb5ae51e23297d034086f17fc7279fef385a7acb473/fake_useragent-2.2.0.tar.gz", hash = "sha256:4e6ab6571e40cc086d788523cf9e018f618d07f9050f822ff409a4dfe17c16b2", size = 158898, upload-time = "2025-04-14T15:32:19.238Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/51/37/b3ea9cd5558ff4cb51957caca2193981c6b0ff30bd0d2630ac62505d99d0/fake_useragent-2.2.0-py3-none-any.whl", hash = "sha256:67f35ca4d847b0d298187443aaf020413746e56acd985a611908c73dba2daa24", size = 161695, upload-time = "2025-04-14T15:32:17.732Z" }, -] - [[package]] name = "fastapi" -version = "0.133.1" +version = "0.135.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "annotated-doc" }, @@ -714,9 +635,9 @@ dependencies = [ { name = "typing-extensions" }, { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/22/6f/0eafed8349eea1fa462238b54a624c8b408cd1ba2795c8e64aa6c34f8ab7/fastapi-0.133.1.tar.gz", hash = "sha256:ed152a45912f102592976fde6cbce7dae1a8a1053da94202e51dd35d184fadd6", size = 378741, upload-time = "2026-02-25T18:18:17.398Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/7b/f8e0211e9380f7195ba3f3d40c292594fd81ba8ec4629e3854c353aaca45/fastapi-0.135.1.tar.gz", hash = "sha256:d04115b508d936d254cea545b7312ecaa58a7b3a0f84952535b4c9afae7668cd", size = 394962, upload-time = "2026-03-01T18:18:29.369Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/c9/a175a7779f3599dfa4adfc97a6ce0e157237b3d7941538604aadaf97bfb6/fastapi-0.133.1-py3-none-any.whl", hash = "sha256:658f34ba334605b1617a65adf2ea6461901bdb9af3a3080d63ff791ecf7dc2e2", size = 109029, upload-time = "2026-02-25T18:18:18.578Z" }, + { url = "https://files.pythonhosted.org/packages/e4/72/42e900510195b23a56bde950d26a51f8b723846bfcaa0286e90287f0422b/fastapi-0.135.1-py3-none-any.whl", hash = "sha256:46e2fc5745924b7c840f71ddd277382af29ce1cdb7d5eab5bf697e3fb9999c9e", size = 116999, upload-time = "2026-03-01T18:18:30.831Z" }, ] [[package]] @@ -773,11 +694,11 @@ wheels = [ [[package]] name = "filelock" -version = "3.24.3" +version = "3.25.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/73/92/a8e2479937ff39185d20dd6a851c1a63e55849e447a55e798cc2e1f49c65/filelock-3.24.3.tar.gz", hash = "sha256:011a5644dc937c22699943ebbfc46e969cdde3e171470a6e40b9533e5a72affa", size = 37935, upload-time = "2026-02-19T00:48:20.543Z" } +sdist = { url = "https://files.pythonhosted.org/packages/77/18/a1fd2231c679dcb9726204645721b12498aeac28e1ad0601038f94b42556/filelock-3.25.0.tar.gz", hash = "sha256:8f00faf3abf9dc730a1ffe9c354ae5c04e079ab7d3a683b7c32da5dd05f26af3", size = 40158, upload-time = "2026-03-01T15:08:45.916Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9c/0f/5d0c71a1aefeb08efff26272149e07ab922b64f46c63363756224bd6872e/filelock-3.24.3-py3-none-any.whl", hash = "sha256:426e9a4660391f7f8a810d71b0555bce9008b0a1cc342ab1f6947d37639e002d", size = 24331, upload-time = "2026-02-19T00:48:18.465Z" }, + { url = "https://files.pythonhosted.org/packages/f9/0b/de6f54d4a8bedfe8645c41497f3c18d749f0bd3218170c667bf4b81d0cdd/filelock-3.25.0-py3-none-any.whl", hash = "sha256:5ccf8069f7948f494968fc0713c10e5c182a9c9d9eef3a636307a20c2490f047", size = 26427, upload-time = "2026-03-01T15:08:44.593Z" }, ] [[package]] @@ -945,58 +866,36 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, ] -[[package]] -name = "h2" -version = "4.3.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "hpack" }, - { name = "hyperframe" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/1d/17/afa56379f94ad0fe8defd37d6eb3f89a25404ffc71d4d848893d270325fc/h2-4.3.0.tar.gz", hash = "sha256:6c59efe4323fa18b47a632221a1888bd7fde6249819beda254aeca909f221bf1", size = 2152026, upload-time = "2025-08-23T18:12:19.778Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/69/b2/119f6e6dcbd96f9069ce9a2665e0146588dc9f88f29549711853645e736a/h2-4.3.0-py3-none-any.whl", hash = "sha256:c438f029a25f7945c69e0ccf0fb951dc3f73a5f6412981daee861431b70e2bdd", size = 61779, upload-time = "2025-08-23T18:12:17.779Z" }, -] - [[package]] name = "hf-xet" -version = "1.3.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a6/d0/73454ef7ca885598a3194d07d5c517d91a840753c5b35d272600d7907f64/hf_xet-1.3.1.tar.gz", hash = "sha256:513aa75f8dc39a63cc44dbc8d635ccf6b449e07cdbd8b2e2d006320d2e4be9bb", size = 641393, upload-time = "2026-02-25T00:57:56.701Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/56/79/9b6a5614230d7a871442d8d8e1c270496821638ba3a9baac16a5b9166200/hf_xet-1.3.1-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:08b231260c68172c866f7aa7257c165d0c87887491aafc5efeee782731725366", size = 3759716, upload-time = "2026-02-25T00:57:41.052Z" }, - { url = "https://files.pythonhosted.org/packages/d4/de/72acb8d7702b3cf9b36a68e8380f3114bf04f9f21cf9e25317457fe31f00/hf_xet-1.3.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:0810b69c64e96dee849036193848007f665dca2311879c9ea8693f4fc37f1795", size = 3518075, upload-time = "2026-02-25T00:57:39.605Z" }, - { url = "https://files.pythonhosted.org/packages/1d/5c/ed728d8530fec28da88ee882b522fccf00dc98e9d7bae4cdb0493070cb17/hf_xet-1.3.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ecd38f98e7f0f41108e30fd4a9a5553ec30cf726df7473dd3e75a1b6d56728c2", size = 4174369, upload-time = "2026-02-25T00:57:32.697Z" }, - { url = "https://files.pythonhosted.org/packages/3c/db/785a0e20aa3086948a26573f1d4ff5c090e63564bf0a52d32eb5b4d82e8d/hf_xet-1.3.1-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:65411867d46700765018b1990eb1604c3bf0bf576d9e65fc57fdcc10797a2eb9", size = 3953249, upload-time = "2026-02-25T00:57:30.096Z" }, - { url = "https://files.pythonhosted.org/packages/c4/6a/51b669c1e3dbd9374b61356f554e8726b9e1c1d6a7bee5d727d3913b10ad/hf_xet-1.3.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:1684c840c60da12d76c2a031ba40e4b154fdbf9593836fcf5ff090d95a033c61", size = 4152989, upload-time = "2026-02-25T00:57:48.308Z" }, - { url = "https://files.pythonhosted.org/packages/df/31/de07e26e396f46d13a09251df69df9444190e93e06a9d30d639e96c8a0ed/hf_xet-1.3.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:b3012c0f2ce1f0863338491a2bc0fd3f84aded0e147ab25f230da1f5249547fd", size = 4390709, upload-time = "2026-02-25T00:57:49.845Z" }, - { url = "https://files.pythonhosted.org/packages/e3/c1/fcb010b54488c2c112224f55b71f80e44d1706d9b764a0966310b283f86e/hf_xet-1.3.1-cp313-cp313t-win_amd64.whl", hash = "sha256:4eb432e1aa707a65a7e1f8455e40c5b47431d44fe0fb1b0c5d53848c27469398", size = 3634142, upload-time = "2026-02-25T00:57:59.063Z" }, - { url = "https://files.pythonhosted.org/packages/da/a6/9ef49cc601c68209979661b3e0b6659fc5a47bfb40f3ebf29eae9ee09e5c/hf_xet-1.3.1-cp313-cp313t-win_arm64.whl", hash = "sha256:e56104c84b2a88b9c7b23ba11a2d7ed0ccbe96886b3f985a50cedd2f0e99853f", size = 3494918, upload-time = "2026-02-25T00:57:57.654Z" }, - { url = "https://files.pythonhosted.org/packages/e7/f5/66adbb1f54a1b3c6da002fa36d4405901ddbcb7d927d780db17ce18ab99d/hf_xet-1.3.1-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:6517a245e41df3eae5adc5f9e8c86fa52abd548de798cbcd989f0082152860aa", size = 3759781, upload-time = "2026-02-25T00:57:47.017Z" }, - { url = "https://files.pythonhosted.org/packages/1e/75/189d91a90480c142cc710c1baa35ece20e8652d5fe5c9b2364a13573d827/hf_xet-1.3.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:4a322d506c513f98fdc1aa2aaa825daefd535b686e80ca789e6d33fcb146f524", size = 3517533, upload-time = "2026-02-25T00:57:45.812Z" }, - { url = "https://files.pythonhosted.org/packages/c6/52/52dd1ab6c29661e29585f3c10d14572e2535a3a472f27a0a46215b0f4659/hf_xet-1.3.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8f16ec9d26badec46334a798e01b5d86af536924789c95b1a1ec6a05f26523e0", size = 4174082, upload-time = "2026-02-25T00:57:38.171Z" }, - { url = "https://files.pythonhosted.org/packages/14/03/460add181c79e2ea1527d2ad27788ecccaee1d5a82563f9402e25ee627e4/hf_xet-1.3.1-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:e1f5d72bd5b73e61530fff573bcff34bdb64af2bf4862cdd516e6c1dab4dc75b", size = 3952874, upload-time = "2026-02-25T00:57:36.942Z" }, - { url = "https://files.pythonhosted.org/packages/01/56/bf78f18890dfc8caa907830e95424dce0887d5c45efde13f23c9ebbaa8ef/hf_xet-1.3.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:4bc71afd853508b2ddf123b8fc9de71b0afa4c956ec730b69fb76103781e94cd", size = 4152325, upload-time = "2026-02-25T00:57:54.081Z" }, - { url = "https://files.pythonhosted.org/packages/3c/94/91685c6a4a7f513097a6a73b1e879024304cd0eae78080e3d737622f2fd9/hf_xet-1.3.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:541b4b00ed294ae6cfd9416de9506e58971013714d7316189c9638ed54e362d4", size = 4390499, upload-time = "2026-02-25T00:57:55.258Z" }, - { url = "https://files.pythonhosted.org/packages/79/1b/1e72c8ea1f31ef94640d1f265630d35b97b2ef31fe12696bbcc32dbcdc95/hf_xet-1.3.1-cp314-cp314t-win_amd64.whl", hash = "sha256:f85480b4fe3e8e4cdbc59ef1d235152b732fd57ca439cc983c291892945ae818", size = 3634352, upload-time = "2026-02-25T00:58:04.749Z" }, - { url = "https://files.pythonhosted.org/packages/cf/61/b59e87a7a10b95c4578a6ce555339b2f002035569dfd366662b9f59975a8/hf_xet-1.3.1-cp314-cp314t-win_arm64.whl", hash = "sha256:83a8830160392ef4bea78d443ea2cf1febe65783b3843a8f12c64b368981e7e2", size = 3494371, upload-time = "2026-02-25T00:58:03.422Z" }, - { url = "https://files.pythonhosted.org/packages/75/f8/c2da4352c0335df6ae41750cf5bab09fdbfc30d3b4deeed9d621811aa835/hf_xet-1.3.1-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:581d1809a016f7881069d86a072168a8199a46c839cf394ff53970a47e4f1ca1", size = 3761755, upload-time = "2026-02-25T00:57:43.621Z" }, - { url = "https://files.pythonhosted.org/packages/c0/e5/a2f3eaae09da57deceb16a96ebe9ae1f6f7b9b94145a9cd3c3f994e7782a/hf_xet-1.3.1-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:329c80c86f2dda776bafd2e4813a46a3ee648dce3ac0c84625902c70d7a6ddba", size = 3523677, upload-time = "2026-02-25T00:57:42.3Z" }, - { url = "https://files.pythonhosted.org/packages/61/cd/acbbf9e51f17d8cef2630e61741228e12d4050716619353efc1ac119f902/hf_xet-1.3.1-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2973c3ff594c3a8da890836308cae1444c8af113c6f10fe6824575ddbc37eca7", size = 4178557, upload-time = "2026-02-25T00:57:35.399Z" }, - { url = "https://files.pythonhosted.org/packages/df/4f/014c14c4ae3461d9919008d0bed2f6f35ba1741e28b31e095746e8dac66f/hf_xet-1.3.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ed4bfd2e6d10cb86c9b0f3483df1d7dd2d0220f75f27166925253bacbc1c2dbe", size = 3958975, upload-time = "2026-02-25T00:57:34.004Z" }, - { url = "https://files.pythonhosted.org/packages/86/50/043f5c5a26f3831c3fa2509c17fcd468fd02f1f24d363adc7745fbe661cb/hf_xet-1.3.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:713913387cc76e300116030705d843a9f15aee86158337eeffb9eb8d26f47fcd", size = 4158298, upload-time = "2026-02-25T00:57:51.14Z" }, - { url = "https://files.pythonhosted.org/packages/08/9c/b667098a636a88358dbeb2caf90e3cb9e4b961f61f6c55bb312793424def/hf_xet-1.3.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:e5063789c9d21f51e9ed4edbee8539655d3486e9cad37e96b7af967da20e8b16", size = 4395743, upload-time = "2026-02-25T00:57:52.783Z" }, - { url = "https://files.pythonhosted.org/packages/70/37/4db0e4e1534270800cfffd5a7e0b338f2137f8ceb5768000147650d34ea9/hf_xet-1.3.1-cp37-abi3-win_amd64.whl", hash = "sha256:607d5bbc2730274516714e2e442a26e40e3330673ac0d0173004461409147dee", size = 3638145, upload-time = "2026-02-25T00:58:02.167Z" }, - { url = "https://files.pythonhosted.org/packages/4e/46/1ba8d36f8290a4b98f78898bdce2b0e8fe6d9a59df34a1399eb61a8d877f/hf_xet-1.3.1-cp37-abi3-win_arm64.whl", hash = "sha256:851b1be6597a87036fe7258ce7578d5df3c08176283b989c3b165f94125c5097", size = 3500490, upload-time = "2026-02-25T00:58:00.667Z" }, -] - -[[package]] -name = "hpack" -version = "4.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2c/48/71de9ed269fdae9c8057e5a4c0aa7402e8bb16f2c6e90b3aa53327b113f8/hpack-4.1.0.tar.gz", hash = "sha256:ec5eca154f7056aa06f196a557655c5b009b382873ac8d1e66e79e87535f1dca", size = 51276, upload-time = "2025-01-22T21:44:58.347Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/07/c6/80c95b1b2b94682a72cbdbfb85b81ae2daffa4291fbfa1b1464502ede10d/hpack-4.1.0-py3-none-any.whl", hash = "sha256:157ac792668d995c657d93111f46b4535ed114f0c9c8d672271bbec7eae1b496", size = 34357, upload-time = "2025-01-22T21:44:56.92Z" }, +version = "1.3.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8b/cb/9bb543bd987ffa1ee48202cc96a756951b734b79a542335c566148ade36c/hf_xet-1.3.2.tar.gz", hash = "sha256:e130ee08984783d12717444e538587fa2119385e5bd8fc2bb9f930419b73a7af", size = 643646, upload-time = "2026-02-27T17:26:08.051Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/49/75/462285971954269432aad2e7938c5c7ff9ec7d60129cec542ab37121e3d6/hf_xet-1.3.2-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:335a8f36c55fd35a92d0062f4e9201b4015057e62747b7e7001ffb203c0ee1d2", size = 3761019, upload-time = "2026-02-27T17:25:49.441Z" }, + { url = "https://files.pythonhosted.org/packages/35/56/987b0537ddaf88e17192ea09afa8eca853e55f39a4721578be436f8409df/hf_xet-1.3.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c1ae4d3a716afc774e66922f3cac8206bfa707db13f6a7e62dfff74bfc95c9a8", size = 3521565, upload-time = "2026-02-27T17:25:47.469Z" }, + { url = "https://files.pythonhosted.org/packages/a8/5c/7e4a33a3d689f77761156cc34558047569e54af92e4d15a8f493229f6767/hf_xet-1.3.2-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d6dbdf231efac0b9b39adcf12a07f0c030498f9212a18e8c50224d0e84ab803d", size = 4176494, upload-time = "2026-02-27T17:25:40.247Z" }, + { url = "https://files.pythonhosted.org/packages/6b/b3/71e856bf9d9a69b3931837e8bf22e095775f268c8edcd4a9e8c355f92484/hf_xet-1.3.2-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:c1980abfb68ecf6c1c7983379ed7b1e2b49a1aaf1a5aca9acc7d48e5e2e0a961", size = 3955601, upload-time = "2026-02-27T17:25:38.376Z" }, + { url = "https://files.pythonhosted.org/packages/63/d7/aecf97b3f0a981600a67ff4db15e2d433389d698a284bb0ea5d8fcdd6f7f/hf_xet-1.3.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:1c88fbd90ad0d27c46b77a445f0a436ebaa94e14965c581123b68b1c52f5fd30", size = 4154770, upload-time = "2026-02-27T17:25:56.756Z" }, + { url = "https://files.pythonhosted.org/packages/e2/e1/3af961f71a40e09bf5ee909842127b6b00f5ab4ee3817599dc0771b79893/hf_xet-1.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:35b855024ca37f2dd113ac1c08993e997fbe167b9d61f9ef66d3d4f84015e508", size = 4394161, upload-time = "2026-02-27T17:25:58.111Z" }, + { url = "https://files.pythonhosted.org/packages/a1/c3/859509bade9178e21b8b1db867b8e10e9f817ab9ac1de77cb9f461ced765/hf_xet-1.3.2-cp313-cp313t-win_amd64.whl", hash = "sha256:31612ba0629046e425ba50375685a2586e11fb9144270ebabd75878c3eaf6378", size = 3637377, upload-time = "2026-02-27T17:26:10.611Z" }, + { url = "https://files.pythonhosted.org/packages/05/7f/724cfbef4da92d577b71f68bf832961c8919f36c60d28d289a9fc9d024d4/hf_xet-1.3.2-cp313-cp313t-win_arm64.whl", hash = "sha256:433c77c9f4e132b562f37d66c9b22c05b5479f243a1f06a120c1c06ce8b1502a", size = 3497875, upload-time = "2026-02-27T17:26:09.034Z" }, + { url = "https://files.pythonhosted.org/packages/ba/75/9d54c1ae1d05fb704f977eca1671747babf1957f19f38ae75c5933bc2dc1/hf_xet-1.3.2-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:c34e2c7aefad15792d57067c1c89b2b02c1bbaeabd7f8456ae3d07b4bbaf4094", size = 3761076, upload-time = "2026-02-27T17:25:55.42Z" }, + { url = "https://files.pythonhosted.org/packages/f2/8a/08a24b6c6f52b5d26848c16e4b6d790bb810d1bf62c3505bed179f7032d3/hf_xet-1.3.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:4bc995d6c41992831f762096020dc14a65fdf3963f86ffed580b596d04de32e3", size = 3521745, upload-time = "2026-02-27T17:25:54.217Z" }, + { url = "https://files.pythonhosted.org/packages/b5/db/a75cf400dd8a1a8acf226a12955ff6ee999f272dfc0505bafd8079a61267/hf_xet-1.3.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:959083c89dee30f7d6f890b36cdadda823386c4de63b1a30384a75bfd2ae995d", size = 4176301, upload-time = "2026-02-27T17:25:46.044Z" }, + { url = "https://files.pythonhosted.org/packages/01/40/6c4c798ffdd83e740dd3925c4e47793b07442a9efa3bc3866ba141a82365/hf_xet-1.3.2-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:cfa760888633b08c01b398d212ce7e8c0d7adac6c86e4b20dfb2397d8acd78ee", size = 3955437, upload-time = "2026-02-27T17:25:44.703Z" }, + { url = "https://files.pythonhosted.org/packages/0c/09/9a3aa7c5f07d3e5cc57bb750d12a124ffa72c273a87164bd848f9ac5cc14/hf_xet-1.3.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:3155a02e083aa21fd733a7485c7c36025e49d5975c8d6bda0453d224dd0b0ac4", size = 4154535, upload-time = "2026-02-27T17:26:05.207Z" }, + { url = "https://files.pythonhosted.org/packages/ae/e0/831f7fa6d90cb47a230bc23284b502c700e1483bbe459437b3844cdc0776/hf_xet-1.3.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:91b1dc03c31cbf733d35dc03df7c5353686233d86af045e716f1e0ea4a2673cf", size = 4393891, upload-time = "2026-02-27T17:26:06.607Z" }, + { url = "https://files.pythonhosted.org/packages/ab/96/6ed472fdce7f8b70f5da6e3f05be76816a610063003bfd6d9cea0bbb58a3/hf_xet-1.3.2-cp314-cp314t-win_amd64.whl", hash = "sha256:211f30098512d95e85ad03ae63bd7dd2c4df476558a5095d09f9e38e78cbf674", size = 3637583, upload-time = "2026-02-27T17:26:17.349Z" }, + { url = "https://files.pythonhosted.org/packages/8b/e8/a069edc4570b3f8e123c0b80fadc94530f3d7b01394e1fc1bb223339366c/hf_xet-1.3.2-cp314-cp314t-win_arm64.whl", hash = "sha256:4a6817c41de7c48ed9270da0b02849347e089c5ece9a0e72ae4f4b3a57617f82", size = 3497977, upload-time = "2026-02-27T17:26:14.966Z" }, + { url = "https://files.pythonhosted.org/packages/d8/28/dbb024e2e3907f6f3052847ca7d1a2f7a3972fafcd53ff79018977fcb3e4/hf_xet-1.3.2-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:f93b7595f1d8fefddfede775c18b5c9256757824f7f6832930b49858483cd56f", size = 3763961, upload-time = "2026-02-27T17:25:52.537Z" }, + { url = "https://files.pythonhosted.org/packages/e4/71/b99aed3823c9d1795e4865cf437d651097356a3f38c7d5877e4ac544b8e4/hf_xet-1.3.2-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:a85d3d43743174393afe27835bde0cd146e652b5fcfdbcd624602daef2ef3259", size = 3526171, upload-time = "2026-02-27T17:25:50.968Z" }, + { url = "https://files.pythonhosted.org/packages/9d/ca/907890ce6ef5598b5920514f255ed0a65f558f820515b18db75a51b2f878/hf_xet-1.3.2-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7c2a054a97c44e136b1f7f5a78f12b3efffdf2eed3abc6746fc5ea4b39511633", size = 4180750, upload-time = "2026-02-27T17:25:43.125Z" }, + { url = "https://files.pythonhosted.org/packages/8c/ad/bc7f41f87173d51d0bce497b171c4ee0cbde1eed2d7b4216db5d0ada9f50/hf_xet-1.3.2-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:06b724a361f670ae557836e57801b82c75b534812e351a87a2c739f77d1e0635", size = 3961035, upload-time = "2026-02-27T17:25:41.837Z" }, + { url = "https://files.pythonhosted.org/packages/73/38/600f4dda40c4a33133404d9fe644f1d35ff2d9babb4d0435c646c63dd107/hf_xet-1.3.2-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:305f5489d7241a47e0458ef49334be02411d1d0f480846363c1c8084ed9916f7", size = 4161378, upload-time = "2026-02-27T17:26:00.365Z" }, + { url = "https://files.pythonhosted.org/packages/00/b3/7bc1ff91d1ac18420b7ad1e169b618b27c00001b96310a89f8a9294fe509/hf_xet-1.3.2-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:06cdbde243c85f39a63b28e9034321399c507bcd5e7befdd17ed2ccc06dfe14e", size = 4398020, upload-time = "2026-02-27T17:26:03.977Z" }, + { url = "https://files.pythonhosted.org/packages/2b/0b/99bfd948a3ed3620ab709276df3ad3710dcea61976918cce8706502927af/hf_xet-1.3.2-cp37-abi3-win_amd64.whl", hash = "sha256:9298b47cce6037b7045ae41482e703c471ce36b52e73e49f71226d2e8e5685a1", size = 3641624, upload-time = "2026-02-27T17:26:13.542Z" }, + { url = "https://files.pythonhosted.org/packages/cc/02/9a6e4ca1f3f73a164c0cd48e41b3cc56585dcc37e809250de443d673266f/hf_xet-1.3.2-cp37-abi3-win_arm64.whl", hash = "sha256:83d8ec273136171431833a6957e8f3af496bee227a0fe47c7b8b39c106d1749a", size = 3503976, upload-time = "2026-02-27T17:26:12.123Z" }, ] [[package]] @@ -1027,18 +926,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, ] -[package.optional-dependencies] -brotli = [ - { name = "brotli", marker = "platform_python_implementation == 'CPython'" }, - { name = "brotlicffi", marker = "platform_python_implementation != 'CPython'" }, -] -http2 = [ - { name = "h2" }, -] -socks = [ - { name = "socksio" }, -] - [[package]] name = "httpx-sse" version = "0.4.3" @@ -1068,15 +955,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ec/74/2bc951622e2dbba1af9a460d93c51d15e458becd486e62c29cc0ccb08178/huggingface_hub-1.5.0-py3-none-any.whl", hash = "sha256:c9c0b3ab95a777fc91666111f3b3ede71c0cdced3614c553a64e98920585c4ee", size = 596261, upload-time = "2026-02-26T15:35:31.1Z" }, ] -[[package]] -name = "hyperframe" -version = "6.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/02/e7/94f8232d4a74cc99514c13a9f995811485a6903d48e5d952771ef6322e30/hyperframe-6.1.0.tar.gz", hash = "sha256:f630908a00854a7adeabd6382b43923a4c4cd4b821fcb527e6ab9e15382a3b08", size = 26566, upload-time = "2025-01-22T21:41:49.302Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/48/30/47d0bf6072f7252e6521f3447ccfa40b421b6824517f82854703d0f5a98b/hyperframe-6.1.0-py3-none-any.whl", hash = "sha256:b03380493a519fce58ea5af42e4a42317bf9bd425596f7a0835ffce80f1a42e5", size = 13007, upload-time = "2025-01-22T21:41:47.295Z" }, -] - [[package]] name = "idna" version = "3.11" @@ -1269,7 +1147,7 @@ wheels = [ [[package]] name = "litellm" -version = "1.81.16" +version = "1.82.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohttp" }, @@ -1285,9 +1163,9 @@ dependencies = [ { name = "tiktoken" }, { name = "tokenizers" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d6/36/3cbb22d6ef88c10f3fa4f04664c2a37e93a2e6f9c51899cd9fd025cb0a50/litellm-1.81.16.tar.gz", hash = "sha256:264a3868942e722cd6c19c2d625524fe624a1b6961c37c22d299dc7ea99823b3", size = 16668405, upload-time = "2026-02-26T13:01:48.429Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6c/00/49bb5c28e0dea0f5086229a2a08d5fdc6c8dc0d8e2acb2a2d1f7dd9f4b70/litellm-1.82.0.tar.gz", hash = "sha256:d388f52447daccbcaafa19a3e68d17b75f1374b5bf2cde680d65e1cd86e50d22", size = 16800355, upload-time = "2026-03-01T02:35:30.363Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1f/1e/0022cde913bac87a493e4a182b8768f75e7ae90b64d4e11acb009b18311f/litellm-1.81.16-py3-none-any.whl", hash = "sha256:d6bcc13acbd26719e07bfa6b9923740e88409cbf1f9d626d85fc9ae0e0eec88c", size = 14774277, upload-time = "2026-02-26T13:01:45.652Z" }, + { url = "https://files.pythonhosted.org/packages/28/89/eb28bfcf97d6b045c400e72eb047c381594467048c237dbb6c227764084c/litellm-1.82.0-py3-none-any.whl", hash = "sha256:5496b5d4532cccdc7a095c21cbac4042f7662021c57bc1d17be4e39838929e80", size = 14911978, upload-time = "2026-03-01T02:35:26.844Z" }, ] [[package]] @@ -1859,40 +1737,40 @@ wheels = [ [[package]] name = "primp" -version = "1.1.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/de/25/1113a87a693121f4eb18d2df3a99d8ad43984f4068e31a5765c03e4b8b96/primp-1.1.1.tar.gz", hash = "sha256:58775e74f86cc58f9abe4b1dacea399fa6367c1959e591ad9345f151ad38d259", size = 311388, upload-time = "2026-02-24T16:12:53.452Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/bf/0f/027fc0394f70721c6dc5054fb3efff6479753da0b272e15b16cefba958b8/primp-1.1.1-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:691215c5a514a7395c1ee775cd03a94a41497941e17291e1a71f5356142c61e6", size = 3997489, upload-time = "2026-02-24T16:12:49.154Z" }, - { url = "https://files.pythonhosted.org/packages/af/ea/0f23fbfef2a550c420eaa73fd3e21176acb0ddf0d50028d8bc8d937441be/primp-1.1.1-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:17ace56cd24a894236121bf37d3616ec15d5299a6fa2d2a30fbbf9c22b946a03", size = 3734591, upload-time = "2026-02-24T16:12:45.629Z" }, - { url = "https://files.pythonhosted.org/packages/0a/63/c5669652446a981dd5faad8a8255e5567db5818b951dbe74e81968f672cb/primp-1.1.1-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cfec08ae15f6d86b2bcaaee3358d5cc349a843c8be164502ea73658a817c5cf2", size = 3875508, upload-time = "2026-02-24T16:12:59.403Z" }, - { url = "https://files.pythonhosted.org/packages/14/79/19e4d19a445b39c930a317e4ea4d1eff07ef0661b4e7397ad425f7ff0bd8/primp-1.1.1-cp310-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c3cf7e93e8ff4842eee9c6d4ac47d638a5c981752b19f458877a3536c1da6671", size = 3510461, upload-time = "2026-02-24T16:12:37.908Z" }, - { url = "https://files.pythonhosted.org/packages/50/39/091282d624067958b42a087976c0da80eecc5ade03acfc732389be3af723/primp-1.1.1-cp310-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:db6f3f18855bf25dca14f6d121d214e5c922275f49cdadd248eff28abb779edb", size = 3727644, upload-time = "2026-02-24T16:12:16.671Z" }, - { url = "https://files.pythonhosted.org/packages/33/ae/ca4e4a5d0cbd35684a228fd1f7c1425db0860a7bd74ce8f40835f6184834/primp-1.1.1-cp310-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2d8363faadb1d07fa8ae73de6ed2ca4666b36c77ea3990714164b8ee7ab1aa1d", size = 4004689, upload-time = "2026-02-24T16:12:57.957Z" }, - { url = "https://files.pythonhosted.org/packages/3a/ed/b3cf17bcac4914aa63cd83d763c9e347aab6e0b9285645b0015b036f914d/primp-1.1.1-cp310-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:302241ee447c185417e93e3a3e5a2801fdd710b1a5cc63c01a26ee7dc634e9b1", size = 3918084, upload-time = "2026-02-24T16:12:30.283Z" }, - { url = "https://files.pythonhosted.org/packages/6a/9f/f563eaeb654749fa519c627b1f1ab93cf875537c56123fba507f74b647fc/primp-1.1.1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a37ad318f1b8295d414e1c32ca407efcb92e664c5ff41f06901bd3ee03bab1fa", size = 4108648, upload-time = "2026-02-24T16:12:15.269Z" }, - { url = "https://files.pythonhosted.org/packages/1c/b9/2df5376900c293238cf641591952979f689ea3f009195df4cce15786afb9/primp-1.1.1-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e46829d9d86caf18b2b40829655d470e0ce2eebb061f2ee973451b2509f1c5a2", size = 4055747, upload-time = "2026-02-24T16:12:42.925Z" }, - { url = "https://files.pythonhosted.org/packages/a1/e9/eaaea488b4ae445059bd99559649402c77ddd9dfdda01528daa9ee11d8fe/primp-1.1.1-cp310-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:8ef9cb971915d2db3fbb1a512777261e5267c95d4717b18aff453f5e3dbb9bda", size = 3742046, upload-time = "2026-02-24T16:12:19.945Z" }, - { url = "https://files.pythonhosted.org/packages/0a/92/0607dd9d01840e0c007519d69cdcbb6f1358d6d7f8e739fc3359773b50d2/primp-1.1.1-cp310-abi3-musllinux_1_2_i686.whl", hash = "sha256:1a350656142772b5d6afc0dfaf9172c69449fbfafb9b6590af7ba116d32554d7", size = 3857103, upload-time = "2026-02-24T16:12:39.338Z" }, - { url = "https://files.pythonhosted.org/packages/e5/b6/5d574a7a84afd38df03c5535a9bb1052090bd0289760dcca24188510dd09/primp-1.1.1-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:ec71a66750befd219f29cb6ff01bc1c26671040fc76b4115bf045c85f84da041", size = 4357972, upload-time = "2026-02-24T16:12:12.159Z" }, - { url = "https://files.pythonhosted.org/packages/8b/f3/34ba2deba36de0a6041a61c16f2097e0bd2e74114f8d85096b3911288b4c/primp-1.1.1-cp310-abi3-win32.whl", hash = "sha256:901dc1e40b99ba5925463ab120af14afb8a66f4ac7eb2cdf87aaf21047f6db39", size = 3259840, upload-time = "2026-02-24T16:12:31.762Z" }, - { url = "https://files.pythonhosted.org/packages/a8/c6/fa3c17e5b6e4cff5bbdfd6bed1d0e8f81e17708dd8106906a031a2432b61/primp-1.1.1-cp310-abi3-win_amd64.whl", hash = "sha256:6bedd91451ec9ac46203ccb5c2c9925e9206e33abec7c791a2b39e3f86530bf0", size = 3596643, upload-time = "2026-02-24T16:12:21.554Z" }, - { url = "https://files.pythonhosted.org/packages/94/3d/a5b391107ba1c72dc8eb4f603c5764067449e1445438d71e093a72d5eda1/primp-1.1.1-cp310-abi3-win_arm64.whl", hash = "sha256:fd22a10164536374262e32fccbf81736b20798ac7582f159d5ffdef01a755579", size = 3606836, upload-time = "2026-02-24T16:12:28.579Z" }, - { url = "https://files.pythonhosted.org/packages/5d/77/b7df4f1776ae2e7cb5cf123b977167709c120712c7a4f968dc93b28d05ac/primp-1.1.1-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:e6b0fdeb12cc60b0fa756191118cec8ede8d26f869b83fa501aed722984a964b", size = 3981048, upload-time = "2026-02-24T16:12:24.396Z" }, - { url = "https://files.pythonhosted.org/packages/9a/c8/f198cd6ad9f232a171739a69c534c684237362af8e55f0cc2fc452377aa8/primp-1.1.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:fc473e87adc88f6ce94b7f3edeb2ca6c973f4ceb2d4199d0e707544f71c639c4", size = 3729293, upload-time = "2026-02-24T16:12:18.07Z" }, - { url = "https://files.pythonhosted.org/packages/e7/ce/bd8e564f8233ab0213a296dda2e04b484e0c4b9975702c7ba712e96ead8c/primp-1.1.1-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e85f2aea74b8683611c76958de8827322bd800e1b51aec88130da68d00a20462", size = 3873474, upload-time = "2026-02-24T16:12:40.749Z" }, - { url = "https://files.pythonhosted.org/packages/e7/ab/d3ee13de657cb068e81008eedc2d61103094497d9edc054997b85d85163e/primp-1.1.1-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ca535dfbc5a8290975f4bd8ce38922b26cf4fefc737aa2116bcb1a5795c14309", size = 3509513, upload-time = "2026-02-24T16:12:44.251Z" }, - { url = "https://files.pythonhosted.org/packages/6f/5d/3ed38dd94ae503977329976dbe00831e66d22f0f298c026f8d7493be2b39/primp-1.1.1-cp314-cp314t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d94073e9ecbf97f6d1538d4678df1bb662fd418ad5fd09da4040fe46623e2ec5", size = 3728743, upload-time = "2026-02-24T16:12:33.277Z" }, - { url = "https://files.pythonhosted.org/packages/bc/15/19af65a35b2189d6f2267148ea5b7cbb266aa36891acd641388b7a0f6022/primp-1.1.1-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7e639441bd36e582feec7033e4b8661e0979a61bff65af5f476d33e02ebb3c4d", size = 3999650, upload-time = "2026-02-24T16:12:36.157Z" }, - { url = "https://files.pythonhosted.org/packages/22/cb/aa635a9903a1ee3b0ffe5dd9218a2e2d8880828a1eaba9d0035f967d118a/primp-1.1.1-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd770ca4f73a700da0911d1300a952e4d9a4a3321e205aa5a8644ae81cbd4d7d", size = 3896990, upload-time = "2026-02-24T16:12:13.66Z" }, - { url = "https://files.pythonhosted.org/packages/25/98/916916ec3bd5dab4125bf17b28d1959883a831dc4f9757f915e509c43ec2/primp-1.1.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7dccb605997c918b7abbdd163303d789d63eb03d7cd0440184f34b06a8522fc1", size = 4096157, upload-time = "2026-02-24T16:12:27.163Z" }, - { url = "https://files.pythonhosted.org/packages/ff/57/219c44bf21896a3f2132821ea00bbc9af36b194449ee5083791f690daf7d/primp-1.1.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:1ada94c7f9f047b1c5ba339f62effd44f4c4943d4d8bb96447e9c84ab3bd874d", size = 4052968, upload-time = "2026-02-24T16:12:34.574Z" }, - { url = "https://files.pythonhosted.org/packages/6a/ce/dfdd734c7372faef4a26ecb0267a724e19f78b76a9a92440b8ca824e8f5a/primp-1.1.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:21ac92542f378a21fba8093dbeb7e093851e00da2bdfd9bc6aa63f81cff035d0", size = 3744522, upload-time = "2026-02-24T16:12:25.726Z" }, - { url = "https://files.pythonhosted.org/packages/d6/9c/3eb9e484c17784eac6549c505a68d82b6e5959a0af6efbcf28a773450a81/primp-1.1.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:adaa5d7e8d2ca089cbf41a837a301da605c21ff0ea5fecac8a8b1eead4bc563f", size = 3855298, upload-time = "2026-02-24T16:12:54.518Z" }, - { url = "https://files.pythonhosted.org/packages/1d/ca/80924591ec24f9341982e4d74251f6bfeda44cbb90f6f792403d0737a390/primp-1.1.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b041ab0019e0fb21c24de542e80056775508e5d1d0f0333fb661185bdb359138", size = 4348887, upload-time = "2026-02-24T16:12:47.376Z" }, - { url = "https://files.pythonhosted.org/packages/95/4b/0edc62583af9a03fd1eb34ffd865245c921919f374b0e72b1bb73dc9adf6/primp-1.1.1-cp314-cp314t-win32.whl", hash = "sha256:b7270b9755a931e7667854ad5d9b2aeb88068f0add4fb741529e8c25d953f21b", size = 3252145, upload-time = "2026-02-24T16:12:52.335Z" }, - { url = "https://files.pythonhosted.org/packages/01/b7/9784b93d252e4c2a50f7a46908d91110b7ce9d04e1adb47227fc212576ff/primp-1.1.1-cp314-cp314t-win_amd64.whl", hash = "sha256:19a48f4e91256ec661e022976a75e6a0621522244ac928e8c632d829adb929ce", size = 3591097, upload-time = "2026-02-24T16:12:22.898Z" }, - { url = "https://files.pythonhosted.org/packages/db/d5/3b34601cb2da1cec7aec88f447af9de1e8e3bb3101f26351aa8570b5b7af/primp-1.1.1-cp314-cp314t-win_arm64.whl", hash = "sha256:c97b951afb203b9528f36524e96b1e37ce42f3a7eb0cd77cd053ad5bdfc93d81", size = 3603917, upload-time = "2026-02-24T16:12:55.859Z" }, +version = "1.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/03/35/80be154508529f753fb82cb81298bdeb33e90f39f9901d7cfa0f488a581f/primp-1.1.2.tar.gz", hash = "sha256:c4707ab374a77c0cbead3d9a65605919fa4997fa910ef06e37b65df42a1d4d04", size = 313908, upload-time = "2026-03-01T05:52:49.773Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/13/dc9588356d983f988877ae065c842cdd6cf95073615b56b460cbe857f3dc/primp-1.1.2-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:181bb9a6d5544e0483592f693f33f5874a60726ea0da1f41685aa2267f084a4d", size = 4002669, upload-time = "2026-03-01T05:52:31.977Z" }, + { url = "https://files.pythonhosted.org/packages/70/af/6a6c26141583a5081bad69b9753c85df81b466939663742ef5bec35ee868/primp-1.1.2-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:f362424ffa83e1de55a7573300a416fa71dc5516829526a9bf77dc0cfa42256b", size = 3743010, upload-time = "2026-03-01T05:52:38.452Z" }, + { url = "https://files.pythonhosted.org/packages/a9/99/03db937e031a02885d8c80d073d7424967d629721b5044dcb4e80b6cbdcf/primp-1.1.2-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:736820326eb1ed19c6b0e971f852316c049c36bdd251a03757056a74182796df", size = 3889905, upload-time = "2026-03-01T05:52:20.616Z" }, + { url = "https://files.pythonhosted.org/packages/15/3c/faecef36238f464e2dd52056420676eb2d541cd20ff478d3b967815079e3/primp-1.1.2-cp310-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed37d1bc89fa8cad8b60481c81ea7b3bd42dc757868009ad3bb0b1e74c17fd22", size = 3524521, upload-time = "2026-03-01T05:52:08.403Z" }, + { url = "https://files.pythonhosted.org/packages/7f/d5/8954e5b5b454139ff35063d5a143a1570f865b736cfd8a46cc7ce9575a5a/primp-1.1.2-cp310-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78e78355b1c495bc7e3d92121067760c7e7a1d419519542ed9dd88688ce43aab", size = 3738228, upload-time = "2026-03-01T05:52:05.127Z" }, + { url = "https://files.pythonhosted.org/packages/26/e7/dc93dbeddb7642e12f4575aaf2c9fda7234b241050a112a9baa288971b16/primp-1.1.2-cp310-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c4c560d018dad4e3a3f17b07f9f5d894941e3acbbb5b566f6b6baf42786012f", size = 4013704, upload-time = "2026-03-01T05:52:48.529Z" }, + { url = "https://files.pythonhosted.org/packages/dd/3d/2cc2e0cd310f585df05a7008fd6de4542d7c0bc61e62b6797f28a9ede28b/primp-1.1.2-cp310-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2494b52cf3056d3e41c0746a11cbeca7f2f882a92a09d87383646cd75e2f3d8c", size = 3920174, upload-time = "2026-03-01T05:52:06.635Z" }, + { url = "https://files.pythonhosted.org/packages/35/60/dc4572ba96911374b43b4f5d1f012706c3f27fd2c12dd3e158fcf74ac3dd/primp-1.1.2-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c424a46f48ccd8fd309215a15bc098b47198b8f779c43ed8d95b3f53a382ffa8", size = 4113822, upload-time = "2026-03-01T05:52:51.061Z" }, + { url = "https://files.pythonhosted.org/packages/ec/2e/90f5f8e138f8bc6652c5134aa59a746775623a820f92164c6690217e49d6/primp-1.1.2-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ba51cf19f17fd4bab4567d96b4cd7dcb6a4e0f0d4721819180b46af9794ae310", size = 4068028, upload-time = "2026-03-01T05:52:13.843Z" }, + { url = "https://files.pythonhosted.org/packages/d4/ea/753d8edcb85c3c36d5731fbd2b215528738d917ae9cf3dce651ae0f1c529/primp-1.1.2-cp310-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:77ebae43c6735328051beb08e7e2360b6cf79d50f6cef77629beba880c99222d", size = 3754469, upload-time = "2026-03-01T05:52:15.671Z" }, + { url = "https://files.pythonhosted.org/packages/ae/51/b417cd741bf8eacea86debad358a6dc5821e2849a22e2c91cff926bebbb2/primp-1.1.2-cp310-abi3-musllinux_1_2_i686.whl", hash = "sha256:5f3252d47e9d0f4a567990c79cd388be43353fc7c78efea2a6a5734e8a425598", size = 3859330, upload-time = "2026-03-01T05:52:46.979Z" }, + { url = "https://files.pythonhosted.org/packages/3e/20/19db933c878748e9a7b9ad4057e9caf7ad9c91fd27d2a2692ac629453a66/primp-1.1.2-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:9e094417825df9748e179a1104b2df4459c3dbd1eea994f05a136860b847f0e1", size = 4365491, upload-time = "2026-03-01T05:52:35.007Z" }, + { url = "https://files.pythonhosted.org/packages/fc/0f/48a57ee744cc6dc64fb7daff7bc04e9ec3cefd0594d008a775496dddaeb1/primp-1.1.2-cp310-abi3-win32.whl", hash = "sha256:bc67112b61a8dc1d40ddcc81ff5c47a1cb7b620954fee01a529e28bebb359e20", size = 3266998, upload-time = "2026-03-01T05:52:02.059Z" }, + { url = "https://files.pythonhosted.org/packages/9c/0a/119d497fb098c739142d4a47b062a8a9cc0b4b87aca65334150066d075a0/primp-1.1.2-cp310-abi3-win_amd64.whl", hash = "sha256:4509850301c669c04e124762e953946ed10fe9039f059ec40b818c085697d9a4", size = 3601691, upload-time = "2026-03-01T05:52:12.34Z" }, + { url = "https://files.pythonhosted.org/packages/95/1f/2b8f218aebb4f236d94ae148b4f5c0471b3d00316b0ef5d0b7c2222d8417/primp-1.1.2-cp310-abi3-win_arm64.whl", hash = "sha256:de5958dc7ce78ce107dd776056a58f9da7a7164a912e908cb9b66b84f87967f6", size = 3613756, upload-time = "2026-03-01T05:52:28.279Z" }, + { url = "https://files.pythonhosted.org/packages/40/38/f77c5af1fd53658e04ae52decfab71349af43bdfdb32ddd8a622f6251842/primp-1.1.2-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:c3bbece26e8312e3e0df2ec222b954f9ac9f279422ffbbf47a6cad31ef8736cd", size = 3992311, upload-time = "2026-03-01T05:52:43.497Z" }, + { url = "https://files.pythonhosted.org/packages/77/f6/2e4504cfdeec5d39063173205ca10a281a2681fd9999da37b442ac7e6662/primp-1.1.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:78acdf43b57d984170e986be5fcae0a1537a245fafda970e92056dae42cd9545", size = 3736438, upload-time = "2026-03-01T05:52:22.505Z" }, + { url = "https://files.pythonhosted.org/packages/d3/6c/fe10c51b79cd407d3a1e08a0bb8a35ae53d79ce4156543ea4df7262581ef/primp-1.1.2-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89a2641441732f81e1876db2e18490d3210a8302290e4844b7f04159e02033d4", size = 3878622, upload-time = "2026-03-01T05:52:33.458Z" }, + { url = "https://files.pythonhosted.org/packages/fb/86/5c68dc877af9baf4fba3e5d2615fe0aefbdd4e1337d3b678b66769b434c9/primp-1.1.2-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a1df66deacb539efbca5730d0fc3dea19cd83c33422fa05445bbddc17aef3f71", size = 3520112, upload-time = "2026-03-01T05:52:45.214Z" }, + { url = "https://files.pythonhosted.org/packages/fd/aa/f8798a1c0fabbc9254e29330df61b93bdb54130e9d5e5d8495eff99fc658/primp-1.1.2-cp314-cp314t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78ea1f56dd3ac52f2d5375a084c7f31ce6ad274811bdb5d17ecaca6b4ddb8b6d", size = 3740187, upload-time = "2026-03-01T05:52:26.052Z" }, + { url = "https://files.pythonhosted.org/packages/90/e4/ea08359b6fbcda7b3ffcc15b4c1e0bf4f89680db126ba96889e7f8e1fe04/primp-1.1.2-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3c980527bd46c034ab9e06dca75b6237cea8d5b3fe1f5691904a2c35d92d143c", size = 4011825, upload-time = "2026-03-01T05:52:17.403Z" }, + { url = "https://files.pythonhosted.org/packages/01/4a/8cf516250cc97eab2d4c822478ab0037b9848bca844787196481b5691f25/primp-1.1.2-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0c0b4006a9a25c5f89a968f3bf67221fc19183890b8a1304873132d703697816", size = 3907535, upload-time = "2026-03-01T05:52:24.455Z" }, + { url = "https://files.pythonhosted.org/packages/90/00/e6fe4abf75012d05009abf22e9e1eb89b4bca06ad9f79c10876cebdf7271/primp-1.1.2-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2851bedc1598ed72f6a2016e391012744259c523dc5d27f2f02e3ae5ef020d4", size = 4108136, upload-time = "2026-03-01T05:52:42.007Z" }, + { url = "https://files.pythonhosted.org/packages/9d/8a/64cd76fee8b994f349c1a9c6541b4144dee64056dcaa8109bd352518b777/primp-1.1.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:f7340e34023dda2660bd02cb92ac8ed441f13a1afdc00487581d8b8b473f890b", size = 4060289, upload-time = "2026-03-01T05:52:40.4Z" }, + { url = "https://files.pythonhosted.org/packages/dd/7c/fbea74676def2ce1d21a53e86cdbb3ef9c7a12b2febfdd3961a8466449a7/primp-1.1.2-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:618a027bb45ac44e9b6c35d5758547ce5e73607de4fb54b52bb9d0dc896f11fa", size = 3749499, upload-time = "2026-03-01T05:51:59.988Z" }, + { url = "https://files.pythonhosted.org/packages/12/7a/36fc46a385141063e2ae4fd24dda308e75da8c6409c425a56ffceb6e4f71/primp-1.1.2-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:37e30ce1435142dd010f2ee1dd909f1e6e3a8cd3e32c8e22f3bb6703bf618209", size = 3858861, upload-time = "2026-03-01T05:52:10.621Z" }, + { url = "https://files.pythonhosted.org/packages/65/bb/d0319dbd2e20fb4f54d8b3f536b89431a9d1442f00fa11a874dfbe9d2de7/primp-1.1.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9b5d335d28eae65543b20c75911d71c5f89882a4598efade47abe92389f6da7f", size = 4358677, upload-time = "2026-03-01T05:52:18.978Z" }, + { url = "https://files.pythonhosted.org/packages/57/89/ab887a516dc83dbae12ea5b338f60c46a56966a972fed65f8de5bf05a9c2/primp-1.1.2-cp314-cp314t-win32.whl", hash = "sha256:b938cc2d033ac56be90c617836a60fb468f33ab630d3eacab2b36651b7ce106e", size = 3258062, upload-time = "2026-03-01T05:52:36.741Z" }, + { url = "https://files.pythonhosted.org/packages/df/ca/e870d65162f6c68da6d25afa3e01202ac500c8ad1b682dfd03e8c45e4d4a/primp-1.1.2-cp314-cp314t-win_amd64.whl", hash = "sha256:6378d55bbe8b722e7b39b6c0df1e46a1b767d2e4e8a7c1e60d9f8ec238bf48c4", size = 3599631, upload-time = "2026-03-01T05:52:03.595Z" }, + { url = "https://files.pythonhosted.org/packages/4e/cb/61667c710293d8007416130c9ad69f60a956393b52e82557c84ae8286aa7/primp-1.1.2-cp314-cp314t-win_arm64.whl", hash = "sha256:2431104658b86e7cf9bedbadabe6d2c4705c1c10b54f17ad0094cc927577adea", size = 3610624, upload-time = "2026-03-01T05:52:30.19Z" }, ] [[package]] @@ -2202,18 +2080,18 @@ crypto = [ [[package]] name = "pyrefly" -version = "0.54.0" +version = "0.55.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/81/44/c10b16a302fda90d0af1328f880b232761b510eab546616a7be2fdf35a57/pyrefly-0.54.0.tar.gz", hash = "sha256:c6663be64d492f0d2f2a411ada9f28a6792163d34133639378b7f3dd9a8dca94", size = 5098893, upload-time = "2026-02-23T15:44:35.111Z" } +sdist = { url = "https://files.pythonhosted.org/packages/bf/c4/76e0797215e62d007f81f86c9c4fb5d6202685a3f5e70810f3fd94294f92/pyrefly-0.55.0.tar.gz", hash = "sha256:434c3282532dd4525c4840f2040ed0eb79b0ec8224fe18d957956b15471f2441", size = 5135682, upload-time = "2026-03-03T00:46:38.122Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5f/99/8fdcdb4e55f0227fdd9f6abce36b619bab1ecb0662b83b66adc8cba3c788/pyrefly-0.54.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:58a3f092b6dc25ef79b2dc6c69a40f36784ca157c312bfc0baea463926a9db6d", size = 12223973, upload-time = "2026-02-23T15:44:14.278Z" }, - { url = "https://files.pythonhosted.org/packages/90/35/c2aaf87a76003ad27b286594d2e5178f811eaa15bfe3d98dba2b47d56dd1/pyrefly-0.54.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:615081414106dd95873bc39c3a4bed68754c6cc24a8177ac51d22f88f88d3eb3", size = 11785585, upload-time = "2026-02-23T15:44:17.468Z" }, - { url = "https://files.pythonhosted.org/packages/c4/4a/ced02691ed67e5a897714979196f08ad279ec7ec7f63c45e00a75a7f3c0e/pyrefly-0.54.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cbcaf20f5fe585079079a95205c1f3cd4542d17228cdf1df560288880623b70", size = 33381977, upload-time = "2026-02-23T15:44:19.736Z" }, - { url = "https://files.pythonhosted.org/packages/0b/ce/72a117ed437c8f6950862181014b41e36f3c3997580e29b772b71e78d587/pyrefly-0.54.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66d5da116c0d34acfbd66663addd3ca8aa78a636f6692a66e078126d3620a883", size = 35962821, upload-time = "2026-02-23T15:44:22.357Z" }, - { url = "https://files.pythonhosted.org/packages/85/de/89013f5ae0a35d2b6b01274a92a35ee91431ea001050edf0a16748d39875/pyrefly-0.54.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ef3ac27f1a4baaf67aead64287d3163350844794aca6315ad1a9650b16ec26a", size = 38496689, upload-time = "2026-02-23T15:44:25.236Z" }, - { url = "https://files.pythonhosted.org/packages/9f/9a/33b097c7bf498b924742dca32dd5d9c6a3fa6c2b52b63a58eb9e1980ca89/pyrefly-0.54.0-py3-none-win32.whl", hash = "sha256:7d607d72200a8afbd2db10bfefb40160a7a5d709d207161c21649cedd5cfc09a", size = 11295268, upload-time = "2026-02-23T15:44:27.551Z" }, - { url = "https://files.pythonhosted.org/packages/d4/21/9263fd1144d2a3d7342b474f183f7785b3358a1565c864089b780110b933/pyrefly-0.54.0-py3-none-win_amd64.whl", hash = "sha256:fd416f04f89309385696f685bd5c9141011f18c8072f84d31ca20c748546e791", size = 12081810, upload-time = "2026-02-23T15:44:29.461Z" }, - { url = "https://files.pythonhosted.org/packages/ea/5b/fad062a196c064cbc8564de5b2f4d3cb6315f852e3b31e8a1ce74c69a1ea/pyrefly-0.54.0-py3-none-win_arm64.whl", hash = "sha256:f06ab371356c7b1925e0bffe193b738797e71e5dbbff7fb5a13f90ee7521211d", size = 11564930, upload-time = "2026-02-23T15:44:33.053Z" }, + { url = "https://files.pythonhosted.org/packages/39/b0/16e50cf716784513648e23e726a24f71f9544aa4f86103032dcaa5ff71a2/pyrefly-0.55.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:49aafcefe5e2dd4256147db93e5b0ada42bff7d9a60db70e03d1f7055338eec9", size = 12210073, upload-time = "2026-03-03T00:46:15.51Z" }, + { url = "https://files.pythonhosted.org/packages/3a/ad/89500c01bac3083383011600370289fbc67700c5be46e781787392628a3a/pyrefly-0.55.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:2827426e6b28397c13badb93c0ede0fb0f48046a7a89e3d774cda04e8e2067cd", size = 11767474, upload-time = "2026-03-03T00:46:18.003Z" }, + { url = "https://files.pythonhosted.org/packages/78/68/4c66b260f817f304ead11176ff13985625f7c269e653304b4bdb546551af/pyrefly-0.55.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7346b2d64dc575bd61aa3bca854fbf8b5a19a471cbdb45e0ca1e09861b63488c", size = 33260395, upload-time = "2026-03-03T00:46:20.509Z" }, + { url = "https://files.pythonhosted.org/packages/47/09/10bd48c9f860064f29f412954126a827d60f6451512224912c265e26bbe6/pyrefly-0.55.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:233b861b4cff008b1aff62f4f941577ed752e4d0060834229eb9b6826e6973c9", size = 35848269, upload-time = "2026-03-03T00:46:23.418Z" }, + { url = "https://files.pythonhosted.org/packages/a9/39/bc65cdd5243eb2dfea25dd1321f9a5a93e8d9c3a308501c4c6c05d011585/pyrefly-0.55.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5aa85657d76da1d25d081a49f0e33c8fc3ec91c1a0f185a8ed393a5a3d9e178", size = 38449820, upload-time = "2026-03-03T00:46:26.309Z" }, + { url = "https://files.pythonhosted.org/packages/e5/64/58b38963b011af91209e87f868cc85cfc762ec49a4568ce610c45e7a5f40/pyrefly-0.55.0-py3-none-win32.whl", hash = "sha256:23f786a78536a56fed331b245b7d10ec8945bebee7b723491c8d66fdbc155fe6", size = 11259415, upload-time = "2026-03-03T00:46:30.875Z" }, + { url = "https://files.pythonhosted.org/packages/7a/0b/a4aa519ff632a1ea69eec942566951670b870b99b5c08407e1387b85b6a4/pyrefly-0.55.0-py3-none-win_amd64.whl", hash = "sha256:d465b49e999b50eeb069ad23f0f5710651cad2576f9452a82991bef557df91ee", size = 12043581, upload-time = "2026-03-03T00:46:33.674Z" }, + { url = "https://files.pythonhosted.org/packages/f1/51/89017636fbe1ffd166ad478990c6052df615b926182fa6d3c0842b407e89/pyrefly-0.55.0-py3-none-win_arm64.whl", hash = "sha256:732ff490e0e863b296e7c0b2471e08f8ba7952f9fa6e9de09d8347fd67dde77f", size = 11548076, upload-time = "2026-03-03T00:46:36.193Z" }, ] [[package]] @@ -2260,11 +2138,11 @@ wheels = [ [[package]] name = "python-dotenv" -version = "1.2.1" +version = "1.2.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f0/26/19cadc79a718c5edbec86fd4919a6b6d3f681039a2f6d66d14be94e75fb9/python_dotenv-1.2.1.tar.gz", hash = "sha256:42667e897e16ab0d66954af0e60a9caa94f0fd4ecf3aaf6d2d260eec1aa36ad6", size = 44221, upload-time = "2025-10-26T15:12:10.434Z" } +sdist = { url = "https://files.pythonhosted.org/packages/82/ed/0301aeeac3e5353ef3d94b6ec08bbcabd04a72018415dcb29e588514bba8/python_dotenv-1.2.2.tar.gz", hash = "sha256:2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3", size = 50135, upload-time = "2026-03-01T16:00:26.196Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61", size = 21230, upload-time = "2025-10-26T15:12:09.109Z" }, + { url = "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl", hash = "sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a", size = 22101, upload-time = "2026-03-01T16:00:25.09Z" }, ] [[package]] @@ -2366,106 +2244,106 @@ wheels = [ [[package]] name = "regex" -version = "2026.2.19" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ff/c0/d8079d4f6342e4cec5c3e7d7415b5cd3e633d5f4124f7a4626908dbe84c7/regex-2026.2.19.tar.gz", hash = "sha256:6fb8cb09b10e38f3ae17cc6dc04a1df77762bd0351b6ba9041438e7cc85ec310", size = 414973, upload-time = "2026-02-19T19:03:47.899Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6f/93/43f405a98f54cc59c786efb4fc0b644615ed2392fc89d57d30da11f35b5b/regex-2026.2.19-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:93b16a18cadb938f0f2306267161d57eb33081a861cee9ffcd71e60941eb5dfc", size = 488365, upload-time = "2026-02-19T19:00:17.857Z" }, - { url = "https://files.pythonhosted.org/packages/66/46/da0efce22cd8f5ae28eeb25ac69703f49edcad3331ac22440776f4ea0867/regex-2026.2.19-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:78af1e499cab704131f6f4e2f155b7f54ce396ca2acb6ef21a49507e4752e0be", size = 290737, upload-time = "2026-02-19T19:00:19.869Z" }, - { url = "https://files.pythonhosted.org/packages/fb/19/f735078448132c1c974974d30d5306337bc297fe6b6f126164bff72c1019/regex-2026.2.19-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:eb20c11aa4c3793c9ad04c19a972078cdadb261b8429380364be28e867a843f2", size = 288654, upload-time = "2026-02-19T19:00:21.307Z" }, - { url = "https://files.pythonhosted.org/packages/e2/3e/6d7c24a2f423c03ad03e3fbddefa431057186ac1c4cb4fa98b03c7f39808/regex-2026.2.19-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:db5fd91eec71e7b08de10011a2223d0faa20448d4e1380b9daa179fa7bf58906", size = 793785, upload-time = "2026-02-19T19:00:22.926Z" }, - { url = "https://files.pythonhosted.org/packages/67/32/fdb8107504b3122a79bde6705ac1f9d495ed1fe35b87d7cfc1864471999a/regex-2026.2.19-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:fdbade8acba71bb45057c2b72f477f0b527c4895f9c83e6cfc30d4a006c21726", size = 860731, upload-time = "2026-02-19T19:00:25.196Z" }, - { url = "https://files.pythonhosted.org/packages/9a/fd/cc8c6f05868defd840be6e75919b1c3f462357969ac2c2a0958363b4dc23/regex-2026.2.19-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:31a5f561eb111d6aae14202e7043fb0b406d3c8dddbbb9e60851725c9b38ab1d", size = 907350, upload-time = "2026-02-19T19:00:27.093Z" }, - { url = "https://files.pythonhosted.org/packages/b5/1b/4590db9caa8db3d5a3fe31197c4e42c15aab3643b549ef6a454525fa3a61/regex-2026.2.19-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4584a3ee5f257b71e4b693cc9be3a5104249399f4116fe518c3f79b0c6fc7083", size = 800628, upload-time = "2026-02-19T19:00:29.392Z" }, - { url = "https://files.pythonhosted.org/packages/76/05/513eaa5b96fa579fd0b813e19ec047baaaf573d7374ff010fa139b384bf7/regex-2026.2.19-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:196553ba2a2f47904e5dc272d948a746352e2644005627467e055be19d73b39e", size = 773711, upload-time = "2026-02-19T19:00:30.996Z" }, - { url = "https://files.pythonhosted.org/packages/95/65/5aed06d8c54563d37fea496cf888be504879a3981a7c8e12c24b2c92c209/regex-2026.2.19-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0c10869d18abb759a3317c757746cc913d6324ce128b8bcec99350df10419f18", size = 783186, upload-time = "2026-02-19T19:00:34.598Z" }, - { url = "https://files.pythonhosted.org/packages/2c/57/79a633ad90f2371b4ef9cd72ba3a69a1a67d0cfaab4fe6fa8586d46044ef/regex-2026.2.19-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e689fed279cbe797a6b570bd18ff535b284d057202692c73420cb93cca41aa32", size = 854854, upload-time = "2026-02-19T19:00:37.306Z" }, - { url = "https://files.pythonhosted.org/packages/eb/2d/0f113d477d9e91ec4545ec36c82e58be25038d06788229c91ad52da2b7f5/regex-2026.2.19-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:0782bd983f19ac7594039c9277cd6f75c89598c1d72f417e4d30d874105eb0c7", size = 762279, upload-time = "2026-02-19T19:00:39.793Z" }, - { url = "https://files.pythonhosted.org/packages/39/cb/237e9fa4f61469fd4f037164dbe8e675a376c88cf73aaaa0aedfd305601c/regex-2026.2.19-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:dbb240c81cfed5d4a67cb86d7676d9f7ec9c3f186310bec37d8a1415210e111e", size = 846172, upload-time = "2026-02-19T19:00:42.134Z" }, - { url = "https://files.pythonhosted.org/packages/ac/7c/104779c5915cc4eb557a33590f8a3f68089269c64287dd769afd76c7ce61/regex-2026.2.19-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:80d31c3f1fe7e4c6cd1831cd4478a0609903044dfcdc4660abfe6fb307add7f0", size = 789078, upload-time = "2026-02-19T19:00:43.908Z" }, - { url = "https://files.pythonhosted.org/packages/a8/4a/eae4e88b1317fb2ff57794915e0099198f51e760f6280b320adfa0ad396d/regex-2026.2.19-cp311-cp311-win32.whl", hash = "sha256:66e6a43225ff1064f8926adbafe0922b370d381c3330edaf9891cade52daa790", size = 266013, upload-time = "2026-02-19T19:00:47.274Z" }, - { url = "https://files.pythonhosted.org/packages/f9/29/ba89eb8fae79705e07ad1bd69e568f776159d2a8093c9dbc5303ee618298/regex-2026.2.19-cp311-cp311-win_amd64.whl", hash = "sha256:59a7a5216485a1896c5800e9feb8ff9213e11967b482633b6195d7da11450013", size = 277906, upload-time = "2026-02-19T19:00:49.011Z" }, - { url = "https://files.pythonhosted.org/packages/e3/1a/042d8f04b28e318df92df69d8becb0f42221eb3dd4fe5e976522f4337c76/regex-2026.2.19-cp311-cp311-win_arm64.whl", hash = "sha256:ec661807ffc14c8d14bb0b8c1bb3d5906e476bc96f98b565b709d03962ee4dd4", size = 270463, upload-time = "2026-02-19T19:00:50.988Z" }, - { url = "https://files.pythonhosted.org/packages/b3/73/13b39c7c9356f333e564ab4790b6cb0df125b8e64e8d6474e73da49b1955/regex-2026.2.19-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:c1665138776e4ac1aa75146669236f7a8a696433ec4e525abf092ca9189247cc", size = 489541, upload-time = "2026-02-19T19:00:52.728Z" }, - { url = "https://files.pythonhosted.org/packages/15/77/fcc7bd9a67000d07fbcc11ed226077287a40d5c84544e62171d29d3ef59c/regex-2026.2.19-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d792b84709021945597e05656aac059526df4e0c9ef60a0eaebb306f8fafcaa8", size = 291414, upload-time = "2026-02-19T19:00:54.51Z" }, - { url = "https://files.pythonhosted.org/packages/f9/87/3997fc72dc59233426ef2e18dfdd105bb123812fff740ee9cc348f1a3243/regex-2026.2.19-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:db970bcce4d63b37b3f9eb8c893f0db980bbf1d404a1d8d2b17aa8189de92c53", size = 289140, upload-time = "2026-02-19T19:00:56.841Z" }, - { url = "https://files.pythonhosted.org/packages/f3/d0/b7dd3883ed1cff8ee0c0c9462d828aaf12be63bf5dc55453cbf423523b13/regex-2026.2.19-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:03d706fbe7dfec503c8c3cb76f9352b3e3b53b623672aa49f18a251a6c71b8e6", size = 798767, upload-time = "2026-02-19T19:00:59.014Z" }, - { url = "https://files.pythonhosted.org/packages/4a/7e/8e2d09103832891b2b735a2515abf377db21144c6dd5ede1fb03c619bf09/regex-2026.2.19-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8dbff048c042beef60aa1848961384572c5afb9e8b290b0f1203a5c42cf5af65", size = 864436, upload-time = "2026-02-19T19:01:00.772Z" }, - { url = "https://files.pythonhosted.org/packages/8a/2e/afea8d23a6db1f67f45e3a0da3057104ce32e154f57dd0c8997274d45fcd/regex-2026.2.19-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ccaaf9b907ea6b4223d5cbf5fa5dff5f33dc66f4907a25b967b8a81339a6e332", size = 912391, upload-time = "2026-02-19T19:01:02.865Z" }, - { url = "https://files.pythonhosted.org/packages/59/3c/ea5a4687adaba5e125b9bd6190153d0037325a0ba3757cc1537cc2c8dd90/regex-2026.2.19-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:75472631eee7898e16a8a20998d15106cb31cfde21cdf96ab40b432a7082af06", size = 803702, upload-time = "2026-02-19T19:01:05.298Z" }, - { url = "https://files.pythonhosted.org/packages/dc/c5/624a0705e8473a26488ec1a3a4e0b8763ecfc682a185c302dfec71daea35/regex-2026.2.19-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d89f85a5ccc0cec125c24be75610d433d65295827ebaf0d884cbe56df82d4774", size = 775980, upload-time = "2026-02-19T19:01:07.047Z" }, - { url = "https://files.pythonhosted.org/packages/4d/4b/ed776642533232b5599b7c1f9d817fe11faf597e8a92b7a44b841daaae76/regex-2026.2.19-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0d9f81806abdca3234c3dd582b8a97492e93de3602c8772013cb4affa12d1668", size = 788122, upload-time = "2026-02-19T19:01:08.744Z" }, - { url = "https://files.pythonhosted.org/packages/8c/58/e93e093921d13b9784b4f69896b6e2a9e09580a265c59d9eb95e87d288f2/regex-2026.2.19-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:9dadc10d1c2bbb1326e572a226d2ec56474ab8aab26fdb8cf19419b372c349a9", size = 858910, upload-time = "2026-02-19T19:01:10.488Z" }, - { url = "https://files.pythonhosted.org/packages/85/77/ff1d25a0c56cd546e0455cbc93235beb33474899690e6a361fa6b52d265b/regex-2026.2.19-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:6bc25d7e15f80c9dc7853cbb490b91c1ec7310808b09d56bd278fe03d776f4f6", size = 764153, upload-time = "2026-02-19T19:01:12.156Z" }, - { url = "https://files.pythonhosted.org/packages/cd/ef/8ec58df26d52d04443b1dc56f9be4b409f43ed5ae6c0248a287f52311fc4/regex-2026.2.19-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:965d59792f5037d9138da6fed50ba943162160443b43d4895b182551805aff9c", size = 850348, upload-time = "2026-02-19T19:01:14.147Z" }, - { url = "https://files.pythonhosted.org/packages/f5/b3/c42fd5ed91639ce5a4225b9df909180fc95586db071f2bf7c68d2ccbfbe6/regex-2026.2.19-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:38d88c6ed4a09ed61403dbdf515d969ccba34669af3961ceb7311ecd0cef504a", size = 789977, upload-time = "2026-02-19T19:01:15.838Z" }, - { url = "https://files.pythonhosted.org/packages/b6/22/bc3b58ebddbfd6ca5633e71fd41829ee931963aad1ebeec55aad0c23044e/regex-2026.2.19-cp312-cp312-win32.whl", hash = "sha256:5df947cabab4b643d4791af5e28aecf6bf62e6160e525651a12eba3d03755e6b", size = 266381, upload-time = "2026-02-19T19:01:17.952Z" }, - { url = "https://files.pythonhosted.org/packages/fc/4a/6ff550b63e67603ee60e69dc6bd2d5694e85046a558f663b2434bdaeb285/regex-2026.2.19-cp312-cp312-win_amd64.whl", hash = "sha256:4146dc576ea99634ae9c15587d0c43273b4023a10702998edf0fa68ccb60237a", size = 277274, upload-time = "2026-02-19T19:01:19.826Z" }, - { url = "https://files.pythonhosted.org/packages/cc/29/9ec48b679b1e87e7bc8517dff45351eab38f74fbbda1fbcf0e9e6d4e8174/regex-2026.2.19-cp312-cp312-win_arm64.whl", hash = "sha256:cdc0a80f679353bd68450d2a42996090c30b2e15ca90ded6156c31f1a3b63f3b", size = 270509, upload-time = "2026-02-19T19:01:22.075Z" }, - { url = "https://files.pythonhosted.org/packages/d2/2d/a849835e76ac88fcf9e8784e642d3ea635d183c4112150ca91499d6703af/regex-2026.2.19-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8df08decd339e8b3f6a2eb5c05c687fe9d963ae91f352bc57beb05f5b2ac6879", size = 489329, upload-time = "2026-02-19T19:01:23.841Z" }, - { url = "https://files.pythonhosted.org/packages/da/aa/78ff4666d3855490bae87845a5983485e765e1f970da20adffa2937b241d/regex-2026.2.19-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3aa0944f1dc6e92f91f3b306ba7f851e1009398c84bfd370633182ee4fc26a64", size = 291308, upload-time = "2026-02-19T19:01:25.605Z" }, - { url = "https://files.pythonhosted.org/packages/cd/58/714384efcc07ae6beba528a541f6e99188c5cc1bc0295337f4e8a868296d/regex-2026.2.19-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c13228fbecb03eadbfd8f521732c5fda09ef761af02e920a3148e18ad0e09968", size = 289033, upload-time = "2026-02-19T19:01:27.243Z" }, - { url = "https://files.pythonhosted.org/packages/75/ec/6438a9344d2869cf5265236a06af1ca6d885e5848b6561e10629bc8e5a11/regex-2026.2.19-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0d0e72703c60d68b18b27cde7cdb65ed2570ae29fb37231aa3076bfb6b1d1c13", size = 798798, upload-time = "2026-02-19T19:01:28.877Z" }, - { url = "https://files.pythonhosted.org/packages/c2/be/b1ce2d395e3fd2ce5f2fde2522f76cade4297cfe84cd61990ff48308749c/regex-2026.2.19-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:46e69a4bf552e30e74a8aa73f473c87efcb7f6e8c8ece60d9fd7bf13d5c86f02", size = 864444, upload-time = "2026-02-19T19:01:30.933Z" }, - { url = "https://files.pythonhosted.org/packages/d5/97/a3406460c504f7136f140d9461960c25f058b0240e4424d6fb73c7a067ab/regex-2026.2.19-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8edda06079bd770f7f0cf7f3bba1a0b447b96b4a543c91fe0c142d034c166161", size = 912633, upload-time = "2026-02-19T19:01:32.744Z" }, - { url = "https://files.pythonhosted.org/packages/8b/d9/e5dbef95008d84e9af1dc0faabbc34a7fbc8daa05bc5807c5cf86c2bec49/regex-2026.2.19-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9cbc69eae834afbf634f7c902fc72ff3e993f1c699156dd1af1adab5d06b7fe7", size = 803718, upload-time = "2026-02-19T19:01:34.61Z" }, - { url = "https://files.pythonhosted.org/packages/2f/e5/61d80132690a1ef8dc48e0f44248036877aebf94235d43f63a20d1598888/regex-2026.2.19-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bcf57d30659996ee5c7937999874504c11b5a068edc9515e6a59221cc2744dd1", size = 775975, upload-time = "2026-02-19T19:01:36.525Z" }, - { url = "https://files.pythonhosted.org/packages/05/32/ae828b3b312c972cf228b634447de27237d593d61505e6ad84723f8eabba/regex-2026.2.19-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:8e6e77cd92216eb489e21e5652a11b186afe9bdefca8a2db739fd6b205a9e0a4", size = 788129, upload-time = "2026-02-19T19:01:38.498Z" }, - { url = "https://files.pythonhosted.org/packages/cb/25/d74f34676f22bec401eddf0e5e457296941e10cbb2a49a571ca7a2c16e5a/regex-2026.2.19-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b9ab8dec42afefa6314ea9b31b188259ffdd93f433d77cad454cd0b8d235ce1c", size = 858818, upload-time = "2026-02-19T19:01:40.409Z" }, - { url = "https://files.pythonhosted.org/packages/1e/eb/0bc2b01a6b0b264e1406e5ef11cae3f634c3bd1a6e61206fd3227ce8e89c/regex-2026.2.19-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:294c0fb2e87c6bcc5f577c8f609210f5700b993151913352ed6c6af42f30f95f", size = 764186, upload-time = "2026-02-19T19:01:43.009Z" }, - { url = "https://files.pythonhosted.org/packages/eb/37/5fe5a630d0d99ecf0c3570f8905dafbc160443a2d80181607770086c9812/regex-2026.2.19-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:c0924c64b082d4512b923ac016d6e1dcf647a3560b8a4c7e55cbbd13656cb4ed", size = 850363, upload-time = "2026-02-19T19:01:45.015Z" }, - { url = "https://files.pythonhosted.org/packages/c3/45/ef68d805294b01ec030cfd388724ba76a5a21a67f32af05b17924520cb0b/regex-2026.2.19-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:790dbf87b0361606cb0d79b393c3e8f4436a14ee56568a7463014565d97da02a", size = 790026, upload-time = "2026-02-19T19:01:47.51Z" }, - { url = "https://files.pythonhosted.org/packages/d6/3a/40d3b66923dfc5aeba182f194f0ca35d09afe8c031a193e6ae46971a0a0e/regex-2026.2.19-cp313-cp313-win32.whl", hash = "sha256:43cdde87006271be6963896ed816733b10967baaf0e271d529c82e93da66675b", size = 266372, upload-time = "2026-02-19T19:01:49.469Z" }, - { url = "https://files.pythonhosted.org/packages/3d/f2/39082e8739bfd553497689e74f9d5e5bb531d6f8936d0b94f43e18f219c0/regex-2026.2.19-cp313-cp313-win_amd64.whl", hash = "sha256:127ea69273485348a126ebbf3d6052604d3c7da284f797bba781f364c0947d47", size = 277253, upload-time = "2026-02-19T19:01:51.208Z" }, - { url = "https://files.pythonhosted.org/packages/c2/c2/852b9600d53fb47e47080c203e2cdc0ac7e84e37032a57e0eaa37446033a/regex-2026.2.19-cp313-cp313-win_arm64.whl", hash = "sha256:5e56c669535ac59cbf96ca1ece0ef26cb66809990cda4fa45e1e32c3b146599e", size = 270505, upload-time = "2026-02-19T19:01:52.865Z" }, - { url = "https://files.pythonhosted.org/packages/a9/a2/e0b4575b93bc84db3b1fab24183e008691cd2db5c0ef14ed52681fbd94dd/regex-2026.2.19-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:93d881cab5afdc41a005dba1524a40947d6f7a525057aa64aaf16065cf62faa9", size = 492202, upload-time = "2026-02-19T19:01:54.816Z" }, - { url = "https://files.pythonhosted.org/packages/24/b5/b84fec8cbb5f92a7eed2b6b5353a6a9eed9670fee31817c2da9eb85dc797/regex-2026.2.19-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:80caaa1ddcc942ec7be18427354f9d58a79cee82dea2a6b3d4fd83302e1240d7", size = 292884, upload-time = "2026-02-19T19:01:58.254Z" }, - { url = "https://files.pythonhosted.org/packages/70/0c/fe89966dfae43da46f475362401f03e4d7dc3a3c955b54f632abc52669e0/regex-2026.2.19-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:d793c5b4d2b4c668524cd1651404cfc798d40694c759aec997e196fe9729ec60", size = 291236, upload-time = "2026-02-19T19:01:59.966Z" }, - { url = "https://files.pythonhosted.org/packages/f2/f7/bda2695134f3e63eb5cccbbf608c2a12aab93d261ff4e2fe49b47fabc948/regex-2026.2.19-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b5100acb20648d9efd3f4e7e91f51187f95f22a741dcd719548a6cf4e1b34b3f", size = 807660, upload-time = "2026-02-19T19:02:01.632Z" }, - { url = "https://files.pythonhosted.org/packages/11/56/6e3a4bf5e60d17326b7003d91bbde8938e439256dec211d835597a44972d/regex-2026.2.19-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5e3a31e94d10e52a896adaa3adf3621bd526ad2b45b8c2d23d1bbe74c7423007", size = 873585, upload-time = "2026-02-19T19:02:03.522Z" }, - { url = "https://files.pythonhosted.org/packages/35/5e/c90c6aa4d1317cc11839359479cfdd2662608f339e84e81ba751c8a4e461/regex-2026.2.19-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8497421099b981f67c99eba4154cf0dfd8e47159431427a11cfb6487f7791d9e", size = 915243, upload-time = "2026-02-19T19:02:05.608Z" }, - { url = "https://files.pythonhosted.org/packages/90/7c/981ea0694116793001496aaf9524e5c99e122ec3952d9e7f1878af3a6bf1/regex-2026.2.19-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1e7a08622f7d51d7a068f7e4052a38739c412a3e74f55817073d2e2418149619", size = 812922, upload-time = "2026-02-19T19:02:08.115Z" }, - { url = "https://files.pythonhosted.org/packages/2d/be/9eda82afa425370ffdb3fa9f3ea42450b9ae4da3ff0a4ec20466f69e371b/regex-2026.2.19-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8abe671cf0f15c26b1ad389bf4043b068ce7d3b1c5d9313e12895f57d6738555", size = 781318, upload-time = "2026-02-19T19:02:10.072Z" }, - { url = "https://files.pythonhosted.org/packages/c6/d5/50f0bbe56a8199f60a7b6c714e06e54b76b33d31806a69d0703b23ce2a9e/regex-2026.2.19-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:5a8f28dd32a4ce9c41758d43b5b9115c1c497b4b1f50c457602c1d571fa98ce1", size = 795649, upload-time = "2026-02-19T19:02:11.96Z" }, - { url = "https://files.pythonhosted.org/packages/c5/09/d039f081e44a8b0134d0bb2dd805b0ddf390b69d0b58297ae098847c572f/regex-2026.2.19-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:654dc41a5ba9b8cc8432b3f1aa8906d8b45f3e9502442a07c2f27f6c63f85db5", size = 868844, upload-time = "2026-02-19T19:02:14.043Z" }, - { url = "https://files.pythonhosted.org/packages/ef/53/e2903b79a19ec8557fe7cd21cd093956ff2dbc2e0e33969e3adbe5b184dd/regex-2026.2.19-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:4a02faea614e7fdd6ba8b3bec6c8e79529d356b100381cec76e638f45d12ca04", size = 770113, upload-time = "2026-02-19T19:02:16.161Z" }, - { url = "https://files.pythonhosted.org/packages/8f/e2/784667767b55714ebb4e59bf106362327476b882c0b2f93c25e84cc99b1a/regex-2026.2.19-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:d96162140bb819814428800934c7b71b7bffe81fb6da2d6abc1dcca31741eca3", size = 854922, upload-time = "2026-02-19T19:02:18.155Z" }, - { url = "https://files.pythonhosted.org/packages/59/78/9ef4356bd4aed752775bd18071034979b85f035fec51f3a4f9dea497a254/regex-2026.2.19-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c227f2922153ee42bbeb355fd6d009f8c81d9d7bdd666e2276ce41f53ed9a743", size = 799636, upload-time = "2026-02-19T19:02:20.04Z" }, - { url = "https://files.pythonhosted.org/packages/cf/54/fcfc9287f20c5c9bd8db755aafe3e8cf4d99a6a3f1c7162ee182e0ca9374/regex-2026.2.19-cp313-cp313t-win32.whl", hash = "sha256:a178df8ec03011153fbcd2c70cb961bc98cbbd9694b28f706c318bee8927c3db", size = 268968, upload-time = "2026-02-19T19:02:22.816Z" }, - { url = "https://files.pythonhosted.org/packages/1e/a0/ff24c6cb1273e42472706d277147fc38e1f9074a280fb6034b0fc9b69415/regex-2026.2.19-cp313-cp313t-win_amd64.whl", hash = "sha256:2c1693ca6f444d554aa246b592355b5cec030ace5a2729eae1b04ab6e853e768", size = 280390, upload-time = "2026-02-19T19:02:25.231Z" }, - { url = "https://files.pythonhosted.org/packages/1a/b6/a3f6ad89d780ffdeebb4d5e2e3e30bd2ef1f70f6a94d1760e03dd1e12c60/regex-2026.2.19-cp313-cp313t-win_arm64.whl", hash = "sha256:c0761d7ae8d65773e01515ebb0b304df1bf37a0a79546caad9cbe79a42c12af7", size = 271643, upload-time = "2026-02-19T19:02:27.175Z" }, - { url = "https://files.pythonhosted.org/packages/2d/e2/7ad4e76a6dddefc0d64dbe12a4d3ca3947a19ddc501f864a5df2a8222ddd/regex-2026.2.19-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:03d191a9bcf94d31af56d2575210cb0d0c6a054dbcad2ea9e00aa4c42903b919", size = 489306, upload-time = "2026-02-19T19:02:29.058Z" }, - { url = "https://files.pythonhosted.org/packages/14/95/ee1736135733afbcf1846c58671046f99c4d5170102a150ebb3dd8d701d9/regex-2026.2.19-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:516ee067c6c721d0d0bfb80a2004edbd060fffd07e456d4e1669e38fe82f922e", size = 291218, upload-time = "2026-02-19T19:02:31.083Z" }, - { url = "https://files.pythonhosted.org/packages/ef/08/180d1826c3d7065200a5168c6b993a44947395c7bb6e04b2c2a219c34225/regex-2026.2.19-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:997862c619994c4a356cb7c3592502cbd50c2ab98da5f61c5c871f10f22de7e5", size = 289097, upload-time = "2026-02-19T19:02:33.485Z" }, - { url = "https://files.pythonhosted.org/packages/28/93/0651924c390c5740f5f896723f8ddd946a6c63083a7d8647231c343912ff/regex-2026.2.19-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:02b9e1b8a7ebe2807cd7bbdf662510c8e43053a23262b9f46ad4fc2dfc9d204e", size = 799147, upload-time = "2026-02-19T19:02:35.669Z" }, - { url = "https://files.pythonhosted.org/packages/a7/00/2078bd8bcd37d58a756989adbfd9f1d0151b7ca4085a9c2a07e917fbac61/regex-2026.2.19-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6c8fb3b19652e425ff24169dad3ee07f99afa7996caa9dfbb3a9106cd726f49a", size = 865239, upload-time = "2026-02-19T19:02:38.012Z" }, - { url = "https://files.pythonhosted.org/packages/2a/13/75195161ec16936b35a365fa8c1dd2ab29fd910dd2587765062b174d8cfc/regex-2026.2.19-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:50f1ee9488dd7a9fda850ec7c68cad7a32fa49fd19733f5403a3f92b451dcf73", size = 911904, upload-time = "2026-02-19T19:02:40.737Z" }, - { url = "https://files.pythonhosted.org/packages/96/72/ac42f6012179343d1c4bd0ffee8c948d841cb32ea188d37e96d80527fcc9/regex-2026.2.19-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ab780092b1424d13200aa5a62996e95f65ee3db8509be366437439cdc0af1a9f", size = 803518, upload-time = "2026-02-19T19:02:42.923Z" }, - { url = "https://files.pythonhosted.org/packages/bc/d1/75a08e2269b007b9783f0f86aa64488e023141219cb5f14dc1e69cda56c6/regex-2026.2.19-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:17648e1a88e72d88641b12635e70e6c71c5136ba14edba29bf8fc6834005a265", size = 775866, upload-time = "2026-02-19T19:02:45.189Z" }, - { url = "https://files.pythonhosted.org/packages/92/41/70e7d05faf6994c2ca7a9fcaa536da8f8e4031d45b0ec04b57040ede201f/regex-2026.2.19-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2f914ae8c804c8a8a562fe216100bc156bfb51338c1f8d55fe32cf407774359a", size = 788224, upload-time = "2026-02-19T19:02:47.804Z" }, - { url = "https://files.pythonhosted.org/packages/c8/83/34a2dd601f9deb13c20545c674a55f4a05c90869ab73d985b74d639bac43/regex-2026.2.19-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:c7e121a918bbee3f12ac300ce0a0d2f2c979cf208fb071ed8df5a6323281915c", size = 859682, upload-time = "2026-02-19T19:02:50.583Z" }, - { url = "https://files.pythonhosted.org/packages/8e/30/136db9a09a7f222d6e48b806f3730e7af6499a8cad9c72ac0d49d52c746e/regex-2026.2.19-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2fedd459c791da24914ecc474feecd94cf7845efb262ac3134fe27cbd7eda799", size = 764223, upload-time = "2026-02-19T19:02:52.777Z" }, - { url = "https://files.pythonhosted.org/packages/9e/ea/bb947743c78a16df481fa0635c50aa1a439bb80b0e6dc24cd4e49c716679/regex-2026.2.19-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:ea8dfc99689240e61fb21b5fc2828f68b90abf7777d057b62d3166b7c1543c4c", size = 850101, upload-time = "2026-02-19T19:02:55.87Z" }, - { url = "https://files.pythonhosted.org/packages/25/27/e3bfe6e97a99f7393665926be02fef772da7f8aa59e50bc3134e4262a032/regex-2026.2.19-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9fff45852160960f29e184ec8a5be5ab4063cfd0b168d439d1fc4ac3744bf29e", size = 789904, upload-time = "2026-02-19T19:02:58.523Z" }, - { url = "https://files.pythonhosted.org/packages/84/7b/7e2be6f00cea59d08761b027ad237002e90cac74b1607200ebaa2ba3d586/regex-2026.2.19-cp314-cp314-win32.whl", hash = "sha256:5390b130cce14a7d1db226a3896273b7b35be10af35e69f1cca843b6e5d2bb2d", size = 271784, upload-time = "2026-02-19T19:03:00.418Z" }, - { url = "https://files.pythonhosted.org/packages/f7/f6/639911530335773e7ec60bcaa519557b719586024c1d7eaad1daf87b646b/regex-2026.2.19-cp314-cp314-win_amd64.whl", hash = "sha256:e581f75d5c0b15669139ca1c2d3e23a65bb90e3c06ba9d9ea194c377c726a904", size = 280506, upload-time = "2026-02-19T19:03:02.302Z" }, - { url = "https://files.pythonhosted.org/packages/cd/ec/2582b56b4e036d46bb9b5d74a18548439ffa16c11cf59076419174d80f48/regex-2026.2.19-cp314-cp314-win_arm64.whl", hash = "sha256:7187fdee1be0896c1499a991e9bf7c78e4b56b7863e7405d7bb687888ac10c4b", size = 273557, upload-time = "2026-02-19T19:03:04.836Z" }, - { url = "https://files.pythonhosted.org/packages/49/0b/f901cfeb4efd83e4f5c3e9f91a6de77e8e5ceb18555698aca3a27e215ed3/regex-2026.2.19-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:5ec1d7c080832fdd4e150c6f5621fe674c70c63b3ae5a4454cebd7796263b175", size = 492196, upload-time = "2026-02-19T19:03:08.188Z" }, - { url = "https://files.pythonhosted.org/packages/94/0a/349b959e3da874e15eda853755567b4cde7e5309dbb1e07bfe910cfde452/regex-2026.2.19-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:8457c1bc10ee9b29cdfd897ccda41dce6bde0e9abd514bcfef7bcd05e254d411", size = 292878, upload-time = "2026-02-19T19:03:10.272Z" }, - { url = "https://files.pythonhosted.org/packages/98/b0/9d81b3c2c5ddff428f8c506713737278979a2c476f6e3675a9c51da0c389/regex-2026.2.19-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:cce8027010d1ffa3eb89a0b19621cdc78ae548ea2b49fea1f7bfb3ea77064c2b", size = 291235, upload-time = "2026-02-19T19:03:12.5Z" }, - { url = "https://files.pythonhosted.org/packages/04/e7/be7818df8691dbe9508c381ea2cc4c1153e4fdb1c4b06388abeaa93bd712/regex-2026.2.19-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:11c138febb40546ff9e026dbbc41dc9fb8b29e61013fa5848ccfe045f5b23b83", size = 807893, upload-time = "2026-02-19T19:03:15.064Z" }, - { url = "https://files.pythonhosted.org/packages/0c/b6/b898a8b983190cfa0276031c17beb73cfd1db07c03c8c37f606d80b655e2/regex-2026.2.19-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:74ff212aa61532246bb3036b3dfea62233414b0154b8bc3676975da78383cac3", size = 873696, upload-time = "2026-02-19T19:03:17.848Z" }, - { url = "https://files.pythonhosted.org/packages/1a/98/126ba671d54f19080ec87cad228fb4f3cc387fff8c4a01cb4e93f4ff9d94/regex-2026.2.19-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d00c95a2b6bfeb3ea1cb68d1751b1dfce2b05adc2a72c488d77a780db06ab867", size = 915493, upload-time = "2026-02-19T19:03:20.343Z" }, - { url = "https://files.pythonhosted.org/packages/b2/10/550c84a1a1a7371867fe8be2bea7df55e797cbca4709974811410e195c5d/regex-2026.2.19-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:311fcccb76af31be4c588d5a17f8f1a059ae8f4b097192896ebffc95612f223a", size = 813094, upload-time = "2026-02-19T19:03:23.287Z" }, - { url = "https://files.pythonhosted.org/packages/29/fb/ba221d2fc76a27b6b7d7a60f73a7a6a7bac21c6ba95616a08be2bcb434b0/regex-2026.2.19-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:77cfd6b5e7c4e8bf7a39d243ea05882acf5e3c7002b0ef4756de6606893b0ecd", size = 781583, upload-time = "2026-02-19T19:03:26.872Z" }, - { url = "https://files.pythonhosted.org/packages/26/f1/af79231301297c9e962679efc04a31361b58dc62dec1fc0cb4b8dd95956a/regex-2026.2.19-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:6380f29ff212ec922b6efb56100c089251940e0526a0d05aa7c2d9b571ddf2fe", size = 795875, upload-time = "2026-02-19T19:03:29.223Z" }, - { url = "https://files.pythonhosted.org/packages/a0/90/1e1d76cb0a2d0a4f38a039993e1c5cd971ae50435d751c5bae4f10e1c302/regex-2026.2.19-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:655f553a1fa3ab8a7fd570eca793408b8d26a80bfd89ed24d116baaf13a38969", size = 868916, upload-time = "2026-02-19T19:03:31.415Z" }, - { url = "https://files.pythonhosted.org/packages/9a/67/a1c01da76dbcfed690855a284c665cc0a370e7d02d1bd635cf9ff7dd74b8/regex-2026.2.19-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:015088b8558502f1f0bccd58754835aa154a7a5b0bd9d4c9b7b96ff4ae9ba876", size = 770386, upload-time = "2026-02-19T19:03:33.972Z" }, - { url = "https://files.pythonhosted.org/packages/49/6f/94842bf294f432ff3836bfd91032e2ecabea6d284227f12d1f935318c9c4/regex-2026.2.19-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:9e6693b8567a59459b5dda19104c4a4dbbd4a1c78833eacc758796f2cfef1854", size = 855007, upload-time = "2026-02-19T19:03:36.238Z" }, - { url = "https://files.pythonhosted.org/packages/ff/93/393cd203ca0d1d368f05ce12d2c7e91a324bc93c240db2e6d5ada05835f4/regex-2026.2.19-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:4071209fd4376ab5ceec72ad3507e9d3517c59e38a889079b98916477a871868", size = 799863, upload-time = "2026-02-19T19:03:38.497Z" }, - { url = "https://files.pythonhosted.org/packages/43/d9/35afda99bd92bf1a5831e55a4936d37ea4bed6e34c176a3c2238317faf4f/regex-2026.2.19-cp314-cp314t-win32.whl", hash = "sha256:2905ff4a97fad42f2d0834d8b1ea3c2f856ec209837e458d71a061a7d05f9f01", size = 274742, upload-time = "2026-02-19T19:03:40.804Z" }, - { url = "https://files.pythonhosted.org/packages/ae/42/7edc3344dcc87b698e9755f7f685d463852d481302539dae07135202d3ca/regex-2026.2.19-cp314-cp314t-win_amd64.whl", hash = "sha256:64128549b600987e0f335c2365879895f860a9161f283b14207c800a6ed623d3", size = 284443, upload-time = "2026-02-19T19:03:42.954Z" }, - { url = "https://files.pythonhosted.org/packages/3a/45/affdf2d851b42adf3d13fc5b3b059372e9bd299371fd84cf5723c45871fa/regex-2026.2.19-cp314-cp314t-win_arm64.whl", hash = "sha256:a09ae430e94c049dc6957f6baa35ee3418a3a77f3c12b6e02883bd80a2b679b0", size = 274932, upload-time = "2026-02-19T19:03:45.488Z" }, +version = "2026.2.28" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8b/71/41455aa99a5a5ac1eaf311f5d8efd9ce6433c03ac1e0962de163350d0d97/regex-2026.2.28.tar.gz", hash = "sha256:a729e47d418ea11d03469f321aaf67cdee8954cde3ff2cf8403ab87951ad10f2", size = 415184, upload-time = "2026-02-28T02:19:42.792Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/db/8cbfd0ba3f302f2d09dd0019a9fcab74b63fee77a76c937d0e33161fb8c1/regex-2026.2.28-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e621fb7c8dc147419b28e1702f58a0177ff8308a76fa295c71f3e7827849f5d9", size = 488462, upload-time = "2026-02-28T02:16:22.616Z" }, + { url = "https://files.pythonhosted.org/packages/5d/10/ccc22c52802223f2368731964ddd117799e1390ffc39dbb31634a83022ee/regex-2026.2.28-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0d5bef2031cbf38757a0b0bc4298bb4824b6332d28edc16b39247228fbdbad97", size = 290774, upload-time = "2026-02-28T02:16:23.993Z" }, + { url = "https://files.pythonhosted.org/packages/62/b9/6796b3bf3101e64117201aaa3a5a030ec677ecf34b3cd6141b5d5c6c67d5/regex-2026.2.28-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bcb399ed84eabf4282587ba151f2732ad8168e66f1d3f85b1d038868fe547703", size = 288724, upload-time = "2026-02-28T02:16:25.403Z" }, + { url = "https://files.pythonhosted.org/packages/9c/02/291c0ae3f3a10cea941d0f5366da1843d8d1fa8a25b0671e20a0e454bb38/regex-2026.2.28-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7c1b34dfa72f826f535b20712afa9bb3ba580020e834f3c69866c5bddbf10098", size = 791924, upload-time = "2026-02-28T02:16:26.863Z" }, + { url = "https://files.pythonhosted.org/packages/0f/57/f0235cc520d9672742196c5c15098f8f703f2758d48d5a7465a56333e496/regex-2026.2.28-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:851fa70df44325e1e4cdb79c5e676e91a78147b1b543db2aec8734d2add30ec2", size = 860095, upload-time = "2026-02-28T02:16:28.772Z" }, + { url = "https://files.pythonhosted.org/packages/b3/7c/393c94cbedda79a0f5f2435ebd01644aba0b338d327eb24b4aa5b8d6c07f/regex-2026.2.28-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:516604edd17b1c2c3e579cf4e9b25a53bf8fa6e7cedddf1127804d3e0140ca64", size = 906583, upload-time = "2026-02-28T02:16:30.977Z" }, + { url = "https://files.pythonhosted.org/packages/2c/73/a72820f47ca5abf2b5d911d0407ba5178fc52cf9780191ed3a54f5f419a2/regex-2026.2.28-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e7ce83654d1ab701cb619285a18a8e5a889c1216d746ddc710c914ca5fd71022", size = 800234, upload-time = "2026-02-28T02:16:32.55Z" }, + { url = "https://files.pythonhosted.org/packages/34/b3/6e6a4b7b31fa998c4cf159a12cbeaf356386fbd1a8be743b1e80a3da51e4/regex-2026.2.28-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f2791948f7c70bb9335a9102df45e93d428f4b8128020d85920223925d73b9e1", size = 772803, upload-time = "2026-02-28T02:16:34.029Z" }, + { url = "https://files.pythonhosted.org/packages/10/e7/5da0280c765d5a92af5e1cd324b3fe8464303189cbaa449de9a71910e273/regex-2026.2.28-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:03a83cc26aa2acda6b8b9dfe748cf9e84cbd390c424a1de34fdcef58961a297a", size = 781117, upload-time = "2026-02-28T02:16:36.253Z" }, + { url = "https://files.pythonhosted.org/packages/76/39/0b8d7efb256ae34e1b8157acc1afd8758048a1cf0196e1aec2e71fd99f4b/regex-2026.2.28-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:ec6f5674c5dc836994f50f1186dd1fafde4be0666aae201ae2fcc3d29d8adf27", size = 854224, upload-time = "2026-02-28T02:16:38.119Z" }, + { url = "https://files.pythonhosted.org/packages/21/ff/a96d483ebe8fe6d1c67907729202313895d8de8495569ec319c6f29d0438/regex-2026.2.28-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:50c2fc924749543e0eacc93ada6aeeb3ea5f6715825624baa0dccaec771668ae", size = 761898, upload-time = "2026-02-28T02:16:40.333Z" }, + { url = "https://files.pythonhosted.org/packages/89/bd/d4f2e75cb4a54b484e796017e37c0d09d8a0a837de43d17e238adf163f4e/regex-2026.2.28-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:ba55c50f408fb5c346a3a02d2ce0ebc839784e24f7c9684fde328ff063c3cdea", size = 844832, upload-time = "2026-02-28T02:16:41.875Z" }, + { url = "https://files.pythonhosted.org/packages/8a/a7/428a135cf5e15e4e11d1e696eb2bf968362f8ea8a5f237122e96bc2ae950/regex-2026.2.28-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:edb1b1b3a5576c56f08ac46f108c40333f222ebfd5cf63afdfa3aab0791ebe5b", size = 788347, upload-time = "2026-02-28T02:16:43.472Z" }, + { url = "https://files.pythonhosted.org/packages/a9/59/68691428851cf9c9c3707217ab1d9b47cfeec9d153a49919e6c368b9e926/regex-2026.2.28-cp311-cp311-win32.whl", hash = "sha256:948c12ef30ecedb128903c2c2678b339746eb7c689c5c21957c4a23950c96d15", size = 266033, upload-time = "2026-02-28T02:16:45.094Z" }, + { url = "https://files.pythonhosted.org/packages/42/8b/1483de1c57024e89296cbcceb9cccb3f625d416ddb46e570be185c9b05a9/regex-2026.2.28-cp311-cp311-win_amd64.whl", hash = "sha256:fd63453f10d29097cc3dc62d070746523973fb5aa1c66d25f8558bebd47fed61", size = 277978, upload-time = "2026-02-28T02:16:46.75Z" }, + { url = "https://files.pythonhosted.org/packages/a4/36/abec45dc6e7252e3dbc797120496e43bb5730a7abf0d9cb69340696a2f2d/regex-2026.2.28-cp311-cp311-win_arm64.whl", hash = "sha256:00f2b8d9615aa165fdff0a13f1a92049bfad555ee91e20d246a51aa0b556c60a", size = 270340, upload-time = "2026-02-28T02:16:48.626Z" }, + { url = "https://files.pythonhosted.org/packages/07/42/9061b03cf0fc4b5fa2c3984cbbaed54324377e440a5c5a29d29a72518d62/regex-2026.2.28-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:fcf26c3c6d0da98fada8ae4ef0aa1c3405a431c0a77eb17306d38a89b02adcd7", size = 489574, upload-time = "2026-02-28T02:16:50.455Z" }, + { url = "https://files.pythonhosted.org/packages/77/83/0c8a5623a233015595e3da499c5a1c13720ac63c107897a6037bb97af248/regex-2026.2.28-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:02473c954af35dd2defeb07e44182f5705b30ea3f351a7cbffa9177beb14da5d", size = 291426, upload-time = "2026-02-28T02:16:52.52Z" }, + { url = "https://files.pythonhosted.org/packages/9e/06/3ef1ac6910dc3295ebd71b1f9bfa737e82cfead211a18b319d45f85ddd09/regex-2026.2.28-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9b65d33a17101569f86d9c5966a8b1d7fbf8afdda5a8aa219301b0a80f58cf7d", size = 289200, upload-time = "2026-02-28T02:16:54.08Z" }, + { url = "https://files.pythonhosted.org/packages/dd/c9/8cc8d850b35ab5650ff6756a1cb85286e2000b66c97520b29c1587455344/regex-2026.2.28-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e71dcecaa113eebcc96622c17692672c2d104b1d71ddf7adeda90da7ddeb26fc", size = 796765, upload-time = "2026-02-28T02:16:55.905Z" }, + { url = "https://files.pythonhosted.org/packages/e9/5d/57702597627fc23278ebf36fbb497ac91c0ce7fec89ac6c81e420ca3e38c/regex-2026.2.28-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:481df4623fa4969c8b11f3433ed7d5e3dc9cec0f008356c3212b3933fb77e3d8", size = 863093, upload-time = "2026-02-28T02:16:58.094Z" }, + { url = "https://files.pythonhosted.org/packages/02/6d/f3ecad537ca2811b4d26b54ca848cf70e04fcfc138667c146a9f3157779c/regex-2026.2.28-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:64e7c6ad614573e0640f271e811a408d79a9e1fe62a46adb602f598df42a818d", size = 909455, upload-time = "2026-02-28T02:17:00.918Z" }, + { url = "https://files.pythonhosted.org/packages/9e/40/bb226f203caa22c1043c1ca79b36340156eca0f6a6742b46c3bb222a3a57/regex-2026.2.28-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6b08a06976ff4fb0d83077022fde3eca06c55432bb997d8c0495b9a4e9872f4", size = 802037, upload-time = "2026-02-28T02:17:02.842Z" }, + { url = "https://files.pythonhosted.org/packages/44/7c/c6d91d8911ac6803b45ca968e8e500c46934e58c0903cbc6d760ee817a0a/regex-2026.2.28-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:864cdd1a2ef5716b0ab468af40139e62ede1b3a53386b375ec0786bb6783fc05", size = 775113, upload-time = "2026-02-28T02:17:04.506Z" }, + { url = "https://files.pythonhosted.org/packages/dc/8d/4a9368d168d47abd4158580b8c848709667b1cd293ff0c0c277279543bd0/regex-2026.2.28-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:511f7419f7afab475fd4d639d4aedfc54205bcb0800066753ef68a59f0f330b5", size = 784194, upload-time = "2026-02-28T02:17:06.888Z" }, + { url = "https://files.pythonhosted.org/packages/cc/bf/2c72ab5d8b7be462cb1651b5cc333da1d0068740342f350fcca3bca31947/regex-2026.2.28-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:b42f7466e32bf15a961cf09f35fa6323cc72e64d3d2c990b10de1274a5da0a59", size = 856846, upload-time = "2026-02-28T02:17:09.11Z" }, + { url = "https://files.pythonhosted.org/packages/7c/f4/6b65c979bb6d09f51bb2d2a7bc85de73c01ec73335d7ddd202dcb8cd1c8f/regex-2026.2.28-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:8710d61737b0c0ce6836b1da7109f20d495e49b3809f30e27e9560be67a257bf", size = 763516, upload-time = "2026-02-28T02:17:11.004Z" }, + { url = "https://files.pythonhosted.org/packages/8e/32/29ea5e27400ee86d2cc2b4e80aa059df04eaf78b4f0c18576ae077aeff68/regex-2026.2.28-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:4390c365fd2d45278f45afd4673cb90f7285f5701607e3ad4274df08e36140ae", size = 849278, upload-time = "2026-02-28T02:17:12.693Z" }, + { url = "https://files.pythonhosted.org/packages/1d/91/3233d03b5f865111cd517e1c95ee8b43e8b428d61fa73764a80c9bb6f537/regex-2026.2.28-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:cb3b1db8ff6c7b8bf838ab05583ea15230cb2f678e569ab0e3a24d1e8320940b", size = 790068, upload-time = "2026-02-28T02:17:14.9Z" }, + { url = "https://files.pythonhosted.org/packages/76/92/abc706c1fb03b4580a09645b206a3fc032f5a9f457bc1a8038ac555658ab/regex-2026.2.28-cp312-cp312-win32.whl", hash = "sha256:f8ed9a5d4612df9d4de15878f0bc6aa7a268afbe5af21a3fdd97fa19516e978c", size = 266416, upload-time = "2026-02-28T02:17:17.15Z" }, + { url = "https://files.pythonhosted.org/packages/fa/06/2a6f7dff190e5fa9df9fb4acf2fdf17a1aa0f7f54596cba8de608db56b3a/regex-2026.2.28-cp312-cp312-win_amd64.whl", hash = "sha256:01d65fd24206c8e1e97e2e31b286c59009636c022eb5d003f52760b0f42155d4", size = 277297, upload-time = "2026-02-28T02:17:18.723Z" }, + { url = "https://files.pythonhosted.org/packages/b7/f0/58a2484851fadf284458fdbd728f580d55c1abac059ae9f048c63b92f427/regex-2026.2.28-cp312-cp312-win_arm64.whl", hash = "sha256:c0b5ccbb8ffb433939d248707d4a8b31993cb76ab1a0187ca886bf50e96df952", size = 270408, upload-time = "2026-02-28T02:17:20.328Z" }, + { url = "https://files.pythonhosted.org/packages/87/f6/dc9ef48c61b79c8201585bf37fa70cd781977da86e466cd94e8e95d2443b/regex-2026.2.28-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6d63a07e5ec8ce7184452cb00c41c37b49e67dc4f73b2955b5b8e782ea970784", size = 489311, upload-time = "2026-02-28T02:17:22.591Z" }, + { url = "https://files.pythonhosted.org/packages/95/c8/c20390f2232d3f7956f420f4ef1852608ad57aa26c3dd78516cb9f3dc913/regex-2026.2.28-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e59bc8f30414d283ae8ee1617b13d8112e7135cb92830f0ec3688cb29152585a", size = 291285, upload-time = "2026-02-28T02:17:24.355Z" }, + { url = "https://files.pythonhosted.org/packages/d2/a6/ba1068a631ebd71a230e7d8013fcd284b7c89c35f46f34a7da02082141b1/regex-2026.2.28-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:de0cf053139f96219ccfabb4a8dd2d217c8c82cb206c91d9f109f3f552d6b43d", size = 289051, upload-time = "2026-02-28T02:17:26.722Z" }, + { url = "https://files.pythonhosted.org/packages/1d/1b/7cc3b7af4c244c204b7a80924bd3d85aecd9ba5bc82b485c5806ee8cda9e/regex-2026.2.28-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fb4db2f17e6484904f986c5a657cec85574c76b5c5e61c7aae9ffa1bc6224f95", size = 796842, upload-time = "2026-02-28T02:17:29.064Z" }, + { url = "https://files.pythonhosted.org/packages/24/87/26bd03efc60e0d772ac1e7b60a2e6325af98d974e2358f659c507d3c76db/regex-2026.2.28-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:52b017b35ac2214d0db5f4f90e303634dc44e4aba4bd6235a27f97ecbe5b0472", size = 863083, upload-time = "2026-02-28T02:17:31.363Z" }, + { url = "https://files.pythonhosted.org/packages/ae/54/aeaf4afb1aa0a65e40de52a61dc2ac5b00a83c6cb081c8a1d0dda74f3010/regex-2026.2.28-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:69fc560ccbf08a09dc9b52ab69cacfae51e0ed80dc5693078bdc97db2f91ae96", size = 909412, upload-time = "2026-02-28T02:17:33.248Z" }, + { url = "https://files.pythonhosted.org/packages/12/2f/049901def913954e640d199bbc6a7ca2902b6aeda0e5da9d17f114100ec2/regex-2026.2.28-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e61eea47230eba62a31f3e8a0e3164d0f37ef9f40529fb2c79361bc6b53d2a92", size = 802101, upload-time = "2026-02-28T02:17:35.053Z" }, + { url = "https://files.pythonhosted.org/packages/7d/a5/512fb9ff7f5b15ea204bb1967ebb649059446decacccb201381f9fa6aad4/regex-2026.2.28-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4f5c0b182ad4269e7381b7c27fdb0408399881f7a92a4624fd5487f2971dfc11", size = 775260, upload-time = "2026-02-28T02:17:37.692Z" }, + { url = "https://files.pythonhosted.org/packages/d1/a8/9a92935878aba19bd72706b9db5646a6f993d99b3f6ed42c02ec8beb1d61/regex-2026.2.28-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:96f6269a2882fbb0ee76967116b83679dc628e68eaea44e90884b8d53d833881", size = 784311, upload-time = "2026-02-28T02:17:39.855Z" }, + { url = "https://files.pythonhosted.org/packages/09/d3/fc51a8a738a49a6b6499626580554c9466d3ea561f2b72cfdc72e4149773/regex-2026.2.28-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b5acd4b6a95f37c3c3828e5d053a7d4edaedb85de551db0153754924cb7c83e3", size = 856876, upload-time = "2026-02-28T02:17:42.317Z" }, + { url = "https://files.pythonhosted.org/packages/08/b7/2e641f3d084b120ca4c52e8c762a78da0b32bf03ef546330db3e2635dc5f/regex-2026.2.28-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:2234059cfe33d9813a3677ef7667999caea9eeaa83fef98eb6ce15c6cf9e0215", size = 763632, upload-time = "2026-02-28T02:17:45.073Z" }, + { url = "https://files.pythonhosted.org/packages/fe/6d/0009021d97e79ee99f3d8641f0a8d001eed23479ade4c3125a5480bf3e2d/regex-2026.2.28-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:c15af43c72a7fb0c97cbc66fa36a43546eddc5c06a662b64a0cbf30d6ac40944", size = 849320, upload-time = "2026-02-28T02:17:47.192Z" }, + { url = "https://files.pythonhosted.org/packages/05/7a/51cfbad5758f8edae430cb21961a9c8d04bce1dae4d2d18d4186eec7cfa1/regex-2026.2.28-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9185cc63359862a6e80fe97f696e04b0ad9a11c4ac0a4a927f979f611bfe3768", size = 790152, upload-time = "2026-02-28T02:17:49.067Z" }, + { url = "https://files.pythonhosted.org/packages/90/3d/a83e2b6b3daa142acb8c41d51de3876186307d5cb7490087031747662500/regex-2026.2.28-cp313-cp313-win32.whl", hash = "sha256:fb66e5245db9652abd7196ace599b04d9c0e4aa7c8f0e2803938377835780081", size = 266398, upload-time = "2026-02-28T02:17:50.744Z" }, + { url = "https://files.pythonhosted.org/packages/85/4f/16e9ebb1fe5425e11b9596c8d57bf8877dcb32391da0bfd33742e3290637/regex-2026.2.28-cp313-cp313-win_amd64.whl", hash = "sha256:71a911098be38c859ceb3f9a9ce43f4ed9f4c6720ad8684a066ea246b76ad9ff", size = 277282, upload-time = "2026-02-28T02:17:53.074Z" }, + { url = "https://files.pythonhosted.org/packages/07/b4/92851335332810c5a89723bf7a7e35c7209f90b7d4160024501717b28cc9/regex-2026.2.28-cp313-cp313-win_arm64.whl", hash = "sha256:39bb5727650b9a0275c6a6690f9bb3fe693a7e6cc5c3155b1240aedf8926423e", size = 270382, upload-time = "2026-02-28T02:17:54.888Z" }, + { url = "https://files.pythonhosted.org/packages/24/07/6c7e4cec1e585959e96cbc24299d97e4437a81173217af54f1804994e911/regex-2026.2.28-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:97054c55db06ab020342cc0d35d6f62a465fa7662871190175f1ad6c655c028f", size = 492541, upload-time = "2026-02-28T02:17:56.813Z" }, + { url = "https://files.pythonhosted.org/packages/7c/13/55eb22ada7f43d4f4bb3815b6132183ebc331c81bd496e2d1f3b8d862e0d/regex-2026.2.28-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0d25a10811de831c2baa6aef3c0be91622f44dd8d31dd12e69f6398efb15e48b", size = 292984, upload-time = "2026-02-28T02:17:58.538Z" }, + { url = "https://files.pythonhosted.org/packages/5b/11/c301f8cb29ce9644a5ef85104c59244e6e7e90994a0f458da4d39baa8e17/regex-2026.2.28-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:d6cfe798d8da41bb1862ed6e0cba14003d387c3c0c4a5d45591076ae9f0ce2f8", size = 291509, upload-time = "2026-02-28T02:18:00.208Z" }, + { url = "https://files.pythonhosted.org/packages/b5/43/aabe384ec1994b91796e903582427bc2ffaed9c4103819ed3c16d8e749f3/regex-2026.2.28-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fd0ce43e71d825b7c0661f9c54d4d74bd97c56c3fd102a8985bcfea48236bacb", size = 809429, upload-time = "2026-02-28T02:18:02.328Z" }, + { url = "https://files.pythonhosted.org/packages/04/b8/8d2d987a816720c4f3109cee7c06a4b24ad0e02d4fc74919ab619e543737/regex-2026.2.28-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:00945d007fd74a9084d2ab79b695b595c6b7ba3698972fadd43e23230c6979c1", size = 869422, upload-time = "2026-02-28T02:18:04.23Z" }, + { url = "https://files.pythonhosted.org/packages/fc/ad/2c004509e763c0c3719f97c03eca26473bffb3868d54c5f280b8cd4f9e3d/regex-2026.2.28-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bec23c11cbbf09a4df32fe50d57cbdd777bc442269b6e39a1775654f1c95dee2", size = 915175, upload-time = "2026-02-28T02:18:06.791Z" }, + { url = "https://files.pythonhosted.org/packages/55/c2/fd429066da487ef555a9da73bf214894aec77fc8c66a261ee355a69871a8/regex-2026.2.28-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5cdcc17d935c8f9d3f4db5c2ebe2640c332e3822ad5d23c2f8e0228e6947943a", size = 812044, upload-time = "2026-02-28T02:18:08.736Z" }, + { url = "https://files.pythonhosted.org/packages/5b/ca/feedb7055c62a3f7f659971bf45f0e0a87544b6b0cf462884761453f97c5/regex-2026.2.28-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a448af01e3d8031c89c5d902040b124a5e921a25c4e5e07a861ca591ce429341", size = 782056, upload-time = "2026-02-28T02:18:10.777Z" }, + { url = "https://files.pythonhosted.org/packages/95/30/1aa959ed0d25c1dd7dd5047ea8ba482ceaef38ce363c401fd32a6b923e60/regex-2026.2.28-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:10d28e19bd4888e4abf43bd3925f3c134c52fdf7259219003588a42e24c2aa25", size = 798743, upload-time = "2026-02-28T02:18:13.025Z" }, + { url = "https://files.pythonhosted.org/packages/3b/1f/dadb9cf359004784051c897dcf4d5d79895f73a1bbb7b827abaa4814ae80/regex-2026.2.28-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:99985a2c277dcb9ccb63f937451af5d65177af1efdeb8173ac55b61095a0a05c", size = 864633, upload-time = "2026-02-28T02:18:16.84Z" }, + { url = "https://files.pythonhosted.org/packages/a7/f1/b9a25eb24e1cf79890f09e6ec971ee5b511519f1851de3453bc04f6c902b/regex-2026.2.28-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:e1e7b24cb3ae9953a560c563045d1ba56ee4749fbd05cf21ba571069bd7be81b", size = 770862, upload-time = "2026-02-28T02:18:18.892Z" }, + { url = "https://files.pythonhosted.org/packages/02/9a/c5cb10b7aa6f182f9247a30cc9527e326601f46f4df864ac6db588d11fcd/regex-2026.2.28-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:d8511a01d0e4ee1992eb3ba19e09bc1866fe03f05129c3aec3fdc4cbc77aad3f", size = 854788, upload-time = "2026-02-28T02:18:21.475Z" }, + { url = "https://files.pythonhosted.org/packages/0a/50/414ba0731c4bd40b011fa4703b2cc86879ec060c64f2a906e65a56452589/regex-2026.2.28-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:aaffaecffcd2479ce87aa1e74076c221700b7c804e48e98e62500ee748f0f550", size = 800184, upload-time = "2026-02-28T02:18:23.492Z" }, + { url = "https://files.pythonhosted.org/packages/69/50/0c7290987f97e7e6830b0d853f69dc4dc5852c934aae63e7fdcd76b4c383/regex-2026.2.28-cp313-cp313t-win32.whl", hash = "sha256:ef77bdde9c9eba3f7fa5b58084b29bbcc74bcf55fdbeaa67c102a35b5bd7e7cc", size = 269137, upload-time = "2026-02-28T02:18:25.375Z" }, + { url = "https://files.pythonhosted.org/packages/68/80/ef26ff90e74ceb4051ad6efcbbb8a4be965184a57e879ebcbdef327d18fa/regex-2026.2.28-cp313-cp313t-win_amd64.whl", hash = "sha256:98adf340100cbe6fbaf8e6dc75e28f2c191b1be50ffefe292fb0e6f6eefdb0d8", size = 280682, upload-time = "2026-02-28T02:18:27.205Z" }, + { url = "https://files.pythonhosted.org/packages/69/8b/fbad9c52e83ffe8f97e3ed1aa0516e6dff6bb633a41da9e64645bc7efdc5/regex-2026.2.28-cp313-cp313t-win_arm64.whl", hash = "sha256:2fb950ac1d88e6b6a9414381f403797b236f9fa17e1eee07683af72b1634207b", size = 271735, upload-time = "2026-02-28T02:18:29.015Z" }, + { url = "https://files.pythonhosted.org/packages/cf/03/691015f7a7cb1ed6dacb2ea5de5682e4858e05a4c5506b2839cd533bbcd6/regex-2026.2.28-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:78454178c7df31372ea737996fb7f36b3c2c92cccc641d251e072478afb4babc", size = 489497, upload-time = "2026-02-28T02:18:30.889Z" }, + { url = "https://files.pythonhosted.org/packages/c6/ba/8db8fd19afcbfa0e1036eaa70c05f20ca8405817d4ad7a38a6b4c2f031ac/regex-2026.2.28-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:5d10303dd18cedfd4d095543998404df656088240bcfd3cd20a8f95b861f74bd", size = 291295, upload-time = "2026-02-28T02:18:33.426Z" }, + { url = "https://files.pythonhosted.org/packages/5a/79/9aa0caf089e8defef9b857b52fc53801f62ff868e19e5c83d4a96612eba1/regex-2026.2.28-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:19a9c9e0a8f24f39d575a6a854d516b48ffe4cbdcb9de55cb0570a032556ecff", size = 289275, upload-time = "2026-02-28T02:18:35.247Z" }, + { url = "https://files.pythonhosted.org/packages/eb/26/ee53117066a30ef9c883bf1127eece08308ccf8ccd45c45a966e7a665385/regex-2026.2.28-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:09500be324f49b470d907b3ef8af9afe857f5cca486f853853f7945ddbf75911", size = 797176, upload-time = "2026-02-28T02:18:37.15Z" }, + { url = "https://files.pythonhosted.org/packages/05/1b/67fb0495a97259925f343ae78b5d24d4a6624356ae138b57f18bd43006e4/regex-2026.2.28-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:fb1c4ff62277d87a7335f2c1ea4e0387b8f2b3ad88a64efd9943906aafad4f33", size = 863813, upload-time = "2026-02-28T02:18:39.478Z" }, + { url = "https://files.pythonhosted.org/packages/a0/1d/93ac9bbafc53618091c685c7ed40239a90bf9f2a82c983f0baa97cb7ae07/regex-2026.2.28-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b8b3f1be1738feadc69f62daa250c933e85c6f34fa378f54a7ff43807c1b9117", size = 908678, upload-time = "2026-02-28T02:18:41.619Z" }, + { url = "https://files.pythonhosted.org/packages/c7/7a/a8f5e0561702b25239846a16349feece59712ae20598ebb205580332a471/regex-2026.2.28-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dc8ed8c3f41c27acb83f7b6a9eb727a73fc6663441890c5cb3426a5f6a91ce7d", size = 801528, upload-time = "2026-02-28T02:18:43.624Z" }, + { url = "https://files.pythonhosted.org/packages/96/5d/ed6d4cbde80309854b1b9f42d9062fee38ade15f7eb4909f6ef2440403b5/regex-2026.2.28-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fa539be029844c0ce1114762d2952ab6cfdd7c7c9bd72e0db26b94c3c36dcc5a", size = 775373, upload-time = "2026-02-28T02:18:46.102Z" }, + { url = "https://files.pythonhosted.org/packages/6a/e9/6e53c34e8068b9deec3e87210086ecb5b9efebdefca6b0d3fa43d66dcecb/regex-2026.2.28-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7900157786428a79615a8264dac1f12c9b02957c473c8110c6b1f972dcecaddf", size = 784859, upload-time = "2026-02-28T02:18:48.269Z" }, + { url = "https://files.pythonhosted.org/packages/48/3c/736e1c7ca7f0dcd2ae33819888fdc69058a349b7e5e84bc3e2f296bbf794/regex-2026.2.28-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:0b1d2b07614d95fa2bf8a63fd1e98bd8fa2b4848dc91b1efbc8ba219fdd73952", size = 857813, upload-time = "2026-02-28T02:18:50.576Z" }, + { url = "https://files.pythonhosted.org/packages/6e/7c/48c4659ad9da61f58e79dbe8c05223e0006696b603c16eb6b5cbfbb52c27/regex-2026.2.28-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:b389c61aa28a79c2e0527ac36da579869c2e235a5b208a12c5b5318cda2501d8", size = 763705, upload-time = "2026-02-28T02:18:52.59Z" }, + { url = "https://files.pythonhosted.org/packages/cf/a1/bc1c261789283128165f71b71b4b221dd1b79c77023752a6074c102f18d8/regex-2026.2.28-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:f467cb602f03fbd1ab1908f68b53c649ce393fde056628dc8c7e634dab6bfc07", size = 848734, upload-time = "2026-02-28T02:18:54.595Z" }, + { url = "https://files.pythonhosted.org/packages/10/d8/979407faf1397036e25a5ae778157366a911c0f382c62501009f4957cf86/regex-2026.2.28-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e8c8cb2deba42f5ec1ede46374e990f8adc5e6456a57ac1a261b19be6f28e4e6", size = 789871, upload-time = "2026-02-28T02:18:57.34Z" }, + { url = "https://files.pythonhosted.org/packages/03/23/da716821277115fcb1f4e3de1e5dc5023a1e6533598c486abf5448612579/regex-2026.2.28-cp314-cp314-win32.whl", hash = "sha256:9036b400b20e4858d56d117108d7813ed07bb7803e3eed766675862131135ca6", size = 271825, upload-time = "2026-02-28T02:18:59.202Z" }, + { url = "https://files.pythonhosted.org/packages/91/ff/90696f535d978d5f16a52a419be2770a8d8a0e7e0cfecdbfc31313df7fab/regex-2026.2.28-cp314-cp314-win_amd64.whl", hash = "sha256:1d367257cd86c1cbb97ea94e77b373a0bbc2224976e247f173d19e8f18b4afa7", size = 280548, upload-time = "2026-02-28T02:19:01.049Z" }, + { url = "https://files.pythonhosted.org/packages/69/f9/5e1b5652fc0af3fcdf7677e7df3ad2a0d47d669b34ac29a63bb177bb731b/regex-2026.2.28-cp314-cp314-win_arm64.whl", hash = "sha256:5e68192bb3a1d6fb2836da24aa494e413ea65853a21505e142e5b1064a595f3d", size = 273444, upload-time = "2026-02-28T02:19:03.255Z" }, + { url = "https://files.pythonhosted.org/packages/d3/eb/8389f9e940ac89bcf58d185e230a677b4fd07c5f9b917603ad5c0f8fa8fe/regex-2026.2.28-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:a5dac14d0872eeb35260a8e30bac07ddf22adc1e3a0635b52b02e180d17c9c7e", size = 492546, upload-time = "2026-02-28T02:19:05.378Z" }, + { url = "https://files.pythonhosted.org/packages/7b/c7/09441d27ce2a6fa6a61ea3150ea4639c1dcda9b31b2ea07b80d6937b24dd/regex-2026.2.28-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:ec0c608b7a7465ffadb344ed7c987ff2f11ee03f6a130b569aa74d8a70e8333c", size = 292986, upload-time = "2026-02-28T02:19:07.24Z" }, + { url = "https://files.pythonhosted.org/packages/fb/69/4144b60ed7760a6bd235e4087041f487aa4aa62b45618ce018b0c14833ea/regex-2026.2.28-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c7815afb0ca45456613fdaf60ea9c993715511c8d53a83bc468305cbc0ee23c7", size = 291518, upload-time = "2026-02-28T02:19:09.698Z" }, + { url = "https://files.pythonhosted.org/packages/2d/be/77e5426cf5948c82f98c53582009ca9e94938c71f73a8918474f2e2990bb/regex-2026.2.28-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b059e71ec363968671693a78c5053bd9cb2fe410f9b8e4657e88377ebd603a2e", size = 809464, upload-time = "2026-02-28T02:19:12.494Z" }, + { url = "https://files.pythonhosted.org/packages/45/99/2c8c5ac90dc7d05c6e7d8e72c6a3599dc08cd577ac476898e91ca787d7f1/regex-2026.2.28-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b8cf76f1a29f0e99dcfd7aef1551a9827588aae5a737fe31442021165f1920dc", size = 869553, upload-time = "2026-02-28T02:19:15.151Z" }, + { url = "https://files.pythonhosted.org/packages/53/34/daa66a342f0271e7737003abf6c3097aa0498d58c668dbd88362ef94eb5d/regex-2026.2.28-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:180e08a435a0319e6a4821c3468da18dc7001987e1c17ae1335488dfe7518dd8", size = 915289, upload-time = "2026-02-28T02:19:17.331Z" }, + { url = "https://files.pythonhosted.org/packages/c5/c7/e22c2aaf0a12e7e22ab19b004bb78d32ca1ecc7ef245949935463c5567de/regex-2026.2.28-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1e496956106fd59ba6322a8ea17141a27c5040e5ee8f9433ae92d4e5204462a0", size = 812156, upload-time = "2026-02-28T02:19:20.011Z" }, + { url = "https://files.pythonhosted.org/packages/7f/bb/2dc18c1efd9051cf389cd0d7a3a4d90f6804b9fff3a51b5dc3c85b935f71/regex-2026.2.28-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bba2b18d70eeb7b79950f12f633beeecd923f7c9ad6f6bae28e59b4cb3ab046b", size = 782215, upload-time = "2026-02-28T02:19:22.047Z" }, + { url = "https://files.pythonhosted.org/packages/17/1e/9e4ec9b9013931faa32226ec4aa3c71fe664a6d8a2b91ac56442128b332f/regex-2026.2.28-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:6db7bfae0f8a2793ff1f7021468ea55e2699d0790eb58ee6ab36ae43aa00bc5b", size = 798925, upload-time = "2026-02-28T02:19:24.173Z" }, + { url = "https://files.pythonhosted.org/packages/71/57/a505927e449a9ccb41e2cc8d735e2abe3444b0213d1cf9cb364a8c1f2524/regex-2026.2.28-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:d0b02e8b7e5874b48ae0f077ecca61c1a6a9f9895e9c6dfb191b55b242862033", size = 864701, upload-time = "2026-02-28T02:19:26.376Z" }, + { url = "https://files.pythonhosted.org/packages/a6/ad/c62cb60cdd93e13eac5b3d9d6bd5d284225ed0e3329426f94d2552dd7cca/regex-2026.2.28-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:25b6eb660c5cf4b8c3407a1ed462abba26a926cc9965e164268a3267bcc06a43", size = 770899, upload-time = "2026-02-28T02:19:29.38Z" }, + { url = "https://files.pythonhosted.org/packages/3c/5a/874f861f5c3d5ab99633e8030dee1bc113db8e0be299d1f4b07f5b5ec349/regex-2026.2.28-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:5a932ea8ad5d0430351ff9c76c8db34db0d9f53c1d78f06022a21f4e290c5c18", size = 854727, upload-time = "2026-02-28T02:19:31.494Z" }, + { url = "https://files.pythonhosted.org/packages/6b/ca/d2c03b0efde47e13db895b975b2be6a73ed90b8ba963677927283d43bf74/regex-2026.2.28-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:1c2c95e1a2b0f89d01e821ff4de1be4b5d73d1f4b0bf679fa27c1ad8d2327f1a", size = 800366, upload-time = "2026-02-28T02:19:34.248Z" }, + { url = "https://files.pythonhosted.org/packages/14/bd/ee13b20b763b8989f7c75d592bfd5de37dc1181814a2a2747fedcf97e3ba/regex-2026.2.28-cp314-cp314t-win32.whl", hash = "sha256:bbb882061f742eb5d46f2f1bd5304055be0a66b783576de3d7eef1bed4778a6e", size = 274936, upload-time = "2026-02-28T02:19:36.313Z" }, + { url = "https://files.pythonhosted.org/packages/cb/e7/d8020e39414c93af7f0d8688eabcecece44abfd5ce314b21dfda0eebd3d8/regex-2026.2.28-cp314-cp314t-win_amd64.whl", hash = "sha256:6591f281cb44dc13de9585b552cec6fc6cf47fb2fe7a48892295ee9bc4a612f9", size = 284779, upload-time = "2026-02-28T02:19:38.625Z" }, + { url = "https://files.pythonhosted.org/packages/13/c0/ad225f4a405827486f1955283407cf758b6d2fb966712644c5f5aef33d1b/regex-2026.2.28-cp314-cp314t-win_arm64.whl", hash = "sha256:dee50f1be42222f89767b64b283283ef963189da0dda4a515aa54a5563c62dec", size = 275010, upload-time = "2026-02-28T02:19:40.65Z" }, ] [[package]] @@ -2659,26 +2537,17 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, ] -[[package]] -name = "socksio" -version = "1.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f8/5c/48a7d9495be3d1c651198fd99dbb6ce190e2274d0f28b9051307bdec6b85/socksio-1.0.0.tar.gz", hash = "sha256:f88beb3da5b5c38b9890469de67d0cb0f9d494b78b106ca1845f96c10b91c4ac", size = 19055, upload-time = "2020-04-17T15:50:34.664Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/37/c3/6eeb6034408dac0fa653d126c9204ade96b819c936e136c5e8a6897eee9c/socksio-1.0.0-py3-none-any.whl", hash = "sha256:95dc1f15f9b34e8d7b16f06d74b8ccf48f609af32ab33c608d08761c5dcbb1f3", size = 12763, upload-time = "2020-04-17T15:50:31.878Z" }, -] - [[package]] name = "sse-starlette" -version = "3.2.0" +version = "3.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, { name = "starlette" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/8b/8d/00d280c03ffd39aaee0e86ec81e2d3b9253036a0f93f51d10503adef0e65/sse_starlette-3.2.0.tar.gz", hash = "sha256:8127594edfb51abe44eac9c49e59b0b01f1039d0c7461c6fd91d4e03b70da422", size = 27253, upload-time = "2026-01-17T13:11:05.62Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/9f/c3695c2d2d4ef70072c3a06992850498b01c6bc9be531950813716b426fa/sse_starlette-3.3.2.tar.gz", hash = "sha256:678fca55a1945c734d8472a6cad186a55ab02840b4f6786f5ee8770970579dcd", size = 32326, upload-time = "2026-02-28T11:24:34.36Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/96/7f/832f015020844a8b8f7a9cbc103dd76ba8e3875004c41e08440ea3a2b41a/sse_starlette-3.2.0-py3-none-any.whl", hash = "sha256:5876954bd51920fc2cd51baee47a080eb88a37b5b784e615abb0b283f801cdbf", size = 12763, upload-time = "2026-01-17T13:11:03.775Z" }, + { url = "https://files.pythonhosted.org/packages/61/28/8cb142d3fe80c4a2d8af54ca0b003f47ce0ba920974e7990fa6e016402d1/sse_starlette-3.3.2-py3-none-any.whl", hash = "sha256:5c3ea3dad425c601236726af2f27689b74494643f57017cafcb6f8c9acfbb862", size = 14270, upload-time = "2026-02-28T11:24:32.984Z" }, ] [[package]] @@ -2923,112 +2792,124 @@ wheels = [ [[package]] name = "yarl" -version = "1.22.0" +version = "1.23.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "idna" }, { name = "multidict" }, { name = "propcache" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/57/63/0c6ebca57330cd313f6102b16dd57ffaf3ec4c83403dcb45dbd15c6f3ea1/yarl-1.22.0.tar.gz", hash = "sha256:bebf8557577d4401ba8bd9ff33906f1376c877aa78d1fe216ad01b4d6745af71", size = 187169, upload-time = "2025-10-06T14:12:55.963Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4d/27/5ab13fc84c76a0250afd3d26d5936349a35be56ce5785447d6c423b26d92/yarl-1.22.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1ab72135b1f2db3fed3997d7e7dc1b80573c67138023852b6efb336a5eae6511", size = 141607, upload-time = "2025-10-06T14:09:16.298Z" }, - { url = "https://files.pythonhosted.org/packages/6a/a1/d065d51d02dc02ce81501d476b9ed2229d9a990818332242a882d5d60340/yarl-1.22.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:669930400e375570189492dc8d8341301578e8493aec04aebc20d4717f899dd6", size = 94027, upload-time = "2025-10-06T14:09:17.786Z" }, - { url = "https://files.pythonhosted.org/packages/c1/da/8da9f6a53f67b5106ffe902c6fa0164e10398d4e150d85838b82f424072a/yarl-1.22.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:792a2af6d58177ef7c19cbf0097aba92ca1b9cb3ffdd9c7470e156c8f9b5e028", size = 94963, upload-time = "2025-10-06T14:09:19.662Z" }, - { url = "https://files.pythonhosted.org/packages/68/fe/2c1f674960c376e29cb0bec1249b117d11738db92a6ccc4a530b972648db/yarl-1.22.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3ea66b1c11c9150f1372f69afb6b8116f2dd7286f38e14ea71a44eee9ec51b9d", size = 368406, upload-time = "2025-10-06T14:09:21.402Z" }, - { url = "https://files.pythonhosted.org/packages/95/26/812a540e1c3c6418fec60e9bbd38e871eaba9545e94fa5eff8f4a8e28e1e/yarl-1.22.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3e2daa88dc91870215961e96a039ec73e4937da13cf77ce17f9cad0c18df3503", size = 336581, upload-time = "2025-10-06T14:09:22.98Z" }, - { url = "https://files.pythonhosted.org/packages/0b/f5/5777b19e26fdf98563985e481f8be3d8a39f8734147a6ebf459d0dab5a6b/yarl-1.22.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ba440ae430c00eee41509353628600212112cd5018d5def7e9b05ea7ac34eb65", size = 388924, upload-time = "2025-10-06T14:09:24.655Z" }, - { url = "https://files.pythonhosted.org/packages/86/08/24bd2477bd59c0bbd994fe1d93b126e0472e4e3df5a96a277b0a55309e89/yarl-1.22.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e6438cc8f23a9c1478633d216b16104a586b9761db62bfacb6425bac0a36679e", size = 392890, upload-time = "2025-10-06T14:09:26.617Z" }, - { url = "https://files.pythonhosted.org/packages/46/00/71b90ed48e895667ecfb1eaab27c1523ee2fa217433ed77a73b13205ca4b/yarl-1.22.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c52a6e78aef5cf47a98ef8e934755abf53953379b7d53e68b15ff4420e6683d", size = 365819, upload-time = "2025-10-06T14:09:28.544Z" }, - { url = "https://files.pythonhosted.org/packages/30/2d/f715501cae832651d3282387c6a9236cd26bd00d0ff1e404b3dc52447884/yarl-1.22.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3b06bcadaac49c70f4c88af4ffcfbe3dc155aab3163e75777818092478bcbbe7", size = 363601, upload-time = "2025-10-06T14:09:30.568Z" }, - { url = "https://files.pythonhosted.org/packages/f8/f9/a678c992d78e394e7126ee0b0e4e71bd2775e4334d00a9278c06a6cce96a/yarl-1.22.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:6944b2dc72c4d7f7052683487e3677456050ff77fcf5e6204e98caf785ad1967", size = 358072, upload-time = "2025-10-06T14:09:32.528Z" }, - { url = "https://files.pythonhosted.org/packages/2c/d1/b49454411a60edb6fefdcad4f8e6dbba7d8019e3a508a1c5836cba6d0781/yarl-1.22.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:d5372ca1df0f91a86b047d1277c2aaf1edb32d78bbcefffc81b40ffd18f027ed", size = 385311, upload-time = "2025-10-06T14:09:34.634Z" }, - { url = "https://files.pythonhosted.org/packages/87/e5/40d7a94debb8448c7771a916d1861d6609dddf7958dc381117e7ba36d9e8/yarl-1.22.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:51af598701f5299012b8416486b40fceef8c26fc87dc6d7d1f6fc30609ea0aa6", size = 381094, upload-time = "2025-10-06T14:09:36.268Z" }, - { url = "https://files.pythonhosted.org/packages/35/d8/611cc282502381ad855448643e1ad0538957fc82ae83dfe7762c14069e14/yarl-1.22.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b266bd01fedeffeeac01a79ae181719ff848a5a13ce10075adbefc8f1daee70e", size = 370944, upload-time = "2025-10-06T14:09:37.872Z" }, - { url = "https://files.pythonhosted.org/packages/2d/df/fadd00fb1c90e1a5a8bd731fa3d3de2e165e5a3666a095b04e31b04d9cb6/yarl-1.22.0-cp311-cp311-win32.whl", hash = "sha256:a9b1ba5610a4e20f655258d5a1fdc7ebe3d837bb0e45b581398b99eb98b1f5ca", size = 81804, upload-time = "2025-10-06T14:09:39.359Z" }, - { url = "https://files.pythonhosted.org/packages/b5/f7/149bb6f45f267cb5c074ac40c01c6b3ea6d8a620d34b337f6321928a1b4d/yarl-1.22.0-cp311-cp311-win_amd64.whl", hash = "sha256:078278b9b0b11568937d9509b589ee83ef98ed6d561dfe2020e24a9fd08eaa2b", size = 86858, upload-time = "2025-10-06T14:09:41.068Z" }, - { url = "https://files.pythonhosted.org/packages/2b/13/88b78b93ad3f2f0b78e13bfaaa24d11cbc746e93fe76d8c06bf139615646/yarl-1.22.0-cp311-cp311-win_arm64.whl", hash = "sha256:b6a6f620cfe13ccec221fa312139135166e47ae169f8253f72a0abc0dae94376", size = 81637, upload-time = "2025-10-06T14:09:42.712Z" }, - { url = "https://files.pythonhosted.org/packages/75/ff/46736024fee3429b80a165a732e38e5d5a238721e634ab41b040d49f8738/yarl-1.22.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e340382d1afa5d32b892b3ff062436d592ec3d692aeea3bef3a5cfe11bbf8c6f", size = 142000, upload-time = "2025-10-06T14:09:44.631Z" }, - { url = "https://files.pythonhosted.org/packages/5a/9a/b312ed670df903145598914770eb12de1bac44599549b3360acc96878df8/yarl-1.22.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f1e09112a2c31ffe8d80be1b0988fa6a18c5d5cad92a9ffbb1c04c91bfe52ad2", size = 94338, upload-time = "2025-10-06T14:09:46.372Z" }, - { url = "https://files.pythonhosted.org/packages/ba/f5/0601483296f09c3c65e303d60c070a5c19fcdbc72daa061e96170785bc7d/yarl-1.22.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:939fe60db294c786f6b7c2d2e121576628468f65453d86b0fe36cb52f987bd74", size = 94909, upload-time = "2025-10-06T14:09:48.648Z" }, - { url = "https://files.pythonhosted.org/packages/60/41/9a1fe0b73dbcefce72e46cf149b0e0a67612d60bfc90fb59c2b2efdfbd86/yarl-1.22.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e1651bf8e0398574646744c1885a41198eba53dc8a9312b954073f845c90a8df", size = 372940, upload-time = "2025-10-06T14:09:50.089Z" }, - { url = "https://files.pythonhosted.org/packages/17/7a/795cb6dfee561961c30b800f0ed616b923a2ec6258b5def2a00bf8231334/yarl-1.22.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b8a0588521a26bf92a57a1705b77b8b59044cdceccac7151bd8d229e66b8dedb", size = 345825, upload-time = "2025-10-06T14:09:52.142Z" }, - { url = "https://files.pythonhosted.org/packages/d7/93/a58f4d596d2be2ae7bab1a5846c4d270b894958845753b2c606d666744d3/yarl-1.22.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:42188e6a615c1a75bcaa6e150c3fe8f3e8680471a6b10150c5f7e83f47cc34d2", size = 386705, upload-time = "2025-10-06T14:09:54.128Z" }, - { url = "https://files.pythonhosted.org/packages/61/92/682279d0e099d0e14d7fd2e176bd04f48de1484f56546a3e1313cd6c8e7c/yarl-1.22.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f6d2cb59377d99718913ad9a151030d6f83ef420a2b8f521d94609ecc106ee82", size = 396518, upload-time = "2025-10-06T14:09:55.762Z" }, - { url = "https://files.pythonhosted.org/packages/db/0f/0d52c98b8a885aeda831224b78f3be7ec2e1aa4a62091f9f9188c3c65b56/yarl-1.22.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50678a3b71c751d58d7908edc96d332af328839eea883bb554a43f539101277a", size = 377267, upload-time = "2025-10-06T14:09:57.958Z" }, - { url = "https://files.pythonhosted.org/packages/22/42/d2685e35908cbeaa6532c1fc73e89e7f2efb5d8a7df3959ea8e37177c5a3/yarl-1.22.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e8fbaa7cec507aa24ea27a01456e8dd4b6fab829059b69844bd348f2d467124", size = 365797, upload-time = "2025-10-06T14:09:59.527Z" }, - { url = "https://files.pythonhosted.org/packages/a2/83/cf8c7bcc6355631762f7d8bdab920ad09b82efa6b722999dfb05afa6cfac/yarl-1.22.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:433885ab5431bc3d3d4f2f9bd15bfa1614c522b0f1405d62c4f926ccd69d04fa", size = 365535, upload-time = "2025-10-06T14:10:01.139Z" }, - { url = "https://files.pythonhosted.org/packages/25/e1/5302ff9b28f0c59cac913b91fe3f16c59a033887e57ce9ca5d41a3a94737/yarl-1.22.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:b790b39c7e9a4192dc2e201a282109ed2985a1ddbd5ac08dc56d0e121400a8f7", size = 382324, upload-time = "2025-10-06T14:10:02.756Z" }, - { url = "https://files.pythonhosted.org/packages/bf/cd/4617eb60f032f19ae3a688dc990d8f0d89ee0ea378b61cac81ede3e52fae/yarl-1.22.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:31f0b53913220599446872d757257be5898019c85e7971599065bc55065dc99d", size = 383803, upload-time = "2025-10-06T14:10:04.552Z" }, - { url = "https://files.pythonhosted.org/packages/59/65/afc6e62bb506a319ea67b694551dab4a7e6fb7bf604e9bd9f3e11d575fec/yarl-1.22.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a49370e8f711daec68d09b821a34e1167792ee2d24d405cbc2387be4f158b520", size = 374220, upload-time = "2025-10-06T14:10:06.489Z" }, - { url = "https://files.pythonhosted.org/packages/e7/3d/68bf18d50dc674b942daec86a9ba922d3113d8399b0e52b9897530442da2/yarl-1.22.0-cp312-cp312-win32.whl", hash = "sha256:70dfd4f241c04bd9239d53b17f11e6ab672b9f1420364af63e8531198e3f5fe8", size = 81589, upload-time = "2025-10-06T14:10:09.254Z" }, - { url = "https://files.pythonhosted.org/packages/c8/9a/6ad1a9b37c2f72874f93e691b2e7ecb6137fb2b899983125db4204e47575/yarl-1.22.0-cp312-cp312-win_amd64.whl", hash = "sha256:8884d8b332a5e9b88e23f60bb166890009429391864c685e17bd73a9eda9105c", size = 87213, upload-time = "2025-10-06T14:10:11.369Z" }, - { url = "https://files.pythonhosted.org/packages/44/c5/c21b562d1680a77634d748e30c653c3ca918beb35555cff24986fff54598/yarl-1.22.0-cp312-cp312-win_arm64.whl", hash = "sha256:ea70f61a47f3cc93bdf8b2f368ed359ef02a01ca6393916bc8ff877427181e74", size = 81330, upload-time = "2025-10-06T14:10:13.112Z" }, - { url = "https://files.pythonhosted.org/packages/ea/f3/d67de7260456ee105dc1d162d43a019ecad6b91e2f51809d6cddaa56690e/yarl-1.22.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8dee9c25c74997f6a750cd317b8ca63545169c098faee42c84aa5e506c819b53", size = 139980, upload-time = "2025-10-06T14:10:14.601Z" }, - { url = "https://files.pythonhosted.org/packages/01/88/04d98af0b47e0ef42597b9b28863b9060bb515524da0a65d5f4db160b2d5/yarl-1.22.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:01e73b85a5434f89fc4fe27dcda2aff08ddf35e4d47bbbea3bdcd25321af538a", size = 93424, upload-time = "2025-10-06T14:10:16.115Z" }, - { url = "https://files.pythonhosted.org/packages/18/91/3274b215fd8442a03975ce6bee5fe6aa57a8326b29b9d3d56234a1dca244/yarl-1.22.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:22965c2af250d20c873cdbee8ff958fb809940aeb2e74ba5f20aaf6b7ac8c70c", size = 93821, upload-time = "2025-10-06T14:10:17.993Z" }, - { url = "https://files.pythonhosted.org/packages/61/3a/caf4e25036db0f2da4ca22a353dfeb3c9d3c95d2761ebe9b14df8fc16eb0/yarl-1.22.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b4f15793aa49793ec8d1c708ab7f9eded1aa72edc5174cae703651555ed1b601", size = 373243, upload-time = "2025-10-06T14:10:19.44Z" }, - { url = "https://files.pythonhosted.org/packages/6e/9e/51a77ac7516e8e7803b06e01f74e78649c24ee1021eca3d6a739cb6ea49c/yarl-1.22.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e5542339dcf2747135c5c85f68680353d5cb9ffd741c0f2e8d832d054d41f35a", size = 342361, upload-time = "2025-10-06T14:10:21.124Z" }, - { url = "https://files.pythonhosted.org/packages/d4/f8/33b92454789dde8407f156c00303e9a891f1f51a0330b0fad7c909f87692/yarl-1.22.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5c401e05ad47a75869c3ab3e35137f8468b846770587e70d71e11de797d113df", size = 387036, upload-time = "2025-10-06T14:10:22.902Z" }, - { url = "https://files.pythonhosted.org/packages/d9/9a/c5db84ea024f76838220280f732970aa4ee154015d7f5c1bfb60a267af6f/yarl-1.22.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:243dda95d901c733f5b59214d28b0120893d91777cb8aa043e6ef059d3cddfe2", size = 397671, upload-time = "2025-10-06T14:10:24.523Z" }, - { url = "https://files.pythonhosted.org/packages/11/c9/cd8538dc2e7727095e0c1d867bad1e40c98f37763e6d995c1939f5fdc7b1/yarl-1.22.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bec03d0d388060058f5d291a813f21c011041938a441c593374da6077fe21b1b", size = 377059, upload-time = "2025-10-06T14:10:26.406Z" }, - { url = "https://files.pythonhosted.org/packages/a1/b9/ab437b261702ced75122ed78a876a6dec0a1b0f5e17a4ac7a9a2482d8abe/yarl-1.22.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b0748275abb8c1e1e09301ee3cf90c8a99678a4e92e4373705f2a2570d581273", size = 365356, upload-time = "2025-10-06T14:10:28.461Z" }, - { url = "https://files.pythonhosted.org/packages/b2/9d/8e1ae6d1d008a9567877b08f0ce4077a29974c04c062dabdb923ed98e6fe/yarl-1.22.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:47fdb18187e2a4e18fda2c25c05d8251a9e4a521edaed757fef033e7d8498d9a", size = 361331, upload-time = "2025-10-06T14:10:30.541Z" }, - { url = "https://files.pythonhosted.org/packages/ca/5a/09b7be3905962f145b73beb468cdd53db8aa171cf18c80400a54c5b82846/yarl-1.22.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c7044802eec4524fde550afc28edda0dd5784c4c45f0be151a2d3ba017daca7d", size = 382590, upload-time = "2025-10-06T14:10:33.352Z" }, - { url = "https://files.pythonhosted.org/packages/aa/7f/59ec509abf90eda5048b0bc3e2d7b5099dffdb3e6b127019895ab9d5ef44/yarl-1.22.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:139718f35149ff544caba20fce6e8a2f71f1e39b92c700d8438a0b1d2a631a02", size = 385316, upload-time = "2025-10-06T14:10:35.034Z" }, - { url = "https://files.pythonhosted.org/packages/e5/84/891158426bc8036bfdfd862fabd0e0fa25df4176ec793e447f4b85cf1be4/yarl-1.22.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e1b51bebd221006d3d2f95fbe124b22b247136647ae5dcc8c7acafba66e5ee67", size = 374431, upload-time = "2025-10-06T14:10:37.76Z" }, - { url = "https://files.pythonhosted.org/packages/bb/49/03da1580665baa8bef5e8ed34c6df2c2aca0a2f28bf397ed238cc1bbc6f2/yarl-1.22.0-cp313-cp313-win32.whl", hash = "sha256:d3e32536234a95f513bd374e93d717cf6b2231a791758de6c509e3653f234c95", size = 81555, upload-time = "2025-10-06T14:10:39.649Z" }, - { url = "https://files.pythonhosted.org/packages/9a/ee/450914ae11b419eadd067c6183ae08381cfdfcb9798b90b2b713bbebddda/yarl-1.22.0-cp313-cp313-win_amd64.whl", hash = "sha256:47743b82b76d89a1d20b83e60d5c20314cbd5ba2befc9cda8f28300c4a08ed4d", size = 86965, upload-time = "2025-10-06T14:10:41.313Z" }, - { url = "https://files.pythonhosted.org/packages/98/4d/264a01eae03b6cf629ad69bae94e3b0e5344741e929073678e84bf7a3e3b/yarl-1.22.0-cp313-cp313-win_arm64.whl", hash = "sha256:5d0fcda9608875f7d052eff120c7a5da474a6796fe4d83e152e0e4d42f6d1a9b", size = 81205, upload-time = "2025-10-06T14:10:43.167Z" }, - { url = "https://files.pythonhosted.org/packages/88/fc/6908f062a2f77b5f9f6d69cecb1747260831ff206adcbc5b510aff88df91/yarl-1.22.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:719ae08b6972befcba4310e49edb1161a88cdd331e3a694b84466bd938a6ab10", size = 146209, upload-time = "2025-10-06T14:10:44.643Z" }, - { url = "https://files.pythonhosted.org/packages/65/47/76594ae8eab26210b4867be6f49129861ad33da1f1ebdf7051e98492bf62/yarl-1.22.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:47d8a5c446df1c4db9d21b49619ffdba90e77c89ec6e283f453856c74b50b9e3", size = 95966, upload-time = "2025-10-06T14:10:46.554Z" }, - { url = "https://files.pythonhosted.org/packages/ab/ce/05e9828a49271ba6b5b038b15b3934e996980dd78abdfeb52a04cfb9467e/yarl-1.22.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:cfebc0ac8333520d2d0423cbbe43ae43c8838862ddb898f5ca68565e395516e9", size = 97312, upload-time = "2025-10-06T14:10:48.007Z" }, - { url = "https://files.pythonhosted.org/packages/d1/c5/7dffad5e4f2265b29c9d7ec869c369e4223166e4f9206fc2243ee9eea727/yarl-1.22.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4398557cbf484207df000309235979c79c4356518fd5c99158c7d38203c4da4f", size = 361967, upload-time = "2025-10-06T14:10:49.997Z" }, - { url = "https://files.pythonhosted.org/packages/50/b2/375b933c93a54bff7fc041e1a6ad2c0f6f733ffb0c6e642ce56ee3b39970/yarl-1.22.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2ca6fd72a8cd803be290d42f2dec5cdcd5299eeb93c2d929bf060ad9efaf5de0", size = 323949, upload-time = "2025-10-06T14:10:52.004Z" }, - { url = "https://files.pythonhosted.org/packages/66/50/bfc2a29a1d78644c5a7220ce2f304f38248dc94124a326794e677634b6cf/yarl-1.22.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ca1f59c4e1ab6e72f0a23c13fca5430f889634166be85dbf1013683e49e3278e", size = 361818, upload-time = "2025-10-06T14:10:54.078Z" }, - { url = "https://files.pythonhosted.org/packages/46/96/f3941a46af7d5d0f0498f86d71275696800ddcdd20426298e572b19b91ff/yarl-1.22.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6c5010a52015e7c70f86eb967db0f37f3c8bd503a695a49f8d45700144667708", size = 372626, upload-time = "2025-10-06T14:10:55.767Z" }, - { url = "https://files.pythonhosted.org/packages/c1/42/8b27c83bb875cd89448e42cd627e0fb971fa1675c9ec546393d18826cb50/yarl-1.22.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d7672ecf7557476642c88497c2f8d8542f8e36596e928e9bcba0e42e1e7d71f", size = 341129, upload-time = "2025-10-06T14:10:57.985Z" }, - { url = "https://files.pythonhosted.org/packages/49/36/99ca3122201b382a3cf7cc937b95235b0ac944f7e9f2d5331d50821ed352/yarl-1.22.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:3b7c88eeef021579d600e50363e0b6ee4f7f6f728cd3486b9d0f3ee7b946398d", size = 346776, upload-time = "2025-10-06T14:10:59.633Z" }, - { url = "https://files.pythonhosted.org/packages/85/b4/47328bf996acd01a4c16ef9dcd2f59c969f495073616586f78cd5f2efb99/yarl-1.22.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f4afb5c34f2c6fecdcc182dfcfc6af6cccf1aa923eed4d6a12e9d96904e1a0d8", size = 334879, upload-time = "2025-10-06T14:11:01.454Z" }, - { url = "https://files.pythonhosted.org/packages/c2/ad/b77d7b3f14a4283bffb8e92c6026496f6de49751c2f97d4352242bba3990/yarl-1.22.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:59c189e3e99a59cf8d83cbb31d4db02d66cda5a1a4374e8a012b51255341abf5", size = 350996, upload-time = "2025-10-06T14:11:03.452Z" }, - { url = "https://files.pythonhosted.org/packages/81/c8/06e1d69295792ba54d556f06686cbd6a7ce39c22307100e3fb4a2c0b0a1d/yarl-1.22.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:5a3bf7f62a289fa90f1990422dc8dff5a458469ea71d1624585ec3a4c8d6960f", size = 356047, upload-time = "2025-10-06T14:11:05.115Z" }, - { url = "https://files.pythonhosted.org/packages/4b/b8/4c0e9e9f597074b208d18cef227d83aac36184bfbc6eab204ea55783dbc5/yarl-1.22.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:de6b9a04c606978fdfe72666fa216ffcf2d1a9f6a381058d4378f8d7b1e5de62", size = 342947, upload-time = "2025-10-06T14:11:08.137Z" }, - { url = "https://files.pythonhosted.org/packages/e0/e5/11f140a58bf4c6ad7aca69a892bff0ee638c31bea4206748fc0df4ebcb3a/yarl-1.22.0-cp313-cp313t-win32.whl", hash = "sha256:1834bb90991cc2999f10f97f5f01317f99b143284766d197e43cd5b45eb18d03", size = 86943, upload-time = "2025-10-06T14:11:10.284Z" }, - { url = "https://files.pythonhosted.org/packages/31/74/8b74bae38ed7fe6793d0c15a0c8207bbb819cf287788459e5ed230996cdd/yarl-1.22.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ff86011bd159a9d2dfc89c34cfd8aff12875980e3bd6a39ff097887520e60249", size = 93715, upload-time = "2025-10-06T14:11:11.739Z" }, - { url = "https://files.pythonhosted.org/packages/69/66/991858aa4b5892d57aef7ee1ba6b4d01ec3b7eb3060795d34090a3ca3278/yarl-1.22.0-cp313-cp313t-win_arm64.whl", hash = "sha256:7861058d0582b847bc4e3a4a4c46828a410bca738673f35a29ba3ca5db0b473b", size = 83857, upload-time = "2025-10-06T14:11:13.586Z" }, - { url = "https://files.pythonhosted.org/packages/46/b3/e20ef504049f1a1c54a814b4b9bed96d1ac0e0610c3b4da178f87209db05/yarl-1.22.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:34b36c2c57124530884d89d50ed2c1478697ad7473efd59cfd479945c95650e4", size = 140520, upload-time = "2025-10-06T14:11:15.465Z" }, - { url = "https://files.pythonhosted.org/packages/e4/04/3532d990fdbab02e5ede063676b5c4260e7f3abea2151099c2aa745acc4c/yarl-1.22.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:0dd9a702591ca2e543631c2a017e4a547e38a5c0f29eece37d9097e04a7ac683", size = 93504, upload-time = "2025-10-06T14:11:17.106Z" }, - { url = "https://files.pythonhosted.org/packages/11/63/ff458113c5c2dac9a9719ac68ee7c947cb621432bcf28c9972b1c0e83938/yarl-1.22.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:594fcab1032e2d2cc3321bb2e51271e7cd2b516c7d9aee780ece81b07ff8244b", size = 94282, upload-time = "2025-10-06T14:11:19.064Z" }, - { url = "https://files.pythonhosted.org/packages/a7/bc/315a56aca762d44a6aaaf7ad253f04d996cb6b27bad34410f82d76ea8038/yarl-1.22.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f3d7a87a78d46a2e3d5b72587ac14b4c16952dd0887dbb051451eceac774411e", size = 372080, upload-time = "2025-10-06T14:11:20.996Z" }, - { url = "https://files.pythonhosted.org/packages/3f/3f/08e9b826ec2e099ea6e7c69a61272f4f6da62cb5b1b63590bb80ca2e4a40/yarl-1.22.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:852863707010316c973162e703bddabec35e8757e67fcb8ad58829de1ebc8590", size = 338696, upload-time = "2025-10-06T14:11:22.847Z" }, - { url = "https://files.pythonhosted.org/packages/e3/9f/90360108e3b32bd76789088e99538febfea24a102380ae73827f62073543/yarl-1.22.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:131a085a53bfe839a477c0845acf21efc77457ba2bcf5899618136d64f3303a2", size = 387121, upload-time = "2025-10-06T14:11:24.889Z" }, - { url = "https://files.pythonhosted.org/packages/98/92/ab8d4657bd5b46a38094cfaea498f18bb70ce6b63508fd7e909bd1f93066/yarl-1.22.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:078a8aefd263f4d4f923a9677b942b445a2be970ca24548a8102689a3a8ab8da", size = 394080, upload-time = "2025-10-06T14:11:27.307Z" }, - { url = "https://files.pythonhosted.org/packages/f5/e7/d8c5a7752fef68205296201f8ec2bf718f5c805a7a7e9880576c67600658/yarl-1.22.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bca03b91c323036913993ff5c738d0842fc9c60c4648e5c8d98331526df89784", size = 372661, upload-time = "2025-10-06T14:11:29.387Z" }, - { url = "https://files.pythonhosted.org/packages/b6/2e/f4d26183c8db0bb82d491b072f3127fb8c381a6206a3a56332714b79b751/yarl-1.22.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:68986a61557d37bb90d3051a45b91fa3d5c516d177dfc6dd6f2f436a07ff2b6b", size = 364645, upload-time = "2025-10-06T14:11:31.423Z" }, - { url = "https://files.pythonhosted.org/packages/80/7c/428e5812e6b87cd00ee8e898328a62c95825bf37c7fa87f0b6bb2ad31304/yarl-1.22.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:4792b262d585ff0dff6bcb787f8492e40698443ec982a3568c2096433660c694", size = 355361, upload-time = "2025-10-06T14:11:33.055Z" }, - { url = "https://files.pythonhosted.org/packages/ec/2a/249405fd26776f8b13c067378ef4d7dd49c9098d1b6457cdd152a99e96a9/yarl-1.22.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:ebd4549b108d732dba1d4ace67614b9545b21ece30937a63a65dd34efa19732d", size = 381451, upload-time = "2025-10-06T14:11:35.136Z" }, - { url = "https://files.pythonhosted.org/packages/67/a8/fb6b1adbe98cf1e2dd9fad71003d3a63a1bc22459c6e15f5714eb9323b93/yarl-1.22.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:f87ac53513d22240c7d59203f25cc3beac1e574c6cd681bbfd321987b69f95fd", size = 383814, upload-time = "2025-10-06T14:11:37.094Z" }, - { url = "https://files.pythonhosted.org/packages/d9/f9/3aa2c0e480fb73e872ae2814c43bc1e734740bb0d54e8cb2a95925f98131/yarl-1.22.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:22b029f2881599e2f1b06f8f1db2ee63bd309e2293ba2d566e008ba12778b8da", size = 370799, upload-time = "2025-10-06T14:11:38.83Z" }, - { url = "https://files.pythonhosted.org/packages/50/3c/af9dba3b8b5eeb302f36f16f92791f3ea62e3f47763406abf6d5a4a3333b/yarl-1.22.0-cp314-cp314-win32.whl", hash = "sha256:6a635ea45ba4ea8238463b4f7d0e721bad669f80878b7bfd1f89266e2ae63da2", size = 82990, upload-time = "2025-10-06T14:11:40.624Z" }, - { url = "https://files.pythonhosted.org/packages/ac/30/ac3a0c5bdc1d6efd1b41fa24d4897a4329b3b1e98de9449679dd327af4f0/yarl-1.22.0-cp314-cp314-win_amd64.whl", hash = "sha256:0d6e6885777af0f110b0e5d7e5dda8b704efed3894da26220b7f3d887b839a79", size = 88292, upload-time = "2025-10-06T14:11:42.578Z" }, - { url = "https://files.pythonhosted.org/packages/df/0a/227ab4ff5b998a1b7410abc7b46c9b7a26b0ca9e86c34ba4b8d8bc7c63d5/yarl-1.22.0-cp314-cp314-win_arm64.whl", hash = "sha256:8218f4e98d3c10d683584cb40f0424f4b9fd6e95610232dd75e13743b070ee33", size = 82888, upload-time = "2025-10-06T14:11:44.863Z" }, - { url = "https://files.pythonhosted.org/packages/06/5e/a15eb13db90abd87dfbefb9760c0f3f257ac42a5cac7e75dbc23bed97a9f/yarl-1.22.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:45c2842ff0e0d1b35a6bf1cd6c690939dacb617a70827f715232b2e0494d55d1", size = 146223, upload-time = "2025-10-06T14:11:46.796Z" }, - { url = "https://files.pythonhosted.org/packages/18/82/9665c61910d4d84f41a5bf6837597c89e665fa88aa4941080704645932a9/yarl-1.22.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:d947071e6ebcf2e2bee8fce76e10faca8f7a14808ca36a910263acaacef08eca", size = 95981, upload-time = "2025-10-06T14:11:48.845Z" }, - { url = "https://files.pythonhosted.org/packages/5d/9a/2f65743589809af4d0a6d3aa749343c4b5f4c380cc24a8e94a3c6625a808/yarl-1.22.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:334b8721303e61b00019474cc103bdac3d7b1f65e91f0bfedeec2d56dfe74b53", size = 97303, upload-time = "2025-10-06T14:11:50.897Z" }, - { url = "https://files.pythonhosted.org/packages/b0/ab/5b13d3e157505c43c3b43b5a776cbf7b24a02bc4cccc40314771197e3508/yarl-1.22.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e7ce67c34138a058fd092f67d07a72b8e31ff0c9236e751957465a24b28910c", size = 361820, upload-time = "2025-10-06T14:11:52.549Z" }, - { url = "https://files.pythonhosted.org/packages/fb/76/242a5ef4677615cf95330cfc1b4610e78184400699bdda0acb897ef5e49a/yarl-1.22.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d77e1b2c6d04711478cb1c4ab90db07f1609ccf06a287d5607fcd90dc9863acf", size = 323203, upload-time = "2025-10-06T14:11:54.225Z" }, - { url = "https://files.pythonhosted.org/packages/8c/96/475509110d3f0153b43d06164cf4195c64d16999e0c7e2d8a099adcd6907/yarl-1.22.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4647674b6150d2cae088fc07de2738a84b8bcedebef29802cf0b0a82ab6face", size = 363173, upload-time = "2025-10-06T14:11:56.069Z" }, - { url = "https://files.pythonhosted.org/packages/c9/66/59db471aecfbd559a1fd48aedd954435558cd98c7d0da8b03cc6c140a32c/yarl-1.22.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:efb07073be061c8f79d03d04139a80ba33cbd390ca8f0297aae9cce6411e4c6b", size = 373562, upload-time = "2025-10-06T14:11:58.783Z" }, - { url = "https://files.pythonhosted.org/packages/03/1f/c5d94abc91557384719da10ff166b916107c1b45e4d0423a88457071dd88/yarl-1.22.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e51ac5435758ba97ad69617e13233da53908beccc6cfcd6c34bbed8dcbede486", size = 339828, upload-time = "2025-10-06T14:12:00.686Z" }, - { url = "https://files.pythonhosted.org/packages/5f/97/aa6a143d3afba17b6465733681c70cf175af89f76ec8d9286e08437a7454/yarl-1.22.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:33e32a0dd0c8205efa8e83d04fc9f19313772b78522d1bdc7d9aed706bfd6138", size = 347551, upload-time = "2025-10-06T14:12:02.628Z" }, - { url = "https://files.pythonhosted.org/packages/43/3c/45a2b6d80195959239a7b2a8810506d4eea5487dce61c2a3393e7fc3c52e/yarl-1.22.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:bf4a21e58b9cde0e401e683ebd00f6ed30a06d14e93f7c8fd059f8b6e8f87b6a", size = 334512, upload-time = "2025-10-06T14:12:04.871Z" }, - { url = "https://files.pythonhosted.org/packages/86/a0/c2ab48d74599c7c84cb104ebd799c5813de252bea0f360ffc29d270c2caa/yarl-1.22.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:e4b582bab49ac33c8deb97e058cd67c2c50dac0dd134874106d9c774fd272529", size = 352400, upload-time = "2025-10-06T14:12:06.624Z" }, - { url = "https://files.pythonhosted.org/packages/32/75/f8919b2eafc929567d3d8411f72bdb1a2109c01caaab4ebfa5f8ffadc15b/yarl-1.22.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:0b5bcc1a9c4839e7e30b7b30dd47fe5e7e44fb7054ec29b5bb8d526aa1041093", size = 357140, upload-time = "2025-10-06T14:12:08.362Z" }, - { url = "https://files.pythonhosted.org/packages/cf/72/6a85bba382f22cf78add705d8c3731748397d986e197e53ecc7835e76de7/yarl-1.22.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c0232bce2170103ec23c454e54a57008a9a72b5d1c3105dc2496750da8cfa47c", size = 341473, upload-time = "2025-10-06T14:12:10.994Z" }, - { url = "https://files.pythonhosted.org/packages/35/18/55e6011f7c044dc80b98893060773cefcfdbf60dfefb8cb2f58b9bacbd83/yarl-1.22.0-cp314-cp314t-win32.whl", hash = "sha256:8009b3173bcd637be650922ac455946197d858b3630b6d8787aa9e5c4564533e", size = 89056, upload-time = "2025-10-06T14:12:13.317Z" }, - { url = "https://files.pythonhosted.org/packages/f9/86/0f0dccb6e59a9e7f122c5afd43568b1d31b8ab7dda5f1b01fb5c7025c9a9/yarl-1.22.0-cp314-cp314t-win_amd64.whl", hash = "sha256:9fb17ea16e972c63d25d4a97f016d235c78dd2344820eb35bc034bc32012ee27", size = 96292, upload-time = "2025-10-06T14:12:15.398Z" }, - { url = "https://files.pythonhosted.org/packages/48/b7/503c98092fb3b344a179579f55814b613c1fbb1c23b3ec14a7b008a66a6e/yarl-1.22.0-cp314-cp314t-win_arm64.whl", hash = "sha256:9f6d73c1436b934e3f01df1e1b21ff765cd1d28c77dfb9ace207f746d4610ee1", size = 85171, upload-time = "2025-10-06T14:12:16.935Z" }, - { url = "https://files.pythonhosted.org/packages/73/ae/b48f95715333080afb75a4504487cbe142cae1268afc482d06692d605ae6/yarl-1.22.0-py3-none-any.whl", hash = "sha256:1380560bdba02b6b6c90de54133c81c9f2a453dee9912fe58c1dcced1edb7cff", size = 46814, upload-time = "2025-10-06T14:12:53.872Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/23/6e/beb1beec874a72f23815c1434518bfc4ed2175065173fb138c3705f658d4/yarl-1.23.0.tar.gz", hash = "sha256:53b1ea6ca88ebd4420379c330aea57e258408dd0df9af0992e5de2078dc9f5d5", size = 194676, upload-time = "2026-03-01T22:07:53.373Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a2/aa/60da938b8f0997ba3a911263c40d82b6f645a67902a490b46f3355e10fae/yarl-1.23.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b35d13d549077713e4414f927cdc388d62e543987c572baee613bf82f11a4b99", size = 123641, upload-time = "2026-03-01T22:04:42.841Z" }, + { url = "https://files.pythonhosted.org/packages/24/84/e237607faf4e099dbb8a4f511cfd5efcb5f75918baad200ff7380635631b/yarl-1.23.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cbb0fef01f0c6b38cb0f39b1f78fc90b807e0e3c86a7ff3ce74ad77ce5c7880c", size = 86248, upload-time = "2026-03-01T22:04:44.757Z" }, + { url = "https://files.pythonhosted.org/packages/b2/0d/71ceabc14c146ba8ee3804ca7b3d42b1664c8440439de5214d366fec7d3a/yarl-1.23.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dc52310451fc7c629e13c4e061cbe2dd01684d91f2f8ee2821b083c58bd72432", size = 85988, upload-time = "2026-03-01T22:04:46.365Z" }, + { url = "https://files.pythonhosted.org/packages/8c/6c/4a90d59c572e46b270ca132aca66954f1175abd691f74c1ef4c6711828e2/yarl-1.23.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b2c6b50c7b0464165472b56b42d4c76a7b864597007d9c085e8b63e185cf4a7a", size = 100566, upload-time = "2026-03-01T22:04:47.639Z" }, + { url = "https://files.pythonhosted.org/packages/49/fb/c438fb5108047e629f6282a371e6e91cf3f97ee087c4fb748a1f32ceef55/yarl-1.23.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:aafe5dcfda86c8af00386d7781d4c2181b5011b7be3f2add5e99899ea925df05", size = 92079, upload-time = "2026-03-01T22:04:48.925Z" }, + { url = "https://files.pythonhosted.org/packages/d9/13/d269aa1aed3e4f50a5a103f96327210cc5fa5dd2d50882778f13c7a14606/yarl-1.23.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9ee33b875f0b390564c1fb7bc528abf18c8ee6073b201c6ae8524aca778e2d83", size = 108741, upload-time = "2026-03-01T22:04:50.838Z" }, + { url = "https://files.pythonhosted.org/packages/85/fb/115b16f22c37ea4437d323e472945bea97301c8ec6089868fa560abab590/yarl-1.23.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4c41e021bc6d7affb3364dc1e1e5fa9582b470f283748784bd6ea0558f87f42c", size = 108099, upload-time = "2026-03-01T22:04:52.499Z" }, + { url = "https://files.pythonhosted.org/packages/9a/64/c53487d9f4968045b8afa51aed7ca44f58b2589e772f32745f3744476c82/yarl-1.23.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:99c8a9ed30f4164bc4c14b37a90208836cbf50d4ce2a57c71d0f52c7fb4f7598", size = 102678, upload-time = "2026-03-01T22:04:55.176Z" }, + { url = "https://files.pythonhosted.org/packages/85/59/cd98e556fbb2bf8fab29c1a722f67ad45c5f3447cac798ab85620d1e70af/yarl-1.23.0-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f2af5c81a1f124609d5f33507082fc3f739959d4719b56877ab1ee7e7b3d602b", size = 100803, upload-time = "2026-03-01T22:04:56.588Z" }, + { url = "https://files.pythonhosted.org/packages/9e/c0/b39770b56d4a9f0bb5f77e2f1763cd2d75cc2f6c0131e3b4c360348fcd65/yarl-1.23.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6b41389c19b07c760c7e427a3462e8ab83c4bb087d127f0e854c706ce1b9215c", size = 100163, upload-time = "2026-03-01T22:04:58.492Z" }, + { url = "https://files.pythonhosted.org/packages/e7/64/6980f99ab00e1f0ff67cb84766c93d595b067eed07439cfccfc8fb28c1a6/yarl-1.23.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:1dc702e42d0684f42d6519c8d581e49c96cefaaab16691f03566d30658ee8788", size = 93859, upload-time = "2026-03-01T22:05:00.268Z" }, + { url = "https://files.pythonhosted.org/packages/38/69/912e6c5e146793e5d4b5fe39ff5b00f4d22463dfd5a162bec565ac757673/yarl-1.23.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:0e40111274f340d32ebcc0a5668d54d2b552a6cca84c9475859d364b380e3222", size = 108202, upload-time = "2026-03-01T22:05:02.273Z" }, + { url = "https://files.pythonhosted.org/packages/59/97/35ca6767524687ad64e5f5c31ad54bc76d585585a9fcb40f649e7e82ffed/yarl-1.23.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:4764a6a7588561a9aef92f65bda2c4fb58fe7c675c0883862e6df97559de0bfb", size = 99866, upload-time = "2026-03-01T22:05:03.597Z" }, + { url = "https://files.pythonhosted.org/packages/d3/1c/1a3387ee6d73589f6f2a220ae06f2984f6c20b40c734989b0a44f5987308/yarl-1.23.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:03214408cfa590df47728b84c679ae4ef00be2428e11630277be0727eba2d7cc", size = 107852, upload-time = "2026-03-01T22:05:04.986Z" }, + { url = "https://files.pythonhosted.org/packages/a4/b8/35c0750fcd5a3f781058bfd954515dd4b1eab45e218cbb85cf11132215f1/yarl-1.23.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:170e26584b060879e29fac213e4228ef063f39128723807a312e5c7fec28eff2", size = 102919, upload-time = "2026-03-01T22:05:06.397Z" }, + { url = "https://files.pythonhosted.org/packages/e5/1c/9a1979aec4a81896d597bcb2177827f2dbee3f5b7cc48b2d0dadb644b41d/yarl-1.23.0-cp311-cp311-win32.whl", hash = "sha256:51430653db848d258336cfa0244427b17d12db63d42603a55f0d4546f50f25b5", size = 82602, upload-time = "2026-03-01T22:05:08.444Z" }, + { url = "https://files.pythonhosted.org/packages/93/22/b85eca6fa2ad9491af48c973e4c8cf6b103a73dbb271fe3346949449fca0/yarl-1.23.0-cp311-cp311-win_amd64.whl", hash = "sha256:bf49a3ae946a87083ef3a34c8f677ae4243f5b824bfc4c69672e72b3d6719d46", size = 87461, upload-time = "2026-03-01T22:05:10.145Z" }, + { url = "https://files.pythonhosted.org/packages/93/95/07e3553fe6f113e6864a20bdc53a78113cda3b9ced8784ee52a52c9f80d8/yarl-1.23.0-cp311-cp311-win_arm64.whl", hash = "sha256:b39cb32a6582750b6cc77bfb3c49c0f8760dc18dc96ec9fb55fbb0f04e08b928", size = 82336, upload-time = "2026-03-01T22:05:11.554Z" }, + { url = "https://files.pythonhosted.org/packages/88/8a/94615bc31022f711add374097ad4144d569e95ff3c38d39215d07ac153a0/yarl-1.23.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1932b6b8bba8d0160a9d1078aae5838a66039e8832d41d2992daa9a3a08f7860", size = 124737, upload-time = "2026-03-01T22:05:12.897Z" }, + { url = "https://files.pythonhosted.org/packages/e3/6f/c6554045d59d64052698add01226bc867b52fe4a12373415d7991fdca95d/yarl-1.23.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:411225bae281f114067578891bc75534cfb3d92a3b4dfef7a6ca78ba354e6069", size = 87029, upload-time = "2026-03-01T22:05:14.376Z" }, + { url = "https://files.pythonhosted.org/packages/19/2a/725ecc166d53438bc88f76822ed4b1e3b10756e790bafd7b523fe97c322d/yarl-1.23.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:13a563739ae600a631c36ce096615fe307f131344588b0bc0daec108cdb47b25", size = 86310, upload-time = "2026-03-01T22:05:15.71Z" }, + { url = "https://files.pythonhosted.org/packages/99/30/58260ed98e6ff7f90ba84442c1ddd758c9170d70327394a6227b310cd60f/yarl-1.23.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9cbf44c5cb4a7633d078788e1b56387e3d3cf2b8139a3be38040b22d6c3221c8", size = 97587, upload-time = "2026-03-01T22:05:17.384Z" }, + { url = "https://files.pythonhosted.org/packages/76/0a/8b08aac08b50682e65759f7f8dde98ae8168f72487e7357a5d684c581ef9/yarl-1.23.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:53ad387048f6f09a8969631e4de3f1bf70c50e93545d64af4f751b2498755072", size = 92528, upload-time = "2026-03-01T22:05:18.804Z" }, + { url = "https://files.pythonhosted.org/packages/52/07/0b7179101fe5f8385ec6c6bb5d0cb9f76bd9fb4a769591ab6fb5cdbfc69a/yarl-1.23.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4a59ba56f340334766f3a4442e0efd0af895fae9e2b204741ef885c446b3a1a8", size = 105339, upload-time = "2026-03-01T22:05:20.235Z" }, + { url = "https://files.pythonhosted.org/packages/d3/8a/36d82869ab5ec829ca8574dfcb92b51286fcfb1e9c7a73659616362dc880/yarl-1.23.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:803a3c3ce4acc62eaf01eaca1208dcf0783025ef27572c3336502b9c232005e7", size = 105061, upload-time = "2026-03-01T22:05:22.268Z" }, + { url = "https://files.pythonhosted.org/packages/66/3e/868e5c3364b6cee19ff3e1a122194fa4ce51def02c61023970442162859e/yarl-1.23.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a3d2bff8f37f8d0f96c7ec554d16945050d54462d6e95414babaa18bfafc7f51", size = 100132, upload-time = "2026-03-01T22:05:23.638Z" }, + { url = "https://files.pythonhosted.org/packages/cf/26/9c89acf82f08a52cb52d6d39454f8d18af15f9d386a23795389d1d423823/yarl-1.23.0-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c75eb09e8d55bceb4367e83496ff8ef2bc7ea6960efb38e978e8073ea59ecb67", size = 99289, upload-time = "2026-03-01T22:05:25.749Z" }, + { url = "https://files.pythonhosted.org/packages/6f/54/5b0db00d2cb056922356104468019c0a132e89c8d3ab67d8ede9f4483d2a/yarl-1.23.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:877b0738624280e34c55680d6054a307aa94f7d52fa0e3034a9cc6e790871da7", size = 96950, upload-time = "2026-03-01T22:05:27.318Z" }, + { url = "https://files.pythonhosted.org/packages/f6/40/10fa93811fd439341fad7e0718a86aca0de9548023bbb403668d6555acab/yarl-1.23.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:b5405bb8f0e783a988172993cfc627e4d9d00432d6bbac65a923041edacf997d", size = 93960, upload-time = "2026-03-01T22:05:28.738Z" }, + { url = "https://files.pythonhosted.org/packages/bc/d2/8ae2e6cd77d0805f4526e30ec43b6f9a3dfc542d401ac4990d178e4bf0cf/yarl-1.23.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:1c3a3598a832590c5a3ce56ab5576361b5688c12cb1d39429cf5dba30b510760", size = 104703, upload-time = "2026-03-01T22:05:30.438Z" }, + { url = "https://files.pythonhosted.org/packages/2f/0c/b3ceacf82c3fe21183ce35fa2acf5320af003d52bc1fcf5915077681142e/yarl-1.23.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:8419ebd326430d1cbb7efb5292330a2cf39114e82df5cc3d83c9a0d5ebeaf2f2", size = 98325, upload-time = "2026-03-01T22:05:31.835Z" }, + { url = "https://files.pythonhosted.org/packages/9d/e0/12900edd28bdab91a69bd2554b85ad7b151f64e8b521fe16f9ad2f56477a/yarl-1.23.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:be61f6fff406ca40e3b1d84716fde398fc08bc63dd96d15f3a14230a0973ed86", size = 105067, upload-time = "2026-03-01T22:05:33.358Z" }, + { url = "https://files.pythonhosted.org/packages/15/61/74bb1182cf79c9bbe4eb6b1f14a57a22d7a0be5e9cedf8e2d5c2086474c3/yarl-1.23.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3ceb13c5c858d01321b5d9bb65e4cf37a92169ea470b70fec6f236b2c9dd7e34", size = 100285, upload-time = "2026-03-01T22:05:35.4Z" }, + { url = "https://files.pythonhosted.org/packages/69/7f/cd5ef733f2550de6241bd8bd8c3febc78158b9d75f197d9c7baa113436af/yarl-1.23.0-cp312-cp312-win32.whl", hash = "sha256:fffc45637bcd6538de8b85f51e3df3223e4ad89bccbfca0481c08c7fc8b7ed7d", size = 82359, upload-time = "2026-03-01T22:05:36.811Z" }, + { url = "https://files.pythonhosted.org/packages/f5/be/25216a49daeeb7af2bec0db22d5e7df08ed1d7c9f65d78b14f3b74fd72fc/yarl-1.23.0-cp312-cp312-win_amd64.whl", hash = "sha256:f69f57305656a4852f2a7203efc661d8c042e6cc67f7acd97d8667fb448a426e", size = 87674, upload-time = "2026-03-01T22:05:38.171Z" }, + { url = "https://files.pythonhosted.org/packages/d2/35/aeab955d6c425b227d5b7247eafb24f2653fedc32f95373a001af5dfeb9e/yarl-1.23.0-cp312-cp312-win_arm64.whl", hash = "sha256:6e87a6e8735b44816e7db0b2fbc9686932df473c826b0d9743148432e10bb9b9", size = 81879, upload-time = "2026-03-01T22:05:40.006Z" }, + { url = "https://files.pythonhosted.org/packages/9a/4b/a0a6e5d0ee8a2f3a373ddef8a4097d74ac901ac363eea1440464ccbe0898/yarl-1.23.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:16c6994ac35c3e74fb0ae93323bf8b9c2a9088d55946109489667c510a7d010e", size = 123796, upload-time = "2026-03-01T22:05:41.412Z" }, + { url = "https://files.pythonhosted.org/packages/67/b6/8925d68af039b835ae876db5838e82e76ec87b9782ecc97e192b809c4831/yarl-1.23.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4a42e651629dafb64fd5b0286a3580613702b5809ad3f24934ea87595804f2c5", size = 86547, upload-time = "2026-03-01T22:05:42.841Z" }, + { url = "https://files.pythonhosted.org/packages/ae/50/06d511cc4b8e0360d3c94af051a768e84b755c5eb031b12adaaab6dec6e5/yarl-1.23.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7c6b9461a2a8b47c65eef63bb1c76a4f1c119618ffa99ea79bc5bb1e46c5821b", size = 85854, upload-time = "2026-03-01T22:05:44.85Z" }, + { url = "https://files.pythonhosted.org/packages/c4/f4/4e30b250927ffdab4db70da08b9b8d2194d7c7b400167b8fbeca1e4701ca/yarl-1.23.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2569b67d616eab450d262ca7cb9f9e19d2f718c70a8b88712859359d0ab17035", size = 98351, upload-time = "2026-03-01T22:05:46.836Z" }, + { url = "https://files.pythonhosted.org/packages/86/fc/4118c5671ea948208bdb1492d8b76bdf1453d3e73df051f939f563e7dcc5/yarl-1.23.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e9d9a4d06d3481eab79803beb4d9bd6f6a8e781ec078ac70d7ef2dcc29d1bea5", size = 92711, upload-time = "2026-03-01T22:05:48.316Z" }, + { url = "https://files.pythonhosted.org/packages/56/11/1ed91d42bd9e73c13dc9e7eb0dd92298d75e7ac4dd7f046ad0c472e231cd/yarl-1.23.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f514f6474e04179d3d33175ed3f3e31434d3130d42ec153540d5b157deefd735", size = 106014, upload-time = "2026-03-01T22:05:50.028Z" }, + { url = "https://files.pythonhosted.org/packages/ce/c9/74e44e056a23fbc33aca71779ef450ca648a5bc472bdad7a82339918f818/yarl-1.23.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fda207c815b253e34f7e1909840fd14299567b1c0eb4908f8c2ce01a41265401", size = 105557, upload-time = "2026-03-01T22:05:51.416Z" }, + { url = "https://files.pythonhosted.org/packages/66/fe/b1e10b08d287f518994f1e2ff9b6d26f0adeecd8dd7d533b01bab29a3eda/yarl-1.23.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:34b6cf500e61c90f305094911f9acc9c86da1a05a7a3f5be9f68817043f486e4", size = 101559, upload-time = "2026-03-01T22:05:52.872Z" }, + { url = "https://files.pythonhosted.org/packages/72/59/c5b8d94b14e3d3c2a9c20cb100119fd534ab5a14b93673ab4cc4a4141ea5/yarl-1.23.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d7504f2b476d21653e4d143f44a175f7f751cd41233525312696c76aa3dbb23f", size = 100502, upload-time = "2026-03-01T22:05:54.954Z" }, + { url = "https://files.pythonhosted.org/packages/77/4f/96976cb54cbfc5c9fd73ed4c51804f92f209481d1fb190981c0f8a07a1d7/yarl-1.23.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:578110dd426f0d209d1509244e6d4a3f1a3e9077655d98c5f22583d63252a08a", size = 98027, upload-time = "2026-03-01T22:05:56.409Z" }, + { url = "https://files.pythonhosted.org/packages/63/6e/904c4f476471afdbad6b7e5b70362fb5810e35cd7466529a97322b6f5556/yarl-1.23.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:609d3614d78d74ebe35f54953c5bbd2ac647a7ddb9c30a5d877580f5e86b22f2", size = 95369, upload-time = "2026-03-01T22:05:58.141Z" }, + { url = "https://files.pythonhosted.org/packages/9d/40/acfcdb3b5f9d68ef499e39e04d25e141fe90661f9d54114556cf83be8353/yarl-1.23.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4966242ec68afc74c122f8459abd597afd7d8a60dc93d695c1334c5fd25f762f", size = 105565, upload-time = "2026-03-01T22:06:00.286Z" }, + { url = "https://files.pythonhosted.org/packages/5e/c6/31e28f3a6ba2869c43d124f37ea5260cac9c9281df803c354b31f4dd1f3c/yarl-1.23.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:e0fd068364a6759bc794459f0a735ab151d11304346332489c7972bacbe9e72b", size = 99813, upload-time = "2026-03-01T22:06:01.712Z" }, + { url = "https://files.pythonhosted.org/packages/08/1f/6f65f59e72d54aa467119b63fc0b0b1762eff0232db1f4720cd89e2f4a17/yarl-1.23.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:39004f0ad156da43e86aa71f44e033de68a44e5a31fc53507b36dd253970054a", size = 105632, upload-time = "2026-03-01T22:06:03.188Z" }, + { url = "https://files.pythonhosted.org/packages/a3/c4/18b178a69935f9e7a338127d5b77d868fdc0f0e49becd286d51b3a18c61d/yarl-1.23.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e5723c01a56c5028c807c701aa66722916d2747ad737a046853f6c46f4875543", size = 101895, upload-time = "2026-03-01T22:06:04.651Z" }, + { url = "https://files.pythonhosted.org/packages/8f/54/f5b870b5505663911dba950a8e4776a0dbd51c9c54c0ae88e823e4b874a0/yarl-1.23.0-cp313-cp313-win32.whl", hash = "sha256:1b6b572edd95b4fa8df75de10b04bc81acc87c1c7d16bcdd2035b09d30acc957", size = 82356, upload-time = "2026-03-01T22:06:06.04Z" }, + { url = "https://files.pythonhosted.org/packages/7a/84/266e8da36879c6edcd37b02b547e2d9ecdfea776be49598e75696e3316e1/yarl-1.23.0-cp313-cp313-win_amd64.whl", hash = "sha256:baaf55442359053c7d62f6f8413a62adba3205119bcb6f49594894d8be47e5e3", size = 87515, upload-time = "2026-03-01T22:06:08.107Z" }, + { url = "https://files.pythonhosted.org/packages/00/fd/7e1c66efad35e1649114fa13f17485f62881ad58edeeb7f49f8c5e748bf9/yarl-1.23.0-cp313-cp313-win_arm64.whl", hash = "sha256:fb4948814a2a98e3912505f09c9e7493b1506226afb1f881825368d6fb776ee3", size = 81785, upload-time = "2026-03-01T22:06:10.181Z" }, + { url = "https://files.pythonhosted.org/packages/9c/fc/119dd07004f17ea43bb91e3ece6587759edd7519d6b086d16bfbd3319982/yarl-1.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:aecfed0b41aa72b7881712c65cf764e39ce2ec352324f5e0837c7048d9e6daaa", size = 130719, upload-time = "2026-03-01T22:06:11.708Z" }, + { url = "https://files.pythonhosted.org/packages/e6/0d/9f2348502fbb3af409e8f47730282cd6bc80dec6630c1e06374d882d6eb2/yarl-1.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a41bcf68efd19073376eb8cf948b8d9be0af26256403e512bb18f3966f1f9120", size = 89690, upload-time = "2026-03-01T22:06:13.429Z" }, + { url = "https://files.pythonhosted.org/packages/50/93/e88f3c80971b42cfc83f50a51b9d165a1dbf154b97005f2994a79f212a07/yarl-1.23.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:cde9a2ecd91668bcb7f077c4966d8ceddb60af01b52e6e3e2680e4cf00ad1a59", size = 89851, upload-time = "2026-03-01T22:06:15.53Z" }, + { url = "https://files.pythonhosted.org/packages/1c/07/61c9dd8ba8f86473263b4036f70fb594c09e99c0d9737a799dfd8bc85651/yarl-1.23.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5023346c4ee7992febc0068e7593de5fa2bf611848c08404b35ebbb76b1b0512", size = 95874, upload-time = "2026-03-01T22:06:17.553Z" }, + { url = "https://files.pythonhosted.org/packages/9e/e9/f9ff8ceefba599eac6abddcfb0b3bee9b9e636e96dbf54342a8577252379/yarl-1.23.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d1009abedb49ae95b136a8904a3f71b342f849ffeced2d3747bf29caeda218c4", size = 88710, upload-time = "2026-03-01T22:06:19.004Z" }, + { url = "https://files.pythonhosted.org/packages/eb/78/0231bfcc5d4c8eec220bc2f9ef82cb4566192ea867a7c5b4148f44f6cbcd/yarl-1.23.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a8d00f29b42f534cc8aa3931cfe773b13b23e561e10d2b26f27a8d309b0e82a1", size = 101033, upload-time = "2026-03-01T22:06:21.203Z" }, + { url = "https://files.pythonhosted.org/packages/cd/9b/30ea5239a61786f18fd25797151a17fbb3be176977187a48d541b5447dd4/yarl-1.23.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:95451e6ce06c3e104556d73b559f5da6c34a069b6b62946d3ad66afcd51642ea", size = 100817, upload-time = "2026-03-01T22:06:22.738Z" }, + { url = "https://files.pythonhosted.org/packages/62/e2/a4980481071791bc83bce2b7a1a1f7adcabfa366007518b4b845e92eeee3/yarl-1.23.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:531ef597132086b6cf96faa7c6c1dcd0361dd5f1694e5cc30375907b9b7d3ea9", size = 97482, upload-time = "2026-03-01T22:06:24.21Z" }, + { url = "https://files.pythonhosted.org/packages/e5/1e/304a00cf5f6100414c4b5a01fc7ff9ee724b62158a08df2f8170dfc72a2d/yarl-1.23.0-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:88f9fb0116fbfcefcab70f85cf4b74a2b6ce5d199c41345296f49d974ddb4123", size = 95949, upload-time = "2026-03-01T22:06:25.697Z" }, + { url = "https://files.pythonhosted.org/packages/68/03/093f4055ed4cae649ac53bca3d180bd37102e9e11d048588e9ab0c0108d0/yarl-1.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:e7b0460976dc75cb87ad9cc1f9899a4b97751e7d4e77ab840fc9b6d377b8fd24", size = 95839, upload-time = "2026-03-01T22:06:27.309Z" }, + { url = "https://files.pythonhosted.org/packages/b9/28/4c75ebb108f322aa8f917ae10a8ffa4f07cae10a8a627b64e578617df6a0/yarl-1.23.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:115136c4a426f9da976187d238e84139ff6b51a20839aa6e3720cd1026d768de", size = 90696, upload-time = "2026-03-01T22:06:29.048Z" }, + { url = "https://files.pythonhosted.org/packages/23/9c/42c2e2dd91c1a570402f51bdf066bfdb1241c2240ba001967bad778e77b7/yarl-1.23.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:ead11956716a940c1abc816b7df3fa2b84d06eaed8832ca32f5c5e058c65506b", size = 100865, upload-time = "2026-03-01T22:06:30.525Z" }, + { url = "https://files.pythonhosted.org/packages/74/05/1bcd60a8a0a914d462c305137246b6f9d167628d73568505fce3f1cb2e65/yarl-1.23.0-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:fe8f8f5e70e6dbdfca9882cd9deaac058729bcf323cf7a58660901e55c9c94f6", size = 96234, upload-time = "2026-03-01T22:06:32.692Z" }, + { url = "https://files.pythonhosted.org/packages/90/b2/f52381aac396d6778ce516b7bc149c79e65bfc068b5de2857ab69eeea3b7/yarl-1.23.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:a0e317df055958a0c1e79e5d2aa5a5eaa4a6d05a20d4b0c9c3f48918139c9fc6", size = 100295, upload-time = "2026-03-01T22:06:34.268Z" }, + { url = "https://files.pythonhosted.org/packages/e5/e8/638bae5bbf1113a659b2435d8895474598afe38b4a837103764f603aba56/yarl-1.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6f0fd84de0c957b2d280143522c4f91a73aada1923caee763e24a2b3fda9f8a5", size = 97784, upload-time = "2026-03-01T22:06:35.864Z" }, + { url = "https://files.pythonhosted.org/packages/80/25/a3892b46182c586c202629fc2159aa13975d3741d52ebd7347fd501d48d5/yarl-1.23.0-cp313-cp313t-win32.whl", hash = "sha256:93a784271881035ab4406a172edb0faecb6e7d00f4b53dc2f55919d6c9688595", size = 88313, upload-time = "2026-03-01T22:06:37.39Z" }, + { url = "https://files.pythonhosted.org/packages/43/68/8c5b36aa5178900b37387937bc2c2fe0e9505537f713495472dcf6f6fccc/yarl-1.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:dd00607bffbf30250fe108065f07453ec124dbf223420f57f5e749b04295e090", size = 94932, upload-time = "2026-03-01T22:06:39.579Z" }, + { url = "https://files.pythonhosted.org/packages/c6/cc/d79ba8292f51f81f4dc533a8ccfb9fc6992cabf0998ed3245de7589dc07c/yarl-1.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:ac09d42f48f80c9ee1635b2fcaa819496a44502737660d3c0f2ade7526d29144", size = 84786, upload-time = "2026-03-01T22:06:41.988Z" }, + { url = "https://files.pythonhosted.org/packages/90/98/b85a038d65d1b92c3903ab89444f48d3cee490a883477b716d7a24b1a78c/yarl-1.23.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:21d1b7305a71a15b4794b5ff22e8eef96ff4a6d7f9657155e5aa419444b28912", size = 124455, upload-time = "2026-03-01T22:06:43.615Z" }, + { url = "https://files.pythonhosted.org/packages/39/54/bc2b45559f86543d163b6e294417a107bb87557609007c007ad889afec18/yarl-1.23.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:85610b4f27f69984932a7abbe52703688de3724d9f72bceb1cca667deff27474", size = 86752, upload-time = "2026-03-01T22:06:45.425Z" }, + { url = "https://files.pythonhosted.org/packages/24/f9/e8242b68362bffe6fb536c8db5076861466fc780f0f1b479fc4ffbebb128/yarl-1.23.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:23f371bd662cf44a7630d4d113101eafc0cfa7518a2760d20760b26021454719", size = 86291, upload-time = "2026-03-01T22:06:46.974Z" }, + { url = "https://files.pythonhosted.org/packages/ea/d8/d1cb2378c81dd729e98c716582b1ccb08357e8488e4c24714658cc6630e8/yarl-1.23.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c4a80f77dc1acaaa61f0934176fccca7096d9b1ff08c8ba9cddf5ae034a24319", size = 99026, upload-time = "2026-03-01T22:06:48.459Z" }, + { url = "https://files.pythonhosted.org/packages/0a/ff/7196790538f31debe3341283b5b0707e7feb947620fc5e8236ef28d44f72/yarl-1.23.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:bd654fad46d8d9e823afbb4f87c79160b5a374ed1ff5bde24e542e6ba8f41434", size = 92355, upload-time = "2026-03-01T22:06:50.306Z" }, + { url = "https://files.pythonhosted.org/packages/c1/56/25d58c3eddde825890a5fe6aa1866228377354a3c39262235234ab5f616b/yarl-1.23.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:682bae25f0a0dd23a056739f23a134db9f52a63e2afd6bfb37ddc76292bbd723", size = 106417, upload-time = "2026-03-01T22:06:52.1Z" }, + { url = "https://files.pythonhosted.org/packages/51/8a/882c0e7bc8277eb895b31bce0138f51a1ba551fc2e1ec6753ffc1e7c1377/yarl-1.23.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a82836cab5f197a0514235aaf7ffccdc886ccdaa2324bc0aafdd4ae898103039", size = 106422, upload-time = "2026-03-01T22:06:54.424Z" }, + { url = "https://files.pythonhosted.org/packages/42/2b/fef67d616931055bf3d6764885990a3ac647d68734a2d6a9e1d13de437a2/yarl-1.23.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1c57676bdedc94cd3bc37724cf6f8cd2779f02f6aba48de45feca073e714fe52", size = 101915, upload-time = "2026-03-01T22:06:55.895Z" }, + { url = "https://files.pythonhosted.org/packages/18/6a/530e16aebce27c5937920f3431c628a29a4b6b430fab3fd1c117b26ff3f6/yarl-1.23.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c7f8dc16c498ff06497c015642333219871effba93e4a2e8604a06264aca5c5c", size = 100690, upload-time = "2026-03-01T22:06:58.21Z" }, + { url = "https://files.pythonhosted.org/packages/88/08/93749219179a45e27b036e03260fda05190b911de8e18225c294ac95bbc9/yarl-1.23.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:5ee586fb17ff8f90c91cf73c6108a434b02d69925f44f5f8e0d7f2f260607eae", size = 98750, upload-time = "2026-03-01T22:06:59.794Z" }, + { url = "https://files.pythonhosted.org/packages/d9/cf/ea424a004969f5d81a362110a6ac1496d79efdc6d50c2c4b2e3ea0fc2519/yarl-1.23.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:17235362f580149742739cc3828b80e24029d08cbb9c4bda0242c7b5bc610a8e", size = 94685, upload-time = "2026-03-01T22:07:01.375Z" }, + { url = "https://files.pythonhosted.org/packages/e2/b7/14341481fe568e2b0408bcf1484c652accafe06a0ade9387b5d3fd9df446/yarl-1.23.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:0793e2bd0cf14234983bbb371591e6bea9e876ddf6896cdcc93450996b0b5c85", size = 106009, upload-time = "2026-03-01T22:07:03.151Z" }, + { url = "https://files.pythonhosted.org/packages/0a/e6/5c744a9b54f4e8007ad35bce96fbc9218338e84812d36f3390cea616881a/yarl-1.23.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:3650dc2480f94f7116c364096bc84b1d602f44224ef7d5c7208425915c0475dd", size = 100033, upload-time = "2026-03-01T22:07:04.701Z" }, + { url = "https://files.pythonhosted.org/packages/0c/23/e3bfc188d0b400f025bc49d99793d02c9abe15752138dcc27e4eaf0c4a9e/yarl-1.23.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:f40e782d49630ad384db66d4d8b73ff4f1b8955dc12e26b09a3e3af064b3b9d6", size = 106483, upload-time = "2026-03-01T22:07:06.231Z" }, + { url = "https://files.pythonhosted.org/packages/72/42/f0505f949a90b3f8b7a363d6cbdf398f6e6c58946d85c6d3a3bc70595b26/yarl-1.23.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:94f8575fbdf81749008d980c17796097e645574a3b8c28ee313931068dad14fe", size = 102175, upload-time = "2026-03-01T22:07:08.4Z" }, + { url = "https://files.pythonhosted.org/packages/aa/65/b39290f1d892a9dd671d1c722014ca062a9c35d60885d57e5375db0404b5/yarl-1.23.0-cp314-cp314-win32.whl", hash = "sha256:c8aa34a5c864db1087d911a0b902d60d203ea3607d91f615acd3f3108ac32169", size = 83871, upload-time = "2026-03-01T22:07:09.968Z" }, + { url = "https://files.pythonhosted.org/packages/a9/5b/9b92f54c784c26e2a422e55a8d2607ab15b7ea3349e28359282f84f01d43/yarl-1.23.0-cp314-cp314-win_amd64.whl", hash = "sha256:63e92247f383c85ab00dd0091e8c3fa331a96e865459f5ee80353c70a4a42d70", size = 89093, upload-time = "2026-03-01T22:07:11.501Z" }, + { url = "https://files.pythonhosted.org/packages/e0/7d/8a84dc9381fd4412d5e7ff04926f9865f6372b4c2fd91e10092e65d29eb8/yarl-1.23.0-cp314-cp314-win_arm64.whl", hash = "sha256:70efd20be968c76ece7baa8dafe04c5be06abc57f754d6f36f3741f7aa7a208e", size = 83384, upload-time = "2026-03-01T22:07:13.069Z" }, + { url = "https://files.pythonhosted.org/packages/dd/8d/d2fad34b1c08aa161b74394183daa7d800141aaaee207317e82c790b418d/yarl-1.23.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:9a18d6f9359e45722c064c97464ec883eb0e0366d33eda61cb19a244bf222679", size = 131019, upload-time = "2026-03-01T22:07:14.903Z" }, + { url = "https://files.pythonhosted.org/packages/19/ff/33009a39d3ccf4b94d7d7880dfe17fb5816c5a4fe0096d9b56abceea9ac7/yarl-1.23.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:2803ed8b21ca47a43da80a6fd1ed3019d30061f7061daa35ac54f63933409412", size = 89894, upload-time = "2026-03-01T22:07:17.372Z" }, + { url = "https://files.pythonhosted.org/packages/0c/f1/dab7ac5e7306fb79c0190766a3c00b4cb8d09a1f390ded68c85a5934faf5/yarl-1.23.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:394906945aa8b19fc14a61cf69743a868bb8c465efe85eee687109cc540b98f4", size = 89979, upload-time = "2026-03-01T22:07:19.361Z" }, + { url = "https://files.pythonhosted.org/packages/aa/b1/08e95f3caee1fad6e65017b9f26c1d79877b502622d60e517de01e72f95d/yarl-1.23.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:71d006bee8397a4a89f469b8deb22469fe7508132d3c17fa6ed871e79832691c", size = 95943, upload-time = "2026-03-01T22:07:21.266Z" }, + { url = "https://files.pythonhosted.org/packages/c0/cc/6409f9018864a6aa186c61175b977131f373f1988e198e031236916e87e4/yarl-1.23.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:62694e275c93d54f7ccedcfef57d42761b2aad5234b6be1f3e3026cae4001cd4", size = 88786, upload-time = "2026-03-01T22:07:23.129Z" }, + { url = "https://files.pythonhosted.org/packages/76/40/cc22d1d7714b717fde2006fad2ced5efe5580606cb059ae42117542122f3/yarl-1.23.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a31de1613658308efdb21ada98cbc86a97c181aa050ba22a808120bb5be3ab94", size = 101307, upload-time = "2026-03-01T22:07:24.689Z" }, + { url = "https://files.pythonhosted.org/packages/8f/0d/476c38e85ddb4c6ec6b20b815bdd779aa386a013f3d8b85516feee55c8dc/yarl-1.23.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fb1e8b8d66c278b21d13b0a7ca22c41dd757a7c209c6b12c313e445c31dd3b28", size = 100904, upload-time = "2026-03-01T22:07:26.287Z" }, + { url = "https://files.pythonhosted.org/packages/72/32/0abe4a76d59adf2081dcb0397168553ece4616ada1c54d1c49d8936c74f8/yarl-1.23.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50f9d8d531dfb767c565f348f33dd5139a6c43f5cbdf3f67da40d54241df93f6", size = 97728, upload-time = "2026-03-01T22:07:27.906Z" }, + { url = "https://files.pythonhosted.org/packages/b7/35/7b30f4810fba112f60f5a43237545867504e15b1c7647a785fbaf588fac2/yarl-1.23.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:575aa4405a656e61a540f4a80eaa5260f2a38fff7bfdc4b5f611840d76e9e277", size = 95964, upload-time = "2026-03-01T22:07:30.198Z" }, + { url = "https://files.pythonhosted.org/packages/2d/86/ed7a73ab85ef00e8bb70b0cb5421d8a2a625b81a333941a469a6f4022828/yarl-1.23.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:041b1a4cefacf65840b4e295c6985f334ba83c30607441ae3cf206a0eed1a2e4", size = 95882, upload-time = "2026-03-01T22:07:32.132Z" }, + { url = "https://files.pythonhosted.org/packages/19/90/d56967f61a29d8498efb7afb651e0b2b422a1e9b47b0ab5f4e40a19b699b/yarl-1.23.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:d38c1e8231722c4ce40d7593f28d92b5fc72f3e9774fe73d7e800ec32299f63a", size = 90797, upload-time = "2026-03-01T22:07:34.404Z" }, + { url = "https://files.pythonhosted.org/packages/72/00/8b8f76909259f56647adb1011d7ed8b321bcf97e464515c65016a47ecdf0/yarl-1.23.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:d53834e23c015ee83a99377db6e5e37d8484f333edb03bd15b4bc312cc7254fb", size = 101023, upload-time = "2026-03-01T22:07:35.953Z" }, + { url = "https://files.pythonhosted.org/packages/ac/e2/cab11b126fb7d440281b7df8e9ddbe4851e70a4dde47a202b6642586b8d9/yarl-1.23.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:2e27c8841126e017dd2a054a95771569e6070b9ee1b133366d8b31beb5018a41", size = 96227, upload-time = "2026-03-01T22:07:37.594Z" }, + { url = "https://files.pythonhosted.org/packages/c2/9b/2c893e16bfc50e6b2edf76c1a9eb6cb0c744346197e74c65e99ad8d634d0/yarl-1.23.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:76855800ac56f878847a09ce6dba727c93ca2d89c9e9d63002d26b916810b0a2", size = 100302, upload-time = "2026-03-01T22:07:39.334Z" }, + { url = "https://files.pythonhosted.org/packages/28/ec/5498c4e3a6d5f1003beb23405671c2eb9cdbf3067d1c80f15eeafe301010/yarl-1.23.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e09fd068c2e169a7070d83d3bde728a4d48de0549f975290be3c108c02e499b4", size = 98202, upload-time = "2026-03-01T22:07:41.717Z" }, + { url = "https://files.pythonhosted.org/packages/fe/c3/cd737e2d45e70717907f83e146f6949f20cc23cd4bf7b2688727763aa458/yarl-1.23.0-cp314-cp314t-win32.whl", hash = "sha256:73309162a6a571d4cbd3b6a1dcc703c7311843ae0d1578df6f09be4e98df38d4", size = 90558, upload-time = "2026-03-01T22:07:43.433Z" }, + { url = "https://files.pythonhosted.org/packages/e1/19/3774d162f6732d1cfb0b47b4140a942a35ca82bb19b6db1f80e9e7bdc8f8/yarl-1.23.0-cp314-cp314t-win_amd64.whl", hash = "sha256:4503053d296bc6e4cbd1fad61cf3b6e33b939886c4f249ba7c78b602214fabe2", size = 97610, upload-time = "2026-03-01T22:07:45.773Z" }, + { url = "https://files.pythonhosted.org/packages/51/47/3fa2286c3cb162c71cdb34c4224d5745a1ceceb391b2bd9b19b668a8d724/yarl-1.23.0-cp314-cp314t-win_arm64.whl", hash = "sha256:44bb7bef4ea409384e3f8bc36c063d77ea1b8d4a5b2706956c0d6695f07dcc25", size = 86041, upload-time = "2026-03-01T22:07:49.026Z" }, + { url = "https://files.pythonhosted.org/packages/69/68/c8739671f5699c7dc470580a4f821ef37c32c4cb0b047ce223a7f115757f/yarl-1.23.0-py3-none-any.whl", hash = "sha256:a2df6afe50dea8ae15fa34c9f824a3ee958d785fd5d089063d960bae1daa0a3f", size = 48288, upload-time = "2026-03-01T22:07:51.388Z" }, ] [[package]] diff --git a/apps/agentstack-server/.vscode/launch.json b/apps/agentstack-server/.vscode/launch.json index 8093ae3392..3e8b38bdf9 100644 --- a/apps/agentstack-server/.vscode/launch.json +++ b/apps/agentstack-server/.vscode/launch.json @@ -14,6 +14,8 @@ "--timeout-keep-alive=60", "--timeout-graceful-shutdown=2" ], + "envFile": "${workspaceFolder}/.env", + "console": "internalConsole", }, { "name": "debug-file", diff --git a/apps/agentstack-server/uv.lock b/apps/agentstack-server/uv.lock index 1e2f88e0ee..13c84dbcb5 100644 --- a/apps/agentstack-server/uv.lock +++ b/apps/agentstack-server/uv.lock @@ -4,8 +4,8 @@ requires-python = "==3.14.*" [[package]] name = "a2a-sdk" -version = "0.3.24.post37.dev0+dce3650" -source = { git = "https://github.com/a2aproject/a2a-python.git?rev=1.0-dev#dce36502b51f671ae0e0a926cc0ad8c208393329" } +version = "0.3.24.post41.dev0+041f0f5" +source = { git = "https://github.com/a2aproject/a2a-python.git?rev=1.0-dev#041f0f53bcf5fc2e74545d653bfeeba8d2d85c79" } dependencies = [ { name = "google-api-core" }, { name = "googleapis-common-protos" }, @@ -458,14 +458,14 @@ wheels = [ [[package]] name = "authlib" -version = "1.6.8" +version = "1.6.9" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cryptography" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/6b/6c/c88eac87468c607f88bc24df1f3b31445ee6fc9ba123b09e666adf687cd9/authlib-1.6.8.tar.gz", hash = "sha256:41ae180a17cf672bc784e4a518e5c82687f1fe1e98b0cafaeda80c8e4ab2d1cb", size = 165074, upload-time = "2026-02-14T04:02:17.941Z" } +sdist = { url = "https://files.pythonhosted.org/packages/af/98/00d3dd826d46959ad8e32af2dbb2398868fd9fd0683c26e56d0789bd0e68/authlib-1.6.9.tar.gz", hash = "sha256:d8f2421e7e5980cc1ddb4e32d3f5fa659cfaf60d8eaf3281ebed192e4ab74f04", size = 165134, upload-time = "2026-03-02T07:44:01.998Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9b/73/f7084bf12755113cd535ae586782ff3a6e710bfbe6a0d13d1c2f81ffbbfa/authlib-1.6.8-py2.py3-none-any.whl", hash = "sha256:97286fd7a15e6cfefc32771c8ef9c54f0ed58028f1322de6a2a7c969c3817888", size = 244116, upload-time = "2026-02-14T04:02:15.579Z" }, + { url = "https://files.pythonhosted.org/packages/53/23/b65f568ed0c22f1efacb744d2db1a33c8068f384b8c9b482b52ebdbc3ef6/authlib-1.6.9-py2.py3-none-any.whl", hash = "sha256:f08b4c14e08f0861dc18a32357b33fbcfd2ea86cfe3fe149484b4d764c4a0ac3", size = 244197, upload-time = "2026-03-02T07:44:00.307Z" }, ] [[package]] @@ -750,7 +750,7 @@ wheels = [ [[package]] name = "fastapi" -version = "0.133.1" +version = "0.135.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "annotated-doc" }, @@ -759,9 +759,9 @@ dependencies = [ { name = "typing-extensions" }, { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/22/6f/0eafed8349eea1fa462238b54a624c8b408cd1ba2795c8e64aa6c34f8ab7/fastapi-0.133.1.tar.gz", hash = "sha256:ed152a45912f102592976fde6cbce7dae1a8a1053da94202e51dd35d184fadd6", size = 378741, upload-time = "2026-02-25T18:18:17.398Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/7b/f8e0211e9380f7195ba3f3d40c292594fd81ba8ec4629e3854c353aaca45/fastapi-0.135.1.tar.gz", hash = "sha256:d04115b508d936d254cea545b7312ecaa58a7b3a0f84952535b4c9afae7668cd", size = 394962, upload-time = "2026-03-01T18:18:29.369Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/c9/a175a7779f3599dfa4adfc97a6ce0e157237b3d7941538604aadaf97bfb6/fastapi-0.133.1-py3-none-any.whl", hash = "sha256:658f34ba334605b1617a65adf2ea6461901bdb9af3a3080d63ff791ecf7dc2e2", size = 109029, upload-time = "2026-02-25T18:18:18.578Z" }, + { url = "https://files.pythonhosted.org/packages/e4/72/42e900510195b23a56bde950d26a51f8b723846bfcaa0286e90287f0422b/fastapi-0.135.1-py3-none-any.whl", hash = "sha256:46e2fc5745924b7c840f71ddd277382af29ce1cdb7d5eab5bf697e3fb9999c9e", size = 116999, upload-time = "2026-03-01T18:18:30.831Z" }, ] [package.optional-dependencies] @@ -2219,11 +2219,11 @@ wheels = [ [[package]] name = "python-dotenv" -version = "1.2.1" +version = "1.2.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f0/26/19cadc79a718c5edbec86fd4919a6b6d3f681039a2f6d66d14be94e75fb9/python_dotenv-1.2.1.tar.gz", hash = "sha256:42667e897e16ab0d66954af0e60a9caa94f0fd4ecf3aaf6d2d260eec1aa36ad6", size = 44221, upload-time = "2025-10-26T15:12:10.434Z" } +sdist = { url = "https://files.pythonhosted.org/packages/82/ed/0301aeeac3e5353ef3d94b6ec08bbcabd04a72018415dcb29e588514bba8/python_dotenv-1.2.2.tar.gz", hash = "sha256:2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3", size = 50135, upload-time = "2026-03-01T16:00:26.196Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61", size = 21230, upload-time = "2025-10-26T15:12:09.109Z" }, + { url = "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl", hash = "sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a", size = 22101, upload-time = "2026-03-01T16:00:25.09Z" }, ] [[package]] @@ -2592,15 +2592,15 @@ wheels = [ [[package]] name = "sse-starlette" -version = "3.2.0" +version = "3.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, { name = "starlette" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/8b/8d/00d280c03ffd39aaee0e86ec81e2d3b9253036a0f93f51d10503adef0e65/sse_starlette-3.2.0.tar.gz", hash = "sha256:8127594edfb51abe44eac9c49e59b0b01f1039d0c7461c6fd91d4e03b70da422", size = 27253, upload-time = "2026-01-17T13:11:05.62Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/9f/c3695c2d2d4ef70072c3a06992850498b01c6bc9be531950813716b426fa/sse_starlette-3.3.2.tar.gz", hash = "sha256:678fca55a1945c734d8472a6cad186a55ab02840b4f6786f5ee8770970579dcd", size = 32326, upload-time = "2026-02-28T11:24:34.36Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/96/7f/832f015020844a8b8f7a9cbc103dd76ba8e3875004c41e08440ea3a2b41a/sse_starlette-3.2.0-py3-none-any.whl", hash = "sha256:5876954bd51920fc2cd51baee47a080eb88a37b5b784e615abb0b283f801cdbf", size = 12763, upload-time = "2026-01-17T13:11:03.775Z" }, + { url = "https://files.pythonhosted.org/packages/61/28/8cb142d3fe80c4a2d8af54ca0b003f47ce0ba920974e7990fa6e016402d1/sse_starlette-3.3.2-py3-none-any.whl", hash = "sha256:5c3ea3dad425c601236726af2f27689b74494643f57017cafcb6f8c9acfbb862", size = 14270, upload-time = "2026-02-28T11:24:32.984Z" }, ] [[package]] @@ -2856,48 +2856,52 @@ wheels = [ [[package]] name = "yarl" -version = "1.22.0" +version = "1.23.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "idna" }, { name = "multidict" }, { name = "propcache" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/57/63/0c6ebca57330cd313f6102b16dd57ffaf3ec4c83403dcb45dbd15c6f3ea1/yarl-1.22.0.tar.gz", hash = "sha256:bebf8557577d4401ba8bd9ff33906f1376c877aa78d1fe216ad01b4d6745af71", size = 187169, upload-time = "2025-10-06T14:12:55.963Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/46/b3/e20ef504049f1a1c54a814b4b9bed96d1ac0e0610c3b4da178f87209db05/yarl-1.22.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:34b36c2c57124530884d89d50ed2c1478697ad7473efd59cfd479945c95650e4", size = 140520, upload-time = "2025-10-06T14:11:15.465Z" }, - { url = "https://files.pythonhosted.org/packages/e4/04/3532d990fdbab02e5ede063676b5c4260e7f3abea2151099c2aa745acc4c/yarl-1.22.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:0dd9a702591ca2e543631c2a017e4a547e38a5c0f29eece37d9097e04a7ac683", size = 93504, upload-time = "2025-10-06T14:11:17.106Z" }, - { url = "https://files.pythonhosted.org/packages/11/63/ff458113c5c2dac9a9719ac68ee7c947cb621432bcf28c9972b1c0e83938/yarl-1.22.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:594fcab1032e2d2cc3321bb2e51271e7cd2b516c7d9aee780ece81b07ff8244b", size = 94282, upload-time = "2025-10-06T14:11:19.064Z" }, - { url = "https://files.pythonhosted.org/packages/a7/bc/315a56aca762d44a6aaaf7ad253f04d996cb6b27bad34410f82d76ea8038/yarl-1.22.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f3d7a87a78d46a2e3d5b72587ac14b4c16952dd0887dbb051451eceac774411e", size = 372080, upload-time = "2025-10-06T14:11:20.996Z" }, - { url = "https://files.pythonhosted.org/packages/3f/3f/08e9b826ec2e099ea6e7c69a61272f4f6da62cb5b1b63590bb80ca2e4a40/yarl-1.22.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:852863707010316c973162e703bddabec35e8757e67fcb8ad58829de1ebc8590", size = 338696, upload-time = "2025-10-06T14:11:22.847Z" }, - { url = "https://files.pythonhosted.org/packages/e3/9f/90360108e3b32bd76789088e99538febfea24a102380ae73827f62073543/yarl-1.22.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:131a085a53bfe839a477c0845acf21efc77457ba2bcf5899618136d64f3303a2", size = 387121, upload-time = "2025-10-06T14:11:24.889Z" }, - { url = "https://files.pythonhosted.org/packages/98/92/ab8d4657bd5b46a38094cfaea498f18bb70ce6b63508fd7e909bd1f93066/yarl-1.22.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:078a8aefd263f4d4f923a9677b942b445a2be970ca24548a8102689a3a8ab8da", size = 394080, upload-time = "2025-10-06T14:11:27.307Z" }, - { url = "https://files.pythonhosted.org/packages/f5/e7/d8c5a7752fef68205296201f8ec2bf718f5c805a7a7e9880576c67600658/yarl-1.22.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bca03b91c323036913993ff5c738d0842fc9c60c4648e5c8d98331526df89784", size = 372661, upload-time = "2025-10-06T14:11:29.387Z" }, - { url = "https://files.pythonhosted.org/packages/b6/2e/f4d26183c8db0bb82d491b072f3127fb8c381a6206a3a56332714b79b751/yarl-1.22.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:68986a61557d37bb90d3051a45b91fa3d5c516d177dfc6dd6f2f436a07ff2b6b", size = 364645, upload-time = "2025-10-06T14:11:31.423Z" }, - { url = "https://files.pythonhosted.org/packages/80/7c/428e5812e6b87cd00ee8e898328a62c95825bf37c7fa87f0b6bb2ad31304/yarl-1.22.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:4792b262d585ff0dff6bcb787f8492e40698443ec982a3568c2096433660c694", size = 355361, upload-time = "2025-10-06T14:11:33.055Z" }, - { url = "https://files.pythonhosted.org/packages/ec/2a/249405fd26776f8b13c067378ef4d7dd49c9098d1b6457cdd152a99e96a9/yarl-1.22.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:ebd4549b108d732dba1d4ace67614b9545b21ece30937a63a65dd34efa19732d", size = 381451, upload-time = "2025-10-06T14:11:35.136Z" }, - { url = "https://files.pythonhosted.org/packages/67/a8/fb6b1adbe98cf1e2dd9fad71003d3a63a1bc22459c6e15f5714eb9323b93/yarl-1.22.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:f87ac53513d22240c7d59203f25cc3beac1e574c6cd681bbfd321987b69f95fd", size = 383814, upload-time = "2025-10-06T14:11:37.094Z" }, - { url = "https://files.pythonhosted.org/packages/d9/f9/3aa2c0e480fb73e872ae2814c43bc1e734740bb0d54e8cb2a95925f98131/yarl-1.22.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:22b029f2881599e2f1b06f8f1db2ee63bd309e2293ba2d566e008ba12778b8da", size = 370799, upload-time = "2025-10-06T14:11:38.83Z" }, - { url = "https://files.pythonhosted.org/packages/50/3c/af9dba3b8b5eeb302f36f16f92791f3ea62e3f47763406abf6d5a4a3333b/yarl-1.22.0-cp314-cp314-win32.whl", hash = "sha256:6a635ea45ba4ea8238463b4f7d0e721bad669f80878b7bfd1f89266e2ae63da2", size = 82990, upload-time = "2025-10-06T14:11:40.624Z" }, - { url = "https://files.pythonhosted.org/packages/ac/30/ac3a0c5bdc1d6efd1b41fa24d4897a4329b3b1e98de9449679dd327af4f0/yarl-1.22.0-cp314-cp314-win_amd64.whl", hash = "sha256:0d6e6885777af0f110b0e5d7e5dda8b704efed3894da26220b7f3d887b839a79", size = 88292, upload-time = "2025-10-06T14:11:42.578Z" }, - { url = "https://files.pythonhosted.org/packages/df/0a/227ab4ff5b998a1b7410abc7b46c9b7a26b0ca9e86c34ba4b8d8bc7c63d5/yarl-1.22.0-cp314-cp314-win_arm64.whl", hash = "sha256:8218f4e98d3c10d683584cb40f0424f4b9fd6e95610232dd75e13743b070ee33", size = 82888, upload-time = "2025-10-06T14:11:44.863Z" }, - { url = "https://files.pythonhosted.org/packages/06/5e/a15eb13db90abd87dfbefb9760c0f3f257ac42a5cac7e75dbc23bed97a9f/yarl-1.22.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:45c2842ff0e0d1b35a6bf1cd6c690939dacb617a70827f715232b2e0494d55d1", size = 146223, upload-time = "2025-10-06T14:11:46.796Z" }, - { url = "https://files.pythonhosted.org/packages/18/82/9665c61910d4d84f41a5bf6837597c89e665fa88aa4941080704645932a9/yarl-1.22.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:d947071e6ebcf2e2bee8fce76e10faca8f7a14808ca36a910263acaacef08eca", size = 95981, upload-time = "2025-10-06T14:11:48.845Z" }, - { url = "https://files.pythonhosted.org/packages/5d/9a/2f65743589809af4d0a6d3aa749343c4b5f4c380cc24a8e94a3c6625a808/yarl-1.22.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:334b8721303e61b00019474cc103bdac3d7b1f65e91f0bfedeec2d56dfe74b53", size = 97303, upload-time = "2025-10-06T14:11:50.897Z" }, - { url = "https://files.pythonhosted.org/packages/b0/ab/5b13d3e157505c43c3b43b5a776cbf7b24a02bc4cccc40314771197e3508/yarl-1.22.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e7ce67c34138a058fd092f67d07a72b8e31ff0c9236e751957465a24b28910c", size = 361820, upload-time = "2025-10-06T14:11:52.549Z" }, - { url = "https://files.pythonhosted.org/packages/fb/76/242a5ef4677615cf95330cfc1b4610e78184400699bdda0acb897ef5e49a/yarl-1.22.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d77e1b2c6d04711478cb1c4ab90db07f1609ccf06a287d5607fcd90dc9863acf", size = 323203, upload-time = "2025-10-06T14:11:54.225Z" }, - { url = "https://files.pythonhosted.org/packages/8c/96/475509110d3f0153b43d06164cf4195c64d16999e0c7e2d8a099adcd6907/yarl-1.22.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4647674b6150d2cae088fc07de2738a84b8bcedebef29802cf0b0a82ab6face", size = 363173, upload-time = "2025-10-06T14:11:56.069Z" }, - { url = "https://files.pythonhosted.org/packages/c9/66/59db471aecfbd559a1fd48aedd954435558cd98c7d0da8b03cc6c140a32c/yarl-1.22.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:efb07073be061c8f79d03d04139a80ba33cbd390ca8f0297aae9cce6411e4c6b", size = 373562, upload-time = "2025-10-06T14:11:58.783Z" }, - { url = "https://files.pythonhosted.org/packages/03/1f/c5d94abc91557384719da10ff166b916107c1b45e4d0423a88457071dd88/yarl-1.22.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e51ac5435758ba97ad69617e13233da53908beccc6cfcd6c34bbed8dcbede486", size = 339828, upload-time = "2025-10-06T14:12:00.686Z" }, - { url = "https://files.pythonhosted.org/packages/5f/97/aa6a143d3afba17b6465733681c70cf175af89f76ec8d9286e08437a7454/yarl-1.22.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:33e32a0dd0c8205efa8e83d04fc9f19313772b78522d1bdc7d9aed706bfd6138", size = 347551, upload-time = "2025-10-06T14:12:02.628Z" }, - { url = "https://files.pythonhosted.org/packages/43/3c/45a2b6d80195959239a7b2a8810506d4eea5487dce61c2a3393e7fc3c52e/yarl-1.22.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:bf4a21e58b9cde0e401e683ebd00f6ed30a06d14e93f7c8fd059f8b6e8f87b6a", size = 334512, upload-time = "2025-10-06T14:12:04.871Z" }, - { url = "https://files.pythonhosted.org/packages/86/a0/c2ab48d74599c7c84cb104ebd799c5813de252bea0f360ffc29d270c2caa/yarl-1.22.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:e4b582bab49ac33c8deb97e058cd67c2c50dac0dd134874106d9c774fd272529", size = 352400, upload-time = "2025-10-06T14:12:06.624Z" }, - { url = "https://files.pythonhosted.org/packages/32/75/f8919b2eafc929567d3d8411f72bdb1a2109c01caaab4ebfa5f8ffadc15b/yarl-1.22.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:0b5bcc1a9c4839e7e30b7b30dd47fe5e7e44fb7054ec29b5bb8d526aa1041093", size = 357140, upload-time = "2025-10-06T14:12:08.362Z" }, - { url = "https://files.pythonhosted.org/packages/cf/72/6a85bba382f22cf78add705d8c3731748397d986e197e53ecc7835e76de7/yarl-1.22.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c0232bce2170103ec23c454e54a57008a9a72b5d1c3105dc2496750da8cfa47c", size = 341473, upload-time = "2025-10-06T14:12:10.994Z" }, - { url = "https://files.pythonhosted.org/packages/35/18/55e6011f7c044dc80b98893060773cefcfdbf60dfefb8cb2f58b9bacbd83/yarl-1.22.0-cp314-cp314t-win32.whl", hash = "sha256:8009b3173bcd637be650922ac455946197d858b3630b6d8787aa9e5c4564533e", size = 89056, upload-time = "2025-10-06T14:12:13.317Z" }, - { url = "https://files.pythonhosted.org/packages/f9/86/0f0dccb6e59a9e7f122c5afd43568b1d31b8ab7dda5f1b01fb5c7025c9a9/yarl-1.22.0-cp314-cp314t-win_amd64.whl", hash = "sha256:9fb17ea16e972c63d25d4a97f016d235c78dd2344820eb35bc034bc32012ee27", size = 96292, upload-time = "2025-10-06T14:12:15.398Z" }, - { url = "https://files.pythonhosted.org/packages/48/b7/503c98092fb3b344a179579f55814b613c1fbb1c23b3ec14a7b008a66a6e/yarl-1.22.0-cp314-cp314t-win_arm64.whl", hash = "sha256:9f6d73c1436b934e3f01df1e1b21ff765cd1d28c77dfb9ace207f746d4610ee1", size = 85171, upload-time = "2025-10-06T14:12:16.935Z" }, - { url = "https://files.pythonhosted.org/packages/73/ae/b48f95715333080afb75a4504487cbe142cae1268afc482d06692d605ae6/yarl-1.22.0-py3-none-any.whl", hash = "sha256:1380560bdba02b6b6c90de54133c81c9f2a453dee9912fe58c1dcced1edb7cff", size = 46814, upload-time = "2025-10-06T14:12:53.872Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/23/6e/beb1beec874a72f23815c1434518bfc4ed2175065173fb138c3705f658d4/yarl-1.23.0.tar.gz", hash = "sha256:53b1ea6ca88ebd4420379c330aea57e258408dd0df9af0992e5de2078dc9f5d5", size = 194676, upload-time = "2026-03-01T22:07:53.373Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/90/98/b85a038d65d1b92c3903ab89444f48d3cee490a883477b716d7a24b1a78c/yarl-1.23.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:21d1b7305a71a15b4794b5ff22e8eef96ff4a6d7f9657155e5aa419444b28912", size = 124455, upload-time = "2026-03-01T22:06:43.615Z" }, + { url = "https://files.pythonhosted.org/packages/39/54/bc2b45559f86543d163b6e294417a107bb87557609007c007ad889afec18/yarl-1.23.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:85610b4f27f69984932a7abbe52703688de3724d9f72bceb1cca667deff27474", size = 86752, upload-time = "2026-03-01T22:06:45.425Z" }, + { url = "https://files.pythonhosted.org/packages/24/f9/e8242b68362bffe6fb536c8db5076861466fc780f0f1b479fc4ffbebb128/yarl-1.23.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:23f371bd662cf44a7630d4d113101eafc0cfa7518a2760d20760b26021454719", size = 86291, upload-time = "2026-03-01T22:06:46.974Z" }, + { url = "https://files.pythonhosted.org/packages/ea/d8/d1cb2378c81dd729e98c716582b1ccb08357e8488e4c24714658cc6630e8/yarl-1.23.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c4a80f77dc1acaaa61f0934176fccca7096d9b1ff08c8ba9cddf5ae034a24319", size = 99026, upload-time = "2026-03-01T22:06:48.459Z" }, + { url = "https://files.pythonhosted.org/packages/0a/ff/7196790538f31debe3341283b5b0707e7feb947620fc5e8236ef28d44f72/yarl-1.23.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:bd654fad46d8d9e823afbb4f87c79160b5a374ed1ff5bde24e542e6ba8f41434", size = 92355, upload-time = "2026-03-01T22:06:50.306Z" }, + { url = "https://files.pythonhosted.org/packages/c1/56/25d58c3eddde825890a5fe6aa1866228377354a3c39262235234ab5f616b/yarl-1.23.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:682bae25f0a0dd23a056739f23a134db9f52a63e2afd6bfb37ddc76292bbd723", size = 106417, upload-time = "2026-03-01T22:06:52.1Z" }, + { url = "https://files.pythonhosted.org/packages/51/8a/882c0e7bc8277eb895b31bce0138f51a1ba551fc2e1ec6753ffc1e7c1377/yarl-1.23.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a82836cab5f197a0514235aaf7ffccdc886ccdaa2324bc0aafdd4ae898103039", size = 106422, upload-time = "2026-03-01T22:06:54.424Z" }, + { url = "https://files.pythonhosted.org/packages/42/2b/fef67d616931055bf3d6764885990a3ac647d68734a2d6a9e1d13de437a2/yarl-1.23.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1c57676bdedc94cd3bc37724cf6f8cd2779f02f6aba48de45feca073e714fe52", size = 101915, upload-time = "2026-03-01T22:06:55.895Z" }, + { url = "https://files.pythonhosted.org/packages/18/6a/530e16aebce27c5937920f3431c628a29a4b6b430fab3fd1c117b26ff3f6/yarl-1.23.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c7f8dc16c498ff06497c015642333219871effba93e4a2e8604a06264aca5c5c", size = 100690, upload-time = "2026-03-01T22:06:58.21Z" }, + { url = "https://files.pythonhosted.org/packages/88/08/93749219179a45e27b036e03260fda05190b911de8e18225c294ac95bbc9/yarl-1.23.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:5ee586fb17ff8f90c91cf73c6108a434b02d69925f44f5f8e0d7f2f260607eae", size = 98750, upload-time = "2026-03-01T22:06:59.794Z" }, + { url = "https://files.pythonhosted.org/packages/d9/cf/ea424a004969f5d81a362110a6ac1496d79efdc6d50c2c4b2e3ea0fc2519/yarl-1.23.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:17235362f580149742739cc3828b80e24029d08cbb9c4bda0242c7b5bc610a8e", size = 94685, upload-time = "2026-03-01T22:07:01.375Z" }, + { url = "https://files.pythonhosted.org/packages/e2/b7/14341481fe568e2b0408bcf1484c652accafe06a0ade9387b5d3fd9df446/yarl-1.23.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:0793e2bd0cf14234983bbb371591e6bea9e876ddf6896cdcc93450996b0b5c85", size = 106009, upload-time = "2026-03-01T22:07:03.151Z" }, + { url = "https://files.pythonhosted.org/packages/0a/e6/5c744a9b54f4e8007ad35bce96fbc9218338e84812d36f3390cea616881a/yarl-1.23.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:3650dc2480f94f7116c364096bc84b1d602f44224ef7d5c7208425915c0475dd", size = 100033, upload-time = "2026-03-01T22:07:04.701Z" }, + { url = "https://files.pythonhosted.org/packages/0c/23/e3bfc188d0b400f025bc49d99793d02c9abe15752138dcc27e4eaf0c4a9e/yarl-1.23.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:f40e782d49630ad384db66d4d8b73ff4f1b8955dc12e26b09a3e3af064b3b9d6", size = 106483, upload-time = "2026-03-01T22:07:06.231Z" }, + { url = "https://files.pythonhosted.org/packages/72/42/f0505f949a90b3f8b7a363d6cbdf398f6e6c58946d85c6d3a3bc70595b26/yarl-1.23.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:94f8575fbdf81749008d980c17796097e645574a3b8c28ee313931068dad14fe", size = 102175, upload-time = "2026-03-01T22:07:08.4Z" }, + { url = "https://files.pythonhosted.org/packages/aa/65/b39290f1d892a9dd671d1c722014ca062a9c35d60885d57e5375db0404b5/yarl-1.23.0-cp314-cp314-win32.whl", hash = "sha256:c8aa34a5c864db1087d911a0b902d60d203ea3607d91f615acd3f3108ac32169", size = 83871, upload-time = "2026-03-01T22:07:09.968Z" }, + { url = "https://files.pythonhosted.org/packages/a9/5b/9b92f54c784c26e2a422e55a8d2607ab15b7ea3349e28359282f84f01d43/yarl-1.23.0-cp314-cp314-win_amd64.whl", hash = "sha256:63e92247f383c85ab00dd0091e8c3fa331a96e865459f5ee80353c70a4a42d70", size = 89093, upload-time = "2026-03-01T22:07:11.501Z" }, + { url = "https://files.pythonhosted.org/packages/e0/7d/8a84dc9381fd4412d5e7ff04926f9865f6372b4c2fd91e10092e65d29eb8/yarl-1.23.0-cp314-cp314-win_arm64.whl", hash = "sha256:70efd20be968c76ece7baa8dafe04c5be06abc57f754d6f36f3741f7aa7a208e", size = 83384, upload-time = "2026-03-01T22:07:13.069Z" }, + { url = "https://files.pythonhosted.org/packages/dd/8d/d2fad34b1c08aa161b74394183daa7d800141aaaee207317e82c790b418d/yarl-1.23.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:9a18d6f9359e45722c064c97464ec883eb0e0366d33eda61cb19a244bf222679", size = 131019, upload-time = "2026-03-01T22:07:14.903Z" }, + { url = "https://files.pythonhosted.org/packages/19/ff/33009a39d3ccf4b94d7d7880dfe17fb5816c5a4fe0096d9b56abceea9ac7/yarl-1.23.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:2803ed8b21ca47a43da80a6fd1ed3019d30061f7061daa35ac54f63933409412", size = 89894, upload-time = "2026-03-01T22:07:17.372Z" }, + { url = "https://files.pythonhosted.org/packages/0c/f1/dab7ac5e7306fb79c0190766a3c00b4cb8d09a1f390ded68c85a5934faf5/yarl-1.23.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:394906945aa8b19fc14a61cf69743a868bb8c465efe85eee687109cc540b98f4", size = 89979, upload-time = "2026-03-01T22:07:19.361Z" }, + { url = "https://files.pythonhosted.org/packages/aa/b1/08e95f3caee1fad6e65017b9f26c1d79877b502622d60e517de01e72f95d/yarl-1.23.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:71d006bee8397a4a89f469b8deb22469fe7508132d3c17fa6ed871e79832691c", size = 95943, upload-time = "2026-03-01T22:07:21.266Z" }, + { url = "https://files.pythonhosted.org/packages/c0/cc/6409f9018864a6aa186c61175b977131f373f1988e198e031236916e87e4/yarl-1.23.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:62694e275c93d54f7ccedcfef57d42761b2aad5234b6be1f3e3026cae4001cd4", size = 88786, upload-time = "2026-03-01T22:07:23.129Z" }, + { url = "https://files.pythonhosted.org/packages/76/40/cc22d1d7714b717fde2006fad2ced5efe5580606cb059ae42117542122f3/yarl-1.23.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a31de1613658308efdb21ada98cbc86a97c181aa050ba22a808120bb5be3ab94", size = 101307, upload-time = "2026-03-01T22:07:24.689Z" }, + { url = "https://files.pythonhosted.org/packages/8f/0d/476c38e85ddb4c6ec6b20b815bdd779aa386a013f3d8b85516feee55c8dc/yarl-1.23.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fb1e8b8d66c278b21d13b0a7ca22c41dd757a7c209c6b12c313e445c31dd3b28", size = 100904, upload-time = "2026-03-01T22:07:26.287Z" }, + { url = "https://files.pythonhosted.org/packages/72/32/0abe4a76d59adf2081dcb0397168553ece4616ada1c54d1c49d8936c74f8/yarl-1.23.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50f9d8d531dfb767c565f348f33dd5139a6c43f5cbdf3f67da40d54241df93f6", size = 97728, upload-time = "2026-03-01T22:07:27.906Z" }, + { url = "https://files.pythonhosted.org/packages/b7/35/7b30f4810fba112f60f5a43237545867504e15b1c7647a785fbaf588fac2/yarl-1.23.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:575aa4405a656e61a540f4a80eaa5260f2a38fff7bfdc4b5f611840d76e9e277", size = 95964, upload-time = "2026-03-01T22:07:30.198Z" }, + { url = "https://files.pythonhosted.org/packages/2d/86/ed7a73ab85ef00e8bb70b0cb5421d8a2a625b81a333941a469a6f4022828/yarl-1.23.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:041b1a4cefacf65840b4e295c6985f334ba83c30607441ae3cf206a0eed1a2e4", size = 95882, upload-time = "2026-03-01T22:07:32.132Z" }, + { url = "https://files.pythonhosted.org/packages/19/90/d56967f61a29d8498efb7afb651e0b2b422a1e9b47b0ab5f4e40a19b699b/yarl-1.23.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:d38c1e8231722c4ce40d7593f28d92b5fc72f3e9774fe73d7e800ec32299f63a", size = 90797, upload-time = "2026-03-01T22:07:34.404Z" }, + { url = "https://files.pythonhosted.org/packages/72/00/8b8f76909259f56647adb1011d7ed8b321bcf97e464515c65016a47ecdf0/yarl-1.23.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:d53834e23c015ee83a99377db6e5e37d8484f333edb03bd15b4bc312cc7254fb", size = 101023, upload-time = "2026-03-01T22:07:35.953Z" }, + { url = "https://files.pythonhosted.org/packages/ac/e2/cab11b126fb7d440281b7df8e9ddbe4851e70a4dde47a202b6642586b8d9/yarl-1.23.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:2e27c8841126e017dd2a054a95771569e6070b9ee1b133366d8b31beb5018a41", size = 96227, upload-time = "2026-03-01T22:07:37.594Z" }, + { url = "https://files.pythonhosted.org/packages/c2/9b/2c893e16bfc50e6b2edf76c1a9eb6cb0c744346197e74c65e99ad8d634d0/yarl-1.23.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:76855800ac56f878847a09ce6dba727c93ca2d89c9e9d63002d26b916810b0a2", size = 100302, upload-time = "2026-03-01T22:07:39.334Z" }, + { url = "https://files.pythonhosted.org/packages/28/ec/5498c4e3a6d5f1003beb23405671c2eb9cdbf3067d1c80f15eeafe301010/yarl-1.23.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e09fd068c2e169a7070d83d3bde728a4d48de0549f975290be3c108c02e499b4", size = 98202, upload-time = "2026-03-01T22:07:41.717Z" }, + { url = "https://files.pythonhosted.org/packages/fe/c3/cd737e2d45e70717907f83e146f6949f20cc23cd4bf7b2688727763aa458/yarl-1.23.0-cp314-cp314t-win32.whl", hash = "sha256:73309162a6a571d4cbd3b6a1dcc703c7311843ae0d1578df6f09be4e98df38d4", size = 90558, upload-time = "2026-03-01T22:07:43.433Z" }, + { url = "https://files.pythonhosted.org/packages/e1/19/3774d162f6732d1cfb0b47b4140a942a35ca82bb19b6db1f80e9e7bdc8f8/yarl-1.23.0-cp314-cp314t-win_amd64.whl", hash = "sha256:4503053d296bc6e4cbd1fad61cf3b6e33b939886c4f249ba7c78b602214fabe2", size = 97610, upload-time = "2026-03-01T22:07:45.773Z" }, + { url = "https://files.pythonhosted.org/packages/51/47/3fa2286c3cb162c71cdb34c4224d5745a1ceceb391b2bd9b19b668a8d724/yarl-1.23.0-cp314-cp314t-win_arm64.whl", hash = "sha256:44bb7bef4ea409384e3f8bc36c063d77ea1b8d4a5b2706956c0d6695f07dcc25", size = 86041, upload-time = "2026-03-01T22:07:49.026Z" }, + { url = "https://files.pythonhosted.org/packages/69/68/c8739671f5699c7dc470580a4f821ef37c32c4cb0b047ce223a7f115757f/yarl-1.23.0-py3-none-any.whl", hash = "sha256:a2df6afe50dea8ae15fa34c9f824a3ee958d785fd5d089063d960bae1daa0a3f", size = 48288, upload-time = "2026-03-01T22:07:51.388Z" }, ] [[package]] From 88c3c0a4e9076f722e36106ba369890b97fa64f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radek=20Je=C5=BEek?= Date: Thu, 5 Mar 2026 13:46:21 +0100 Subject: [PATCH 5/6] fix(a2a): adapt to a2a-sdk breaking changes - Remove ServerError wrapper (class removed in new SDK) - Replace A2AClientJSONRPCError with A2AClientError - Replace A2AClientHTTPError with A2AClientError - Replace MethodNotImplementedError with UnsupportedOperationError - Remove ERROR_CODE_MAP usage (SDK now raises typed errors directly) - Remove unused fastapi.responses import --- agents/chat/Dockerfile | 2 +- agents/chat/uv.lock | 124 ++++----- apps/agentstack-cli/src/agentstack_cli/api.py | 4 +- apps/agentstack-cli/uv.lock | 260 +++++------------- apps/agentstack-sdk-py/tests/e2e/test_runs.py | 4 +- apps/agentstack-sdk-py/uv.lock | 82 +++--- apps/agentstack-server/Dockerfile | 2 +- .../src/agentstack_server/api/routes/a2a.py | 1 - .../service_layer/services/a2a.py | 22 +- .../tests/e2e/agents/test_agent_starts.py | 4 +- .../tests/e2e/routes/test_a2a_proxy.py | 4 +- apps/agentstack-server/uv.lock | 158 +++++------ 12 files changed, 266 insertions(+), 401 deletions(-) diff --git a/agents/chat/Dockerfile b/agents/chat/Dockerfile index c1ce9b1fc4..f8e0b04163 100644 --- a/agents/chat/Dockerfile +++ b/agents/chat/Dockerfile @@ -3,7 +3,7 @@ ARG UV_VERSION=0.10.7 FROM ghcr.io/astral-sh/uv:${UV_VERSION} AS uv FROM python:3.14-alpine3.23@sha256:faee120f7885a06fcc9677922331391fa690d911c020abb9e8025ff3d908e510 ARG RELEASE_VERSION="main" -RUN apk add bash git nodejs npm +RUN apk add bash git nodejs npm curl COPY ./agents/chat/ /app/agents/chat COPY ./apps/agentstack-sdk-py/ /app/apps/agentstack-sdk-py/ WORKDIR /app/agents/chat diff --git a/agents/chat/uv.lock b/agents/chat/uv.lock index e6887ea4d2..9f0e3d41d8 100644 --- a/agents/chat/uv.lock +++ b/agents/chat/uv.lock @@ -4,8 +4,8 @@ requires-python = "==3.14.*" [[package]] name = "a2a-sdk" -version = "0.3.24.post41.dev0+041f0f5" -source = { git = "https://github.com/a2aproject/a2a-python.git?rev=1.0-dev#041f0f53bcf5fc2e74545d653bfeeba8d2d85c79" } +version = "0.3.24.post54.dev0+5b354e4" +source = { git = "https://github.com/a2aproject/a2a-python.git?rev=1.0-dev#5b354e403a717c3c6bf47a291bef028c8c6a9d94" } dependencies = [ { name = "google-api-core" }, { name = "googleapis-common-protos" }, @@ -298,11 +298,11 @@ wikipedia = [ [[package]] name = "cachetools" -version = "7.0.1" +version = "7.0.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d4/07/56595285564e90777d758ebd383d6b0b971b87729bbe2184a849932a3736/cachetools-7.0.1.tar.gz", hash = "sha256:e31e579d2c5b6e2944177a0397150d312888ddf4e16e12f1016068f0c03b8341", size = 36126, upload-time = "2026-02-10T22:24:05.03Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6c/c7/342b33cc6877eebc6c9bb45cb9f78e170e575839699f6f3cc96050176431/cachetools-7.0.2.tar.gz", hash = "sha256:7e7f09a4ca8b791d8bb4864afc71e9c17e607a28e6839ca1a644253c97dbeae0", size = 36983, upload-time = "2026-03-02T19:45:16.926Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ed/9e/5faefbf9db1db466d633735faceda1f94aa99ce506ac450d232536266b32/cachetools-7.0.1-py3-none-any.whl", hash = "sha256:8f086515c254d5664ae2146d14fc7f65c9a4bce75152eb247e5a9c5e6d7b2ecf", size = 13484, upload-time = "2026-02-10T22:24:03.741Z" }, + { url = "https://files.pythonhosted.org/packages/ef/04/4b6968e77c110f12da96fdbfcb39c6557c2e5e81bd7afcf8ed893d5bc588/cachetools-7.0.2-py3-none-any.whl", hash = "sha256:938dcad184827c5e94928c4fd5526e2b46692b7fb1ae94472da9131d0299343c", size = 13793, upload-time = "2026-03-02T19:45:15.495Z" }, ] [[package]] @@ -496,16 +496,16 @@ wheels = [ [[package]] name = "ddgs" -version = "9.11.1" +version = "9.11.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, { name = "lxml" }, { name = "primp" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fa/06/b148a33eb074ef0cde6f82a83dc2af2ec60d2a63f3e39b049dd8abdfaf39/ddgs-9.11.1.tar.gz", hash = "sha256:f01aec85e59ffe73dbab4517628d24702fb6ce2c345d2f5e6dd4b120526b56c7", size = 34442, upload-time = "2026-03-02T06:45:23.341Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6b/80/eb387dd4291d1624e773f455fd1dfc54596e06469d680fe3b3f8c326ba1a/ddgs-9.11.2.tar.gz", hash = "sha256:b5f072149580773291fd3eb6e9f4de47fa9d910ebd5ef85845a37e59cfe24c40", size = 34722, upload-time = "2026-03-05T05:17:31.574Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/92/6b/446ce962d40f243c90f704aceadaa1f577e35db11677323e35b7c4b55867/ddgs-9.11.1-py3-none-any.whl", hash = "sha256:404382a17c6055f28aa752809bd100ca23167611bb77368aa4c7012e254a16b8", size = 43304, upload-time = "2026-03-02T06:45:22.283Z" }, + { url = "https://files.pythonhosted.org/packages/2c/fe/7591bfa694ee26fcf0dd8035811994e28a9699402d3861eea7754958c1bd/ddgs-9.11.2-py3-none-any.whl", hash = "sha256:0023a3633d271e72cdd1da757d3fcea2d996608da3f3c9da2cc0c0607b219c76", size = 43646, upload-time = "2026-03-05T05:17:30.469Z" }, ] [[package]] @@ -1172,7 +1172,7 @@ wheels = [ [[package]] name = "openinference-instrumentation" -version = "0.1.45" +version = "0.1.46" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "openinference-semantic-conventions" }, @@ -1180,9 +1180,9 @@ dependencies = [ { name = "opentelemetry-sdk" }, { name = "wrapt" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/89/25/26db627b2d1d13030fdfb23cfa4437d6bb7e9c7ee42a8ec22b50e64edb6d/openinference_instrumentation-0.1.45.tar.gz", hash = "sha256:71d58cf4a9849351ed2dccfcd023277e80d2c9326d7cb67017c8ec2062df4c9b", size = 23989, upload-time = "2026-02-24T05:59:42.222Z" } +sdist = { url = "https://files.pythonhosted.org/packages/64/8d/9b76b43e8b2ee2ccf1fe15b21c924095f9c0e4839919bcd4951b1c99c2ab/openinference_instrumentation-0.1.46.tar.gz", hash = "sha256:0b520002a1c682c525dcab49005c209bfd71611e8e4e4933b49779d5e899e6db", size = 23937, upload-time = "2026-03-04T10:13:48.883Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/41/a3/f652a6ae71f33800bce4dffb727e8e5b3b0061d4ac9b6b166f0fc3ca4ed7/openinference_instrumentation-0.1.45-py3-none-any.whl", hash = "sha256:ee4bf930b8133210d6a5eb5577ca097dd9926035676e8a3a5b2ebb7e4a1129da", size = 30118, upload-time = "2026-02-24T05:59:40.456Z" }, + { url = "https://files.pythonhosted.org/packages/25/d1/f6668492152a4180492044313e2dc427fbc237904f6bb1629abd030e3469/openinference_instrumentation-0.1.46-py3-none-any.whl", hash = "sha256:f7b63ccd5f93ce82e4e40035c9faa6b021984cbe06ad791f4cf033551533bc48", size = 30124, upload-time = "2026-03-04T10:13:47.613Z" }, ] [[package]] @@ -1205,41 +1205,41 @@ wheels = [ [[package]] name = "openinference-semantic-conventions" -version = "0.1.26" +version = "0.1.27" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5a/91/f67c1971deaf5b75dea84731393bca2042ff4a46acae9a727dfe267dd568/openinference_semantic_conventions-0.1.26.tar.gz", hash = "sha256:34dae06b40743fb7b846a36fd402810a554b2ec4ee96b9dd8b820663aee4a1f1", size = 12782, upload-time = "2026-02-01T01:09:46.095Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b4/cf/7c0ea344b99ecdb9f55cb5287ecb6a6ad68e6098df32728691fa7846f112/openinference_semantic_conventions-0.1.27.tar.gz", hash = "sha256:db0b1bbc1cd66f8108b17f972976fa1833413a01967ff930e2707a77e0f66bd3", size = 12744, upload-time = "2026-03-04T08:38:56.974Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6b/ca/bb4b9cbd96f72600abec5280cf8ed67bcd849ed19b8bec919aec97adb61c/openinference_semantic_conventions-0.1.26-py3-none-any.whl", hash = "sha256:35b4f487d18ac7d016125c428c0d950dd290e18dafb99787880a9b2e05745f42", size = 10401, upload-time = "2026-02-01T01:09:44.781Z" }, + { url = "https://files.pythonhosted.org/packages/27/b4/1c218ed1e68c8fbd68f37258ce40f908cdad86ee9d38b12c48c9e4c4e030/openinference_semantic_conventions-0.1.27-py3-none-any.whl", hash = "sha256:3871fd2cc9d203bdb444ab66ff2ba9bdbf1013dc48c64c5700dd449d47b338c5", size = 10430, upload-time = "2026-03-04T08:38:56.166Z" }, ] [[package]] name = "opentelemetry-api" -version = "1.39.1" +version = "1.40.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "importlib-metadata" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/97/b9/3161be15bb8e3ad01be8be5a968a9237c3027c5be504362ff800fca3e442/opentelemetry_api-1.39.1.tar.gz", hash = "sha256:fbde8c80e1b937a2c61f20347e91c0c18a1940cecf012d62e65a7caf08967c9c", size = 65767, upload-time = "2025-12-11T13:32:39.182Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2c/1d/4049a9e8698361cc1a1aa03a6c59e4fa4c71e0c0f94a30f988a6876a2ae6/opentelemetry_api-1.40.0.tar.gz", hash = "sha256:159be641c0b04d11e9ecd576906462773eb97ae1b657730f0ecf64d32071569f", size = 70851, upload-time = "2026-03-04T14:17:21.555Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cf/df/d3f1ddf4bb4cb50ed9b1139cc7b1c54c34a1e7ce8fd1b9a37c0d1551a6bd/opentelemetry_api-1.39.1-py3-none-any.whl", hash = "sha256:2edd8463432a7f8443edce90972169b195e7d6a05500cd29e6d13898187c9950", size = 66356, upload-time = "2025-12-11T13:32:17.304Z" }, + { url = "https://files.pythonhosted.org/packages/5f/bf/93795954016c522008da367da292adceed71cca6ee1717e1d64c83089099/opentelemetry_api-1.40.0-py3-none-any.whl", hash = "sha256:82dd69331ae74b06f6a874704be0cfaa49a1650e1537d4a813b86ecef7d0ecf9", size = 68676, upload-time = "2026-03-04T14:17:01.24Z" }, ] [[package]] name = "opentelemetry-exporter-otlp-proto-common" -version = "1.39.1" +version = "1.40.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-proto" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e9/9d/22d241b66f7bbde88a3bfa6847a351d2c46b84de23e71222c6aae25c7050/opentelemetry_exporter_otlp_proto_common-1.39.1.tar.gz", hash = "sha256:763370d4737a59741c89a67b50f9e39271639ee4afc999dadfe768541c027464", size = 20409, upload-time = "2025-12-11T13:32:40.885Z" } +sdist = { url = "https://files.pythonhosted.org/packages/51/bc/1559d46557fe6eca0b46c88d4c2676285f1f3be2e8d06bb5d15fbffc814a/opentelemetry_exporter_otlp_proto_common-1.40.0.tar.gz", hash = "sha256:1cbee86a4064790b362a86601ee7934f368b81cd4cc2f2e163902a6e7818a0fa", size = 20416, upload-time = "2026-03-04T14:17:23.801Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8c/02/ffc3e143d89a27ac21fd557365b98bd0653b98de8a101151d5805b5d4c33/opentelemetry_exporter_otlp_proto_common-1.39.1-py3-none-any.whl", hash = "sha256:08f8a5862d64cc3435105686d0216c1365dc5701f86844a8cd56597d0c764fde", size = 18366, upload-time = "2025-12-11T13:32:20.2Z" }, + { url = "https://files.pythonhosted.org/packages/8b/ca/8f122055c97a932311a3f640273f084e738008933503d0c2563cd5d591fc/opentelemetry_exporter_otlp_proto_common-1.40.0-py3-none-any.whl", hash = "sha256:7081ff453835a82417bf38dccf122c827c3cbc94f2079b03bba02a3165f25149", size = 18369, upload-time = "2026-03-04T14:17:04.796Z" }, ] [[package]] name = "opentelemetry-exporter-otlp-proto-http" -version = "1.39.1" +version = "1.40.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "googleapis-common-protos" }, @@ -1250,14 +1250,14 @@ dependencies = [ { name = "requests" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/80/04/2a08fa9c0214ae38880df01e8bfae12b067ec0793446578575e5080d6545/opentelemetry_exporter_otlp_proto_http-1.39.1.tar.gz", hash = "sha256:31bdab9745c709ce90a49a0624c2bd445d31a28ba34275951a6a362d16a0b9cb", size = 17288, upload-time = "2025-12-11T13:32:42.029Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2e/fa/73d50e2c15c56be4d000c98e24221d494674b0cc95524e2a8cb3856d95a4/opentelemetry_exporter_otlp_proto_http-1.40.0.tar.gz", hash = "sha256:db48f5e0f33217588bbc00274a31517ba830da576e59503507c839b38fa0869c", size = 17772, upload-time = "2026-03-04T14:17:25.324Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/95/f1/b27d3e2e003cd9a3592c43d099d2ed8d0a947c15281bf8463a256db0b46c/opentelemetry_exporter_otlp_proto_http-1.39.1-py3-none-any.whl", hash = "sha256:d9f5207183dd752a412c4cd564ca8875ececba13be6e9c6c370ffb752fd59985", size = 19641, upload-time = "2025-12-11T13:32:22.248Z" }, + { url = "https://files.pythonhosted.org/packages/a0/3a/8865d6754e61c9fb170cdd530a124a53769ee5f740236064816eb0ca7301/opentelemetry_exporter_otlp_proto_http-1.40.0-py3-none-any.whl", hash = "sha256:a8d1dab28f504c5d96577d6509f80a8150e44e8f45f82cdbe0e34c99ab040069", size = 19960, upload-time = "2026-03-04T14:17:07.153Z" }, ] [[package]] name = "opentelemetry-instrumentation" -version = "0.60b1" +version = "0.61b0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, @@ -1265,14 +1265,14 @@ dependencies = [ { name = "packaging" }, { name = "wrapt" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/41/0f/7e6b713ac117c1f5e4e3300748af699b9902a2e5e34c9cf443dde25a01fa/opentelemetry_instrumentation-0.60b1.tar.gz", hash = "sha256:57ddc7974c6eb35865af0426d1a17132b88b2ed8586897fee187fd5b8944bd6a", size = 31706, upload-time = "2025-12-11T13:36:42.515Z" } +sdist = { url = "https://files.pythonhosted.org/packages/da/37/6bf8e66bfcee5d3c6515b79cb2ee9ad05fe573c20f7ceb288d0e7eeec28c/opentelemetry_instrumentation-0.61b0.tar.gz", hash = "sha256:cb21b48db738c9de196eba6b805b4ff9de3b7f187e4bbf9a466fa170514f1fc7", size = 32606, upload-time = "2026-03-04T14:20:16.825Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/77/d2/6788e83c5c86a2690101681aeef27eeb2a6bf22df52d3f263a22cee20915/opentelemetry_instrumentation-0.60b1-py3-none-any.whl", hash = "sha256:04480db952b48fb1ed0073f822f0ee26012b7be7c3eac1a3793122737c78632d", size = 33096, upload-time = "2025-12-11T13:35:33.067Z" }, + { url = "https://files.pythonhosted.org/packages/d8/3e/f6f10f178b6316de67f0dfdbbb699a24fbe8917cf1743c1595fb9dcdd461/opentelemetry_instrumentation-0.61b0-py3-none-any.whl", hash = "sha256:92a93a280e69788e8f88391247cc530fd81f16f2b011979d4d6398f805cfbc63", size = 33448, upload-time = "2026-03-04T14:19:02.447Z" }, ] [[package]] name = "opentelemetry-instrumentation-asgi" -version = "0.60b1" +version = "0.61b0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "asgiref" }, @@ -1281,14 +1281,14 @@ dependencies = [ { name = "opentelemetry-semantic-conventions" }, { name = "opentelemetry-util-http" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/77/db/851fa88db7441da82d50bd80f2de5ee55213782e25dc858e04d0c9961d60/opentelemetry_instrumentation_asgi-0.60b1.tar.gz", hash = "sha256:16bfbe595cd24cda309a957456d0fc2523f41bc7b076d1f2d7e98a1ad9876d6f", size = 26107, upload-time = "2025-12-11T13:36:47.015Z" } +sdist = { url = "https://files.pythonhosted.org/packages/00/3e/143cf5c034e58037307e6a24f06e0dd64b2c49ae60a965fc580027581931/opentelemetry_instrumentation_asgi-0.61b0.tar.gz", hash = "sha256:9d08e127244361dc33976d39dd4ca8f128b5aa5a7ae425208400a80a095019b5", size = 26691, upload-time = "2026-03-04T14:20:21.038Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/76/76/1fb94367cef64420d2171157a6b9509582873bd09a6afe08a78a8d1f59d9/opentelemetry_instrumentation_asgi-0.60b1-py3-none-any.whl", hash = "sha256:d48def2dbed10294c99cfcf41ebbd0c414d390a11773a41f472d20000fcddc25", size = 16933, upload-time = "2025-12-11T13:35:40.462Z" }, + { url = "https://files.pythonhosted.org/packages/19/78/154470cf9d741a7487fbb5067357b87386475bbb77948a6707cae982e158/opentelemetry_instrumentation_asgi-0.61b0-py3-none-any.whl", hash = "sha256:e4b3ce6b66074e525e717efff20745434e5efd5d9df6557710856fba356da7a4", size = 16980, upload-time = "2026-03-04T14:19:10.894Z" }, ] [[package]] name = "opentelemetry-instrumentation-fastapi" -version = "0.60b1" +version = "0.61b0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, @@ -1297,14 +1297,14 @@ dependencies = [ { name = "opentelemetry-semantic-conventions" }, { name = "opentelemetry-util-http" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9c/e7/e7e5e50218cf488377209d85666b182fa2d4928bf52389411ceeee1b2b60/opentelemetry_instrumentation_fastapi-0.60b1.tar.gz", hash = "sha256:de608955f7ff8eecf35d056578346a5365015fd7d8623df9b1f08d1c74769c01", size = 24958, upload-time = "2025-12-11T13:36:59.35Z" } +sdist = { url = "https://files.pythonhosted.org/packages/37/35/aa727bb6e6ef930dcdc96a617b83748fece57b43c47d83ba8d83fbeca657/opentelemetry_instrumentation_fastapi-0.61b0.tar.gz", hash = "sha256:3a24f35b07c557ae1bbc483bf8412221f25d79a405f8b047de8b670722e2fa9f", size = 24800, upload-time = "2026-03-04T14:20:32.759Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7d/cc/6e808328ba54662e50babdcab21138eae4250bc0fddf67d55526a615a2ca/opentelemetry_instrumentation_fastapi-0.60b1-py3-none-any.whl", hash = "sha256:af94b7a239ad1085fc3a820ecf069f67f579d7faf4c085aaa7bd9b64eafc8eaf", size = 13478, upload-time = "2025-12-11T13:36:00.811Z" }, + { url = "https://files.pythonhosted.org/packages/91/05/acfeb2cccd434242a0a7d0ea29afaf077e04b42b35b485d89aee4e0d9340/opentelemetry_instrumentation_fastapi-0.61b0-py3-none-any.whl", hash = "sha256:a1a844d846540d687d377516b2ff698b51d87c781b59f47c214359c4a241047c", size = 13485, upload-time = "2026-03-04T14:19:30.351Z" }, ] [[package]] name = "opentelemetry-instrumentation-httpx" -version = "0.60b1" +version = "0.61b0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, @@ -1313,14 +1313,14 @@ dependencies = [ { name = "opentelemetry-util-http" }, { name = "wrapt" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/86/08/11208bcfcab4fc2023252c3f322aa397fd9ad948355fea60f5fc98648603/opentelemetry_instrumentation_httpx-0.60b1.tar.gz", hash = "sha256:a506ebaf28c60112cbe70ad4f0338f8603f148938cb7b6794ce1051cd2b270ae", size = 20611, upload-time = "2025-12-11T13:37:01.661Z" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/2a/e2becd55e33c29d1d9ef76e2579040ed1951cb33bacba259f6aff2fdd2a6/opentelemetry_instrumentation_httpx-0.61b0.tar.gz", hash = "sha256:6569ec097946c5551c2a4252f74c98666addd1bf047c1dde6b4ef426719ff8dd", size = 24104, upload-time = "2026-03-04T14:20:34.752Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/43/59/b98e84eebf745ffc75397eaad4763795bff8a30cbf2373a50ed4e70646c5/opentelemetry_instrumentation_httpx-0.60b1-py3-none-any.whl", hash = "sha256:f37636dd742ad2af83d896ba69601ed28da51fa4e25d1ab62fde89ce413e275b", size = 15701, upload-time = "2025-12-11T13:36:04.56Z" }, + { url = "https://files.pythonhosted.org/packages/af/88/dde310dce56e2d85cf1a09507f5888544955309edc4b8d22971d6d3d1417/opentelemetry_instrumentation_httpx-0.61b0-py3-none-any.whl", hash = "sha256:dee05c93a6593a5dc3ae5d9d5c01df8b4e2c5d02e49275e5558534ee46343d5e", size = 17198, upload-time = "2026-03-04T14:19:33.585Z" }, ] [[package]] name = "opentelemetry-instrumentation-openai" -version = "0.52.6" +version = "0.53.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, @@ -1328,48 +1328,48 @@ dependencies = [ { name = "opentelemetry-semantic-conventions" }, { name = "opentelemetry-semantic-conventions-ai" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/37/86/1fe5008f3714118fdc1024cd141140a5f204d5ac7016e87a0f07a834efb2/opentelemetry_instrumentation_openai-0.52.6.tar.gz", hash = "sha256:0eb23dc90804a726e516fcbd649cb99f10dfdb5e31d29e44c4b1b8f402dd905d", size = 6978397, upload-time = "2026-02-26T15:40:17.154Z" } +sdist = { url = "https://files.pythonhosted.org/packages/10/b7/b3b5536671658001c62c117fa834df2a3bd524e950a7773d53b71fca3219/opentelemetry_instrumentation_openai-0.53.0.tar.gz", hash = "sha256:c0cd83d223d138309af3cc5f53c9c6d22136374bfa00e8f66dff31cd322ef547", size = 6978375, upload-time = "2026-03-04T07:49:18.112Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/4a/4623d0adc0187cc45bce631f891c30cd01cf2562d37b918b79561200d985/opentelemetry_instrumentation_openai-0.52.6-py3-none-any.whl", hash = "sha256:5e174388520f294f648f9732471c1b9919c71e5d09649a64ab8ff81714c1278b", size = 43084, upload-time = "2026-02-26T15:39:35.584Z" }, + { url = "https://files.pythonhosted.org/packages/44/3b/58ac94d0f56afb3c0352d3e6d35ea9de6331292a7316403ea97de4c6d915/opentelemetry_instrumentation_openai-0.53.0-py3-none-any.whl", hash = "sha256:91d9f69673636f5f7d50e5a4782e4526d6df3a1ddfd6ac2d9e15a957f8fd9ad8", size = 43084, upload-time = "2026-03-04T07:48:43.676Z" }, ] [[package]] name = "opentelemetry-proto" -version = "1.39.1" +version = "1.40.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/49/1d/f25d76d8260c156c40c97c9ed4511ec0f9ce353f8108ca6e7561f82a06b2/opentelemetry_proto-1.39.1.tar.gz", hash = "sha256:6c8e05144fc0d3ed4d22c2289c6b126e03bcd0e6a7da0f16cedd2e1c2772e2c8", size = 46152, upload-time = "2025-12-11T13:32:48.681Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4c/77/dd38991db037fdfce45849491cb61de5ab000f49824a00230afb112a4392/opentelemetry_proto-1.40.0.tar.gz", hash = "sha256:03f639ca129ba513f5819810f5b1f42bcb371391405d99c168fe6937c62febcd", size = 45667, upload-time = "2026-03-04T14:17:31.194Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/51/95/b40c96a7b5203005a0b03d8ce8cd212ff23f1793d5ba289c87a097571b18/opentelemetry_proto-1.39.1-py3-none-any.whl", hash = "sha256:22cdc78efd3b3765d09e68bfbd010d4fc254c9818afd0b6b423387d9dee46007", size = 72535, upload-time = "2025-12-11T13:32:33.866Z" }, + { url = "https://files.pythonhosted.org/packages/b9/b2/189b2577dde745b15625b3214302605b1353436219d42b7912e77fa8dc24/opentelemetry_proto-1.40.0-py3-none-any.whl", hash = "sha256:266c4385d88923a23d63e353e9761af0f47a6ed0d486979777fe4de59dc9b25f", size = 72073, upload-time = "2026-03-04T14:17:16.673Z" }, ] [[package]] name = "opentelemetry-sdk" -version = "1.39.1" +version = "1.40.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, { name = "opentelemetry-semantic-conventions" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/eb/fb/c76080c9ba07e1e8235d24cdcc4d125ef7aa3edf23eb4e497c2e50889adc/opentelemetry_sdk-1.39.1.tar.gz", hash = "sha256:cf4d4563caf7bff906c9f7967e2be22d0d6b349b908be0d90fb21c8e9c995cc6", size = 171460, upload-time = "2025-12-11T13:32:49.369Z" } +sdist = { url = "https://files.pythonhosted.org/packages/58/fd/3c3125b20ba18ce2155ba9ea74acb0ae5d25f8cd39cfd37455601b7955cc/opentelemetry_sdk-1.40.0.tar.gz", hash = "sha256:18e9f5ec20d859d268c7cb3c5198c8d105d073714db3de50b593b8c1345a48f2", size = 184252, upload-time = "2026-03-04T14:17:31.87Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7c/98/e91cf858f203d86f4eccdf763dcf01cf03f1dae80c3750f7e635bfa206b6/opentelemetry_sdk-1.39.1-py3-none-any.whl", hash = "sha256:4d5482c478513ecb0a5d938dcc61394e647066e0cc2676bee9f3af3f3f45f01c", size = 132565, upload-time = "2025-12-11T13:32:35.069Z" }, + { url = "https://files.pythonhosted.org/packages/2c/c5/6a852903d8bfac758c6dc6e9a68b015d3c33f2f1be5e9591e0f4b69c7e0a/opentelemetry_sdk-1.40.0-py3-none-any.whl", hash = "sha256:787d2154a71f4b3d81f20524a8ce061b7db667d24e46753f32a7bc48f1c1f3f1", size = 141951, upload-time = "2026-03-04T14:17:17.961Z" }, ] [[package]] name = "opentelemetry-semantic-conventions" -version = "0.60b1" +version = "0.61b0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/91/df/553f93ed38bf22f4b999d9be9c185adb558982214f33eae539d3b5cd0858/opentelemetry_semantic_conventions-0.60b1.tar.gz", hash = "sha256:87c228b5a0669b748c76d76df6c364c369c28f1c465e50f661e39737e84bc953", size = 137935, upload-time = "2025-12-11T13:32:50.487Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6d/c0/4ae7973f3c2cfd2b6e321f1675626f0dab0a97027cc7a297474c9c8f3d04/opentelemetry_semantic_conventions-0.61b0.tar.gz", hash = "sha256:072f65473c5d7c6dc0355b27d6c9d1a679d63b6d4b4b16a9773062cb7e31192a", size = 145755, upload-time = "2026-03-04T14:17:32.664Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7a/5e/5958555e09635d09b75de3c4f8b9cae7335ca545d77392ffe7331534c402/opentelemetry_semantic_conventions-0.60b1-py3-none-any.whl", hash = "sha256:9fa8c8b0c110da289809292b0591220d3a7b53c1526a23021e977d68597893fb", size = 219982, upload-time = "2025-12-11T13:32:36.955Z" }, + { url = "https://files.pythonhosted.org/packages/b2/37/cc6a55e448deaa9b27377d087da8615a3416d8ad523d5960b78dbeadd02a/opentelemetry_semantic_conventions-0.61b0-py3-none-any.whl", hash = "sha256:fa530a96be229795f8cef353739b618148b0fe2b4b3f005e60e262926c4d38e2", size = 231621, upload-time = "2026-03-04T14:17:19.33Z" }, ] [[package]] @@ -1387,11 +1387,11 @@ wheels = [ [[package]] name = "opentelemetry-util-http" -version = "0.60b1" +version = "0.61b0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/50/fc/c47bb04a1d8a941a4061307e1eddfa331ed4d0ab13d8a9781e6db256940a/opentelemetry_util_http-0.60b1.tar.gz", hash = "sha256:0d97152ca8c8a41ced7172d29d3622a219317f74ae6bb3027cfbdcf22c3cc0d6", size = 11053, upload-time = "2025-12-11T13:37:25.115Z" } +sdist = { url = "https://files.pythonhosted.org/packages/57/3c/f0196223efc5c4ca19f8fad3d5462b171ac6333013335ce540c01af419e9/opentelemetry_util_http-0.61b0.tar.gz", hash = "sha256:1039cb891334ad2731affdf034d8fb8b48c239af9b6dd295e5fabd07f1c95572", size = 11361, upload-time = "2026-03-04T14:20:57.01Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/16/5c/d3f1733665f7cd582ef0842fb1d2ed0bc1fba10875160593342d22bba375/opentelemetry_util_http-0.60b1-py3-none-any.whl", hash = "sha256:66381ba28550c91bee14dcba8979ace443444af1ed609226634596b4b0faf199", size = 8947, upload-time = "2025-12-11T13:36:37.151Z" }, + { url = "https://files.pythonhosted.org/packages/0d/e5/c08aaaf2f64288d2b6ef65741d2de5454e64af3e050f34285fb1907492fe/opentelemetry_util_http-0.61b0-py3-none-any.whl", hash = "sha256:8e715e848233e9527ea47e275659ea60a57a75edf5206a3b937e236a6da5fc33", size = 9281, upload-time = "2026-03-04T14:20:08.364Z" }, ] [[package]] @@ -1630,18 +1630,18 @@ crypto = [ [[package]] name = "pyrefly" -version = "0.54.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/81/44/c10b16a302fda90d0af1328f880b232761b510eab546616a7be2fdf35a57/pyrefly-0.54.0.tar.gz", hash = "sha256:c6663be64d492f0d2f2a411ada9f28a6792163d34133639378b7f3dd9a8dca94", size = 5098893, upload-time = "2026-02-23T15:44:35.111Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5f/99/8fdcdb4e55f0227fdd9f6abce36b619bab1ecb0662b83b66adc8cba3c788/pyrefly-0.54.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:58a3f092b6dc25ef79b2dc6c69a40f36784ca157c312bfc0baea463926a9db6d", size = 12223973, upload-time = "2026-02-23T15:44:14.278Z" }, - { url = "https://files.pythonhosted.org/packages/90/35/c2aaf87a76003ad27b286594d2e5178f811eaa15bfe3d98dba2b47d56dd1/pyrefly-0.54.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:615081414106dd95873bc39c3a4bed68754c6cc24a8177ac51d22f88f88d3eb3", size = 11785585, upload-time = "2026-02-23T15:44:17.468Z" }, - { url = "https://files.pythonhosted.org/packages/c4/4a/ced02691ed67e5a897714979196f08ad279ec7ec7f63c45e00a75a7f3c0e/pyrefly-0.54.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cbcaf20f5fe585079079a95205c1f3cd4542d17228cdf1df560288880623b70", size = 33381977, upload-time = "2026-02-23T15:44:19.736Z" }, - { url = "https://files.pythonhosted.org/packages/0b/ce/72a117ed437c8f6950862181014b41e36f3c3997580e29b772b71e78d587/pyrefly-0.54.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66d5da116c0d34acfbd66663addd3ca8aa78a636f6692a66e078126d3620a883", size = 35962821, upload-time = "2026-02-23T15:44:22.357Z" }, - { url = "https://files.pythonhosted.org/packages/85/de/89013f5ae0a35d2b6b01274a92a35ee91431ea001050edf0a16748d39875/pyrefly-0.54.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ef3ac27f1a4baaf67aead64287d3163350844794aca6315ad1a9650b16ec26a", size = 38496689, upload-time = "2026-02-23T15:44:25.236Z" }, - { url = "https://files.pythonhosted.org/packages/9f/9a/33b097c7bf498b924742dca32dd5d9c6a3fa6c2b52b63a58eb9e1980ca89/pyrefly-0.54.0-py3-none-win32.whl", hash = "sha256:7d607d72200a8afbd2db10bfefb40160a7a5d709d207161c21649cedd5cfc09a", size = 11295268, upload-time = "2026-02-23T15:44:27.551Z" }, - { url = "https://files.pythonhosted.org/packages/d4/21/9263fd1144d2a3d7342b474f183f7785b3358a1565c864089b780110b933/pyrefly-0.54.0-py3-none-win_amd64.whl", hash = "sha256:fd416f04f89309385696f685bd5c9141011f18c8072f84d31ca20c748546e791", size = 12081810, upload-time = "2026-02-23T15:44:29.461Z" }, - { url = "https://files.pythonhosted.org/packages/ea/5b/fad062a196c064cbc8564de5b2f4d3cb6315f852e3b31e8a1ce74c69a1ea/pyrefly-0.54.0-py3-none-win_arm64.whl", hash = "sha256:f06ab371356c7b1925e0bffe193b738797e71e5dbbff7fb5a13f90ee7521211d", size = 11564930, upload-time = "2026-02-23T15:44:33.053Z" }, +version = "0.55.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bf/c4/76e0797215e62d007f81f86c9c4fb5d6202685a3f5e70810f3fd94294f92/pyrefly-0.55.0.tar.gz", hash = "sha256:434c3282532dd4525c4840f2040ed0eb79b0ec8224fe18d957956b15471f2441", size = 5135682, upload-time = "2026-03-03T00:46:38.122Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/39/b0/16e50cf716784513648e23e726a24f71f9544aa4f86103032dcaa5ff71a2/pyrefly-0.55.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:49aafcefe5e2dd4256147db93e5b0ada42bff7d9a60db70e03d1f7055338eec9", size = 12210073, upload-time = "2026-03-03T00:46:15.51Z" }, + { url = "https://files.pythonhosted.org/packages/3a/ad/89500c01bac3083383011600370289fbc67700c5be46e781787392628a3a/pyrefly-0.55.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:2827426e6b28397c13badb93c0ede0fb0f48046a7a89e3d774cda04e8e2067cd", size = 11767474, upload-time = "2026-03-03T00:46:18.003Z" }, + { url = "https://files.pythonhosted.org/packages/78/68/4c66b260f817f304ead11176ff13985625f7c269e653304b4bdb546551af/pyrefly-0.55.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7346b2d64dc575bd61aa3bca854fbf8b5a19a471cbdb45e0ca1e09861b63488c", size = 33260395, upload-time = "2026-03-03T00:46:20.509Z" }, + { url = "https://files.pythonhosted.org/packages/47/09/10bd48c9f860064f29f412954126a827d60f6451512224912c265e26bbe6/pyrefly-0.55.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:233b861b4cff008b1aff62f4f941577ed752e4d0060834229eb9b6826e6973c9", size = 35848269, upload-time = "2026-03-03T00:46:23.418Z" }, + { url = "https://files.pythonhosted.org/packages/a9/39/bc65cdd5243eb2dfea25dd1321f9a5a93e8d9c3a308501c4c6c05d011585/pyrefly-0.55.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5aa85657d76da1d25d081a49f0e33c8fc3ec91c1a0f185a8ed393a5a3d9e178", size = 38449820, upload-time = "2026-03-03T00:46:26.309Z" }, + { url = "https://files.pythonhosted.org/packages/e5/64/58b38963b011af91209e87f868cc85cfc762ec49a4568ce610c45e7a5f40/pyrefly-0.55.0-py3-none-win32.whl", hash = "sha256:23f786a78536a56fed331b245b7d10ec8945bebee7b723491c8d66fdbc155fe6", size = 11259415, upload-time = "2026-03-03T00:46:30.875Z" }, + { url = "https://files.pythonhosted.org/packages/7a/0b/a4aa519ff632a1ea69eec942566951670b870b99b5c08407e1387b85b6a4/pyrefly-0.55.0-py3-none-win_amd64.whl", hash = "sha256:d465b49e999b50eeb069ad23f0f5710651cad2576f9452a82991bef557df91ee", size = 12043581, upload-time = "2026-03-03T00:46:33.674Z" }, + { url = "https://files.pythonhosted.org/packages/f1/51/89017636fbe1ffd166ad478990c6052df615b926182fa6d3c0842b407e89/pyrefly-0.55.0-py3-none-win_arm64.whl", hash = "sha256:732ff490e0e863b296e7c0b2471e08f8ba7952f9fa6e9de09d8347fd67dde77f", size = 11548076, upload-time = "2026-03-03T00:46:36.193Z" }, ] [[package]] diff --git a/apps/agentstack-cli/src/agentstack_cli/api.py b/apps/agentstack-cli/src/agentstack_cli/api.py index 8e73910baa..c821c2da2d 100644 --- a/apps/agentstack-cli/src/agentstack_cli/api.py +++ b/apps/agentstack-cli/src/agentstack_cli/api.py @@ -16,7 +16,7 @@ import httpx import openai import pydantic -from a2a.client import A2AClientHTTPError, Client, ClientConfig, ClientFactory +from a2a.client import A2AClientError, Client, ClientConfig, ClientFactory from a2a.types import AgentCard from agentstack_sdk.platform.context import ContextToken from google.protobuf.json_format import MessageToDict @@ -142,7 +142,7 @@ async def a2a_client(agent_card: AgentCard, context_token: ContextToken) -> Asyn yield ClientFactory(ClientConfig(httpx_client=httpx_client, use_client_preference=True)).create( card=agent_card ) - except A2AClientHTTPError as ex: + except A2AClientError as ex: card_data = json.dumps( pick(MessageToDict(agent_card), {"url", "additional_interfaces", "preferred_transport"}), indent=2, diff --git a/apps/agentstack-cli/uv.lock b/apps/agentstack-cli/uv.lock index 5bc4f84d3d..b1cfc253e2 100644 --- a/apps/agentstack-cli/uv.lock +++ b/apps/agentstack-cli/uv.lock @@ -1,11 +1,11 @@ version = 1 revision = 3 -requires-python = ">=3.13, <3.15" +requires-python = "==3.14.*" [[package]] name = "a2a-sdk" -version = "0.3.24.post37.dev0+dce3650" -source = { git = "https://github.com/a2aproject/a2a-python.git?rev=1.0-dev#dce36502b51f671ae0e0a926cc0ad8c208393329" } +version = "0.3.24.post54.dev0+5b354e4" +source = { git = "https://github.com/a2aproject/a2a-python.git?rev=1.0-dev#5b354e403a717c3c6bf47a291bef028c8c6a9d94" } dependencies = [ { name = "google-api-core" }, { name = "googleapis-common-protos" }, @@ -213,23 +213,23 @@ wheels = [ [[package]] name = "authlib" -version = "1.6.8" +version = "1.6.9" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cryptography" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/6b/6c/c88eac87468c607f88bc24df1f3b31445ee6fc9ba123b09e666adf687cd9/authlib-1.6.8.tar.gz", hash = "sha256:41ae180a17cf672bc784e4a518e5c82687f1fe1e98b0cafaeda80c8e4ab2d1cb", size = 165074, upload-time = "2026-02-14T04:02:17.941Z" } +sdist = { url = "https://files.pythonhosted.org/packages/af/98/00d3dd826d46959ad8e32af2dbb2398868fd9fd0683c26e56d0789bd0e68/authlib-1.6.9.tar.gz", hash = "sha256:d8f2421e7e5980cc1ddb4e32d3f5fa659cfaf60d8eaf3281ebed192e4ab74f04", size = 165134, upload-time = "2026-03-02T07:44:01.998Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9b/73/f7084bf12755113cd535ae586782ff3a6e710bfbe6a0d13d1c2f81ffbbfa/authlib-1.6.8-py2.py3-none-any.whl", hash = "sha256:97286fd7a15e6cfefc32771c8ef9c54f0ed58028f1322de6a2a7c969c3817888", size = 244116, upload-time = "2026-02-14T04:02:15.579Z" }, + { url = "https://files.pythonhosted.org/packages/53/23/b65f568ed0c22f1efacb744d2db1a33c8068f384b8c9b482b52ebdbc3ef6/authlib-1.6.9-py2.py3-none-any.whl", hash = "sha256:f08b4c14e08f0861dc18a32357b33fbcfd2ea86cfe3fe149484b4d764c4a0ac3", size = 244197, upload-time = "2026-03-02T07:44:00.307Z" }, ] [[package]] name = "cachetools" -version = "7.0.1" +version = "7.0.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d4/07/56595285564e90777d758ebd383d6b0b971b87729bbe2184a849932a3736/cachetools-7.0.1.tar.gz", hash = "sha256:e31e579d2c5b6e2944177a0397150d312888ddf4e16e12f1016068f0c03b8341", size = 36126, upload-time = "2026-02-10T22:24:05.03Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6c/c7/342b33cc6877eebc6c9bb45cb9f78e170e575839699f6f3cc96050176431/cachetools-7.0.2.tar.gz", hash = "sha256:7e7f09a4ca8b791d8bb4864afc71e9c17e607a28e6839ca1a644253c97dbeae0", size = 36983, upload-time = "2026-03-02T19:45:16.926Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ed/9e/5faefbf9db1db466d633735faceda1f94aa99ce506ac450d232536266b32/cachetools-7.0.1-py3-none-any.whl", hash = "sha256:8f086515c254d5664ae2146d14fc7f65c9a4bce75152eb247e5a9c5e6d7b2ecf", size = 13484, upload-time = "2026-02-10T22:24:03.741Z" }, + { url = "https://files.pythonhosted.org/packages/ef/04/4b6968e77c110f12da96fdbfcb39c6557c2e5e81bd7afcf8ed893d5bc588/cachetools-7.0.2-py3-none-any.whl", hash = "sha256:938dcad184827c5e94928c4fd5526e2b46692b7fb1ae94472da9131d0299343c", size = 13793, upload-time = "2026-03-02T19:45:15.495Z" }, ] [[package]] @@ -250,18 +250,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" }, - { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" }, - { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" }, - { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" }, - { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" }, - { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" }, - { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" }, - { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" }, - { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" }, - { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" }, - { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" }, - { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" }, { url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" }, { url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" }, { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" }, @@ -292,22 +280,6 @@ version = "3.4.4" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418, upload-time = "2025-10-14T04:42:32.879Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/97/45/4b3a1239bbacd321068ea6e7ac28875b03ab8bc0aa0966452db17cd36714/charset_normalizer-3.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794", size = 208091, upload-time = "2025-10-14T04:41:13.346Z" }, - { url = "https://files.pythonhosted.org/packages/7d/62/73a6d7450829655a35bb88a88fca7d736f9882a27eacdca2c6d505b57e2e/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b39f987ae8ccdf0d2642338faf2abb1862340facc796048b604ef14919e55ed", size = 147936, upload-time = "2025-10-14T04:41:14.461Z" }, - { url = "https://files.pythonhosted.org/packages/89/c5/adb8c8b3d6625bef6d88b251bbb0d95f8205831b987631ab0c8bb5d937c2/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3162d5d8ce1bb98dd51af660f2121c55d0fa541b46dff7bb9b9f86ea1d87de72", size = 144180, upload-time = "2025-10-14T04:41:15.588Z" }, - { url = "https://files.pythonhosted.org/packages/91/ed/9706e4070682d1cc219050b6048bfd293ccf67b3d4f5a4f39207453d4b99/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:81d5eb2a312700f4ecaa977a8235b634ce853200e828fbadf3a9c50bab278328", size = 161346, upload-time = "2025-10-14T04:41:16.738Z" }, - { url = "https://files.pythonhosted.org/packages/d5/0d/031f0d95e4972901a2f6f09ef055751805ff541511dc1252ba3ca1f80cf5/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5bd2293095d766545ec1a8f612559f6b40abc0eb18bb2f5d1171872d34036ede", size = 158874, upload-time = "2025-10-14T04:41:17.923Z" }, - { url = "https://files.pythonhosted.org/packages/f5/83/6ab5883f57c9c801ce5e5677242328aa45592be8a00644310a008d04f922/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894", size = 153076, upload-time = "2025-10-14T04:41:19.106Z" }, - { url = "https://files.pythonhosted.org/packages/75/1e/5ff781ddf5260e387d6419959ee89ef13878229732732ee73cdae01800f2/charset_normalizer-3.4.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc7637e2f80d8530ee4a78e878bce464f70087ce73cf7c1caf142416923b98f1", size = 150601, upload-time = "2025-10-14T04:41:20.245Z" }, - { url = "https://files.pythonhosted.org/packages/d7/57/71be810965493d3510a6ca79b90c19e48696fb1ff964da319334b12677f0/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f8bf04158c6b607d747e93949aa60618b61312fe647a6369f88ce2ff16043490", size = 150376, upload-time = "2025-10-14T04:41:21.398Z" }, - { url = "https://files.pythonhosted.org/packages/e5/d5/c3d057a78c181d007014feb7e9f2e65905a6c4ef182c0ddf0de2924edd65/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:554af85e960429cf30784dd47447d5125aaa3b99a6f0683589dbd27e2f45da44", size = 144825, upload-time = "2025-10-14T04:41:22.583Z" }, - { url = "https://files.pythonhosted.org/packages/e6/8c/d0406294828d4976f275ffbe66f00266c4b3136b7506941d87c00cab5272/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:74018750915ee7ad843a774364e13a3db91682f26142baddf775342c3f5b1133", size = 162583, upload-time = "2025-10-14T04:41:23.754Z" }, - { url = "https://files.pythonhosted.org/packages/d7/24/e2aa1f18c8f15c4c0e932d9287b8609dd30ad56dbe41d926bd846e22fb8d/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c0463276121fdee9c49b98908b3a89c39be45d86d1dbaa22957e38f6321d4ce3", size = 150366, upload-time = "2025-10-14T04:41:25.27Z" }, - { url = "https://files.pythonhosted.org/packages/e4/5b/1e6160c7739aad1e2df054300cc618b06bf784a7a164b0f238360721ab86/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:362d61fd13843997c1c446760ef36f240cf81d3ebf74ac62652aebaf7838561e", size = 160300, upload-time = "2025-10-14T04:41:26.725Z" }, - { url = "https://files.pythonhosted.org/packages/7a/10/f882167cd207fbdd743e55534d5d9620e095089d176d55cb22d5322f2afd/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc", size = 154465, upload-time = "2025-10-14T04:41:28.322Z" }, - { url = "https://files.pythonhosted.org/packages/89/66/c7a9e1b7429be72123441bfdbaf2bc13faab3f90b933f664db506dea5915/charset_normalizer-3.4.4-cp313-cp313-win32.whl", hash = "sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac", size = 99404, upload-time = "2025-10-14T04:41:29.95Z" }, - { url = "https://files.pythonhosted.org/packages/c4/26/b9924fa27db384bdcd97ab83b4f0a8058d96ad9626ead570674d5e737d90/charset_normalizer-3.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14", size = 107092, upload-time = "2025-10-14T04:41:31.188Z" }, - { url = "https://files.pythonhosted.org/packages/af/8f/3ed4bfa0c0c72a7ca17f0380cd9e4dd842b09f664e780c13cff1dcf2ef1b/charset_normalizer-3.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2", size = 100408, upload-time = "2025-10-14T04:41:32.624Z" }, { url = "https://files.pythonhosted.org/packages/2a/35/7051599bd493e62411d6ede36fd5af83a38f37c4767b92884df7301db25d/charset_normalizer-3.4.4-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:da3326d9e65ef63a817ecbcc0df6e94463713b754fe293eaa03da99befb9a5bd", size = 207746, upload-time = "2025-10-14T04:41:33.773Z" }, { url = "https://files.pythonhosted.org/packages/10/9a/97c8d48ef10d6cd4fcead2415523221624bf58bcf68a802721a6bc807c8f/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8af65f14dc14a79b924524b1e7fffe304517b2bff5a58bf64f30b98bbc5079eb", size = 147889, upload-time = "2025-10-14T04:41:34.897Z" }, { url = "https://files.pythonhosted.org/packages/10/bf/979224a919a1b606c82bd2c5fa49b5c6d5727aa47b4312bb27b1734f53cd/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74664978bb272435107de04e36db5a9735e78232b85b77d45cfb38f758efd33e", size = 143641, upload-time = "2025-10-14T04:41:36.116Z" }, @@ -412,19 +384,19 @@ wheels = [ [[package]] name = "faker" -version = "40.5.1" +version = "40.8.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "tzdata", marker = "sys_platform == 'win32'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/03/2a/96fff3edcb10f6505143448a4b91535f77b74865cec45be52690ee280443/faker-40.5.1.tar.gz", hash = "sha256:70222361cd82aa10cb86066d1a4e8f47f2bcdc919615c412045a69c4e6da0cd3", size = 1952684, upload-time = "2026-02-23T21:34:38.362Z" } +sdist = { url = "https://files.pythonhosted.org/packages/70/03/14428edc541467c460d363f6e94bee9acc271f3e62470630fc9a647d0cf2/faker-40.8.0.tar.gz", hash = "sha256:936a3c9be6c004433f20aa4d99095df5dec82b8c7ad07459756041f8c1728875", size = 1956493, upload-time = "2026-03-04T16:18:48.161Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/4d/a9/1eed4db92d0aec2f9bfdf1faae0ab0418b5e121dda5701f118a7a4f0cd6a/faker-40.5.1-py3-none-any.whl", hash = "sha256:c69640c1e13bad49b4bcebcbf1b52f9f1a872b6ea186c248ada34d798f1661bf", size = 1987053, upload-time = "2026-02-23T21:34:36.418Z" }, + { url = "https://files.pythonhosted.org/packages/4c/3b/c6348f1e285e75b069085b18110a4e6325b763a5d35d5e204356fc7c20b3/faker-40.8.0-py3-none-any.whl", hash = "sha256:eb21bdba18f7a8375382eb94fb436fce07046893dc94cb20817d28deb0c3d579", size = 1989124, upload-time = "2026-03-04T16:18:46.45Z" }, ] [[package]] name = "fastapi" -version = "0.133.1" +version = "0.135.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "annotated-doc" }, @@ -433,9 +405,9 @@ dependencies = [ { name = "typing-extensions" }, { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/22/6f/0eafed8349eea1fa462238b54a624c8b408cd1ba2795c8e64aa6c34f8ab7/fastapi-0.133.1.tar.gz", hash = "sha256:ed152a45912f102592976fde6cbce7dae1a8a1053da94202e51dd35d184fadd6", size = 378741, upload-time = "2026-02-25T18:18:17.398Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/7b/f8e0211e9380f7195ba3f3d40c292594fd81ba8ec4629e3854c353aaca45/fastapi-0.135.1.tar.gz", hash = "sha256:d04115b508d936d254cea545b7312ecaa58a7b3a0f84952535b4c9afae7668cd", size = 394962, upload-time = "2026-03-01T18:18:29.369Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/c9/a175a7779f3599dfa4adfc97a6ce0e157237b3d7941538604aadaf97bfb6/fastapi-0.133.1-py3-none-any.whl", hash = "sha256:658f34ba334605b1617a65adf2ea6461901bdb9af3a3080d63ff791ecf7dc2e2", size = 109029, upload-time = "2026-02-25T18:18:18.578Z" }, + { url = "https://files.pythonhosted.org/packages/e4/72/42e900510195b23a56bde950d26a51f8b723846bfcaa0286e90287f0422b/fastapi-0.135.1-py3-none-any.whl", hash = "sha256:46e2fc5745924b7c840f71ddd277382af29ce1cdb7d5eab5bf697e3fb9999c9e", size = 116999, upload-time = "2026-03-01T18:18:30.831Z" }, ] [[package]] @@ -444,14 +416,6 @@ version = "8.3.3" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/34/33/d0a1a41e687f0d1956cc5a7b07735c6893f3fa061440fddb7a2c9d2bcd35/gnureadline-8.3.3.tar.gz", hash = "sha256:0972392bd2f31244e2d981178246fe8b729c8766454fdaeb275946ac47b7e9fd", size = 3595875, upload-time = "2026-01-06T15:03:17.802Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1d/a6/69fc7b54bbc74797c8ede68904b6b1f3fe9c891f1bb6be12a6b40d5aa76c/gnureadline-8.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:14df36d06f8102caadff0df0a87ba33b381c2b22904f0ed2ad527784f5ec9f46", size = 167501, upload-time = "2026-01-06T15:04:11.297Z" }, - { url = "https://files.pythonhosted.org/packages/12/ae/1a20910eee2582eab73c4aea1ff6bd71ba78e0d12d58cddec32e7936fb42/gnureadline-8.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:75519fea565510a868389cd841e45d64140a323d723dda30edf72009c2e3362f", size = 167327, upload-time = "2026-01-06T15:04:12.401Z" }, - { url = "https://files.pythonhosted.org/packages/71/e2/e87ec94780fee48e0b614c609b41d97945839e2c5260d4c2e823507e87f6/gnureadline-8.3.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1267ba734d24ffbc8967191c5bc213f6dd8718284d917c69a3ee7d2541e60179", size = 698275, upload-time = "2026-01-06T15:04:13.881Z" }, - { url = "https://files.pythonhosted.org/packages/f5/09/9c9559ab69c5232a4f7f72614203331df68bf1bbfda446db0dc948f8d0d4/gnureadline-8.3.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a326ef2fb5e213518b96ef41b1f74c12f61d2ac8c2dca9ae6dbf88991b46244e", size = 705259, upload-time = "2026-01-06T15:04:15.216Z" }, - { url = "https://files.pythonhosted.org/packages/2a/ea/93d9bcccb3f0b02f9cf07c57c2492512f75b27d82fb722629698edf5356b/gnureadline-8.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:8012e70db91f13409f36655a10f9752c43d9848de6d1ed379b526f3f8a449a44", size = 168490, upload-time = "2026-01-06T15:04:16.526Z" }, - { url = "https://files.pythonhosted.org/packages/6e/85/fd0f7fce581c56a45e2d53e34c29c9b82b6c3fd082533872e54d105a1bf5/gnureadline-8.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:da1335bdc70fc99f45578d7cdeb89bd5a16e0d26785bbe5bcc1dc1acdd7a7734", size = 168265, upload-time = "2026-01-06T15:04:18.262Z" }, - { url = "https://files.pythonhosted.org/packages/4c/16/dee379d104a9b55e011b1e8d0f1bd15fcf6e96d57abcfbdf78c638f26aa1/gnureadline-8.3.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:11e4d8572eba509aca690e026928e1cd3df3f1b5ec39b551c6571cfd559f84e1", size = 712395, upload-time = "2026-01-06T15:04:19.72Z" }, - { url = "https://files.pythonhosted.org/packages/e1/fc/5d34adade939e65bc1a26d0485feb7167a52531237deb73c90cbc74348a8/gnureadline-8.3.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5b10e62f86f3738682ac5df2165fa711eba1f35193dc8a1af20d794434ca2816", size = 717655, upload-time = "2026-01-06T15:04:20.905Z" }, { url = "https://files.pythonhosted.org/packages/0c/b7/f8c9be26236c376c796a8b6ada0d4efe9bc604843d97c5bef0b86b4e865f/gnureadline-8.3.3-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:251495414ee34dd7f068e0c4f09ee46f068e0e08a75428a7fbdf41a8ffa8bb27", size = 167489, upload-time = "2026-01-06T15:04:22.465Z" }, { url = "https://files.pythonhosted.org/packages/bd/2b/ec2958df1bbb878d56c29b5ef7fbf1f1eb2c3b27bb3e9e1b4bff71a7dfad/gnureadline-8.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8513db40b4c5404ad3e883ad747e0cf113ec7b0b884dff1f6f873f9a1c1d2432", size = 167309, upload-time = "2026-01-06T15:04:23.69Z" }, { url = "https://files.pythonhosted.org/packages/ae/9f/1d8e8f83a8e36e011436311ef9c917fb8707d945fd1a18366cbc82f53937/gnureadline-8.3.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c1dabc49d09ab802dccb9f8057956cf9561b2ff9e5e4f7c2e2ad103356b2397d", size = 698298, upload-time = "2026-01-06T15:04:24.95Z" }, @@ -608,24 +572,6 @@ version = "0.13.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/0d/5e/4ec91646aee381d01cdb9974e30882c9cd3b8c5d1079d6b5ff4af522439a/jiter-0.13.0.tar.gz", hash = "sha256:f2839f9c2c7e2dffc1bc5929a510e14ce0a946be9365fd1219e7ef342dae14f4", size = 164847, upload-time = "2026-02-02T12:37:56.441Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/91/9c/7ee5a6ff4b9991e1a45263bfc46731634c4a2bde27dfda6c8251df2d958c/jiter-0.13.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1f8a55b848cbabf97d861495cd65f1e5c590246fabca8b48e1747c4dfc8f85bf", size = 306897, upload-time = "2026-02-02T12:36:16.748Z" }, - { url = "https://files.pythonhosted.org/packages/7c/02/be5b870d1d2be5dd6a91bdfb90f248fbb7dcbd21338f092c6b89817c3dbf/jiter-0.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f556aa591c00f2c45eb1b89f68f52441a016034d18b65da60e2d2875bbbf344a", size = 317507, upload-time = "2026-02-02T12:36:18.351Z" }, - { url = "https://files.pythonhosted.org/packages/da/92/b25d2ec333615f5f284f3a4024f7ce68cfa0604c322c6808b2344c7f5d2b/jiter-0.13.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7e1d61da332ec412350463891923f960c3073cf1aae93b538f0bb4c8cd46efb", size = 350560, upload-time = "2026-02-02T12:36:19.746Z" }, - { url = "https://files.pythonhosted.org/packages/be/ec/74dcb99fef0aca9fbe56b303bf79f6bd839010cb18ad41000bf6cc71eec0/jiter-0.13.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3097d665a27bc96fd9bbf7f86178037db139f319f785e4757ce7ccbf390db6c2", size = 363232, upload-time = "2026-02-02T12:36:21.243Z" }, - { url = "https://files.pythonhosted.org/packages/1b/37/f17375e0bb2f6a812d4dd92d7616e41917f740f3e71343627da9db2824ce/jiter-0.13.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d01ecc3a8cbdb6f25a37bd500510550b64ddf9f7d64a107d92f3ccb25035d0f", size = 483727, upload-time = "2026-02-02T12:36:22.688Z" }, - { url = "https://files.pythonhosted.org/packages/77/d2/a71160a5ae1a1e66c1395b37ef77da67513b0adba73b993a27fbe47eb048/jiter-0.13.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ed9bbc30f5d60a3bdf63ae76beb3f9db280d7f195dfcfa61af792d6ce912d159", size = 370799, upload-time = "2026-02-02T12:36:24.106Z" }, - { url = "https://files.pythonhosted.org/packages/01/99/ed5e478ff0eb4e8aa5fd998f9d69603c9fd3f32de3bd16c2b1194f68361c/jiter-0.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98fbafb6e88256f4454de33c1f40203d09fc33ed19162a68b3b257b29ca7f663", size = 359120, upload-time = "2026-02-02T12:36:25.519Z" }, - { url = "https://files.pythonhosted.org/packages/16/be/7ffd08203277a813f732ba897352797fa9493faf8dc7995b31f3d9cb9488/jiter-0.13.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5467696f6b827f1116556cb0db620440380434591e93ecee7fd14d1a491b6daa", size = 390664, upload-time = "2026-02-02T12:36:26.866Z" }, - { url = "https://files.pythonhosted.org/packages/d1/84/e0787856196d6d346264d6dcccb01f741e5f0bd014c1d9a2ebe149caf4f3/jiter-0.13.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:2d08c9475d48b92892583df9da592a0e2ac49bcd41fae1fec4f39ba6cf107820", size = 513543, upload-time = "2026-02-02T12:36:28.217Z" }, - { url = "https://files.pythonhosted.org/packages/65/50/ecbd258181c4313cf79bca6c88fb63207d04d5bf5e4f65174114d072aa55/jiter-0.13.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:aed40e099404721d7fcaf5b89bd3b4568a4666358bcac7b6b15c09fb6252ab68", size = 547262, upload-time = "2026-02-02T12:36:29.678Z" }, - { url = "https://files.pythonhosted.org/packages/27/da/68f38d12e7111d2016cd198161b36e1f042bd115c169255bcb7ec823a3bf/jiter-0.13.0-cp313-cp313-win32.whl", hash = "sha256:36ebfbcffafb146d0e6ffb3e74d51e03d9c35ce7c625c8066cdbfc7b953bdc72", size = 200630, upload-time = "2026-02-02T12:36:31.808Z" }, - { url = "https://files.pythonhosted.org/packages/25/65/3bd1a972c9a08ecd22eb3b08a95d1941ebe6938aea620c246cf426ae09c2/jiter-0.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:8d76029f077379374cf0dbc78dbe45b38dec4a2eb78b08b5194ce836b2517afc", size = 202602, upload-time = "2026-02-02T12:36:33.679Z" }, - { url = "https://files.pythonhosted.org/packages/15/fe/13bd3678a311aa67686bb303654792c48206a112068f8b0b21426eb6851e/jiter-0.13.0-cp313-cp313-win_arm64.whl", hash = "sha256:bb7613e1a427cfcb6ea4544f9ac566b93d5bf67e0d48c787eca673ff9c9dff2b", size = 185939, upload-time = "2026-02-02T12:36:35.065Z" }, - { url = "https://files.pythonhosted.org/packages/49/19/a929ec002ad3228bc97ca01dbb14f7632fffdc84a95ec92ceaf4145688ae/jiter-0.13.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:fa476ab5dd49f3bf3a168e05f89358c75a17608dbabb080ef65f96b27c19ab10", size = 316616, upload-time = "2026-02-02T12:36:36.579Z" }, - { url = "https://files.pythonhosted.org/packages/52/56/d19a9a194afa37c1728831e5fb81b7722c3de18a3109e8f282bfc23e587a/jiter-0.13.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ade8cb6ff5632a62b7dbd4757d8c5573f7a2e9ae285d6b5b841707d8363205ef", size = 346850, upload-time = "2026-02-02T12:36:38.058Z" }, - { url = "https://files.pythonhosted.org/packages/36/4a/94e831c6bf287754a8a019cb966ed39ff8be6ab78cadecf08df3bb02d505/jiter-0.13.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9950290340acc1adaded363edd94baebcee7dabdfa8bee4790794cd5cfad2af6", size = 358551, upload-time = "2026-02-02T12:36:39.417Z" }, - { url = "https://files.pythonhosted.org/packages/a2/ec/a4c72c822695fa80e55d2b4142b73f0012035d9fcf90eccc56bc060db37c/jiter-0.13.0-cp313-cp313t-win_amd64.whl", hash = "sha256:2b4972c6df33731aac0742b64fd0d18e0a69bc7d6e03108ce7d40c85fd9e3e6d", size = 201950, upload-time = "2026-02-02T12:36:40.791Z" }, - { url = "https://files.pythonhosted.org/packages/b6/00/393553ec27b824fbc29047e9c7cd4a3951d7fbe4a76743f17e44034fa4e4/jiter-0.13.0-cp313-cp313t-win_arm64.whl", hash = "sha256:701a1e77d1e593c1b435315ff625fd071f0998c5f02792038a5ca98899261b7d", size = 185852, upload-time = "2026-02-02T12:36:42.077Z" }, { url = "https://files.pythonhosted.org/packages/6e/f5/f1997e987211f6f9bd71b8083047b316208b4aca0b529bb5f8c96c89ef3e/jiter-0.13.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:cc5223ab19fe25e2f0bf2643204ad7318896fe3729bf12fde41b77bfc4fafff0", size = 308804, upload-time = "2026-02-02T12:36:43.496Z" }, { url = "https://files.pythonhosted.org/packages/cd/8f/5482a7677731fd44881f0204981ce2d7175db271f82cba2085dd2212e095/jiter-0.13.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9776ebe51713acf438fd9b4405fcd86893ae5d03487546dae7f34993217f8a91", size = 318787, upload-time = "2026-02-02T12:36:45.071Z" }, { url = "https://files.pythonhosted.org/packages/f3/b9/7257ac59778f1cd025b26a23c5520a36a424f7f1b068f2442a5b499b7464/jiter-0.13.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:879e768938e7b49b5e90b7e3fecc0dbec01b8cb89595861fb39a8967c5220d09", size = 353880, upload-time = "2026-02-02T12:36:47.365Z" }, @@ -782,32 +728,32 @@ wheels = [ [[package]] name = "opentelemetry-api" -version = "1.39.1" +version = "1.40.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "importlib-metadata" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/97/b9/3161be15bb8e3ad01be8be5a968a9237c3027c5be504362ff800fca3e442/opentelemetry_api-1.39.1.tar.gz", hash = "sha256:fbde8c80e1b937a2c61f20347e91c0c18a1940cecf012d62e65a7caf08967c9c", size = 65767, upload-time = "2025-12-11T13:32:39.182Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2c/1d/4049a9e8698361cc1a1aa03a6c59e4fa4c71e0c0f94a30f988a6876a2ae6/opentelemetry_api-1.40.0.tar.gz", hash = "sha256:159be641c0b04d11e9ecd576906462773eb97ae1b657730f0ecf64d32071569f", size = 70851, upload-time = "2026-03-04T14:17:21.555Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cf/df/d3f1ddf4bb4cb50ed9b1139cc7b1c54c34a1e7ce8fd1b9a37c0d1551a6bd/opentelemetry_api-1.39.1-py3-none-any.whl", hash = "sha256:2edd8463432a7f8443edce90972169b195e7d6a05500cd29e6d13898187c9950", size = 66356, upload-time = "2025-12-11T13:32:17.304Z" }, + { url = "https://files.pythonhosted.org/packages/5f/bf/93795954016c522008da367da292adceed71cca6ee1717e1d64c83089099/opentelemetry_api-1.40.0-py3-none-any.whl", hash = "sha256:82dd69331ae74b06f6a874704be0cfaa49a1650e1537d4a813b86ecef7d0ecf9", size = 68676, upload-time = "2026-03-04T14:17:01.24Z" }, ] [[package]] name = "opentelemetry-exporter-otlp-proto-common" -version = "1.39.1" +version = "1.40.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-proto" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e9/9d/22d241b66f7bbde88a3bfa6847a351d2c46b84de23e71222c6aae25c7050/opentelemetry_exporter_otlp_proto_common-1.39.1.tar.gz", hash = "sha256:763370d4737a59741c89a67b50f9e39271639ee4afc999dadfe768541c027464", size = 20409, upload-time = "2025-12-11T13:32:40.885Z" } +sdist = { url = "https://files.pythonhosted.org/packages/51/bc/1559d46557fe6eca0b46c88d4c2676285f1f3be2e8d06bb5d15fbffc814a/opentelemetry_exporter_otlp_proto_common-1.40.0.tar.gz", hash = "sha256:1cbee86a4064790b362a86601ee7934f368b81cd4cc2f2e163902a6e7818a0fa", size = 20416, upload-time = "2026-03-04T14:17:23.801Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8c/02/ffc3e143d89a27ac21fd557365b98bd0653b98de8a101151d5805b5d4c33/opentelemetry_exporter_otlp_proto_common-1.39.1-py3-none-any.whl", hash = "sha256:08f8a5862d64cc3435105686d0216c1365dc5701f86844a8cd56597d0c764fde", size = 18366, upload-time = "2025-12-11T13:32:20.2Z" }, + { url = "https://files.pythonhosted.org/packages/8b/ca/8f122055c97a932311a3f640273f084e738008933503d0c2563cd5d591fc/opentelemetry_exporter_otlp_proto_common-1.40.0-py3-none-any.whl", hash = "sha256:7081ff453835a82417bf38dccf122c827c3cbc94f2079b03bba02a3165f25149", size = 18369, upload-time = "2026-03-04T14:17:04.796Z" }, ] [[package]] name = "opentelemetry-exporter-otlp-proto-http" -version = "1.39.1" +version = "1.40.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "googleapis-common-protos" }, @@ -818,14 +764,14 @@ dependencies = [ { name = "requests" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/80/04/2a08fa9c0214ae38880df01e8bfae12b067ec0793446578575e5080d6545/opentelemetry_exporter_otlp_proto_http-1.39.1.tar.gz", hash = "sha256:31bdab9745c709ce90a49a0624c2bd445d31a28ba34275951a6a362d16a0b9cb", size = 17288, upload-time = "2025-12-11T13:32:42.029Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2e/fa/73d50e2c15c56be4d000c98e24221d494674b0cc95524e2a8cb3856d95a4/opentelemetry_exporter_otlp_proto_http-1.40.0.tar.gz", hash = "sha256:db48f5e0f33217588bbc00274a31517ba830da576e59503507c839b38fa0869c", size = 17772, upload-time = "2026-03-04T14:17:25.324Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/95/f1/b27d3e2e003cd9a3592c43d099d2ed8d0a947c15281bf8463a256db0b46c/opentelemetry_exporter_otlp_proto_http-1.39.1-py3-none-any.whl", hash = "sha256:d9f5207183dd752a412c4cd564ca8875ececba13be6e9c6c370ffb752fd59985", size = 19641, upload-time = "2025-12-11T13:32:22.248Z" }, + { url = "https://files.pythonhosted.org/packages/a0/3a/8865d6754e61c9fb170cdd530a124a53769ee5f740236064816eb0ca7301/opentelemetry_exporter_otlp_proto_http-1.40.0-py3-none-any.whl", hash = "sha256:a8d1dab28f504c5d96577d6509f80a8150e44e8f45f82cdbe0e34c99ab040069", size = 19960, upload-time = "2026-03-04T14:17:07.153Z" }, ] [[package]] name = "opentelemetry-instrumentation" -version = "0.60b1" +version = "0.61b0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, @@ -833,14 +779,14 @@ dependencies = [ { name = "packaging" }, { name = "wrapt" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/41/0f/7e6b713ac117c1f5e4e3300748af699b9902a2e5e34c9cf443dde25a01fa/opentelemetry_instrumentation-0.60b1.tar.gz", hash = "sha256:57ddc7974c6eb35865af0426d1a17132b88b2ed8586897fee187fd5b8944bd6a", size = 31706, upload-time = "2025-12-11T13:36:42.515Z" } +sdist = { url = "https://files.pythonhosted.org/packages/da/37/6bf8e66bfcee5d3c6515b79cb2ee9ad05fe573c20f7ceb288d0e7eeec28c/opentelemetry_instrumentation-0.61b0.tar.gz", hash = "sha256:cb21b48db738c9de196eba6b805b4ff9de3b7f187e4bbf9a466fa170514f1fc7", size = 32606, upload-time = "2026-03-04T14:20:16.825Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/77/d2/6788e83c5c86a2690101681aeef27eeb2a6bf22df52d3f263a22cee20915/opentelemetry_instrumentation-0.60b1-py3-none-any.whl", hash = "sha256:04480db952b48fb1ed0073f822f0ee26012b7be7c3eac1a3793122737c78632d", size = 33096, upload-time = "2025-12-11T13:35:33.067Z" }, + { url = "https://files.pythonhosted.org/packages/d8/3e/f6f10f178b6316de67f0dfdbbb699a24fbe8917cf1743c1595fb9dcdd461/opentelemetry_instrumentation-0.61b0-py3-none-any.whl", hash = "sha256:92a93a280e69788e8f88391247cc530fd81f16f2b011979d4d6398f805cfbc63", size = 33448, upload-time = "2026-03-04T14:19:02.447Z" }, ] [[package]] name = "opentelemetry-instrumentation-asgi" -version = "0.60b1" +version = "0.61b0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "asgiref" }, @@ -849,14 +795,14 @@ dependencies = [ { name = "opentelemetry-semantic-conventions" }, { name = "opentelemetry-util-http" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/77/db/851fa88db7441da82d50bd80f2de5ee55213782e25dc858e04d0c9961d60/opentelemetry_instrumentation_asgi-0.60b1.tar.gz", hash = "sha256:16bfbe595cd24cda309a957456d0fc2523f41bc7b076d1f2d7e98a1ad9876d6f", size = 26107, upload-time = "2025-12-11T13:36:47.015Z" } +sdist = { url = "https://files.pythonhosted.org/packages/00/3e/143cf5c034e58037307e6a24f06e0dd64b2c49ae60a965fc580027581931/opentelemetry_instrumentation_asgi-0.61b0.tar.gz", hash = "sha256:9d08e127244361dc33976d39dd4ca8f128b5aa5a7ae425208400a80a095019b5", size = 26691, upload-time = "2026-03-04T14:20:21.038Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/76/76/1fb94367cef64420d2171157a6b9509582873bd09a6afe08a78a8d1f59d9/opentelemetry_instrumentation_asgi-0.60b1-py3-none-any.whl", hash = "sha256:d48def2dbed10294c99cfcf41ebbd0c414d390a11773a41f472d20000fcddc25", size = 16933, upload-time = "2025-12-11T13:35:40.462Z" }, + { url = "https://files.pythonhosted.org/packages/19/78/154470cf9d741a7487fbb5067357b87386475bbb77948a6707cae982e158/opentelemetry_instrumentation_asgi-0.61b0-py3-none-any.whl", hash = "sha256:e4b3ce6b66074e525e717efff20745434e5efd5d9df6557710856fba356da7a4", size = 16980, upload-time = "2026-03-04T14:19:10.894Z" }, ] [[package]] name = "opentelemetry-instrumentation-fastapi" -version = "0.60b1" +version = "0.61b0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, @@ -865,14 +811,14 @@ dependencies = [ { name = "opentelemetry-semantic-conventions" }, { name = "opentelemetry-util-http" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9c/e7/e7e5e50218cf488377209d85666b182fa2d4928bf52389411ceeee1b2b60/opentelemetry_instrumentation_fastapi-0.60b1.tar.gz", hash = "sha256:de608955f7ff8eecf35d056578346a5365015fd7d8623df9b1f08d1c74769c01", size = 24958, upload-time = "2025-12-11T13:36:59.35Z" } +sdist = { url = "https://files.pythonhosted.org/packages/37/35/aa727bb6e6ef930dcdc96a617b83748fece57b43c47d83ba8d83fbeca657/opentelemetry_instrumentation_fastapi-0.61b0.tar.gz", hash = "sha256:3a24f35b07c557ae1bbc483bf8412221f25d79a405f8b047de8b670722e2fa9f", size = 24800, upload-time = "2026-03-04T14:20:32.759Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7d/cc/6e808328ba54662e50babdcab21138eae4250bc0fddf67d55526a615a2ca/opentelemetry_instrumentation_fastapi-0.60b1-py3-none-any.whl", hash = "sha256:af94b7a239ad1085fc3a820ecf069f67f579d7faf4c085aaa7bd9b64eafc8eaf", size = 13478, upload-time = "2025-12-11T13:36:00.811Z" }, + { url = "https://files.pythonhosted.org/packages/91/05/acfeb2cccd434242a0a7d0ea29afaf077e04b42b35b485d89aee4e0d9340/opentelemetry_instrumentation_fastapi-0.61b0-py3-none-any.whl", hash = "sha256:a1a844d846540d687d377516b2ff698b51d87c781b59f47c214359c4a241047c", size = 13485, upload-time = "2026-03-04T14:19:30.351Z" }, ] [[package]] name = "opentelemetry-instrumentation-httpx" -version = "0.60b1" +version = "0.61b0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, @@ -881,14 +827,14 @@ dependencies = [ { name = "opentelemetry-util-http" }, { name = "wrapt" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/86/08/11208bcfcab4fc2023252c3f322aa397fd9ad948355fea60f5fc98648603/opentelemetry_instrumentation_httpx-0.60b1.tar.gz", hash = "sha256:a506ebaf28c60112cbe70ad4f0338f8603f148938cb7b6794ce1051cd2b270ae", size = 20611, upload-time = "2025-12-11T13:37:01.661Z" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/2a/e2becd55e33c29d1d9ef76e2579040ed1951cb33bacba259f6aff2fdd2a6/opentelemetry_instrumentation_httpx-0.61b0.tar.gz", hash = "sha256:6569ec097946c5551c2a4252f74c98666addd1bf047c1dde6b4ef426719ff8dd", size = 24104, upload-time = "2026-03-04T14:20:34.752Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/43/59/b98e84eebf745ffc75397eaad4763795bff8a30cbf2373a50ed4e70646c5/opentelemetry_instrumentation_httpx-0.60b1-py3-none-any.whl", hash = "sha256:f37636dd742ad2af83d896ba69601ed28da51fa4e25d1ab62fde89ce413e275b", size = 15701, upload-time = "2025-12-11T13:36:04.56Z" }, + { url = "https://files.pythonhosted.org/packages/af/88/dde310dce56e2d85cf1a09507f5888544955309edc4b8d22971d6d3d1417/opentelemetry_instrumentation_httpx-0.61b0-py3-none-any.whl", hash = "sha256:dee05c93a6593a5dc3ae5d9d5c01df8b4e2c5d02e49275e5558534ee46343d5e", size = 17198, upload-time = "2026-03-04T14:19:33.585Z" }, ] [[package]] name = "opentelemetry-instrumentation-openai" -version = "0.52.6" +version = "0.53.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, @@ -896,48 +842,48 @@ dependencies = [ { name = "opentelemetry-semantic-conventions" }, { name = "opentelemetry-semantic-conventions-ai" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/37/86/1fe5008f3714118fdc1024cd141140a5f204d5ac7016e87a0f07a834efb2/opentelemetry_instrumentation_openai-0.52.6.tar.gz", hash = "sha256:0eb23dc90804a726e516fcbd649cb99f10dfdb5e31d29e44c4b1b8f402dd905d", size = 6978397, upload-time = "2026-02-26T15:40:17.154Z" } +sdist = { url = "https://files.pythonhosted.org/packages/10/b7/b3b5536671658001c62c117fa834df2a3bd524e950a7773d53b71fca3219/opentelemetry_instrumentation_openai-0.53.0.tar.gz", hash = "sha256:c0cd83d223d138309af3cc5f53c9c6d22136374bfa00e8f66dff31cd322ef547", size = 6978375, upload-time = "2026-03-04T07:49:18.112Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/4a/4623d0adc0187cc45bce631f891c30cd01cf2562d37b918b79561200d985/opentelemetry_instrumentation_openai-0.52.6-py3-none-any.whl", hash = "sha256:5e174388520f294f648f9732471c1b9919c71e5d09649a64ab8ff81714c1278b", size = 43084, upload-time = "2026-02-26T15:39:35.584Z" }, + { url = "https://files.pythonhosted.org/packages/44/3b/58ac94d0f56afb3c0352d3e6d35ea9de6331292a7316403ea97de4c6d915/opentelemetry_instrumentation_openai-0.53.0-py3-none-any.whl", hash = "sha256:91d9f69673636f5f7d50e5a4782e4526d6df3a1ddfd6ac2d9e15a957f8fd9ad8", size = 43084, upload-time = "2026-03-04T07:48:43.676Z" }, ] [[package]] name = "opentelemetry-proto" -version = "1.39.1" +version = "1.40.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/49/1d/f25d76d8260c156c40c97c9ed4511ec0f9ce353f8108ca6e7561f82a06b2/opentelemetry_proto-1.39.1.tar.gz", hash = "sha256:6c8e05144fc0d3ed4d22c2289c6b126e03bcd0e6a7da0f16cedd2e1c2772e2c8", size = 46152, upload-time = "2025-12-11T13:32:48.681Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4c/77/dd38991db037fdfce45849491cb61de5ab000f49824a00230afb112a4392/opentelemetry_proto-1.40.0.tar.gz", hash = "sha256:03f639ca129ba513f5819810f5b1f42bcb371391405d99c168fe6937c62febcd", size = 45667, upload-time = "2026-03-04T14:17:31.194Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/51/95/b40c96a7b5203005a0b03d8ce8cd212ff23f1793d5ba289c87a097571b18/opentelemetry_proto-1.39.1-py3-none-any.whl", hash = "sha256:22cdc78efd3b3765d09e68bfbd010d4fc254c9818afd0b6b423387d9dee46007", size = 72535, upload-time = "2025-12-11T13:32:33.866Z" }, + { url = "https://files.pythonhosted.org/packages/b9/b2/189b2577dde745b15625b3214302605b1353436219d42b7912e77fa8dc24/opentelemetry_proto-1.40.0-py3-none-any.whl", hash = "sha256:266c4385d88923a23d63e353e9761af0f47a6ed0d486979777fe4de59dc9b25f", size = 72073, upload-time = "2026-03-04T14:17:16.673Z" }, ] [[package]] name = "opentelemetry-sdk" -version = "1.39.1" +version = "1.40.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, { name = "opentelemetry-semantic-conventions" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/eb/fb/c76080c9ba07e1e8235d24cdcc4d125ef7aa3edf23eb4e497c2e50889adc/opentelemetry_sdk-1.39.1.tar.gz", hash = "sha256:cf4d4563caf7bff906c9f7967e2be22d0d6b349b908be0d90fb21c8e9c995cc6", size = 171460, upload-time = "2025-12-11T13:32:49.369Z" } +sdist = { url = "https://files.pythonhosted.org/packages/58/fd/3c3125b20ba18ce2155ba9ea74acb0ae5d25f8cd39cfd37455601b7955cc/opentelemetry_sdk-1.40.0.tar.gz", hash = "sha256:18e9f5ec20d859d268c7cb3c5198c8d105d073714db3de50b593b8c1345a48f2", size = 184252, upload-time = "2026-03-04T14:17:31.87Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7c/98/e91cf858f203d86f4eccdf763dcf01cf03f1dae80c3750f7e635bfa206b6/opentelemetry_sdk-1.39.1-py3-none-any.whl", hash = "sha256:4d5482c478513ecb0a5d938dcc61394e647066e0cc2676bee9f3af3f3f45f01c", size = 132565, upload-time = "2025-12-11T13:32:35.069Z" }, + { url = "https://files.pythonhosted.org/packages/2c/c5/6a852903d8bfac758c6dc6e9a68b015d3c33f2f1be5e9591e0f4b69c7e0a/opentelemetry_sdk-1.40.0-py3-none-any.whl", hash = "sha256:787d2154a71f4b3d81f20524a8ce061b7db667d24e46753f32a7bc48f1c1f3f1", size = 141951, upload-time = "2026-03-04T14:17:17.961Z" }, ] [[package]] name = "opentelemetry-semantic-conventions" -version = "0.60b1" +version = "0.61b0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/91/df/553f93ed38bf22f4b999d9be9c185adb558982214f33eae539d3b5cd0858/opentelemetry_semantic_conventions-0.60b1.tar.gz", hash = "sha256:87c228b5a0669b748c76d76df6c364c369c28f1c465e50f661e39737e84bc953", size = 137935, upload-time = "2025-12-11T13:32:50.487Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6d/c0/4ae7973f3c2cfd2b6e321f1675626f0dab0a97027cc7a297474c9c8f3d04/opentelemetry_semantic_conventions-0.61b0.tar.gz", hash = "sha256:072f65473c5d7c6dc0355b27d6c9d1a679d63b6d4b4b16a9773062cb7e31192a", size = 145755, upload-time = "2026-03-04T14:17:32.664Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7a/5e/5958555e09635d09b75de3c4f8b9cae7335ca545d77392ffe7331534c402/opentelemetry_semantic_conventions-0.60b1-py3-none-any.whl", hash = "sha256:9fa8c8b0c110da289809292b0591220d3a7b53c1526a23021e977d68597893fb", size = 219982, upload-time = "2025-12-11T13:32:36.955Z" }, + { url = "https://files.pythonhosted.org/packages/b2/37/cc6a55e448deaa9b27377d087da8615a3416d8ad523d5960b78dbeadd02a/opentelemetry_semantic_conventions-0.61b0-py3-none-any.whl", hash = "sha256:fa530a96be229795f8cef353739b618148b0fe2b4b3f005e60e262926c4d38e2", size = 231621, upload-time = "2026-03-04T14:17:19.33Z" }, ] [[package]] @@ -955,11 +901,11 @@ wheels = [ [[package]] name = "opentelemetry-util-http" -version = "0.60b1" +version = "0.61b0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/50/fc/c47bb04a1d8a941a4061307e1eddfa331ed4d0ab13d8a9781e6db256940a/opentelemetry_util_http-0.60b1.tar.gz", hash = "sha256:0d97152ca8c8a41ced7172d29d3622a219317f74ae6bb3027cfbdcf22c3cc0d6", size = 11053, upload-time = "2025-12-11T13:37:25.115Z" } +sdist = { url = "https://files.pythonhosted.org/packages/57/3c/f0196223efc5c4ca19f8fad3d5462b171ac6333013335ce540c01af419e9/opentelemetry_util_http-0.61b0.tar.gz", hash = "sha256:1039cb891334ad2731affdf034d8fb8b48c239af9b6dd295e5fabd07f1c95572", size = 11361, upload-time = "2026-03-04T14:20:57.01Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/16/5c/d3f1733665f7cd582ef0842fb1d2ed0bc1fba10875160593342d22bba375/opentelemetry_util_http-0.60b1-py3-none-any.whl", hash = "sha256:66381ba28550c91bee14dcba8979ace443444af1ed609226634596b4b0faf199", size = 8947, upload-time = "2025-12-11T13:36:37.151Z" }, + { url = "https://files.pythonhosted.org/packages/0d/e5/c08aaaf2f64288d2b6ef65741d2de5454e64af3e050f34285fb1907492fe/opentelemetry_util_http-0.61b0-py3-none-any.whl", hash = "sha256:8e715e848233e9527ea47e275659ea60a57a75edf5206a3b937e236a6da5fc33", size = 9281, upload-time = "2026-03-04T14:20:08.364Z" }, ] [[package]] @@ -1034,12 +980,6 @@ version = "7.2.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/aa/c6/d1ddf4abb55e93cebc4f2ed8b5d6dbad109ecb8d63748dd2b20ab5e57ebe/psutil-7.2.2.tar.gz", hash = "sha256:0746f5f8d406af344fd547f1c8daa5f5c33dbc293bb8d6a16d80b4bb88f59372", size = 493740, upload-time = "2026-01-28T18:14:54.428Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/51/08/510cbdb69c25a96f4ae523f733cdc963ae654904e8db864c07585ef99875/psutil-7.2.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:2edccc433cbfa046b980b0df0171cd25bcaeb3a68fe9022db0979e7aa74a826b", size = 130595, upload-time = "2026-01-28T18:14:57.293Z" }, - { url = "https://files.pythonhosted.org/packages/d6/f5/97baea3fe7a5a9af7436301f85490905379b1c6f2dd51fe3ecf24b4c5fbf/psutil-7.2.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e78c8603dcd9a04c7364f1a3e670cea95d51ee865e4efb3556a3a63adef958ea", size = 131082, upload-time = "2026-01-28T18:14:59.732Z" }, - { url = "https://files.pythonhosted.org/packages/37/d6/246513fbf9fa174af531f28412297dd05241d97a75911ac8febefa1a53c6/psutil-7.2.2-cp313-cp313t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1a571f2330c966c62aeda00dd24620425d4b0cc86881c89861fbc04549e5dc63", size = 181476, upload-time = "2026-01-28T18:15:01.884Z" }, - { url = "https://files.pythonhosted.org/packages/b8/b5/9182c9af3836cca61696dabe4fd1304e17bc56cb62f17439e1154f225dd3/psutil-7.2.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:917e891983ca3c1887b4ef36447b1e0873e70c933afc831c6b6da078ba474312", size = 184062, upload-time = "2026-01-28T18:15:04.436Z" }, - { url = "https://files.pythonhosted.org/packages/16/ba/0756dca669f5a9300d0cbcbfae9a4c30e446dfc7440ffe43ded5724bfd93/psutil-7.2.2-cp313-cp313t-win_amd64.whl", hash = "sha256:ab486563df44c17f5173621c7b198955bd6b613fb87c71c161f827d3fb149a9b", size = 139893, upload-time = "2026-01-28T18:15:06.378Z" }, - { url = "https://files.pythonhosted.org/packages/1c/61/8fa0e26f33623b49949346de05ec1ddaad02ed8ba64af45f40a147dbfa97/psutil-7.2.2-cp313-cp313t-win_arm64.whl", hash = "sha256:ae0aefdd8796a7737eccea863f80f81e468a1e4cf14d926bd9b6f5f2d5f90ca9", size = 135589, upload-time = "2026-01-28T18:15:08.03Z" }, { url = "https://files.pythonhosted.org/packages/81/69/ef179ab5ca24f32acc1dac0c247fd6a13b501fd5534dbae0e05a1c48b66d/psutil-7.2.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:eed63d3b4d62449571547b60578c5b2c4bcccc5387148db46e0c2313dad0ee00", size = 130664, upload-time = "2026-01-28T18:15:09.469Z" }, { url = "https://files.pythonhosted.org/packages/7b/64/665248b557a236d3fa9efc378d60d95ef56dd0a490c2cd37dafc7660d4a9/psutil-7.2.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7b6d09433a10592ce39b13d7be5a54fbac1d1228ed29abc880fb23df7cb694c9", size = 131087, upload-time = "2026-01-28T18:15:11.724Z" }, { url = "https://files.pythonhosted.org/packages/d5/2e/e6782744700d6759ebce3043dcfa661fb61e2fb752b91cdeae9af12c2178/psutil-7.2.2-cp314-cp314t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1fa4ecf83bcdf6e6c8f4449aff98eefb5d0604bf88cb883d7da3d8d2d909546a", size = 182383, upload-time = "2026-01-28T18:15:13.445Z" }, @@ -1110,20 +1050,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/71/70/23b021c950c2addd24ec408e9ab05d59b035b39d97cdc1130e1bce647bb6/pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e", size = 460952, upload-time = "2025-11-04T13:43:49.098Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/87/06/8806241ff1f70d9939f9af039c6c35f2360cf16e93c2ca76f184e76b1564/pydantic_core-2.41.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:941103c9be18ac8daf7b7adca8228f8ed6bb7a1849020f643b3a14d15b1924d9", size = 2120403, upload-time = "2025-11-04T13:40:25.248Z" }, - { url = "https://files.pythonhosted.org/packages/94/02/abfa0e0bda67faa65fef1c84971c7e45928e108fe24333c81f3bfe35d5f5/pydantic_core-2.41.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:112e305c3314f40c93998e567879e887a3160bb8689ef3d2c04b6cc62c33ac34", size = 1896206, upload-time = "2025-11-04T13:40:27.099Z" }, - { url = "https://files.pythonhosted.org/packages/15/df/a4c740c0943e93e6500f9eb23f4ca7ec9bf71b19e608ae5b579678c8d02f/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cbaad15cb0c90aa221d43c00e77bb33c93e8d36e0bf74760cd00e732d10a6a0", size = 1919307, upload-time = "2025-11-04T13:40:29.806Z" }, - { url = "https://files.pythonhosted.org/packages/9a/e3/6324802931ae1d123528988e0e86587c2072ac2e5394b4bc2bc34b61ff6e/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:03ca43e12fab6023fc79d28ca6b39b05f794ad08ec2feccc59a339b02f2b3d33", size = 2063258, upload-time = "2025-11-04T13:40:33.544Z" }, - { url = "https://files.pythonhosted.org/packages/c9/d4/2230d7151d4957dd79c3044ea26346c148c98fbf0ee6ebd41056f2d62ab5/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc799088c08fa04e43144b164feb0c13f9a0bc40503f8df3e9fde58a3c0c101e", size = 2214917, upload-time = "2025-11-04T13:40:35.479Z" }, - { url = "https://files.pythonhosted.org/packages/e6/9f/eaac5df17a3672fef0081b6c1bb0b82b33ee89aa5cec0d7b05f52fd4a1fa/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97aeba56665b4c3235a0e52b2c2f5ae9cd071b8a8310ad27bddb3f7fb30e9aa2", size = 2332186, upload-time = "2025-11-04T13:40:37.436Z" }, - { url = "https://files.pythonhosted.org/packages/cf/4e/35a80cae583a37cf15604b44240e45c05e04e86f9cfd766623149297e971/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:406bf18d345822d6c21366031003612b9c77b3e29ffdb0f612367352aab7d586", size = 2073164, upload-time = "2025-11-04T13:40:40.289Z" }, - { url = "https://files.pythonhosted.org/packages/bf/e3/f6e262673c6140dd3305d144d032f7bd5f7497d3871c1428521f19f9efa2/pydantic_core-2.41.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b93590ae81f7010dbe380cdeab6f515902ebcbefe0b9327cc4804d74e93ae69d", size = 2179146, upload-time = "2025-11-04T13:40:42.809Z" }, - { url = "https://files.pythonhosted.org/packages/75/c7/20bd7fc05f0c6ea2056a4565c6f36f8968c0924f19b7d97bbfea55780e73/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:01a3d0ab748ee531f4ea6c3e48ad9dac84ddba4b0d82291f87248f2f9de8d740", size = 2137788, upload-time = "2025-11-04T13:40:44.752Z" }, - { url = "https://files.pythonhosted.org/packages/3a/8d/34318ef985c45196e004bc46c6eab2eda437e744c124ef0dbe1ff2c9d06b/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:6561e94ba9dacc9c61bce40e2d6bdc3bfaa0259d3ff36ace3b1e6901936d2e3e", size = 2340133, upload-time = "2025-11-04T13:40:46.66Z" }, - { url = "https://files.pythonhosted.org/packages/9c/59/013626bf8c78a5a5d9350d12e7697d3d4de951a75565496abd40ccd46bee/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:915c3d10f81bec3a74fbd4faebe8391013ba61e5a1a8d48c4455b923bdda7858", size = 2324852, upload-time = "2025-11-04T13:40:48.575Z" }, - { url = "https://files.pythonhosted.org/packages/1a/d9/c248c103856f807ef70c18a4f986693a46a8ffe1602e5d361485da502d20/pydantic_core-2.41.5-cp313-cp313-win32.whl", hash = "sha256:650ae77860b45cfa6e2cdafc42618ceafab3a2d9a3811fcfbd3bbf8ac3c40d36", size = 1994679, upload-time = "2025-11-04T13:40:50.619Z" }, - { url = "https://files.pythonhosted.org/packages/9e/8b/341991b158ddab181cff136acd2552c9f35bd30380422a639c0671e99a91/pydantic_core-2.41.5-cp313-cp313-win_amd64.whl", hash = "sha256:79ec52ec461e99e13791ec6508c722742ad745571f234ea6255bed38c6480f11", size = 2019766, upload-time = "2025-11-04T13:40:52.631Z" }, - { url = "https://files.pythonhosted.org/packages/73/7d/f2f9db34af103bea3e09735bb40b021788a5e834c81eedb541991badf8f5/pydantic_core-2.41.5-cp313-cp313-win_arm64.whl", hash = "sha256:3f84d5c1b4ab906093bdc1ff10484838aca54ef08de4afa9de0f5f14d69639cd", size = 1981005, upload-time = "2025-11-04T13:40:54.734Z" }, { url = "https://files.pythonhosted.org/packages/ea/28/46b7c5c9635ae96ea0fbb779e271a38129df2550f763937659ee6c5dbc65/pydantic_core-2.41.5-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:3f37a19d7ebcdd20b96485056ba9e8b304e27d9904d233d7b1015db320e51f0a", size = 2119622, upload-time = "2025-11-04T13:40:56.68Z" }, { url = "https://files.pythonhosted.org/packages/74/1a/145646e5687e8d9a1e8d09acb278c8535ebe9e972e1f162ed338a622f193/pydantic_core-2.41.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1d1d9764366c73f996edd17abb6d9d7649a7eb690006ab6adbda117717099b14", size = 1891725, upload-time = "2025-11-04T13:40:58.807Z" }, { url = "https://files.pythonhosted.org/packages/23/04/e89c29e267b8060b40dca97bfc64a19b2a3cf99018167ea1677d96368273/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25e1c2af0fce638d5f1988b686f3b3ea8cd7de5f244ca147c777769e798a9cd1", size = 1915040, upload-time = "2025-11-04T13:41:00.853Z" }, @@ -1193,18 +1119,18 @@ crypto = [ [[package]] name = "pyrefly" -version = "0.54.0" +version = "0.55.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/81/44/c10b16a302fda90d0af1328f880b232761b510eab546616a7be2fdf35a57/pyrefly-0.54.0.tar.gz", hash = "sha256:c6663be64d492f0d2f2a411ada9f28a6792163d34133639378b7f3dd9a8dca94", size = 5098893, upload-time = "2026-02-23T15:44:35.111Z" } +sdist = { url = "https://files.pythonhosted.org/packages/bf/c4/76e0797215e62d007f81f86c9c4fb5d6202685a3f5e70810f3fd94294f92/pyrefly-0.55.0.tar.gz", hash = "sha256:434c3282532dd4525c4840f2040ed0eb79b0ec8224fe18d957956b15471f2441", size = 5135682, upload-time = "2026-03-03T00:46:38.122Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5f/99/8fdcdb4e55f0227fdd9f6abce36b619bab1ecb0662b83b66adc8cba3c788/pyrefly-0.54.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:58a3f092b6dc25ef79b2dc6c69a40f36784ca157c312bfc0baea463926a9db6d", size = 12223973, upload-time = "2026-02-23T15:44:14.278Z" }, - { url = "https://files.pythonhosted.org/packages/90/35/c2aaf87a76003ad27b286594d2e5178f811eaa15bfe3d98dba2b47d56dd1/pyrefly-0.54.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:615081414106dd95873bc39c3a4bed68754c6cc24a8177ac51d22f88f88d3eb3", size = 11785585, upload-time = "2026-02-23T15:44:17.468Z" }, - { url = "https://files.pythonhosted.org/packages/c4/4a/ced02691ed67e5a897714979196f08ad279ec7ec7f63c45e00a75a7f3c0e/pyrefly-0.54.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cbcaf20f5fe585079079a95205c1f3cd4542d17228cdf1df560288880623b70", size = 33381977, upload-time = "2026-02-23T15:44:19.736Z" }, - { url = "https://files.pythonhosted.org/packages/0b/ce/72a117ed437c8f6950862181014b41e36f3c3997580e29b772b71e78d587/pyrefly-0.54.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66d5da116c0d34acfbd66663addd3ca8aa78a636f6692a66e078126d3620a883", size = 35962821, upload-time = "2026-02-23T15:44:22.357Z" }, - { url = "https://files.pythonhosted.org/packages/85/de/89013f5ae0a35d2b6b01274a92a35ee91431ea001050edf0a16748d39875/pyrefly-0.54.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ef3ac27f1a4baaf67aead64287d3163350844794aca6315ad1a9650b16ec26a", size = 38496689, upload-time = "2026-02-23T15:44:25.236Z" }, - { url = "https://files.pythonhosted.org/packages/9f/9a/33b097c7bf498b924742dca32dd5d9c6a3fa6c2b52b63a58eb9e1980ca89/pyrefly-0.54.0-py3-none-win32.whl", hash = "sha256:7d607d72200a8afbd2db10bfefb40160a7a5d709d207161c21649cedd5cfc09a", size = 11295268, upload-time = "2026-02-23T15:44:27.551Z" }, - { url = "https://files.pythonhosted.org/packages/d4/21/9263fd1144d2a3d7342b474f183f7785b3358a1565c864089b780110b933/pyrefly-0.54.0-py3-none-win_amd64.whl", hash = "sha256:fd416f04f89309385696f685bd5c9141011f18c8072f84d31ca20c748546e791", size = 12081810, upload-time = "2026-02-23T15:44:29.461Z" }, - { url = "https://files.pythonhosted.org/packages/ea/5b/fad062a196c064cbc8564de5b2f4d3cb6315f852e3b31e8a1ce74c69a1ea/pyrefly-0.54.0-py3-none-win_arm64.whl", hash = "sha256:f06ab371356c7b1925e0bffe193b738797e71e5dbbff7fb5a13f90ee7521211d", size = 11564930, upload-time = "2026-02-23T15:44:33.053Z" }, + { url = "https://files.pythonhosted.org/packages/39/b0/16e50cf716784513648e23e726a24f71f9544aa4f86103032dcaa5ff71a2/pyrefly-0.55.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:49aafcefe5e2dd4256147db93e5b0ada42bff7d9a60db70e03d1f7055338eec9", size = 12210073, upload-time = "2026-03-03T00:46:15.51Z" }, + { url = "https://files.pythonhosted.org/packages/3a/ad/89500c01bac3083383011600370289fbc67700c5be46e781787392628a3a/pyrefly-0.55.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:2827426e6b28397c13badb93c0ede0fb0f48046a7a89e3d774cda04e8e2067cd", size = 11767474, upload-time = "2026-03-03T00:46:18.003Z" }, + { url = "https://files.pythonhosted.org/packages/78/68/4c66b260f817f304ead11176ff13985625f7c269e653304b4bdb546551af/pyrefly-0.55.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7346b2d64dc575bd61aa3bca854fbf8b5a19a471cbdb45e0ca1e09861b63488c", size = 33260395, upload-time = "2026-03-03T00:46:20.509Z" }, + { url = "https://files.pythonhosted.org/packages/47/09/10bd48c9f860064f29f412954126a827d60f6451512224912c265e26bbe6/pyrefly-0.55.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:233b861b4cff008b1aff62f4f941577ed752e4d0060834229eb9b6826e6973c9", size = 35848269, upload-time = "2026-03-03T00:46:23.418Z" }, + { url = "https://files.pythonhosted.org/packages/a9/39/bc65cdd5243eb2dfea25dd1321f9a5a93e8d9c3a308501c4c6c05d011585/pyrefly-0.55.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5aa85657d76da1d25d081a49f0e33c8fc3ec91c1a0f185a8ed393a5a3d9e178", size = 38449820, upload-time = "2026-03-03T00:46:26.309Z" }, + { url = "https://files.pythonhosted.org/packages/e5/64/58b38963b011af91209e87f868cc85cfc762ec49a4568ce610c45e7a5f40/pyrefly-0.55.0-py3-none-win32.whl", hash = "sha256:23f786a78536a56fed331b245b7d10ec8945bebee7b723491c8d66fdbc155fe6", size = 11259415, upload-time = "2026-03-03T00:46:30.875Z" }, + { url = "https://files.pythonhosted.org/packages/7a/0b/a4aa519ff632a1ea69eec942566951670b870b99b5c08407e1387b85b6a4/pyrefly-0.55.0-py3-none-win_amd64.whl", hash = "sha256:d465b49e999b50eeb069ad23f0f5710651cad2576f9452a82991bef557df91ee", size = 12043581, upload-time = "2026-03-03T00:46:33.674Z" }, + { url = "https://files.pythonhosted.org/packages/f1/51/89017636fbe1ffd166ad478990c6052df615b926182fa6d3c0842b407e89/pyrefly-0.55.0-py3-none-win_arm64.whl", hash = "sha256:732ff490e0e863b296e7c0b2471e08f8ba7952f9fa6e9de09d8347fd67dde77f", size = 11548076, upload-time = "2026-03-03T00:46:36.193Z" }, ] [[package]] @@ -1225,11 +1151,11 @@ wheels = [ [[package]] name = "python-dotenv" -version = "1.2.1" +version = "1.2.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f0/26/19cadc79a718c5edbec86fd4919a6b6d3f681039a2f6d66d14be94e75fb9/python_dotenv-1.2.1.tar.gz", hash = "sha256:42667e897e16ab0d66954af0e60a9caa94f0fd4ecf3aaf6d2d260eec1aa36ad6", size = 44221, upload-time = "2025-10-26T15:12:10.434Z" } +sdist = { url = "https://files.pythonhosted.org/packages/82/ed/0301aeeac3e5353ef3d94b6ec08bbcabd04a72018415dcb29e588514bba8/python_dotenv-1.2.2.tar.gz", hash = "sha256:2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3", size = 50135, upload-time = "2026-03-01T16:00:26.196Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61", size = 21230, upload-time = "2025-10-26T15:12:09.109Z" }, + { url = "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl", hash = "sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a", size = 22101, upload-time = "2026-03-01T16:00:25.09Z" }, ] [[package]] @@ -1246,9 +1172,6 @@ name = "pywin32" version = "311" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a5/be/3fd5de0979fcb3994bfee0d65ed8ca9506a8a1260651b86174f6a86f52b3/pywin32-311-cp313-cp313-win32.whl", hash = "sha256:f95ba5a847cba10dd8c4d8fefa9f2a6cf283b8b88ed6178fa8a6c1ab16054d0d", size = 8705700, upload-time = "2025-07-14T20:13:26.471Z" }, - { url = "https://files.pythonhosted.org/packages/e3/28/e0a1909523c6890208295a29e05c2adb2126364e289826c0a8bc7297bd5c/pywin32-311-cp313-cp313-win_amd64.whl", hash = "sha256:718a38f7e5b058e76aee1c56ddd06908116d35147e133427e59a3983f703a20d", size = 9494700, upload-time = "2025-07-14T20:13:28.243Z" }, - { url = "https://files.pythonhosted.org/packages/04/bf/90339ac0f55726dce7d794e6d79a18a91265bdf3aa70b6b9ca52f35e022a/pywin32-311-cp313-cp313-win_arm64.whl", hash = "sha256:7b4075d959648406202d92a2310cb990fea19b535c7f4a78d3f5e10b926eeb8a", size = 8709318, upload-time = "2025-07-14T20:13:30.348Z" }, { url = "https://files.pythonhosted.org/packages/c9/31/097f2e132c4f16d99a22bfb777e0fd88bd8e1c634304e102f313af69ace5/pywin32-311-cp314-cp314-win32.whl", hash = "sha256:b7a2c10b93f8986666d0c803ee19b5990885872a7de910fc460f9b0c2fbf92ee", size = 8840714, upload-time = "2025-07-14T20:13:32.449Z" }, { url = "https://files.pythonhosted.org/packages/90/4b/07c77d8ba0e01349358082713400435347df8426208171ce297da32c313d/pywin32-311-cp314-cp314-win_amd64.whl", hash = "sha256:3aca44c046bd2ed8c90de9cb8427f581c479e594e99b5c0bb19b29c10fd6cb87", size = 9656800, upload-time = "2025-07-14T20:13:34.312Z" }, { url = "https://files.pythonhosted.org/packages/c0/d2/21af5c535501a7233e734b8af901574572da66fcc254cb35d0609c9080dd/pywin32-311-cp314-cp314-win_arm64.whl", hash = "sha256:a508e2d9025764a8270f93111a970e1d0fbfc33f4153b388bb649b7eec4f9b42", size = 8932540, upload-time = "2025-07-14T20:13:36.379Z" }, @@ -1260,16 +1183,6 @@ version = "6.0.3" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" }, - { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" }, - { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" }, - { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" }, - { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" }, - { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" }, - { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" }, - { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" }, - { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" }, - { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" }, { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" }, { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" }, { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" }, @@ -1337,35 +1250,6 @@ version = "0.30.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/20/af/3f2f423103f1113b36230496629986e0ef7e199d2aa8392452b484b38ced/rpds_py-0.30.0.tar.gz", hash = "sha256:dd8ff7cf90014af0c0f787eea34794ebf6415242ee1d6fa91eaba725cc441e84", size = 69469, upload-time = "2025-11-30T20:24:38.837Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ed/dc/d61221eb88ff410de3c49143407f6f3147acf2538c86f2ab7ce65ae7d5f9/rpds_py-0.30.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:f83424d738204d9770830d35290ff3273fbb02b41f919870479fab14b9d303b2", size = 374887, upload-time = "2025-11-30T20:22:41.812Z" }, - { url = "https://files.pythonhosted.org/packages/fd/32/55fb50ae104061dbc564ef15cc43c013dc4a9f4527a1f4d99baddf56fe5f/rpds_py-0.30.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e7536cd91353c5273434b4e003cbda89034d67e7710eab8761fd918ec6c69cf8", size = 358904, upload-time = "2025-11-30T20:22:43.479Z" }, - { url = "https://files.pythonhosted.org/packages/58/70/faed8186300e3b9bdd138d0273109784eea2396c68458ed580f885dfe7ad/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2771c6c15973347f50fece41fc447c054b7ac2ae0502388ce3b6738cd366e3d4", size = 389945, upload-time = "2025-11-30T20:22:44.819Z" }, - { url = "https://files.pythonhosted.org/packages/bd/a8/073cac3ed2c6387df38f71296d002ab43496a96b92c823e76f46b8af0543/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0a59119fc6e3f460315fe9d08149f8102aa322299deaa5cab5b40092345c2136", size = 407783, upload-time = "2025-11-30T20:22:46.103Z" }, - { url = "https://files.pythonhosted.org/packages/77/57/5999eb8c58671f1c11eba084115e77a8899d6e694d2a18f69f0ba471ec8b/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:76fec018282b4ead0364022e3c54b60bf368b9d926877957a8624b58419169b7", size = 515021, upload-time = "2025-11-30T20:22:47.458Z" }, - { url = "https://files.pythonhosted.org/packages/e0/af/5ab4833eadc36c0a8ed2bc5c0de0493c04f6c06de223170bd0798ff98ced/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:692bef75a5525db97318e8cd061542b5a79812d711ea03dbc1f6f8dbb0c5f0d2", size = 414589, upload-time = "2025-11-30T20:22:48.872Z" }, - { url = "https://files.pythonhosted.org/packages/b7/de/f7192e12b21b9e9a68a6d0f249b4af3fdcdff8418be0767a627564afa1f1/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9027da1ce107104c50c81383cae773ef5c24d296dd11c99e2629dbd7967a20c6", size = 394025, upload-time = "2025-11-30T20:22:50.196Z" }, - { url = "https://files.pythonhosted.org/packages/91/c4/fc70cd0249496493500e7cc2de87504f5aa6509de1e88623431fec76d4b6/rpds_py-0.30.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:9cf69cdda1f5968a30a359aba2f7f9aa648a9ce4b580d6826437f2b291cfc86e", size = 408895, upload-time = "2025-11-30T20:22:51.87Z" }, - { url = "https://files.pythonhosted.org/packages/58/95/d9275b05ab96556fefff73a385813eb66032e4c99f411d0795372d9abcea/rpds_py-0.30.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a4796a717bf12b9da9d3ad002519a86063dcac8988b030e405704ef7d74d2d9d", size = 422799, upload-time = "2025-11-30T20:22:53.341Z" }, - { url = "https://files.pythonhosted.org/packages/06/c1/3088fc04b6624eb12a57eb814f0d4997a44b0d208d6cace713033ff1a6ba/rpds_py-0.30.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5d4c2aa7c50ad4728a094ebd5eb46c452e9cb7edbfdb18f9e1221f597a73e1e7", size = 572731, upload-time = "2025-11-30T20:22:54.778Z" }, - { url = "https://files.pythonhosted.org/packages/d8/42/c612a833183b39774e8ac8fecae81263a68b9583ee343db33ab571a7ce55/rpds_py-0.30.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ba81a9203d07805435eb06f536d95a266c21e5b2dfbf6517748ca40c98d19e31", size = 599027, upload-time = "2025-11-30T20:22:56.212Z" }, - { url = "https://files.pythonhosted.org/packages/5f/60/525a50f45b01d70005403ae0e25f43c0384369ad24ffe46e8d9068b50086/rpds_py-0.30.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:945dccface01af02675628334f7cf49c2af4c1c904748efc5cf7bbdf0b579f95", size = 563020, upload-time = "2025-11-30T20:22:58.2Z" }, - { url = "https://files.pythonhosted.org/packages/0b/5d/47c4655e9bcd5ca907148535c10e7d489044243cc9941c16ed7cd53be91d/rpds_py-0.30.0-cp313-cp313-win32.whl", hash = "sha256:b40fb160a2db369a194cb27943582b38f79fc4887291417685f3ad693c5a1d5d", size = 223139, upload-time = "2025-11-30T20:23:00.209Z" }, - { url = "https://files.pythonhosted.org/packages/f2/e1/485132437d20aa4d3e1d8b3fb5a5e65aa8139f1e097080c2a8443201742c/rpds_py-0.30.0-cp313-cp313-win_amd64.whl", hash = "sha256:806f36b1b605e2d6a72716f321f20036b9489d29c51c91f4dd29a3e3afb73b15", size = 240224, upload-time = "2025-11-30T20:23:02.008Z" }, - { url = "https://files.pythonhosted.org/packages/24/95/ffd128ed1146a153d928617b0ef673960130be0009c77d8fbf0abe306713/rpds_py-0.30.0-cp313-cp313-win_arm64.whl", hash = "sha256:d96c2086587c7c30d44f31f42eae4eac89b60dabbac18c7669be3700f13c3ce1", size = 230645, upload-time = "2025-11-30T20:23:03.43Z" }, - { url = "https://files.pythonhosted.org/packages/ff/1b/b10de890a0def2a319a2626334a7f0ae388215eb60914dbac8a3bae54435/rpds_py-0.30.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:eb0b93f2e5c2189ee831ee43f156ed34e2a89a78a66b98cadad955972548be5a", size = 364443, upload-time = "2025-11-30T20:23:04.878Z" }, - { url = "https://files.pythonhosted.org/packages/0d/bf/27e39f5971dc4f305a4fb9c672ca06f290f7c4e261c568f3dea16a410d47/rpds_py-0.30.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:922e10f31f303c7c920da8981051ff6d8c1a56207dbdf330d9047f6d30b70e5e", size = 353375, upload-time = "2025-11-30T20:23:06.342Z" }, - { url = "https://files.pythonhosted.org/packages/40/58/442ada3bba6e8e6615fc00483135c14a7538d2ffac30e2d933ccf6852232/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdc62c8286ba9bf7f47befdcea13ea0e26bf294bda99758fd90535cbaf408000", size = 383850, upload-time = "2025-11-30T20:23:07.825Z" }, - { url = "https://files.pythonhosted.org/packages/14/14/f59b0127409a33c6ef6f5c1ebd5ad8e32d7861c9c7adfa9a624fc3889f6c/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:47f9a91efc418b54fb8190a6b4aa7813a23fb79c51f4bb84e418f5476c38b8db", size = 392812, upload-time = "2025-11-30T20:23:09.228Z" }, - { url = "https://files.pythonhosted.org/packages/b3/66/e0be3e162ac299b3a22527e8913767d869e6cc75c46bd844aa43fb81ab62/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1f3587eb9b17f3789ad50824084fa6f81921bbf9a795826570bda82cb3ed91f2", size = 517841, upload-time = "2025-11-30T20:23:11.186Z" }, - { url = "https://files.pythonhosted.org/packages/3d/55/fa3b9cf31d0c963ecf1ba777f7cf4b2a2c976795ac430d24a1f43d25a6ba/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:39c02563fc592411c2c61d26b6c5fe1e51eaa44a75aa2c8735ca88b0d9599daa", size = 408149, upload-time = "2025-11-30T20:23:12.864Z" }, - { url = "https://files.pythonhosted.org/packages/60/ca/780cf3b1a32b18c0f05c441958d3758f02544f1d613abf9488cd78876378/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51a1234d8febafdfd33a42d97da7a43f5dcb120c1060e352a3fbc0c6d36e2083", size = 383843, upload-time = "2025-11-30T20:23:14.638Z" }, - { url = "https://files.pythonhosted.org/packages/82/86/d5f2e04f2aa6247c613da0c1dd87fcd08fa17107e858193566048a1e2f0a/rpds_py-0.30.0-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:eb2c4071ab598733724c08221091e8d80e89064cd472819285a9ab0f24bcedb9", size = 396507, upload-time = "2025-11-30T20:23:16.105Z" }, - { url = "https://files.pythonhosted.org/packages/4b/9a/453255d2f769fe44e07ea9785c8347edaf867f7026872e76c1ad9f7bed92/rpds_py-0.30.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6bdfdb946967d816e6adf9a3d8201bfad269c67efe6cefd7093ef959683c8de0", size = 414949, upload-time = "2025-11-30T20:23:17.539Z" }, - { url = "https://files.pythonhosted.org/packages/a3/31/622a86cdc0c45d6df0e9ccb6becdba5074735e7033c20e401a6d9d0e2ca0/rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c77afbd5f5250bf27bf516c7c4a016813eb2d3e116139aed0096940c5982da94", size = 565790, upload-time = "2025-11-30T20:23:19.029Z" }, - { url = "https://files.pythonhosted.org/packages/1c/5d/15bbf0fb4a3f58a3b1c67855ec1efcc4ceaef4e86644665fff03e1b66d8d/rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:61046904275472a76c8c90c9ccee9013d70a6d0f73eecefd38c1ae7c39045a08", size = 590217, upload-time = "2025-11-30T20:23:20.885Z" }, - { url = "https://files.pythonhosted.org/packages/6d/61/21b8c41f68e60c8cc3b2e25644f0e3681926020f11d06ab0b78e3c6bbff1/rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4c5f36a861bc4b7da6516dbdf302c55313afa09b81931e8280361a4f6c9a2d27", size = 555806, upload-time = "2025-11-30T20:23:22.488Z" }, - { url = "https://files.pythonhosted.org/packages/f9/39/7e067bb06c31de48de3eb200f9fc7c58982a4d3db44b07e73963e10d3be9/rpds_py-0.30.0-cp313-cp313t-win32.whl", hash = "sha256:3d4a69de7a3e50ffc214ae16d79d8fbb0922972da0356dcf4d0fdca2878559c6", size = 211341, upload-time = "2025-11-30T20:23:24.449Z" }, - { url = "https://files.pythonhosted.org/packages/0a/4d/222ef0b46443cf4cf46764d9c630f3fe4abaa7245be9417e56e9f52b8f65/rpds_py-0.30.0-cp313-cp313t-win_amd64.whl", hash = "sha256:f14fc5df50a716f7ece6a80b6c78bb35ea2ca47c499e422aa4463455dd96d56d", size = 225768, upload-time = "2025-11-30T20:23:25.908Z" }, { url = "https://files.pythonhosted.org/packages/86/81/dad16382ebbd3d0e0328776d8fd7ca94220e4fa0798d1dc5e7da48cb3201/rpds_py-0.30.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:68f19c879420aa08f61203801423f6cd5ac5f0ac4ac82a2368a9fcd6a9a075e0", size = 362099, upload-time = "2025-11-30T20:23:27.316Z" }, { url = "https://files.pythonhosted.org/packages/2b/60/19f7884db5d5603edf3c6bce35408f45ad3e97e10007df0e17dd57af18f8/rpds_py-0.30.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ec7c4490c672c1a0389d319b3a9cfcd098dcdc4783991553c332a15acf7249be", size = 353192, upload-time = "2025-11-30T20:23:29.151Z" }, { url = "https://files.pythonhosted.org/packages/bf/c4/76eb0e1e72d1a9c4703c69607cec123c29028bff28ce41588792417098ac/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f251c812357a3fed308d684a5079ddfb9d933860fc6de89f2b7ab00da481e65f", size = 384080, upload-time = "2025-11-30T20:23:30.785Z" }, @@ -1480,15 +1364,15 @@ wheels = [ [[package]] name = "sse-starlette" -version = "3.2.0" +version = "3.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, { name = "starlette" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/8b/8d/00d280c03ffd39aaee0e86ec81e2d3b9253036a0f93f51d10503adef0e65/sse_starlette-3.2.0.tar.gz", hash = "sha256:8127594edfb51abe44eac9c49e59b0b01f1039d0c7461c6fd91d4e03b70da422", size = 27253, upload-time = "2026-01-17T13:11:05.62Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/9f/c3695c2d2d4ef70072c3a06992850498b01c6bc9be531950813716b426fa/sse_starlette-3.3.2.tar.gz", hash = "sha256:678fca55a1945c734d8472a6cad186a55ab02840b4f6786f5ee8770970579dcd", size = 32326, upload-time = "2026-02-28T11:24:34.36Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/96/7f/832f015020844a8b8f7a9cbc103dd76ba8e3875004c41e08440ea3a2b41a/sse_starlette-3.2.0-py3-none-any.whl", hash = "sha256:5876954bd51920fc2cd51baee47a080eb88a37b5b784e615abb0b283f801cdbf", size = 12763, upload-time = "2026-01-17T13:11:03.775Z" }, + { url = "https://files.pythonhosted.org/packages/61/28/8cb142d3fe80c4a2d8af54ca0b003f47ce0ba920974e7990fa6e016402d1/sse_starlette-3.3.2-py3-none-any.whl", hash = "sha256:5c3ea3dad425c601236726af2f27689b74494643f57017cafcb6f8c9acfbb862", size = 14270, upload-time = "2026-02-28T11:24:32.984Z" }, ] [[package]] @@ -1618,16 +1502,6 @@ version = "1.17.3" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/95/8f/aeb76c5b46e273670962298c23e7ddde79916cb74db802131d49a85e4b7d/wrapt-1.17.3.tar.gz", hash = "sha256:f66eb08feaa410fe4eebd17f2a2c8e2e46d3476e9f8c783daa8e09e0faa666d0", size = 55547, upload-time = "2025-08-12T05:53:21.714Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fc/f6/759ece88472157acb55fc195e5b116e06730f1b651b5b314c66291729193/wrapt-1.17.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a47681378a0439215912ef542c45a783484d4dd82bac412b71e59cf9c0e1cea0", size = 54003, upload-time = "2025-08-12T05:51:48.627Z" }, - { url = "https://files.pythonhosted.org/packages/4f/a9/49940b9dc6d47027dc850c116d79b4155f15c08547d04db0f07121499347/wrapt-1.17.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:54a30837587c6ee3cd1a4d1c2ec5d24e77984d44e2f34547e2323ddb4e22eb77", size = 39025, upload-time = "2025-08-12T05:51:37.156Z" }, - { url = "https://files.pythonhosted.org/packages/45/35/6a08de0f2c96dcdd7fe464d7420ddb9a7655a6561150e5fc4da9356aeaab/wrapt-1.17.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:16ecf15d6af39246fe33e507105d67e4b81d8f8d2c6598ff7e3ca1b8a37213f7", size = 39108, upload-time = "2025-08-12T05:51:58.425Z" }, - { url = "https://files.pythonhosted.org/packages/0c/37/6faf15cfa41bf1f3dba80cd3f5ccc6622dfccb660ab26ed79f0178c7497f/wrapt-1.17.3-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6fd1ad24dc235e4ab88cda009e19bf347aabb975e44fd5c2fb22a3f6e4141277", size = 88072, upload-time = "2025-08-12T05:52:37.53Z" }, - { url = "https://files.pythonhosted.org/packages/78/f2/efe19ada4a38e4e15b6dff39c3e3f3f73f5decf901f66e6f72fe79623a06/wrapt-1.17.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ed61b7c2d49cee3c027372df5809a59d60cf1b6c2f81ee980a091f3afed6a2d", size = 88214, upload-time = "2025-08-12T05:52:15.886Z" }, - { url = "https://files.pythonhosted.org/packages/40/90/ca86701e9de1622b16e09689fc24b76f69b06bb0150990f6f4e8b0eeb576/wrapt-1.17.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:423ed5420ad5f5529db9ce89eac09c8a2f97da18eb1c870237e84c5a5c2d60aa", size = 87105, upload-time = "2025-08-12T05:52:17.914Z" }, - { url = "https://files.pythonhosted.org/packages/fd/e0/d10bd257c9a3e15cbf5523025252cc14d77468e8ed644aafb2d6f54cb95d/wrapt-1.17.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e01375f275f010fcbf7f643b4279896d04e571889b8a5b3f848423d91bf07050", size = 87766, upload-time = "2025-08-12T05:52:39.243Z" }, - { url = "https://files.pythonhosted.org/packages/e8/cf/7d848740203c7b4b27eb55dbfede11aca974a51c3d894f6cc4b865f42f58/wrapt-1.17.3-cp313-cp313-win32.whl", hash = "sha256:53e5e39ff71b3fc484df8a522c933ea2b7cdd0d5d15ae82e5b23fde87d44cbd8", size = 36711, upload-time = "2025-08-12T05:53:10.074Z" }, - { url = "https://files.pythonhosted.org/packages/57/54/35a84d0a4d23ea675994104e667ceff49227ce473ba6a59ba2c84f250b74/wrapt-1.17.3-cp313-cp313-win_amd64.whl", hash = "sha256:1f0b2f40cf341ee8cc1a97d51ff50dddb9fcc73241b9143ec74b30fc4f44f6cb", size = 38885, upload-time = "2025-08-12T05:53:08.695Z" }, - { url = "https://files.pythonhosted.org/packages/01/77/66e54407c59d7b02a3c4e0af3783168fff8e5d61def52cda8728439d86bc/wrapt-1.17.3-cp313-cp313-win_arm64.whl", hash = "sha256:7425ac3c54430f5fc5e7b6f41d41e704db073309acfc09305816bc6a0b26bb16", size = 36896, upload-time = "2025-08-12T05:52:55.34Z" }, { url = "https://files.pythonhosted.org/packages/02/a2/cd864b2a14f20d14f4c496fab97802001560f9f41554eef6df201cd7f76c/wrapt-1.17.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:cf30f6e3c077c8e6a9a7809c94551203c8843e74ba0c960f4a98cd80d4665d39", size = 54132, upload-time = "2025-08-12T05:51:49.864Z" }, { url = "https://files.pythonhosted.org/packages/d5/46/d011725b0c89e853dc44cceb738a307cde5d240d023d6d40a82d1b4e1182/wrapt-1.17.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e228514a06843cae89621384cfe3a80418f3c04aadf8a3b14e46a7be704e4235", size = 39091, upload-time = "2025-08-12T05:51:38.935Z" }, { url = "https://files.pythonhosted.org/packages/2e/9e/3ad852d77c35aae7ddebdbc3b6d35ec8013af7d7dddad0ad911f3d891dae/wrapt-1.17.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:5ea5eb3c0c071862997d6f3e02af1d055f381b1d25b286b9d6644b79db77657c", size = 39172, upload-time = "2025-08-12T05:51:59.365Z" }, diff --git a/apps/agentstack-sdk-py/tests/e2e/test_runs.py b/apps/agentstack-sdk-py/tests/e2e/test_runs.py index 3891d134b3..8b889f7d22 100644 --- a/apps/agentstack-sdk-py/tests/e2e/test_runs.py +++ b/apps/agentstack-sdk-py/tests/e2e/test_runs.py @@ -8,7 +8,7 @@ import pytest from a2a.client import Client, ClientEvent, create_text_message_object -from a2a.client.errors import A2AClientJSONRPCError +from a2a.utils.errors import A2AError from a2a.types import ( CancelTaskRequest, GetTaskRequest, @@ -352,5 +352,5 @@ async def test_run_timeout(awaiter_with_1s_timeout: tuple[Server, Client]) -> No resume_message = create_text_message_object(content="Resume input") resume_message.task_id = initial_task.id - with pytest.raises(A2AClientJSONRPCError, match="is in terminal state"): + with pytest.raises(A2AError, match="is in terminal state"): await get_final_task_from_stream(client.send_message(resume_message)) diff --git a/apps/agentstack-sdk-py/uv.lock b/apps/agentstack-sdk-py/uv.lock index f09d0030b7..cb41fb0249 100644 --- a/apps/agentstack-sdk-py/uv.lock +++ b/apps/agentstack-sdk-py/uv.lock @@ -8,8 +8,8 @@ resolution-markers = [ [[package]] name = "a2a-sdk" -version = "0.3.24.post44.dev0+6086f96" -source = { git = "https://github.com/a2aproject/a2a-python.git?rev=1.0-dev#6086f96a2b32cc01f822836385d8d68b074e61d1" } +version = "0.3.24.post54.dev0+5b354e4" +source = { git = "https://github.com/a2aproject/a2a-python.git?rev=1.0-dev#5b354e403a717c3c6bf47a291bef028c8c6a9d94" } dependencies = [ { name = "google-api-core" }, { name = "googleapis-common-protos" }, @@ -591,16 +591,16 @@ wheels = [ [[package]] name = "ddgs" -version = "9.11.1" +version = "9.11.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, { name = "lxml" }, { name = "primp" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fa/06/b148a33eb074ef0cde6f82a83dc2af2ec60d2a63f3e39b049dd8abdfaf39/ddgs-9.11.1.tar.gz", hash = "sha256:f01aec85e59ffe73dbab4517628d24702fb6ce2c345d2f5e6dd4b120526b56c7", size = 34442, upload-time = "2026-03-02T06:45:23.341Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6b/80/eb387dd4291d1624e773f455fd1dfc54596e06469d680fe3b3f8c326ba1a/ddgs-9.11.2.tar.gz", hash = "sha256:b5f072149580773291fd3eb6e9f4de47fa9d910ebd5ef85845a37e59cfe24c40", size = 34722, upload-time = "2026-03-05T05:17:31.574Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/92/6b/446ce962d40f243c90f704aceadaa1f577e35db11677323e35b7c4b55867/ddgs-9.11.1-py3-none-any.whl", hash = "sha256:404382a17c6055f28aa752809bd100ca23167611bb77368aa4c7012e254a16b8", size = 43304, upload-time = "2026-03-02T06:45:22.283Z" }, + { url = "https://files.pythonhosted.org/packages/2c/fe/7591bfa694ee26fcf0dd8035811994e28a9699402d3861eea7754958c1bd/ddgs-9.11.2-py3-none-any.whl", hash = "sha256:0023a3633d271e72cdd1da757d3fcea2d996608da3f3c9da2cc0c0607b219c76", size = 43646, upload-time = "2026-03-05T05:17:30.469Z" }, ] [[package]] @@ -1537,32 +1537,32 @@ wheels = [ [[package]] name = "opentelemetry-api" -version = "1.39.1" +version = "1.40.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "importlib-metadata" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/97/b9/3161be15bb8e3ad01be8be5a968a9237c3027c5be504362ff800fca3e442/opentelemetry_api-1.39.1.tar.gz", hash = "sha256:fbde8c80e1b937a2c61f20347e91c0c18a1940cecf012d62e65a7caf08967c9c", size = 65767, upload-time = "2025-12-11T13:32:39.182Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2c/1d/4049a9e8698361cc1a1aa03a6c59e4fa4c71e0c0f94a30f988a6876a2ae6/opentelemetry_api-1.40.0.tar.gz", hash = "sha256:159be641c0b04d11e9ecd576906462773eb97ae1b657730f0ecf64d32071569f", size = 70851, upload-time = "2026-03-04T14:17:21.555Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cf/df/d3f1ddf4bb4cb50ed9b1139cc7b1c54c34a1e7ce8fd1b9a37c0d1551a6bd/opentelemetry_api-1.39.1-py3-none-any.whl", hash = "sha256:2edd8463432a7f8443edce90972169b195e7d6a05500cd29e6d13898187c9950", size = 66356, upload-time = "2025-12-11T13:32:17.304Z" }, + { url = "https://files.pythonhosted.org/packages/5f/bf/93795954016c522008da367da292adceed71cca6ee1717e1d64c83089099/opentelemetry_api-1.40.0-py3-none-any.whl", hash = "sha256:82dd69331ae74b06f6a874704be0cfaa49a1650e1537d4a813b86ecef7d0ecf9", size = 68676, upload-time = "2026-03-04T14:17:01.24Z" }, ] [[package]] name = "opentelemetry-exporter-otlp-proto-common" -version = "1.39.1" +version = "1.40.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-proto" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e9/9d/22d241b66f7bbde88a3bfa6847a351d2c46b84de23e71222c6aae25c7050/opentelemetry_exporter_otlp_proto_common-1.39.1.tar.gz", hash = "sha256:763370d4737a59741c89a67b50f9e39271639ee4afc999dadfe768541c027464", size = 20409, upload-time = "2025-12-11T13:32:40.885Z" } +sdist = { url = "https://files.pythonhosted.org/packages/51/bc/1559d46557fe6eca0b46c88d4c2676285f1f3be2e8d06bb5d15fbffc814a/opentelemetry_exporter_otlp_proto_common-1.40.0.tar.gz", hash = "sha256:1cbee86a4064790b362a86601ee7934f368b81cd4cc2f2e163902a6e7818a0fa", size = 20416, upload-time = "2026-03-04T14:17:23.801Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8c/02/ffc3e143d89a27ac21fd557365b98bd0653b98de8a101151d5805b5d4c33/opentelemetry_exporter_otlp_proto_common-1.39.1-py3-none-any.whl", hash = "sha256:08f8a5862d64cc3435105686d0216c1365dc5701f86844a8cd56597d0c764fde", size = 18366, upload-time = "2025-12-11T13:32:20.2Z" }, + { url = "https://files.pythonhosted.org/packages/8b/ca/8f122055c97a932311a3f640273f084e738008933503d0c2563cd5d591fc/opentelemetry_exporter_otlp_proto_common-1.40.0-py3-none-any.whl", hash = "sha256:7081ff453835a82417bf38dccf122c827c3cbc94f2079b03bba02a3165f25149", size = 18369, upload-time = "2026-03-04T14:17:04.796Z" }, ] [[package]] name = "opentelemetry-exporter-otlp-proto-http" -version = "1.39.1" +version = "1.40.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "googleapis-common-protos" }, @@ -1573,14 +1573,14 @@ dependencies = [ { name = "requests" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/80/04/2a08fa9c0214ae38880df01e8bfae12b067ec0793446578575e5080d6545/opentelemetry_exporter_otlp_proto_http-1.39.1.tar.gz", hash = "sha256:31bdab9745c709ce90a49a0624c2bd445d31a28ba34275951a6a362d16a0b9cb", size = 17288, upload-time = "2025-12-11T13:32:42.029Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2e/fa/73d50e2c15c56be4d000c98e24221d494674b0cc95524e2a8cb3856d95a4/opentelemetry_exporter_otlp_proto_http-1.40.0.tar.gz", hash = "sha256:db48f5e0f33217588bbc00274a31517ba830da576e59503507c839b38fa0869c", size = 17772, upload-time = "2026-03-04T14:17:25.324Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/95/f1/b27d3e2e003cd9a3592c43d099d2ed8d0a947c15281bf8463a256db0b46c/opentelemetry_exporter_otlp_proto_http-1.39.1-py3-none-any.whl", hash = "sha256:d9f5207183dd752a412c4cd564ca8875ececba13be6e9c6c370ffb752fd59985", size = 19641, upload-time = "2025-12-11T13:32:22.248Z" }, + { url = "https://files.pythonhosted.org/packages/a0/3a/8865d6754e61c9fb170cdd530a124a53769ee5f740236064816eb0ca7301/opentelemetry_exporter_otlp_proto_http-1.40.0-py3-none-any.whl", hash = "sha256:a8d1dab28f504c5d96577d6509f80a8150e44e8f45f82cdbe0e34c99ab040069", size = 19960, upload-time = "2026-03-04T14:17:07.153Z" }, ] [[package]] name = "opentelemetry-instrumentation" -version = "0.60b1" +version = "0.61b0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, @@ -1588,14 +1588,14 @@ dependencies = [ { name = "packaging" }, { name = "wrapt" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/41/0f/7e6b713ac117c1f5e4e3300748af699b9902a2e5e34c9cf443dde25a01fa/opentelemetry_instrumentation-0.60b1.tar.gz", hash = "sha256:57ddc7974c6eb35865af0426d1a17132b88b2ed8586897fee187fd5b8944bd6a", size = 31706, upload-time = "2025-12-11T13:36:42.515Z" } +sdist = { url = "https://files.pythonhosted.org/packages/da/37/6bf8e66bfcee5d3c6515b79cb2ee9ad05fe573c20f7ceb288d0e7eeec28c/opentelemetry_instrumentation-0.61b0.tar.gz", hash = "sha256:cb21b48db738c9de196eba6b805b4ff9de3b7f187e4bbf9a466fa170514f1fc7", size = 32606, upload-time = "2026-03-04T14:20:16.825Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/77/d2/6788e83c5c86a2690101681aeef27eeb2a6bf22df52d3f263a22cee20915/opentelemetry_instrumentation-0.60b1-py3-none-any.whl", hash = "sha256:04480db952b48fb1ed0073f822f0ee26012b7be7c3eac1a3793122737c78632d", size = 33096, upload-time = "2025-12-11T13:35:33.067Z" }, + { url = "https://files.pythonhosted.org/packages/d8/3e/f6f10f178b6316de67f0dfdbbb699a24fbe8917cf1743c1595fb9dcdd461/opentelemetry_instrumentation-0.61b0-py3-none-any.whl", hash = "sha256:92a93a280e69788e8f88391247cc530fd81f16f2b011979d4d6398f805cfbc63", size = 33448, upload-time = "2026-03-04T14:19:02.447Z" }, ] [[package]] name = "opentelemetry-instrumentation-asgi" -version = "0.60b1" +version = "0.61b0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "asgiref" }, @@ -1604,14 +1604,14 @@ dependencies = [ { name = "opentelemetry-semantic-conventions" }, { name = "opentelemetry-util-http" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/77/db/851fa88db7441da82d50bd80f2de5ee55213782e25dc858e04d0c9961d60/opentelemetry_instrumentation_asgi-0.60b1.tar.gz", hash = "sha256:16bfbe595cd24cda309a957456d0fc2523f41bc7b076d1f2d7e98a1ad9876d6f", size = 26107, upload-time = "2025-12-11T13:36:47.015Z" } +sdist = { url = "https://files.pythonhosted.org/packages/00/3e/143cf5c034e58037307e6a24f06e0dd64b2c49ae60a965fc580027581931/opentelemetry_instrumentation_asgi-0.61b0.tar.gz", hash = "sha256:9d08e127244361dc33976d39dd4ca8f128b5aa5a7ae425208400a80a095019b5", size = 26691, upload-time = "2026-03-04T14:20:21.038Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/76/76/1fb94367cef64420d2171157a6b9509582873bd09a6afe08a78a8d1f59d9/opentelemetry_instrumentation_asgi-0.60b1-py3-none-any.whl", hash = "sha256:d48def2dbed10294c99cfcf41ebbd0c414d390a11773a41f472d20000fcddc25", size = 16933, upload-time = "2025-12-11T13:35:40.462Z" }, + { url = "https://files.pythonhosted.org/packages/19/78/154470cf9d741a7487fbb5067357b87386475bbb77948a6707cae982e158/opentelemetry_instrumentation_asgi-0.61b0-py3-none-any.whl", hash = "sha256:e4b3ce6b66074e525e717efff20745434e5efd5d9df6557710856fba356da7a4", size = 16980, upload-time = "2026-03-04T14:19:10.894Z" }, ] [[package]] name = "opentelemetry-instrumentation-fastapi" -version = "0.60b1" +version = "0.61b0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, @@ -1620,14 +1620,14 @@ dependencies = [ { name = "opentelemetry-semantic-conventions" }, { name = "opentelemetry-util-http" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9c/e7/e7e5e50218cf488377209d85666b182fa2d4928bf52389411ceeee1b2b60/opentelemetry_instrumentation_fastapi-0.60b1.tar.gz", hash = "sha256:de608955f7ff8eecf35d056578346a5365015fd7d8623df9b1f08d1c74769c01", size = 24958, upload-time = "2025-12-11T13:36:59.35Z" } +sdist = { url = "https://files.pythonhosted.org/packages/37/35/aa727bb6e6ef930dcdc96a617b83748fece57b43c47d83ba8d83fbeca657/opentelemetry_instrumentation_fastapi-0.61b0.tar.gz", hash = "sha256:3a24f35b07c557ae1bbc483bf8412221f25d79a405f8b047de8b670722e2fa9f", size = 24800, upload-time = "2026-03-04T14:20:32.759Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7d/cc/6e808328ba54662e50babdcab21138eae4250bc0fddf67d55526a615a2ca/opentelemetry_instrumentation_fastapi-0.60b1-py3-none-any.whl", hash = "sha256:af94b7a239ad1085fc3a820ecf069f67f579d7faf4c085aaa7bd9b64eafc8eaf", size = 13478, upload-time = "2025-12-11T13:36:00.811Z" }, + { url = "https://files.pythonhosted.org/packages/91/05/acfeb2cccd434242a0a7d0ea29afaf077e04b42b35b485d89aee4e0d9340/opentelemetry_instrumentation_fastapi-0.61b0-py3-none-any.whl", hash = "sha256:a1a844d846540d687d377516b2ff698b51d87c781b59f47c214359c4a241047c", size = 13485, upload-time = "2026-03-04T14:19:30.351Z" }, ] [[package]] name = "opentelemetry-instrumentation-httpx" -version = "0.60b1" +version = "0.61b0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, @@ -1636,14 +1636,14 @@ dependencies = [ { name = "opentelemetry-util-http" }, { name = "wrapt" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/86/08/11208bcfcab4fc2023252c3f322aa397fd9ad948355fea60f5fc98648603/opentelemetry_instrumentation_httpx-0.60b1.tar.gz", hash = "sha256:a506ebaf28c60112cbe70ad4f0338f8603f148938cb7b6794ce1051cd2b270ae", size = 20611, upload-time = "2025-12-11T13:37:01.661Z" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/2a/e2becd55e33c29d1d9ef76e2579040ed1951cb33bacba259f6aff2fdd2a6/opentelemetry_instrumentation_httpx-0.61b0.tar.gz", hash = "sha256:6569ec097946c5551c2a4252f74c98666addd1bf047c1dde6b4ef426719ff8dd", size = 24104, upload-time = "2026-03-04T14:20:34.752Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/43/59/b98e84eebf745ffc75397eaad4763795bff8a30cbf2373a50ed4e70646c5/opentelemetry_instrumentation_httpx-0.60b1-py3-none-any.whl", hash = "sha256:f37636dd742ad2af83d896ba69601ed28da51fa4e25d1ab62fde89ce413e275b", size = 15701, upload-time = "2025-12-11T13:36:04.56Z" }, + { url = "https://files.pythonhosted.org/packages/af/88/dde310dce56e2d85cf1a09507f5888544955309edc4b8d22971d6d3d1417/opentelemetry_instrumentation_httpx-0.61b0-py3-none-any.whl", hash = "sha256:dee05c93a6593a5dc3ae5d9d5c01df8b4e2c5d02e49275e5558534ee46343d5e", size = 17198, upload-time = "2026-03-04T14:19:33.585Z" }, ] [[package]] name = "opentelemetry-instrumentation-openai" -version = "0.52.6" +version = "0.53.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, @@ -1651,48 +1651,48 @@ dependencies = [ { name = "opentelemetry-semantic-conventions" }, { name = "opentelemetry-semantic-conventions-ai" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/37/86/1fe5008f3714118fdc1024cd141140a5f204d5ac7016e87a0f07a834efb2/opentelemetry_instrumentation_openai-0.52.6.tar.gz", hash = "sha256:0eb23dc90804a726e516fcbd649cb99f10dfdb5e31d29e44c4b1b8f402dd905d", size = 6978397, upload-time = "2026-02-26T15:40:17.154Z" } +sdist = { url = "https://files.pythonhosted.org/packages/10/b7/b3b5536671658001c62c117fa834df2a3bd524e950a7773d53b71fca3219/opentelemetry_instrumentation_openai-0.53.0.tar.gz", hash = "sha256:c0cd83d223d138309af3cc5f53c9c6d22136374bfa00e8f66dff31cd322ef547", size = 6978375, upload-time = "2026-03-04T07:49:18.112Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/4a/4623d0adc0187cc45bce631f891c30cd01cf2562d37b918b79561200d985/opentelemetry_instrumentation_openai-0.52.6-py3-none-any.whl", hash = "sha256:5e174388520f294f648f9732471c1b9919c71e5d09649a64ab8ff81714c1278b", size = 43084, upload-time = "2026-02-26T15:39:35.584Z" }, + { url = "https://files.pythonhosted.org/packages/44/3b/58ac94d0f56afb3c0352d3e6d35ea9de6331292a7316403ea97de4c6d915/opentelemetry_instrumentation_openai-0.53.0-py3-none-any.whl", hash = "sha256:91d9f69673636f5f7d50e5a4782e4526d6df3a1ddfd6ac2d9e15a957f8fd9ad8", size = 43084, upload-time = "2026-03-04T07:48:43.676Z" }, ] [[package]] name = "opentelemetry-proto" -version = "1.39.1" +version = "1.40.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/49/1d/f25d76d8260c156c40c97c9ed4511ec0f9ce353f8108ca6e7561f82a06b2/opentelemetry_proto-1.39.1.tar.gz", hash = "sha256:6c8e05144fc0d3ed4d22c2289c6b126e03bcd0e6a7da0f16cedd2e1c2772e2c8", size = 46152, upload-time = "2025-12-11T13:32:48.681Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4c/77/dd38991db037fdfce45849491cb61de5ab000f49824a00230afb112a4392/opentelemetry_proto-1.40.0.tar.gz", hash = "sha256:03f639ca129ba513f5819810f5b1f42bcb371391405d99c168fe6937c62febcd", size = 45667, upload-time = "2026-03-04T14:17:31.194Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/51/95/b40c96a7b5203005a0b03d8ce8cd212ff23f1793d5ba289c87a097571b18/opentelemetry_proto-1.39.1-py3-none-any.whl", hash = "sha256:22cdc78efd3b3765d09e68bfbd010d4fc254c9818afd0b6b423387d9dee46007", size = 72535, upload-time = "2025-12-11T13:32:33.866Z" }, + { url = "https://files.pythonhosted.org/packages/b9/b2/189b2577dde745b15625b3214302605b1353436219d42b7912e77fa8dc24/opentelemetry_proto-1.40.0-py3-none-any.whl", hash = "sha256:266c4385d88923a23d63e353e9761af0f47a6ed0d486979777fe4de59dc9b25f", size = 72073, upload-time = "2026-03-04T14:17:16.673Z" }, ] [[package]] name = "opentelemetry-sdk" -version = "1.39.1" +version = "1.40.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, { name = "opentelemetry-semantic-conventions" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/eb/fb/c76080c9ba07e1e8235d24cdcc4d125ef7aa3edf23eb4e497c2e50889adc/opentelemetry_sdk-1.39.1.tar.gz", hash = "sha256:cf4d4563caf7bff906c9f7967e2be22d0d6b349b908be0d90fb21c8e9c995cc6", size = 171460, upload-time = "2025-12-11T13:32:49.369Z" } +sdist = { url = "https://files.pythonhosted.org/packages/58/fd/3c3125b20ba18ce2155ba9ea74acb0ae5d25f8cd39cfd37455601b7955cc/opentelemetry_sdk-1.40.0.tar.gz", hash = "sha256:18e9f5ec20d859d268c7cb3c5198c8d105d073714db3de50b593b8c1345a48f2", size = 184252, upload-time = "2026-03-04T14:17:31.87Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7c/98/e91cf858f203d86f4eccdf763dcf01cf03f1dae80c3750f7e635bfa206b6/opentelemetry_sdk-1.39.1-py3-none-any.whl", hash = "sha256:4d5482c478513ecb0a5d938dcc61394e647066e0cc2676bee9f3af3f3f45f01c", size = 132565, upload-time = "2025-12-11T13:32:35.069Z" }, + { url = "https://files.pythonhosted.org/packages/2c/c5/6a852903d8bfac758c6dc6e9a68b015d3c33f2f1be5e9591e0f4b69c7e0a/opentelemetry_sdk-1.40.0-py3-none-any.whl", hash = "sha256:787d2154a71f4b3d81f20524a8ce061b7db667d24e46753f32a7bc48f1c1f3f1", size = 141951, upload-time = "2026-03-04T14:17:17.961Z" }, ] [[package]] name = "opentelemetry-semantic-conventions" -version = "0.60b1" +version = "0.61b0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/91/df/553f93ed38bf22f4b999d9be9c185adb558982214f33eae539d3b5cd0858/opentelemetry_semantic_conventions-0.60b1.tar.gz", hash = "sha256:87c228b5a0669b748c76d76df6c364c369c28f1c465e50f661e39737e84bc953", size = 137935, upload-time = "2025-12-11T13:32:50.487Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6d/c0/4ae7973f3c2cfd2b6e321f1675626f0dab0a97027cc7a297474c9c8f3d04/opentelemetry_semantic_conventions-0.61b0.tar.gz", hash = "sha256:072f65473c5d7c6dc0355b27d6c9d1a679d63b6d4b4b16a9773062cb7e31192a", size = 145755, upload-time = "2026-03-04T14:17:32.664Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7a/5e/5958555e09635d09b75de3c4f8b9cae7335ca545d77392ffe7331534c402/opentelemetry_semantic_conventions-0.60b1-py3-none-any.whl", hash = "sha256:9fa8c8b0c110da289809292b0591220d3a7b53c1526a23021e977d68597893fb", size = 219982, upload-time = "2025-12-11T13:32:36.955Z" }, + { url = "https://files.pythonhosted.org/packages/b2/37/cc6a55e448deaa9b27377d087da8615a3416d8ad523d5960b78dbeadd02a/opentelemetry_semantic_conventions-0.61b0-py3-none-any.whl", hash = "sha256:fa530a96be229795f8cef353739b618148b0fe2b4b3f005e60e262926c4d38e2", size = 231621, upload-time = "2026-03-04T14:17:19.33Z" }, ] [[package]] @@ -1710,11 +1710,11 @@ wheels = [ [[package]] name = "opentelemetry-util-http" -version = "0.60b1" +version = "0.61b0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/50/fc/c47bb04a1d8a941a4061307e1eddfa331ed4d0ab13d8a9781e6db256940a/opentelemetry_util_http-0.60b1.tar.gz", hash = "sha256:0d97152ca8c8a41ced7172d29d3622a219317f74ae6bb3027cfbdcf22c3cc0d6", size = 11053, upload-time = "2025-12-11T13:37:25.115Z" } +sdist = { url = "https://files.pythonhosted.org/packages/57/3c/f0196223efc5c4ca19f8fad3d5462b171ac6333013335ce540c01af419e9/opentelemetry_util_http-0.61b0.tar.gz", hash = "sha256:1039cb891334ad2731affdf034d8fb8b48c239af9b6dd295e5fabd07f1c95572", size = 11361, upload-time = "2026-03-04T14:20:57.01Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/16/5c/d3f1733665f7cd582ef0842fb1d2ed0bc1fba10875160593342d22bba375/opentelemetry_util_http-0.60b1-py3-none-any.whl", hash = "sha256:66381ba28550c91bee14dcba8979ace443444af1ed609226634596b4b0faf199", size = 8947, upload-time = "2025-12-11T13:36:37.151Z" }, + { url = "https://files.pythonhosted.org/packages/0d/e5/c08aaaf2f64288d2b6ef65741d2de5454e64af3e050f34285fb1907492fe/opentelemetry_util_http-0.61b0-py3-none-any.whl", hash = "sha256:8e715e848233e9527ea47e275659ea60a57a75edf5206a3b937e236a6da5fc33", size = 9281, upload-time = "2026-03-04T14:20:08.364Z" }, ] [[package]] diff --git a/apps/agentstack-server/Dockerfile b/apps/agentstack-server/Dockerfile index 4788a9fbe9..1d5c8b4884 100644 --- a/apps/agentstack-server/Dockerfile +++ b/apps/agentstack-server/Dockerfile @@ -6,7 +6,7 @@ ENV UV_COMPILE_BYTECODE=1 \ UV_LINK_MODE=copy \ HOME="/tmp" \ AGENT_REGISTRY__LOCATIONS__FILE="file:///app/registry.yaml" -RUN apk add bash git nodejs npm +RUN apk add bash git nodejs npm curl RUN --mount=type=cache,target=/tmp/.cache/uv \ --mount=type=bind,source=dist/requirements.txt,target=/requirements.txt \ --mount=type=bind,from=uv,source=/uv,target=/bin/uv \ diff --git a/apps/agentstack-server/src/agentstack_server/api/routes/a2a.py b/apps/agentstack-server/src/agentstack_server/api/routes/a2a.py index 159e6f9386..b2455eb5b3 100644 --- a/apps/agentstack-server/src/agentstack_server/api/routes/a2a.py +++ b/apps/agentstack-server/src/agentstack_server/api/routes/a2a.py @@ -8,7 +8,6 @@ from uuid import UUID import fastapi -import fastapi.responses from a2a.server.apps import A2AFastAPIApplication from a2a.server.apps.rest.rest_adapter import RESTAdapter from a2a.types import AgentCard, AgentInterface, HTTPAuthSecurityScheme, SecurityRequirement, SecurityScheme diff --git a/apps/agentstack-server/src/agentstack_server/service_layer/services/a2a.py b/apps/agentstack-server/src/agentstack_server/service_layer/services/a2a.py index 8c0c7de715..487b898ce1 100644 --- a/apps/agentstack-server/src/agentstack_server/service_layer/services/a2a.py +++ b/apps/agentstack-server/src/agentstack_server/service_layer/services/a2a.py @@ -17,11 +17,9 @@ import httpx from a2a.client import ClientCallContext, ClientConfig, ClientFactory from a2a.client.base_client import BaseClient -from a2a.client.errors import A2AClientJSONRPCError from a2a.client.transports.base import ClientTransport from a2a.server.context import ServerCallContext from a2a.server.events import Event -from a2a.server.request_handlers.jsonrpc_handler import ERROR_CODE_MAP from a2a.server.request_handlers.request_handler import RequestHandler from a2a.types import ( AgentCard, @@ -45,7 +43,7 @@ TaskNotFoundError, TaskPushNotificationConfig, ) -from a2a.utils.errors import ServerError +from a2a.utils.errors import A2AError from google.protobuf.json_format import ParseDict from kink import inject from opentelemetry import trace @@ -126,22 +124,16 @@ def _handle_exception_impl() -> Iterator[None]: yield except EntityNotFoundError as e: if "task" in e.entity: - raise ServerError(error=TaskNotFoundError()) from e + raise TaskNotFoundError() from e raise except ForbiddenUpdateError as e: - raise ServerError(error=InvalidRequestError(message=str(e))) from e - except A2AClientJSONRPCError as e: - if ( - isinstance(e.error, dict) - and "code" in e.error - and (error_cls := {v: k for k, v in ERROR_CODE_MAP.items()}.get(e.error["code"])) - ): - raise ServerError(error=error_cls(e.error.get("message"))) from e - raise ServerError(error=e.error) from e + raise InvalidRequestError(message=str(e)) from e + except A2AError: + raise except InvalidProviderCallError as e: - raise ServerError(error=InvalidRequestError(message=f"Invalid request to agent: {e!r}")) from e + raise InvalidRequestError(message=f"Invalid request to agent: {e!r}") from e except Exception as e: - raise ServerError(error=InternalError(message=f"Internal error: {e!r}")) from e + raise InternalError(message=f"Internal error: {e!r}") from e if inspect.isasyncgenfunction(fn): diff --git a/apps/agentstack-server/tests/e2e/agents/test_agent_starts.py b/apps/agentstack-server/tests/e2e/agents/test_agent_starts.py index 065c9fd49e..9a390df215 100644 --- a/apps/agentstack-server/tests/e2e/agents/test_agent_starts.py +++ b/apps/agentstack-server/tests/e2e/agents/test_agent_starts.py @@ -14,7 +14,7 @@ import kr8s import pytest import uvicorn -from a2a.client import A2AClientHTTPError +from a2a.client import A2AClientError from a2a.client.helpers import create_text_message_object from a2a.server.agent_execution import AgentExecutor from a2a.server.apps import A2AStarletteApplication @@ -143,7 +143,7 @@ async def main(): async with a2a_client_factory(providers[0].agent_card, invalid_context_token) as a2a_client: with ( subtests.test("run chat agent with invalid token"), - pytest.raises(A2AClientHTTPError, match="403 Forbidden"), + pytest.raises(A2AClientError, match="403 Forbidden"), ): await get_final_task_from_stream(a2a_client.send_message(message)) diff --git a/apps/agentstack-server/tests/e2e/routes/test_a2a_proxy.py b/apps/agentstack-server/tests/e2e/routes/test_a2a_proxy.py index 0f95c285c5..9f10b34514 100644 --- a/apps/agentstack-server/tests/e2e/routes/test_a2a_proxy.py +++ b/apps/agentstack-server/tests/e2e/routes/test_a2a_proxy.py @@ -49,7 +49,7 @@ EXTENDED_AGENT_CARD_PATH, PREV_AGENT_CARD_WELL_KNOWN_PATH, ) -from a2a.utils.errors import MethodNotImplementedError +from a2a.utils.errors import UnsupportedOperationError from fastapi import FastAPI from google.protobuf.struct_pb2 import Struct, Value from httpx import Client, ReadTimeout @@ -788,7 +788,7 @@ def test_invalid_request_structure(client: Client): def test_method_not_implemented(client: Client, handler: mock.AsyncMock, ensure_mock_task): """Test handling MethodNotImplementedError.""" - handler.on_get_task.side_effect = MethodNotImplementedError() + handler.on_get_task.side_effect = UnsupportedOperationError() response = client.post( "/", diff --git a/apps/agentstack-server/uv.lock b/apps/agentstack-server/uv.lock index 13c84dbcb5..d39e654675 100644 --- a/apps/agentstack-server/uv.lock +++ b/apps/agentstack-server/uv.lock @@ -4,8 +4,8 @@ requires-python = "==3.14.*" [[package]] name = "a2a-sdk" -version = "0.3.24.post41.dev0+041f0f5" -source = { git = "https://github.com/a2aproject/a2a-python.git?rev=1.0-dev#041f0f53bcf5fc2e74545d653bfeeba8d2d85c79" } +version = "0.3.24.post54.dev0+5b354e4" +source = { git = "https://github.com/a2aproject/a2a-python.git?rev=1.0-dev#5b354e403a717c3c6bf47a291bef028c8c6a9d94" } dependencies = [ { name = "google-api-core" }, { name = "googleapis-common-protos" }, @@ -507,11 +507,11 @@ wheels = [ [[package]] name = "cachetools" -version = "7.0.1" +version = "7.0.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d4/07/56595285564e90777d758ebd383d6b0b971b87729bbe2184a849932a3736/cachetools-7.0.1.tar.gz", hash = "sha256:e31e579d2c5b6e2944177a0397150d312888ddf4e16e12f1016068f0c03b8341", size = 36126, upload-time = "2026-02-10T22:24:05.03Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6c/c7/342b33cc6877eebc6c9bb45cb9f78e170e575839699f6f3cc96050176431/cachetools-7.0.2.tar.gz", hash = "sha256:7e7f09a4ca8b791d8bb4864afc71e9c17e607a28e6839ca1a644253c97dbeae0", size = 36983, upload-time = "2026-03-02T19:45:16.926Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ed/9e/5faefbf9db1db466d633735faceda1f94aa99ce506ac450d232536266b32/cachetools-7.0.1-py3-none-any.whl", hash = "sha256:8f086515c254d5664ae2146d14fc7f65c9a4bce75152eb247e5a9c5e6d7b2ecf", size = 13484, upload-time = "2026-02-10T22:24:03.741Z" }, + { url = "https://files.pythonhosted.org/packages/ef/04/4b6968e77c110f12da96fdbfcb39c6557c2e5e81bd7afcf8ed893d5bc588/cachetools-7.0.2-py3-none-any.whl", hash = "sha256:938dcad184827c5e94928c4fd5526e2b46692b7fb1ae94472da9131d0299343c", size = 13793, upload-time = "2026-03-02T19:45:15.495Z" }, ] [[package]] @@ -1517,32 +1517,32 @@ wheels = [ [[package]] name = "opentelemetry-api" -version = "1.39.1" +version = "1.40.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "importlib-metadata" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/97/b9/3161be15bb8e3ad01be8be5a968a9237c3027c5be504362ff800fca3e442/opentelemetry_api-1.39.1.tar.gz", hash = "sha256:fbde8c80e1b937a2c61f20347e91c0c18a1940cecf012d62e65a7caf08967c9c", size = 65767, upload-time = "2025-12-11T13:32:39.182Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2c/1d/4049a9e8698361cc1a1aa03a6c59e4fa4c71e0c0f94a30f988a6876a2ae6/opentelemetry_api-1.40.0.tar.gz", hash = "sha256:159be641c0b04d11e9ecd576906462773eb97ae1b657730f0ecf64d32071569f", size = 70851, upload-time = "2026-03-04T14:17:21.555Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cf/df/d3f1ddf4bb4cb50ed9b1139cc7b1c54c34a1e7ce8fd1b9a37c0d1551a6bd/opentelemetry_api-1.39.1-py3-none-any.whl", hash = "sha256:2edd8463432a7f8443edce90972169b195e7d6a05500cd29e6d13898187c9950", size = 66356, upload-time = "2025-12-11T13:32:17.304Z" }, + { url = "https://files.pythonhosted.org/packages/5f/bf/93795954016c522008da367da292adceed71cca6ee1717e1d64c83089099/opentelemetry_api-1.40.0-py3-none-any.whl", hash = "sha256:82dd69331ae74b06f6a874704be0cfaa49a1650e1537d4a813b86ecef7d0ecf9", size = 68676, upload-time = "2026-03-04T14:17:01.24Z" }, ] [[package]] name = "opentelemetry-exporter-otlp-proto-common" -version = "1.39.1" +version = "1.40.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-proto" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e9/9d/22d241b66f7bbde88a3bfa6847a351d2c46b84de23e71222c6aae25c7050/opentelemetry_exporter_otlp_proto_common-1.39.1.tar.gz", hash = "sha256:763370d4737a59741c89a67b50f9e39271639ee4afc999dadfe768541c027464", size = 20409, upload-time = "2025-12-11T13:32:40.885Z" } +sdist = { url = "https://files.pythonhosted.org/packages/51/bc/1559d46557fe6eca0b46c88d4c2676285f1f3be2e8d06bb5d15fbffc814a/opentelemetry_exporter_otlp_proto_common-1.40.0.tar.gz", hash = "sha256:1cbee86a4064790b362a86601ee7934f368b81cd4cc2f2e163902a6e7818a0fa", size = 20416, upload-time = "2026-03-04T14:17:23.801Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8c/02/ffc3e143d89a27ac21fd557365b98bd0653b98de8a101151d5805b5d4c33/opentelemetry_exporter_otlp_proto_common-1.39.1-py3-none-any.whl", hash = "sha256:08f8a5862d64cc3435105686d0216c1365dc5701f86844a8cd56597d0c764fde", size = 18366, upload-time = "2025-12-11T13:32:20.2Z" }, + { url = "https://files.pythonhosted.org/packages/8b/ca/8f122055c97a932311a3f640273f084e738008933503d0c2563cd5d591fc/opentelemetry_exporter_otlp_proto_common-1.40.0-py3-none-any.whl", hash = "sha256:7081ff453835a82417bf38dccf122c827c3cbc94f2079b03bba02a3165f25149", size = 18369, upload-time = "2026-03-04T14:17:04.796Z" }, ] [[package]] name = "opentelemetry-exporter-otlp-proto-http" -version = "1.39.1" +version = "1.40.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "googleapis-common-protos" }, @@ -1553,14 +1553,14 @@ dependencies = [ { name = "requests" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/80/04/2a08fa9c0214ae38880df01e8bfae12b067ec0793446578575e5080d6545/opentelemetry_exporter_otlp_proto_http-1.39.1.tar.gz", hash = "sha256:31bdab9745c709ce90a49a0624c2bd445d31a28ba34275951a6a362d16a0b9cb", size = 17288, upload-time = "2025-12-11T13:32:42.029Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2e/fa/73d50e2c15c56be4d000c98e24221d494674b0cc95524e2a8cb3856d95a4/opentelemetry_exporter_otlp_proto_http-1.40.0.tar.gz", hash = "sha256:db48f5e0f33217588bbc00274a31517ba830da576e59503507c839b38fa0869c", size = 17772, upload-time = "2026-03-04T14:17:25.324Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/95/f1/b27d3e2e003cd9a3592c43d099d2ed8d0a947c15281bf8463a256db0b46c/opentelemetry_exporter_otlp_proto_http-1.39.1-py3-none-any.whl", hash = "sha256:d9f5207183dd752a412c4cd564ca8875ececba13be6e9c6c370ffb752fd59985", size = 19641, upload-time = "2025-12-11T13:32:22.248Z" }, + { url = "https://files.pythonhosted.org/packages/a0/3a/8865d6754e61c9fb170cdd530a124a53769ee5f740236064816eb0ca7301/opentelemetry_exporter_otlp_proto_http-1.40.0-py3-none-any.whl", hash = "sha256:a8d1dab28f504c5d96577d6509f80a8150e44e8f45f82cdbe0e34c99ab040069", size = 19960, upload-time = "2026-03-04T14:17:07.153Z" }, ] [[package]] name = "opentelemetry-instrumentation" -version = "0.60b1" +version = "0.61b0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, @@ -1568,14 +1568,14 @@ dependencies = [ { name = "packaging" }, { name = "wrapt" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/41/0f/7e6b713ac117c1f5e4e3300748af699b9902a2e5e34c9cf443dde25a01fa/opentelemetry_instrumentation-0.60b1.tar.gz", hash = "sha256:57ddc7974c6eb35865af0426d1a17132b88b2ed8586897fee187fd5b8944bd6a", size = 31706, upload-time = "2025-12-11T13:36:42.515Z" } +sdist = { url = "https://files.pythonhosted.org/packages/da/37/6bf8e66bfcee5d3c6515b79cb2ee9ad05fe573c20f7ceb288d0e7eeec28c/opentelemetry_instrumentation-0.61b0.tar.gz", hash = "sha256:cb21b48db738c9de196eba6b805b4ff9de3b7f187e4bbf9a466fa170514f1fc7", size = 32606, upload-time = "2026-03-04T14:20:16.825Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/77/d2/6788e83c5c86a2690101681aeef27eeb2a6bf22df52d3f263a22cee20915/opentelemetry_instrumentation-0.60b1-py3-none-any.whl", hash = "sha256:04480db952b48fb1ed0073f822f0ee26012b7be7c3eac1a3793122737c78632d", size = 33096, upload-time = "2025-12-11T13:35:33.067Z" }, + { url = "https://files.pythonhosted.org/packages/d8/3e/f6f10f178b6316de67f0dfdbbb699a24fbe8917cf1743c1595fb9dcdd461/opentelemetry_instrumentation-0.61b0-py3-none-any.whl", hash = "sha256:92a93a280e69788e8f88391247cc530fd81f16f2b011979d4d6398f805cfbc63", size = 33448, upload-time = "2026-03-04T14:19:02.447Z" }, ] [[package]] name = "opentelemetry-instrumentation-asgi" -version = "0.60b1" +version = "0.61b0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "asgiref" }, @@ -1584,14 +1584,14 @@ dependencies = [ { name = "opentelemetry-semantic-conventions" }, { name = "opentelemetry-util-http" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/77/db/851fa88db7441da82d50bd80f2de5ee55213782e25dc858e04d0c9961d60/opentelemetry_instrumentation_asgi-0.60b1.tar.gz", hash = "sha256:16bfbe595cd24cda309a957456d0fc2523f41bc7b076d1f2d7e98a1ad9876d6f", size = 26107, upload-time = "2025-12-11T13:36:47.015Z" } +sdist = { url = "https://files.pythonhosted.org/packages/00/3e/143cf5c034e58037307e6a24f06e0dd64b2c49ae60a965fc580027581931/opentelemetry_instrumentation_asgi-0.61b0.tar.gz", hash = "sha256:9d08e127244361dc33976d39dd4ca8f128b5aa5a7ae425208400a80a095019b5", size = 26691, upload-time = "2026-03-04T14:20:21.038Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/76/76/1fb94367cef64420d2171157a6b9509582873bd09a6afe08a78a8d1f59d9/opentelemetry_instrumentation_asgi-0.60b1-py3-none-any.whl", hash = "sha256:d48def2dbed10294c99cfcf41ebbd0c414d390a11773a41f472d20000fcddc25", size = 16933, upload-time = "2025-12-11T13:35:40.462Z" }, + { url = "https://files.pythonhosted.org/packages/19/78/154470cf9d741a7487fbb5067357b87386475bbb77948a6707cae982e158/opentelemetry_instrumentation_asgi-0.61b0-py3-none-any.whl", hash = "sha256:e4b3ce6b66074e525e717efff20745434e5efd5d9df6557710856fba356da7a4", size = 16980, upload-time = "2026-03-04T14:19:10.894Z" }, ] [[package]] name = "opentelemetry-instrumentation-fastapi" -version = "0.60b1" +version = "0.61b0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, @@ -1600,14 +1600,14 @@ dependencies = [ { name = "opentelemetry-semantic-conventions" }, { name = "opentelemetry-util-http" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9c/e7/e7e5e50218cf488377209d85666b182fa2d4928bf52389411ceeee1b2b60/opentelemetry_instrumentation_fastapi-0.60b1.tar.gz", hash = "sha256:de608955f7ff8eecf35d056578346a5365015fd7d8623df9b1f08d1c74769c01", size = 24958, upload-time = "2025-12-11T13:36:59.35Z" } +sdist = { url = "https://files.pythonhosted.org/packages/37/35/aa727bb6e6ef930dcdc96a617b83748fece57b43c47d83ba8d83fbeca657/opentelemetry_instrumentation_fastapi-0.61b0.tar.gz", hash = "sha256:3a24f35b07c557ae1bbc483bf8412221f25d79a405f8b047de8b670722e2fa9f", size = 24800, upload-time = "2026-03-04T14:20:32.759Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7d/cc/6e808328ba54662e50babdcab21138eae4250bc0fddf67d55526a615a2ca/opentelemetry_instrumentation_fastapi-0.60b1-py3-none-any.whl", hash = "sha256:af94b7a239ad1085fc3a820ecf069f67f579d7faf4c085aaa7bd9b64eafc8eaf", size = 13478, upload-time = "2025-12-11T13:36:00.811Z" }, + { url = "https://files.pythonhosted.org/packages/91/05/acfeb2cccd434242a0a7d0ea29afaf077e04b42b35b485d89aee4e0d9340/opentelemetry_instrumentation_fastapi-0.61b0-py3-none-any.whl", hash = "sha256:a1a844d846540d687d377516b2ff698b51d87c781b59f47c214359c4a241047c", size = 13485, upload-time = "2026-03-04T14:19:30.351Z" }, ] [[package]] name = "opentelemetry-instrumentation-httpx" -version = "0.60b1" +version = "0.61b0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, @@ -1616,14 +1616,14 @@ dependencies = [ { name = "opentelemetry-util-http" }, { name = "wrapt" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/86/08/11208bcfcab4fc2023252c3f322aa397fd9ad948355fea60f5fc98648603/opentelemetry_instrumentation_httpx-0.60b1.tar.gz", hash = "sha256:a506ebaf28c60112cbe70ad4f0338f8603f148938cb7b6794ce1051cd2b270ae", size = 20611, upload-time = "2025-12-11T13:37:01.661Z" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/2a/e2becd55e33c29d1d9ef76e2579040ed1951cb33bacba259f6aff2fdd2a6/opentelemetry_instrumentation_httpx-0.61b0.tar.gz", hash = "sha256:6569ec097946c5551c2a4252f74c98666addd1bf047c1dde6b4ef426719ff8dd", size = 24104, upload-time = "2026-03-04T14:20:34.752Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/43/59/b98e84eebf745ffc75397eaad4763795bff8a30cbf2373a50ed4e70646c5/opentelemetry_instrumentation_httpx-0.60b1-py3-none-any.whl", hash = "sha256:f37636dd742ad2af83d896ba69601ed28da51fa4e25d1ab62fde89ce413e275b", size = 15701, upload-time = "2025-12-11T13:36:04.56Z" }, + { url = "https://files.pythonhosted.org/packages/af/88/dde310dce56e2d85cf1a09507f5888544955309edc4b8d22971d6d3d1417/opentelemetry_instrumentation_httpx-0.61b0-py3-none-any.whl", hash = "sha256:dee05c93a6593a5dc3ae5d9d5c01df8b4e2c5d02e49275e5558534ee46343d5e", size = 17198, upload-time = "2026-03-04T14:19:33.585Z" }, ] [[package]] name = "opentelemetry-instrumentation-openai" -version = "0.52.6" +version = "0.53.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, @@ -1631,14 +1631,14 @@ dependencies = [ { name = "opentelemetry-semantic-conventions" }, { name = "opentelemetry-semantic-conventions-ai" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/37/86/1fe5008f3714118fdc1024cd141140a5f204d5ac7016e87a0f07a834efb2/opentelemetry_instrumentation_openai-0.52.6.tar.gz", hash = "sha256:0eb23dc90804a726e516fcbd649cb99f10dfdb5e31d29e44c4b1b8f402dd905d", size = 6978397, upload-time = "2026-02-26T15:40:17.154Z" } +sdist = { url = "https://files.pythonhosted.org/packages/10/b7/b3b5536671658001c62c117fa834df2a3bd524e950a7773d53b71fca3219/opentelemetry_instrumentation_openai-0.53.0.tar.gz", hash = "sha256:c0cd83d223d138309af3cc5f53c9c6d22136374bfa00e8f66dff31cd322ef547", size = 6978375, upload-time = "2026-03-04T07:49:18.112Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/4a/4623d0adc0187cc45bce631f891c30cd01cf2562d37b918b79561200d985/opentelemetry_instrumentation_openai-0.52.6-py3-none-any.whl", hash = "sha256:5e174388520f294f648f9732471c1b9919c71e5d09649a64ab8ff81714c1278b", size = 43084, upload-time = "2026-02-26T15:39:35.584Z" }, + { url = "https://files.pythonhosted.org/packages/44/3b/58ac94d0f56afb3c0352d3e6d35ea9de6331292a7316403ea97de4c6d915/opentelemetry_instrumentation_openai-0.53.0-py3-none-any.whl", hash = "sha256:91d9f69673636f5f7d50e5a4782e4526d6df3a1ddfd6ac2d9e15a957f8fd9ad8", size = 43084, upload-time = "2026-03-04T07:48:43.676Z" }, ] [[package]] name = "opentelemetry-instrumentation-sqlalchemy" -version = "0.60b1" +version = "0.61b0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, @@ -1647,48 +1647,48 @@ dependencies = [ { name = "packaging" }, { name = "wrapt" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/92/16/6a4cbff1b7cd86d1e58ffd100255f6da781a88f4a2affdcc3721880191c9/opentelemetry_instrumentation_sqlalchemy-0.60b1.tar.gz", hash = "sha256:b614e874a7c0a692838a0da613d1654e81a0612867836a1f0765e40e9c8cc49b", size = 15317, upload-time = "2025-12-11T13:37:13.089Z" } +sdist = { url = "https://files.pythonhosted.org/packages/9e/4f/3a325b180944610697a0a926d49d782b41a86120050d44fefb2715b630ac/opentelemetry_instrumentation_sqlalchemy-0.61b0.tar.gz", hash = "sha256:13a3a159a2043a52f0180b3757fbaa26741b0e08abb50deddce4394c118956e6", size = 15343, upload-time = "2026-03-04T14:20:47.648Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d0/b7/2234bc761c197c7f099f30cad5d50efd8286c59b5b8f45cfd6ba6ebe7d5e/opentelemetry_instrumentation_sqlalchemy-0.60b1-py3-none-any.whl", hash = "sha256:486a5f264d264c44e07e0320e33fd19d09cecd2fd4b99c1064046e77a27d9f9f", size = 14529, upload-time = "2025-12-11T13:36:24.964Z" }, + { url = "https://files.pythonhosted.org/packages/1f/97/b906a930c6a1a20c53ecc8b58cabc2cdd0ce560a2b5d44259084ffe4333e/opentelemetry_instrumentation_sqlalchemy-0.61b0-py3-none-any.whl", hash = "sha256:f115e0be54116ba4c327b8d7b68db4045ee18d44439d888ab8130a549c50d1c1", size = 14547, upload-time = "2026-03-04T14:19:53.088Z" }, ] [[package]] name = "opentelemetry-proto" -version = "1.39.1" +version = "1.40.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/49/1d/f25d76d8260c156c40c97c9ed4511ec0f9ce353f8108ca6e7561f82a06b2/opentelemetry_proto-1.39.1.tar.gz", hash = "sha256:6c8e05144fc0d3ed4d22c2289c6b126e03bcd0e6a7da0f16cedd2e1c2772e2c8", size = 46152, upload-time = "2025-12-11T13:32:48.681Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4c/77/dd38991db037fdfce45849491cb61de5ab000f49824a00230afb112a4392/opentelemetry_proto-1.40.0.tar.gz", hash = "sha256:03f639ca129ba513f5819810f5b1f42bcb371391405d99c168fe6937c62febcd", size = 45667, upload-time = "2026-03-04T14:17:31.194Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/51/95/b40c96a7b5203005a0b03d8ce8cd212ff23f1793d5ba289c87a097571b18/opentelemetry_proto-1.39.1-py3-none-any.whl", hash = "sha256:22cdc78efd3b3765d09e68bfbd010d4fc254c9818afd0b6b423387d9dee46007", size = 72535, upload-time = "2025-12-11T13:32:33.866Z" }, + { url = "https://files.pythonhosted.org/packages/b9/b2/189b2577dde745b15625b3214302605b1353436219d42b7912e77fa8dc24/opentelemetry_proto-1.40.0-py3-none-any.whl", hash = "sha256:266c4385d88923a23d63e353e9761af0f47a6ed0d486979777fe4de59dc9b25f", size = 72073, upload-time = "2026-03-04T14:17:16.673Z" }, ] [[package]] name = "opentelemetry-sdk" -version = "1.39.1" +version = "1.40.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, { name = "opentelemetry-semantic-conventions" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/eb/fb/c76080c9ba07e1e8235d24cdcc4d125ef7aa3edf23eb4e497c2e50889adc/opentelemetry_sdk-1.39.1.tar.gz", hash = "sha256:cf4d4563caf7bff906c9f7967e2be22d0d6b349b908be0d90fb21c8e9c995cc6", size = 171460, upload-time = "2025-12-11T13:32:49.369Z" } +sdist = { url = "https://files.pythonhosted.org/packages/58/fd/3c3125b20ba18ce2155ba9ea74acb0ae5d25f8cd39cfd37455601b7955cc/opentelemetry_sdk-1.40.0.tar.gz", hash = "sha256:18e9f5ec20d859d268c7cb3c5198c8d105d073714db3de50b593b8c1345a48f2", size = 184252, upload-time = "2026-03-04T14:17:31.87Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7c/98/e91cf858f203d86f4eccdf763dcf01cf03f1dae80c3750f7e635bfa206b6/opentelemetry_sdk-1.39.1-py3-none-any.whl", hash = "sha256:4d5482c478513ecb0a5d938dcc61394e647066e0cc2676bee9f3af3f3f45f01c", size = 132565, upload-time = "2025-12-11T13:32:35.069Z" }, + { url = "https://files.pythonhosted.org/packages/2c/c5/6a852903d8bfac758c6dc6e9a68b015d3c33f2f1be5e9591e0f4b69c7e0a/opentelemetry_sdk-1.40.0-py3-none-any.whl", hash = "sha256:787d2154a71f4b3d81f20524a8ce061b7db667d24e46753f32a7bc48f1c1f3f1", size = 141951, upload-time = "2026-03-04T14:17:17.961Z" }, ] [[package]] name = "opentelemetry-semantic-conventions" -version = "0.60b1" +version = "0.61b0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/91/df/553f93ed38bf22f4b999d9be9c185adb558982214f33eae539d3b5cd0858/opentelemetry_semantic_conventions-0.60b1.tar.gz", hash = "sha256:87c228b5a0669b748c76d76df6c364c369c28f1c465e50f661e39737e84bc953", size = 137935, upload-time = "2025-12-11T13:32:50.487Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6d/c0/4ae7973f3c2cfd2b6e321f1675626f0dab0a97027cc7a297474c9c8f3d04/opentelemetry_semantic_conventions-0.61b0.tar.gz", hash = "sha256:072f65473c5d7c6dc0355b27d6c9d1a679d63b6d4b4b16a9773062cb7e31192a", size = 145755, upload-time = "2026-03-04T14:17:32.664Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7a/5e/5958555e09635d09b75de3c4f8b9cae7335ca545d77392ffe7331534c402/opentelemetry_semantic_conventions-0.60b1-py3-none-any.whl", hash = "sha256:9fa8c8b0c110da289809292b0591220d3a7b53c1526a23021e977d68597893fb", size = 219982, upload-time = "2025-12-11T13:32:36.955Z" }, + { url = "https://files.pythonhosted.org/packages/b2/37/cc6a55e448deaa9b27377d087da8615a3416d8ad523d5960b78dbeadd02a/opentelemetry_semantic_conventions-0.61b0-py3-none-any.whl", hash = "sha256:fa530a96be229795f8cef353739b618148b0fe2b4b3f005e60e262926c4d38e2", size = 231621, upload-time = "2026-03-04T14:17:19.33Z" }, ] [[package]] @@ -1706,11 +1706,11 @@ wheels = [ [[package]] name = "opentelemetry-util-http" -version = "0.60b1" +version = "0.61b0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/50/fc/c47bb04a1d8a941a4061307e1eddfa331ed4d0ab13d8a9781e6db256940a/opentelemetry_util_http-0.60b1.tar.gz", hash = "sha256:0d97152ca8c8a41ced7172d29d3622a219317f74ae6bb3027cfbdcf22c3cc0d6", size = 11053, upload-time = "2025-12-11T13:37:25.115Z" } +sdist = { url = "https://files.pythonhosted.org/packages/57/3c/f0196223efc5c4ca19f8fad3d5462b171ac6333013335ce540c01af419e9/opentelemetry_util_http-0.61b0.tar.gz", hash = "sha256:1039cb891334ad2731affdf034d8fb8b48c239af9b6dd295e5fabd07f1c95572", size = 11361, upload-time = "2026-03-04T14:20:57.01Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/16/5c/d3f1733665f7cd582ef0842fb1d2ed0bc1fba10875160593342d22bba375/opentelemetry_util_http-0.60b1-py3-none-any.whl", hash = "sha256:66381ba28550c91bee14dcba8979ace443444af1ed609226634596b4b0faf199", size = 8947, upload-time = "2025-12-11T13:36:37.151Z" }, + { url = "https://files.pythonhosted.org/packages/0d/e5/c08aaaf2f64288d2b6ef65741d2de5454e64af3e050f34285fb1907492fe/opentelemetry_util_http-0.61b0-py3-none-any.whl", hash = "sha256:8e715e848233e9527ea47e275659ea60a57a75edf5206a3b937e236a6da5fc33", size = 9281, upload-time = "2026-03-04T14:20:08.364Z" }, ] [[package]] @@ -2113,18 +2113,18 @@ wheels = [ [[package]] name = "pyrefly" -version = "0.54.0" +version = "0.55.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/81/44/c10b16a302fda90d0af1328f880b232761b510eab546616a7be2fdf35a57/pyrefly-0.54.0.tar.gz", hash = "sha256:c6663be64d492f0d2f2a411ada9f28a6792163d34133639378b7f3dd9a8dca94", size = 5098893, upload-time = "2026-02-23T15:44:35.111Z" } +sdist = { url = "https://files.pythonhosted.org/packages/bf/c4/76e0797215e62d007f81f86c9c4fb5d6202685a3f5e70810f3fd94294f92/pyrefly-0.55.0.tar.gz", hash = "sha256:434c3282532dd4525c4840f2040ed0eb79b0ec8224fe18d957956b15471f2441", size = 5135682, upload-time = "2026-03-03T00:46:38.122Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5f/99/8fdcdb4e55f0227fdd9f6abce36b619bab1ecb0662b83b66adc8cba3c788/pyrefly-0.54.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:58a3f092b6dc25ef79b2dc6c69a40f36784ca157c312bfc0baea463926a9db6d", size = 12223973, upload-time = "2026-02-23T15:44:14.278Z" }, - { url = "https://files.pythonhosted.org/packages/90/35/c2aaf87a76003ad27b286594d2e5178f811eaa15bfe3d98dba2b47d56dd1/pyrefly-0.54.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:615081414106dd95873bc39c3a4bed68754c6cc24a8177ac51d22f88f88d3eb3", size = 11785585, upload-time = "2026-02-23T15:44:17.468Z" }, - { url = "https://files.pythonhosted.org/packages/c4/4a/ced02691ed67e5a897714979196f08ad279ec7ec7f63c45e00a75a7f3c0e/pyrefly-0.54.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cbcaf20f5fe585079079a95205c1f3cd4542d17228cdf1df560288880623b70", size = 33381977, upload-time = "2026-02-23T15:44:19.736Z" }, - { url = "https://files.pythonhosted.org/packages/0b/ce/72a117ed437c8f6950862181014b41e36f3c3997580e29b772b71e78d587/pyrefly-0.54.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66d5da116c0d34acfbd66663addd3ca8aa78a636f6692a66e078126d3620a883", size = 35962821, upload-time = "2026-02-23T15:44:22.357Z" }, - { url = "https://files.pythonhosted.org/packages/85/de/89013f5ae0a35d2b6b01274a92a35ee91431ea001050edf0a16748d39875/pyrefly-0.54.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ef3ac27f1a4baaf67aead64287d3163350844794aca6315ad1a9650b16ec26a", size = 38496689, upload-time = "2026-02-23T15:44:25.236Z" }, - { url = "https://files.pythonhosted.org/packages/9f/9a/33b097c7bf498b924742dca32dd5d9c6a3fa6c2b52b63a58eb9e1980ca89/pyrefly-0.54.0-py3-none-win32.whl", hash = "sha256:7d607d72200a8afbd2db10bfefb40160a7a5d709d207161c21649cedd5cfc09a", size = 11295268, upload-time = "2026-02-23T15:44:27.551Z" }, - { url = "https://files.pythonhosted.org/packages/d4/21/9263fd1144d2a3d7342b474f183f7785b3358a1565c864089b780110b933/pyrefly-0.54.0-py3-none-win_amd64.whl", hash = "sha256:fd416f04f89309385696f685bd5c9141011f18c8072f84d31ca20c748546e791", size = 12081810, upload-time = "2026-02-23T15:44:29.461Z" }, - { url = "https://files.pythonhosted.org/packages/ea/5b/fad062a196c064cbc8564de5b2f4d3cb6315f852e3b31e8a1ce74c69a1ea/pyrefly-0.54.0-py3-none-win_arm64.whl", hash = "sha256:f06ab371356c7b1925e0bffe193b738797e71e5dbbff7fb5a13f90ee7521211d", size = 11564930, upload-time = "2026-02-23T15:44:33.053Z" }, + { url = "https://files.pythonhosted.org/packages/39/b0/16e50cf716784513648e23e726a24f71f9544aa4f86103032dcaa5ff71a2/pyrefly-0.55.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:49aafcefe5e2dd4256147db93e5b0ada42bff7d9a60db70e03d1f7055338eec9", size = 12210073, upload-time = "2026-03-03T00:46:15.51Z" }, + { url = "https://files.pythonhosted.org/packages/3a/ad/89500c01bac3083383011600370289fbc67700c5be46e781787392628a3a/pyrefly-0.55.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:2827426e6b28397c13badb93c0ede0fb0f48046a7a89e3d774cda04e8e2067cd", size = 11767474, upload-time = "2026-03-03T00:46:18.003Z" }, + { url = "https://files.pythonhosted.org/packages/78/68/4c66b260f817f304ead11176ff13985625f7c269e653304b4bdb546551af/pyrefly-0.55.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7346b2d64dc575bd61aa3bca854fbf8b5a19a471cbdb45e0ca1e09861b63488c", size = 33260395, upload-time = "2026-03-03T00:46:20.509Z" }, + { url = "https://files.pythonhosted.org/packages/47/09/10bd48c9f860064f29f412954126a827d60f6451512224912c265e26bbe6/pyrefly-0.55.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:233b861b4cff008b1aff62f4f941577ed752e4d0060834229eb9b6826e6973c9", size = 35848269, upload-time = "2026-03-03T00:46:23.418Z" }, + { url = "https://files.pythonhosted.org/packages/a9/39/bc65cdd5243eb2dfea25dd1321f9a5a93e8d9c3a308501c4c6c05d011585/pyrefly-0.55.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5aa85657d76da1d25d081a49f0e33c8fc3ec91c1a0f185a8ed393a5a3d9e178", size = 38449820, upload-time = "2026-03-03T00:46:26.309Z" }, + { url = "https://files.pythonhosted.org/packages/e5/64/58b38963b011af91209e87f868cc85cfc762ec49a4568ce610c45e7a5f40/pyrefly-0.55.0-py3-none-win32.whl", hash = "sha256:23f786a78536a56fed331b245b7d10ec8945bebee7b723491c8d66fdbc155fe6", size = 11259415, upload-time = "2026-03-03T00:46:30.875Z" }, + { url = "https://files.pythonhosted.org/packages/7a/0b/a4aa519ff632a1ea69eec942566951670b870b99b5c08407e1387b85b6a4/pyrefly-0.55.0-py3-none-win_amd64.whl", hash = "sha256:d465b49e999b50eeb069ad23f0f5710651cad2576f9452a82991bef557df91ee", size = 12043581, upload-time = "2026-03-03T00:46:33.674Z" }, + { url = "https://files.pythonhosted.org/packages/f1/51/89017636fbe1ffd166ad478990c6052df615b926182fa6d3c0842b407e89/pyrefly-0.55.0-py3-none-win_arm64.whl", hash = "sha256:732ff490e0e863b296e7c0b2471e08f8ba7952f9fa6e9de09d8347fd67dde77f", size = 11548076, upload-time = "2026-03-03T00:46:36.193Z" }, ] [[package]] @@ -2263,11 +2263,11 @@ wheels = [ [[package]] name = "pytz" -version = "2025.2" +version = "2026.1.post1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", size = 320884, upload-time = "2025-03-25T02:25:00.538Z" } +sdist = { url = "https://files.pythonhosted.org/packages/56/db/b8721d71d945e6a8ac63c0fc900b2067181dbb50805958d4d4661cf7d277/pytz-2026.1.post1.tar.gz", hash = "sha256:3378dde6a0c3d26719182142c56e60c7f9af7e968076f31aae569d72a0358ee1", size = 321088, upload-time = "2026-03-03T07:47:50.683Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225, upload-time = "2025-03-25T02:24:58.468Z" }, + { url = "https://files.pythonhosted.org/packages/10/99/781fe0c827be2742bcc775efefccb3b048a3a9c6ce9aec0cbf4a101677e5/pytz-2026.1.post1-py2.py3-none-any.whl", hash = "sha256:f2fd16142fda348286a75e1a524be810bb05d444e5a081f37f7affc635035f7a", size = 510489, upload-time = "2026-03-03T07:47:49.167Z" }, ] [[package]] @@ -2512,15 +2512,15 @@ wheels = [ [[package]] name = "sentry-sdk" -version = "2.53.0" +version = "2.54.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d3/06/66c8b705179bc54087845f28fd1b72f83751b6e9a195628e2e9af9926505/sentry_sdk-2.53.0.tar.gz", hash = "sha256:6520ef2c4acd823f28efc55e43eb6ce2e6d9f954a95a3aa96b6fd14871e92b77", size = 412369, upload-time = "2026-02-16T11:11:14.743Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c8/e9/2e3a46c304e7fa21eaa70612f60354e32699c7102eb961f67448e222ad7c/sentry_sdk-2.54.0.tar.gz", hash = "sha256:2620c2575128d009b11b20f7feb81e4e4e8ae08ec1d36cbc845705060b45cc1b", size = 413813, upload-time = "2026-03-02T15:12:41.355Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/47/d4/2fdf854bc3b9c7f55219678f812600a20a138af2dd847d99004994eada8f/sentry_sdk-2.53.0-py2.py3-none-any.whl", hash = "sha256:46e1ed8d84355ae54406c924f6b290c3d61f4048625989a723fd622aab838899", size = 437908, upload-time = "2026-02-16T11:11:13.227Z" }, + { url = "https://files.pythonhosted.org/packages/53/39/be412cc86bc6247b8f69e9383d7950711bd86f8d0a4a4b0fe8fad685bc21/sentry_sdk-2.54.0-py2.py3-none-any.whl", hash = "sha256:fd74e0e281dcda63afff095d23ebcd6e97006102cdc8e78a29f19ecdf796a0de", size = 439198, upload-time = "2026-03-02T15:12:39.546Z" }, ] [[package]] @@ -2552,28 +2552,28 @@ wheels = [ [[package]] name = "sqlalchemy" -version = "2.0.47" +version = "2.0.48" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "greenlet", marker = "platform_machine == 'AMD64' or platform_machine == 'WIN32' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'ppc64le' or platform_machine == 'win32' or platform_machine == 'x86_64'" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/cd/4b/1e00561093fe2cd8eef09d406da003c8a118ff02d6548498c1ae677d68d9/sqlalchemy-2.0.47.tar.gz", hash = "sha256:e3e7feb57b267fe897e492b9721ae46d5c7de6f9e8dee58aacf105dc4e154f3d", size = 9886323, upload-time = "2026-02-24T16:34:27.947Z" } +sdist = { url = "https://files.pythonhosted.org/packages/1f/73/b4a9737255583b5fa858e0bb8e116eb94b88c910164ed2ed719147bde3de/sqlalchemy-2.0.48.tar.gz", hash = "sha256:5ca74f37f3369b45e1f6b7b06afb182af1fd5dde009e4ffd831830d98cbe5fe7", size = 9886075, upload-time = "2026-03-02T15:28:51.474Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c1/30/98243209aae58ed80e090ea988d5182244ca7ab3ff59e6d850c3dfc7651e/sqlalchemy-2.0.47-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:b03010a5a5dfe71676bc83f2473ebe082478e32d77e6f082c8fe15a31c3b42a6", size = 2154355, upload-time = "2026-02-24T17:05:48.959Z" }, - { url = "https://files.pythonhosted.org/packages/ab/62/12ca6ea92055fe486d6558a2a4efe93e194ff597463849c01f88e5adb99d/sqlalchemy-2.0.47-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f8e3371aa9024520883a415a09cc20c33cfd3eeccf9e0f4f4c367f940b9cbd44", size = 3274486, upload-time = "2026-02-24T17:18:13.659Z" }, - { url = "https://files.pythonhosted.org/packages/97/88/7dfbdeaa8d42b1584e65d6cc713e9d33b6fa563e0d546d5cb87e545bb0e5/sqlalchemy-2.0.47-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c9449f747e50d518c6e1b40cc379e48bfc796453c47b15e627ea901c201e48a6", size = 3279481, upload-time = "2026-02-24T17:27:26.491Z" }, - { url = "https://files.pythonhosted.org/packages/d0/b7/75e1c1970616a9dd64a8a6fd788248da2ddaf81c95f4875f2a1e8aee4128/sqlalchemy-2.0.47-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:21410f60d5cac1d6bfe360e05bd91b179be4fa0aa6eea6be46054971d277608f", size = 3224269, upload-time = "2026-02-24T17:18:15.078Z" }, - { url = "https://files.pythonhosted.org/packages/31/ac/eec1a13b891df9a8bc203334caf6e6aac60b02f61b018ef3b4124b8c4120/sqlalchemy-2.0.47-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:819841dd5bb4324c284c09e2874cf96fe6338bfb57a64548d9b81a4e39c9871f", size = 3246262, upload-time = "2026-02-24T17:27:27.986Z" }, - { url = "https://files.pythonhosted.org/packages/c9/b0/661b0245b06421058610da39f8ceb34abcc90b49f90f256380968d761dbe/sqlalchemy-2.0.47-cp314-cp314-win32.whl", hash = "sha256:e255ee44821a7ef45649c43064cf94e74f81f61b4df70547304b97a351e9b7db", size = 2116528, upload-time = "2026-02-24T17:22:59.363Z" }, - { url = "https://files.pythonhosted.org/packages/aa/ef/1035a90d899e61810791c052004958be622a2cf3eb3df71c3fe20778c5d0/sqlalchemy-2.0.47-cp314-cp314-win_amd64.whl", hash = "sha256:209467ff73ea1518fe1a5aaed9ba75bb9e33b2666e2553af9ccd13387bf192cb", size = 2142181, upload-time = "2026-02-24T17:23:01.001Z" }, - { url = "https://files.pythonhosted.org/packages/76/bb/17a1dd09cbba91258218ceb582225f14b5364d2683f9f5a274f72f2d764f/sqlalchemy-2.0.47-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e78fd9186946afaa287f8a1fe147ead06e5d566b08c0afcb601226e9c7322a64", size = 3563477, upload-time = "2026-02-24T17:12:18.46Z" }, - { url = "https://files.pythonhosted.org/packages/66/8f/1a03d24c40cc321ef2f2231f05420d140bb06a84f7047eaa7eaa21d230ba/sqlalchemy-2.0.47-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5740e2f31b5987ed9619d6912ae5b750c03637f2078850da3002934c9532f172", size = 3528568, upload-time = "2026-02-24T17:28:03.732Z" }, - { url = "https://files.pythonhosted.org/packages/fd/53/d56a213055d6b038a5384f0db5ece7343334aca230ff3f0fa1561106f22c/sqlalchemy-2.0.47-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:fb9ac00d03de93acb210e8ec7243fefe3e012515bf5fd2f0898c8dff38bc77a4", size = 3472284, upload-time = "2026-02-24T17:12:20.319Z" }, - { url = "https://files.pythonhosted.org/packages/ff/19/c235d81b9cfdd6130bf63143b7bade0dc4afa46c4b634d5d6b2a96bea233/sqlalchemy-2.0.47-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c72a0b9eb2672d70d112cb149fbaf172d466bc691014c496aaac594f1988e706", size = 3478410, upload-time = "2026-02-24T17:28:05.892Z" }, - { url = "https://files.pythonhosted.org/packages/0e/db/cafdeca5ecdaa3bb0811ba5449501da677ce0d83be8d05c5822da72d2e86/sqlalchemy-2.0.47-cp314-cp314t-win32.whl", hash = "sha256:c200db1128d72a71dc3c31c24b42eb9fd85b2b3e5a3c9ba1e751c11ac31250ff", size = 2147164, upload-time = "2026-02-24T17:14:40.783Z" }, - { url = "https://files.pythonhosted.org/packages/fc/5e/ff41a010e9e0f76418b02ad352060a4341bb15f0af66cedc924ab376c7c6/sqlalchemy-2.0.47-cp314-cp314t-win_amd64.whl", hash = "sha256:669837759b84e575407355dcff912835892058aea9b80bd1cb76d6a151cf37f7", size = 2182154, upload-time = "2026-02-24T17:14:43.205Z" }, - { url = "https://files.pythonhosted.org/packages/15/9f/7c378406b592fcf1fc157248607b495a40e3202ba4a6f1372a2ba6447717/sqlalchemy-2.0.47-py3-none-any.whl", hash = "sha256:e2647043599297a1ef10e720cf310846b7f31b6c841fee093d2b09d81215eb93", size = 1940159, upload-time = "2026-02-24T17:15:07.158Z" }, + { url = "https://files.pythonhosted.org/packages/f7/b3/f437eaa1cf028bb3c927172c7272366393e73ccd104dcf5b6963f4ab5318/sqlalchemy-2.0.48-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:e2d0d88686e3d35a76f3e15a34e8c12d73fc94c1dea1cd55782e695cc14086dd", size = 2154401, upload-time = "2026-03-02T15:49:17.24Z" }, + { url = "https://files.pythonhosted.org/packages/6c/1c/b3abdf0f402aa3f60f0df6ea53d92a162b458fca2321d8f1f00278506402/sqlalchemy-2.0.48-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:49b7bddc1eebf011ea5ab722fdbe67a401caa34a350d278cc7733c0e88fecb1f", size = 3274528, upload-time = "2026-03-02T15:50:41.489Z" }, + { url = "https://files.pythonhosted.org/packages/f2/5e/327428a034407651a048f5e624361adf3f9fbac9d0fa98e981e9c6ff2f5e/sqlalchemy-2.0.48-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:426c5ca86415d9b8945c7073597e10de9644802e2ff502b8e1f11a7a2642856b", size = 3279523, upload-time = "2026-03-02T15:53:32.962Z" }, + { url = "https://files.pythonhosted.org/packages/2a/ca/ece73c81a918add0965b76b868b7b5359e068380b90ef1656ee995940c02/sqlalchemy-2.0.48-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:288937433bd44e3990e7da2402fabc44a3c6c25d3704da066b85b89a85474ae0", size = 3224312, upload-time = "2026-03-02T15:50:42.996Z" }, + { url = "https://files.pythonhosted.org/packages/88/11/fbaf1ae91fa4ee43f4fe79661cead6358644824419c26adb004941bdce7c/sqlalchemy-2.0.48-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:8183dc57ae7d9edc1346e007e840a9f3d6aa7b7f165203a99e16f447150140d2", size = 3246304, upload-time = "2026-03-02T15:53:34.937Z" }, + { url = "https://files.pythonhosted.org/packages/fa/a8/5fb0deb13930b4f2f698c5541ae076c18981173e27dd00376dbaea7a9c82/sqlalchemy-2.0.48-cp314-cp314-win32.whl", hash = "sha256:1182437cb2d97988cfea04cf6cdc0b0bb9c74f4d56ec3d08b81e23d621a28cc6", size = 2116565, upload-time = "2026-03-02T15:54:38.321Z" }, + { url = "https://files.pythonhosted.org/packages/95/7e/e83615cb63f80047f18e61e31e8e32257d39458426c23006deeaf48f463b/sqlalchemy-2.0.48-cp314-cp314-win_amd64.whl", hash = "sha256:144921da96c08feb9e2b052c5c5c1d0d151a292c6135623c6b2c041f2a45f9e0", size = 2142205, upload-time = "2026-03-02T15:54:39.831Z" }, + { url = "https://files.pythonhosted.org/packages/83/e3/69d8711b3f2c5135e9cde5f063bc1605860f0b2c53086d40c04017eb1f77/sqlalchemy-2.0.48-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5aee45fd2c6c0f2b9cdddf48c48535e7471e42d6fb81adfde801da0bd5b93241", size = 3563519, upload-time = "2026-03-02T15:57:52.387Z" }, + { url = "https://files.pythonhosted.org/packages/f8/4f/a7cce98facca73c149ea4578981594aaa5fd841e956834931de503359336/sqlalchemy-2.0.48-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7cddca31edf8b0653090cbb54562ca027c421c58ddde2c0685f49ff56a1690e0", size = 3528611, upload-time = "2026-03-02T16:04:42.097Z" }, + { url = "https://files.pythonhosted.org/packages/cd/7d/5936c7a03a0b0cb0fa0cc425998821c6029756b0855a8f7ee70fba1de955/sqlalchemy-2.0.48-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7a936f1bb23d370b7c8cc079d5fce4c7d18da87a33c6744e51a93b0f9e97e9b3", size = 3472326, upload-time = "2026-03-02T15:57:54.423Z" }, + { url = "https://files.pythonhosted.org/packages/f4/33/cea7dfc31b52904efe3dcdc169eb4514078887dff1f5ae28a7f4c5d54b3c/sqlalchemy-2.0.48-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e004aa9248e8cb0a5f9b96d003ca7c1c0a5da8decd1066e7b53f59eb8ce7c62b", size = 3478453, upload-time = "2026-03-02T16:04:44.584Z" }, + { url = "https://files.pythonhosted.org/packages/c8/95/32107c4d13be077a9cae61e9ae49966a35dc4bf442a8852dd871db31f62e/sqlalchemy-2.0.48-cp314-cp314t-win32.whl", hash = "sha256:b8438ec5594980d405251451c5b7ea9aa58dda38eb7ac35fb7e4c696712ee24f", size = 2147209, upload-time = "2026-03-02T15:52:54.274Z" }, + { url = "https://files.pythonhosted.org/packages/d2/d7/1e073da7a4bc645eb83c76067284a0374e643bc4be57f14cc6414656f92c/sqlalchemy-2.0.48-cp314-cp314t-win_amd64.whl", hash = "sha256:d854b3970067297f3a7fbd7a4683587134aa9b3877ee15aa29eea478dc68f933", size = 2182198, upload-time = "2026-03-02T15:52:55.606Z" }, + { url = "https://files.pythonhosted.org/packages/46/2c/9664130905f03db57961b8980b05cab624afd114bf2be2576628a9f22da4/sqlalchemy-2.0.48-py3-none-any.whl", hash = "sha256:a66fe406437dd65cacd96a72689a3aaaecaebbcd62d81c5ac1c0fdbeac835096", size = 1940202, upload-time = "2026-03-02T15:52:43.285Z" }, ] [package.optional-dependencies] @@ -2626,11 +2626,11 @@ wheels = [ [[package]] name = "tabulate" -version = "0.9.0" +version = "0.10.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ec/fe/802052aecb21e3797b8f7902564ab6ea0d60ff8ca23952079064155d1ae1/tabulate-0.9.0.tar.gz", hash = "sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c", size = 81090, upload-time = "2022-10-06T17:21:48.54Z" } +sdist = { url = "https://files.pythonhosted.org/packages/46/58/8c37dea7bbf769b20d58e7ace7e5edfe65b849442b00ffcdd56be88697c6/tabulate-0.10.0.tar.gz", hash = "sha256:e2cfde8f79420f6deeffdeda9aaec3b6bc5abce947655d17ac662b126e48a60d", size = 91754, upload-time = "2026-03-04T18:55:34.402Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/40/44/4a5f08c96eb108af5cb50b41f76142f0afa346dfa99d5296fe7202a11854/tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f", size = 35252, upload-time = "2022-10-06T17:21:44.262Z" }, + { url = "https://files.pythonhosted.org/packages/99/55/db07de81b5c630da5cbf5c7df646580ca26dfaefa593667fc6f2fe016d2e/tabulate-0.10.0-py3-none-any.whl", hash = "sha256:f0b0622e567335c8fabaaa659f1b33bcb6ddfe2e496071b743aa113f8774f2d3", size = 39814, upload-time = "2026-03-04T18:55:31.284Z" }, ] [[package]] From 00c9d5cf3d7434b5809950b7a0c4a4326d7b718c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radek=20Je=C5=BEek?= Date: Fri, 6 Mar 2026 10:00:50 +0100 Subject: [PATCH 6/6] fix(a2a): fix compatibility issues from a2a-sdk v1 migration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add ignore_unknown_fields=True to ParseDict calls to handle compat layer fields like preferredTransport - Rename transport methods for push notification config (v1 API change) - Fix display_name assertion in PlatformAuthBackend when JWT has no name claim (falls back to sub) - Pass call_context to TaskManager in scheduled cleanup - Update test imports for removed a2a-sdk constants Signed-off-by: Radek Ježek --- agents/chat/uv.lock | 58 +++++++++---------- .../src/agentstack_cli/utils.py | 2 +- .../src/agentstack_sdk/platform/provider.py | 2 +- .../src/agentstack_sdk/server/agent.py | 3 +- .../middleware/platform_auth_backend.py | 5 +- .../domain/models/provider.py | 2 +- .../service_layer/services/a2a.py | 4 +- .../tests/e2e/examples/conftest.py | 2 +- .../tests/e2e/routes/test_a2a_proxy.py | 32 +++++----- 9 files changed, 57 insertions(+), 53 deletions(-) diff --git a/agents/chat/uv.lock b/agents/chat/uv.lock index 9f0e3d41d8..46bf786357 100644 --- a/agents/chat/uv.lock +++ b/agents/chat/uv.lock @@ -4,8 +4,8 @@ requires-python = "==3.14.*" [[package]] name = "a2a-sdk" -version = "0.3.24.post54.dev0+5b354e4" -source = { git = "https://github.com/a2aproject/a2a-python.git?rev=1.0-dev#5b354e403a717c3c6bf47a291bef028c8c6a9d94" } +version = "0.3.24.post55.dev0+5955197" +source = { git = "https://github.com/a2aproject/a2a-python.git?rev=1.0-dev#59551977d194c107c9b77aad5b251e755b22103a" } dependencies = [ { name = "google-api-core" }, { name = "googleapis-common-protos" }, @@ -298,11 +298,11 @@ wikipedia = [ [[package]] name = "cachetools" -version = "7.0.2" +version = "7.0.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6c/c7/342b33cc6877eebc6c9bb45cb9f78e170e575839699f6f3cc96050176431/cachetools-7.0.2.tar.gz", hash = "sha256:7e7f09a4ca8b791d8bb4864afc71e9c17e607a28e6839ca1a644253c97dbeae0", size = 36983, upload-time = "2026-03-02T19:45:16.926Z" } +sdist = { url = "https://files.pythonhosted.org/packages/48/5c/3b882b82e9af737906539a2eafb62f96a229f1fa80255bede0c7b554cbc4/cachetools-7.0.3.tar.gz", hash = "sha256:8c246313b95849964e54a909c03b327a87ab0428b068fac10da7b105ca275ef6", size = 37187, upload-time = "2026-03-05T21:00:57.918Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/04/4b6968e77c110f12da96fdbfcb39c6557c2e5e81bd7afcf8ed893d5bc588/cachetools-7.0.2-py3-none-any.whl", hash = "sha256:938dcad184827c5e94928c4fd5526e2b46692b7fb1ae94472da9131d0299343c", size = 13793, upload-time = "2026-03-02T19:45:15.495Z" }, + { url = "https://files.pythonhosted.org/packages/05/4a/573185481c50a8841331f54ddae44e4a3469c46aa0b397731c53a004369a/cachetools-7.0.3-py3-none-any.whl", hash = "sha256:c128ffca156eef344c25fcd08a96a5952803786fa33097f5f2d49edf76f79d53", size = 13907, upload-time = "2026-03-05T21:00:56.486Z" }, ] [[package]] @@ -349,27 +349,27 @@ wheels = [ [[package]] name = "charset-normalizer" -version = "3.4.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418, upload-time = "2025-10-14T04:42:32.879Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2a/35/7051599bd493e62411d6ede36fd5af83a38f37c4767b92884df7301db25d/charset_normalizer-3.4.4-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:da3326d9e65ef63a817ecbcc0df6e94463713b754fe293eaa03da99befb9a5bd", size = 207746, upload-time = "2025-10-14T04:41:33.773Z" }, - { url = "https://files.pythonhosted.org/packages/10/9a/97c8d48ef10d6cd4fcead2415523221624bf58bcf68a802721a6bc807c8f/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8af65f14dc14a79b924524b1e7fffe304517b2bff5a58bf64f30b98bbc5079eb", size = 147889, upload-time = "2025-10-14T04:41:34.897Z" }, - { url = "https://files.pythonhosted.org/packages/10/bf/979224a919a1b606c82bd2c5fa49b5c6d5727aa47b4312bb27b1734f53cd/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74664978bb272435107de04e36db5a9735e78232b85b77d45cfb38f758efd33e", size = 143641, upload-time = "2025-10-14T04:41:36.116Z" }, - { url = "https://files.pythonhosted.org/packages/ba/33/0ad65587441fc730dc7bd90e9716b30b4702dc7b617e6ba4997dc8651495/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:752944c7ffbfdd10c074dc58ec2d5a8a4cd9493b314d367c14d24c17684ddd14", size = 160779, upload-time = "2025-10-14T04:41:37.229Z" }, - { url = "https://files.pythonhosted.org/packages/67/ed/331d6b249259ee71ddea93f6f2f0a56cfebd46938bde6fcc6f7b9a3d0e09/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1f13550535ad8cff21b8d757a3257963e951d96e20ec82ab44bc64aeb62a191", size = 159035, upload-time = "2025-10-14T04:41:38.368Z" }, - { url = "https://files.pythonhosted.org/packages/67/ff/f6b948ca32e4f2a4576aa129d8bed61f2e0543bf9f5f2b7fc3758ed005c9/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ecaae4149d99b1c9e7b88bb03e3221956f68fd6d50be2ef061b2381b61d20838", size = 152542, upload-time = "2025-10-14T04:41:39.862Z" }, - { url = "https://files.pythonhosted.org/packages/16/85/276033dcbcc369eb176594de22728541a925b2632f9716428c851b149e83/charset_normalizer-3.4.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cb6254dc36b47a990e59e1068afacdcd02958bdcce30bb50cc1700a8b9d624a6", size = 149524, upload-time = "2025-10-14T04:41:41.319Z" }, - { url = "https://files.pythonhosted.org/packages/9e/f2/6a2a1f722b6aba37050e626530a46a68f74e63683947a8acff92569f979a/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c8ae8a0f02f57a6e61203a31428fa1d677cbe50c93622b4149d5c0f319c1d19e", size = 150395, upload-time = "2025-10-14T04:41:42.539Z" }, - { url = "https://files.pythonhosted.org/packages/60/bb/2186cb2f2bbaea6338cad15ce23a67f9b0672929744381e28b0592676824/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:47cc91b2f4dd2833fddaedd2893006b0106129d4b94fdb6af1f4ce5a9965577c", size = 143680, upload-time = "2025-10-14T04:41:43.661Z" }, - { url = "https://files.pythonhosted.org/packages/7d/a5/bf6f13b772fbb2a90360eb620d52ed8f796f3c5caee8398c3b2eb7b1c60d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:82004af6c302b5d3ab2cfc4cc5f29db16123b1a8417f2e25f9066f91d4411090", size = 162045, upload-time = "2025-10-14T04:41:44.821Z" }, - { url = "https://files.pythonhosted.org/packages/df/c5/d1be898bf0dc3ef9030c3825e5d3b83f2c528d207d246cbabe245966808d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b7d8f6c26245217bd2ad053761201e9f9680f8ce52f0fcd8d0755aeae5b2152", size = 149687, upload-time = "2025-10-14T04:41:46.442Z" }, - { url = "https://files.pythonhosted.org/packages/a5/42/90c1f7b9341eef50c8a1cb3f098ac43b0508413f33affd762855f67a410e/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:799a7a5e4fb2d5898c60b640fd4981d6a25f1c11790935a44ce38c54e985f828", size = 160014, upload-time = "2025-10-14T04:41:47.631Z" }, - { url = "https://files.pythonhosted.org/packages/76/be/4d3ee471e8145d12795ab655ece37baed0929462a86e72372fd25859047c/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:99ae2cffebb06e6c22bdc25801d7b30f503cc87dbd283479e7b606f70aff57ec", size = 154044, upload-time = "2025-10-14T04:41:48.81Z" }, - { url = "https://files.pythonhosted.org/packages/b0/6f/8f7af07237c34a1defe7defc565a9bc1807762f672c0fde711a4b22bf9c0/charset_normalizer-3.4.4-cp314-cp314-win32.whl", hash = "sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9", size = 99940, upload-time = "2025-10-14T04:41:49.946Z" }, - { url = "https://files.pythonhosted.org/packages/4b/51/8ade005e5ca5b0d80fb4aff72a3775b325bdc3d27408c8113811a7cbe640/charset_normalizer-3.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c", size = 107104, upload-time = "2025-10-14T04:41:51.051Z" }, - { url = "https://files.pythonhosted.org/packages/da/5f/6b8f83a55bb8278772c5ae54a577f3099025f9ade59d0136ac24a0df4bde/charset_normalizer-3.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2", size = 100743, upload-time = "2025-10-14T04:41:52.122Z" }, - { url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402, upload-time = "2025-10-14T04:42:31.76Z" }, +version = "3.4.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1d/35/02daf95b9cd686320bb622eb148792655c9412dbb9b67abb5694e5910a24/charset_normalizer-3.4.5.tar.gz", hash = "sha256:95adae7b6c42a6c5b5b559b1a99149f090a57128155daeea91732c8d970d8644", size = 134804, upload-time = "2026-03-06T06:03:19.46Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/43/be/0f0fd9bb4a7fa4fb5067fb7d9ac693d4e928d306f80a0d02bde43a7c4aee/charset_normalizer-3.4.5-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8197abe5ca1ffb7d91e78360f915eef5addff270f8a71c1fc5be24a56f3e4873", size = 280232, upload-time = "2026-03-06T06:02:01.508Z" }, + { url = "https://files.pythonhosted.org/packages/28/02/983b5445e4bef49cd8c9da73a8e029f0825f39b74a06d201bfaa2e55142a/charset_normalizer-3.4.5-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a2aecdb364b8a1802afdc7f9327d55dad5366bc97d8502d0f5854e50712dbc5f", size = 189688, upload-time = "2026-03-06T06:02:02.857Z" }, + { url = "https://files.pythonhosted.org/packages/d0/88/152745c5166437687028027dc080e2daed6fe11cfa95a22f4602591c42db/charset_normalizer-3.4.5-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a66aa5022bf81ab4b1bebfb009db4fd68e0c6d4307a1ce5ef6a26e5878dfc9e4", size = 206833, upload-time = "2026-03-06T06:02:05.127Z" }, + { url = "https://files.pythonhosted.org/packages/cb/0f/ebc15c8b02af2f19be9678d6eed115feeeccc45ce1f4b098d986c13e8769/charset_normalizer-3.4.5-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d77f97e515688bd615c1d1f795d540f32542d514242067adcb8ef532504cb9ee", size = 202879, upload-time = "2026-03-06T06:02:06.446Z" }, + { url = "https://files.pythonhosted.org/packages/38/9c/71336bff6934418dc8d1e8a1644176ac9088068bc571da612767619c97b3/charset_normalizer-3.4.5-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01a1ed54b953303ca7e310fafe0fe347aab348bd81834a0bcd602eb538f89d66", size = 195764, upload-time = "2026-03-06T06:02:08.763Z" }, + { url = "https://files.pythonhosted.org/packages/b7/95/ce92fde4f98615661871bc282a856cf9b8a15f686ba0af012984660d480b/charset_normalizer-3.4.5-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:b2d37d78297b39a9eb9eb92c0f6df98c706467282055419df141389b23f93362", size = 183728, upload-time = "2026-03-06T06:02:10.137Z" }, + { url = "https://files.pythonhosted.org/packages/1c/e7/f5b4588d94e747ce45ae680f0f242bc2d98dbd4eccfab73e6160b6893893/charset_normalizer-3.4.5-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e71bbb595973622b817c042bd943c3f3667e9c9983ce3d205f973f486fec98a7", size = 192937, upload-time = "2026-03-06T06:02:11.663Z" }, + { url = "https://files.pythonhosted.org/packages/f9/29/9d94ed6b929bf9f48bf6ede6e7474576499f07c4c5e878fb186083622716/charset_normalizer-3.4.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4cd966c2559f501c6fd69294d082c2934c8dd4719deb32c22961a5ac6db0df1d", size = 192040, upload-time = "2026-03-06T06:02:13.489Z" }, + { url = "https://files.pythonhosted.org/packages/15/d2/1a093a1cf827957f9445f2fe7298bcc16f8fc5e05c1ed2ad1af0b239035e/charset_normalizer-3.4.5-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:d5e52d127045d6ae01a1e821acfad2f3a1866c54d0e837828538fabe8d9d1bd6", size = 184107, upload-time = "2026-03-06T06:02:14.83Z" }, + { url = "https://files.pythonhosted.org/packages/0f/7d/82068ce16bd36135df7b97f6333c5d808b94e01d4599a682e2337ed5fd14/charset_normalizer-3.4.5-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:30a2b1a48478c3428d047ed9690d57c23038dac838a87ad624c85c0a78ebeb39", size = 208310, upload-time = "2026-03-06T06:02:16.165Z" }, + { url = "https://files.pythonhosted.org/packages/84/4e/4dfb52307bb6af4a5c9e73e482d171b81d36f522b21ccd28a49656baa680/charset_normalizer-3.4.5-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:d8ed79b8f6372ca4254955005830fd61c1ccdd8c0fac6603e2c145c61dd95db6", size = 192918, upload-time = "2026-03-06T06:02:18.144Z" }, + { url = "https://files.pythonhosted.org/packages/08/a4/159ff7da662cf7201502ca89980b8f06acf3e887b278956646a8aeb178ab/charset_normalizer-3.4.5-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:c5af897b45fa606b12464ccbe0014bbf8c09191e0a66aab6aa9d5cf6e77e0c94", size = 204615, upload-time = "2026-03-06T06:02:19.821Z" }, + { url = "https://files.pythonhosted.org/packages/d6/62/0dd6172203cb6b429ffffc9935001fde42e5250d57f07b0c28c6046deb6b/charset_normalizer-3.4.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:1088345bcc93c58d8d8f3d783eca4a6e7a7752bbff26c3eee7e73c597c191c2e", size = 197784, upload-time = "2026-03-06T06:02:21.86Z" }, + { url = "https://files.pythonhosted.org/packages/c7/5e/1aab5cb737039b9c59e63627dc8bbc0d02562a14f831cc450e5f91d84ce1/charset_normalizer-3.4.5-cp314-cp314-win32.whl", hash = "sha256:ee57b926940ba00bca7ba7041e665cc956e55ef482f851b9b65acb20d867e7a2", size = 133009, upload-time = "2026-03-06T06:02:23.289Z" }, + { url = "https://files.pythonhosted.org/packages/40/65/e7c6c77d7aaa4c0d7974f2e403e17f0ed2cb0fc135f77d686b916bf1eead/charset_normalizer-3.4.5-cp314-cp314-win_amd64.whl", hash = "sha256:4481e6da1830c8a1cc0b746b47f603b653dadb690bcd851d039ffaefe70533aa", size = 143511, upload-time = "2026-03-06T06:02:26.195Z" }, + { url = "https://files.pythonhosted.org/packages/ba/91/52b0841c71f152f563b8e072896c14e3d83b195c188b338d3cc2e582d1d4/charset_normalizer-3.4.5-cp314-cp314-win_arm64.whl", hash = "sha256:97ab7787092eb9b50fb47fa04f24c75b768a606af1bcba1957f07f128a7219e4", size = 133775, upload-time = "2026-03-06T06:02:27.473Z" }, + { url = "https://files.pythonhosted.org/packages/c5/60/3a621758945513adfd4db86827a5bafcc615f913dbd0b4c2ed64a65731be/charset_normalizer-3.4.5-py3-none-any.whl", hash = "sha256:9db5e3fcdcee89a78c04dffb3fe33c79f77bd741a624946db2591c81b2fc85b0", size = 55455, upload-time = "2026-03-06T06:03:17.827Z" }, ] [[package]] @@ -1153,7 +1153,7 @@ wheels = [ [[package]] name = "openai" -version = "2.24.0" +version = "2.26.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, @@ -1165,9 +1165,9 @@ dependencies = [ { name = "tqdm" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/55/13/17e87641b89b74552ed408a92b231283786523edddc95f3545809fab673c/openai-2.24.0.tar.gz", hash = "sha256:1e5769f540dbd01cb33bc4716a23e67b9d695161a734aff9c5f925e2bf99a673", size = 658717, upload-time = "2026-02-24T20:02:07.958Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/91/2a06c4e9597c338cac1e5e5a8dd6f29e1836fc229c4c523529dca387fda8/openai-2.26.0.tar.gz", hash = "sha256:b41f37c140ae0034a6e92b0c509376d907f3a66109935fba2c1b471a7c05a8fb", size = 666702, upload-time = "2026-03-05T23:17:35.874Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c9/30/844dc675ee6902579b8eef01ed23917cc9319a1c9c0c14ec6e39340c96d0/openai-2.24.0-py3-none-any.whl", hash = "sha256:fed30480d7d6c884303287bde864980a4b137b60553ffbcf9ab4a233b7a73d94", size = 1120122, upload-time = "2026-02-24T20:02:05.669Z" }, + { url = "https://files.pythonhosted.org/packages/c6/2e/3f73e8ca53718952222cacd0cf7eecc9db439d020f0c1fe7ae717e4e199a/openai-2.26.0-py3-none-any.whl", hash = "sha256:6151bf8f83802f036117f06cc8a57b3a4da60da9926826cc96747888b57f394f", size = 1136409, upload-time = "2026-03-05T23:17:34.072Z" }, ] [[package]] diff --git a/apps/agentstack-cli/src/agentstack_cli/utils.py b/apps/agentstack-cli/src/agentstack_cli/utils.py index dd8e06ace1..1ecabdaa8f 100644 --- a/apps/agentstack-cli/src/agentstack_cli/utils.py +++ b/apps/agentstack-cli/src/agentstack_cli/utils.py @@ -303,7 +303,7 @@ def verbosity(verbose: bool, show_success_status: bool = True): def print_log(line, ansi_mode=False, out_console: Console | None = None): - if "error" in line: + if line.get("error"): class CustomError(Exception): ... diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/platform/provider.py b/apps/agentstack-sdk-py/src/agentstack_sdk/platform/provider.py index 2e1696a7ed..37b021caac 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/platform/provider.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/platform/provider.py @@ -57,7 +57,7 @@ class Provider(pydantic.BaseModel, arbitrary_types_allowed=True): @pydantic.field_validator("agent_card", mode="before") @classmethod def parse_card(cls: Self, value: dict[str, Any]) -> AgentCard: - return ParseDict(value, AgentCard()) + return ParseDict(value, AgentCard(), ignore_unknown_fields=True) @staticmethod async def create( diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/server/agent.py b/apps/agentstack-sdk-py/src/agentstack_sdk/server/agent.py index 953b8c3f69..1b34016e08 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/server/agent.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/server/agent.py @@ -668,7 +668,8 @@ async def cleanup_fn(): await run.cancel(request_context=request_context, event_queue=queue) # the original request queue is closed at this point, we need to propagate state to store manually manager = TaskManager( - task_id=task_id, context_id=context_id, task_store=self._task_store, initial_message=None + task_id=task_id, context_id=context_id, task_store=self._task_store, initial_message=None, + context=request_context.call_context, ) event = await queue.dequeue_event(no_wait=True) if ( diff --git a/apps/agentstack-sdk-py/src/agentstack_sdk/server/middleware/platform_auth_backend.py b/apps/agentstack-sdk-py/src/agentstack_sdk/server/middleware/platform_auth_backend.py index deff917554..1ea768f7a8 100644 --- a/apps/agentstack-sdk-py/src/agentstack_sdk/server/middleware/platform_auth_backend.py +++ b/apps/agentstack-sdk-py/src/agentstack_sdk/server/middleware/platform_auth_backend.py @@ -51,8 +51,9 @@ def user_name(self) -> str: @override def display_name(self) -> str: name = self.claims.get("name", None) - assert name and isinstance(name, str) - return name + if name and isinstance(name, str): + return name + return self.user_name @property @override diff --git a/apps/agentstack-server/src/agentstack_server/domain/models/provider.py b/apps/agentstack-server/src/agentstack_server/domain/models/provider.py index a6efe44261..3faccc9127 100644 --- a/apps/agentstack-server/src/agentstack_server/domain/models/provider.py +++ b/apps/agentstack-server/src/agentstack_server/domain/models/provider.py @@ -86,7 +86,7 @@ async def load_agent_card(self) -> dict[str, Any]: if DOCKER_MANIFEST_LABEL_NAME not in labels: raise MissingAgentCardLabelError(str(self.root)) data = json.loads(base64.b64decode(labels[DOCKER_MANIFEST_LABEL_NAME])) - ParseDict(data, AgentCard()) # try at least parsing card, TODO: validation of required fields + ParseDict(data, AgentCard(), ignore_unknown_fields=True) # try at least parsing card, TODO: validation of required fields return data diff --git a/apps/agentstack-server/src/agentstack_server/service_layer/services/a2a.py b/apps/agentstack-server/src/agentstack_server/service_layer/services/a2a.py index 487b898ce1..d430145f68 100644 --- a/apps/agentstack-server/src/agentstack_server/service_layer/services/a2a.py +++ b/apps/agentstack-server/src/agentstack_server/service_layer/services/a2a.py @@ -332,7 +332,7 @@ async def on_create_task_push_notification_config( ) -> TaskPushNotificationConfig: await self._check_task(params.task_id) async with self._client_transport(context) as transport: - return await transport.set_task_callback(params) + return await transport.create_task_push_notification_config(params, context=self._forward_context(context)) @_handle_exception @override @@ -343,7 +343,7 @@ async def on_get_task_push_notification_config( ) -> TaskPushNotificationConfig: await self._check_task(params.task_id) async with self._client_transport(context) as transport: - return await transport.get_task_callback(params, context=self._forward_context(context)) + return await transport.get_task_push_notification_config(params, context=self._forward_context(context)) @_handle_exception @override diff --git a/apps/agentstack-server/tests/e2e/examples/conftest.py b/apps/agentstack-server/tests/e2e/examples/conftest.py index 95f147a9e0..95948db70a 100644 --- a/apps/agentstack-server/tests/e2e/examples/conftest.py +++ b/apps/agentstack-server/tests/e2e/examples/conftest.py @@ -70,7 +70,7 @@ async def _get_agent_card(agent_url: str): async with httpx.AsyncClient(timeout=None) as httpx_client: card_resp = await httpx_client.get(f"{agent_url}{AGENT_CARD_WELL_KNOWN_PATH}") card_resp.raise_for_status() - card = ParseDict(card_resp.json(), AgentCard()) + card = ParseDict(card_resp.json(), AgentCard(), ignore_unknown_fields=True) return card diff --git a/apps/agentstack-server/tests/e2e/routes/test_a2a_proxy.py b/apps/agentstack-server/tests/e2e/routes/test_a2a_proxy.py index 9f10b34514..921dfd2897 100644 --- a/apps/agentstack-server/tests/e2e/routes/test_a2a_proxy.py +++ b/apps/agentstack-server/tests/e2e/routes/test_a2a_proxy.py @@ -46,9 +46,11 @@ ) from a2a.utils import ( AGENT_CARD_WELL_KNOWN_PATH, - EXTENDED_AGENT_CARD_PATH, - PREV_AGENT_CARD_WELL_KNOWN_PATH, ) + +# These constants were removed in a2a-sdk v1; tests using them are skipped +EXTENDED_AGENT_CARD_PATH = "/agent/authenticatedExtendedCard" +PREV_AGENT_CARD_WELL_KNOWN_PATH = "/.well-known/agent.json" from a2a.utils.errors import UnsupportedOperationError from fastapi import FastAPI from google.protobuf.struct_pb2 import Struct, Value @@ -484,7 +486,7 @@ def test_cancel_task(client: Client, handler: mock.AsyncMock, ensure_mock_task): handler.on_cancel_task.return_value = task # Send request - response = client.post( # noqa: ASYNC212 + response = client.post( "/", json={ "jsonrpc": "2.0", @@ -511,7 +513,7 @@ def test_get_task(client: Client, handler: mock.AsyncMock, ensure_mock_task): handler.on_get_task.return_value = task # Send request - response = client.post( # noqa: ASYNC212 + response = client.post( "/", json={ "jsonrpc": "2.0", @@ -1101,7 +1103,7 @@ async def test_unknown_task_raises_error(create_test_server, handler: mock.Async # Send message with non-existing task client.auth = test_admin - response = client.post( # noqa: ASYNC212 + response = client.post( "/", json={ "jsonrpc": "2.0", @@ -1141,7 +1143,7 @@ async def test_task_ownership_new_task_creation_via_message_send( # Send message as admin which should create new task ownership client.auth = test_admin - response = client.post( # noqa: ASYNC212 + response = client.post( "/", json={ "jsonrpc": "2.0", @@ -1175,7 +1177,7 @@ async def test_task_ownership_new_task_creation_via_message_send( task = Task(id="new-task-123", context_id="ctx1", status=task_status) handler.on_get_task.return_value = task - response = client.post( # noqa: ASYNC212 + response = client.post( "/", json={"jsonrpc": "2.0", "id": "124", "method": "GetTask", "params": {"id": "new-task-123"}}, ) @@ -1185,7 +1187,7 @@ async def test_task_ownership_new_task_creation_via_message_send( # Verify default user cannot access it client.auth = test_user - response = client.post( # noqa: ASYNC212 + response = client.post( "/", json={"jsonrpc": "2.0", "id": "125", "method": "GetTask", "params": {"id": "new-task-123"}}, ) @@ -1208,7 +1210,7 @@ async def test_context_ownership_cannot_be_claimed_by_different_user( mock_task = Task(id="task-ctx-1", context_id="shared-context-789", status=task_status) handler.on_message_send.return_value = mock_task - response = client.post( # noqa: ASYNC212 + response = client.post( "/", json={ "jsonrpc": "2.0", @@ -1244,7 +1246,7 @@ async def test_context_ownership_cannot_be_claimed_by_different_user( ) handler.on_message_send.return_value = mock_task2 - response = client.post( # noqa: ASYNC212 + response = client.post( "/", json={ "jsonrpc": "2.0", @@ -1291,7 +1293,7 @@ async def test_task_update_last_accessed_at(create_test_server, handler: mock.As }, } - response = client.post("/", json=message_data) # noqa: ASYNC212 + response = client.post("/", json=message_data) # Get initial timestamp result = await db_transaction.execute( text("SELECT last_accessed_at FROM a2a_request_tasks WHERE task_id = :task_id"), {"task_id": "task1"} @@ -1306,7 +1308,7 @@ async def test_task_update_last_accessed_at(create_test_server, handler: mock.As task = Task(id="task1", context_id="ctx1", status=task_status) handler.on_get_task.return_value = task - response = client.post("/", json=message_data) # noqa: ASYNC212 + response = client.post("/", json=message_data) assert response.status_code == 200 # Check that timestamp was updated @@ -1342,11 +1344,11 @@ async def test_task_and_context_both_specified_single_query( } }, } - response = client.post("/", json=message_data) # noqa: ASYNC212 + response = client.post("/", json=message_data) assert response.status_code == 200 message_data["params"]["message"]["taskId"] = "dual-task-123" - response = client.post("/", json=message_data) # noqa: ASYNC212 + response = client.post("/", json=message_data) assert response.status_code == 200 # Verify both were recorded in database @@ -1388,7 +1390,7 @@ async def test_invalid_request_raises_a2a_error(create_test_server, handler: moc } }, } - response = client.post("/", json=message_data) # noqa: ASYNC212 + response = client.post("/", json=message_data) assert response.status_code == 200 data = response.json() assert data["id"] == "123"