diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 53c7b4d..d0a9552 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -19,6 +19,7 @@ repos:
types-python-dateutil,
pydantic,
fastapi,
+ "openai-agents[litellm]==0.14.6",
]
args: [--install-types, --non-interactive]
diff --git a/pyproject.toml b/pyproject.toml
index 70aad4e..2cf9986 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -33,7 +33,8 @@ classifiers = [
"Programming Language :: Python :: 3.14",
]
dependencies = [
- "litellm[proxy]>=1.81.1,<1.82.0",
+ "litellm[proxy]>=1.83.0",
+ "openai-agents[litellm]==0.14.6",
"tenacity>=9.0.0",
"pydantic[email]>=2.11.3",
"rich",
@@ -146,6 +147,17 @@ ignore_missing_imports = true
module = ["tests.*"]
disallow_untyped_decorators = false
disallow_untyped_defs = false
+# Test fixtures often build raw dicts that match SDK TypedDict unions
+# structurally; type:ignore-per-line would be very noisy.
+disable_error_code = [
+ "typeddict-item", # TypedDict key access on union variants
+ "typeddict-unknown-key",
+ "type-arg", # generic params on dict/MagicMock in test helpers
+ "no-untyped-call", # SDK has untyped __init__ in some places
+ "no-any-return", # test helpers often return Any from typed call_args
+ "arg-type", # fakes pass mocks where SDK wants strict types
+ "attr-defined", # fake objects monkey-patch attrs
+]
# ============================================================================
# Ruff Configuration (Fast Python Linter & Formatter)
@@ -235,11 +247,36 @@ ignore = [
"S106", # Possible hardcoded password
"S108", # Possible insecure usage of temporary file/directory
"ARG001", # Unused function argument
+ "ARG002", # Unused method argument (test helpers / fakes mirror SDK signatures)
"PLR2004", # Magic value used in comparison
+ "TC002", # Type-only third-party import (tests import for runtime instantiation)
+ "TC003", # Type-only stdlib import
]
"strix/tools/**/*.py" = [
"ARG001", # Unused function argument (tools may have unused args for interface consistency)
]
+# SDK lifecycle hooks have a fixed signature — unused args are part of the contract.
+"strix/orchestration/hooks.py" = [
+ "ARG002", # Unused method argument (RunHooks signature is set by SDK)
+ "TC002", # ModelResponse, RunContextWrapper, AgentHookContext are annotation-only
+]
+# Anthropic cache wrapper inherits from LitellmModel; signature shadows builtin `input`.
+"strix/llm/anthropic_cache_wrapper.py" = [
+ "A002", # Argument shadows builtin (parent signature uses `input`)
+ "TC002", # Many SDK types are imports-for-annotations only
+ "TC003", # collections.abc.AsyncIterator imported for return type
+]
+# Custom Docker subclass duplicates parent body; some imports are for annotations.
+"strix/runtime/strix_docker_client.py" = [
+ "TC002", # Manifest, Container imported for annotations
+ "TC003", # uuid imported for annotation
+]
+"strix/llm/multi_provider_setup.py" = [
+ "TC002", # Model, ModelProvider imported for annotations
+]
+"strix/tools/_decorator.py" = [
+ "TC002", # FunctionTool imported for annotation
+]
[tool.ruff.lint.isort]
force-single-line = false
diff --git a/strix/llm/anthropic_cache_wrapper.py b/strix/llm/anthropic_cache_wrapper.py
new file mode 100644
index 0000000..52f9107
--- /dev/null
+++ b/strix/llm/anthropic_cache_wrapper.py
@@ -0,0 +1,146 @@
+"""AnthropicCachingLitellmModel — inject cache_control on the system message.
+
+ModelSettings.extra_body lands the field at the request top level, which
+Anthropic ignores. Anthropic only honors ``cache_control`` when it is on the
+message itself. We patch the input list before delegating to the parent.
+
+References:
+ - PLAYBOOK.md §2.1
+ - AUDIT.md §2.2 (C2 — original blocker)
+ - AUDIT_R3.md F1 (signature: first 7 params positional, then *,)
+"""
+
+from __future__ import annotations
+
+from collections.abc import AsyncIterator
+from typing import Any
+
+from agents.agent_output import AgentOutputSchemaBase
+from agents.extensions.models.litellm_model import LitellmModel
+from agents.handoffs import Handoff
+from agents.items import ModelResponse, TResponseInputItem, TResponseStreamEvent
+from agents.model_settings import ModelSettings
+from agents.models.interface import ModelTracing
+from agents.tool import Tool
+
+
+class AnthropicCachingLitellmModel(LitellmModel):
+ """LitellmModel that injects ``cache_control: {"type": "ephemeral"}`` on the
+ system message for Anthropic models. Other providers pass through unchanged.
+
+ Detection follows the legacy Strix logic: case-insensitive substring match
+ on ``"anthropic/"`` or ``"claude"`` against the model name (llm/llm.py:338-341).
+
+ For Strix proxy routing where the API model is ``openai/`` but the
+ underlying provider is still Anthropic (e.g., ``strix/claude-sonnet-4.6``
+ resolves to api_model=``openai/claude-sonnet-4.6`` against the Strix
+ proxy with a canonical of ``anthropic/claude-sonnet-4-6``), pass
+ ``is_anthropic_override=True`` so the wrapper still injects cache_control
+ even though the model name doesn't match the heuristic.
+ """
+
+ def __init__(
+ self,
+ model: str,
+ *,
+ is_anthropic_override: bool | None = None,
+ **kwargs: Any,
+ ) -> None:
+ super().__init__(model=model, **kwargs)
+ self._is_anthropic_override = is_anthropic_override
+
+ def _is_anthropic(self) -> bool:
+ if self._is_anthropic_override is not None:
+ return self._is_anthropic_override
+ m = (self.model or "").lower()
+ return "anthropic/" in m or "claude" in m
+
+ def _patch(
+ self,
+ items: list[TResponseInputItem],
+ ) -> list[TResponseInputItem]:
+ """Return a copy of ``items`` with cache_control on the system message.
+
+ Returns the input list unchanged for non-Anthropic models. For
+ Anthropic, the first ``role: system`` item has its content rewritten
+ from a string to a list-of-blocks with ``cache_control`` attached.
+ """
+ if not self._is_anthropic():
+ return items
+ out: list[TResponseInputItem] = []
+ for item in items:
+ if isinstance(item, dict) and item.get("role") == "system":
+ content = item.get("content")
+ if isinstance(content, str):
+ new_item = {
+ **item,
+ "content": [
+ {
+ "type": "text",
+ "text": content,
+ "cache_control": {"type": "ephemeral"},
+ },
+ ],
+ }
+ out.append(new_item) # type: ignore[arg-type]
+ continue
+ out.append(item)
+ return out
+
+ async def get_response(
+ self,
+ system_instructions: str | None,
+ input: str | list[TResponseInputItem],
+ model_settings: ModelSettings,
+ tools: list[Tool],
+ output_schema: AgentOutputSchemaBase | None,
+ handoffs: list[Handoff],
+ tracing: ModelTracing,
+ previous_response_id: str | None = None,
+ conversation_id: str | None = None,
+ prompt: Any | None = None,
+ ) -> ModelResponse:
+ patched = self._patch(input if isinstance(input, list) else [])
+ # If input was a string, patching is a no-op; pass straight through.
+ effective: str | list[TResponseInputItem] = patched if isinstance(input, list) else input
+ return await super().get_response(
+ system_instructions,
+ effective,
+ model_settings,
+ tools,
+ output_schema,
+ handoffs,
+ tracing,
+ previous_response_id=previous_response_id,
+ conversation_id=conversation_id,
+ prompt=prompt,
+ )
+
+ async def stream_response(
+ self,
+ system_instructions: str | None,
+ input: str | list[TResponseInputItem],
+ model_settings: ModelSettings,
+ tools: list[Tool],
+ output_schema: AgentOutputSchemaBase | None,
+ handoffs: list[Handoff],
+ tracing: ModelTracing,
+ previous_response_id: str | None = None,
+ conversation_id: str | None = None,
+ prompt: Any | None = None,
+ ) -> AsyncIterator[TResponseStreamEvent]:
+ patched = self._patch(input if isinstance(input, list) else [])
+ effective: str | list[TResponseInputItem] = patched if isinstance(input, list) else input
+ async for event in super().stream_response(
+ system_instructions,
+ effective,
+ model_settings,
+ tools,
+ output_schema,
+ handoffs,
+ tracing,
+ previous_response_id=previous_response_id,
+ conversation_id=conversation_id,
+ prompt=prompt,
+ ):
+ yield event
diff --git a/strix/llm/multi_provider_setup.py b/strix/llm/multi_provider_setup.py
new file mode 100644
index 0000000..f112332
--- /dev/null
+++ b/strix/llm/multi_provider_setup.py
@@ -0,0 +1,102 @@
+"""Multi-provider routing setup for Strix on top of the SDK MultiProvider.
+
+The SDK's ``MultiProvider`` resolves a model name like ``"strix/claude-sonnet-4.6"``
+by stripping the prefix (``"strix"``) and dispatching to a registered
+``ModelProvider`` keyed on that prefix. We register two custom providers:
+
+- ``"strix"`` → ``StrixModelProvider``: aliases the short name to a Strix-proxy
+ ``openai/`` model URL, but knows whether the underlying provider is
+ Anthropic so cache-control still gets injected at the message layer.
+- ``"litellm/anthropic"`` → ``LitellmAnthropicProvider``: direct Anthropic
+ routing via LiteLLM, always Anthropic, always caching.
+
+Other prefixes fall through to the SDK's built-in OpenAI / LiteLLM defaults.
+
+References:
+ - PLAYBOOK.md §2.7
+ - AUDIT_R3.md C17 (model alias validation; raise UserError on unknown alias)
+ - Legacy: strix/llm/utils.py STRIX_MODEL_MAP and resolve_strix_model
+ - Legacy: strix/config/config.py STRIX_API_BASE
+"""
+
+from __future__ import annotations
+
+from agents.exceptions import UserError
+from agents.extensions.models.litellm_model import LitellmModel
+from agents.models.interface import Model, ModelProvider
+from agents.models.multi_provider import MultiProvider, MultiProviderMap
+
+from strix.config.config import STRIX_API_BASE
+from strix.llm.anthropic_cache_wrapper import AnthropicCachingLitellmModel
+from strix.llm.utils import STRIX_MODEL_MAP
+
+
+def _is_anthropic_canonical(canonical: str) -> bool:
+ """Return True if ``canonical`` looks like an Anthropic provider/model."""
+ c = canonical.lower()
+ return "anthropic/" in c or "claude" in c
+
+
+class StrixModelProvider(ModelProvider):
+ """Resolves the ``strix/`` prefix.
+
+ The MultiProvider strips the prefix before calling ``get_model``, so we
+ receive ``"claude-sonnet-4.6"`` for ``"strix/claude-sonnet-4.6"``. The
+ ``api_model`` (what we actually send over the wire) is always
+ ``openai/`` against the Strix proxy (which is OpenAI-compatible).
+ The ``canonical`` model name is what the upstream provider sees and is
+ used to decide whether to inject Anthropic prompt caching at the message
+ layer.
+
+ C17: unknown aliases raise ``UserError`` listing valid options instead of
+ failing opaquely later in the LLM call.
+ """
+
+ def get_model(self, model_name: str | None) -> Model:
+ if not model_name:
+ raise UserError("StrixModelProvider requires a non-empty model name.")
+ if model_name not in STRIX_MODEL_MAP:
+ valid = ", ".join(sorted(STRIX_MODEL_MAP.keys()))
+ raise UserError(
+ f"Unknown Strix model alias 'strix/{model_name}'. Valid aliases: {valid}",
+ )
+ canonical = STRIX_MODEL_MAP[model_name]
+ api_model = f"openai/{model_name}"
+ if _is_anthropic_canonical(canonical):
+ return AnthropicCachingLitellmModel(
+ model=api_model,
+ base_url=STRIX_API_BASE,
+ is_anthropic_override=True,
+ )
+ return LitellmModel(model=api_model, base_url=STRIX_API_BASE)
+
+
+class LitellmAnthropicProvider(ModelProvider):
+ """Resolves the ``litellm/anthropic`` prefix.
+
+ The MultiProvider strips the matched prefix; for ``litellm/anthropic/...``
+ with a registered provider mapping of ``"litellm/anthropic"``, the call
+ arrives with ``model_name`` like ``"claude-sonnet-4-5-20250929"`` (the
+ suffix after the prefix). Always wraps in the caching model.
+ """
+
+ def get_model(self, model_name: str | None) -> Model:
+ if not model_name:
+ raise UserError(
+ "LitellmAnthropicProvider requires a non-empty model name.",
+ )
+ # Re-prefix for litellm so it routes to Anthropic.
+ full = f"anthropic/{model_name}"
+ return AnthropicCachingLitellmModel(model=full)
+
+
+def build_multi_provider() -> MultiProvider:
+ """Build the configured MultiProvider for Strix.
+
+ Registers Strix-specific prefix routes; OpenAI and other LiteLLM-prefixed
+ models are handled by the SDK's built-in routing.
+ """
+ pmap = MultiProviderMap() # type: ignore[no-untyped-call]
+ pmap.add_provider("strix", StrixModelProvider())
+ pmap.add_provider("litellm/anthropic", LitellmAnthropicProvider())
+ return MultiProvider(provider_map=pmap)
diff --git a/strix/orchestration/__init__.py b/strix/orchestration/__init__.py
new file mode 100644
index 0000000..8b0ada6
--- /dev/null
+++ b/strix/orchestration/__init__.py
@@ -0,0 +1,18 @@
+"""Strix multi-agent orchestration on top of OpenAI Agents SDK.
+
+Provides:
+- AgentMessageBus: peer-to-peer agent inbox + status + stats aggregation
+- inject_messages_filter: SDK call_model_input_filter for inbox drain
+- StrixOrchestrationHooks: SDK RunHooks subclass for lifecycle wiring
+"""
+
+from strix.orchestration.bus import AgentMessageBus
+from strix.orchestration.filter import inject_messages_filter
+from strix.orchestration.hooks import StrixOrchestrationHooks
+
+
+__all__ = [
+ "AgentMessageBus",
+ "StrixOrchestrationHooks",
+ "inject_messages_filter",
+]
diff --git a/strix/orchestration/bus.py b/strix/orchestration/bus.py
new file mode 100644
index 0000000..e978c17
--- /dev/null
+++ b/strix/orchestration/bus.py
@@ -0,0 +1,160 @@
+"""AgentMessageBus — peer-to-peer multi-agent state owned by Strix.
+
+Replaces the legacy harness's _agent_graph / _agent_messages / _agent_instances
+globals (in strix/tools/agents_graph/agents_graph_actions.py) with a single
+asyncio.Lock-protected dataclass that lives for the lifetime of one Strix scan.
+
+References:
+ - PLAYBOOK.md §2.3
+ - AUDIT_R2.md §1.4 (cancel_descendants)
+ - AUDIT_R2.md §1.7 (stats snapshot under lock)
+ - AUDIT_R3.md C13 (finalize cleans up state to avoid orphaned-message leak)
+"""
+
+from __future__ import annotations
+
+import asyncio
+from dataclasses import dataclass, field
+from typing import Any
+
+
+@dataclass
+class AgentMessageBus:
+ """Shared state for multi-agent orchestration.
+
+ All mutations happen under ``_lock``; readers also take the lock for
+ consistent snapshots. The bus owns:
+
+ - ``inboxes``: per-agent FIFO list of pending messages (drained by the
+ ``inject_messages_filter`` at the top of each LLM turn).
+ - ``tasks``: per-agent ``asyncio.Task`` handle so the parent (or signal
+ handler) can cancel descendants.
+ - ``statuses``: per-agent lifecycle state — ``running | waiting |
+ completed | crashed | stopped``.
+ - ``parent_of``: tree edges; root agents have ``None``.
+ - ``names``: human-readable per-agent names.
+ - ``stats_live`` / ``stats_completed``: token + call counters that hooks
+ keep up to date for live and finalized agents respectively.
+ """
+
+ inboxes: dict[str, list[dict[str, Any]]] = field(default_factory=dict)
+ tasks: dict[str, asyncio.Task[Any]] = field(default_factory=dict)
+ statuses: dict[str, str] = field(default_factory=dict)
+ parent_of: dict[str, str | None] = field(default_factory=dict)
+ names: dict[str, str] = field(default_factory=dict)
+ stats_live: dict[str, dict[str, Any]] = field(default_factory=dict)
+ stats_completed: dict[str, dict[str, Any]] = field(default_factory=dict)
+ _lock: asyncio.Lock = field(default_factory=asyncio.Lock)
+
+ async def register(
+ self,
+ agent_id: str,
+ name: str,
+ parent_id: str | None,
+ ) -> None:
+ """Add a new agent to the bus before its Runner.run task starts."""
+ async with self._lock:
+ self.inboxes[agent_id] = []
+ self.statuses[agent_id] = "running"
+ self.parent_of[agent_id] = parent_id
+ self.names[agent_id] = name
+ self.stats_live[agent_id] = {
+ "in": 0,
+ "out": 0,
+ "cached": 0,
+ "cost": 0.0,
+ "calls": 0,
+ }
+
+ async def send(self, target: str, msg: dict[str, Any]) -> None:
+ """Append a message to ``target``'s inbox.
+
+ Idempotent if target was never registered: creates an empty inbox.
+ Messages addressed to a finalized agent are dropped silently — the
+ target's inbox was cleared in :meth:`finalize` (C13).
+ """
+ async with self._lock:
+ if target not in self.statuses:
+ return
+ if self.statuses[target] in ("completed", "crashed", "stopped"):
+ return
+ self.inboxes.setdefault(target, []).append(msg)
+
+ async def drain(self, agent_id: str) -> list[dict[str, Any]]:
+ """Atomically read and clear ``agent_id``'s pending messages.
+
+ Called by ``inject_messages_filter`` before every model call.
+ Filter output is captured by SDK in a lambda closure for retries
+ (verified `model_retry.py:34-35`), so a single drain per turn does
+ not lose messages on retry.
+ """
+ async with self._lock:
+ msgs = self.inboxes.get(agent_id, [])
+ self.inboxes[agent_id] = []
+ return msgs
+
+ async def record_usage(self, agent_id: str, usage: Any) -> None:
+ """Accumulate per-call usage from RunHooks.on_llm_end.
+
+ Tolerates ``usage=None`` (some providers omit usage on streaming).
+ """
+ if usage is None:
+ return
+ async with self._lock:
+ stats = self.stats_live.setdefault(
+ agent_id,
+ {"in": 0, "out": 0, "cached": 0, "cost": 0.0, "calls": 0},
+ )
+ stats["in"] += getattr(usage, "input_tokens", 0) or 0
+ stats["out"] += getattr(usage, "output_tokens", 0) or 0
+ details = getattr(usage, "input_tokens_details", None)
+ if details is not None:
+ stats["cached"] += getattr(details, "cached_tokens", 0) or 0
+ stats["calls"] += 1
+
+ async def finalize(self, agent_id: str, status: str) -> None:
+ """Move an agent from live to completed; clean up routing state.
+
+ C13 (AUDIT_R3): also clears ``inboxes``, ``parent_of``, ``names`` so
+ sibling agents that try to send to a finished agent don't accumulate
+ orphan messages forever.
+ """
+ async with self._lock:
+ self.statuses[agent_id] = status
+ self.stats_completed[agent_id] = self.stats_live.pop(agent_id, {})
+ self.inboxes.pop(agent_id, None)
+ self.parent_of.pop(agent_id, None)
+ self.names.pop(agent_id, None)
+
+ async def total_stats(self) -> dict[str, Any]:
+ """Snapshot of live + completed stats. Lock-protected (C12)."""
+ async with self._lock:
+ agg = {"in": 0, "out": 0, "cached": 0, "cost": 0.0, "calls": 0}
+ for stats in (*self.stats_live.values(), *self.stats_completed.values()):
+ for key, value in stats.items():
+ agg[key] = agg.get(key, 0) + value
+ return agg
+
+ async def cancel_descendants(self, root_agent_id: str) -> None:
+ """Cancel ``root_agent_id`` and every transitive child, leaves first.
+
+ Wired into the CLI Ctrl+C handler and TUI stop button so a root cancel
+ actually propagates (C9 — SDK's ``result.cancel`` does not cascade
+ to children spawned via ``asyncio.create_task``).
+ """
+ async with self._lock:
+ queue = [root_agent_id]
+ order: list[str] = []
+ while queue:
+ aid = queue.pop()
+ order.append(aid)
+ queue.extend(child for child, parent in self.parent_of.items() if parent == aid)
+ tasks_to_cancel = [self.tasks[a] for a in reversed(order) if a in self.tasks]
+ for task in tasks_to_cancel:
+ if not task.done():
+ task.cancel()
+ # Wait for cancellations to settle so on_agent_end can mark statuses.
+ await asyncio.gather(
+ *(t for t in tasks_to_cancel if not t.done()),
+ return_exceptions=True,
+ )
diff --git a/strix/orchestration/filter.py b/strix/orchestration/filter.py
new file mode 100644
index 0000000..cec4681
--- /dev/null
+++ b/strix/orchestration/filter.py
@@ -0,0 +1,83 @@
+"""inject_messages_filter — SDK call_model_input_filter for the message bus.
+
+This is the integration point that replaces Strix's per-iteration
+_check_agent_messages call (legacy: agents/base_agent.py:448-531). The SDK
+runs ``call_model_input_filter`` exactly once per turn before the LLM call
+(``run_internal/turn_preparation.py:55-80``), and captures the filter's
+output in a lambda closure for any subsequent retries
+(``run_internal/model_retry.py:34-35``) — so a single drain per turn does
+not lose messages on retry.
+
+References:
+ - PLAYBOOK.md §2.4
+ - AUDIT_R3.md C14 (filter must be defensive — exception → unmodified data)
+"""
+
+from __future__ import annotations
+
+import logging
+from typing import TYPE_CHECKING
+
+from agents.run_config import CallModelData, ModelInputData
+
+
+if TYPE_CHECKING:
+ from strix.orchestration.bus import AgentMessageBus
+
+
+logger = logging.getLogger(__name__)
+
+
+async def inject_messages_filter(data: CallModelData) -> ModelInputData:
+ """Drain bus inbox and append messages as user-role items before the LLM call.
+
+ Each drained message is wrapped in an ```` XML envelope
+ that mirrors Strix's legacy format (base_agent.py:491-514) so the system
+ prompt's existing rules around inter-agent communication still apply.
+
+ Messages from the literal sender ``"user"`` (a real human via TUI) skip
+ the XML wrap and are added as plain user messages.
+
+ C14: any exception inside the filter — including a malformed message dict
+ or a bug in ``bus.drain`` — is caught and the original ``data.model_data``
+ is returned unmodified. A bug in the filter must never tear down the run.
+ """
+ try:
+ if not isinstance(data.context, dict):
+ return data.model_data
+ bus: AgentMessageBus | None = data.context.get("bus")
+ agent_id: str | None = data.context.get("agent_id")
+ if bus is None or agent_id is None:
+ return data.model_data
+ pending = await bus.drain(agent_id)
+ if not pending:
+ return data.model_data
+
+ new_input = list(data.model_data.input)
+ for msg in pending:
+ sender = msg.get("from", "unknown")
+ content = msg.get("content", "")
+ if sender == "user":
+ new_input.append({"role": "user", "content": content})
+ else:
+ new_input.append(
+ {
+ "role": "user",
+ "content": (
+ f""
+ f"{content}"
+ f""
+ ),
+ }
+ )
+ return ModelInputData(
+ input=new_input,
+ instructions=data.model_data.instructions,
+ )
+ except Exception:
+ logger.exception(
+ "inject_messages_filter failed; proceeding with unmodified input",
+ )
+ return data.model_data
diff --git a/strix/orchestration/hooks.py b/strix/orchestration/hooks.py
new file mode 100644
index 0000000..6119d9d
--- /dev/null
+++ b/strix/orchestration/hooks.py
@@ -0,0 +1,196 @@
+"""StrixOrchestrationHooks — RunHooks subclass wiring bus + tracer + warnings.
+
+References:
+ - PLAYBOOK.md §2.5
+ - AUDIT.md §2.5 (C5 — streaming/hook bridge)
+ - AUDIT_R2.md §1.3 (C8 — subagent crash detection)
+ - AUDIT_R3.md F2 (context types: AgentHookContext for agent_*,
+ RunContextWrapper otherwise; on_tool_end result is str)
+ - AUDIT_R3.md C15 (every hook body try/except so a hook bug never tears down the run)
+"""
+
+from __future__ import annotations
+
+import logging
+from typing import Any
+
+from agents.items import ModelResponse
+from agents.lifecycle import RunHooks
+from agents.run_context import AgentHookContext, RunContextWrapper
+
+
+logger = logging.getLogger(__name__)
+
+
+class StrixOrchestrationHooks(RunHooks[Any]):
+ """Lifecycle hooks for Strix multi-agent runs.
+
+ Wires four concerns:
+
+ 1. Turn-budget warnings injected into ``input_items`` at 85% and ``N - 3``
+ of ``max_turns`` (legacy: ``base_agent.py:186-211``).
+ 2. LLM usage recording into the bus (replaces legacy ``LLM._total_stats``
+ + ``_completed_agent_llm_totals``).
+ 3. Sandbox readiness: awaits the ``CaidoCapability._healthcheck_task``
+ on first agent start so the agent doesn't fire tools before Caido and
+ the tool server are ready.
+ 4. Subagent crash detection (C8): if ``on_agent_end`` fires without
+ ``agent_finish_called`` being set in context, posts a synthetic
+ ```` message to the parent's inbox so the parent learns
+ on its next turn instead of polling ``wait_for_message`` forever.
+ """
+
+ async def on_llm_start(
+ self,
+ context: RunContextWrapper[Any],
+ agent: Any,
+ system_prompt: str | None,
+ input_items: list[Any],
+ ) -> None:
+ try:
+ # Type contract guarantees ``input_items`` is list[TResponseInputItem];
+ # we trust SDK here. The try/except below catches any surprise.
+ ctx = context.context
+ if not isinstance(ctx, dict):
+ return
+ max_turns = int(ctx.get("max_turns", 300))
+ cur = int(ctx.get("turn_count", 0))
+ if max_turns >= 4 and cur == int(max_turns * 0.85):
+ input_items.append(
+ {
+ "role": "user",
+ "content": (
+ "You are at 85% of your iteration "
+ "budget. Begin consolidating findings."
+ ),
+ }
+ )
+ elif max_turns >= 4 and cur == max_turns - 3:
+ input_items.append(
+ {
+ "role": "user",
+ "content": (
+ "You have 3 iterations left. Your "
+ "next tool call MUST be the finish tool."
+ ""
+ ),
+ }
+ )
+ except Exception:
+ logger.exception("on_llm_start failed")
+
+ async def on_llm_end(
+ self,
+ context: RunContextWrapper[Any],
+ agent: Any,
+ response: ModelResponse,
+ ) -> None:
+ try:
+ ctx = context.context
+ if not isinstance(ctx, dict):
+ return
+ bus = ctx.get("bus")
+ agent_id = ctx.get("agent_id")
+ if bus is not None and agent_id is not None:
+ await bus.record_usage(agent_id, getattr(response, "usage", None))
+ ctx["turn_count"] = int(ctx.get("turn_count", 0)) + 1
+ except Exception:
+ logger.exception("on_llm_end failed")
+
+ async def on_agent_start(
+ self,
+ context: AgentHookContext[Any],
+ agent: Any,
+ ) -> None:
+ try:
+ cap = next(
+ (
+ c
+ for c in (getattr(agent, "capabilities", None) or [])
+ if hasattr(c, "_healthcheck_task")
+ ),
+ None,
+ )
+ if cap is not None and getattr(cap, "_healthcheck_task", None) is not None:
+ await cap._healthcheck_task
+ except Exception:
+ logger.exception("on_agent_start failed")
+
+ async def on_agent_end(
+ self,
+ context: AgentHookContext[Any],
+ agent: Any,
+ output: Any,
+ ) -> None:
+ try:
+ ctx = context.context
+ if not isinstance(ctx, dict):
+ return
+ bus = ctx.get("bus")
+ me = ctx.get("agent_id")
+ if bus is None or me is None:
+ return
+ crashed = (output is None) or not ctx.get("agent_finish_called", False)
+ parent = bus.parent_of.get(me)
+ if crashed and parent is not None:
+ await bus.send(
+ parent,
+ {
+ "from": me,
+ "content": (
+ f""
+ "Agent terminated without calling agent_finish. "
+ "Stop waiting on this child."
+ ""
+ ),
+ "type": "crash",
+ },
+ )
+ await bus.finalize(me, "crashed" if crashed else "completed")
+ except Exception:
+ logger.exception("on_agent_end failed")
+
+ async def on_tool_start(
+ self,
+ context: RunContextWrapper[Any],
+ agent: Any,
+ tool: Any,
+ ) -> None:
+ try:
+ ctx = context.context
+ if not isinstance(ctx, dict):
+ return
+ tracer = ctx.get("tracer")
+ if tracer is not None and hasattr(tracer, "log_tool_start"):
+ tracer.log_tool_start(ctx.get("agent_id", "?"), tool.name)
+ except Exception:
+ logger.exception("on_tool_start failed")
+
+ async def on_tool_end(
+ self,
+ context: RunContextWrapper[Any],
+ agent: Any,
+ tool: Any,
+ result: str,
+ ) -> None:
+ try:
+ ctx = context.context
+ if not isinstance(ctx, dict):
+ return
+ if tool.name in ("agent_finish", "finish_scan"):
+ ctx["agent_finish_called"] = True
+ tracer = ctx.get("tracer")
+ if tracer is not None and hasattr(tracer, "log_tool_end"):
+ tracer.log_tool_end(ctx.get("agent_id", "?"), tool.name, result)
+ except Exception:
+ logger.exception("on_tool_end failed")
+
+ async def on_handoff(
+ self,
+ context: RunContextWrapper[Any],
+ from_agent: Any,
+ to_agent: Any,
+ ) -> None:
+ # Strix multi-agent goes through the bus; SDK handoffs are unused.
+ pass
diff --git a/strix/runtime/strix_docker_client.py b/strix/runtime/strix_docker_client.py
new file mode 100644
index 0000000..b8de205
--- /dev/null
+++ b/strix/runtime/strix_docker_client.py
@@ -0,0 +1,108 @@
+"""StrixDockerSandboxClient — adds NET_ADMIN/NET_RAW capabilities + host-gateway.
+
+The SDK's ``DockerSandboxClient._create_container`` does not expose a hook for
+extending ``create_kwargs`` before ``containers.create`` is called. We subclass
+and reimplement the method body verbatim from the SDK source, with two
+additions before the final create call:
+
+ create_kwargs.setdefault("cap_add", []).extend(["NET_ADMIN", "NET_RAW"])
+ create_kwargs.setdefault("extra_hosts", {})["host.docker.internal"] = "host-gateway"
+
+These are required for raw-socket pentest tools (nmap -sS) and for letting
+the agent reach host-served apps via ``host.docker.internal``.
+
+Pinned to ``openai-agents==0.14.6``. Bumping the SDK version requires
+re-merging the parent body. Track upstream PR for an injection hook.
+
+References:
+ - PLAYBOOK.md §2.2
+ - AUDIT.md §2.3 (C3 — original blocker)
+ - SDK source: ``/tmp/openai-agents/src/agents/sandbox/sandboxes/docker.py:1434-1477``
+"""
+
+from __future__ import annotations
+
+import uuid
+from typing import Any
+
+from agents.sandbox.manifest import Manifest
+from agents.sandbox.sandboxes.docker import (
+ DockerSandboxClient,
+ _build_docker_volume_mounts,
+ _docker_port_key,
+ _manifest_requires_fuse,
+ _manifest_requires_sys_admin,
+)
+from docker.models.containers import Container # type: ignore[import-untyped, unused-ignore]
+from docker.utils import parse_repository_tag # type: ignore[import-untyped, unused-ignore]
+
+
+class StrixDockerSandboxClient(DockerSandboxClient):
+ """``DockerSandboxClient`` subclass that injects Strix-required capabilities.
+
+ Only ``_create_container`` is overridden. All other behavior — image
+ management, session lifecycle, port resolution, cleanup — is inherited.
+ """
+
+ async def _create_container(
+ self,
+ image: str,
+ *,
+ manifest: Manifest | None = None,
+ exposed_ports: tuple[int, ...] = (),
+ session_id: uuid.UUID | None = None,
+ ) -> Container:
+ # ----- BEGIN VERBATIM COPY of DockerSandboxClient._create_container -----
+ # SDK ref: src/agents/sandbox/sandboxes/docker.py:1434-1477 (v0.14.6).
+ if not self.image_exists(image):
+ repo, tag = parse_repository_tag(image)
+ self.docker_client.images.pull(repo, tag=tag or None, all_tags=False)
+
+ assert self.image_exists(image)
+ environment: dict[str, str] | None = None
+ if manifest:
+ environment = await manifest.environment.resolve()
+ create_kwargs: dict[str, Any] = {
+ "entrypoint": ["tail"],
+ "image": image,
+ "detach": True,
+ "command": ["-f", "/dev/null"],
+ "environment": environment,
+ }
+ if manifest is not None:
+ docker_mounts = _build_docker_volume_mounts(
+ manifest,
+ session_id=session_id,
+ )
+ if docker_mounts:
+ create_kwargs["mounts"] = docker_mounts
+ if _manifest_requires_fuse(manifest):
+ create_kwargs.update(
+ devices=["/dev/fuse"],
+ cap_add=["SYS_ADMIN"],
+ security_opt=["apparmor:unconfined"],
+ )
+ elif _manifest_requires_sys_admin(manifest):
+ create_kwargs.update(
+ cap_add=["SYS_ADMIN"],
+ security_opt=["apparmor:unconfined"],
+ )
+ if exposed_ports:
+ create_kwargs["ports"] = {
+ _docker_port_key(port): ("127.0.0.1", None) for port in exposed_ports
+ }
+ # ----- END VERBATIM COPY -----
+
+ # Strix injections — append, don't overwrite, so FUSE/SYS_ADMIN survives.
+ cap_add = create_kwargs.setdefault("cap_add", [])
+ if not isinstance(cap_add, list): # defensive — parent always sets list
+ cap_add = list(cap_add)
+ create_kwargs["cap_add"] = cap_add
+ for cap in ("NET_ADMIN", "NET_RAW"):
+ if cap not in cap_add:
+ cap_add.append(cap)
+
+ extra_hosts = create_kwargs.setdefault("extra_hosts", {})
+ extra_hosts["host.docker.internal"] = "host-gateway"
+
+ return self.docker_client.containers.create(**create_kwargs)
diff --git a/strix/sandbox/__init__.py b/strix/sandbox/__init__.py
new file mode 100644
index 0000000..d8ade2b
--- /dev/null
+++ b/strix/sandbox/__init__.py
@@ -0,0 +1,7 @@
+"""Strix sandbox layer on top of OpenAI Agents SDK SandboxAgent / Manifest.
+
+Phase 4 deliverables:
+- CaidoCapability: Caido proxy + 7 GraphQL function tools + system prompt block
+- healthcheck: wait_for_ports_ready
+- session_manager: create_or_reuse / cleanup keyed by scan_id
+"""
diff --git a/strix/tools/_decorator.py b/strix/tools/_decorator.py
new file mode 100644
index 0000000..92accf2
--- /dev/null
+++ b/strix/tools/_decorator.py
@@ -0,0 +1,64 @@
+"""strix_tool — function_tool factory with Strix defaults.
+
+Every tool in the migrated harness should be decorated with ``@strix_tool``
+instead of bare ``@function_tool`` so the team's defaults stay consistent
+without per-tool boilerplate. Override per call when needed.
+
+Defaults:
+ - ``timeout``: 120s (matches the legacy tool server's
+ ``STRIX_SANDBOX_EXECUTION_TIMEOUT``).
+ - ``timeout_behavior``: ``"error_as_result"`` for idempotent tools.
+ Critical sandbox tools (terminal, browser, python) should pass
+ ``timeout_behavior="raise_exception"`` explicitly so the SDK can fail
+ the run rather than letting the model retry the same hung call (C20).
+
+The SDK auto-threads sync function bodies via ``asyncio.to_thread``
+(``tool.py:1820-1829``), so libtmux / IPython / blocking httpx code can be
+written as plain ``def`` and the decorator will not block the event loop.
+
+References:
+ - PLAYBOOK.md §2.6
+ - AUDIT_R3.md C20 (per-tool timeout_behavior discrimination)
+"""
+
+from __future__ import annotations
+
+from collections.abc import Callable
+from typing import Any, Literal
+
+from agents import function_tool
+from agents.tool import FunctionTool
+
+
+_ToolFn = Callable[..., Any]
+_ToolBehavior = Literal["error_as_result", "raise_exception"]
+
+
+def strix_tool(
+ *,
+ timeout: float = 120.0,
+ timeout_behavior: _ToolBehavior = "error_as_result",
+ name_override: str | None = None,
+ description_override: str | None = None,
+) -> Callable[[_ToolFn], FunctionTool]:
+ """Wrap ``agents.function_tool`` with Strix defaults.
+
+ The SDK's ``FunctionTool`` requires ``async def`` for ``timeout_seconds``
+ to apply (sync handlers cannot be cleanly cancelled). All Strix tools are
+ ``async def``; sync libraries (libtmux, IPython) get wrapped in
+ ``asyncio.to_thread`` inside the async tool body.
+
+ Usage::
+
+ @strix_tool()
+ async def my_tool(ctx: RunContextWrapper, x: int) -> str: ...
+
+ @strix_tool(timeout=300, timeout_behavior="raise_exception")
+ async def critical_tool(ctx: RunContextWrapper, ...) -> str: ...
+ """
+ return function_tool(
+ timeout=timeout,
+ timeout_behavior=timeout_behavior,
+ name_override=name_override,
+ description_override=description_override,
+ )
diff --git a/tests/llm/test_anthropic_cache_wrapper.py b/tests/llm/test_anthropic_cache_wrapper.py
new file mode 100644
index 0000000..d2f1350
--- /dev/null
+++ b/tests/llm/test_anthropic_cache_wrapper.py
@@ -0,0 +1,104 @@
+"""Phase 0 smoke tests for AnthropicCachingLitellmModel."""
+
+from __future__ import annotations
+
+import pytest
+
+from strix.llm.anthropic_cache_wrapper import AnthropicCachingLitellmModel
+
+
+def _make(model: str, **kwargs: object) -> AnthropicCachingLitellmModel:
+ # ``LitellmModel.__init__`` only validates that model is a string; we
+ # don't need a real API key for in-memory ``_patch`` testing.
+ return AnthropicCachingLitellmModel(model=model, api_key="test-key", **kwargs)
+
+
+def test_is_anthropic_detects_anthropic_prefix() -> None:
+ m = _make("anthropic/claude-3-5-sonnet")
+ assert m._is_anthropic() is True
+
+
+def test_is_anthropic_detects_claude_substring() -> None:
+ m = _make("openrouter/anthropic-claude-haiku")
+ assert m._is_anthropic() is True
+
+
+def test_is_anthropic_false_for_openai() -> None:
+ m = _make("openai/gpt-4o")
+ assert m._is_anthropic() is False
+
+
+def test_is_anthropic_false_for_gemini() -> None:
+ m = _make("gemini/gemini-1.5-pro")
+ assert m._is_anthropic() is False
+
+
+def test_explicit_override_true_wins() -> None:
+ """For Strix proxy routing where api_model is openai/ but
+ canonical is Anthropic, the override forces cache injection."""
+ m = _make("openai/claude-sonnet-4.6", is_anthropic_override=True)
+ assert m._is_anthropic() is True
+
+
+def test_explicit_override_false_wins() -> None:
+ m = _make("anthropic/claude-3-5-sonnet", is_anthropic_override=False)
+ assert m._is_anthropic() is False
+
+
+def test_patch_anthropic_adds_cache_control_to_system() -> None:
+ m = _make("anthropic/claude-3-5-sonnet")
+ items: list = [
+ {"role": "system", "content": "You are a helpful agent."},
+ {"role": "user", "content": "hi"},
+ ]
+ out = m._patch(items)
+ assert out[0]["role"] == "system"
+ content = out[0]["content"]
+ assert isinstance(content, list)
+ assert content[0]["type"] == "text"
+ assert content[0]["text"] == "You are a helpful agent."
+ assert content[0]["cache_control"] == {"type": "ephemeral"}
+ # Second item passes through unchanged.
+ assert out[1] == {"role": "user", "content": "hi"}
+
+
+def test_patch_non_anthropic_passes_through() -> None:
+ m = _make("openai/gpt-4o")
+ items: list = [
+ {"role": "system", "content": "You are a helpful agent."},
+ {"role": "user", "content": "hi"},
+ ]
+ assert m._patch(items) is items # exact same list reference, no copy
+
+
+def test_patch_skips_non_string_system_content() -> None:
+ """If system content is already structured (e.g., previously patched),
+ don't re-wrap — pass through unchanged."""
+ m = _make("anthropic/claude-3-5-sonnet")
+ items: list = [
+ {"role": "system", "content": [{"type": "text", "text": "x"}]},
+ {"role": "user", "content": "hi"},
+ ]
+ out = m._patch(items)
+ assert out[0]["content"] == [{"type": "text", "text": "x"}]
+
+
+def test_patch_handles_empty_list() -> None:
+ m = _make("anthropic/claude-3-5-sonnet")
+ assert m._patch([]) == []
+
+
+@pytest.mark.parametrize(
+ "model",
+ [
+ "openai/claude-sonnet-4.6", # Strix proxy with Anthropic underneath
+ "openai/gpt-5.4", # Strix proxy with OpenAI underneath
+ ],
+)
+def test_strix_proxy_routing_with_override(model: str) -> None:
+ """Strix proxy uses openai/ for the API URL but the underlying
+ provider varies. The override flag is the source of truth."""
+ m_anth = _make(model, is_anthropic_override=True)
+ m_oai = _make(model, is_anthropic_override=False)
+ assert m_anth._is_anthropic() is True
+ assert m_oai._is_anthropic() is False
diff --git a/tests/llm/test_multi_provider_setup.py b/tests/llm/test_multi_provider_setup.py
new file mode 100644
index 0000000..d894678
--- /dev/null
+++ b/tests/llm/test_multi_provider_setup.py
@@ -0,0 +1,64 @@
+"""Phase 0 smoke tests for multi_provider_setup."""
+
+from __future__ import annotations
+
+import pytest
+from agents.exceptions import UserError
+from agents.extensions.models.litellm_model import LitellmModel
+
+from strix.config.config import STRIX_API_BASE
+from strix.llm.anthropic_cache_wrapper import AnthropicCachingLitellmModel
+from strix.llm.multi_provider_setup import (
+ LitellmAnthropicProvider,
+ StrixModelProvider,
+ build_multi_provider,
+)
+
+
+def test_strix_provider_resolves_anthropic_alias_with_override() -> None:
+ provider = StrixModelProvider()
+ model = provider.get_model("claude-sonnet-4.6")
+ assert isinstance(model, AnthropicCachingLitellmModel)
+ # Goes via Strix proxy as openai/, but is_anthropic still True.
+ assert model.model == "openai/claude-sonnet-4.6"
+ assert str(model.base_url) == STRIX_API_BASE
+ assert model._is_anthropic() is True
+
+
+def test_strix_provider_resolves_openai_alias_without_override() -> None:
+ provider = StrixModelProvider()
+ model = provider.get_model("gpt-5.4")
+ # Plain LitellmModel, NOT the caching subclass.
+ assert isinstance(model, LitellmModel)
+ assert not isinstance(model, AnthropicCachingLitellmModel)
+ assert model.model == "openai/gpt-5.4"
+
+
+def test_strix_provider_unknown_alias_raises_user_error() -> None:
+ """C17 (AUDIT_R3): unknown alias must surface a clear error with valid options."""
+ provider = StrixModelProvider()
+ with pytest.raises(UserError, match="Unknown Strix model alias"):
+ provider.get_model("typo-model-name")
+
+
+def test_strix_provider_empty_name_raises() -> None:
+ provider = StrixModelProvider()
+ with pytest.raises(UserError, match="non-empty"):
+ provider.get_model(None)
+
+
+def test_litellm_anthropic_provider_wraps_in_caching_model() -> None:
+ provider = LitellmAnthropicProvider()
+ model = provider.get_model("claude-3-5-sonnet-20241022")
+ assert isinstance(model, AnthropicCachingLitellmModel)
+ assert model.model == "anthropic/claude-3-5-sonnet-20241022"
+ assert model._is_anthropic() is True
+
+
+def test_build_multi_provider_registers_strix_prefix() -> None:
+ mp = build_multi_provider()
+ # The MultiProvider stores the map; the easiest check is that resolving
+ # "strix/claude-sonnet-4.6" goes through StrixModelProvider.
+ model = mp.get_model("strix/claude-sonnet-4.6")
+ assert isinstance(model, AnthropicCachingLitellmModel)
+ assert model.model == "openai/claude-sonnet-4.6"
diff --git a/tests/orchestration/__init__.py b/tests/orchestration/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/orchestration/test_bus.py b/tests/orchestration/test_bus.py
new file mode 100644
index 0000000..6ccc621
--- /dev/null
+++ b/tests/orchestration/test_bus.py
@@ -0,0 +1,195 @@
+"""Phase 0 smoke tests for AgentMessageBus."""
+
+from __future__ import annotations
+
+import asyncio
+
+import pytest
+
+from strix.orchestration.bus import AgentMessageBus
+
+
+@pytest.fixture
+def bus() -> AgentMessageBus:
+ return AgentMessageBus()
+
+
+@pytest.mark.asyncio
+async def test_register_records_agent(bus: AgentMessageBus) -> None:
+ await bus.register("a1", "alpha", parent_id=None)
+ assert bus.statuses["a1"] == "running"
+ assert bus.parent_of["a1"] is None
+ assert bus.names["a1"] == "alpha"
+ assert bus.inboxes["a1"] == []
+ assert bus.stats_live["a1"]["calls"] == 0
+
+
+@pytest.mark.asyncio
+async def test_send_and_drain_fifo(bus: AgentMessageBus) -> None:
+ await bus.register("a1", "alpha", parent_id=None)
+ await bus.send("a1", {"from": "b", "content": "first"})
+ await bus.send("a1", {"from": "c", "content": "second"})
+ drained = await bus.drain("a1")
+ assert [m["content"] for m in drained] == ["first", "second"]
+ assert await bus.drain("a1") == []
+
+
+@pytest.mark.asyncio
+async def test_send_to_unknown_agent_is_dropped(bus: AgentMessageBus) -> None:
+ await bus.send("ghost", {"from": "user", "content": "x"})
+ assert "ghost" not in bus.inboxes
+
+
+@pytest.mark.asyncio
+async def test_finalize_clears_inbox_parent_name(bus: AgentMessageBus) -> None:
+ """C13 (AUDIT_R3): finalize cleans up routing state to avoid orphan messages."""
+ await bus.register("a1", "alpha", parent_id=None)
+ await bus.register("a2", "beta", parent_id="a1")
+ await bus.send("a1", {"from": "a2", "content": "hi"})
+ await bus.finalize("a1", "completed")
+ # Inbox / parent / name removed so siblings can't accidentally re-fill.
+ assert "a1" not in bus.inboxes
+ assert "a1" not in bus.parent_of
+ assert "a1" not in bus.names
+ # Status remains for diagnostics.
+ assert bus.statuses["a1"] == "completed"
+ # Messages sent to a finalized agent are dropped silently.
+ await bus.send("a1", {"from": "a2", "content": "ignored"})
+ assert "a1" not in bus.inboxes
+
+
+@pytest.mark.asyncio
+async def test_record_usage_aggregates(bus: AgentMessageBus) -> None:
+ await bus.register("a1", "alpha", parent_id=None)
+
+ class _Details:
+ cached_tokens = 10
+
+ class _Usage:
+ input_tokens = 100
+ output_tokens = 50
+ input_tokens_details = _Details()
+
+ await bus.record_usage("a1", _Usage())
+ await bus.record_usage("a1", _Usage())
+ stats = bus.stats_live["a1"]
+ assert stats["in"] == 200
+ assert stats["out"] == 100
+ assert stats["cached"] == 20
+ assert stats["calls"] == 2
+
+
+@pytest.mark.asyncio
+async def test_record_usage_handles_none(bus: AgentMessageBus) -> None:
+ await bus.register("a1", "alpha", parent_id=None)
+ await bus.record_usage("a1", None)
+ assert bus.stats_live["a1"]["calls"] == 0
+
+
+@pytest.mark.asyncio
+async def test_total_stats_snapshot(bus: AgentMessageBus) -> None:
+ """C12 (AUDIT_R2): total_stats acquires the lock for a consistent snapshot."""
+ await bus.register("a1", "alpha", parent_id=None)
+ await bus.register("a2", "beta", parent_id="a1")
+
+ class _Details:
+ cached_tokens = 5
+
+ class _Usage:
+ input_tokens = 10
+ output_tokens = 20
+ input_tokens_details = _Details()
+
+ await bus.record_usage("a1", _Usage())
+ await bus.record_usage("a2", _Usage())
+ await bus.finalize("a2", "completed")
+
+ totals = await bus.total_stats()
+ assert totals["in"] == 20
+ assert totals["out"] == 40
+ assert totals["cached"] == 10
+ assert totals["calls"] == 2
+
+
+@pytest.mark.asyncio
+async def test_concurrent_send_drain_no_lost_messages() -> None:
+ bus = AgentMessageBus()
+ await bus.register("a1", "alpha", parent_id=None)
+
+ async def producer(start: int, count: int) -> None:
+ for i in range(count):
+ await bus.send("a1", {"from": "p", "content": str(start + i)})
+
+ # 50 producers x 20 messages = 1000 messages; drain in 1 reader.
+ producers = [asyncio.create_task(producer(i * 20, 20)) for i in range(50)]
+ await asyncio.gather(*producers)
+ drained = await bus.drain("a1")
+ assert len(drained) == 1000
+
+
+@pytest.mark.asyncio
+async def test_cancel_descendants_cancels_whole_tree() -> None:
+ """C9 (AUDIT_R2): cancel_descendants cancels every transitive child."""
+ bus = AgentMessageBus()
+ await bus.register("root", "root", parent_id=None)
+ await bus.register("child1", "c1", parent_id="root")
+ await bus.register("grandchild1", "g1", parent_id="child1")
+ await bus.register("child2", "c2", parent_id="root")
+
+ pending = asyncio.get_event_loop().create_future()
+
+ async def fake_run() -> None:
+ await pending # block until cancelled
+
+ for aid in ("root", "child1", "grandchild1", "child2"):
+ bus.tasks[aid] = asyncio.create_task(fake_run())
+
+ await bus.cancel_descendants("root")
+
+ for aid in ("root", "child1", "grandchild1", "child2"):
+ assert bus.tasks[aid].cancelled() or bus.tasks[aid].done()
+
+
+@pytest.mark.asyncio
+async def test_cancel_descendants_triggers_leaves_before_root() -> None:
+ """C9: explicit ordering check — leaves' .cancel() called before root's."""
+ bus = AgentMessageBus()
+ await bus.register("root", "root", parent_id=None)
+ await bus.register("child1", "c1", parent_id="root")
+ await bus.register("grandchild1", "g1", parent_id="child1")
+
+ cancel_call_order: list[str] = []
+ pending = asyncio.get_event_loop().create_future()
+
+ class _RecordingTask:
+ """Wrap a real Task; record the moment .cancel() is invoked."""
+
+ def __init__(self, name: str, task: asyncio.Task) -> None:
+ self._name = name
+ self._task = task
+
+ def done(self) -> bool:
+ return self._task.done()
+
+ def cancelled(self) -> bool:
+ return self._task.cancelled()
+
+ def cancel(self, *args: object, **kwargs: object) -> bool:
+ cancel_call_order.append(self._name)
+ return self._task.cancel()
+
+ def __await__(self):
+ return self._task.__await__()
+
+ async def fake_run() -> None:
+ await pending
+
+ for aid in ("root", "child1", "grandchild1"):
+ real = asyncio.create_task(fake_run())
+ bus.tasks[aid] = _RecordingTask(aid, real) # type: ignore[assignment]
+
+ await bus.cancel_descendants("root")
+
+ # grandchild and child must have .cancel() called before root.
+ assert cancel_call_order.index("grandchild1") < cancel_call_order.index("root")
+ assert cancel_call_order.index("child1") < cancel_call_order.index("root")
diff --git a/tests/orchestration/test_filter.py b/tests/orchestration/test_filter.py
new file mode 100644
index 0000000..169e44e
--- /dev/null
+++ b/tests/orchestration/test_filter.py
@@ -0,0 +1,95 @@
+"""Phase 0 smoke tests for inject_messages_filter."""
+
+from __future__ import annotations
+
+from dataclasses import dataclass
+from typing import Any
+
+import pytest
+from agents.run_config import CallModelData, ModelInputData
+
+from strix.orchestration.bus import AgentMessageBus
+from strix.orchestration.filter import inject_messages_filter
+
+
+@dataclass
+class _FakeAgent:
+ name: str = "agent"
+
+
+def _call_data(
+ context: Any,
+ items: list[Any],
+ instructions: str | None = "system",
+) -> CallModelData[Any]:
+ return CallModelData(
+ model_data=ModelInputData(input=items, instructions=instructions),
+ agent=_FakeAgent(),
+ context=context,
+ )
+
+
+@pytest.mark.asyncio
+async def test_empty_inbox_passes_through() -> None:
+ bus = AgentMessageBus()
+ await bus.register("a1", "alpha", parent_id=None)
+ data = _call_data({"bus": bus, "agent_id": "a1"}, [{"role": "user", "content": "x"}])
+
+ out = await inject_messages_filter(data)
+
+ assert out.input == [{"role": "user", "content": "x"}]
+ assert out.instructions == "system"
+
+
+@pytest.mark.asyncio
+async def test_pending_messages_appended_in_order() -> None:
+ bus = AgentMessageBus()
+ await bus.register("a1", "alpha", parent_id=None)
+ await bus.send("a1", {"from": "b", "content": "hello", "type": "info", "priority": "normal"})
+ await bus.send("a1", {"from": "c", "content": "second", "type": "info", "priority": "high"})
+ data = _call_data({"bus": bus, "agent_id": "a1"}, [{"role": "user", "content": "task"}])
+
+ out = await inject_messages_filter(data)
+
+ assert len(out.input) == 3
+ assert out.input[0] == {"role": "user", "content": "task"}
+ assert " None:
+ bus = AgentMessageBus()
+ await bus.register("a1", "alpha", parent_id=None)
+ await bus.send("a1", {"from": "user", "content": "follow-up question"})
+ data = _call_data({"bus": bus, "agent_id": "a1"}, [])
+
+ out = await inject_messages_filter(data)
+
+ assert out.input == [{"role": "user", "content": "follow-up question"}]
+
+
+@pytest.mark.asyncio
+async def test_no_bus_in_context_passes_through() -> None:
+ data = _call_data({"agent_id": "a1"}, [{"role": "user", "content": "x"}])
+ out = await inject_messages_filter(data)
+ assert out.input == [{"role": "user", "content": "x"}]
+
+
+@pytest.mark.asyncio
+async def test_filter_exception_returns_unmodified() -> None:
+ """C14 (AUDIT_R3): filter exception is caught; original data returned."""
+
+ class _BrokenBus:
+ async def drain(self, _: str) -> list[dict[str, Any]]:
+ raise RuntimeError("simulated bug")
+
+ data = _call_data(
+ {"bus": _BrokenBus(), "agent_id": "a1"},
+ [{"role": "user", "content": "still works"}],
+ )
+
+ out = await inject_messages_filter(data)
+ assert out.input == [{"role": "user", "content": "still works"}]
diff --git a/tests/orchestration/test_hooks.py b/tests/orchestration/test_hooks.py
new file mode 100644
index 0000000..08d9b05
--- /dev/null
+++ b/tests/orchestration/test_hooks.py
@@ -0,0 +1,173 @@
+"""Phase 0 smoke tests for StrixOrchestrationHooks."""
+
+from __future__ import annotations
+
+from dataclasses import dataclass, field
+from typing import Any
+
+import pytest
+
+from strix.orchestration.bus import AgentMessageBus
+from strix.orchestration.hooks import StrixOrchestrationHooks
+
+
+@dataclass
+class _Ctx:
+ """Minimal stand-in for RunContextWrapper / AgentHookContext.
+
+ Only ``.context`` is exercised by the hooks under test; SDK's real wrappers
+ expose much more, but the hooks treat ``.context`` as the dict we put in.
+ """
+
+ context: dict[str, Any] = field(default_factory=dict)
+
+
+@dataclass
+class _Tool:
+ name: str
+
+
+class _FakeTracer:
+ def __init__(self) -> None:
+ self.starts: list[tuple[str, str]] = []
+ self.ends: list[tuple[str, str, Any]] = []
+
+ def log_tool_start(self, agent_id: str, tool_name: str) -> None:
+ self.starts.append((agent_id, tool_name))
+
+ def log_tool_end(self, agent_id: str, tool_name: str, result: Any) -> None:
+ self.ends.append((agent_id, tool_name, result))
+
+
+@pytest.mark.asyncio
+async def test_on_llm_start_injects_85_percent_warning() -> None:
+ hooks = StrixOrchestrationHooks()
+ items: list[Any] = []
+ ctx = _Ctx(context={"max_turns": 100, "turn_count": 85})
+ await hooks.on_llm_start(ctx, agent=None, system_prompt="x", input_items=items)
+ assert len(items) == 1
+ assert "85%" in items[0]["content"]
+
+
+@pytest.mark.asyncio
+async def test_on_llm_start_injects_n_minus_3_warning() -> None:
+ hooks = StrixOrchestrationHooks()
+ items: list[Any] = []
+ ctx = _Ctx(context={"max_turns": 100, "turn_count": 97})
+ await hooks.on_llm_start(ctx, agent=None, system_prompt="x", input_items=items)
+ assert len(items) == 1
+ assert "3 iterations left" in items[0]["content"]
+
+
+@pytest.mark.asyncio
+async def test_on_llm_start_no_warning_at_other_turns() -> None:
+ hooks = StrixOrchestrationHooks()
+ items: list[Any] = []
+ ctx = _Ctx(context={"max_turns": 100, "turn_count": 50})
+ await hooks.on_llm_start(ctx, agent=None, system_prompt="x", input_items=items)
+ assert items == []
+
+
+@pytest.mark.asyncio
+async def test_on_llm_end_records_usage_and_increments_turn() -> None:
+ hooks = StrixOrchestrationHooks()
+ bus = AgentMessageBus()
+ await bus.register("a1", "alpha", parent_id=None)
+ ctx = _Ctx(context={"bus": bus, "agent_id": "a1", "turn_count": 0})
+
+ class _Details:
+ cached_tokens = 5
+
+ class _Usage:
+ input_tokens = 10
+ output_tokens = 20
+ input_tokens_details = _Details()
+
+ class _Resp:
+ usage = _Usage()
+
+ await hooks.on_llm_end(ctx, agent=None, response=_Resp())
+ assert ctx.context["turn_count"] == 1
+ assert bus.stats_live["a1"]["in"] == 10
+
+
+@pytest.mark.asyncio
+async def test_on_agent_end_detects_crash() -> None:
+ """C8 (AUDIT_R2): on_agent_end without agent_finish_called posts crash to parent."""
+ hooks = StrixOrchestrationHooks()
+ bus = AgentMessageBus()
+ await bus.register("root", "root", parent_id=None)
+ await bus.register("child", "specialist", parent_id="root")
+ ctx = _Ctx(context={"bus": bus, "agent_id": "child"})
+
+ await hooks.on_agent_end(ctx, agent=None, output=None) # crashed (output=None)
+
+ drained = await bus.drain("root")
+ assert len(drained) == 1
+ assert " None:
+ hooks = StrixOrchestrationHooks()
+ bus = AgentMessageBus()
+ await bus.register("root", "root", parent_id=None)
+ await bus.register("child", "specialist", parent_id="root")
+ ctx = _Ctx(
+ context={
+ "bus": bus,
+ "agent_id": "child",
+ "agent_finish_called": True,
+ }
+ )
+
+ await hooks.on_agent_end(ctx, agent=None, output="done")
+
+ assert await bus.drain("root") == []
+ assert bus.statuses["child"] == "completed"
+
+
+@pytest.mark.asyncio
+async def test_on_tool_end_marks_finish_called() -> None:
+ """When agent_finish or finish_scan returns, mark context flag for crash detection."""
+ hooks = StrixOrchestrationHooks()
+ ctx = _Ctx(context={"agent_id": "a1"})
+ await hooks.on_tool_end(ctx, agent=None, tool=_Tool("agent_finish"), result="ok")
+ assert ctx.context["agent_finish_called"] is True
+
+
+@pytest.mark.asyncio
+async def test_on_tool_end_other_tool_does_not_set_flag() -> None:
+ hooks = StrixOrchestrationHooks()
+ ctx = _Ctx(context={"agent_id": "a1"})
+ await hooks.on_tool_end(ctx, agent=None, tool=_Tool("terminal_execute"), result="x")
+ assert ctx.context.get("agent_finish_called") is None
+
+
+@pytest.mark.asyncio
+async def test_on_tool_start_logs_to_tracer() -> None:
+ hooks = StrixOrchestrationHooks()
+ tracer = _FakeTracer()
+ ctx = _Ctx(context={"tracer": tracer, "agent_id": "a1"})
+ await hooks.on_tool_start(ctx, agent=None, tool=_Tool("browser_action"))
+ assert tracer.starts == [("a1", "browser_action")]
+
+
+@pytest.mark.asyncio
+async def test_hook_exception_does_not_propagate() -> None:
+ """C15 (AUDIT_R3): a bug in the hook body must never tear down the run."""
+ hooks = StrixOrchestrationHooks()
+
+ class _BrokenBus:
+ async def record_usage(self, *_: Any, **__: Any) -> None:
+ raise RuntimeError("simulated")
+
+ ctx = _Ctx(context={"bus": _BrokenBus(), "agent_id": "a1"})
+
+ class _Resp:
+ usage = None
+
+ # Should not raise.
+ await hooks.on_llm_end(ctx, agent=None, response=_Resp())
diff --git a/tests/runtime/test_strix_docker_client.py b/tests/runtime/test_strix_docker_client.py
new file mode 100644
index 0000000..d65e1d0
--- /dev/null
+++ b/tests/runtime/test_strix_docker_client.py
@@ -0,0 +1,103 @@
+"""Phase 0 smoke tests for StrixDockerSandboxClient.
+
+These tests do NOT require Docker. They mock the Docker SDK client (passed
+to the constructor) and verify our subclass injects the right kwargs into
+``containers.create``. Live container tests are part of Phase 0 manual
+smoke (TESTING_STRATEGY.md §9).
+"""
+
+from __future__ import annotations
+
+import asyncio
+from typing import Any
+from unittest.mock import MagicMock
+
+import docker.errors # type: ignore[import-untyped,unused-ignore]
+import pytest
+
+from strix.runtime.strix_docker_client import StrixDockerSandboxClient
+
+
+@pytest.fixture
+def fake_docker() -> MagicMock:
+ """Stand-in for the Docker SDK client passed to the subclass."""
+ fake = MagicMock()
+ fake.images.get.return_value = MagicMock() # image_exists -> True
+ fake.images.pull = MagicMock()
+ fake.containers.create.return_value = MagicMock(name="container")
+ return fake
+
+
+def _create_kwargs(fake: MagicMock) -> dict[str, Any]:
+ result: dict[str, Any] = fake.containers.create.call_args.kwargs
+ return result
+
+
+def test_subclass_injects_net_admin_and_net_raw(fake_docker: MagicMock) -> None:
+ client = StrixDockerSandboxClient(docker_client=fake_docker)
+ asyncio.run(
+ client._create_container("strix-image:latest", manifest=None, exposed_ports=()),
+ )
+ kwargs = _create_kwargs(fake_docker)
+ assert "NET_ADMIN" in kwargs["cap_add"]
+ assert "NET_RAW" in kwargs["cap_add"]
+
+
+def test_subclass_injects_host_gateway(fake_docker: MagicMock) -> None:
+ client = StrixDockerSandboxClient(docker_client=fake_docker)
+ asyncio.run(
+ client._create_container("strix-image:latest", manifest=None, exposed_ports=()),
+ )
+ kwargs = _create_kwargs(fake_docker)
+ assert kwargs["extra_hosts"]["host.docker.internal"] == "host-gateway"
+
+
+def test_subclass_preserves_image_and_command(fake_docker: MagicMock) -> None:
+ client = StrixDockerSandboxClient(docker_client=fake_docker)
+ asyncio.run(
+ client._create_container("custom:tag", manifest=None, exposed_ports=()),
+ )
+ kwargs = _create_kwargs(fake_docker)
+ assert kwargs["image"] == "custom:tag"
+ assert kwargs["entrypoint"] == ["tail"]
+ assert kwargs["command"] == ["-f", "/dev/null"]
+ assert kwargs["detach"] is True
+
+
+def test_subclass_emits_ports_dict_for_exposed_ports(fake_docker: MagicMock) -> None:
+ client = StrixDockerSandboxClient(docker_client=fake_docker)
+ asyncio.run(
+ client._create_container(
+ "strix-image:latest",
+ manifest=None,
+ exposed_ports=(48081, 48080),
+ ),
+ )
+ kwargs = _create_kwargs(fake_docker)
+ assert "48081/tcp" in kwargs["ports"]
+ assert "48080/tcp" in kwargs["ports"]
+
+
+def test_caps_appended_not_duplicated(fake_docker: MagicMock) -> None:
+ """Idempotent injection: calling twice doesn't add duplicate caps."""
+ client = StrixDockerSandboxClient(docker_client=fake_docker)
+ asyncio.run(
+ client._create_container("img:latest", manifest=None, exposed_ports=()),
+ )
+ kwargs = _create_kwargs(fake_docker)
+ assert kwargs["cap_add"].count("NET_ADMIN") == 1
+ assert kwargs["cap_add"].count("NET_RAW") == 1
+
+
+def test_pulls_image_when_missing(fake_docker: MagicMock) -> None:
+ """If image_exists returns False on first check, pull is invoked."""
+ # First call raises ImageNotFound, second succeeds.
+ fake_docker.images.get.side_effect = [
+ docker.errors.ImageNotFound("not found"),
+ MagicMock(),
+ ]
+ client = StrixDockerSandboxClient(docker_client=fake_docker)
+ asyncio.run(
+ client._create_container("registry.io/strix:tag", manifest=None, exposed_ports=()),
+ )
+ fake_docker.images.pull.assert_called_once()
diff --git a/tests/static/__init__.py b/tests/static/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/tools/test_decorator.py b/tests/tools/test_decorator.py
new file mode 100644
index 0000000..dc73e34
--- /dev/null
+++ b/tests/tools/test_decorator.py
@@ -0,0 +1,73 @@
+"""Phase 0 smoke tests for the strix_tool decorator factory.
+
+The SDK's ``FunctionTool`` only honors ``timeout_seconds`` for ``async``
+handlers (verified at ``agents.tool._validate_function_tool_timeout_config``):
+sync function bodies cannot be cleanly cancelled, so the SDK refuses to
+attach a timeout to them. Every Strix tool is therefore an ``async def``;
+sync libraries (libtmux, IPython) get wrapped in ``asyncio.to_thread``
+inside the async tool body.
+"""
+
+from __future__ import annotations
+
+import pytest
+from agents.tool import FunctionTool
+
+from strix.tools._decorator import strix_tool
+
+
+def test_strix_tool_returns_function_tool() -> None:
+ @strix_tool()
+ async def my_tool(x: int) -> str:
+ """Do a thing."""
+ return str(x)
+
+ assert isinstance(my_tool, FunctionTool)
+
+
+def test_strix_tool_default_timeout_is_120s() -> None:
+ @strix_tool()
+ async def my_tool(x: int) -> str:
+ """Do a thing."""
+ return str(x)
+
+ assert my_tool.timeout_seconds == 120.0
+
+
+def test_strix_tool_default_timeout_behavior_is_error_as_result() -> None:
+ @strix_tool()
+ async def my_tool(x: int) -> str:
+ """Do a thing."""
+ return str(x)
+
+ assert my_tool.timeout_behavior == "error_as_result"
+
+
+def test_strix_tool_timeout_override() -> None:
+ @strix_tool(timeout=300)
+ async def my_tool(x: int) -> str:
+ """Do a thing."""
+ return str(x)
+
+ assert my_tool.timeout_seconds == 300.0
+
+
+def test_strix_tool_critical_tool_can_raise() -> None:
+ """C20 (AUDIT_R3): critical tools opt into raise_exception."""
+
+ @strix_tool(timeout=30, timeout_behavior="raise_exception")
+ async def critical_tool(x: int) -> str:
+ """Do a critical thing."""
+ return str(x)
+
+ assert critical_tool.timeout_behavior == "raise_exception"
+
+
+def test_strix_tool_sync_handlers_rejected_by_sdk() -> None:
+ """SDK explicitly rejects timeout on sync handlers; documenting the constraint."""
+ with pytest.raises(ValueError, match="async @function_tool"):
+
+ @strix_tool()
+ def my_sync_tool(x: int) -> str:
+ """Sync tools can't have a timeout in the SDK."""
+ return str(x)
diff --git a/uv.lock b/uv.lock
index 49138cb..d6c3487 100644
--- a/uv.lock
+++ b/uv.lock
@@ -24,7 +24,7 @@ wheels = [
[[package]]
name = "aiohttp"
-version = "3.13.3"
+version = "3.13.5"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "aiohappyeyeballs" },
@@ -35,76 +35,76 @@ dependencies = [
{ name = "propcache" },
{ name = "yarl" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/50/42/32cf8e7704ceb4481406eb87161349abb46a57fee3f008ba9cb610968646/aiohttp-3.13.3.tar.gz", hash = "sha256:a949eee43d3782f2daae4f4a2819b2cb9b0c5d3b7f7a927067cc84dafdbb9f88", size = 7844556, upload-time = "2026-01-03T17:33:05.204Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/77/9a/152096d4808df8e4268befa55fba462f440f14beab85e8ad9bf990516918/aiohttp-3.13.5.tar.gz", hash = "sha256:9d98cc980ecc96be6eb4c1994ce35d28d8b1f5e5208a23b421187d1209dbb7d1", size = 7858271, upload-time = "2026-03-31T22:01:03.343Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/a0/be/4fc11f202955a69e0db803a12a062b8379c970c7c84f4882b6da17337cc1/aiohttp-3.13.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:b903a4dfee7d347e2d87697d0713be59e0b87925be030c9178c5faa58ea58d5c", size = 739732, upload-time = "2026-01-03T17:30:14.23Z" },
- { url = "https://files.pythonhosted.org/packages/97/2c/621d5b851f94fa0bb7430d6089b3aa970a9d9b75196bc93bb624b0db237a/aiohttp-3.13.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a45530014d7a1e09f4a55f4f43097ba0fd155089372e105e4bff4ca76cb1b168", size = 494293, upload-time = "2026-01-03T17:30:15.96Z" },
- { url = "https://files.pythonhosted.org/packages/5d/43/4be01406b78e1be8320bb8316dc9c42dbab553d281c40364e0f862d5661c/aiohttp-3.13.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:27234ef6d85c914f9efeb77ff616dbf4ad2380be0cda40b4db086ffc7ddd1b7d", size = 493533, upload-time = "2026-01-03T17:30:17.431Z" },
- { url = "https://files.pythonhosted.org/packages/8d/a8/5a35dc56a06a2c90d4742cbf35294396907027f80eea696637945a106f25/aiohttp-3.13.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d32764c6c9aafb7fb55366a224756387cd50bfa720f32b88e0e6fa45b27dcf29", size = 1737839, upload-time = "2026-01-03T17:30:19.422Z" },
- { url = "https://files.pythonhosted.org/packages/bf/62/4b9eeb331da56530bf2e198a297e5303e1c1ebdceeb00fe9b568a65c5a0c/aiohttp-3.13.3-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b1a6102b4d3ebc07dad44fbf07b45bb600300f15b552ddf1851b5390202ea2e3", size = 1703932, upload-time = "2026-01-03T17:30:21.756Z" },
- { url = "https://files.pythonhosted.org/packages/7c/f6/af16887b5d419e6a367095994c0b1332d154f647e7dc2bd50e61876e8e3d/aiohttp-3.13.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c014c7ea7fb775dd015b2d3137378b7be0249a448a1612268b5a90c2d81de04d", size = 1771906, upload-time = "2026-01-03T17:30:23.932Z" },
- { url = "https://files.pythonhosted.org/packages/ce/83/397c634b1bcc24292fa1e0c7822800f9f6569e32934bdeef09dae7992dfb/aiohttp-3.13.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2b8d8ddba8f95ba17582226f80e2de99c7a7948e66490ef8d947e272a93e9463", size = 1871020, upload-time = "2026-01-03T17:30:26Z" },
- { url = "https://files.pythonhosted.org/packages/86/f6/a62cbbf13f0ac80a70f71b1672feba90fdb21fd7abd8dbf25c0105fb6fa3/aiohttp-3.13.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9ae8dd55c8e6c4257eae3a20fd2c8f41edaea5992ed67156642493b8daf3cecc", size = 1755181, upload-time = "2026-01-03T17:30:27.554Z" },
- { url = "https://files.pythonhosted.org/packages/0a/87/20a35ad487efdd3fba93d5843efdfaa62d2f1479eaafa7453398a44faf13/aiohttp-3.13.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:01ad2529d4b5035578f5081606a465f3b814c542882804e2e8cda61adf5c71bf", size = 1561794, upload-time = "2026-01-03T17:30:29.254Z" },
- { url = "https://files.pythonhosted.org/packages/de/95/8fd69a66682012f6716e1bc09ef8a1a2a91922c5725cb904689f112309c4/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bb4f7475e359992b580559e008c598091c45b5088f28614e855e42d39c2f1033", size = 1697900, upload-time = "2026-01-03T17:30:31.033Z" },
- { url = "https://files.pythonhosted.org/packages/e5/66/7b94b3b5ba70e955ff597672dad1691333080e37f50280178967aff68657/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:c19b90316ad3b24c69cd78d5c9b4f3aa4497643685901185b65166293d36a00f", size = 1728239, upload-time = "2026-01-03T17:30:32.703Z" },
- { url = "https://files.pythonhosted.org/packages/47/71/6f72f77f9f7d74719692ab65a2a0252584bf8d5f301e2ecb4c0da734530a/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:96d604498a7c782cb15a51c406acaea70d8c027ee6b90c569baa6e7b93073679", size = 1740527, upload-time = "2026-01-03T17:30:34.695Z" },
- { url = "https://files.pythonhosted.org/packages/fa/b4/75ec16cbbd5c01bdaf4a05b19e103e78d7ce1ef7c80867eb0ace42ff4488/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:084911a532763e9d3dd95adf78a78f4096cd5f58cdc18e6fdbc1b58417a45423", size = 1554489, upload-time = "2026-01-03T17:30:36.864Z" },
- { url = "https://files.pythonhosted.org/packages/52/8f/bc518c0eea29f8406dcf7ed1f96c9b48e3bc3995a96159b3fc11f9e08321/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:7a4a94eb787e606d0a09404b9c38c113d3b099d508021faa615d70a0131907ce", size = 1767852, upload-time = "2026-01-03T17:30:39.433Z" },
- { url = "https://files.pythonhosted.org/packages/9d/f2/a07a75173124f31f11ea6f863dc44e6f09afe2bca45dd4e64979490deab1/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:87797e645d9d8e222e04160ee32aa06bc5c163e8499f24db719e7852ec23093a", size = 1722379, upload-time = "2026-01-03T17:30:41.081Z" },
- { url = "https://files.pythonhosted.org/packages/3c/4a/1a3fee7c21350cac78e5c5cef711bac1b94feca07399f3d406972e2d8fcd/aiohttp-3.13.3-cp312-cp312-win32.whl", hash = "sha256:b04be762396457bef43f3597c991e192ee7da460a4953d7e647ee4b1c28e7046", size = 428253, upload-time = "2026-01-03T17:30:42.644Z" },
- { url = "https://files.pythonhosted.org/packages/d9/b7/76175c7cb4eb73d91ad63c34e29fc4f77c9386bba4a65b53ba8e05ee3c39/aiohttp-3.13.3-cp312-cp312-win_amd64.whl", hash = "sha256:e3531d63d3bdfa7e3ac5e9b27b2dd7ec9df3206a98e0b3445fa906f233264c57", size = 455407, upload-time = "2026-01-03T17:30:44.195Z" },
- { url = "https://files.pythonhosted.org/packages/97/8a/12ca489246ca1faaf5432844adbfce7ff2cc4997733e0af120869345643a/aiohttp-3.13.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:5dff64413671b0d3e7d5918ea490bdccb97a4ad29b3f311ed423200b2203e01c", size = 734190, upload-time = "2026-01-03T17:30:45.832Z" },
- { url = "https://files.pythonhosted.org/packages/32/08/de43984c74ed1fca5c014808963cc83cb00d7bb06af228f132d33862ca76/aiohttp-3.13.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:87b9aab6d6ed88235aa2970294f496ff1a1f9adcd724d800e9b952395a80ffd9", size = 491783, upload-time = "2026-01-03T17:30:47.466Z" },
- { url = "https://files.pythonhosted.org/packages/17/f8/8dd2cf6112a5a76f81f81a5130c57ca829d101ad583ce57f889179accdda/aiohttp-3.13.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:425c126c0dc43861e22cb1c14ba4c8e45d09516d0a3ae0a3f7494b79f5f233a3", size = 490704, upload-time = "2026-01-03T17:30:49.373Z" },
- { url = "https://files.pythonhosted.org/packages/6d/40/a46b03ca03936f832bc7eaa47cfbb1ad012ba1be4790122ee4f4f8cba074/aiohttp-3.13.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7f9120f7093c2a32d9647abcaf21e6ad275b4fbec5b55969f978b1a97c7c86bf", size = 1720652, upload-time = "2026-01-03T17:30:50.974Z" },
- { url = "https://files.pythonhosted.org/packages/f7/7e/917fe18e3607af92657e4285498f500dca797ff8c918bd7d90b05abf6c2a/aiohttp-3.13.3-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:697753042d57f4bf7122cab985bf15d0cef23c770864580f5af4f52023a56bd6", size = 1692014, upload-time = "2026-01-03T17:30:52.729Z" },
- { url = "https://files.pythonhosted.org/packages/71/b6/cefa4cbc00d315d68973b671cf105b21a609c12b82d52e5d0c9ae61d2a09/aiohttp-3.13.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6de499a1a44e7de70735d0b39f67c8f25eb3d91eb3103be99ca0fa882cdd987d", size = 1759777, upload-time = "2026-01-03T17:30:54.537Z" },
- { url = "https://files.pythonhosted.org/packages/fb/e3/e06ee07b45e59e6d81498b591fc589629be1553abb2a82ce33efe2a7b068/aiohttp-3.13.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:37239e9f9a7ea9ac5bf6b92b0260b01f8a22281996da609206a84df860bc1261", size = 1861276, upload-time = "2026-01-03T17:30:56.512Z" },
- { url = "https://files.pythonhosted.org/packages/7c/24/75d274228acf35ceeb2850b8ce04de9dd7355ff7a0b49d607ee60c29c518/aiohttp-3.13.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f76c1e3fe7d7c8afad7ed193f89a292e1999608170dcc9751a7462a87dfd5bc0", size = 1743131, upload-time = "2026-01-03T17:30:58.256Z" },
- { url = "https://files.pythonhosted.org/packages/04/98/3d21dde21889b17ca2eea54fdcff21b27b93f45b7bb94ca029c31ab59dc3/aiohttp-3.13.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fc290605db2a917f6e81b0e1e0796469871f5af381ce15c604a3c5c7e51cb730", size = 1556863, upload-time = "2026-01-03T17:31:00.445Z" },
- { url = "https://files.pythonhosted.org/packages/9e/84/da0c3ab1192eaf64782b03971ab4055b475d0db07b17eff925e8c93b3aa5/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4021b51936308aeea0367b8f006dc999ca02bc118a0cc78c303f50a2ff6afb91", size = 1682793, upload-time = "2026-01-03T17:31:03.024Z" },
- { url = "https://files.pythonhosted.org/packages/ff/0f/5802ada182f575afa02cbd0ec5180d7e13a402afb7c2c03a9aa5e5d49060/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:49a03727c1bba9a97d3e93c9f93ca03a57300f484b6e935463099841261195d3", size = 1716676, upload-time = "2026-01-03T17:31:04.842Z" },
- { url = "https://files.pythonhosted.org/packages/3f/8c/714d53bd8b5a4560667f7bbbb06b20c2382f9c7847d198370ec6526af39c/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3d9908a48eb7416dc1f4524e69f1d32e5d90e3981e4e37eb0aa1cd18f9cfa2a4", size = 1733217, upload-time = "2026-01-03T17:31:06.868Z" },
- { url = "https://files.pythonhosted.org/packages/7d/79/e2176f46d2e963facea939f5be2d26368ce543622be6f00a12844d3c991f/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:2712039939ec963c237286113c68dbad80a82a4281543f3abf766d9d73228998", size = 1552303, upload-time = "2026-01-03T17:31:08.958Z" },
- { url = "https://files.pythonhosted.org/packages/ab/6a/28ed4dea1759916090587d1fe57087b03e6c784a642b85ef48217b0277ae/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:7bfdc049127717581866fa4708791220970ce291c23e28ccf3922c700740fdc0", size = 1763673, upload-time = "2026-01-03T17:31:10.676Z" },
- { url = "https://files.pythonhosted.org/packages/e8/35/4a3daeb8b9fab49240d21c04d50732313295e4bd813a465d840236dd0ce1/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8057c98e0c8472d8846b9c79f56766bcc57e3e8ac7bfd510482332366c56c591", size = 1721120, upload-time = "2026-01-03T17:31:12.575Z" },
- { url = "https://files.pythonhosted.org/packages/bc/9f/d643bb3c5fb99547323e635e251c609fbbc660d983144cfebec529e09264/aiohttp-3.13.3-cp313-cp313-win32.whl", hash = "sha256:1449ceddcdbcf2e0446957863af03ebaaa03f94c090f945411b61269e2cb5daf", size = 427383, upload-time = "2026-01-03T17:31:14.382Z" },
- { url = "https://files.pythonhosted.org/packages/4e/f1/ab0395f8a79933577cdd996dd2f9aa6014af9535f65dddcf88204682fe62/aiohttp-3.13.3-cp313-cp313-win_amd64.whl", hash = "sha256:693781c45a4033d31d4187d2436f5ac701e7bbfe5df40d917736108c1cc7436e", size = 453899, upload-time = "2026-01-03T17:31:15.958Z" },
- { url = "https://files.pythonhosted.org/packages/99/36/5b6514a9f5d66f4e2597e40dea2e3db271e023eb7a5d22defe96ba560996/aiohttp-3.13.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:ea37047c6b367fd4bd632bff8077449b8fa034b69e812a18e0132a00fae6e808", size = 737238, upload-time = "2026-01-03T17:31:17.909Z" },
- { url = "https://files.pythonhosted.org/packages/f7/49/459327f0d5bcd8c6c9ca69e60fdeebc3622861e696490d8674a6d0cb90a6/aiohttp-3.13.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:6fc0e2337d1a4c3e6acafda6a78a39d4c14caea625124817420abceed36e2415", size = 492292, upload-time = "2026-01-03T17:31:19.919Z" },
- { url = "https://files.pythonhosted.org/packages/e8/0b/b97660c5fd05d3495b4eb27f2d0ef18dc1dc4eff7511a9bf371397ff0264/aiohttp-3.13.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c685f2d80bb67ca8c3837823ad76196b3694b0159d232206d1e461d3d434666f", size = 493021, upload-time = "2026-01-03T17:31:21.636Z" },
- { url = "https://files.pythonhosted.org/packages/54/d4/438efabdf74e30aeceb890c3290bbaa449780583b1270b00661126b8aae4/aiohttp-3.13.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48e377758516d262bde50c2584fc6c578af272559c409eecbdd2bae1601184d6", size = 1717263, upload-time = "2026-01-03T17:31:23.296Z" },
- { url = "https://files.pythonhosted.org/packages/71/f2/7bddc7fd612367d1459c5bcf598a9e8f7092d6580d98de0e057eb42697ad/aiohttp-3.13.3-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:34749271508078b261c4abb1767d42b8d0c0cc9449c73a4df494777dc55f0687", size = 1669107, upload-time = "2026-01-03T17:31:25.334Z" },
- { url = "https://files.pythonhosted.org/packages/00/5a/1aeaecca40e22560f97610a329e0e5efef5e0b5afdf9f857f0d93839ab2e/aiohttp-3.13.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:82611aeec80eb144416956ec85b6ca45a64d76429c1ed46ae1b5f86c6e0c9a26", size = 1760196, upload-time = "2026-01-03T17:31:27.394Z" },
- { url = "https://files.pythonhosted.org/packages/f8/f8/0ff6992bea7bd560fc510ea1c815f87eedd745fe035589c71ce05612a19a/aiohttp-3.13.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2fff83cfc93f18f215896e3a190e8e5cb413ce01553901aca925176e7568963a", size = 1843591, upload-time = "2026-01-03T17:31:29.238Z" },
- { url = "https://files.pythonhosted.org/packages/e3/d1/e30e537a15f53485b61f5be525f2157da719819e8377298502aebac45536/aiohttp-3.13.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bbe7d4cecacb439e2e2a8a1a7b935c25b812af7a5fd26503a66dadf428e79ec1", size = 1720277, upload-time = "2026-01-03T17:31:31.053Z" },
- { url = "https://files.pythonhosted.org/packages/84/45/23f4c451d8192f553d38d838831ebbc156907ea6e05557f39563101b7717/aiohttp-3.13.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b928f30fe49574253644b1ca44b1b8adbd903aa0da4b9054a6c20fc7f4092a25", size = 1548575, upload-time = "2026-01-03T17:31:32.87Z" },
- { url = "https://files.pythonhosted.org/packages/6a/ed/0a42b127a43712eda7807e7892c083eadfaf8429ca8fb619662a530a3aab/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7b5e8fe4de30df199155baaf64f2fcd604f4c678ed20910db8e2c66dc4b11603", size = 1679455, upload-time = "2026-01-03T17:31:34.76Z" },
- { url = "https://files.pythonhosted.org/packages/2e/b5/c05f0c2b4b4fe2c9d55e73b6d3ed4fd6c9dc2684b1d81cbdf77e7fad9adb/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:8542f41a62bcc58fc7f11cf7c90e0ec324ce44950003feb70640fc2a9092c32a", size = 1687417, upload-time = "2026-01-03T17:31:36.699Z" },
- { url = "https://files.pythonhosted.org/packages/c9/6b/915bc5dad66aef602b9e459b5a973529304d4e89ca86999d9d75d80cbd0b/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:5e1d8c8b8f1d91cd08d8f4a3c2b067bfca6ec043d3ff36de0f3a715feeedf926", size = 1729968, upload-time = "2026-01-03T17:31:38.622Z" },
- { url = "https://files.pythonhosted.org/packages/11/3b/e84581290a9520024a08640b63d07673057aec5ca548177a82026187ba73/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:90455115e5da1c3c51ab619ac57f877da8fd6d73c05aacd125c5ae9819582aba", size = 1545690, upload-time = "2026-01-03T17:31:40.57Z" },
- { url = "https://files.pythonhosted.org/packages/f5/04/0c3655a566c43fd647c81b895dfe361b9f9ad6d58c19309d45cff52d6c3b/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:042e9e0bcb5fba81886c8b4fbb9a09d6b8a00245fd8d88e4d989c1f96c74164c", size = 1746390, upload-time = "2026-01-03T17:31:42.857Z" },
- { url = "https://files.pythonhosted.org/packages/1f/53/71165b26978f719c3419381514c9690bd5980e764a09440a10bb816ea4ab/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2eb752b102b12a76ca02dff751a801f028b4ffbbc478840b473597fc91a9ed43", size = 1702188, upload-time = "2026-01-03T17:31:44.984Z" },
- { url = "https://files.pythonhosted.org/packages/29/a7/cbe6c9e8e136314fa1980da388a59d2f35f35395948a08b6747baebb6aa6/aiohttp-3.13.3-cp314-cp314-win32.whl", hash = "sha256:b556c85915d8efaed322bf1bdae9486aa0f3f764195a0fb6ee962e5c71ef5ce1", size = 433126, upload-time = "2026-01-03T17:31:47.463Z" },
- { url = "https://files.pythonhosted.org/packages/de/56/982704adea7d3b16614fc5936014e9af85c0e34b58f9046655817f04306e/aiohttp-3.13.3-cp314-cp314-win_amd64.whl", hash = "sha256:9bf9f7a65e7aa20dd764151fb3d616c81088f91f8df39c3893a536e279b4b984", size = 459128, upload-time = "2026-01-03T17:31:49.2Z" },
- { url = "https://files.pythonhosted.org/packages/6c/2a/3c79b638a9c3d4658d345339d22070241ea341ed4e07b5ac60fb0f418003/aiohttp-3.13.3-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:05861afbbec40650d8a07ea324367cb93e9e8cc7762e04dd4405df99fa65159c", size = 769512, upload-time = "2026-01-03T17:31:51.134Z" },
- { url = "https://files.pythonhosted.org/packages/29/b9/3e5014d46c0ab0db8707e0ac2711ed28c4da0218c358a4e7c17bae0d8722/aiohttp-3.13.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2fc82186fadc4a8316768d61f3722c230e2c1dcab4200d52d2ebdf2482e47592", size = 506444, upload-time = "2026-01-03T17:31:52.85Z" },
- { url = "https://files.pythonhosted.org/packages/90/03/c1d4ef9a054e151cd7839cdc497f2638f00b93cbe8043983986630d7a80c/aiohttp-3.13.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0add0900ff220d1d5c5ebbf99ed88b0c1bbf87aa7e4262300ed1376a6b13414f", size = 510798, upload-time = "2026-01-03T17:31:54.91Z" },
- { url = "https://files.pythonhosted.org/packages/ea/76/8c1e5abbfe8e127c893fe7ead569148a4d5a799f7cf958d8c09f3eedf097/aiohttp-3.13.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:568f416a4072fbfae453dcf9a99194bbb8bdeab718e08ee13dfa2ba0e4bebf29", size = 1868835, upload-time = "2026-01-03T17:31:56.733Z" },
- { url = "https://files.pythonhosted.org/packages/8e/ac/984c5a6f74c363b01ff97adc96a3976d9c98940b8969a1881575b279ac5d/aiohttp-3.13.3-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:add1da70de90a2569c5e15249ff76a631ccacfe198375eead4aadf3b8dc849dc", size = 1720486, upload-time = "2026-01-03T17:31:58.65Z" },
- { url = "https://files.pythonhosted.org/packages/b2/9a/b7039c5f099c4eb632138728828b33428585031a1e658d693d41d07d89d1/aiohttp-3.13.3-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:10b47b7ba335d2e9b1239fa571131a87e2d8ec96b333e68b2a305e7a98b0bae2", size = 1847951, upload-time = "2026-01-03T17:32:00.989Z" },
- { url = "https://files.pythonhosted.org/packages/3c/02/3bec2b9a1ba3c19ff89a43a19324202b8eb187ca1e928d8bdac9bbdddebd/aiohttp-3.13.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3dd4dce1c718e38081c8f35f323209d4c1df7d4db4bab1b5c88a6b4d12b74587", size = 1941001, upload-time = "2026-01-03T17:32:03.122Z" },
- { url = "https://files.pythonhosted.org/packages/37/df/d879401cedeef27ac4717f6426c8c36c3091c6e9f08a9178cc87549c537f/aiohttp-3.13.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:34bac00a67a812570d4a460447e1e9e06fae622946955f939051e7cc895cfab8", size = 1797246, upload-time = "2026-01-03T17:32:05.255Z" },
- { url = "https://files.pythonhosted.org/packages/8d/15/be122de1f67e6953add23335c8ece6d314ab67c8bebb3f181063010795a7/aiohttp-3.13.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a19884d2ee70b06d9204b2727a7b9f983d0c684c650254679e716b0b77920632", size = 1627131, upload-time = "2026-01-03T17:32:07.607Z" },
- { url = "https://files.pythonhosted.org/packages/12/12/70eedcac9134cfa3219ab7af31ea56bc877395b1ac30d65b1bc4b27d0438/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5f8ca7f2bb6ba8348a3614c7918cc4bb73268c5ac2a207576b7afea19d3d9f64", size = 1795196, upload-time = "2026-01-03T17:32:09.59Z" },
- { url = "https://files.pythonhosted.org/packages/32/11/b30e1b1cd1f3054af86ebe60df96989c6a414dd87e27ad16950eee420bea/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:b0d95340658b9d2f11d9697f59b3814a9d3bb4b7a7c20b131df4bcef464037c0", size = 1782841, upload-time = "2026-01-03T17:32:11.445Z" },
- { url = "https://files.pythonhosted.org/packages/88/0d/d98a9367b38912384a17e287850f5695c528cff0f14f791ce8ee2e4f7796/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:a1e53262fd202e4b40b70c3aff944a8155059beedc8a89bba9dc1f9ef06a1b56", size = 1795193, upload-time = "2026-01-03T17:32:13.705Z" },
- { url = "https://files.pythonhosted.org/packages/43/a5/a2dfd1f5ff5581632c7f6a30e1744deda03808974f94f6534241ef60c751/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:d60ac9663f44168038586cab2157e122e46bdef09e9368b37f2d82d354c23f72", size = 1621979, upload-time = "2026-01-03T17:32:15.965Z" },
- { url = "https://files.pythonhosted.org/packages/fa/f0/12973c382ae7c1cccbc4417e129c5bf54c374dfb85af70893646e1f0e749/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:90751b8eed69435bac9ff4e3d2f6b3af1f57e37ecb0fbeee59c0174c9e2d41df", size = 1822193, upload-time = "2026-01-03T17:32:18.219Z" },
- { url = "https://files.pythonhosted.org/packages/3c/5f/24155e30ba7f8c96918af1350eb0663e2430aad9e001c0489d89cd708ab1/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:fc353029f176fd2b3ec6cfc71be166aba1936fe5d73dd1992ce289ca6647a9aa", size = 1769801, upload-time = "2026-01-03T17:32:20.25Z" },
- { url = "https://files.pythonhosted.org/packages/eb/f8/7314031ff5c10e6ece114da79b338ec17eeff3a079e53151f7e9f43c4723/aiohttp-3.13.3-cp314-cp314t-win32.whl", hash = "sha256:2e41b18a58da1e474a057b3d35248d8320029f61d70a37629535b16a0c8f3767", size = 466523, upload-time = "2026-01-03T17:32:22.215Z" },
- { url = "https://files.pythonhosted.org/packages/b4/63/278a98c715ae467624eafe375542d8ba9b4383a016df8fdefe0ae28382a7/aiohttp-3.13.3-cp314-cp314t-win_amd64.whl", hash = "sha256:44531a36aa2264a1860089ffd4dce7baf875ee5a6079d5fb42e261c704ef7344", size = 499694, upload-time = "2026-01-03T17:32:24.546Z" },
+ { url = "https://files.pythonhosted.org/packages/be/6f/353954c29e7dcce7cf00280a02c75f30e133c00793c7a2ed3776d7b2f426/aiohttp-3.13.5-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:023ecba036ddd840b0b19bf195bfae970083fd7024ce1ac22e9bba90464620e9", size = 748876, upload-time = "2026-03-31T21:57:36.319Z" },
+ { url = "https://files.pythonhosted.org/packages/f5/1b/428a7c64687b3b2e9cd293186695affc0e1e54a445d0361743b231f11066/aiohttp-3.13.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:15c933ad7920b7d9a20de151efcd05a6e38302cbf0e10c9b2acb9a42210a2416", size = 499557, upload-time = "2026-03-31T21:57:38.236Z" },
+ { url = "https://files.pythonhosted.org/packages/29/47/7be41556bfbb6917069d6a6634bb7dd5e163ba445b783a90d40f5ac7e3a7/aiohttp-3.13.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ab2899f9fa2f9f741896ebb6fa07c4c883bfa5c7f2ddd8cf2aafa86fa981b2d2", size = 500258, upload-time = "2026-03-31T21:57:39.923Z" },
+ { url = "https://files.pythonhosted.org/packages/67/84/c9ecc5828cb0b3695856c07c0a6817a99d51e2473400f705275a2b3d9239/aiohttp-3.13.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a60eaa2d440cd4707696b52e40ed3e2b0f73f65be07fd0ef23b6b539c9c0b0b4", size = 1749199, upload-time = "2026-03-31T21:57:41.938Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/d3/3c6d610e66b495657622edb6ae7c7fd31b2e9086b4ec50b47897ad6042a9/aiohttp-3.13.5-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:55b3bdd3292283295774ab585160c4004f4f2f203946997f49aac032c84649e9", size = 1721013, upload-time = "2026-03-31T21:57:43.904Z" },
+ { url = "https://files.pythonhosted.org/packages/49/a0/24409c12217456df0bae7babe3b014e460b0b38a8e60753d6cb339f6556d/aiohttp-3.13.5-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c2b2355dc094e5f7d45a7bb262fe7207aa0460b37a0d87027dcf21b5d890e7d5", size = 1781501, upload-time = "2026-03-31T21:57:46.285Z" },
+ { url = "https://files.pythonhosted.org/packages/98/9d/b65ec649adc5bccc008b0957a9a9c691070aeac4e41cea18559fef49958b/aiohttp-3.13.5-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b38765950832f7d728297689ad78f5f2cf79ff82487131c4d26fe6ceecdc5f8e", size = 1878981, upload-time = "2026-03-31T21:57:48.734Z" },
+ { url = "https://files.pythonhosted.org/packages/57/d8/8d44036d7eb7b6a8ec4c5494ea0c8c8b94fbc0ed3991c1a7adf230df03bf/aiohttp-3.13.5-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b18f31b80d5a33661e08c89e202edabf1986e9b49c42b4504371daeaa11b47c1", size = 1767934, upload-time = "2026-03-31T21:57:51.171Z" },
+ { url = "https://files.pythonhosted.org/packages/31/04/d3f8211f273356f158e3464e9e45484d3fb8c4ce5eb2f6fe9405c3273983/aiohttp-3.13.5-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:33add2463dde55c4f2d9635c6ab33ce154e5ecf322bd26d09af95c5f81cfa286", size = 1566671, upload-time = "2026-03-31T21:57:53.326Z" },
+ { url = "https://files.pythonhosted.org/packages/41/db/073e4ebe00b78e2dfcacff734291651729a62953b48933d765dc513bf798/aiohttp-3.13.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:327cc432fdf1356fb4fbc6fe833ad4e9f6aacb71a8acaa5f1855e4b25910e4a9", size = 1705219, upload-time = "2026-03-31T21:57:55.385Z" },
+ { url = "https://files.pythonhosted.org/packages/48/45/7dfba71a2f9fd97b15c95c06819de7eb38113d2cdb6319669195a7d64270/aiohttp-3.13.5-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:7c35b0bf0b48a70b4cb4fc5d7bed9b932532728e124874355de1a0af8ec4bc88", size = 1743049, upload-time = "2026-03-31T21:57:57.341Z" },
+ { url = "https://files.pythonhosted.org/packages/18/71/901db0061e0f717d226386a7f471bb59b19566f2cae5f0d93874b017271f/aiohttp-3.13.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:df23d57718f24badef8656c49743e11a89fd6f5358fa8a7b96e728fda2abf7d3", size = 1749557, upload-time = "2026-03-31T21:57:59.626Z" },
+ { url = "https://files.pythonhosted.org/packages/08/d5/41eebd16066e59cd43728fe74bce953d7402f2b4ddfdfef2c0e9f17ca274/aiohttp-3.13.5-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:02e048037a6501a5ec1f6fc9736135aec6eb8a004ce48838cb951c515f32c80b", size = 1558931, upload-time = "2026-03-31T21:58:01.972Z" },
+ { url = "https://files.pythonhosted.org/packages/30/e6/4a799798bf05740e66c3a1161079bda7a3dd8e22ca392481d7a7f9af82a6/aiohttp-3.13.5-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:31cebae8b26f8a615d2b546fee45d5ffb76852ae6450e2a03f42c9102260d6fe", size = 1774125, upload-time = "2026-03-31T21:58:04.007Z" },
+ { url = "https://files.pythonhosted.org/packages/84/63/7749337c90f92bc2cb18f9560d67aa6258c7060d1397d21529b8004fcf6f/aiohttp-3.13.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:888e78eb5ca55a615d285c3c09a7a91b42e9dd6fc699b166ebd5dee87c9ccf14", size = 1732427, upload-time = "2026-03-31T21:58:06.337Z" },
+ { url = "https://files.pythonhosted.org/packages/98/de/cf2f44ff98d307e72fb97d5f5bbae3bfcb442f0ea9790c0bf5c5c2331404/aiohttp-3.13.5-cp312-cp312-win32.whl", hash = "sha256:8bd3ec6376e68a41f9f95f5ed170e2fcf22d4eb27a1f8cb361d0508f6e0557f3", size = 433534, upload-time = "2026-03-31T21:58:08.712Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/ca/eadf6f9c8fa5e31d40993e3db153fb5ed0b11008ad5d9de98a95045bed84/aiohttp-3.13.5-cp312-cp312-win_amd64.whl", hash = "sha256:110e448e02c729bcebb18c60b9214a87ba33bac4a9fa5e9a5f139938b56c6cb1", size = 460446, upload-time = "2026-03-31T21:58:10.945Z" },
+ { url = "https://files.pythonhosted.org/packages/78/e9/d76bf503005709e390122d34e15256b88f7008e246c4bdbe915cd4f1adce/aiohttp-3.13.5-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a5029cc80718bbd545123cd8fe5d15025eccaaaace5d0eeec6bd556ad6163d61", size = 742930, upload-time = "2026-03-31T21:58:13.155Z" },
+ { url = "https://files.pythonhosted.org/packages/57/00/4b7b70223deaebd9bb85984d01a764b0d7bd6526fcdc73cca83bcbe7243e/aiohttp-3.13.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4bb6bf5811620003614076bdc807ef3b5e38244f9d25ca5fe888eaccea2a9832", size = 496927, upload-time = "2026-03-31T21:58:15.073Z" },
+ { url = "https://files.pythonhosted.org/packages/9c/f5/0fb20fb49f8efdcdce6cd8127604ad2c503e754a8f139f5e02b01626523f/aiohttp-3.13.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a84792f8631bf5a94e52d9cc881c0b824ab42717165a5579c760b830d9392ac9", size = 497141, upload-time = "2026-03-31T21:58:17.009Z" },
+ { url = "https://files.pythonhosted.org/packages/3b/86/b7c870053e36a94e8951b803cb5b909bfbc9b90ca941527f5fcafbf6b0fa/aiohttp-3.13.5-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:57653eac22c6a4c13eb22ecf4d673d64a12f266e72785ab1c8b8e5940d0e8090", size = 1732476, upload-time = "2026-03-31T21:58:18.925Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/e5/4e161f84f98d80c03a238671b4136e6530453d65262867d989bbe78244d0/aiohttp-3.13.5-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e5e5f7debc7a57af53fdf5c5009f9391d9f4c12867049d509bf7bb164a6e295b", size = 1706507, upload-time = "2026-03-31T21:58:21.094Z" },
+ { url = "https://files.pythonhosted.org/packages/d4/56/ea11a9f01518bd5a2a2fcee869d248c4b8a0cfa0bb13401574fa31adf4d4/aiohttp-3.13.5-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c719f65bebcdf6716f10e9eff80d27567f7892d8988c06de12bbbd39307c6e3a", size = 1773465, upload-time = "2026-03-31T21:58:23.159Z" },
+ { url = "https://files.pythonhosted.org/packages/eb/40/333ca27fb74b0383f17c90570c748f7582501507307350a79d9f9f3c6eb1/aiohttp-3.13.5-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d97f93fdae594d886c5a866636397e2bcab146fd7a132fd6bb9ce182224452f8", size = 1873523, upload-time = "2026-03-31T21:58:25.59Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/d2/e2f77eef1acb7111405433c707dc735e63f67a56e176e72e9e7a2cd3f493/aiohttp-3.13.5-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3df334e39d4c2f899a914f1dba283c1aadc311790733f705182998c6f7cae665", size = 1754113, upload-time = "2026-03-31T21:58:27.624Z" },
+ { url = "https://files.pythonhosted.org/packages/fb/56/3f653d7f53c89669301ec9e42c95233e2a0c0a6dd051269e6e678db4fdb0/aiohttp-3.13.5-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fe6970addfea9e5e081401bcbadf865d2b6da045472f58af08427e108d618540", size = 1562351, upload-time = "2026-03-31T21:58:29.918Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/a6/9b3e91eb8ae791cce4ee736da02211c85c6f835f1bdfac0594a8a3b7018c/aiohttp-3.13.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7becdf835feff2f4f335d7477f121af787e3504b48b449ff737afb35869ba7bb", size = 1693205, upload-time = "2026-03-31T21:58:32.214Z" },
+ { url = "https://files.pythonhosted.org/packages/98/fc/bfb437a99a2fcebd6b6eaec609571954de2ed424f01c352f4b5504371dd3/aiohttp-3.13.5-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:676e5651705ad5d8a70aeb8eb6936c436d8ebbd56e63436cb7dd9bb36d2a9a46", size = 1730618, upload-time = "2026-03-31T21:58:34.728Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/b6/c8534862126191a034f68153194c389addc285a0f1347d85096d349bbc15/aiohttp-3.13.5-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:9b16c653d38eb1a611cc898c41e76859ca27f119d25b53c12875fd0474ae31a8", size = 1745185, upload-time = "2026-03-31T21:58:36.909Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/93/4ca8ee2ef5236e2707e0fd5fecb10ce214aee1ff4ab307af9c558bda3b37/aiohttp-3.13.5-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:999802d5fa0389f58decd24b537c54aa63c01c3219ce17d1214cbda3c2b22d2d", size = 1557311, upload-time = "2026-03-31T21:58:39.38Z" },
+ { url = "https://files.pythonhosted.org/packages/57/ae/76177b15f18c5f5d094f19901d284025db28eccc5ae374d1d254181d33f4/aiohttp-3.13.5-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:ec707059ee75732b1ba130ed5f9580fe10ff75180c812bc267ded039db5128c6", size = 1773147, upload-time = "2026-03-31T21:58:41.476Z" },
+ { url = "https://files.pythonhosted.org/packages/01/a4/62f05a0a98d88af59d93b7fcac564e5f18f513cb7471696ac286db970d6a/aiohttp-3.13.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2d6d44a5b48132053c2f6cd5c8cb14bc67e99a63594e336b0f2af81e94d5530c", size = 1730356, upload-time = "2026-03-31T21:58:44.049Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/85/fc8601f59dfa8c9523808281f2da571f8b4699685f9809a228adcc90838d/aiohttp-3.13.5-cp313-cp313-win32.whl", hash = "sha256:329f292ed14d38a6c4c435e465f48bebb47479fd676a0411936cc371643225cc", size = 432637, upload-time = "2026-03-31T21:58:46.167Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/1b/ac685a8882896acf0f6b31d689e3792199cfe7aba37969fa91da63a7fa27/aiohttp-3.13.5-cp313-cp313-win_amd64.whl", hash = "sha256:69f571de7500e0557801c0b51f4780482c0ec5fe2ac851af5a92cfce1af1cb83", size = 458896, upload-time = "2026-03-31T21:58:48.119Z" },
+ { url = "https://files.pythonhosted.org/packages/5d/ce/46572759afc859e867a5bc8ec3487315869013f59281ce61764f76d879de/aiohttp-3.13.5-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:eb4639f32fd4a9904ab8fb45bf3383ba71137f3d9d4ba25b3b3f3109977c5b8c", size = 745721, upload-time = "2026-03-31T21:58:50.229Z" },
+ { url = "https://files.pythonhosted.org/packages/13/fe/8a2efd7626dbe6049b2ef8ace18ffda8a4dfcbe1bcff3ac30c0c7575c20b/aiohttp-3.13.5-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:7e5dc4311bd5ac493886c63cbf76ab579dbe4641268e7c74e48e774c74b6f2be", size = 497663, upload-time = "2026-03-31T21:58:52.232Z" },
+ { url = "https://files.pythonhosted.org/packages/9b/91/cc8cc78a111826c54743d88651e1687008133c37e5ee615fee9b57990fac/aiohttp-3.13.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:756c3c304d394977519824449600adaf2be0ccee76d206ee339c5e76b70ded25", size = 499094, upload-time = "2026-03-31T21:58:54.566Z" },
+ { url = "https://files.pythonhosted.org/packages/0a/33/a8362cb15cf16a3af7e86ed11962d5cd7d59b449202dc576cdc731310bde/aiohttp-3.13.5-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ecc26751323224cf8186efcf7fbcbc30f4e1d8c7970659daf25ad995e4032a56", size = 1726701, upload-time = "2026-03-31T21:58:56.864Z" },
+ { url = "https://files.pythonhosted.org/packages/45/0c/c091ac5c3a17114bd76cbf85d674650969ddf93387876cf67f754204bd77/aiohttp-3.13.5-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:10a75acfcf794edf9d8db50e5a7ec5fc818b2a8d3f591ce93bc7b1210df016d2", size = 1683360, upload-time = "2026-03-31T21:58:59.072Z" },
+ { url = "https://files.pythonhosted.org/packages/23/73/bcee1c2b79bc275e964d1446c55c54441a461938e70267c86afaae6fba27/aiohttp-3.13.5-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0f7a18f258d124cd678c5fe072fe4432a4d5232b0657fca7c1847f599233c83a", size = 1773023, upload-time = "2026-03-31T21:59:01.776Z" },
+ { url = "https://files.pythonhosted.org/packages/c7/ef/720e639df03004fee2d869f771799d8c23046dec47d5b81e396c7cda583a/aiohttp-3.13.5-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:df6104c009713d3a89621096f3e3e88cc323fd269dbd7c20afe18535094320be", size = 1853795, upload-time = "2026-03-31T21:59:04.568Z" },
+ { url = "https://files.pythonhosted.org/packages/bd/c9/989f4034fb46841208de7aeeac2c6d8300745ab4f28c42f629ba77c2d916/aiohttp-3.13.5-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:241a94f7de7c0c3b616627aaad530fe2cb620084a8b144d3be7b6ecfe95bae3b", size = 1730405, upload-time = "2026-03-31T21:59:07.221Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/75/ee1fd286ca7dc599d824b5651dad7b3be7ff8d9a7e7b3fe9820d9180f7db/aiohttp-3.13.5-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c974fb66180e58709b6fc402846f13791240d180b74de81d23913abe48e96d94", size = 1558082, upload-time = "2026-03-31T21:59:09.484Z" },
+ { url = "https://files.pythonhosted.org/packages/c3/20/1e9e6650dfc436340116b7aa89ff8cb2bbdf0abc11dfaceaad8f74273a10/aiohttp-3.13.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:6e27ea05d184afac78aabbac667450c75e54e35f62238d44463131bd3f96753d", size = 1692346, upload-time = "2026-03-31T21:59:12.068Z" },
+ { url = "https://files.pythonhosted.org/packages/d8/40/8ebc6658d48ea630ac7903912fe0dd4e262f0e16825aa4c833c56c9f1f56/aiohttp-3.13.5-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:a79a6d399cef33a11b6f004c67bb07741d91f2be01b8d712d52c75711b1e07c7", size = 1698891, upload-time = "2026-03-31T21:59:14.552Z" },
+ { url = "https://files.pythonhosted.org/packages/d8/78/ea0ae5ec8ba7a5c10bdd6e318f1ba5e76fcde17db8275188772afc7917a4/aiohttp-3.13.5-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:c632ce9c0b534fbe25b52c974515ed674937c5b99f549a92127c85f771a78772", size = 1742113, upload-time = "2026-03-31T21:59:17.068Z" },
+ { url = "https://files.pythonhosted.org/packages/8a/66/9d308ed71e3f2491be1acb8769d96c6f0c47d92099f3bc9119cada27b357/aiohttp-3.13.5-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:fceedde51fbd67ee2bcc8c0b33d0126cc8b51ef3bbde2f86662bd6d5a6f10ec5", size = 1553088, upload-time = "2026-03-31T21:59:19.541Z" },
+ { url = "https://files.pythonhosted.org/packages/da/a6/6cc25ed8dfc6e00c90f5c6d126a98e2cf28957ad06fa1036bd34b6f24a2c/aiohttp-3.13.5-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:f92995dfec9420bb69ae629abf422e516923ba79ba4403bc750d94fb4a6c68c1", size = 1757976, upload-time = "2026-03-31T21:59:22.311Z" },
+ { url = "https://files.pythonhosted.org/packages/c1/2b/cce5b0ffe0de99c83e5e36d8f828e4161e415660a9f3e58339d07cce3006/aiohttp-3.13.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:20ae0ff08b1f2c8788d6fb85afcb798654ae6ba0b747575f8562de738078457b", size = 1712444, upload-time = "2026-03-31T21:59:24.635Z" },
+ { url = "https://files.pythonhosted.org/packages/6c/cf/9e1795b4160c58d29421eafd1a69c6ce351e2f7c8d3c6b7e4ca44aea1a5b/aiohttp-3.13.5-cp314-cp314-win32.whl", hash = "sha256:b20df693de16f42b2472a9c485e1c948ee55524786a0a34345511afdd22246f3", size = 438128, upload-time = "2026-03-31T21:59:27.291Z" },
+ { url = "https://files.pythonhosted.org/packages/22/4d/eaedff67fc805aeba4ba746aec891b4b24cebb1a7d078084b6300f79d063/aiohttp-3.13.5-cp314-cp314-win_amd64.whl", hash = "sha256:f85c6f327bf0b8c29da7d93b1cabb6363fb5e4e160a32fa241ed2dce21b73162", size = 464029, upload-time = "2026-03-31T21:59:29.429Z" },
+ { url = "https://files.pythonhosted.org/packages/79/11/c27d9332ee20d68dd164dc12a6ecdef2e2e35ecc97ed6cf0d2442844624b/aiohttp-3.13.5-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:1efb06900858bb618ff5cee184ae2de5828896c448403d51fb633f09e109be0a", size = 778758, upload-time = "2026-03-31T21:59:31.547Z" },
+ { url = "https://files.pythonhosted.org/packages/04/fb/377aead2e0a3ba5f09b7624f702a964bdf4f08b5b6728a9799830c80041e/aiohttp-3.13.5-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:fee86b7c4bd29bdaf0d53d14739b08a106fdda809ca5fe032a15f52fae5fe254", size = 512883, upload-time = "2026-03-31T21:59:34.098Z" },
+ { url = "https://files.pythonhosted.org/packages/bb/a6/aa109a33671f7a5d3bd78b46da9d852797c5e665bfda7d6b373f56bff2ec/aiohttp-3.13.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:20058e23909b9e65f9da62b396b77dfa95965cbe840f8def6e572538b1d32e36", size = 516668, upload-time = "2026-03-31T21:59:36.497Z" },
+ { url = "https://files.pythonhosted.org/packages/79/b3/ca078f9f2fa9563c36fb8ef89053ea2bb146d6f792c5104574d49d8acb63/aiohttp-3.13.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8cf20a8d6868cb15a73cab329ffc07291ba8c22b1b88176026106ae39aa6df0f", size = 1883461, upload-time = "2026-03-31T21:59:38.723Z" },
+ { url = "https://files.pythonhosted.org/packages/b7/e3/a7ad633ca1ca497b852233a3cce6906a56c3225fb6d9217b5e5e60b7419d/aiohttp-3.13.5-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:330f5da04c987f1d5bdb8ae189137c77139f36bd1cb23779ca1a354a4b027800", size = 1747661, upload-time = "2026-03-31T21:59:41.187Z" },
+ { url = "https://files.pythonhosted.org/packages/33/b9/cd6fe579bed34a906d3d783fe60f2fa297ef55b27bb4538438ee49d4dc41/aiohttp-3.13.5-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6f1cbf0c7926d315c3c26c2da41fd2b5d2fe01ac0e157b78caefc51a782196cf", size = 1863800, upload-time = "2026-03-31T21:59:43.84Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/3f/2c1e2f5144cefa889c8afd5cf431994c32f3b29da9961698ff4e3811b79a/aiohttp-3.13.5-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:53fc049ed6390d05423ba33103ded7281fe897cf97878f369a527070bd95795b", size = 1958382, upload-time = "2026-03-31T21:59:46.187Z" },
+ { url = "https://files.pythonhosted.org/packages/66/1d/f31ec3f1013723b3babe3609e7f119c2c2fb6ef33da90061a705ef3e1bc8/aiohttp-3.13.5-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:898703aa2667e3c5ca4c54ca36cd73f58b7a38ef87a5606414799ebce4d3fd3a", size = 1803724, upload-time = "2026-03-31T21:59:48.656Z" },
+ { url = "https://files.pythonhosted.org/packages/0e/b4/57712dfc6f1542f067daa81eb61da282fab3e6f1966fca25db06c4fc62d5/aiohttp-3.13.5-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0494a01ca9584eea1e5fbd6d748e61ecff218c51b576ee1999c23db7066417d8", size = 1640027, upload-time = "2026-03-31T21:59:51.284Z" },
+ { url = "https://files.pythonhosted.org/packages/25/3c/734c878fb43ec083d8e31bf029daae1beafeae582d1b35da234739e82ee7/aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:6cf81fe010b8c17b09495cbd15c1d35afbc8fb405c0c9cf4738e5ae3af1d65be", size = 1806644, upload-time = "2026-03-31T21:59:53.753Z" },
+ { url = "https://files.pythonhosted.org/packages/20/a5/f671e5cbec1c21d044ff3078223f949748f3a7f86b14e34a365d74a5d21f/aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:c564dd5f09ddc9d8f2c2d0a301cd30a79a2cc1b46dd1a73bef8f0038863d016b", size = 1791630, upload-time = "2026-03-31T21:59:56.239Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/63/fb8d0ad63a0b8a99be97deac8c04dacf0785721c158bdf23d679a87aa99e/aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:2994be9f6e51046c4f864598fd9abeb4fba6e88f0b2152422c9666dcd4aea9c6", size = 1809403, upload-time = "2026-03-31T21:59:59.103Z" },
+ { url = "https://files.pythonhosted.org/packages/59/0c/bfed7f30662fcf12206481c2aac57dedee43fe1c49275e85b3a1e1742294/aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:157826e2fa245d2ef46c83ea8a5faf77ca19355d278d425c29fda0beb3318037", size = 1634924, upload-time = "2026-03-31T22:00:02.116Z" },
+ { url = "https://files.pythonhosted.org/packages/17/d6/fd518d668a09fd5a3319ae5e984d4d80b9a4b3df4e21c52f02251ef5a32e/aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:a8aca50daa9493e9e13c0f566201a9006f080e7c50e5e90d0b06f53146a54500", size = 1836119, upload-time = "2026-03-31T22:00:04.756Z" },
+ { url = "https://files.pythonhosted.org/packages/78/b7/15fb7a9d52e112a25b621c67b69c167805cb1f2ab8f1708a5c490d1b52fe/aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3b13560160d07e047a93f23aaa30718606493036253d5430887514715b67c9d9", size = 1772072, upload-time = "2026-03-31T22:00:07.494Z" },
+ { url = "https://files.pythonhosted.org/packages/7e/df/57ba7f0c4a553fc2bd8b6321df236870ec6fd64a2a473a8a13d4f733214e/aiohttp-3.13.5-cp314-cp314t-win32.whl", hash = "sha256:9a0f4474b6ea6818b41f82172d799e4b3d29e22c2c520ce4357856fced9af2f8", size = 471819, upload-time = "2026-03-31T22:00:10.277Z" },
+ { url = "https://files.pythonhosted.org/packages/62/29/2f8418269e46454a26171bfdd6a055d74febf32234e474930f2f60a17145/aiohttp-3.13.5-cp314-cp314t-win_amd64.whl", hash = "sha256:18a2f6c1182c51baa1d28d68fea51513cb2a76612f038853c0ad3c145423d3d9", size = 505441, upload-time = "2026-03-31T22:00:12.791Z" },
]
[[package]]
@@ -419,30 +419,30 @@ wheels = [
[[package]]
name = "boto3"
-version = "1.40.76"
+version = "1.42.80"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "botocore" },
{ name = "jmespath" },
{ name = "s3transfer" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/26/04/8cf6cf7e6390c71b9c958f3bfedc45d1182b51a35f7789354bf7b2ff4e8c/boto3-1.40.76.tar.gz", hash = "sha256:16f4cf97f8dd8e0aae015f4dc66219bd7716a91a40d1e2daa0dafa241a4761c5", size = 111598, upload-time = "2025-11-18T20:23:10.938Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/4b/85/f1e43429ce4c81a920742f98af5cd377a020768738645a7d0ff450553ef0/boto3-1.42.80.tar.gz", hash = "sha256:797cec65f8a36dde38d2397119a114ab0d807cf92c43fb44b72b0522558acc0a", size = 112777, upload-time = "2026-03-31T19:33:46.036Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/90/8e/966263696eb441e8d1c4daa5fdfb3b4be10a96a23c418cc74c80b0b03d4e/boto3-1.40.76-py3-none-any.whl", hash = "sha256:8df6df755727be40ad9e309cfda07f9a12c147e17b639430c55d4e4feee8a167", size = 139359, upload-time = "2025-11-18T20:23:08.75Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/3d/a36837ddfcd08e2506b34a6cb785885923f49c9e20559a832681a5e8228d/boto3-1.42.80-py3-none-any.whl", hash = "sha256:293cbdeaec7eda2a0b08e6a9c2bf1a51c54453863137d45a6431058a9280fdda", size = 140554, upload-time = "2026-03-31T19:33:43.656Z" },
]
[[package]]
name = "botocore"
-version = "1.40.76"
+version = "1.42.96"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "jmespath" },
{ name = "python-dateutil" },
{ name = "urllib3" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/07/eb/50e2d280589a3c20c3b649bb66262d2b53a25c03262e4cc492048ac7540a/botocore-1.40.76.tar.gz", hash = "sha256:2b16024d68b29b973005adfb5039adfe9099ebe772d40a90ca89f2e165c495dc", size = 14494001, upload-time = "2025-11-18T20:22:59.131Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/61/77/2c333622a1d47cf5bf73cdcab0cb6c92addafbef2ec05f81b9f75687d9e5/botocore-1.42.96.tar.gz", hash = "sha256:75b3b841ffacaa944f645196655a21ca777591dd8911e732bfb6614545af0250", size = 15263344, upload-time = "2026-04-24T19:47:05.283Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/7f/6c/522e05388aa6fc66cf8ea46c6b29809a1a6f527ea864998b01ffb368ca36/botocore-1.40.76-py3-none-any.whl", hash = "sha256:fe425d386e48ac64c81cbb4a7181688d813df2e2b4c78b95ebe833c9e868c6f4", size = 14161738, upload-time = "2025-11-18T20:22:55.332Z" },
+ { url = "https://files.pythonhosted.org/packages/45/56/152c3a859ca1b9d77ed16deac3cf81682013677c68cf5715698781fc81bd/botocore-1.42.96-py3-none-any.whl", hash = "sha256:db2c3e2006628be6fde81a24124a6563c363d6982fb92728837cf174bad9d98a", size = 14945920, upload-time = "2026-04-24T19:47:00.323Z" },
]
[[package]]
@@ -637,14 +637,14 @@ wheels = [
[[package]]
name = "click"
-version = "8.3.1"
+version = "8.1.8"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "colorama", marker = "sys_platform == 'win32'" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload-time = "2025-11-15T20:45:42.706Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593, upload-time = "2024-12-21T18:38:44.339Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274, upload-time = "2025-11-15T20:45:41.139Z" },
+ { url = "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", size = 98188, upload-time = "2024-12-21T18:38:41.666Z" },
]
[[package]]
@@ -829,55 +829,31 @@ wheels = [
[[package]]
name = "cryptography"
-version = "46.0.5"
+version = "43.0.3"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "cffi", marker = "platform_python_implementation != 'PyPy'" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/60/04/ee2a9e8542e4fa2773b81771ff8349ff19cdd56b7258a0cc442639052edb/cryptography-46.0.5.tar.gz", hash = "sha256:abace499247268e3757271b2f1e244b36b06f8515cf27c4d49468fc9eb16e93d", size = 750064, upload-time = "2026-02-10T19:18:38.255Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/0d/05/07b55d1fa21ac18c3a8c79f764e2514e6f6a9698f1be44994f5adf0d29db/cryptography-43.0.3.tar.gz", hash = "sha256:315b9001266a492a6ff443b61238f956b214dbec9910a081ba5b6646a055a805", size = 686989, upload-time = "2024-10-18T15:58:32.918Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/f7/81/b0bb27f2ba931a65409c6b8a8b358a7f03c0e46eceacddff55f7c84b1f3b/cryptography-46.0.5-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:351695ada9ea9618b3500b490ad54c739860883df6c1f555e088eaf25b1bbaad", size = 7176289, upload-time = "2026-02-10T19:17:08.274Z" },
- { url = "https://files.pythonhosted.org/packages/ff/9e/6b4397a3e3d15123de3b1806ef342522393d50736c13b20ec4c9ea6693a6/cryptography-46.0.5-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c18ff11e86df2e28854939acde2d003f7984f721eba450b56a200ad90eeb0e6b", size = 4275637, upload-time = "2026-02-10T19:17:10.53Z" },
- { url = "https://files.pythonhosted.org/packages/63/e7/471ab61099a3920b0c77852ea3f0ea611c9702f651600397ac567848b897/cryptography-46.0.5-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d7e3d356b8cd4ea5aff04f129d5f66ebdc7b6f8eae802b93739ed520c47c79b", size = 4424742, upload-time = "2026-02-10T19:17:12.388Z" },
- { url = "https://files.pythonhosted.org/packages/37/53/a18500f270342d66bf7e4d9f091114e31e5ee9e7375a5aba2e85a91e0044/cryptography-46.0.5-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:50bfb6925eff619c9c023b967d5b77a54e04256c4281b0e21336a130cd7fc263", size = 4277528, upload-time = "2026-02-10T19:17:13.853Z" },
- { url = "https://files.pythonhosted.org/packages/22/29/c2e812ebc38c57b40e7c583895e73c8c5adb4d1e4a0cc4c5a4fdab2b1acc/cryptography-46.0.5-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:803812e111e75d1aa73690d2facc295eaefd4439be1023fefc4995eaea2af90d", size = 4947993, upload-time = "2026-02-10T19:17:15.618Z" },
- { url = "https://files.pythonhosted.org/packages/6b/e7/237155ae19a9023de7e30ec64e5d99a9431a567407ac21170a046d22a5a3/cryptography-46.0.5-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3ee190460e2fbe447175cda91b88b84ae8322a104fc27766ad09428754a618ed", size = 4456855, upload-time = "2026-02-10T19:17:17.221Z" },
- { url = "https://files.pythonhosted.org/packages/2d/87/fc628a7ad85b81206738abbd213b07702bcbdada1dd43f72236ef3cffbb5/cryptography-46.0.5-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:f145bba11b878005c496e93e257c1e88f154d278d2638e6450d17e0f31e558d2", size = 3984635, upload-time = "2026-02-10T19:17:18.792Z" },
- { url = "https://files.pythonhosted.org/packages/84/29/65b55622bde135aedf4565dc509d99b560ee4095e56989e815f8fd2aa910/cryptography-46.0.5-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:e9251e3be159d1020c4030bd2e5f84d6a43fe54b6c19c12f51cde9542a2817b2", size = 4277038, upload-time = "2026-02-10T19:17:20.256Z" },
- { url = "https://files.pythonhosted.org/packages/bc/36/45e76c68d7311432741faf1fbf7fac8a196a0a735ca21f504c75d37e2558/cryptography-46.0.5-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:47fb8a66058b80e509c47118ef8a75d14c455e81ac369050f20ba0d23e77fee0", size = 4912181, upload-time = "2026-02-10T19:17:21.825Z" },
- { url = "https://files.pythonhosted.org/packages/6d/1a/c1ba8fead184d6e3d5afcf03d569acac5ad063f3ac9fb7258af158f7e378/cryptography-46.0.5-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:4c3341037c136030cb46e4b1e17b7418ea4cbd9dd207e4a6f3b2b24e0d4ac731", size = 4456482, upload-time = "2026-02-10T19:17:25.133Z" },
- { url = "https://files.pythonhosted.org/packages/f9/e5/3fb22e37f66827ced3b902cf895e6a6bc1d095b5b26be26bd13c441fdf19/cryptography-46.0.5-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:890bcb4abd5a2d3f852196437129eb3667d62630333aacc13dfd470fad3aaa82", size = 4405497, upload-time = "2026-02-10T19:17:26.66Z" },
- { url = "https://files.pythonhosted.org/packages/1a/df/9d58bb32b1121a8a2f27383fabae4d63080c7ca60b9b5c88be742be04ee7/cryptography-46.0.5-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:80a8d7bfdf38f87ca30a5391c0c9ce4ed2926918e017c29ddf643d0ed2778ea1", size = 4667819, upload-time = "2026-02-10T19:17:28.569Z" },
- { url = "https://files.pythonhosted.org/packages/ea/ed/325d2a490c5e94038cdb0117da9397ece1f11201f425c4e9c57fe5b9f08b/cryptography-46.0.5-cp311-abi3-win32.whl", hash = "sha256:60ee7e19e95104d4c03871d7d7dfb3d22ef8a9b9c6778c94e1c8fcc8365afd48", size = 3028230, upload-time = "2026-02-10T19:17:30.518Z" },
- { url = "https://files.pythonhosted.org/packages/e9/5a/ac0f49e48063ab4255d9e3b79f5def51697fce1a95ea1370f03dc9db76f6/cryptography-46.0.5-cp311-abi3-win_amd64.whl", hash = "sha256:38946c54b16c885c72c4f59846be9743d699eee2b69b6988e0a00a01f46a61a4", size = 3480909, upload-time = "2026-02-10T19:17:32.083Z" },
- { url = "https://files.pythonhosted.org/packages/00/13/3d278bfa7a15a96b9dc22db5a12ad1e48a9eb3d40e1827ef66a5df75d0d0/cryptography-46.0.5-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:94a76daa32eb78d61339aff7952ea819b1734b46f73646a07decb40e5b3448e2", size = 7119287, upload-time = "2026-02-10T19:17:33.801Z" },
- { url = "https://files.pythonhosted.org/packages/67/c8/581a6702e14f0898a0848105cbefd20c058099e2c2d22ef4e476dfec75d7/cryptography-46.0.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5be7bf2fb40769e05739dd0046e7b26f9d4670badc7b032d6ce4db64dddc0678", size = 4265728, upload-time = "2026-02-10T19:17:35.569Z" },
- { url = "https://files.pythonhosted.org/packages/dd/4a/ba1a65ce8fc65435e5a849558379896c957870dd64fecea97b1ad5f46a37/cryptography-46.0.5-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fe346b143ff9685e40192a4960938545c699054ba11d4f9029f94751e3f71d87", size = 4408287, upload-time = "2026-02-10T19:17:36.938Z" },
- { url = "https://files.pythonhosted.org/packages/f8/67/8ffdbf7b65ed1ac224d1c2df3943553766914a8ca718747ee3871da6107e/cryptography-46.0.5-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:c69fd885df7d089548a42d5ec05be26050ebcd2283d89b3d30676eb32ff87dee", size = 4270291, upload-time = "2026-02-10T19:17:38.748Z" },
- { url = "https://files.pythonhosted.org/packages/f8/e5/f52377ee93bc2f2bba55a41a886fd208c15276ffbd2569f2ddc89d50e2c5/cryptography-46.0.5-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:8293f3dea7fc929ef7240796ba231413afa7b68ce38fd21da2995549f5961981", size = 4927539, upload-time = "2026-02-10T19:17:40.241Z" },
- { url = "https://files.pythonhosted.org/packages/3b/02/cfe39181b02419bbbbcf3abdd16c1c5c8541f03ca8bda240debc467d5a12/cryptography-46.0.5-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:1abfdb89b41c3be0365328a410baa9df3ff8a9110fb75e7b52e66803ddabc9a9", size = 4442199, upload-time = "2026-02-10T19:17:41.789Z" },
- { url = "https://files.pythonhosted.org/packages/c0/96/2fcaeb4873e536cf71421a388a6c11b5bc846e986b2b069c79363dc1648e/cryptography-46.0.5-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:d66e421495fdb797610a08f43b05269e0a5ea7f5e652a89bfd5a7d3c1dee3648", size = 3960131, upload-time = "2026-02-10T19:17:43.379Z" },
- { url = "https://files.pythonhosted.org/packages/d8/d2/b27631f401ddd644e94c5cf33c9a4069f72011821cf3dc7309546b0642a0/cryptography-46.0.5-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:4e817a8920bfbcff8940ecfd60f23d01836408242b30f1a708d93198393a80b4", size = 4270072, upload-time = "2026-02-10T19:17:45.481Z" },
- { url = "https://files.pythonhosted.org/packages/f4/a7/60d32b0370dae0b4ebe55ffa10e8599a2a59935b5ece1b9f06edb73abdeb/cryptography-46.0.5-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:68f68d13f2e1cb95163fa3b4db4bf9a159a418f5f6e7242564fc75fcae667fd0", size = 4892170, upload-time = "2026-02-10T19:17:46.997Z" },
- { url = "https://files.pythonhosted.org/packages/d2/b9/cf73ddf8ef1164330eb0b199a589103c363afa0cf794218c24d524a58eab/cryptography-46.0.5-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:a3d1fae9863299076f05cb8a778c467578262fae09f9dc0ee9b12eb4268ce663", size = 4441741, upload-time = "2026-02-10T19:17:48.661Z" },
- { url = "https://files.pythonhosted.org/packages/5f/eb/eee00b28c84c726fe8fa0158c65afe312d9c3b78d9d01daf700f1f6e37ff/cryptography-46.0.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c4143987a42a2397f2fc3b4d7e3a7d313fbe684f67ff443999e803dd75a76826", size = 4396728, upload-time = "2026-02-10T19:17:50.058Z" },
- { url = "https://files.pythonhosted.org/packages/65/f4/6bc1a9ed5aef7145045114b75b77c2a8261b4d38717bd8dea111a63c3442/cryptography-46.0.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:7d731d4b107030987fd61a7f8ab512b25b53cef8f233a97379ede116f30eb67d", size = 4652001, upload-time = "2026-02-10T19:17:51.54Z" },
- { url = "https://files.pythonhosted.org/packages/86/ef/5d00ef966ddd71ac2e6951d278884a84a40ffbd88948ef0e294b214ae9e4/cryptography-46.0.5-cp314-cp314t-win32.whl", hash = "sha256:c3bcce8521d785d510b2aad26ae2c966092b7daa8f45dd8f44734a104dc0bc1a", size = 3003637, upload-time = "2026-02-10T19:17:52.997Z" },
- { url = "https://files.pythonhosted.org/packages/b7/57/f3f4160123da6d098db78350fdfd9705057aad21de7388eacb2401dceab9/cryptography-46.0.5-cp314-cp314t-win_amd64.whl", hash = "sha256:4d8ae8659ab18c65ced284993c2265910f6c9e650189d4e3f68445ef82a810e4", size = 3469487, upload-time = "2026-02-10T19:17:54.549Z" },
- { url = "https://files.pythonhosted.org/packages/e2/fa/a66aa722105ad6a458bebd64086ca2b72cdd361fed31763d20390f6f1389/cryptography-46.0.5-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:4108d4c09fbbf2789d0c926eb4152ae1760d5a2d97612b92d508d96c861e4d31", size = 7170514, upload-time = "2026-02-10T19:17:56.267Z" },
- { url = "https://files.pythonhosted.org/packages/0f/04/c85bdeab78c8bc77b701bf0d9bdcf514c044e18a46dcff330df5448631b0/cryptography-46.0.5-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7d1f30a86d2757199cb2d56e48cce14deddf1f9c95f1ef1b64ee91ea43fe2e18", size = 4275349, upload-time = "2026-02-10T19:17:58.419Z" },
- { url = "https://files.pythonhosted.org/packages/5c/32/9b87132a2f91ee7f5223b091dc963055503e9b442c98fc0b8a5ca765fab0/cryptography-46.0.5-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:039917b0dc418bb9f6edce8a906572d69e74bd330b0b3fea4f79dab7f8ddd235", size = 4420667, upload-time = "2026-02-10T19:18:00.619Z" },
- { url = "https://files.pythonhosted.org/packages/a1/a6/a7cb7010bec4b7c5692ca6f024150371b295ee1c108bdc1c400e4c44562b/cryptography-46.0.5-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ba2a27ff02f48193fc4daeadf8ad2590516fa3d0adeeb34336b96f7fa64c1e3a", size = 4276980, upload-time = "2026-02-10T19:18:02.379Z" },
- { url = "https://files.pythonhosted.org/packages/8e/7c/c4f45e0eeff9b91e3f12dbd0e165fcf2a38847288fcfd889deea99fb7b6d/cryptography-46.0.5-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:61aa400dce22cb001a98014f647dc21cda08f7915ceb95df0c9eaf84b4b6af76", size = 4939143, upload-time = "2026-02-10T19:18:03.964Z" },
- { url = "https://files.pythonhosted.org/packages/37/19/e1b8f964a834eddb44fa1b9a9976f4e414cbb7aa62809b6760c8803d22d1/cryptography-46.0.5-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3ce58ba46e1bc2aac4f7d9290223cead56743fa6ab94a5d53292ffaac6a91614", size = 4453674, upload-time = "2026-02-10T19:18:05.588Z" },
- { url = "https://files.pythonhosted.org/packages/db/ed/db15d3956f65264ca204625597c410d420e26530c4e2943e05a0d2f24d51/cryptography-46.0.5-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:420d0e909050490d04359e7fdb5ed7e667ca5c3c402b809ae2563d7e66a92229", size = 3978801, upload-time = "2026-02-10T19:18:07.167Z" },
- { url = "https://files.pythonhosted.org/packages/41/e2/df40a31d82df0a70a0daf69791f91dbb70e47644c58581d654879b382d11/cryptography-46.0.5-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:582f5fcd2afa31622f317f80426a027f30dc792e9c80ffee87b993200ea115f1", size = 4276755, upload-time = "2026-02-10T19:18:09.813Z" },
- { url = "https://files.pythonhosted.org/packages/33/45/726809d1176959f4a896b86907b98ff4391a8aa29c0aaaf9450a8a10630e/cryptography-46.0.5-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:bfd56bb4b37ed4f330b82402f6f435845a5f5648edf1ad497da51a8452d5d62d", size = 4901539, upload-time = "2026-02-10T19:18:11.263Z" },
- { url = "https://files.pythonhosted.org/packages/99/0f/a3076874e9c88ecb2ecc31382f6e7c21b428ede6f55aafa1aa272613e3cd/cryptography-46.0.5-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:a3d507bb6a513ca96ba84443226af944b0f7f47dcc9a399d110cd6146481d24c", size = 4452794, upload-time = "2026-02-10T19:18:12.914Z" },
- { url = "https://files.pythonhosted.org/packages/02/ef/ffeb542d3683d24194a38f66ca17c0a4b8bf10631feef44a7ef64e631b1a/cryptography-46.0.5-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9f16fbdf4da055efb21c22d81b89f155f02ba420558db21288b3d0035bafd5f4", size = 4404160, upload-time = "2026-02-10T19:18:14.375Z" },
- { url = "https://files.pythonhosted.org/packages/96/93/682d2b43c1d5f1406ed048f377c0fc9fc8f7b0447a478d5c65ab3d3a66eb/cryptography-46.0.5-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:ced80795227d70549a411a4ab66e8ce307899fad2220ce5ab2f296e687eacde9", size = 4667123, upload-time = "2026-02-10T19:18:15.886Z" },
- { url = "https://files.pythonhosted.org/packages/45/2d/9c5f2926cb5300a8eefc3f4f0b3f3df39db7f7ce40c8365444c49363cbda/cryptography-46.0.5-cp38-abi3-win32.whl", hash = "sha256:02f547fce831f5096c9a567fd41bc12ca8f11df260959ecc7c3202555cc47a72", size = 3010220, upload-time = "2026-02-10T19:18:17.361Z" },
- { url = "https://files.pythonhosted.org/packages/48/ef/0c2f4a8e31018a986949d34a01115dd057bf536905dca38897bacd21fac3/cryptography-46.0.5-cp38-abi3-win_amd64.whl", hash = "sha256:556e106ee01aa13484ce9b0239bca667be5004efb0aabbed28d353df86445595", size = 3467050, upload-time = "2026-02-10T19:18:18.899Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/f3/01fdf26701a26f4b4dbc337a26883ad5bccaa6f1bbbdd29cd89e22f18a1c/cryptography-43.0.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:bf7a1932ac4176486eab36a19ed4c0492da5d97123f1406cf15e41b05e787d2e", size = 6225303, upload-time = "2024-10-18T15:57:36.753Z" },
+ { url = "https://files.pythonhosted.org/packages/a3/01/4896f3d1b392025d4fcbecf40fdea92d3df8662123f6835d0af828d148fd/cryptography-43.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63efa177ff54aec6e1c0aefaa1a241232dcd37413835a9b674b6e3f0ae2bfd3e", size = 3760905, upload-time = "2024-10-18T15:57:39.166Z" },
+ { url = "https://files.pythonhosted.org/packages/0a/be/f9a1f673f0ed4b7f6c643164e513dbad28dd4f2dcdf5715004f172ef24b6/cryptography-43.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e1ce50266f4f70bf41a2c6dc4358afadae90e2a1e5342d3c08883df1675374f", size = 3977271, upload-time = "2024-10-18T15:57:41.227Z" },
+ { url = "https://files.pythonhosted.org/packages/4e/49/80c3a7b5514d1b416d7350830e8c422a4d667b6d9b16a9392ebfd4a5388a/cryptography-43.0.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:443c4a81bb10daed9a8f334365fe52542771f25aedaf889fd323a853ce7377d6", size = 3746606, upload-time = "2024-10-18T15:57:42.903Z" },
+ { url = "https://files.pythonhosted.org/packages/0e/16/a28ddf78ac6e7e3f25ebcef69ab15c2c6be5ff9743dd0709a69a4f968472/cryptography-43.0.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:74f57f24754fe349223792466a709f8e0c093205ff0dca557af51072ff47ab18", size = 3986484, upload-time = "2024-10-18T15:57:45.434Z" },
+ { url = "https://files.pythonhosted.org/packages/01/f5/69ae8da70c19864a32b0315049866c4d411cce423ec169993d0434218762/cryptography-43.0.3-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9762ea51a8fc2a88b70cf2995e5675b38d93bf36bd67d91721c309df184f49bd", size = 3852131, upload-time = "2024-10-18T15:57:47.267Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/db/e74911d95c040f9afd3612b1f732e52b3e517cb80de8bf183be0b7d413c6/cryptography-43.0.3-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:81ef806b1fef6b06dcebad789f988d3b37ccaee225695cf3e07648eee0fc6b73", size = 4075647, upload-time = "2024-10-18T15:57:49.684Z" },
+ { url = "https://files.pythonhosted.org/packages/56/48/7b6b190f1462818b324e674fa20d1d5ef3e24f2328675b9b16189cbf0b3c/cryptography-43.0.3-cp37-abi3-win32.whl", hash = "sha256:cbeb489927bd7af4aa98d4b261af9a5bc025bd87f0e3547e11584be9e9427be2", size = 2623873, upload-time = "2024-10-18T15:57:51.822Z" },
+ { url = "https://files.pythonhosted.org/packages/eb/b1/0ebff61a004f7f89e7b65ca95f2f2375679d43d0290672f7713ee3162aff/cryptography-43.0.3-cp37-abi3-win_amd64.whl", hash = "sha256:f46304d6f0c6ab8e52770addfa2fc41e6629495548862279641972b6215451cd", size = 3068039, upload-time = "2024-10-18T15:57:54.426Z" },
+ { url = "https://files.pythonhosted.org/packages/30/d5/c8b32c047e2e81dd172138f772e81d852c51f0f2ad2ae8a24f1122e9e9a7/cryptography-43.0.3-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:8ac43ae87929a5982f5948ceda07001ee5e83227fd69cf55b109144938d96984", size = 6222984, upload-time = "2024-10-18T15:57:56.174Z" },
+ { url = "https://files.pythonhosted.org/packages/2f/78/55356eb9075d0be6e81b59f45c7b48df87f76a20e73893872170471f3ee8/cryptography-43.0.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:846da004a5804145a5f441b8530b4bf35afbf7da70f82409f151695b127213d5", size = 3762968, upload-time = "2024-10-18T15:57:58.206Z" },
+ { url = "https://files.pythonhosted.org/packages/2a/2c/488776a3dc843f95f86d2f957ca0fc3407d0242b50bede7fad1e339be03f/cryptography-43.0.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f996e7268af62598f2fc1204afa98a3b5712313a55c4c9d434aef49cadc91d4", size = 3977754, upload-time = "2024-10-18T15:58:00.683Z" },
+ { url = "https://files.pythonhosted.org/packages/7c/04/2345ca92f7a22f601a9c62961741ef7dd0127c39f7310dffa0041c80f16f/cryptography-43.0.3-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:f7b178f11ed3664fd0e995a47ed2b5ff0a12d893e41dd0494f406d1cf555cab7", size = 3749458, upload-time = "2024-10-18T15:58:02.225Z" },
+ { url = "https://files.pythonhosted.org/packages/ac/25/e715fa0bc24ac2114ed69da33adf451a38abb6f3f24ec207908112e9ba53/cryptography-43.0.3-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:c2e6fc39c4ab499049df3bdf567f768a723a5e8464816e8f009f121a5a9f4405", size = 3988220, upload-time = "2024-10-18T15:58:04.331Z" },
+ { url = "https://files.pythonhosted.org/packages/21/ce/b9c9ff56c7164d8e2edfb6c9305045fbc0df4508ccfdb13ee66eb8c95b0e/cryptography-43.0.3-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e1be4655c7ef6e1bbe6b5d0403526601323420bcf414598955968c9ef3eb7d16", size = 3853898, upload-time = "2024-10-18T15:58:06.113Z" },
+ { url = "https://files.pythonhosted.org/packages/2a/33/b3682992ab2e9476b9c81fff22f02c8b0a1e6e1d49ee1750a67d85fd7ed2/cryptography-43.0.3-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:df6b6c6d742395dd77a23ea3728ab62f98379eff8fb61be2744d4679ab678f73", size = 4076592, upload-time = "2024-10-18T15:58:08.673Z" },
+ { url = "https://files.pythonhosted.org/packages/81/1e/ffcc41b3cebd64ca90b28fd58141c5f68c83d48563c88333ab660e002cd3/cryptography-43.0.3-cp39-abi3-win32.whl", hash = "sha256:d56e96520b1020449bbace2b78b603442e7e378a9b3bd68de65c782db1507995", size = 2623145, upload-time = "2024-10-18T15:58:10.264Z" },
+ { url = "https://files.pythonhosted.org/packages/87/5c/3dab83cc4aba1f4b0e733e3f0c3e7d4386440d660ba5b1e3ff995feb734d/cryptography-43.0.3-cp39-abi3-win_amd64.whl", hash = "sha256:0c580952eef9bf68c4747774cde7ec1d85a6e61de97281f2dba83c7d2c806362", size = 3068026, upload-time = "2024-10-18T15:58:11.916Z" },
]
[[package]]
@@ -1062,18 +1038,17 @@ wheels = [
[[package]]
name = "fastapi"
-version = "0.135.1"
+version = "0.124.4"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "annotated-doc" },
{ name = "pydantic" },
{ name = "starlette" },
{ name = "typing-extensions" },
- { name = "typing-inspection" },
]
-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" }
+sdist = { url = "https://files.pythonhosted.org/packages/cd/21/ade3ff6745a82ea8ad88552b4139d27941549e4f19125879f848ac8f3c3d/fastapi-0.124.4.tar.gz", hash = "sha256:0e9422e8d6b797515f33f500309f6e1c98ee4e85563ba0f2debb282df6343763", size = 378460, upload-time = "2025-12-12T15:00:43.891Z" }
wheels = [
- { 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" },
+ { url = "https://files.pythonhosted.org/packages/3e/57/aa70121b5008f44031be645a61a7c4abc24e0e888ad3fc8fda916f4d188e/fastapi-0.124.4-py3-none-any.whl", hash = "sha256:6d1e703698443ccb89e50abe4893f3c84d9d6689c0cf1ca4fad6d3c15cf69f15", size = 113281, upload-time = "2025-12-12T15:00:42.44Z" },
]
[[package]]
@@ -1605,6 +1580,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/40/79/29f1373b2ce1eec37c03aefbc17194c2470d8b61ede288e5043231825999/grep_ast-0.9.0-py3-none-any.whl", hash = "sha256:a3973dca99f1abc026a01bbbc70e00a63860c8ff94a56182ff18b089836826d7", size = 13918, upload-time = "2025-05-08T01:08:27.481Z" },
]
+[[package]]
+name = "griffelib"
+version = "2.0.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/9d/82/74f4a3310cdabfbb10da554c3a672847f1ed33c6f61dd472681ce7f1fe67/griffelib-2.0.2.tar.gz", hash = "sha256:3cf20b3bc470e83763ffbf236e0076b1211bac1bc67de13daf494640f2de707e", size = 166461, upload-time = "2026-03-27T11:34:51.091Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/11/8c/c9138d881c79aa0ea9ed83cbd58d5ca75624378b38cee225dcf5c42cc91f/griffelib-2.0.2-py3-none-any.whl", hash = "sha256:925c857658fb1ba40c0772c37acbc2ab650bd794d9c1b9726922e36ea4117ea1", size = 142357, upload-time = "2026-03-27T11:34:46.275Z" },
+]
+
[[package]]
name = "grpc-google-iam-v1"
version = "0.14.3"
@@ -1813,14 +1797,14 @@ wheels = [
[[package]]
name = "importlib-metadata"
-version = "8.7.1"
+version = "8.5.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "zipp" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/f3/49/3b30cad09e7771a4982d9975a8cbf64f00d4a1ececb53297f1d9a7be1b10/importlib_metadata-8.7.1.tar.gz", hash = "sha256:49fef1ae6440c182052f407c8d34a68f72efc36db9ca90dc0113398f2fdde8bb", size = 57107, upload-time = "2025-12-21T10:00:19.278Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/cd/12/33e59336dca5be0c398a7482335911a33aa0e20776128f038019f1a95f1b/importlib_metadata-8.5.0.tar.gz", hash = "sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7", size = 55304, upload-time = "2024-09-11T14:56:08.937Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl", hash = "sha256:5a1f80bf1daa489495071efbb095d75a634cf28a8bc299581244063b53176151", size = 27865, upload-time = "2025-12-21T10:00:18.329Z" },
+ { url = "https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl", hash = "sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b", size = 26514, upload-time = "2024-09-11T14:56:07.019Z" },
]
[[package]]
@@ -2004,7 +1988,7 @@ wheels = [
[[package]]
name = "jsonschema"
-version = "4.26.0"
+version = "4.23.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "attrs" },
@@ -2012,9 +1996,9 @@ dependencies = [
{ name = "referencing" },
{ name = "rpds-py" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/b3/fc/e067678238fa451312d4c62bf6e6cf5ec56375422aee02f9cb5f909b3047/jsonschema-4.26.0.tar.gz", hash = "sha256:0c26707e2efad8aa1bfc5b7ce170f3fccc2e4918ff85989ba9ffa9facb2be326", size = 366583, upload-time = "2026-01-07T13:41:07.246Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/38/2e/03362ee4034a4c917f697890ccd4aec0800ccf9ded7f511971c75451deec/jsonschema-4.23.0.tar.gz", hash = "sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4", size = 325778, upload-time = "2024-07-08T18:40:05.546Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl", hash = "sha256:d489f15263b8d200f8387e64b4c3a75f06629559fb73deb8fdfb525f2dab50ce", size = 90630, upload-time = "2026-01-07T13:41:05.306Z" },
+ { url = "https://files.pythonhosted.org/packages/69/4a/4f9dbeb84e8850557c02365a0eee0649abe5eb1d84af92a25731c6c0f922/jsonschema-4.23.0-py3-none-any.whl", hash = "sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566", size = 88462, upload-time = "2024-07-08T18:40:00.165Z" },
]
[[package]]
@@ -2221,7 +2205,7 @@ wheels = [
[[package]]
name = "litellm"
-version = "1.81.16"
+version = "1.83.7"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "aiohttp" },
@@ -2237,9 +2221,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/77/2b/b58bf6bbcbc3d0e55d0a84fdf9128e5b1436517f46fce89b1cd8948ebb81/litellm-1.83.7.tar.gz", hash = "sha256:e2f2cb99df2e2b2eab63f1354faa45c88dd7c8d40c18eb648afb1b349c689633", size = 17791694, upload-time = "2026-04-13T17:35:01.606Z" }
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/75/80/caeb4cdcad96451ba83ad3ba2a9da08b1e1a915fa845c489f56ea044488b/litellm-1.83.7-py3-none-any.whl", hash = "sha256:5784a1d9a9a4a8acd6ca1e347003a5e2e1b3c749b4d41e7da4904577adade111", size = 16069807, upload-time = "2026-04-13T17:34:58.36Z" },
]
[package.optional-dependencies]
@@ -2273,20 +2257,20 @@ proxy = [
[[package]]
name = "litellm-enterprise"
-version = "0.1.32"
+version = "0.1.37"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/f0/b0/1d181e5f9b62b3747aba3ed57bad1c6cfabd4da0d47c2c739c72ef7ee0a9/litellm_enterprise-0.1.32.tar.gz", hash = "sha256:5648f982f92a3a2323ed49c3eee61e281e4ccb284dd8c45ee997dadea0f56a5a", size = 53648, upload-time = "2026-02-14T21:39:47.702Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/82/61/2d56e2b2d83f32d142422c4798af8bc1afd9dc6b515dbf67687ac460f1e8/litellm_enterprise-0.1.37.tar.gz", hash = "sha256:f1616f36fe66c3ddb0cd9d4a70aba2c777feb6d822475ddab1022a9ae8284122", size = 61260, upload-time = "2026-04-07T04:01:35.065Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/f0/df/1d928e4f46a2136297020ab873d343e9e2c8015a6873200101a3e7dca2f4/litellm_enterprise-0.1.32-py3-none-any.whl", hash = "sha256:db043d2628e6a6a1369b3d582360fc5c6676bb213b53a4e6dd35d0c563d4d3e5", size = 117096, upload-time = "2026-02-14T21:39:46.324Z" },
+ { url = "https://files.pythonhosted.org/packages/e3/2c/1eb2921ecc49ea1015e3fd17987eb7d55fdcc8a58920820441551bbba5b0/litellm_enterprise-0.1.37-py3-none-any.whl", hash = "sha256:c1c231d21df6ab0fe77e2c1e10c14764a726a8eea9c328803ca872e5256afc10", size = 125206, upload-time = "2026-04-07T04:01:33.416Z" },
]
[[package]]
name = "litellm-proxy-extras"
-version = "0.4.48"
+version = "0.4.65"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/08/69/ec88e8d951f59720091f22f65e79d92bc4d13f9eb4b1c223c855d7c38437/litellm_proxy_extras-0.4.48.tar.gz", hash = "sha256:5d5d8acf31b92d0cd6738555fb4a2411819755155438de9fb23c724c356400a2", size = 28657, upload-time = "2026-02-25T20:08:31.03Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/f0/21/134126176621c4e50bc9703f693b90d68899fc68fdebf6958704c5c483e8/litellm_proxy_extras-0.4.65.tar.gz", hash = "sha256:2dd4b75b17008a36e05ef8e234fe4ab1cf1e1e2231baeb8b8f8d2f48162e2b08", size = 32575, upload-time = "2026-04-05T00:20:13.68Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/4a/22/7ee216638ede46fd2a09b9655ae4b0a0eb3987b79855f748f70c64ea5f67/litellm_proxy_extras-0.4.48-py3-none-any.whl", hash = "sha256:097001fccec5dbf4cffd902114898a9cfeba62673202447d55d2d0286cf93126", size = 65185, upload-time = "2026-02-25T20:08:30.073Z" },
+ { url = "https://files.pythonhosted.org/packages/4e/90/d0cc4d0a614494cd3b9153584e11f8f1d06045706de92901dafaf1b12403/litellm_proxy_extras-0.4.65-py3-none-any.whl", hash = "sha256:d165269a0e9ec536784483a5b1aaefe989c9ae7ff2ddb4b3dda132ad96c95b29", size = 78106, upload-time = "2026-04-05T00:20:12.046Z" },
]
[[package]]
@@ -2374,7 +2358,7 @@ name = "macholib"
version = "1.16.4"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "altgraph" },
+ { name = "altgraph", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/10/2f/97589876ea967487978071c9042518d28b958d87b17dceb7cdc1d881f963/macholib-1.16.4.tar.gz", hash = "sha256:f408c93ab2e995cd2c46e34fe328b130404be143469e41bc366c807448979362", size = 59427, upload-time = "2025-11-22T08:28:38.373Z" }
wheels = [
@@ -2894,7 +2878,7 @@ wheels = [
[[package]]
name = "openai"
-version = "2.29.0"
+version = "2.30.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "anyio" },
@@ -2906,9 +2890,33 @@ dependencies = [
{ name = "tqdm" },
{ name = "typing-extensions" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/b4/15/203d537e58986b5673e7f232453a2a2f110f22757b15921cbdeea392e520/openai-2.29.0.tar.gz", hash = "sha256:32d09eb2f661b38d3edd7d7e1a2943d1633f572596febe64c0cd370c86d52bec", size = 671128, upload-time = "2026-03-17T17:53:49.599Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/88/15/52580c8fbc16d0675d516e8749806eda679b16de1e4434ea06fb6feaa610/openai-2.30.0.tar.gz", hash = "sha256:92f7661c990bda4b22a941806c83eabe4896c3094465030dd882a71abe80c885", size = 676084, upload-time = "2026-03-25T22:08:59.96Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/d0/b1/35b6f9c8cf9318e3dbb7146cc82dab4cf61182a8d5406fc9b50864362895/openai-2.29.0-py3-none-any.whl", hash = "sha256:b7c5de513c3286d17c5e29b92c4c98ceaf0d775244ac8159aeb1bddf840eb42a", size = 1141533, upload-time = "2026-03-17T17:53:47.348Z" },
+ { url = "https://files.pythonhosted.org/packages/2a/9e/5bfa2270f902d5b92ab7d41ce0475b8630572e71e349b2a4996d14bdda93/openai-2.30.0-py3-none-any.whl", hash = "sha256:9a5ae616888eb2748ec5e0c5b955a51592e0b201a11f4262db920f2a78c5231d", size = 1146656, upload-time = "2026-03-25T22:08:58.2Z" },
+]
+
+[[package]]
+name = "openai-agents"
+version = "0.14.6"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "griffelib" },
+ { name = "mcp" },
+ { name = "openai" },
+ { name = "pydantic" },
+ { name = "requests" },
+ { name = "types-requests" },
+ { name = "typing-extensions" },
+ { name = "websockets" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/d5/fe/4f859d13ba5eea5fe5a3166ffeed04bd04d478ccf3187da6acebb17ba2a7/openai_agents-0.14.6.tar.gz", hash = "sha256:e9d16b835f73be4c5e3798694f90d7a62efcade931e59416bc7462c850e15705", size = 5311175, upload-time = "2026-04-25T02:32:00.897Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/4b/96/b49d04e860c79699814289c273e88066ce97a50686172b5733b7458da062/openai_agents-0.14.6-py3-none-any.whl", hash = "sha256:fdd3fb459892c8af5d0b522908b544e96f6217c7254ba55e966424493b43c1ed", size = 816112, upload-time = "2026-04-25T02:31:58.976Z" },
+]
+
+[package.optional-dependencies]
+litellm = [
+ { name = "litellm" },
]
[[package]]
@@ -3658,55 +3666,36 @@ wheels = [
[[package]]
name = "orjson"
-version = "3.11.7"
+version = "3.10.15"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/53/45/b268004f745ede84e5798b48ee12b05129d19235d0e15267aa57dcdb400b/orjson-3.11.7.tar.gz", hash = "sha256:9b1a67243945819ce55d24a30b59d6a168e86220452d2c96f4d1f093e71c0c49", size = 6144992, upload-time = "2026-02-02T15:38:49.29Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/ae/f9/5dea21763eeff8c1590076918a446ea3d6140743e0e36f58f369928ed0f4/orjson-3.10.15.tar.gz", hash = "sha256:05ca7fe452a2e9d8d9d706a2984c95b9c2ebc5db417ce0b7a49b91d50642a23e", size = 5282482, upload-time = "2025-01-18T15:55:28.817Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/80/bf/76f4f1665f6983385938f0e2a5d7efa12a58171b8456c252f3bae8a4cf75/orjson-3.11.7-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:bd03ea7606833655048dab1a00734a2875e3e86c276e1d772b2a02556f0d895f", size = 228545, upload-time = "2026-02-02T15:37:46.376Z" },
- { url = "https://files.pythonhosted.org/packages/79/53/6c72c002cb13b5a978a068add59b25a8bdf2800ac1c9c8ecdb26d6d97064/orjson-3.11.7-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:89e440ebc74ce8ab5c7bc4ce6757b4a6b1041becb127df818f6997b5c71aa60b", size = 125224, upload-time = "2026-02-02T15:37:47.697Z" },
- { url = "https://files.pythonhosted.org/packages/2c/83/10e48852865e5dd151bdfe652c06f7da484578ed02c5fca938e3632cb0b8/orjson-3.11.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ede977b5fe5ac91b1dffc0a517ca4542d2ec8a6a4ff7b2652d94f640796342a", size = 128154, upload-time = "2026-02-02T15:37:48.954Z" },
- { url = "https://files.pythonhosted.org/packages/6e/52/a66e22a2b9abaa374b4a081d410edab6d1e30024707b87eab7c734afe28d/orjson-3.11.7-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b7b1dae39230a393df353827c855a5f176271c23434cfd2db74e0e424e693e10", size = 123548, upload-time = "2026-02-02T15:37:50.187Z" },
- { url = "https://files.pythonhosted.org/packages/de/38/605d371417021359f4910c496f764c48ceb8997605f8c25bf1dfe58c0ebe/orjson-3.11.7-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed46f17096e28fb28d2975834836a639af7278aa87c84f68ab08fbe5b8bd75fa", size = 129000, upload-time = "2026-02-02T15:37:51.426Z" },
- { url = "https://files.pythonhosted.org/packages/44/98/af32e842b0ffd2335c89714d48ca4e3917b42f5d6ee5537832e069a4b3ac/orjson-3.11.7-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3726be79e36e526e3d9c1aceaadbfb4a04ee80a72ab47b3f3c17fefb9812e7b8", size = 141686, upload-time = "2026-02-02T15:37:52.607Z" },
- { url = "https://files.pythonhosted.org/packages/96/0b/fc793858dfa54be6feee940c1463370ece34b3c39c1ca0aa3845f5ba9892/orjson-3.11.7-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0724e265bc548af1dedebd9cb3d24b4e1c1e685a343be43e87ba922a5c5fff2f", size = 130812, upload-time = "2026-02-02T15:37:53.944Z" },
- { url = "https://files.pythonhosted.org/packages/dc/91/98a52415059db3f374757d0b7f0f16e3b5cd5976c90d1c2b56acaea039e6/orjson-3.11.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7745312efa9e11c17fbd3cb3097262d079da26930ae9ae7ba28fb738367cbad", size = 133440, upload-time = "2026-02-02T15:37:55.615Z" },
- { url = "https://files.pythonhosted.org/packages/dc/b6/cb540117bda61791f46381f8c26c8f93e802892830a6055748d3bb1925ab/orjson-3.11.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f904c24bdeabd4298f7a977ef14ca2a022ca921ed670b92ecd16ab6f3d01f867", size = 138386, upload-time = "2026-02-02T15:37:56.814Z" },
- { url = "https://files.pythonhosted.org/packages/63/1a/50a3201c334a7f17c231eee5f841342190723794e3b06293f26e7cf87d31/orjson-3.11.7-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:b9fc4d0f81f394689e0814617aadc4f2ea0e8025f38c226cbf22d3b5ddbf025d", size = 408853, upload-time = "2026-02-02T15:37:58.291Z" },
- { url = "https://files.pythonhosted.org/packages/87/cd/8de1c67d0be44fdc22701e5989c0d015a2adf391498ad42c4dc589cd3013/orjson-3.11.7-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:849e38203e5be40b776ed2718e587faf204d184fc9a008ae441f9442320c0cab", size = 144130, upload-time = "2026-02-02T15:38:00.163Z" },
- { url = "https://files.pythonhosted.org/packages/0f/fe/d605d700c35dd55f51710d159fc54516a280923cd1b7e47508982fbb387d/orjson-3.11.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4682d1db3bcebd2b64757e0ddf9e87ae5f00d29d16c5cdf3a62f561d08cc3dd2", size = 134818, upload-time = "2026-02-02T15:38:01.507Z" },
- { url = "https://files.pythonhosted.org/packages/e4/e4/15ecc67edb3ddb3e2f46ae04475f2d294e8b60c1825fbe28a428b93b3fbd/orjson-3.11.7-cp312-cp312-win32.whl", hash = "sha256:f4f7c956b5215d949a1f65334cf9d7612dde38f20a95f2315deef167def91a6f", size = 127923, upload-time = "2026-02-02T15:38:02.75Z" },
- { url = "https://files.pythonhosted.org/packages/34/70/2e0855361f76198a3965273048c8e50a9695d88cd75811a5b46444895845/orjson-3.11.7-cp312-cp312-win_amd64.whl", hash = "sha256:bf742e149121dc5648ba0a08ea0871e87b660467ef168a3a5e53bc1fbd64bb74", size = 125007, upload-time = "2026-02-02T15:38:04.032Z" },
- { url = "https://files.pythonhosted.org/packages/68/40/c2051bd19fc467610fed469dc29e43ac65891571138f476834ca192bc290/orjson-3.11.7-cp312-cp312-win_arm64.whl", hash = "sha256:26c3b9132f783b7d7903bf1efb095fed8d4a3a85ec0d334ee8beff3d7a4749d5", size = 126089, upload-time = "2026-02-02T15:38:05.297Z" },
- { url = "https://files.pythonhosted.org/packages/89/25/6e0e52cac5aab51d7b6dcd257e855e1dec1c2060f6b28566c509b4665f62/orjson-3.11.7-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:1d98b30cc1313d52d4af17d9c3d307b08389752ec5f2e5febdfada70b0f8c733", size = 228390, upload-time = "2026-02-02T15:38:06.8Z" },
- { url = "https://files.pythonhosted.org/packages/a5/29/a77f48d2fc8a05bbc529e5ff481fb43d914f9e383ea2469d4f3d51df3d00/orjson-3.11.7-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:d897e81f8d0cbd2abb82226d1860ad2e1ab3ff16d7b08c96ca00df9d45409ef4", size = 125189, upload-time = "2026-02-02T15:38:08.181Z" },
- { url = "https://files.pythonhosted.org/packages/89/25/0a16e0729a0e6a1504f9d1a13cdd365f030068aab64cec6958396b9969d7/orjson-3.11.7-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:814be4b49b228cfc0b3c565acf642dd7d13538f966e3ccde61f4f55be3e20785", size = 128106, upload-time = "2026-02-02T15:38:09.41Z" },
- { url = "https://files.pythonhosted.org/packages/66/da/a2e505469d60666a05ab373f1a6322eb671cb2ba3a0ccfc7d4bc97196787/orjson-3.11.7-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d06e5c5fed5caedd2e540d62e5b1c25e8c82431b9e577c33537e5fa4aa909539", size = 123363, upload-time = "2026-02-02T15:38:10.73Z" },
- { url = "https://files.pythonhosted.org/packages/23/bf/ed73f88396ea35c71b38961734ea4a4746f7ca0768bf28fd551d37e48dd0/orjson-3.11.7-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:31c80ce534ac4ea3739c5ee751270646cbc46e45aea7576a38ffec040b4029a1", size = 129007, upload-time = "2026-02-02T15:38:12.138Z" },
- { url = "https://files.pythonhosted.org/packages/73/3c/b05d80716f0225fc9008fbf8ab22841dcc268a626aa550561743714ce3bf/orjson-3.11.7-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f50979824bde13d32b4320eedd513431c921102796d86be3eee0b58e58a3ecd1", size = 141667, upload-time = "2026-02-02T15:38:13.398Z" },
- { url = "https://files.pythonhosted.org/packages/61/e8/0be9b0addd9bf86abfc938e97441dcd0375d494594b1c8ad10fe57479617/orjson-3.11.7-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9e54f3808e2b6b945078c41aa8d9b5834b28c50843846e97807e5adb75fa9705", size = 130832, upload-time = "2026-02-02T15:38:14.698Z" },
- { url = "https://files.pythonhosted.org/packages/c9/ec/c68e3b9021a31d9ec15a94931db1410136af862955854ed5dd7e7e4f5bff/orjson-3.11.7-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a12b80df61aab7b98b490fe9e4879925ba666fccdfcd175252ce4d9035865ace", size = 133373, upload-time = "2026-02-02T15:38:16.109Z" },
- { url = "https://files.pythonhosted.org/packages/d2/45/f3466739aaafa570cc8e77c6dbb853c48bf56e3b43738020e2661e08b0ac/orjson-3.11.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:996b65230271f1a97026fd0e6a753f51fbc0c335d2ad0c6201f711b0da32693b", size = 138307, upload-time = "2026-02-02T15:38:17.453Z" },
- { url = "https://files.pythonhosted.org/packages/e1/84/9f7f02288da1ffb31405c1be07657afd1eecbcb4b64ee2817b6fe0f785fa/orjson-3.11.7-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:ab49d4b2a6a1d415ddb9f37a21e02e0d5dbfe10b7870b21bf779fc21e9156157", size = 408695, upload-time = "2026-02-02T15:38:18.831Z" },
- { url = "https://files.pythonhosted.org/packages/18/07/9dd2f0c0104f1a0295ffbe912bc8d63307a539b900dd9e2c48ef7810d971/orjson-3.11.7-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:390a1dce0c055ddf8adb6aa94a73b45a4a7d7177b5c584b8d1c1947f2ba60fb3", size = 144099, upload-time = "2026-02-02T15:38:20.28Z" },
- { url = "https://files.pythonhosted.org/packages/a5/66/857a8e4a3292e1f7b1b202883bcdeb43a91566cf59a93f97c53b44bd6801/orjson-3.11.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1eb80451a9c351a71dfaf5b7ccc13ad065405217726b59fdbeadbcc544f9d223", size = 134806, upload-time = "2026-02-02T15:38:22.186Z" },
- { url = "https://files.pythonhosted.org/packages/0a/5b/6ebcf3defc1aab3a338ca777214966851e92efb1f30dc7fc8285216e6d1b/orjson-3.11.7-cp313-cp313-win32.whl", hash = "sha256:7477aa6a6ec6139c5cb1cc7b214643592169a5494d200397c7fc95d740d5fcf3", size = 127914, upload-time = "2026-02-02T15:38:23.511Z" },
- { url = "https://files.pythonhosted.org/packages/00/04/c6f72daca5092e3117840a1b1e88dfc809cc1470cf0734890d0366b684a1/orjson-3.11.7-cp313-cp313-win_amd64.whl", hash = "sha256:b9f95dcdea9d4f805daa9ddf02617a89e484c6985fa03055459f90e87d7a0757", size = 124986, upload-time = "2026-02-02T15:38:24.836Z" },
- { url = "https://files.pythonhosted.org/packages/03/ba/077a0f6f1085d6b806937246860fafbd5b17f3919c70ee3f3d8d9c713f38/orjson-3.11.7-cp313-cp313-win_arm64.whl", hash = "sha256:800988273a014a0541483dc81021247d7eacb0c845a9d1a34a422bc718f41539", size = 126045, upload-time = "2026-02-02T15:38:26.216Z" },
- { url = "https://files.pythonhosted.org/packages/e9/1e/745565dca749813db9a093c5ebc4bac1a9475c64d54b95654336ac3ed961/orjson-3.11.7-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:de0a37f21d0d364954ad5de1970491d7fbd0fb1ef7417d4d56a36dc01ba0c0a0", size = 228391, upload-time = "2026-02-02T15:38:27.757Z" },
- { url = "https://files.pythonhosted.org/packages/46/19/e40f6225da4d3aa0c8dc6e5219c5e87c2063a560fe0d72a88deb59776794/orjson-3.11.7-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:c2428d358d85e8da9d37cba18b8c4047c55222007a84f97156a5b22028dfbfc0", size = 125188, upload-time = "2026-02-02T15:38:29.241Z" },
- { url = "https://files.pythonhosted.org/packages/9d/7e/c4de2babef2c0817fd1f048fd176aa48c37bec8aef53d2fa932983032cce/orjson-3.11.7-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c4bc6c6ac52cdaa267552544c73e486fecbd710b7ac09bc024d5a78555a22f6", size = 128097, upload-time = "2026-02-02T15:38:30.618Z" },
- { url = "https://files.pythonhosted.org/packages/eb/74/233d360632bafd2197f217eee7fb9c9d0229eac0c18128aee5b35b0014fe/orjson-3.11.7-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bd0d68edd7dfca1b2eca9361a44ac9f24b078de3481003159929a0573f21a6bf", size = 123364, upload-time = "2026-02-02T15:38:32.363Z" },
- { url = "https://files.pythonhosted.org/packages/79/51/af79504981dd31efe20a9e360eb49c15f06df2b40e7f25a0a52d9ae888e8/orjson-3.11.7-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:623ad1b9548ef63886319c16fa317848e465a21513b31a6ad7b57443c3e0dcf5", size = 129076, upload-time = "2026-02-02T15:38:33.68Z" },
- { url = "https://files.pythonhosted.org/packages/67/e2/da898eb68b72304f8de05ca6715870d09d603ee98d30a27e8a9629abc64b/orjson-3.11.7-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6e776b998ac37c0396093d10290e60283f59cfe0fc3fccbd0ccc4bd04dd19892", size = 141705, upload-time = "2026-02-02T15:38:34.989Z" },
- { url = "https://files.pythonhosted.org/packages/c5/89/15364d92acb3d903b029e28d834edb8780c2b97404cbf7929aa6b9abdb24/orjson-3.11.7-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:652c6c3af76716f4a9c290371ba2e390ede06f6603edb277b481daf37f6f464e", size = 130855, upload-time = "2026-02-02T15:38:36.379Z" },
- { url = "https://files.pythonhosted.org/packages/c2/8b/ecdad52d0b38d4b8f514be603e69ccd5eacf4e7241f972e37e79792212ec/orjson-3.11.7-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a56df3239294ea5964adf074c54bcc4f0ccd21636049a2cf3ca9cf03b5d03cf1", size = 133386, upload-time = "2026-02-02T15:38:37.704Z" },
- { url = "https://files.pythonhosted.org/packages/b9/0e/45e1dcf10e17d0924b7c9162f87ec7b4ca79e28a0548acf6a71788d3e108/orjson-3.11.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:bda117c4148e81f746655d5a3239ae9bd00cb7bc3ca178b5fc5a5997e9744183", size = 138295, upload-time = "2026-02-02T15:38:39.096Z" },
- { url = "https://files.pythonhosted.org/packages/63/d7/4d2e8b03561257af0450f2845b91fbd111d7e526ccdf737267108075e0ba/orjson-3.11.7-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:23d6c20517a97a9daf1d48b580fcdc6f0516c6f4b5038823426033690b4d2650", size = 408720, upload-time = "2026-02-02T15:38:40.634Z" },
- { url = "https://files.pythonhosted.org/packages/78/cf/d45343518282108b29c12a65892445fc51f9319dc3c552ceb51bb5905ed2/orjson-3.11.7-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:8ff206156006da5b847c9304b6308a01e8cdbc8cce824e2779a5ba71c3def141", size = 144152, upload-time = "2026-02-02T15:38:42.262Z" },
- { url = "https://files.pythonhosted.org/packages/a9/3a/d6001f51a7275aacd342e77b735c71fa04125a3f93c36fee4526bc8c654e/orjson-3.11.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:962d046ee1765f74a1da723f4b33e3b228fe3a48bd307acce5021dfefe0e29b2", size = 134814, upload-time = "2026-02-02T15:38:43.627Z" },
- { url = "https://files.pythonhosted.org/packages/1d/d3/f19b47ce16820cc2c480f7f1723e17f6d411b3a295c60c8ad3aa9ff1c96a/orjson-3.11.7-cp314-cp314-win32.whl", hash = "sha256:89e13dd3f89f1c38a9c9eba5fbf7cdc2d1feca82f5f290864b4b7a6aac704576", size = 127997, upload-time = "2026-02-02T15:38:45.06Z" },
- { url = "https://files.pythonhosted.org/packages/12/df/172771902943af54bf661a8d102bdf2e7f932127968080632bda6054b62c/orjson-3.11.7-cp314-cp314-win_amd64.whl", hash = "sha256:845c3e0d8ded9c9271cd79596b9b552448b885b97110f628fb687aee2eed11c1", size = 124985, upload-time = "2026-02-02T15:38:46.388Z" },
- { url = "https://files.pythonhosted.org/packages/6f/1c/f2a8d8a1b17514660a614ce5f7aac74b934e69f5abc2700cc7ced882a009/orjson-3.11.7-cp314-cp314-win_arm64.whl", hash = "sha256:4a2e9c5be347b937a2e0203866f12bba36082e89b402ddb9e927d5822e43088d", size = 126038, upload-time = "2026-02-02T15:38:47.703Z" },
+ { url = "https://files.pythonhosted.org/packages/66/85/22fe737188905a71afcc4bf7cc4c79cd7f5bbe9ed1fe0aac4ce4c33edc30/orjson-3.10.15-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:9d11c0714fc85bfcf36ada1179400862da3288fc785c30e8297844c867d7505a", size = 249504, upload-time = "2025-01-18T15:54:02.28Z" },
+ { url = "https://files.pythonhosted.org/packages/48/b7/2622b29f3afebe938a0a9037e184660379797d5fd5234e5998345d7a5b43/orjson-3.10.15-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dba5a1e85d554e3897fa9fe6fbcff2ed32d55008973ec9a2b992bd9a65d2352d", size = 125080, upload-time = "2025-01-18T18:11:59.21Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/8f/0b72a48f4403d0b88b2a41450c535b3e8989e8a2d7800659a967efc7c115/orjson-3.10.15-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7723ad949a0ea502df656948ddd8b392780a5beaa4c3b5f97e525191b102fff0", size = 150121, upload-time = "2025-01-18T15:54:03.998Z" },
+ { url = "https://files.pythonhosted.org/packages/06/ec/acb1a20cd49edb2000be5a0404cd43e3c8aad219f376ac8c60b870518c03/orjson-3.10.15-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6fd9bc64421e9fe9bd88039e7ce8e58d4fead67ca88e3a4014b143cec7684fd4", size = 139796, upload-time = "2025-01-18T15:54:06.551Z" },
+ { url = "https://files.pythonhosted.org/packages/33/e1/f7840a2ea852114b23a52a1c0b2bea0a1ea22236efbcdb876402d799c423/orjson-3.10.15-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dadba0e7b6594216c214ef7894c4bd5f08d7c0135f4dd0145600be4fbcc16767", size = 154636, upload-time = "2025-01-18T15:54:08.001Z" },
+ { url = "https://files.pythonhosted.org/packages/fa/da/31543337febd043b8fa80a3b67de627669b88c7b128d9ad4cc2ece005b7a/orjson-3.10.15-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b48f59114fe318f33bbaee8ebeda696d8ccc94c9e90bc27dbe72153094e26f41", size = 130621, upload-time = "2025-01-18T18:12:00.843Z" },
+ { url = "https://files.pythonhosted.org/packages/ed/78/66115dc9afbc22496530d2139f2f4455698be444c7c2475cb48f657cefc9/orjson-3.10.15-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:035fb83585e0f15e076759b6fedaf0abb460d1765b6a36f48018a52858443514", size = 138516, upload-time = "2025-01-18T15:54:09.413Z" },
+ { url = "https://files.pythonhosted.org/packages/22/84/cd4f5fb5427ffcf823140957a47503076184cb1ce15bcc1165125c26c46c/orjson-3.10.15-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d13b7fe322d75bf84464b075eafd8e7dd9eae05649aa2a5354cfa32f43c59f17", size = 130762, upload-time = "2025-01-18T15:54:11.777Z" },
+ { url = "https://files.pythonhosted.org/packages/93/1f/67596b711ba9f56dd75d73b60089c5c92057f1130bb3a25a0f53fb9a583b/orjson-3.10.15-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:7066b74f9f259849629e0d04db6609db4cf5b973248f455ba5d3bd58a4daaa5b", size = 414700, upload-time = "2025-01-18T15:54:14.026Z" },
+ { url = "https://files.pythonhosted.org/packages/7c/0c/6a3b3271b46443d90efb713c3e4fe83fa8cd71cda0d11a0f69a03f437c6e/orjson-3.10.15-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:88dc3f65a026bd3175eb157fea994fca6ac7c4c8579fc5a86fc2114ad05705b7", size = 141077, upload-time = "2025-01-18T15:54:15.612Z" },
+ { url = "https://files.pythonhosted.org/packages/3b/9b/33c58e0bfc788995eccd0d525ecd6b84b40d7ed182dd0751cd4c1322ac62/orjson-3.10.15-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b342567e5465bd99faa559507fe45e33fc76b9fb868a63f1642c6bc0735ad02a", size = 129898, upload-time = "2025-01-18T15:54:17.049Z" },
+ { url = "https://files.pythonhosted.org/packages/01/c1/d577ecd2e9fa393366a1ea0a9267f6510d86e6c4bb1cdfb9877104cac44c/orjson-3.10.15-cp312-cp312-win32.whl", hash = "sha256:0a4f27ea5617828e6b58922fdbec67b0aa4bb844e2d363b9244c47fa2180e665", size = 142566, upload-time = "2025-01-18T15:54:18.507Z" },
+ { url = "https://files.pythonhosted.org/packages/ed/eb/a85317ee1732d1034b92d56f89f1de4d7bf7904f5c8fb9dcdd5b1c83917f/orjson-3.10.15-cp312-cp312-win_amd64.whl", hash = "sha256:ef5b87e7aa9545ddadd2309efe6824bd3dd64ac101c15dae0f2f597911d46eaa", size = 133732, upload-time = "2025-01-18T15:54:20.027Z" },
+ { url = "https://files.pythonhosted.org/packages/06/10/fe7d60b8da538e8d3d3721f08c1b7bff0491e8fa4dd3bf11a17e34f4730e/orjson-3.10.15-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:bae0e6ec2b7ba6895198cd981b7cca95d1487d0147c8ed751e5632ad16f031a6", size = 249399, upload-time = "2025-01-18T15:54:22.46Z" },
+ { url = "https://files.pythonhosted.org/packages/6b/83/52c356fd3a61abd829ae7e4366a6fe8e8863c825a60d7ac5156067516edf/orjson-3.10.15-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f93ce145b2db1252dd86af37d4165b6faa83072b46e3995ecc95d4b2301b725a", size = 125044, upload-time = "2025-01-18T18:12:02.747Z" },
+ { url = "https://files.pythonhosted.org/packages/55/b2/d06d5901408e7ded1a74c7c20d70e3a127057a6d21355f50c90c0f337913/orjson-3.10.15-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7c203f6f969210128af3acae0ef9ea6aab9782939f45f6fe02d05958fe761ef9", size = 150066, upload-time = "2025-01-18T15:54:24.752Z" },
+ { url = "https://files.pythonhosted.org/packages/75/8c/60c3106e08dc593a861755781c7c675a566445cc39558677d505878d879f/orjson-3.10.15-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8918719572d662e18b8af66aef699d8c21072e54b6c82a3f8f6404c1f5ccd5e0", size = 139737, upload-time = "2025-01-18T15:54:26.236Z" },
+ { url = "https://files.pythonhosted.org/packages/6a/8c/ae00d7d0ab8a4490b1efeb01ad4ab2f1982e69cc82490bf8093407718ff5/orjson-3.10.15-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f71eae9651465dff70aa80db92586ad5b92df46a9373ee55252109bb6b703307", size = 154804, upload-time = "2025-01-18T15:54:28.275Z" },
+ { url = "https://files.pythonhosted.org/packages/22/86/65dc69bd88b6dd254535310e97bc518aa50a39ef9c5a2a5d518e7a223710/orjson-3.10.15-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e117eb299a35f2634e25ed120c37c641398826c2f5a3d3cc39f5993b96171b9e", size = 130583, upload-time = "2025-01-18T18:12:04.343Z" },
+ { url = "https://files.pythonhosted.org/packages/bb/00/6fe01ededb05d52be42fabb13d93a36e51f1fd9be173bd95707d11a8a860/orjson-3.10.15-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:13242f12d295e83c2955756a574ddd6741c81e5b99f2bef8ed8d53e47a01e4b7", size = 138465, upload-time = "2025-01-18T15:54:29.808Z" },
+ { url = "https://files.pythonhosted.org/packages/db/2f/4cc151c4b471b0cdc8cb29d3eadbce5007eb0475d26fa26ed123dca93b33/orjson-3.10.15-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7946922ada8f3e0b7b958cc3eb22cfcf6c0df83d1fe5521b4a100103e3fa84c8", size = 130742, upload-time = "2025-01-18T15:54:31.289Z" },
+ { url = "https://files.pythonhosted.org/packages/9f/13/8a6109e4b477c518498ca37963d9c0eb1508b259725553fb53d53b20e2ea/orjson-3.10.15-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:b7155eb1623347f0f22c38c9abdd738b287e39b9982e1da227503387b81b34ca", size = 414669, upload-time = "2025-01-18T15:54:33.687Z" },
+ { url = "https://files.pythonhosted.org/packages/22/7b/1d229d6d24644ed4d0a803de1b0e2df832032d5beda7346831c78191b5b2/orjson-3.10.15-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:208beedfa807c922da4e81061dafa9c8489c6328934ca2a562efa707e049e561", size = 141043, upload-time = "2025-01-18T15:54:35.482Z" },
+ { url = "https://files.pythonhosted.org/packages/cc/d3/6dc91156cf12ed86bed383bcb942d84d23304a1e57b7ab030bf60ea130d6/orjson-3.10.15-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eca81f83b1b8c07449e1d6ff7074e82e3fd6777e588f1a6632127f286a968825", size = 129826, upload-time = "2025-01-18T15:54:37.906Z" },
+ { url = "https://files.pythonhosted.org/packages/b3/38/c47c25b86f6996f1343be721b6ea4367bc1c8bc0fc3f6bbcd995d18cb19d/orjson-3.10.15-cp313-cp313-win32.whl", hash = "sha256:c03cd6eea1bd3b949d0d007c8d57049aa2b39bd49f58b4b2af571a5d3833d890", size = 142542, upload-time = "2025-01-18T15:54:40.181Z" },
+ { url = "https://files.pythonhosted.org/packages/27/f1/1d7ec15b20f8ce9300bc850de1e059132b88990e46cd0ccac29cbf11e4f9/orjson-3.10.15-cp313-cp313-win_amd64.whl", hash = "sha256:fd56a26a04f6ba5fb2045b0acc487a63162a958ed837648c5781e1fe3316cfbf", size = 133444, upload-time = "2025-01-18T15:54:42.076Z" },
]
[[package]]
@@ -3815,7 +3804,7 @@ name = "pexpect"
version = "4.9.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "ptyprocess" },
+ { name = "ptyprocess", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450, upload-time = "2023-11-25T09:07:26.339Z" }
wheels = [
@@ -4458,7 +4447,7 @@ name = "pyroscope-io"
version = "0.8.16"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "cffi" },
+ { name = "cffi", marker = "sys_platform != 'win32'" },
]
wheels = [
{ url = "https://files.pythonhosted.org/packages/a8/50/607b38b120ba8adad954119ba512c53590c793f0cf7f009ba6549e4e1d77/pyroscope_io-0.8.16-py2.py3-none-macosx_11_0_arm64.whl", hash = "sha256:e07edcfd59f5bdce42948b92c9b118c824edbd551730305f095a6b9af401a9e8", size = 3138869, upload-time = "2026-01-22T06:23:24.664Z" },
@@ -4561,20 +4550,20 @@ wheels = [
[[package]]
name = "python-dotenv"
-version = "1.2.2"
+version = "1.0.1"
source = { registry = "https://pypi.org/simple" }
-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" }
+sdist = { url = "https://files.pythonhosted.org/packages/bc/57/e84d88dfe0aec03b7a2d4327012c1627ab5f03652216c63d49846d7a6c58/python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca", size = 39115, upload-time = "2024-01-23T06:33:00.505Z" }
wheels = [
- { 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" },
+ { url = "https://files.pythonhosted.org/packages/6a/3e/b68c118422ec867fa7ab88444e1274aa40681c606d59ac27de5a5588f082/python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a", size = 19863, upload-time = "2024-01-23T06:32:58.246Z" },
]
[[package]]
name = "python-multipart"
-version = "0.0.22"
+version = "0.0.20"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/94/01/979e98d542a70714b0cb2b6728ed0b7c46792b695e3eaec3e20711271ca3/python_multipart-0.0.22.tar.gz", hash = "sha256:7340bef99a7e0032613f56dc36027b959fd3b30a787ed62d310e951f7c3a3a58", size = 37612, upload-time = "2026-01-25T10:15:56.219Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/f3/87/f44d7c9f274c7ee665a29b885ec97089ec5dc034c7f3fafa03da9e39a09e/python_multipart-0.0.20.tar.gz", hash = "sha256:8dd0cab45b8e23064ae09147625994d090fa46f5b0d1e13af944c331a7fa9d13", size = 37158, upload-time = "2024-12-16T19:45:46.972Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/1b/d0/397f9626e711ff749a95d96b7af99b9c566a9bb5129b8e4c10fc4d100304/python_multipart-0.0.22-py3-none-any.whl", hash = "sha256:2b2cd894c83d21bf49d702499531c7bafd057d730c201782048f7945d82de155", size = 24579, upload-time = "2026-01-25T10:15:54.811Z" },
+ { url = "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl", hash = "sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104", size = 24546, upload-time = "2024-12-16T19:45:44.423Z" },
]
[[package]]
@@ -4913,15 +4902,15 @@ wheels = [
[[package]]
name = "rich"
-version = "13.7.1"
+version = "13.9.4"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "markdown-it-py" },
{ name = "pygments" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/b3/01/c954e134dc440ab5f96952fe52b4fdc64225530320a910473c1fe270d9aa/rich-13.7.1.tar.gz", hash = "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432", size = 221248, upload-time = "2024-02-28T14:51:19.472Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/ab/3a/0316b28d0761c6734d6bc14e770d85506c986c85ffb239e688eeaab2c2bc/rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098", size = 223149, upload-time = "2024-11-01T16:43:57.873Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/87/67/a37f6214d0e9fe57f6ae54b2956d550ca8365857f42a1ce0392bb21d9410/rich-13.7.1-py3-none-any.whl", hash = "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222", size = 240681, upload-time = "2024-02-28T14:51:14.353Z" },
+ { url = "https://files.pythonhosted.org/packages/19/71/39c7c0d87f8d4e6c020a393182060eaefeeae6c01dab6a84ec346f2567df/rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90", size = 242424, upload-time = "2024-11-01T16:43:55.817Z" },
]
[[package]]
@@ -5055,14 +5044,14 @@ wheels = [
[[package]]
name = "s3transfer"
-version = "0.14.0"
+version = "0.16.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "botocore" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/62/74/8d69dcb7a9efe8baa2046891735e5dfe433ad558ae23d9e3c14c633d1d58/s3transfer-0.14.0.tar.gz", hash = "sha256:eff12264e7c8b4985074ccce27a3b38a485bb7f7422cc8046fee9be4983e4125", size = 151547, upload-time = "2025-09-09T19:23:31.089Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/46/29/af14f4ef3c11a50435308660e2cc68761c9a7742475e0585cd4396b91777/s3transfer-0.16.1.tar.gz", hash = "sha256:8e424355754b9ccb32467bdc568edf55be82692ef2002d934b1311dbb3b9e524", size = 154801, upload-time = "2026-04-22T20:36:06.475Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/48/f0/ae7ca09223a81a1d890b2557186ea015f6e0502e9b8cb8e1813f1d8cfa4e/s3transfer-0.14.0-py3-none-any.whl", hash = "sha256:ea3b790c7077558ed1f02a3072fb3cb992bbbd253392f4b6e9e8976941c7d456", size = 85712, upload-time = "2025-09-09T19:23:30.041Z" },
+ { url = "https://files.pythonhosted.org/packages/03/19/90d7d4ed51932c022d53f1d02d564b62d10e272692a1f9b76425c1ad2a02/s3transfer-0.16.1-py3-none-any.whl", hash = "sha256:61bcd00ccb83b21a0fe7e91a553fff9729d46c83b4e0106e7c314a733891f7c2", size = 86825, upload-time = "2026-04-22T20:36:04.992Z" },
]
[[package]]
@@ -5417,15 +5406,15 @@ wheels = [
[[package]]
name = "starlette"
-version = "0.52.1"
+version = "0.50.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "anyio" },
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/c4/68/79977123bb7be889ad680d79a40f339082c1978b5cfcf62c2d8d196873ac/starlette-0.52.1.tar.gz", hash = "sha256:834edd1b0a23167694292e94f597773bc3f89f362be6effee198165a35d62933", size = 2653702, upload-time = "2026-01-18T13:34:11.062Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/ba/b8/73a0e6a6e079a9d9cfa64113d771e421640b6f679a52eeb9b32f72d871a1/starlette-0.50.0.tar.gz", hash = "sha256:a2a17b22203254bcbc2e1f926d2d55f3f9497f769416b3190768befe598fa3ca", size = 2646985, upload-time = "2025-11-01T15:25:27.516Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl", hash = "sha256:0029d43eb3d273bc4f83a08720b4912ea4b071087a3b48db01b7c839f7954d74", size = 74272, upload-time = "2026-01-18T13:34:09.188Z" },
+ { url = "https://files.pythonhosted.org/packages/d9/52/1064f510b141bd54025f9b55105e26d1fa970b9be67ad766380a3c9b74b0/starlette-0.50.0-py3-none-any.whl", hash = "sha256:9e5391843ec9b6e472eed1365a78c8098cfceb7a74bfd4d6b1c0c0095efb3bca", size = 74033, upload-time = "2025-11-01T15:25:25.461Z" },
]
[[package]]
@@ -5439,13 +5428,14 @@ wheels = [
[[package]]
name = "strix-agent"
-version = "0.8.2"
+version = "0.8.3"
source = { editable = "." }
dependencies = [
{ name = "cvss" },
{ name = "defusedxml" },
{ name = "docker" },
{ name = "litellm", extra = ["proxy"] },
+ { name = "openai-agents", extra = ["litellm"] },
{ name = "opentelemetry-exporter-otlp-proto-http" },
{ name = "pydantic", extra = ["email"] },
{ name = "requests" },
@@ -5500,8 +5490,9 @@ requires-dist = [
{ name = "gql", extras = ["requests"], marker = "extra == 'sandbox'", specifier = ">=3.5.3" },
{ name = "ipython", marker = "extra == 'sandbox'", specifier = ">=9.3.0" },
{ name = "libtmux", marker = "extra == 'sandbox'", specifier = ">=0.46.2" },
- { name = "litellm", extras = ["proxy"], specifier = ">=1.81.1,<1.82.0" },
+ { name = "litellm", extras = ["proxy"], specifier = ">=1.83.0" },
{ name = "numpydoc", marker = "extra == 'sandbox'", specifier = ">=1.8.0" },
+ { name = "openai-agents", extras = ["litellm"], specifier = "==0.14.6" },
{ name = "openhands-aci", marker = "extra == 'sandbox'", specifier = ">=0.3.0" },
{ name = "opentelemetry-exporter-otlp-proto-http", specifier = ">=1.40.0" },
{ name = "playwright", marker = "extra == 'sandbox'", specifier = ">=1.48.0" },
@@ -5511,7 +5502,7 @@ requires-dist = [
{ name = "rich" },
{ name = "scrubadub", specifier = ">=2.0.1" },
{ name = "tenacity", specifier = ">=9.0.0" },
- { name = "textual", specifier = ">=4.0.0" },
+ { name = "textual", specifier = ">=6.0.0" },
{ name = "traceloop-sdk", specifier = ">=0.53.0" },
{ name = "uvicorn", marker = "extra == 'sandbox'" },
{ name = "xmltodict", specifier = ">=0.13.0" },
@@ -5772,6 +5763,14 @@ version = "0.23.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/22/85/a61c782afbb706a47d990eaee6977e7c2bd013771c5bf5c81c617684f286/tree_sitter_c_sharp-0.23.1.tar.gz", hash = "sha256:322e2cfd3a547a840375276b2aea3335fa6458aeac082f6c60fec3f745c967eb", size = 1317728, upload-time = "2024-11-11T05:25:32.535Z" }
wheels = [
+ { url = "https://files.pythonhosted.org/packages/4c/dc/d4a0ad9e466263728f80f9dac399609473af01c1aba2ea3ea8879ce56276/tree_sitter_c_sharp-0.23.1-cp310-abi3-macosx_10_9_x86_64.whl", hash = "sha256:e87be7572991552606a3155d2f6c2045ded8bce94bfd9f74bf521d949c219a1c", size = 333661, upload-time = "2026-04-14T15:11:14.227Z" },
+ { url = "https://files.pythonhosted.org/packages/61/7a/5c862770460a2e27079e725585ad2718100373c09448c14e36934ef44414/tree_sitter_c_sharp-0.23.1-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:86c2fdf178c66474a1be2965602818d30780e4e3ed890e3c206931f65d9a154c", size = 376295, upload-time = "2026-04-14T15:11:15.346Z" },
+ { url = "https://files.pythonhosted.org/packages/67/18/0571a3a34c0feda60a9c37cf6dd5edfdbc24f8fcb1e48b6b6eb0f324ad2a/tree_sitter_c_sharp-0.23.1-cp310-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:035d259e64c41d02cc45afc3b8b46388b232e7d16d84734d851cca7334761da5", size = 358331, upload-time = "2026-04-14T15:11:16.418Z" },
+ { url = "https://files.pythonhosted.org/packages/44/65/0f7e1f50f6365338eb700f01710da0adc49a49fa9a8443e5a90ea4f29491/tree_sitter_c_sharp-0.23.1-cp310-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fa472cb9de7e14fee9408e144f29f68384cd8e9c677dff0002da19f361a59bdf", size = 359444, upload-time = "2026-04-14T15:11:17.509Z" },
+ { url = "https://files.pythonhosted.org/packages/98/60/129bd56d5ef22b4ae254940a09b6d3ed873093218868a3f9635d571d514e/tree_sitter_c_sharp-0.23.1-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:1a0ea86eccff74e85ab4a2cf77c813fad7c84162962ce242dff0c51601028832", size = 358143, upload-time = "2026-04-14T15:11:18.755Z" },
+ { url = "https://files.pythonhosted.org/packages/7c/cd/e12cdca47e0c56151cb4b156d48091b7bc1d968e072c1656cf6b73fe7218/tree_sitter_c_sharp-0.23.1-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:8ab26dc998bbd4b4287b129f67c10ca715deb402ed77d0645674490ea509097e", size = 357524, upload-time = "2026-04-14T15:11:19.717Z" },
+ { url = "https://files.pythonhosted.org/packages/6a/2c/f742d60f818cba83760f4975c7158d1c96c36b5807e95a843db7fb8c64b7/tree_sitter_c_sharp-0.23.1-cp310-abi3-win_amd64.whl", hash = "sha256:d4486653feaff3314ef45534dcb6f9ea8ab3aa160896287c6473788f88eb38be", size = 338755, upload-time = "2026-04-14T15:11:20.883Z" },
+ { url = "https://files.pythonhosted.org/packages/5b/e4/8a8642b9bba86248ac2facc81ffb187c06c6768efa56c79d61fab70d736b/tree_sitter_c_sharp-0.23.1-cp310-abi3-win_arm64.whl", hash = "sha256:e7a14b76ec23cc8386cf662d5ea602d81331376c93ca6299a97b174047790345", size = 337261, upload-time = "2026-04-14T15:11:22.111Z" },
{ url = "https://files.pythonhosted.org/packages/58/04/f6c2df4c53a588ccd88d50851155945cff8cd887bd70c175e00aaade7edf/tree_sitter_c_sharp-0.23.1-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2b612a6e5bd17bb7fa2aab4bb6fc1fba45c94f09cb034ab332e45603b86e32fd", size = 372235, upload-time = "2024-11-11T05:25:19.424Z" },
{ url = "https://files.pythonhosted.org/packages/99/10/1aa9486f1e28fc22810fa92cbdc54e1051e7f5536a5e5b5e9695f609b31e/tree_sitter_c_sharp-0.23.1-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:1a8b98f62bc53efcd4d971151950c9b9cd5cbe3bacdb0cd69fdccac63350d83e", size = 419046, upload-time = "2024-11-11T05:25:20.679Z" },
{ url = "https://files.pythonhosted.org/packages/0f/21/13df29f8fcb9ba9f209b7b413a4764b673dfd58989a0dd67e9c7e19e9c2e/tree_sitter_c_sharp-0.23.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:986e93d845a438ec3c4416401aa98e6a6f6631d644bbbc2e43fcb915c51d255d", size = 415999, upload-time = "2024-11-11T05:25:22.359Z" },
@@ -5833,7 +5832,7 @@ wheels = [
[[package]]
name = "typer"
-version = "0.24.1"
+version = "0.23.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "annotated-doc" },
@@ -5841,9 +5840,21 @@ dependencies = [
{ name = "rich" },
{ name = "shellingham" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/f5/24/cb09efec5cc954f7f9b930bf8279447d24618bb6758d4f6adf2574c41780/typer-0.24.1.tar.gz", hash = "sha256:e39b4732d65fbdcde189ae76cf7cd48aeae72919dea1fdfc16593be016256b45", size = 118613, upload-time = "2026-02-21T16:54:40.609Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/fd/07/b822e1b307d40e263e8253d2384cf98c51aa2368cc7ba9a07e523a1d964b/typer-0.23.1.tar.gz", hash = "sha256:2070374e4d31c83e7b61362fd859aa683576432fd5b026b060ad6b4cd3b86134", size = 120047, upload-time = "2026-02-13T10:04:30.984Z" }
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" },
+ { url = "https://files.pythonhosted.org/packages/d5/91/9b286ab899c008c2cb05e8be99814807e7fbbd33f0c0c960470826e5ac82/typer-0.23.1-py3-none-any.whl", hash = "sha256:3291ad0d3c701cbf522012faccfbb29352ff16ad262db2139e6b01f15781f14e", size = 56813, upload-time = "2026-02-13T10:04:32.008Z" },
+]
+
+[[package]]
+name = "types-requests"
+version = "2.33.0.20260408"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "urllib3" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/69/6a/749dc53a54a3f35842c1f8197b3ca6b54af6d7458a1bfc75f6629b6da666/types_requests-2.33.0.20260408.tar.gz", hash = "sha256:95b9a86376807a216b2fb412b47617b202091c3ea7c078f47cc358d5528ccb7b", size = 23882, upload-time = "2026-04-08T04:34:49.33Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/90/b8/78fd6c037de4788c040fdd323b3369804400351b7827473920f6c1d03c10/types_requests-2.33.0.20260408-py3-none-any.whl", hash = "sha256:81f31d5ea4acb39f03be7bc8bed569ba6d5a9c5d97e89f45ac43d819b68ca50f", size = 20739, upload-time = "2026-04-08T04:34:48.325Z" },
]
[[package]]
@@ -5908,15 +5919,15 @@ wheels = [
[[package]]
name = "uvicorn"
-version = "0.42.0"
+version = "0.33.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "click" },
{ name = "h11" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/e3/ad/4a96c425be6fb67e0621e62d86c402b4a17ab2be7f7c055d9bd2f638b9e2/uvicorn-0.42.0.tar.gz", hash = "sha256:9b1f190ce15a2dd22e7758651d9b6d12df09a13d51ba5bf4fc33c383a48e1775", size = 85393, upload-time = "2026-03-16T06:19:50.077Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/cb/81/a083ae41716b00df56d45d4b5f6ca8e90fc233a62e6c04ab3ad3c476b6c4/uvicorn-0.33.0.tar.gz", hash = "sha256:3577119f82b7091cf4d3d4177bfda0bae4723ed92ab1439e8d779de880c9cc59", size = 76590, upload-time = "2024-12-14T11:14:46.526Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/0a/89/f8827ccff89c1586027a105e5630ff6139a64da2515e24dafe860bd9ae4d/uvicorn-0.42.0-py3-none-any.whl", hash = "sha256:96c30f5c7abe6f74ae8900a70e92b85ad6613b745d4879eb9b16ccad15645359", size = 68830, upload-time = "2026-03-16T06:19:48.325Z" },
+ { url = "https://files.pythonhosted.org/packages/98/79/2e2620337ef1e4ef7a058b351603b765f59ac28e6e3ac7c5e7cdee9ea1ab/uvicorn-0.33.0-py3-none-any.whl", hash = "sha256:2c30de4aeea83661a520abab179b24084a0019c0c1bbe137e5409f741cbde5f8", size = 62297, upload-time = "2024-12-14T11:14:43.408Z" },
]
[[package]]