From 5bff24096cb444c994cda9a244d1d2b49dd640fa Mon Sep 17 00:00:00 2001 From: qiupinhua Date: Thu, 5 Feb 2026 17:39:18 +0800 Subject: [PATCH 01/60] feat: implement OpenAI Codex OAuth login and provider integration --- nanobot/auth/__init__.py | 13 + nanobot/auth/codex_oauth.py | 607 +++++++++++++++++++++ nanobot/cli/commands.py | 104 +++- nanobot/providers/__init__.py | 3 +- nanobot/providers/openai_codex_provider.py | 333 +++++++++++ 5 files changed, 1041 insertions(+), 19 deletions(-) create mode 100644 nanobot/auth/__init__.py create mode 100644 nanobot/auth/codex_oauth.py create mode 100644 nanobot/providers/openai_codex_provider.py diff --git a/nanobot/auth/__init__.py b/nanobot/auth/__init__.py new file mode 100644 index 0000000..e74e1c2 --- /dev/null +++ b/nanobot/auth/__init__.py @@ -0,0 +1,13 @@ +"""鉴权相关模块。""" + +from nanobot.auth.codex_oauth import ( + ensure_codex_token_available, + get_codex_token, + login_codex_oauth_interactive, +) + +__all__ = [ + "ensure_codex_token_available", + "get_codex_token", + "login_codex_oauth_interactive", +] diff --git a/nanobot/auth/codex_oauth.py b/nanobot/auth/codex_oauth.py new file mode 100644 index 0000000..0784267 --- /dev/null +++ b/nanobot/auth/codex_oauth.py @@ -0,0 +1,607 @@ +"""OpenAI Codex OAuth implementation.""" + +from __future__ import annotations + +import asyncio +import base64 +import hashlib +import json +import os +import socket +import sys +import threading +import time +import urllib.parse +import webbrowser +from dataclasses import dataclass +from http.server import BaseHTTPRequestHandler, HTTPServer +from pathlib import Path +from typing import Any, Callable + +import httpx + +from nanobot.utils.helpers import ensure_dir, get_data_path + +# Fixed parameters (sourced from the official Codex CLI OAuth client). +CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann" +AUTHORIZE_URL = "https://auth.openai.com/oauth/authorize" +TOKEN_URL = "https://auth.openai.com/oauth/token" +REDIRECT_URI = "http://localhost:1455/auth/callback" +SCOPE = "openid profile email offline_access" +JWT_CLAIM_PATH = "https://api.openai.com/auth" + +DEFAULT_ORIGINATOR = "nanobot" +TOKEN_FILENAME = "codex.json" +MANUAL_PROMPT_DELAY_SEC = 3 +SUCCESS_HTML = ( + "" + "" + "" + "" + "" + "Authentication successful" + "" + "" + "

Authentication successful. Return to your terminal to continue.

" + "" + "" +) + + +@dataclass +class CodexToken: + """Codex OAuth token data structure.""" + access: str + refresh: str + expires: int + account_id: str + + +def _base64url(data: bytes) -> str: + return base64.urlsafe_b64encode(data).rstrip(b"=").decode("utf-8") + + +def _decode_base64url(data: str) -> bytes: + padding = "=" * (-len(data) % 4) + return base64.urlsafe_b64decode(data + padding) + + +def _generate_pkce() -> tuple[str, str]: + verifier = _base64url(os.urandom(32)) + challenge = _base64url(hashlib.sha256(verifier.encode("utf-8")).digest()) + return verifier, challenge + + +def _create_state() -> str: + return _base64url(os.urandom(16)) + + +def _get_token_path() -> Path: + auth_dir = ensure_dir(get_data_path() / "auth") + return auth_dir / TOKEN_FILENAME + + +def _parse_authorization_input(raw: str) -> tuple[str | None, str | None]: + value = raw.strip() + if not value: + return None, None + try: + url = urllib.parse.urlparse(value) + qs = urllib.parse.parse_qs(url.query) + code = qs.get("code", [None])[0] + state = qs.get("state", [None])[0] + if code: + return code, state + except Exception: + pass + + if "#" in value: + parts = value.split("#", 1) + return parts[0] or None, parts[1] or None + + if "code=" in value: + qs = urllib.parse.parse_qs(value) + return qs.get("code", [None])[0], qs.get("state", [None])[0] + + return value, None + + +def _decode_account_id(access_token: str) -> str: + parts = access_token.split(".") + if len(parts) != 3: + raise ValueError("Invalid JWT token") + payload = json.loads(_decode_base64url(parts[1]).decode("utf-8")) + auth = payload.get(JWT_CLAIM_PATH) or {} + account_id = auth.get("chatgpt_account_id") + if not account_id: + raise ValueError("Failed to extract account_id from token") + return str(account_id) + + +class _OAuthHandler(BaseHTTPRequestHandler): + """Local callback HTTP handler.""" + + server_version = "NanobotOAuth/1.0" + protocol_version = "HTTP/1.1" + + def do_GET(self) -> None: # noqa: N802 + try: + url = urllib.parse.urlparse(self.path) + if url.path != "/auth/callback": + self.send_response(404) + self.end_headers() + self.wfile.write(b"Not found") + return + + qs = urllib.parse.parse_qs(url.query) + code = qs.get("code", [None])[0] + state = qs.get("state", [None])[0] + + if state != self.server.expected_state: + self.send_response(400) + self.end_headers() + self.wfile.write(b"State mismatch") + return + + if not code: + self.send_response(400) + self.end_headers() + self.wfile.write(b"Missing code") + return + + self.server.code = code + try: + if getattr(self.server, "on_code", None): + self.server.on_code(code) + except Exception: + pass + body = SUCCESS_HTML.encode("utf-8") + self.send_response(200) + self.send_header("Content-Type", "text/html; charset=utf-8") + self.send_header("Content-Length", str(len(body))) + self.send_header("Connection", "close") + self.end_headers() + self.wfile.write(body) + try: + self.wfile.flush() + except Exception: + pass + self.close_connection = True + except Exception: + self.send_response(500) + self.end_headers() + self.wfile.write(b"Internal error") + + def log_message(self, format: str, *args: Any) -> None: # noqa: A003 + # Suppress default logs to avoid noisy output. + return + + +class _OAuthServer(HTTPServer): + """OAuth callback server with state.""" + + def __init__( + self, + server_address: tuple[str, int], + expected_state: str, + on_code: Callable[[str], None] | None = None, + ): + super().__init__(server_address, _OAuthHandler) + self.expected_state = expected_state + self.code: str | None = None + self.on_code = on_code + + +def _start_local_server( + state: str, + on_code: Callable[[str], None] | None = None, +) -> tuple[_OAuthServer | None, str | None]: + """Start a local OAuth callback server on the first available localhost address.""" + try: + addrinfos = socket.getaddrinfo("localhost", 1455, type=socket.SOCK_STREAM) + except OSError as exc: + return None, f"Failed to resolve localhost: {exc}" + + last_error: OSError | None = None + for family, _socktype, _proto, _canonname, sockaddr in addrinfos: + try: + # 兼容 IPv4/IPv6 监听,避免 localhost 解析到 ::1 时收不到回调 + class _AddrOAuthServer(_OAuthServer): + address_family = family + + server = _AddrOAuthServer(sockaddr, state, on_code=on_code) + thread = threading.Thread(target=server.serve_forever, daemon=True) + thread.start() + return server, None + except OSError as exc: + last_error = exc + continue + + if last_error: + return None, f"Local callback server failed to start: {last_error}" + return None, "Local callback server failed to start: unknown error" + + +def _exchange_code_for_token(code: str, verifier: str) -> CodexToken: + data = { + "grant_type": "authorization_code", + "client_id": CLIENT_ID, + "code": code, + "code_verifier": verifier, + "redirect_uri": REDIRECT_URI, + } + with httpx.Client(timeout=30.0) as client: + response = client.post(TOKEN_URL, data=data, headers={"Content-Type": "application/x-www-form-urlencoded"}) + if response.status_code != 200: + raise RuntimeError(f"Token exchange failed: {response.status_code} {response.text}") + + payload = response.json() + access = payload.get("access_token") + refresh = payload.get("refresh_token") + expires_in = payload.get("expires_in") + if not access or not refresh or not isinstance(expires_in, int): + raise RuntimeError("Token response missing fields") + print("Received access token:", access) + account_id = _decode_account_id(access) + return CodexToken( + access=access, + refresh=refresh, + expires=int(time.time() * 1000 + expires_in * 1000), + account_id=account_id, + ) + + +async def _exchange_code_for_token_async(code: str, verifier: str) -> CodexToken: + data = { + "grant_type": "authorization_code", + "client_id": CLIENT_ID, + "code": code, + "code_verifier": verifier, + "redirect_uri": REDIRECT_URI, + } + async with httpx.AsyncClient(timeout=30.0) as client: + response = await client.post( + TOKEN_URL, + data=data, + headers={"Content-Type": "application/x-www-form-urlencoded"}, + ) + if response.status_code != 200: + raise RuntimeError(f"Token exchange failed: {response.status_code} {response.text}") + + payload = response.json() + access = payload.get("access_token") + refresh = payload.get("refresh_token") + expires_in = payload.get("expires_in") + if not access or not refresh or not isinstance(expires_in, int): + raise RuntimeError("Token response missing fields") + + account_id = _decode_account_id(access) + return CodexToken( + access=access, + refresh=refresh, + expires=int(time.time() * 1000 + expires_in * 1000), + account_id=account_id, + ) + + +def _refresh_token(refresh_token: str) -> CodexToken: + data = { + "grant_type": "refresh_token", + "refresh_token": refresh_token, + "client_id": CLIENT_ID, + } + with httpx.Client(timeout=30.0) as client: + response = client.post(TOKEN_URL, data=data, headers={"Content-Type": "application/x-www-form-urlencoded"}) + if response.status_code != 200: + raise RuntimeError(f"Token refresh failed: {response.status_code} {response.text}") + + payload = response.json() + access = payload.get("access_token") + refresh = payload.get("refresh_token") + expires_in = payload.get("expires_in") + if not access or not refresh or not isinstance(expires_in, int): + raise RuntimeError("Token refresh response missing fields") + + account_id = _decode_account_id(access) + return CodexToken( + access=access, + refresh=refresh, + expires=int(time.time() * 1000 + expires_in * 1000), + account_id=account_id, + ) + + +def _load_token_file() -> CodexToken | None: + path = _get_token_path() + if not path.exists(): + return None + try: + data = json.loads(path.read_text(encoding="utf-8")) + return CodexToken( + access=data["access"], + refresh=data["refresh"], + expires=int(data["expires"]), + account_id=data["account_id"], + ) + except Exception: + return None + + +def _save_token_file(token: CodexToken) -> None: + path = _get_token_path() + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text( + json.dumps( + { + "access": token.access, + "refresh": token.refresh, + "expires": token.expires, + "account_id": token.account_id, + }, + ensure_ascii=True, + indent=2, + ), + encoding="utf-8", + ) + try: + os.chmod(path, 0o600) + except Exception: + # Ignore permission setting failures. + pass + + +def _try_import_codex_cli_token() -> CodexToken | None: + codex_path = Path.home() / ".codex" / "auth.json" + if not codex_path.exists(): + return None + try: + data = json.loads(codex_path.read_text(encoding="utf-8")) + tokens = data.get("tokens") or {} + access = tokens.get("access_token") + refresh = tokens.get("refresh_token") + account_id = tokens.get("account_id") + if not access or not refresh or not account_id: + return None + try: + mtime = codex_path.stat().st_mtime + expires = int(mtime * 1000 + 60 * 60 * 1000) + except Exception: + expires = int(time.time() * 1000 + 60 * 60 * 1000) + token = CodexToken( + access=str(access), + refresh=str(refresh), + expires=expires, + account_id=str(account_id), + ) + _save_token_file(token) + return token + except Exception: + return None + + +class _FileLock: + """Simple file lock to reduce concurrent refreshes.""" + + def __init__(self, path: Path): + self._path = path + self._fp = None + + def __enter__(self) -> "_FileLock": + self._path.parent.mkdir(parents=True, exist_ok=True) + self._fp = open(self._path, "a+") + try: + import fcntl + + fcntl.flock(self._fp.fileno(), fcntl.LOCK_EX) + except Exception: + # Non-POSIX or failed lock: continue without locking. + pass + return self + + def __exit__(self, exc_type, exc, tb) -> None: + try: + import fcntl + + fcntl.flock(self._fp.fileno(), fcntl.LOCK_UN) + except Exception: + pass + try: + if self._fp: + self._fp.close() + except Exception: + pass + + +def get_codex_token() -> CodexToken: + """Get an available token (refresh if needed).""" + token = _load_token_file() or _try_import_codex_cli_token() + if not token: + raise RuntimeError("Codex OAuth credentials not found. Please run the login command.") + + # Refresh 60 seconds early. + now_ms = int(time.time() * 1000) + if token.expires - now_ms > 60 * 1000: + return token + + lock_path = _get_token_path().with_suffix(".lock") + with _FileLock(lock_path): + # Re-read to avoid stale token if another process refreshed it. + token = _load_token_file() or token + now_ms = int(time.time() * 1000) + if token.expires - now_ms > 60 * 1000: + return token + try: + refreshed = _refresh_token(token.refresh) + _save_token_file(refreshed) + return refreshed + except Exception: + # If refresh fails, re-read the file to avoid false negatives. + latest = _load_token_file() + if latest and latest.expires - now_ms > 0: + return latest + raise + + +def ensure_codex_token_available() -> None: + """Ensure a valid token is available; raise if not.""" + _ = get_codex_token() + + +async def _read_stdin_line() -> str: + loop = asyncio.get_running_loop() + if hasattr(loop, "add_reader") and sys.stdin: + future: asyncio.Future[str] = loop.create_future() + + def _on_readable() -> None: + line = sys.stdin.readline() + if not future.done(): + future.set_result(line) + + try: + loop.add_reader(sys.stdin, _on_readable) + except Exception: + return await loop.run_in_executor(None, sys.stdin.readline) + + try: + return await future + finally: + try: + loop.remove_reader(sys.stdin) + except Exception: + pass + + return await loop.run_in_executor(None, sys.stdin.readline) + + +async def _await_manual_input( + on_manual_code_input: Callable[[str], None], +) -> str: + await asyncio.sleep(MANUAL_PROMPT_DELAY_SEC) + on_manual_code_input("Paste the authorization code (or full redirect URL), or wait for the browser callback:") + return await _read_stdin_line() + + +def login_codex_oauth_interactive( + on_auth: Callable[[str], None] | None = None, + on_prompt: Callable[[str], str] | None = None, + on_status: Callable[[str], None] | None = None, + on_progress: Callable[[str], None] | None = None, + on_manual_code_input: Callable[[str], None] = None, + originator: str = DEFAULT_ORIGINATOR, +) -> CodexToken: + """Interactive login flow.""" + async def _login_async() -> CodexToken: + verifier, challenge = _generate_pkce() + state = _create_state() + + params = { + "response_type": "code", + "client_id": CLIENT_ID, + "redirect_uri": REDIRECT_URI, + "scope": SCOPE, + "code_challenge": challenge, + "code_challenge_method": "S256", + "state": state, + "id_token_add_organizations": "true", + "codex_cli_simplified_flow": "true", + "originator": originator, + } + url = f"{AUTHORIZE_URL}?{urllib.parse.urlencode(params)}" + + loop = asyncio.get_running_loop() + code_future: asyncio.Future[str] = loop.create_future() + + def _notify(code_value: str) -> None: + if code_future.done(): + return + loop.call_soon_threadsafe(code_future.set_result, code_value) + + server, server_error = _start_local_server(state, on_code=_notify) + if on_auth: + on_auth(url) + else: + webbrowser.open(url) + + if not server and server_error and on_status: + on_status( + f"Local callback server could not start ({server_error}). " + "You will need to paste the callback URL or authorization code." + ) + + code: str | None = None + try: + if server: + if on_progress and not on_manual_code_input: + on_progress("Waiting for browser callback...") + + tasks: list[asyncio.Task[Any]] = [] + callback_task = asyncio.create_task(asyncio.wait_for(code_future, timeout=120)) + tasks.append(callback_task) + manual_task = asyncio.create_task(_await_manual_input(on_manual_code_input)) + tasks.append(manual_task) + + done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED) + for task in pending: + task.cancel() + + for task in done: + try: + result = task.result() + except asyncio.TimeoutError: + result = None + if not result: + continue + if task is manual_task: + parsed_code, parsed_state = _parse_authorization_input(result) + if parsed_state and parsed_state != state: + raise RuntimeError("State validation failed.") + code = parsed_code + else: + code = result + if code: + break + + if not code: + prompt = "Please paste the callback URL or authorization code:" + if on_prompt: + raw = await loop.run_in_executor(None, on_prompt, prompt) + else: + raw = await loop.run_in_executor(None, input, prompt) + parsed_code, parsed_state = _parse_authorization_input(raw) + if parsed_state and parsed_state != state: + raise RuntimeError("State validation failed.") + code = parsed_code + + if not code: + raise RuntimeError("Authorization code not found.") + + if on_progress: + on_progress("Exchanging authorization code for tokens...") + token = await _exchange_code_for_token_async(code, verifier) + _save_token_file(token) + return token + finally: + if server: + server.shutdown() + server.server_close() + + try: + asyncio.get_running_loop() + except RuntimeError: + return asyncio.run(_login_async()) + + result: list[CodexToken] = [] + error: list[Exception] = [] + + def _runner() -> None: + try: + result.append(asyncio.run(_login_async())) + except Exception as exc: + error.append(exc) + + thread = threading.Thread(target=_runner) + thread.start() + thread.join() + if error: + raise error[0] + return result[0] diff --git a/nanobot/cli/commands.py b/nanobot/cli/commands.py index c2241fb..213f8c5 100644 --- a/nanobot/cli/commands.py +++ b/nanobot/cli/commands.py @@ -73,6 +73,49 @@ def onboard(): console.print("\n[dim]Want Telegram/WhatsApp? See: https://github.com/HKUDS/nanobot#-chat-apps[/dim]") +@app.command("login") +def login( + provider: str = typer.Option("openai-codex", "--provider", "-p", help="Auth provider"), +): + """Login to an auth provider (e.g. openai-codex).""" + if provider != "openai-codex": + console.print(f"[red]Unsupported provider: {provider}[/red]") + raise typer.Exit(1) + + from nanobot.auth.codex_oauth import login_codex_oauth_interactive + + def on_auth(url: str) -> None: + console.print("[cyan]A browser window will open for login. If it doesn't, open this URL manually:[/cyan]") + console.print(url) + try: + import webbrowser + webbrowser.open(url) + except Exception: + pass + + def on_status(message: str) -> None: + console.print(f"[yellow]{message}[/yellow]") + + def on_progress(message: str) -> None: + console.print(f"[dim]{message}[/dim]") + + def on_prompt(message: str) -> str: + return typer.prompt(message) + + def on_manual_code_input(message: str) -> None: + console.print(f"[cyan]{message}[/cyan]") + + console.print("[green]Starting OpenAI Codex OAuth login...[/green]") + login_codex_oauth_interactive( + on_auth=on_auth, + on_prompt=on_prompt, + on_status=on_status, + on_progress=on_progress, + on_manual_code_input=on_manual_code_input, + ) + console.print("[green]✓ Login successful. Credentials saved.[/green]") + + def _create_workspace_templates(workspace: Path): @@ -161,6 +204,8 @@ def gateway( from nanobot.config.loader import load_config, get_data_dir from nanobot.bus.queue import MessageBus from nanobot.providers.litellm_provider import LiteLLMProvider + from nanobot.providers.openai_codex_provider import OpenAICodexProvider + from nanobot.auth.codex_oauth import ensure_codex_token_available from nanobot.agent.loop import AgentLoop from nanobot.channels.manager import ChannelManager from nanobot.cron.service import CronService @@ -183,17 +228,26 @@ def gateway( api_base = config.get_api_base() model = config.agents.defaults.model is_bedrock = model.startswith("bedrock/") + is_codex = model.startswith("openai-codex/") - if not api_key and not is_bedrock: - console.print("[red]Error: No API key configured.[/red]") - console.print("Set one in ~/.nanobot/config.json under providers.openrouter.apiKey") - raise typer.Exit(1) - - provider = LiteLLMProvider( - api_key=api_key, - api_base=api_base, - default_model=config.agents.defaults.model - ) + if is_codex: + try: + ensure_codex_token_available() + except Exception as e: + console.print(f"[red]Error: {e}[/red]") + console.print("Please run: [cyan]nanobot login --provider openai-codex[/cyan]") + raise typer.Exit(1) + provider = OpenAICodexProvider(default_model=model) + else: + if not api_key and not is_bedrock: + console.print("[red]Error: No API key configured.[/red]") + console.print("Set one in ~/.nanobot/config.json under providers.openrouter.apiKey") + raise typer.Exit(1) + provider = LiteLLMProvider( + api_key=api_key, + api_base=api_base, + default_model=config.agents.defaults.model + ) # Create agent agent = AgentLoop( @@ -286,6 +340,8 @@ def agent( from nanobot.config.loader import load_config from nanobot.bus.queue import MessageBus from nanobot.providers.litellm_provider import LiteLLMProvider + from nanobot.providers.openai_codex_provider import OpenAICodexProvider + from nanobot.auth.codex_oauth import ensure_codex_token_available from nanobot.agent.loop import AgentLoop config = load_config() @@ -294,17 +350,29 @@ def agent( api_base = config.get_api_base() model = config.agents.defaults.model is_bedrock = model.startswith("bedrock/") + is_codex = model.startswith("openai-codex/") - if not api_key and not is_bedrock: - console.print("[red]Error: No API key configured.[/red]") - raise typer.Exit(1) + if is_codex: + try: + ensure_codex_token_available() + except Exception as e: + console.print(f"[red]Error: {e}[/red]") + console.print("Please run: [cyan]nanobot login --provider openai-codex[/cyan]") + raise typer.Exit(1) + else: + if not api_key and not is_bedrock: + console.print("[red]Error: No API key configured.[/red]") + raise typer.Exit(1) bus = MessageBus() - provider = LiteLLMProvider( - api_key=api_key, - api_base=api_base, - default_model=config.agents.defaults.model - ) + if is_codex: + provider = OpenAICodexProvider(default_model=config.agents.defaults.model) + else: + provider = LiteLLMProvider( + api_key=api_key, + api_base=api_base, + default_model=config.agents.defaults.model + ) agent_loop = AgentLoop( bus=bus, diff --git a/nanobot/providers/__init__.py b/nanobot/providers/__init__.py index ceff8fa..b2bb2b9 100644 --- a/nanobot/providers/__init__.py +++ b/nanobot/providers/__init__.py @@ -2,5 +2,6 @@ from nanobot.providers.base import LLMProvider, LLMResponse from nanobot.providers.litellm_provider import LiteLLMProvider +from nanobot.providers.openai_codex_provider import OpenAICodexProvider -__all__ = ["LLMProvider", "LLMResponse", "LiteLLMProvider"] +__all__ = ["LLMProvider", "LLMResponse", "LiteLLMProvider", "OpenAICodexProvider"] diff --git a/nanobot/providers/openai_codex_provider.py b/nanobot/providers/openai_codex_provider.py new file mode 100644 index 0000000..2081180 --- /dev/null +++ b/nanobot/providers/openai_codex_provider.py @@ -0,0 +1,333 @@ +"""OpenAI Codex Responses Provider。""" + +from __future__ import annotations + +import asyncio +import hashlib +import json +from typing import Any, AsyncGenerator + +import httpx + +from nanobot.auth.codex_oauth import get_codex_token +from nanobot.providers.base import LLMProvider, LLMResponse, ToolCallRequest + +DEFAULT_CODEX_BASE_URL = "https://chatgpt.com/backend-api" +DEFAULT_ORIGINATOR = "nanobot" + + +class OpenAICodexProvider(LLMProvider): + """使用 Codex OAuth 调用 Responses 接口。""" + + def __init__(self, default_model: str = "openai-codex/gpt-5.1-codex"): + super().__init__(api_key=None, api_base=None) + self.default_model = default_model + + async def chat( + self, + messages: list[dict[str, Any]], + tools: list[dict[str, Any]] | None = None, + model: str | None = None, + max_tokens: int = 4096, + temperature: float = 0.7, + ) -> LLMResponse: + model = model or self.default_model + system_prompt, input_items = _convert_messages(messages) + + token = await asyncio.to_thread(get_codex_token) + headers = _build_headers(token.account_id, token.access) + + body: dict[str, Any] = { + "model": _strip_model_prefix(model), + "store": False, + "stream": True, + "instructions": system_prompt, + "input": input_items, + "text": {"verbosity": "medium"}, + "include": ["reasoning.encrypted_content"], + "prompt_cache_key": _prompt_cache_key(messages), + "tool_choice": "auto", + "parallel_tool_calls": True, + } + + if tools: + body["tools"] = _convert_tools(tools) + + url = _resolve_codex_url(DEFAULT_CODEX_BASE_URL) + + try: + async with httpx.AsyncClient(timeout=60.0) as client: + try: + async with client.stream("POST", url, headers=headers, json=body) as response: + if response.status_code != 200: + text = await response.aread() + raise RuntimeError( + _friendly_error(response.status_code, text.decode("utf-8", "ignore")) + ) + content, tool_calls, finish_reason = await _consume_sse(response) + return LLMResponse( + content=content, + tool_calls=tool_calls, + finish_reason=finish_reason, + ) + except Exception as e: + # 证书校验失败时降级关闭校验(存在安全风险) + if "CERTIFICATE_VERIFY_FAILED" not in str(e): + raise + async with httpx.AsyncClient(timeout=60.0, verify=False) as insecure_client: + async with insecure_client.stream("POST", url, headers=headers, json=body) as response: + if response.status_code != 200: + text = await response.aread() + raise RuntimeError( + _friendly_error(response.status_code, text.decode("utf-8", "ignore")) + ) + content, tool_calls, finish_reason = await _consume_sse(response) + return LLMResponse( + content=content, + tool_calls=tool_calls, + finish_reason=finish_reason, + ) + except Exception as e: + return LLMResponse( + content=f"Error calling Codex: {str(e)}", + finish_reason="error", + ) + + def get_default_model(self) -> str: + return self.default_model + + +def _strip_model_prefix(model: str) -> str: + if model.startswith("openai-codex/"): + return model.split("/", 1)[1] + return model + + +def _resolve_codex_url(base_url: str) -> str: + raw = base_url.rstrip("/") + if raw.endswith("/codex/responses"): + return raw + if raw.endswith("/codex"): + return f"{raw}/responses" + return f"{raw}/codex/responses" + + +def _build_headers(account_id: str, token: str) -> dict[str, str]: + return { + "Authorization": f"Bearer {token}", + "chatgpt-account-id": account_id, + "OpenAI-Beta": "responses=experimental", + "originator": DEFAULT_ORIGINATOR, + "User-Agent": "nanobot (python)", + "accept": "text/event-stream", + "content-type": "application/json", + } + + +def _convert_tools(tools: list[dict[str, Any]]) -> list[dict[str, Any]]: + # nanobot 工具定义已是 OpenAI function schema + converted: list[dict[str, Any]] = [] + for tool in tools: + name = tool.get("name") + if not isinstance(name, str) or not name: + # 忽略无效工具,避免被 Codex 拒绝 + continue + params = tool.get("parameters") or {} + if not isinstance(params, dict): + # 参数必须是 JSON Schema 对象 + params = {} + converted.append( + { + "type": "function", + "name": name, + "description": tool.get("description") or "", + "parameters": params, + } + ) + return converted + + +def _convert_messages(messages: list[dict[str, Any]]) -> tuple[str, list[dict[str, Any]]]: + system_prompt = "" + input_items: list[dict[str, Any]] = [] + + for idx, msg in enumerate(messages): + role = msg.get("role") + content = msg.get("content") + + if role == "system": + system_prompt = content if isinstance(content, str) else "" + continue + + if role == "user": + input_items.append(_convert_user_message(content)) + continue + + if role == "assistant": + # 先处理文本 + if isinstance(content, str) and content: + input_items.append( + { + "type": "message", + "role": "assistant", + "content": [{"type": "output_text", "text": content}], + "status": "completed", + "id": f"msg_{idx}", + } + ) + # 再处理工具调用 + for tool_call in msg.get("tool_calls", []) or []: + fn = tool_call.get("function") or {} + call_id = tool_call.get("id") or f"call_{idx}" + item_id = f"fc_{idx}" + input_items.append( + { + "type": "function_call", + "id": item_id, + "call_id": call_id, + "name": fn.get("name"), + "arguments": fn.get("arguments") or "{}", + } + ) + continue + + if role == "tool": + call_id = _extract_call_id(msg.get("tool_call_id")) + output_text = content if isinstance(content, str) else json.dumps(content) + input_items.append( + { + "type": "function_call_output", + "call_id": call_id, + "output": output_text, + } + ) + continue + + return system_prompt, input_items + + +def _convert_user_message(content: Any) -> dict[str, Any]: + if isinstance(content, str): + return {"role": "user", "content": [{"type": "input_text", "text": content}]} + if isinstance(content, list): + converted: list[dict[str, Any]] = [] + for item in content: + if not isinstance(item, dict): + continue + if item.get("type") == "text": + converted.append({"type": "input_text", "text": item.get("text", "")}) + elif item.get("type") == "image_url": + url = (item.get("image_url") or {}).get("url") + if url: + converted.append({"type": "input_image", "image_url": url, "detail": "auto"}) + if converted: + return {"role": "user", "content": converted} + return {"role": "user", "content": [{"type": "input_text", "text": ""}]} + + +def _extract_call_id(tool_call_id: Any) -> str: + if isinstance(tool_call_id, str) and tool_call_id: + return tool_call_id.split("|", 1)[0] + return "call_0" + + +def _prompt_cache_key(messages: list[dict[str, Any]]) -> str: + raw = json.dumps(messages, ensure_ascii=True, sort_keys=True) + return hashlib.sha256(raw.encode("utf-8")).hexdigest() + + +async def _iter_sse(response: httpx.Response) -> AsyncGenerator[dict[str, Any], None]: + buffer: list[str] = [] + async for line in response.aiter_lines(): + if line == "": + if buffer: + data_lines = [l[5:].strip() for l in buffer if l.startswith("data:")] + buffer = [] + if not data_lines: + continue + data = "\n".join(data_lines).strip() + if not data or data == "[DONE]": + continue + try: + yield json.loads(data) + except Exception: + continue + continue + buffer.append(line) + + + + +async def _consume_sse(response: httpx.Response) -> tuple[str, list[ToolCallRequest], str]: + content = "" + tool_calls: list[ToolCallRequest] = [] + tool_call_buffers: dict[str, dict[str, Any]] = {} + finish_reason = "stop" + + async for event in _iter_sse(response): + event_type = event.get("type") + if event_type == "response.output_item.added": + item = event.get("item") or {} + if item.get("type") == "function_call": + call_id = item.get("call_id") + if not call_id: + continue + tool_call_buffers[call_id] = { + "id": item.get("id") or "fc_0", + "name": item.get("name"), + "arguments": item.get("arguments") or "", + } + elif event_type == "response.output_text.delta": + content += event.get("delta") or "" + elif event_type == "response.function_call_arguments.delta": + call_id = event.get("call_id") + if call_id and call_id in tool_call_buffers: + tool_call_buffers[call_id]["arguments"] += event.get("delta") or "" + elif event_type == "response.function_call_arguments.done": + call_id = event.get("call_id") + if call_id and call_id in tool_call_buffers: + tool_call_buffers[call_id]["arguments"] = event.get("arguments") or "" + elif event_type == "response.output_item.done": + item = event.get("item") or {} + if item.get("type") == "function_call": + call_id = item.get("call_id") + if not call_id: + continue + buf = tool_call_buffers.get(call_id) or {} + args_raw = buf.get("arguments") or item.get("arguments") or "{}" + try: + args = json.loads(args_raw) + except Exception: + args = {"raw": args_raw} + tool_calls.append( + ToolCallRequest( + id=f"{call_id}|{buf.get('id') or item.get('id') or 'fc_0'}", + name=buf.get("name") or item.get("name"), + arguments=args, + ) + ) + elif event_type == "response.completed": + status = (event.get("response") or {}).get("status") + finish_reason = _map_finish_reason(status) + elif event_type in {"error", "response.failed"}: + raise RuntimeError("Codex response failed") + + return content, tool_calls, finish_reason + + +def _map_finish_reason(status: str | None) -> str: + if not status: + return "stop" + if status == "completed": + return "stop" + if status == "incomplete": + return "length" + if status in {"failed", "cancelled"}: + return "error" + return "stop" + + +def _friendly_error(status_code: int, raw: str) -> str: + if status_code == 429: + return "ChatGPT 使用额度已达上限或触发限流,请稍后再试。" + return f"HTTP {status_code}: {raw}" From d4e65319eeba616caaf9564abe83a62ebf51435e Mon Sep 17 00:00:00 2001 From: qiupinhua Date: Thu, 5 Feb 2026 17:53:00 +0800 Subject: [PATCH 02/60] refactor: split codex oauth logic to several files --- nanobot/auth/__init__.py | 4 +- nanobot/auth/codex/__init__.py | 15 + nanobot/auth/codex/constants.py | 25 + nanobot/auth/codex/flow.py | 312 +++++++++++ nanobot/auth/codex/models.py | 15 + nanobot/auth/codex/pkce.py | 77 +++ nanobot/auth/codex/server.py | 115 ++++ nanobot/auth/codex/storage.py | 118 ++++ nanobot/auth/codex_oauth.py | 607 --------------------- nanobot/cli/commands.py | 6 +- nanobot/providers/openai_codex_provider.py | 75 ++- 11 files changed, 717 insertions(+), 652 deletions(-) create mode 100644 nanobot/auth/codex/__init__.py create mode 100644 nanobot/auth/codex/constants.py create mode 100644 nanobot/auth/codex/flow.py create mode 100644 nanobot/auth/codex/models.py create mode 100644 nanobot/auth/codex/pkce.py create mode 100644 nanobot/auth/codex/server.py create mode 100644 nanobot/auth/codex/storage.py delete mode 100644 nanobot/auth/codex_oauth.py diff --git a/nanobot/auth/__init__.py b/nanobot/auth/__init__.py index e74e1c2..c74d992 100644 --- a/nanobot/auth/__init__.py +++ b/nanobot/auth/__init__.py @@ -1,6 +1,6 @@ -"""鉴权相关模块。""" +"""Authentication modules.""" -from nanobot.auth.codex_oauth import ( +from nanobot.auth.codex import ( ensure_codex_token_available, get_codex_token, login_codex_oauth_interactive, diff --git a/nanobot/auth/codex/__init__.py b/nanobot/auth/codex/__init__.py new file mode 100644 index 0000000..707cd4d --- /dev/null +++ b/nanobot/auth/codex/__init__.py @@ -0,0 +1,15 @@ +"""Codex OAuth module.""" + +from nanobot.auth.codex.flow import ( + ensure_codex_token_available, + get_codex_token, + login_codex_oauth_interactive, +) +from nanobot.auth.codex.models import CodexToken + +__all__ = [ + "CodexToken", + "ensure_codex_token_available", + "get_codex_token", + "login_codex_oauth_interactive", +] diff --git a/nanobot/auth/codex/constants.py b/nanobot/auth/codex/constants.py new file mode 100644 index 0000000..bbe676a --- /dev/null +++ b/nanobot/auth/codex/constants.py @@ -0,0 +1,25 @@ +"""Codex OAuth constants.""" + +CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann" +AUTHORIZE_URL = "https://auth.openai.com/oauth/authorize" +TOKEN_URL = "https://auth.openai.com/oauth/token" +REDIRECT_URI = "http://localhost:1455/auth/callback" +SCOPE = "openid profile email offline_access" +JWT_CLAIM_PATH = "https://api.openai.com/auth" + +DEFAULT_ORIGINATOR = "nanobot" +TOKEN_FILENAME = "codex.json" +MANUAL_PROMPT_DELAY_SEC = 3 +SUCCESS_HTML = ( + "" + "" + "" + "" + "" + "Authentication successful" + "" + "" + "

Authentication successful. Return to your terminal to continue.

" + "" + "" +) diff --git a/nanobot/auth/codex/flow.py b/nanobot/auth/codex/flow.py new file mode 100644 index 0000000..0966327 --- /dev/null +++ b/nanobot/auth/codex/flow.py @@ -0,0 +1,312 @@ +"""Codex OAuth login and token management.""" + +from __future__ import annotations + +import asyncio +import sys +import threading +import time +import urllib.parse +import webbrowser +from typing import Any, Callable + +import httpx + +from nanobot.auth.codex.constants import ( + AUTHORIZE_URL, + CLIENT_ID, + DEFAULT_ORIGINATOR, + MANUAL_PROMPT_DELAY_SEC, + REDIRECT_URI, + SCOPE, + TOKEN_URL, +) +from nanobot.auth.codex.models import CodexToken +from nanobot.auth.codex.pkce import ( + _create_state, + _decode_account_id, + _generate_pkce, + _parse_authorization_input, + _parse_token_payload, +) +from nanobot.auth.codex.server import _start_local_server +from nanobot.auth.codex.storage import ( + _FileLock, + _get_token_path, + _load_token_file, + _save_token_file, + _try_import_codex_cli_token, +) + + +def _exchange_code_for_token(code: str, verifier: str) -> CodexToken: + data = { + "grant_type": "authorization_code", + "client_id": CLIENT_ID, + "code": code, + "code_verifier": verifier, + "redirect_uri": REDIRECT_URI, + } + with httpx.Client(timeout=30.0) as client: + response = client.post(TOKEN_URL, data=data, headers={"Content-Type": "application/x-www-form-urlencoded"}) + if response.status_code != 200: + raise RuntimeError(f"Token exchange failed: {response.status_code} {response.text}") + + payload = response.json() + access, refresh, expires_in = _parse_token_payload(payload, "Token response missing fields") + print("Received access token:", access) + account_id = _decode_account_id(access) + return CodexToken( + access=access, + refresh=refresh, + expires=int(time.time() * 1000 + expires_in * 1000), + account_id=account_id, + ) + + +async def _exchange_code_for_token_async(code: str, verifier: str) -> CodexToken: + data = { + "grant_type": "authorization_code", + "client_id": CLIENT_ID, + "code": code, + "code_verifier": verifier, + "redirect_uri": REDIRECT_URI, + } + async with httpx.AsyncClient(timeout=30.0) as client: + response = await client.post( + TOKEN_URL, + data=data, + headers={"Content-Type": "application/x-www-form-urlencoded"}, + ) + if response.status_code != 200: + raise RuntimeError(f"Token exchange failed: {response.status_code} {response.text}") + + payload = response.json() + access, refresh, expires_in = _parse_token_payload(payload, "Token response missing fields") + + account_id = _decode_account_id(access) + return CodexToken( + access=access, + refresh=refresh, + expires=int(time.time() * 1000 + expires_in * 1000), + account_id=account_id, + ) + + +def _refresh_token(refresh_token: str) -> CodexToken: + data = { + "grant_type": "refresh_token", + "refresh_token": refresh_token, + "client_id": CLIENT_ID, + } + with httpx.Client(timeout=30.0) as client: + response = client.post(TOKEN_URL, data=data, headers={"Content-Type": "application/x-www-form-urlencoded"}) + if response.status_code != 200: + raise RuntimeError(f"Token refresh failed: {response.status_code} {response.text}") + + payload = response.json() + access, refresh, expires_in = _parse_token_payload(payload, "Token refresh response missing fields") + + account_id = _decode_account_id(access) + return CodexToken( + access=access, + refresh=refresh, + expires=int(time.time() * 1000 + expires_in * 1000), + account_id=account_id, + ) + + +def get_codex_token() -> CodexToken: + """Get an available token (refresh if needed).""" + token = _load_token_file() or _try_import_codex_cli_token() + if not token: + raise RuntimeError("Codex OAuth credentials not found. Please run the login command.") + + # Refresh 60 seconds early. + now_ms = int(time.time() * 1000) + if token.expires - now_ms > 60 * 1000: + return token + + lock_path = _get_token_path().with_suffix(".lock") + with _FileLock(lock_path): + # Re-read to avoid stale token if another process refreshed it. + token = _load_token_file() or token + now_ms = int(time.time() * 1000) + if token.expires - now_ms > 60 * 1000: + return token + try: + refreshed = _refresh_token(token.refresh) + _save_token_file(refreshed) + return refreshed + except Exception: + # If refresh fails, re-read the file to avoid false negatives. + latest = _load_token_file() + if latest and latest.expires - now_ms > 0: + return latest + raise + + +def ensure_codex_token_available() -> None: + """Ensure a valid token is available; raise if not.""" + _ = get_codex_token() + + +async def _read_stdin_line() -> str: + loop = asyncio.get_running_loop() + if hasattr(loop, "add_reader") and sys.stdin: + future: asyncio.Future[str] = loop.create_future() + + def _on_readable() -> None: + line = sys.stdin.readline() + if not future.done(): + future.set_result(line) + + try: + loop.add_reader(sys.stdin, _on_readable) + except Exception: + return await loop.run_in_executor(None, sys.stdin.readline) + + try: + return await future + finally: + try: + loop.remove_reader(sys.stdin) + except Exception: + pass + + return await loop.run_in_executor(None, sys.stdin.readline) + + +async def _await_manual_input( + on_manual_code_input: Callable[[str], None], +) -> str: + await asyncio.sleep(MANUAL_PROMPT_DELAY_SEC) + on_manual_code_input("Paste the authorization code (or full redirect URL), or wait for the browser callback:") + return await _read_stdin_line() + + +def login_codex_oauth_interactive( + on_auth: Callable[[str], None] | None = None, + on_prompt: Callable[[str], str] | None = None, + on_status: Callable[[str], None] | None = None, + on_progress: Callable[[str], None] | None = None, + on_manual_code_input: Callable[[str], None] = None, + originator: str = DEFAULT_ORIGINATOR, +) -> CodexToken: + """Interactive login flow.""" + + async def _login_async() -> CodexToken: + verifier, challenge = _generate_pkce() + state = _create_state() + + params = { + "response_type": "code", + "client_id": CLIENT_ID, + "redirect_uri": REDIRECT_URI, + "scope": SCOPE, + "code_challenge": challenge, + "code_challenge_method": "S256", + "state": state, + "id_token_add_organizations": "true", + "codex_cli_simplified_flow": "true", + "originator": originator, + } + url = f"{AUTHORIZE_URL}?{urllib.parse.urlencode(params)}" + + loop = asyncio.get_running_loop() + code_future: asyncio.Future[str] = loop.create_future() + + def _notify(code_value: str) -> None: + if code_future.done(): + return + loop.call_soon_threadsafe(code_future.set_result, code_value) + + server, server_error = _start_local_server(state, on_code=_notify) + if on_auth: + on_auth(url) + else: + webbrowser.open(url) + + if not server and server_error and on_status: + on_status( + f"Local callback server could not start ({server_error}). " + "You will need to paste the callback URL or authorization code." + ) + + code: str | None = None + try: + if server: + if on_progress and not on_manual_code_input: + on_progress("Waiting for browser callback...") + + tasks: list[asyncio.Task[Any]] = [] + callback_task = asyncio.create_task(asyncio.wait_for(code_future, timeout=120)) + tasks.append(callback_task) + manual_task = asyncio.create_task(_await_manual_input(on_manual_code_input)) + tasks.append(manual_task) + + done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED) + for task in pending: + task.cancel() + + for task in done: + try: + result = task.result() + except asyncio.TimeoutError: + result = None + if not result: + continue + if task is manual_task: + parsed_code, parsed_state = _parse_authorization_input(result) + if parsed_state and parsed_state != state: + raise RuntimeError("State validation failed.") + code = parsed_code + else: + code = result + if code: + break + + if not code: + prompt = "Please paste the callback URL or authorization code:" + if on_prompt: + raw = await loop.run_in_executor(None, on_prompt, prompt) + else: + raw = await loop.run_in_executor(None, input, prompt) + parsed_code, parsed_state = _parse_authorization_input(raw) + if parsed_state and parsed_state != state: + raise RuntimeError("State validation failed.") + code = parsed_code + + if not code: + raise RuntimeError("Authorization code not found.") + + if on_progress: + on_progress("Exchanging authorization code for tokens...") + token = await _exchange_code_for_token_async(code, verifier) + _save_token_file(token) + return token + finally: + if server: + server.shutdown() + server.server_close() + + try: + asyncio.get_running_loop() + except RuntimeError: + return asyncio.run(_login_async()) + + result: list[CodexToken] = [] + error: list[Exception] = [] + + def _runner() -> None: + try: + result.append(asyncio.run(_login_async())) + except Exception as exc: + error.append(exc) + + thread = threading.Thread(target=_runner) + thread.start() + thread.join() + if error: + raise error[0] + return result[0] diff --git a/nanobot/auth/codex/models.py b/nanobot/auth/codex/models.py new file mode 100644 index 0000000..e3a5f55 --- /dev/null +++ b/nanobot/auth/codex/models.py @@ -0,0 +1,15 @@ +"""Codex OAuth data models.""" + +from __future__ import annotations + +from dataclasses import dataclass + + +@dataclass +class CodexToken: + """Codex OAuth token data structure.""" + + access: str + refresh: str + expires: int + account_id: str diff --git a/nanobot/auth/codex/pkce.py b/nanobot/auth/codex/pkce.py new file mode 100644 index 0000000..b682386 --- /dev/null +++ b/nanobot/auth/codex/pkce.py @@ -0,0 +1,77 @@ +"""PKCE and authorization helpers.""" + +from __future__ import annotations + +import base64 +import hashlib +import json +import os +import urllib.parse +from typing import Any + +from nanobot.auth.codex.constants import JWT_CLAIM_PATH + + +def _base64url(data: bytes) -> str: + return base64.urlsafe_b64encode(data).rstrip(b"=").decode("utf-8") + + +def _decode_base64url(data: str) -> bytes: + padding = "=" * (-len(data) % 4) + return base64.urlsafe_b64decode(data + padding) + + +def _generate_pkce() -> tuple[str, str]: + verifier = _base64url(os.urandom(32)) + challenge = _base64url(hashlib.sha256(verifier.encode("utf-8")).digest()) + return verifier, challenge + + +def _create_state() -> str: + return _base64url(os.urandom(16)) + + +def _parse_authorization_input(raw: str) -> tuple[str | None, str | None]: + value = raw.strip() + if not value: + return None, None + try: + url = urllib.parse.urlparse(value) + qs = urllib.parse.parse_qs(url.query) + code = qs.get("code", [None])[0] + state = qs.get("state", [None])[0] + if code: + return code, state + except Exception: + pass + + if "#" in value: + parts = value.split("#", 1) + return parts[0] or None, parts[1] or None + + if "code=" in value: + qs = urllib.parse.parse_qs(value) + return qs.get("code", [None])[0], qs.get("state", [None])[0] + + return value, None + + +def _decode_account_id(access_token: str) -> str: + parts = access_token.split(".") + if len(parts) != 3: + raise ValueError("Invalid JWT token") + payload = json.loads(_decode_base64url(parts[1]).decode("utf-8")) + auth = payload.get(JWT_CLAIM_PATH) or {} + account_id = auth.get("chatgpt_account_id") + if not account_id: + raise ValueError("Failed to extract account_id from token") + return str(account_id) + + +def _parse_token_payload(payload: dict[str, Any], missing_message: str) -> tuple[str, str, int]: + access = payload.get("access_token") + refresh = payload.get("refresh_token") + expires_in = payload.get("expires_in") + if not access or not refresh or not isinstance(expires_in, int): + raise RuntimeError(missing_message) + return access, refresh, expires_in diff --git a/nanobot/auth/codex/server.py b/nanobot/auth/codex/server.py new file mode 100644 index 0000000..f31db19 --- /dev/null +++ b/nanobot/auth/codex/server.py @@ -0,0 +1,115 @@ +"""Local OAuth callback server.""" + +from __future__ import annotations + +import socket +import threading +import urllib.parse +from http.server import BaseHTTPRequestHandler, HTTPServer +from typing import Any, Callable + +from nanobot.auth.codex.constants import SUCCESS_HTML + + +class _OAuthHandler(BaseHTTPRequestHandler): + """Local callback HTTP handler.""" + + server_version = "NanobotOAuth/1.0" + protocol_version = "HTTP/1.1" + + def do_GET(self) -> None: # noqa: N802 + try: + url = urllib.parse.urlparse(self.path) + if url.path != "/auth/callback": + self.send_response(404) + self.end_headers() + self.wfile.write(b"Not found") + return + + qs = urllib.parse.parse_qs(url.query) + code = qs.get("code", [None])[0] + state = qs.get("state", [None])[0] + + if state != self.server.expected_state: + self.send_response(400) + self.end_headers() + self.wfile.write(b"State mismatch") + return + + if not code: + self.send_response(400) + self.end_headers() + self.wfile.write(b"Missing code") + return + + self.server.code = code + try: + if getattr(self.server, "on_code", None): + self.server.on_code(code) + except Exception: + pass + body = SUCCESS_HTML.encode("utf-8") + self.send_response(200) + self.send_header("Content-Type", "text/html; charset=utf-8") + self.send_header("Content-Length", str(len(body))) + self.send_header("Connection", "close") + self.end_headers() + self.wfile.write(body) + try: + self.wfile.flush() + except Exception: + pass + self.close_connection = True + except Exception: + self.send_response(500) + self.end_headers() + self.wfile.write(b"Internal error") + + def log_message(self, format: str, *args: Any) -> None: # noqa: A003 + # Suppress default logs to avoid noisy output. + return + + +class _OAuthServer(HTTPServer): + """OAuth callback server with state.""" + + def __init__( + self, + server_address: tuple[str, int], + expected_state: str, + on_code: Callable[[str], None] | None = None, + ): + super().__init__(server_address, _OAuthHandler) + self.expected_state = expected_state + self.code: str | None = None + self.on_code = on_code + + +def _start_local_server( + state: str, + on_code: Callable[[str], None] | None = None, +) -> tuple[_OAuthServer | None, str | None]: + """Start a local OAuth callback server on the first available localhost address.""" + try: + addrinfos = socket.getaddrinfo("localhost", 1455, type=socket.SOCK_STREAM) + except OSError as exc: + return None, f"Failed to resolve localhost: {exc}" + + last_error: OSError | None = None + for family, _socktype, _proto, _canonname, sockaddr in addrinfos: + try: + # Support IPv4/IPv6 to avoid missing callbacks when localhost resolves to ::1. + class _AddrOAuthServer(_OAuthServer): + address_family = family + + server = _AddrOAuthServer(sockaddr, state, on_code=on_code) + thread = threading.Thread(target=server.serve_forever, daemon=True) + thread.start() + return server, None + except OSError as exc: + last_error = exc + continue + + if last_error: + return None, f"Local callback server failed to start: {last_error}" + return None, "Local callback server failed to start: unknown error" diff --git a/nanobot/auth/codex/storage.py b/nanobot/auth/codex/storage.py new file mode 100644 index 0000000..31e5e3d --- /dev/null +++ b/nanobot/auth/codex/storage.py @@ -0,0 +1,118 @@ +"""Token storage helpers.""" + +from __future__ import annotations + +import json +import os +import time +from pathlib import Path + +from nanobot.auth.codex.constants import TOKEN_FILENAME +from nanobot.auth.codex.models import CodexToken +from nanobot.utils.helpers import ensure_dir, get_data_path + + +def _get_token_path() -> Path: + auth_dir = ensure_dir(get_data_path() / "auth") + return auth_dir / TOKEN_FILENAME + + +def _load_token_file() -> CodexToken | None: + path = _get_token_path() + if not path.exists(): + return None + try: + data = json.loads(path.read_text(encoding="utf-8")) + return CodexToken( + access=data["access"], + refresh=data["refresh"], + expires=int(data["expires"]), + account_id=data["account_id"], + ) + except Exception: + return None + + +def _save_token_file(token: CodexToken) -> None: + path = _get_token_path() + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text( + json.dumps( + { + "access": token.access, + "refresh": token.refresh, + "expires": token.expires, + "account_id": token.account_id, + }, + ensure_ascii=True, + indent=2, + ), + encoding="utf-8", + ) + try: + os.chmod(path, 0o600) + except Exception: + # Ignore permission setting failures. + pass + + +def _try_import_codex_cli_token() -> CodexToken | None: + codex_path = Path.home() / ".codex" / "auth.json" + if not codex_path.exists(): + return None + try: + data = json.loads(codex_path.read_text(encoding="utf-8")) + tokens = data.get("tokens") or {} + access = tokens.get("access_token") + refresh = tokens.get("refresh_token") + account_id = tokens.get("account_id") + if not access or not refresh or not account_id: + return None + try: + mtime = codex_path.stat().st_mtime + expires = int(mtime * 1000 + 60 * 60 * 1000) + except Exception: + expires = int(time.time() * 1000 + 60 * 60 * 1000) + token = CodexToken( + access=str(access), + refresh=str(refresh), + expires=expires, + account_id=str(account_id), + ) + _save_token_file(token) + return token + except Exception: + return None + + +class _FileLock: + """Simple file lock to reduce concurrent refreshes.""" + + def __init__(self, path: Path): + self._path = path + self._fp = None + + def __enter__(self) -> "_FileLock": + self._path.parent.mkdir(parents=True, exist_ok=True) + self._fp = open(self._path, "a+") + try: + import fcntl + + fcntl.flock(self._fp.fileno(), fcntl.LOCK_EX) + except Exception: + # Non-POSIX or failed lock: continue without locking. + pass + return self + + def __exit__(self, exc_type, exc, tb) -> None: + try: + import fcntl + + fcntl.flock(self._fp.fileno(), fcntl.LOCK_UN) + except Exception: + pass + try: + if self._fp: + self._fp.close() + except Exception: + pass diff --git a/nanobot/auth/codex_oauth.py b/nanobot/auth/codex_oauth.py deleted file mode 100644 index 0784267..0000000 --- a/nanobot/auth/codex_oauth.py +++ /dev/null @@ -1,607 +0,0 @@ -"""OpenAI Codex OAuth implementation.""" - -from __future__ import annotations - -import asyncio -import base64 -import hashlib -import json -import os -import socket -import sys -import threading -import time -import urllib.parse -import webbrowser -from dataclasses import dataclass -from http.server import BaseHTTPRequestHandler, HTTPServer -from pathlib import Path -from typing import Any, Callable - -import httpx - -from nanobot.utils.helpers import ensure_dir, get_data_path - -# Fixed parameters (sourced from the official Codex CLI OAuth client). -CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann" -AUTHORIZE_URL = "https://auth.openai.com/oauth/authorize" -TOKEN_URL = "https://auth.openai.com/oauth/token" -REDIRECT_URI = "http://localhost:1455/auth/callback" -SCOPE = "openid profile email offline_access" -JWT_CLAIM_PATH = "https://api.openai.com/auth" - -DEFAULT_ORIGINATOR = "nanobot" -TOKEN_FILENAME = "codex.json" -MANUAL_PROMPT_DELAY_SEC = 3 -SUCCESS_HTML = ( - "" - "" - "" - "" - "" - "Authentication successful" - "" - "" - "

Authentication successful. Return to your terminal to continue.

" - "" - "" -) - - -@dataclass -class CodexToken: - """Codex OAuth token data structure.""" - access: str - refresh: str - expires: int - account_id: str - - -def _base64url(data: bytes) -> str: - return base64.urlsafe_b64encode(data).rstrip(b"=").decode("utf-8") - - -def _decode_base64url(data: str) -> bytes: - padding = "=" * (-len(data) % 4) - return base64.urlsafe_b64decode(data + padding) - - -def _generate_pkce() -> tuple[str, str]: - verifier = _base64url(os.urandom(32)) - challenge = _base64url(hashlib.sha256(verifier.encode("utf-8")).digest()) - return verifier, challenge - - -def _create_state() -> str: - return _base64url(os.urandom(16)) - - -def _get_token_path() -> Path: - auth_dir = ensure_dir(get_data_path() / "auth") - return auth_dir / TOKEN_FILENAME - - -def _parse_authorization_input(raw: str) -> tuple[str | None, str | None]: - value = raw.strip() - if not value: - return None, None - try: - url = urllib.parse.urlparse(value) - qs = urllib.parse.parse_qs(url.query) - code = qs.get("code", [None])[0] - state = qs.get("state", [None])[0] - if code: - return code, state - except Exception: - pass - - if "#" in value: - parts = value.split("#", 1) - return parts[0] or None, parts[1] or None - - if "code=" in value: - qs = urllib.parse.parse_qs(value) - return qs.get("code", [None])[0], qs.get("state", [None])[0] - - return value, None - - -def _decode_account_id(access_token: str) -> str: - parts = access_token.split(".") - if len(parts) != 3: - raise ValueError("Invalid JWT token") - payload = json.loads(_decode_base64url(parts[1]).decode("utf-8")) - auth = payload.get(JWT_CLAIM_PATH) or {} - account_id = auth.get("chatgpt_account_id") - if not account_id: - raise ValueError("Failed to extract account_id from token") - return str(account_id) - - -class _OAuthHandler(BaseHTTPRequestHandler): - """Local callback HTTP handler.""" - - server_version = "NanobotOAuth/1.0" - protocol_version = "HTTP/1.1" - - def do_GET(self) -> None: # noqa: N802 - try: - url = urllib.parse.urlparse(self.path) - if url.path != "/auth/callback": - self.send_response(404) - self.end_headers() - self.wfile.write(b"Not found") - return - - qs = urllib.parse.parse_qs(url.query) - code = qs.get("code", [None])[0] - state = qs.get("state", [None])[0] - - if state != self.server.expected_state: - self.send_response(400) - self.end_headers() - self.wfile.write(b"State mismatch") - return - - if not code: - self.send_response(400) - self.end_headers() - self.wfile.write(b"Missing code") - return - - self.server.code = code - try: - if getattr(self.server, "on_code", None): - self.server.on_code(code) - except Exception: - pass - body = SUCCESS_HTML.encode("utf-8") - self.send_response(200) - self.send_header("Content-Type", "text/html; charset=utf-8") - self.send_header("Content-Length", str(len(body))) - self.send_header("Connection", "close") - self.end_headers() - self.wfile.write(body) - try: - self.wfile.flush() - except Exception: - pass - self.close_connection = True - except Exception: - self.send_response(500) - self.end_headers() - self.wfile.write(b"Internal error") - - def log_message(self, format: str, *args: Any) -> None: # noqa: A003 - # Suppress default logs to avoid noisy output. - return - - -class _OAuthServer(HTTPServer): - """OAuth callback server with state.""" - - def __init__( - self, - server_address: tuple[str, int], - expected_state: str, - on_code: Callable[[str], None] | None = None, - ): - super().__init__(server_address, _OAuthHandler) - self.expected_state = expected_state - self.code: str | None = None - self.on_code = on_code - - -def _start_local_server( - state: str, - on_code: Callable[[str], None] | None = None, -) -> tuple[_OAuthServer | None, str | None]: - """Start a local OAuth callback server on the first available localhost address.""" - try: - addrinfos = socket.getaddrinfo("localhost", 1455, type=socket.SOCK_STREAM) - except OSError as exc: - return None, f"Failed to resolve localhost: {exc}" - - last_error: OSError | None = None - for family, _socktype, _proto, _canonname, sockaddr in addrinfos: - try: - # 兼容 IPv4/IPv6 监听,避免 localhost 解析到 ::1 时收不到回调 - class _AddrOAuthServer(_OAuthServer): - address_family = family - - server = _AddrOAuthServer(sockaddr, state, on_code=on_code) - thread = threading.Thread(target=server.serve_forever, daemon=True) - thread.start() - return server, None - except OSError as exc: - last_error = exc - continue - - if last_error: - return None, f"Local callback server failed to start: {last_error}" - return None, "Local callback server failed to start: unknown error" - - -def _exchange_code_for_token(code: str, verifier: str) -> CodexToken: - data = { - "grant_type": "authorization_code", - "client_id": CLIENT_ID, - "code": code, - "code_verifier": verifier, - "redirect_uri": REDIRECT_URI, - } - with httpx.Client(timeout=30.0) as client: - response = client.post(TOKEN_URL, data=data, headers={"Content-Type": "application/x-www-form-urlencoded"}) - if response.status_code != 200: - raise RuntimeError(f"Token exchange failed: {response.status_code} {response.text}") - - payload = response.json() - access = payload.get("access_token") - refresh = payload.get("refresh_token") - expires_in = payload.get("expires_in") - if not access or not refresh or not isinstance(expires_in, int): - raise RuntimeError("Token response missing fields") - print("Received access token:", access) - account_id = _decode_account_id(access) - return CodexToken( - access=access, - refresh=refresh, - expires=int(time.time() * 1000 + expires_in * 1000), - account_id=account_id, - ) - - -async def _exchange_code_for_token_async(code: str, verifier: str) -> CodexToken: - data = { - "grant_type": "authorization_code", - "client_id": CLIENT_ID, - "code": code, - "code_verifier": verifier, - "redirect_uri": REDIRECT_URI, - } - async with httpx.AsyncClient(timeout=30.0) as client: - response = await client.post( - TOKEN_URL, - data=data, - headers={"Content-Type": "application/x-www-form-urlencoded"}, - ) - if response.status_code != 200: - raise RuntimeError(f"Token exchange failed: {response.status_code} {response.text}") - - payload = response.json() - access = payload.get("access_token") - refresh = payload.get("refresh_token") - expires_in = payload.get("expires_in") - if not access or not refresh or not isinstance(expires_in, int): - raise RuntimeError("Token response missing fields") - - account_id = _decode_account_id(access) - return CodexToken( - access=access, - refresh=refresh, - expires=int(time.time() * 1000 + expires_in * 1000), - account_id=account_id, - ) - - -def _refresh_token(refresh_token: str) -> CodexToken: - data = { - "grant_type": "refresh_token", - "refresh_token": refresh_token, - "client_id": CLIENT_ID, - } - with httpx.Client(timeout=30.0) as client: - response = client.post(TOKEN_URL, data=data, headers={"Content-Type": "application/x-www-form-urlencoded"}) - if response.status_code != 200: - raise RuntimeError(f"Token refresh failed: {response.status_code} {response.text}") - - payload = response.json() - access = payload.get("access_token") - refresh = payload.get("refresh_token") - expires_in = payload.get("expires_in") - if not access or not refresh or not isinstance(expires_in, int): - raise RuntimeError("Token refresh response missing fields") - - account_id = _decode_account_id(access) - return CodexToken( - access=access, - refresh=refresh, - expires=int(time.time() * 1000 + expires_in * 1000), - account_id=account_id, - ) - - -def _load_token_file() -> CodexToken | None: - path = _get_token_path() - if not path.exists(): - return None - try: - data = json.loads(path.read_text(encoding="utf-8")) - return CodexToken( - access=data["access"], - refresh=data["refresh"], - expires=int(data["expires"]), - account_id=data["account_id"], - ) - except Exception: - return None - - -def _save_token_file(token: CodexToken) -> None: - path = _get_token_path() - path.parent.mkdir(parents=True, exist_ok=True) - path.write_text( - json.dumps( - { - "access": token.access, - "refresh": token.refresh, - "expires": token.expires, - "account_id": token.account_id, - }, - ensure_ascii=True, - indent=2, - ), - encoding="utf-8", - ) - try: - os.chmod(path, 0o600) - except Exception: - # Ignore permission setting failures. - pass - - -def _try_import_codex_cli_token() -> CodexToken | None: - codex_path = Path.home() / ".codex" / "auth.json" - if not codex_path.exists(): - return None - try: - data = json.loads(codex_path.read_text(encoding="utf-8")) - tokens = data.get("tokens") or {} - access = tokens.get("access_token") - refresh = tokens.get("refresh_token") - account_id = tokens.get("account_id") - if not access or not refresh or not account_id: - return None - try: - mtime = codex_path.stat().st_mtime - expires = int(mtime * 1000 + 60 * 60 * 1000) - except Exception: - expires = int(time.time() * 1000 + 60 * 60 * 1000) - token = CodexToken( - access=str(access), - refresh=str(refresh), - expires=expires, - account_id=str(account_id), - ) - _save_token_file(token) - return token - except Exception: - return None - - -class _FileLock: - """Simple file lock to reduce concurrent refreshes.""" - - def __init__(self, path: Path): - self._path = path - self._fp = None - - def __enter__(self) -> "_FileLock": - self._path.parent.mkdir(parents=True, exist_ok=True) - self._fp = open(self._path, "a+") - try: - import fcntl - - fcntl.flock(self._fp.fileno(), fcntl.LOCK_EX) - except Exception: - # Non-POSIX or failed lock: continue without locking. - pass - return self - - def __exit__(self, exc_type, exc, tb) -> None: - try: - import fcntl - - fcntl.flock(self._fp.fileno(), fcntl.LOCK_UN) - except Exception: - pass - try: - if self._fp: - self._fp.close() - except Exception: - pass - - -def get_codex_token() -> CodexToken: - """Get an available token (refresh if needed).""" - token = _load_token_file() or _try_import_codex_cli_token() - if not token: - raise RuntimeError("Codex OAuth credentials not found. Please run the login command.") - - # Refresh 60 seconds early. - now_ms = int(time.time() * 1000) - if token.expires - now_ms > 60 * 1000: - return token - - lock_path = _get_token_path().with_suffix(".lock") - with _FileLock(lock_path): - # Re-read to avoid stale token if another process refreshed it. - token = _load_token_file() or token - now_ms = int(time.time() * 1000) - if token.expires - now_ms > 60 * 1000: - return token - try: - refreshed = _refresh_token(token.refresh) - _save_token_file(refreshed) - return refreshed - except Exception: - # If refresh fails, re-read the file to avoid false negatives. - latest = _load_token_file() - if latest and latest.expires - now_ms > 0: - return latest - raise - - -def ensure_codex_token_available() -> None: - """Ensure a valid token is available; raise if not.""" - _ = get_codex_token() - - -async def _read_stdin_line() -> str: - loop = asyncio.get_running_loop() - if hasattr(loop, "add_reader") and sys.stdin: - future: asyncio.Future[str] = loop.create_future() - - def _on_readable() -> None: - line = sys.stdin.readline() - if not future.done(): - future.set_result(line) - - try: - loop.add_reader(sys.stdin, _on_readable) - except Exception: - return await loop.run_in_executor(None, sys.stdin.readline) - - try: - return await future - finally: - try: - loop.remove_reader(sys.stdin) - except Exception: - pass - - return await loop.run_in_executor(None, sys.stdin.readline) - - -async def _await_manual_input( - on_manual_code_input: Callable[[str], None], -) -> str: - await asyncio.sleep(MANUAL_PROMPT_DELAY_SEC) - on_manual_code_input("Paste the authorization code (or full redirect URL), or wait for the browser callback:") - return await _read_stdin_line() - - -def login_codex_oauth_interactive( - on_auth: Callable[[str], None] | None = None, - on_prompt: Callable[[str], str] | None = None, - on_status: Callable[[str], None] | None = None, - on_progress: Callable[[str], None] | None = None, - on_manual_code_input: Callable[[str], None] = None, - originator: str = DEFAULT_ORIGINATOR, -) -> CodexToken: - """Interactive login flow.""" - async def _login_async() -> CodexToken: - verifier, challenge = _generate_pkce() - state = _create_state() - - params = { - "response_type": "code", - "client_id": CLIENT_ID, - "redirect_uri": REDIRECT_URI, - "scope": SCOPE, - "code_challenge": challenge, - "code_challenge_method": "S256", - "state": state, - "id_token_add_organizations": "true", - "codex_cli_simplified_flow": "true", - "originator": originator, - } - url = f"{AUTHORIZE_URL}?{urllib.parse.urlencode(params)}" - - loop = asyncio.get_running_loop() - code_future: asyncio.Future[str] = loop.create_future() - - def _notify(code_value: str) -> None: - if code_future.done(): - return - loop.call_soon_threadsafe(code_future.set_result, code_value) - - server, server_error = _start_local_server(state, on_code=_notify) - if on_auth: - on_auth(url) - else: - webbrowser.open(url) - - if not server and server_error and on_status: - on_status( - f"Local callback server could not start ({server_error}). " - "You will need to paste the callback URL or authorization code." - ) - - code: str | None = None - try: - if server: - if on_progress and not on_manual_code_input: - on_progress("Waiting for browser callback...") - - tasks: list[asyncio.Task[Any]] = [] - callback_task = asyncio.create_task(asyncio.wait_for(code_future, timeout=120)) - tasks.append(callback_task) - manual_task = asyncio.create_task(_await_manual_input(on_manual_code_input)) - tasks.append(manual_task) - - done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED) - for task in pending: - task.cancel() - - for task in done: - try: - result = task.result() - except asyncio.TimeoutError: - result = None - if not result: - continue - if task is manual_task: - parsed_code, parsed_state = _parse_authorization_input(result) - if parsed_state and parsed_state != state: - raise RuntimeError("State validation failed.") - code = parsed_code - else: - code = result - if code: - break - - if not code: - prompt = "Please paste the callback URL or authorization code:" - if on_prompt: - raw = await loop.run_in_executor(None, on_prompt, prompt) - else: - raw = await loop.run_in_executor(None, input, prompt) - parsed_code, parsed_state = _parse_authorization_input(raw) - if parsed_state and parsed_state != state: - raise RuntimeError("State validation failed.") - code = parsed_code - - if not code: - raise RuntimeError("Authorization code not found.") - - if on_progress: - on_progress("Exchanging authorization code for tokens...") - token = await _exchange_code_for_token_async(code, verifier) - _save_token_file(token) - return token - finally: - if server: - server.shutdown() - server.server_close() - - try: - asyncio.get_running_loop() - except RuntimeError: - return asyncio.run(_login_async()) - - result: list[CodexToken] = [] - error: list[Exception] = [] - - def _runner() -> None: - try: - result.append(asyncio.run(_login_async())) - except Exception as exc: - error.append(exc) - - thread = threading.Thread(target=_runner) - thread.start() - thread.join() - if error: - raise error[0] - return result[0] diff --git a/nanobot/cli/commands.py b/nanobot/cli/commands.py index 213f8c5..93be424 100644 --- a/nanobot/cli/commands.py +++ b/nanobot/cli/commands.py @@ -82,7 +82,7 @@ def login( console.print(f"[red]Unsupported provider: {provider}[/red]") raise typer.Exit(1) - from nanobot.auth.codex_oauth import login_codex_oauth_interactive + from nanobot.auth.codex import login_codex_oauth_interactive def on_auth(url: str) -> None: console.print("[cyan]A browser window will open for login. If it doesn't, open this URL manually:[/cyan]") @@ -205,7 +205,7 @@ def gateway( from nanobot.bus.queue import MessageBus from nanobot.providers.litellm_provider import LiteLLMProvider from nanobot.providers.openai_codex_provider import OpenAICodexProvider - from nanobot.auth.codex_oauth import ensure_codex_token_available + from nanobot.auth.codex import ensure_codex_token_available from nanobot.agent.loop import AgentLoop from nanobot.channels.manager import ChannelManager from nanobot.cron.service import CronService @@ -341,7 +341,7 @@ def agent( from nanobot.bus.queue import MessageBus from nanobot.providers.litellm_provider import LiteLLMProvider from nanobot.providers.openai_codex_provider import OpenAICodexProvider - from nanobot.auth.codex_oauth import ensure_codex_token_available + from nanobot.auth.codex import ensure_codex_token_available from nanobot.agent.loop import AgentLoop config = load_config() diff --git a/nanobot/providers/openai_codex_provider.py b/nanobot/providers/openai_codex_provider.py index 2081180..ec0383c 100644 --- a/nanobot/providers/openai_codex_provider.py +++ b/nanobot/providers/openai_codex_provider.py @@ -1,4 +1,4 @@ -"""OpenAI Codex Responses Provider。""" +"""OpenAI Codex Responses Provider.""" from __future__ import annotations @@ -9,7 +9,7 @@ from typing import Any, AsyncGenerator import httpx -from nanobot.auth.codex_oauth import get_codex_token +from nanobot.auth.codex import get_codex_token from nanobot.providers.base import LLMProvider, LLMResponse, ToolCallRequest DEFAULT_CODEX_BASE_URL = "https://chatgpt.com/backend-api" @@ -17,7 +17,7 @@ DEFAULT_ORIGINATOR = "nanobot" class OpenAICodexProvider(LLMProvider): - """使用 Codex OAuth 调用 Responses 接口。""" + """Use Codex OAuth to call the Responses API.""" def __init__(self, default_model: str = "openai-codex/gpt-5.1-codex"): super().__init__(api_key=None, api_base=None) @@ -56,37 +56,18 @@ class OpenAICodexProvider(LLMProvider): url = _resolve_codex_url(DEFAULT_CODEX_BASE_URL) try: - async with httpx.AsyncClient(timeout=60.0) as client: - try: - async with client.stream("POST", url, headers=headers, json=body) as response: - if response.status_code != 200: - text = await response.aread() - raise RuntimeError( - _friendly_error(response.status_code, text.decode("utf-8", "ignore")) - ) - content, tool_calls, finish_reason = await _consume_sse(response) - return LLMResponse( - content=content, - tool_calls=tool_calls, - finish_reason=finish_reason, - ) - except Exception as e: - # 证书校验失败时降级关闭校验(存在安全风险) - if "CERTIFICATE_VERIFY_FAILED" not in str(e): - raise - async with httpx.AsyncClient(timeout=60.0, verify=False) as insecure_client: - async with insecure_client.stream("POST", url, headers=headers, json=body) as response: - if response.status_code != 200: - text = await response.aread() - raise RuntimeError( - _friendly_error(response.status_code, text.decode("utf-8", "ignore")) - ) - content, tool_calls, finish_reason = await _consume_sse(response) - return LLMResponse( - content=content, - tool_calls=tool_calls, - finish_reason=finish_reason, - ) + try: + content, tool_calls, finish_reason = await _request_codex(url, headers, body, verify=True) + except Exception as e: + # Certificate verification failed, downgrade to disable verification (security risk) + if "CERTIFICATE_VERIFY_FAILED" not in str(e): + raise + content, tool_calls, finish_reason = await _request_codex(url, headers, body, verify=False) + return LLMResponse( + content=content, + tool_calls=tool_calls, + finish_reason=finish_reason, + ) except Exception as e: return LLMResponse( content=f"Error calling Codex: {str(e)}", @@ -124,17 +105,31 @@ def _build_headers(account_id: str, token: str) -> dict[str, str]: } +async def _request_codex( + url: str, + headers: dict[str, str], + body: dict[str, Any], + verify: bool, +) -> tuple[str, list[ToolCallRequest], str]: + async with httpx.AsyncClient(timeout=60.0, verify=verify) as client: + async with client.stream("POST", url, headers=headers, json=body) as response: + if response.status_code != 200: + text = await response.aread() + raise RuntimeError(_friendly_error(response.status_code, text.decode("utf-8", "ignore"))) + return await _consume_sse(response) + + def _convert_tools(tools: list[dict[str, Any]]) -> list[dict[str, Any]]: - # nanobot 工具定义已是 OpenAI function schema + # Nanobot tool definitions already use the OpenAI function schema. converted: list[dict[str, Any]] = [] for tool in tools: name = tool.get("name") if not isinstance(name, str) or not name: - # 忽略无效工具,避免被 Codex 拒绝 + # Skip invalid tools to avoid Codex rejection. continue params = tool.get("parameters") or {} if not isinstance(params, dict): - # 参数必须是 JSON Schema 对象 + # Parameters must be a JSON Schema object. params = {} converted.append( { @@ -164,7 +159,7 @@ def _convert_messages(messages: list[dict[str, Any]]) -> tuple[str, list[dict[st continue if role == "assistant": - # 先处理文本 + # Handle text first. if isinstance(content, str) and content: input_items.append( { @@ -175,7 +170,7 @@ def _convert_messages(messages: list[dict[str, Any]]) -> tuple[str, list[dict[st "id": f"msg_{idx}", } ) - # 再处理工具调用 + # Then handle tool calls. for tool_call in msg.get("tool_calls", []) or []: fn = tool_call.get("function") or {} call_id = tool_call.get("id") or f"call_{idx}" @@ -329,5 +324,5 @@ def _map_finish_reason(status: str | None) -> str: def _friendly_error(status_code: int, raw: str) -> str: if status_code == 429: - return "ChatGPT 使用额度已达上限或触发限流,请稍后再试。" + return "ChatGPT usage quota exceeded or rate limit triggered. Please try again later." return f"HTTP {status_code}: {raw}" From 01420f4dd607aea6c8f9881a1b72ac2a814a628a Mon Sep 17 00:00:00 2001 From: pinhua33 Date: Fri, 6 Feb 2026 00:14:31 +0800 Subject: [PATCH 03/60] refactor: remove unused functions and simplify code --- nanobot/auth/__init__.py | 7 +-- nanobot/auth/codex/__init__.py | 10 +---- nanobot/auth/codex/constants.py | 1 - nanobot/auth/codex/flow.py | 76 +++++++++------------------------ nanobot/cli/commands.py | 42 ++++-------------- 5 files changed, 30 insertions(+), 106 deletions(-) diff --git a/nanobot/auth/__init__.py b/nanobot/auth/__init__.py index c74d992..ecdc1dc 100644 --- a/nanobot/auth/__init__.py +++ b/nanobot/auth/__init__.py @@ -1,13 +1,8 @@ """Authentication modules.""" -from nanobot.auth.codex import ( - ensure_codex_token_available, - get_codex_token, - login_codex_oauth_interactive, -) +from nanobot.auth.codex import get_codex_token, login_codex_oauth_interactive __all__ = [ - "ensure_codex_token_available", "get_codex_token", "login_codex_oauth_interactive", ] diff --git a/nanobot/auth/codex/__init__.py b/nanobot/auth/codex/__init__.py index 707cd4d..7a9a39b 100644 --- a/nanobot/auth/codex/__init__.py +++ b/nanobot/auth/codex/__init__.py @@ -1,15 +1,7 @@ """Codex OAuth module.""" -from nanobot.auth.codex.flow import ( - ensure_codex_token_available, - get_codex_token, - login_codex_oauth_interactive, -) -from nanobot.auth.codex.models import CodexToken - +from nanobot.auth.codex.flow import get_codex_token, login_codex_oauth_interactive __all__ = [ - "CodexToken", - "ensure_codex_token_available", "get_codex_token", "login_codex_oauth_interactive", ] diff --git a/nanobot/auth/codex/constants.py b/nanobot/auth/codex/constants.py index bbe676a..7f20aad 100644 --- a/nanobot/auth/codex/constants.py +++ b/nanobot/auth/codex/constants.py @@ -9,7 +9,6 @@ JWT_CLAIM_PATH = "https://api.openai.com/auth" DEFAULT_ORIGINATOR = "nanobot" TOKEN_FILENAME = "codex.json" -MANUAL_PROMPT_DELAY_SEC = 3 SUCCESS_HTML = ( "" "" diff --git a/nanobot/auth/codex/flow.py b/nanobot/auth/codex/flow.py index 0966327..d05feb7 100644 --- a/nanobot/auth/codex/flow.py +++ b/nanobot/auth/codex/flow.py @@ -8,7 +8,7 @@ import threading import time import urllib.parse import webbrowser -from typing import Any, Callable +from typing import Callable import httpx @@ -16,7 +16,6 @@ from nanobot.auth.codex.constants import ( AUTHORIZE_URL, CLIENT_ID, DEFAULT_ORIGINATOR, - MANUAL_PROMPT_DELAY_SEC, REDIRECT_URI, SCOPE, TOKEN_URL, @@ -39,31 +38,6 @@ from nanobot.auth.codex.storage import ( ) -def _exchange_code_for_token(code: str, verifier: str) -> CodexToken: - data = { - "grant_type": "authorization_code", - "client_id": CLIENT_ID, - "code": code, - "code_verifier": verifier, - "redirect_uri": REDIRECT_URI, - } - with httpx.Client(timeout=30.0) as client: - response = client.post(TOKEN_URL, data=data, headers={"Content-Type": "application/x-www-form-urlencoded"}) - if response.status_code != 200: - raise RuntimeError(f"Token exchange failed: {response.status_code} {response.text}") - - payload = response.json() - access, refresh, expires_in = _parse_token_payload(payload, "Token response missing fields") - print("Received access token:", access) - account_id = _decode_account_id(access) - return CodexToken( - access=access, - refresh=refresh, - expires=int(time.time() * 1000 + expires_in * 1000), - account_id=account_id, - ) - - async def _exchange_code_for_token_async(code: str, verifier: str) -> CodexToken: data = { "grant_type": "authorization_code", @@ -146,11 +120,6 @@ def get_codex_token() -> CodexToken: raise -def ensure_codex_token_available() -> None: - """Ensure a valid token is available; raise if not.""" - _ = get_codex_token() - - async def _read_stdin_line() -> str: loop = asyncio.get_running_loop() if hasattr(loop, "add_reader") and sys.stdin: @@ -177,20 +146,14 @@ async def _read_stdin_line() -> str: return await loop.run_in_executor(None, sys.stdin.readline) -async def _await_manual_input( - on_manual_code_input: Callable[[str], None], -) -> str: - await asyncio.sleep(MANUAL_PROMPT_DELAY_SEC) - on_manual_code_input("Paste the authorization code (or full redirect URL), or wait for the browser callback:") +async def _await_manual_input(print_fn: Callable[[str], None]) -> str: + print_fn("[cyan]Paste the authorization code (or full redirect URL), or wait for the browser callback:[/cyan]") return await _read_stdin_line() def login_codex_oauth_interactive( - on_auth: Callable[[str], None] | None = None, - on_prompt: Callable[[str], str] | None = None, - on_status: Callable[[str], None] | None = None, - on_progress: Callable[[str], None] | None = None, - on_manual_code_input: Callable[[str], None] = None, + print_fn: Callable[[str], None], + prompt_fn: Callable[[str], str], originator: str = DEFAULT_ORIGINATOR, ) -> CodexToken: """Interactive login flow.""" @@ -222,27 +185,30 @@ def login_codex_oauth_interactive( loop.call_soon_threadsafe(code_future.set_result, code_value) server, server_error = _start_local_server(state, on_code=_notify) - if on_auth: - on_auth(url) - else: + print_fn("[cyan]A browser window will open for login. If it doesn't, open this URL manually:[/cyan]") + print_fn(url) + try: webbrowser.open(url) + except Exception: + pass - if not server and server_error and on_status: - on_status( + if not server and server_error: + print_fn( + "[yellow]" f"Local callback server could not start ({server_error}). " "You will need to paste the callback URL or authorization code." + "[/yellow]" ) code: str | None = None try: if server: - if on_progress and not on_manual_code_input: - on_progress("Waiting for browser callback...") + print_fn("[dim]Waiting for browser callback...[/dim]") - tasks: list[asyncio.Task[Any]] = [] + tasks: list[asyncio.Task[object]] = [] callback_task = asyncio.create_task(asyncio.wait_for(code_future, timeout=120)) tasks.append(callback_task) - manual_task = asyncio.create_task(_await_manual_input(on_manual_code_input)) + manual_task = asyncio.create_task(_await_manual_input(print_fn)) tasks.append(manual_task) done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED) @@ -268,10 +234,7 @@ def login_codex_oauth_interactive( if not code: prompt = "Please paste the callback URL or authorization code:" - if on_prompt: - raw = await loop.run_in_executor(None, on_prompt, prompt) - else: - raw = await loop.run_in_executor(None, input, prompt) + raw = await loop.run_in_executor(None, prompt_fn, prompt) parsed_code, parsed_state = _parse_authorization_input(raw) if parsed_state and parsed_state != state: raise RuntimeError("State validation failed.") @@ -280,8 +243,7 @@ def login_codex_oauth_interactive( if not code: raise RuntimeError("Authorization code not found.") - if on_progress: - on_progress("Exchanging authorization code for tokens...") + print_fn("[dim]Exchanging authorization code for tokens...[/dim]") token = await _exchange_code_for_token_async(code, verifier) _save_token_file(token) return token diff --git a/nanobot/cli/commands.py b/nanobot/cli/commands.py index 93be424..7827103 100644 --- a/nanobot/cli/commands.py +++ b/nanobot/cli/commands.py @@ -84,37 +84,12 @@ def login( from nanobot.auth.codex import login_codex_oauth_interactive - def on_auth(url: str) -> None: - console.print("[cyan]A browser window will open for login. If it doesn't, open this URL manually:[/cyan]") - console.print(url) - try: - import webbrowser - webbrowser.open(url) - except Exception: - pass - - def on_status(message: str) -> None: - console.print(f"[yellow]{message}[/yellow]") - - def on_progress(message: str) -> None: - console.print(f"[dim]{message}[/dim]") - - def on_prompt(message: str) -> str: - return typer.prompt(message) - - def on_manual_code_input(message: str) -> None: - console.print(f"[cyan]{message}[/cyan]") - console.print("[green]Starting OpenAI Codex OAuth login...[/green]") login_codex_oauth_interactive( - on_auth=on_auth, - on_prompt=on_prompt, - on_status=on_status, - on_progress=on_progress, - on_manual_code_input=on_manual_code_input, + print_fn=console.print, + prompt_fn=typer.prompt, ) - console.print("[green]✓ Login successful. Credentials saved.[/green]") - + console.print("[green]Login successful. Credentials saved.[/green]") @@ -205,7 +180,7 @@ def gateway( from nanobot.bus.queue import MessageBus from nanobot.providers.litellm_provider import LiteLLMProvider from nanobot.providers.openai_codex_provider import OpenAICodexProvider - from nanobot.auth.codex import ensure_codex_token_available + from nanobot.auth.codex import get_codex_token from nanobot.agent.loop import AgentLoop from nanobot.channels.manager import ChannelManager from nanobot.cron.service import CronService @@ -232,7 +207,7 @@ def gateway( if is_codex: try: - ensure_codex_token_available() + _ = get_codex_token() except Exception as e: console.print(f"[red]Error: {e}[/red]") console.print("Please run: [cyan]nanobot login --provider openai-codex[/cyan]") @@ -341,7 +316,7 @@ def agent( from nanobot.bus.queue import MessageBus from nanobot.providers.litellm_provider import LiteLLMProvider from nanobot.providers.openai_codex_provider import OpenAICodexProvider - from nanobot.auth.codex import ensure_codex_token_available + from nanobot.auth.codex import get_codex_token from nanobot.agent.loop import AgentLoop config = load_config() @@ -354,7 +329,7 @@ def agent( if is_codex: try: - ensure_codex_token_available() + _ = get_codex_token() except Exception as e: console.print(f"[red]Error: {e}[/red]") console.print("Please run: [cyan]nanobot login --provider openai-codex[/cyan]") @@ -716,9 +691,10 @@ def status(): console.print(f"Anthropic API: {'[green]✓[/green]' if has_anthropic else '[dim]not set[/dim]'}") console.print(f"OpenAI API: {'[green]✓[/green]' if has_openai else '[dim]not set[/dim]'}") console.print(f"Gemini API: {'[green]✓[/green]' if has_gemini else '[dim]not set[/dim]'}") - vllm_status = f"[green]✓ {config.providers.vllm.api_base}[/green]" if has_vllm else "[dim]not set[/dim]" + vllm_status = f"[green]�?{config.providers.vllm.api_base}[/green]" if has_vllm else "[dim]not set[/dim]" console.print(f"vLLM/Local: {vllm_status}") if __name__ == "__main__": app() + From f20afc8d2f033f873f57072ed77c2a08ece250a2 Mon Sep 17 00:00:00 2001 From: pinhua33 Date: Fri, 6 Feb 2026 00:39:02 +0800 Subject: [PATCH 04/60] feat: add Codex login status to nanobot status command --- nanobot/cli/commands.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/nanobot/cli/commands.py b/nanobot/cli/commands.py index 7827103..3be4e23 100644 --- a/nanobot/cli/commands.py +++ b/nanobot/cli/commands.py @@ -1,4 +1,4 @@ -"""CLI commands for nanobot.""" +"""CLI commands for nanobot.""" import asyncio from pathlib import Path @@ -667,6 +667,7 @@ def cron_run( def status(): """Show nanobot status.""" from nanobot.config.loader import load_config, get_config_path + from nanobot.auth.codex import get_codex_token config_path = get_config_path() config = load_config() @@ -694,6 +695,12 @@ def status(): vllm_status = f"[green]�?{config.providers.vllm.api_base}[/green]" if has_vllm else "[dim]not set[/dim]" console.print(f"vLLM/Local: {vllm_status}") + try: + _ = get_codex_token() + codex_status = "[green]logged in[/green]" + except Exception: + codex_status = "[dim]not logged in[/dim]" + console.print(f"Codex Login: {codex_status}") if __name__ == "__main__": app() From b639192e46d7a9ebe94714c270ea1bbace0bb224 Mon Sep 17 00:00:00 2001 From: pinhua33 Date: Fri, 6 Feb 2026 11:52:03 +0800 Subject: [PATCH 05/60] fix: codex tool calling failed unexpectedly --- nanobot/providers/openai_codex_provider.py | 28 ++++++++++++++++++---- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/nanobot/providers/openai_codex_provider.py b/nanobot/providers/openai_codex_provider.py index ec0383c..a23becd 100644 --- a/nanobot/providers/openai_codex_provider.py +++ b/nanobot/providers/openai_codex_provider.py @@ -123,11 +123,19 @@ def _convert_tools(tools: list[dict[str, Any]]) -> list[dict[str, Any]]: # Nanobot tool definitions already use the OpenAI function schema. converted: list[dict[str, Any]] = [] for tool in tools: - name = tool.get("name") + fn = tool.get("function") if isinstance(tool, dict) and tool.get("type") == "function" else None + if fn and isinstance(fn, dict): + name = fn.get("name") + desc = fn.get("description") + params = fn.get("parameters") + else: + name = tool.get("name") + desc = tool.get("description") + params = tool.get("parameters") if not isinstance(name, str) or not name: # Skip invalid tools to avoid Codex rejection. continue - params = tool.get("parameters") or {} + params = params or {} if not isinstance(params, dict): # Parameters must be a JSON Schema object. params = {} @@ -135,7 +143,7 @@ def _convert_tools(tools: list[dict[str, Any]]) -> list[dict[str, Any]]: { "type": "function", "name": name, - "description": tool.get("description") or "", + "description": desc or "", "parameters": params, } ) @@ -173,8 +181,9 @@ def _convert_messages(messages: list[dict[str, Any]]) -> tuple[str, list[dict[st # Then handle tool calls. for tool_call in msg.get("tool_calls", []) or []: fn = tool_call.get("function") or {} - call_id = tool_call.get("id") or f"call_{idx}" - item_id = f"fc_{idx}" + call_id, item_id = _split_tool_call_id(tool_call.get("id")) + call_id = call_id or f"call_{idx}" + item_id = item_id or f"fc_{idx}" input_items.append( { "type": "function_call", @@ -226,6 +235,15 @@ def _extract_call_id(tool_call_id: Any) -> str: return "call_0" +def _split_tool_call_id(tool_call_id: Any) -> tuple[str, str | None]: + if isinstance(tool_call_id, str) and tool_call_id: + if "|" in tool_call_id: + call_id, item_id = tool_call_id.split("|", 1) + return call_id, item_id or None + return tool_call_id, None + return "call_0", None + + def _prompt_cache_key(messages: list[dict[str, Any]]) -> str: raw = json.dumps(messages, ensure_ascii=True, sort_keys=True) return hashlib.sha256(raw.encode("utf-8")).hexdigest() From 42c2d83d70251a98233057ba0e55047a4cb112e7 Mon Sep 17 00:00:00 2001 From: pinhua33 Date: Sun, 8 Feb 2026 13:41:47 +0800 Subject: [PATCH 06/60] refactor: remove Codex OAuth implementation and integrate oauth-cli-kit --- nanobot/auth/__init__.py | 8 - nanobot/auth/codex/__init__.py | 7 - nanobot/auth/codex/constants.py | 24 -- nanobot/auth/codex/flow.py | 274 --------------------- nanobot/auth/codex/models.py | 15 -- nanobot/auth/codex/pkce.py | 77 ------ nanobot/auth/codex/server.py | 115 --------- nanobot/auth/codex/storage.py | 118 --------- nanobot/cli/commands.py | 20 +- nanobot/providers/openai_codex_provider.py | 2 +- pyproject.toml | 1 + 11 files changed, 15 insertions(+), 646 deletions(-) delete mode 100644 nanobot/auth/__init__.py delete mode 100644 nanobot/auth/codex/__init__.py delete mode 100644 nanobot/auth/codex/constants.py delete mode 100644 nanobot/auth/codex/flow.py delete mode 100644 nanobot/auth/codex/models.py delete mode 100644 nanobot/auth/codex/pkce.py delete mode 100644 nanobot/auth/codex/server.py delete mode 100644 nanobot/auth/codex/storage.py diff --git a/nanobot/auth/__init__.py b/nanobot/auth/__init__.py deleted file mode 100644 index ecdc1dc..0000000 --- a/nanobot/auth/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -"""Authentication modules.""" - -from nanobot.auth.codex import get_codex_token, login_codex_oauth_interactive - -__all__ = [ - "get_codex_token", - "login_codex_oauth_interactive", -] diff --git a/nanobot/auth/codex/__init__.py b/nanobot/auth/codex/__init__.py deleted file mode 100644 index 7a9a39b..0000000 --- a/nanobot/auth/codex/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -"""Codex OAuth module.""" - -from nanobot.auth.codex.flow import get_codex_token, login_codex_oauth_interactive -__all__ = [ - "get_codex_token", - "login_codex_oauth_interactive", -] diff --git a/nanobot/auth/codex/constants.py b/nanobot/auth/codex/constants.py deleted file mode 100644 index 7f20aad..0000000 --- a/nanobot/auth/codex/constants.py +++ /dev/null @@ -1,24 +0,0 @@ -"""Codex OAuth constants.""" - -CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann" -AUTHORIZE_URL = "https://auth.openai.com/oauth/authorize" -TOKEN_URL = "https://auth.openai.com/oauth/token" -REDIRECT_URI = "http://localhost:1455/auth/callback" -SCOPE = "openid profile email offline_access" -JWT_CLAIM_PATH = "https://api.openai.com/auth" - -DEFAULT_ORIGINATOR = "nanobot" -TOKEN_FILENAME = "codex.json" -SUCCESS_HTML = ( - "" - "" - "" - "" - "" - "Authentication successful" - "" - "" - "

Authentication successful. Return to your terminal to continue.

" - "" - "" -) diff --git a/nanobot/auth/codex/flow.py b/nanobot/auth/codex/flow.py deleted file mode 100644 index d05feb7..0000000 --- a/nanobot/auth/codex/flow.py +++ /dev/null @@ -1,274 +0,0 @@ -"""Codex OAuth login and token management.""" - -from __future__ import annotations - -import asyncio -import sys -import threading -import time -import urllib.parse -import webbrowser -from typing import Callable - -import httpx - -from nanobot.auth.codex.constants import ( - AUTHORIZE_URL, - CLIENT_ID, - DEFAULT_ORIGINATOR, - REDIRECT_URI, - SCOPE, - TOKEN_URL, -) -from nanobot.auth.codex.models import CodexToken -from nanobot.auth.codex.pkce import ( - _create_state, - _decode_account_id, - _generate_pkce, - _parse_authorization_input, - _parse_token_payload, -) -from nanobot.auth.codex.server import _start_local_server -from nanobot.auth.codex.storage import ( - _FileLock, - _get_token_path, - _load_token_file, - _save_token_file, - _try_import_codex_cli_token, -) - - -async def _exchange_code_for_token_async(code: str, verifier: str) -> CodexToken: - data = { - "grant_type": "authorization_code", - "client_id": CLIENT_ID, - "code": code, - "code_verifier": verifier, - "redirect_uri": REDIRECT_URI, - } - async with httpx.AsyncClient(timeout=30.0) as client: - response = await client.post( - TOKEN_URL, - data=data, - headers={"Content-Type": "application/x-www-form-urlencoded"}, - ) - if response.status_code != 200: - raise RuntimeError(f"Token exchange failed: {response.status_code} {response.text}") - - payload = response.json() - access, refresh, expires_in = _parse_token_payload(payload, "Token response missing fields") - - account_id = _decode_account_id(access) - return CodexToken( - access=access, - refresh=refresh, - expires=int(time.time() * 1000 + expires_in * 1000), - account_id=account_id, - ) - - -def _refresh_token(refresh_token: str) -> CodexToken: - data = { - "grant_type": "refresh_token", - "refresh_token": refresh_token, - "client_id": CLIENT_ID, - } - with httpx.Client(timeout=30.0) as client: - response = client.post(TOKEN_URL, data=data, headers={"Content-Type": "application/x-www-form-urlencoded"}) - if response.status_code != 200: - raise RuntimeError(f"Token refresh failed: {response.status_code} {response.text}") - - payload = response.json() - access, refresh, expires_in = _parse_token_payload(payload, "Token refresh response missing fields") - - account_id = _decode_account_id(access) - return CodexToken( - access=access, - refresh=refresh, - expires=int(time.time() * 1000 + expires_in * 1000), - account_id=account_id, - ) - - -def get_codex_token() -> CodexToken: - """Get an available token (refresh if needed).""" - token = _load_token_file() or _try_import_codex_cli_token() - if not token: - raise RuntimeError("Codex OAuth credentials not found. Please run the login command.") - - # Refresh 60 seconds early. - now_ms = int(time.time() * 1000) - if token.expires - now_ms > 60 * 1000: - return token - - lock_path = _get_token_path().with_suffix(".lock") - with _FileLock(lock_path): - # Re-read to avoid stale token if another process refreshed it. - token = _load_token_file() or token - now_ms = int(time.time() * 1000) - if token.expires - now_ms > 60 * 1000: - return token - try: - refreshed = _refresh_token(token.refresh) - _save_token_file(refreshed) - return refreshed - except Exception: - # If refresh fails, re-read the file to avoid false negatives. - latest = _load_token_file() - if latest and latest.expires - now_ms > 0: - return latest - raise - - -async def _read_stdin_line() -> str: - loop = asyncio.get_running_loop() - if hasattr(loop, "add_reader") and sys.stdin: - future: asyncio.Future[str] = loop.create_future() - - def _on_readable() -> None: - line = sys.stdin.readline() - if not future.done(): - future.set_result(line) - - try: - loop.add_reader(sys.stdin, _on_readable) - except Exception: - return await loop.run_in_executor(None, sys.stdin.readline) - - try: - return await future - finally: - try: - loop.remove_reader(sys.stdin) - except Exception: - pass - - return await loop.run_in_executor(None, sys.stdin.readline) - - -async def _await_manual_input(print_fn: Callable[[str], None]) -> str: - print_fn("[cyan]Paste the authorization code (or full redirect URL), or wait for the browser callback:[/cyan]") - return await _read_stdin_line() - - -def login_codex_oauth_interactive( - print_fn: Callable[[str], None], - prompt_fn: Callable[[str], str], - originator: str = DEFAULT_ORIGINATOR, -) -> CodexToken: - """Interactive login flow.""" - - async def _login_async() -> CodexToken: - verifier, challenge = _generate_pkce() - state = _create_state() - - params = { - "response_type": "code", - "client_id": CLIENT_ID, - "redirect_uri": REDIRECT_URI, - "scope": SCOPE, - "code_challenge": challenge, - "code_challenge_method": "S256", - "state": state, - "id_token_add_organizations": "true", - "codex_cli_simplified_flow": "true", - "originator": originator, - } - url = f"{AUTHORIZE_URL}?{urllib.parse.urlencode(params)}" - - loop = asyncio.get_running_loop() - code_future: asyncio.Future[str] = loop.create_future() - - def _notify(code_value: str) -> None: - if code_future.done(): - return - loop.call_soon_threadsafe(code_future.set_result, code_value) - - server, server_error = _start_local_server(state, on_code=_notify) - print_fn("[cyan]A browser window will open for login. If it doesn't, open this URL manually:[/cyan]") - print_fn(url) - try: - webbrowser.open(url) - except Exception: - pass - - if not server and server_error: - print_fn( - "[yellow]" - f"Local callback server could not start ({server_error}). " - "You will need to paste the callback URL or authorization code." - "[/yellow]" - ) - - code: str | None = None - try: - if server: - print_fn("[dim]Waiting for browser callback...[/dim]") - - tasks: list[asyncio.Task[object]] = [] - callback_task = asyncio.create_task(asyncio.wait_for(code_future, timeout=120)) - tasks.append(callback_task) - manual_task = asyncio.create_task(_await_manual_input(print_fn)) - tasks.append(manual_task) - - done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED) - for task in pending: - task.cancel() - - for task in done: - try: - result = task.result() - except asyncio.TimeoutError: - result = None - if not result: - continue - if task is manual_task: - parsed_code, parsed_state = _parse_authorization_input(result) - if parsed_state and parsed_state != state: - raise RuntimeError("State validation failed.") - code = parsed_code - else: - code = result - if code: - break - - if not code: - prompt = "Please paste the callback URL or authorization code:" - raw = await loop.run_in_executor(None, prompt_fn, prompt) - parsed_code, parsed_state = _parse_authorization_input(raw) - if parsed_state and parsed_state != state: - raise RuntimeError("State validation failed.") - code = parsed_code - - if not code: - raise RuntimeError("Authorization code not found.") - - print_fn("[dim]Exchanging authorization code for tokens...[/dim]") - token = await _exchange_code_for_token_async(code, verifier) - _save_token_file(token) - return token - finally: - if server: - server.shutdown() - server.server_close() - - try: - asyncio.get_running_loop() - except RuntimeError: - return asyncio.run(_login_async()) - - result: list[CodexToken] = [] - error: list[Exception] = [] - - def _runner() -> None: - try: - result.append(asyncio.run(_login_async())) - except Exception as exc: - error.append(exc) - - thread = threading.Thread(target=_runner) - thread.start() - thread.join() - if error: - raise error[0] - return result[0] diff --git a/nanobot/auth/codex/models.py b/nanobot/auth/codex/models.py deleted file mode 100644 index e3a5f55..0000000 --- a/nanobot/auth/codex/models.py +++ /dev/null @@ -1,15 +0,0 @@ -"""Codex OAuth data models.""" - -from __future__ import annotations - -from dataclasses import dataclass - - -@dataclass -class CodexToken: - """Codex OAuth token data structure.""" - - access: str - refresh: str - expires: int - account_id: str diff --git a/nanobot/auth/codex/pkce.py b/nanobot/auth/codex/pkce.py deleted file mode 100644 index b682386..0000000 --- a/nanobot/auth/codex/pkce.py +++ /dev/null @@ -1,77 +0,0 @@ -"""PKCE and authorization helpers.""" - -from __future__ import annotations - -import base64 -import hashlib -import json -import os -import urllib.parse -from typing import Any - -from nanobot.auth.codex.constants import JWT_CLAIM_PATH - - -def _base64url(data: bytes) -> str: - return base64.urlsafe_b64encode(data).rstrip(b"=").decode("utf-8") - - -def _decode_base64url(data: str) -> bytes: - padding = "=" * (-len(data) % 4) - return base64.urlsafe_b64decode(data + padding) - - -def _generate_pkce() -> tuple[str, str]: - verifier = _base64url(os.urandom(32)) - challenge = _base64url(hashlib.sha256(verifier.encode("utf-8")).digest()) - return verifier, challenge - - -def _create_state() -> str: - return _base64url(os.urandom(16)) - - -def _parse_authorization_input(raw: str) -> tuple[str | None, str | None]: - value = raw.strip() - if not value: - return None, None - try: - url = urllib.parse.urlparse(value) - qs = urllib.parse.parse_qs(url.query) - code = qs.get("code", [None])[0] - state = qs.get("state", [None])[0] - if code: - return code, state - except Exception: - pass - - if "#" in value: - parts = value.split("#", 1) - return parts[0] or None, parts[1] or None - - if "code=" in value: - qs = urllib.parse.parse_qs(value) - return qs.get("code", [None])[0], qs.get("state", [None])[0] - - return value, None - - -def _decode_account_id(access_token: str) -> str: - parts = access_token.split(".") - if len(parts) != 3: - raise ValueError("Invalid JWT token") - payload = json.loads(_decode_base64url(parts[1]).decode("utf-8")) - auth = payload.get(JWT_CLAIM_PATH) or {} - account_id = auth.get("chatgpt_account_id") - if not account_id: - raise ValueError("Failed to extract account_id from token") - return str(account_id) - - -def _parse_token_payload(payload: dict[str, Any], missing_message: str) -> tuple[str, str, int]: - access = payload.get("access_token") - refresh = payload.get("refresh_token") - expires_in = payload.get("expires_in") - if not access or not refresh or not isinstance(expires_in, int): - raise RuntimeError(missing_message) - return access, refresh, expires_in diff --git a/nanobot/auth/codex/server.py b/nanobot/auth/codex/server.py deleted file mode 100644 index f31db19..0000000 --- a/nanobot/auth/codex/server.py +++ /dev/null @@ -1,115 +0,0 @@ -"""Local OAuth callback server.""" - -from __future__ import annotations - -import socket -import threading -import urllib.parse -from http.server import BaseHTTPRequestHandler, HTTPServer -from typing import Any, Callable - -from nanobot.auth.codex.constants import SUCCESS_HTML - - -class _OAuthHandler(BaseHTTPRequestHandler): - """Local callback HTTP handler.""" - - server_version = "NanobotOAuth/1.0" - protocol_version = "HTTP/1.1" - - def do_GET(self) -> None: # noqa: N802 - try: - url = urllib.parse.urlparse(self.path) - if url.path != "/auth/callback": - self.send_response(404) - self.end_headers() - self.wfile.write(b"Not found") - return - - qs = urllib.parse.parse_qs(url.query) - code = qs.get("code", [None])[0] - state = qs.get("state", [None])[0] - - if state != self.server.expected_state: - self.send_response(400) - self.end_headers() - self.wfile.write(b"State mismatch") - return - - if not code: - self.send_response(400) - self.end_headers() - self.wfile.write(b"Missing code") - return - - self.server.code = code - try: - if getattr(self.server, "on_code", None): - self.server.on_code(code) - except Exception: - pass - body = SUCCESS_HTML.encode("utf-8") - self.send_response(200) - self.send_header("Content-Type", "text/html; charset=utf-8") - self.send_header("Content-Length", str(len(body))) - self.send_header("Connection", "close") - self.end_headers() - self.wfile.write(body) - try: - self.wfile.flush() - except Exception: - pass - self.close_connection = True - except Exception: - self.send_response(500) - self.end_headers() - self.wfile.write(b"Internal error") - - def log_message(self, format: str, *args: Any) -> None: # noqa: A003 - # Suppress default logs to avoid noisy output. - return - - -class _OAuthServer(HTTPServer): - """OAuth callback server with state.""" - - def __init__( - self, - server_address: tuple[str, int], - expected_state: str, - on_code: Callable[[str], None] | None = None, - ): - super().__init__(server_address, _OAuthHandler) - self.expected_state = expected_state - self.code: str | None = None - self.on_code = on_code - - -def _start_local_server( - state: str, - on_code: Callable[[str], None] | None = None, -) -> tuple[_OAuthServer | None, str | None]: - """Start a local OAuth callback server on the first available localhost address.""" - try: - addrinfos = socket.getaddrinfo("localhost", 1455, type=socket.SOCK_STREAM) - except OSError as exc: - return None, f"Failed to resolve localhost: {exc}" - - last_error: OSError | None = None - for family, _socktype, _proto, _canonname, sockaddr in addrinfos: - try: - # Support IPv4/IPv6 to avoid missing callbacks when localhost resolves to ::1. - class _AddrOAuthServer(_OAuthServer): - address_family = family - - server = _AddrOAuthServer(sockaddr, state, on_code=on_code) - thread = threading.Thread(target=server.serve_forever, daemon=True) - thread.start() - return server, None - except OSError as exc: - last_error = exc - continue - - if last_error: - return None, f"Local callback server failed to start: {last_error}" - return None, "Local callback server failed to start: unknown error" diff --git a/nanobot/auth/codex/storage.py b/nanobot/auth/codex/storage.py deleted file mode 100644 index 31e5e3d..0000000 --- a/nanobot/auth/codex/storage.py +++ /dev/null @@ -1,118 +0,0 @@ -"""Token storage helpers.""" - -from __future__ import annotations - -import json -import os -import time -from pathlib import Path - -from nanobot.auth.codex.constants import TOKEN_FILENAME -from nanobot.auth.codex.models import CodexToken -from nanobot.utils.helpers import ensure_dir, get_data_path - - -def _get_token_path() -> Path: - auth_dir = ensure_dir(get_data_path() / "auth") - return auth_dir / TOKEN_FILENAME - - -def _load_token_file() -> CodexToken | None: - path = _get_token_path() - if not path.exists(): - return None - try: - data = json.loads(path.read_text(encoding="utf-8")) - return CodexToken( - access=data["access"], - refresh=data["refresh"], - expires=int(data["expires"]), - account_id=data["account_id"], - ) - except Exception: - return None - - -def _save_token_file(token: CodexToken) -> None: - path = _get_token_path() - path.parent.mkdir(parents=True, exist_ok=True) - path.write_text( - json.dumps( - { - "access": token.access, - "refresh": token.refresh, - "expires": token.expires, - "account_id": token.account_id, - }, - ensure_ascii=True, - indent=2, - ), - encoding="utf-8", - ) - try: - os.chmod(path, 0o600) - except Exception: - # Ignore permission setting failures. - pass - - -def _try_import_codex_cli_token() -> CodexToken | None: - codex_path = Path.home() / ".codex" / "auth.json" - if not codex_path.exists(): - return None - try: - data = json.loads(codex_path.read_text(encoding="utf-8")) - tokens = data.get("tokens") or {} - access = tokens.get("access_token") - refresh = tokens.get("refresh_token") - account_id = tokens.get("account_id") - if not access or not refresh or not account_id: - return None - try: - mtime = codex_path.stat().st_mtime - expires = int(mtime * 1000 + 60 * 60 * 1000) - except Exception: - expires = int(time.time() * 1000 + 60 * 60 * 1000) - token = CodexToken( - access=str(access), - refresh=str(refresh), - expires=expires, - account_id=str(account_id), - ) - _save_token_file(token) - return token - except Exception: - return None - - -class _FileLock: - """Simple file lock to reduce concurrent refreshes.""" - - def __init__(self, path: Path): - self._path = path - self._fp = None - - def __enter__(self) -> "_FileLock": - self._path.parent.mkdir(parents=True, exist_ok=True) - self._fp = open(self._path, "a+") - try: - import fcntl - - fcntl.flock(self._fp.fileno(), fcntl.LOCK_EX) - except Exception: - # Non-POSIX or failed lock: continue without locking. - pass - return self - - def __exit__(self, exc_type, exc, tb) -> None: - try: - import fcntl - - fcntl.flock(self._fp.fileno(), fcntl.LOCK_UN) - except Exception: - pass - try: - if self._fp: - self._fp.close() - except Exception: - pass diff --git a/nanobot/cli/commands.py b/nanobot/cli/commands.py index 3be4e23..727c451 100644 --- a/nanobot/cli/commands.py +++ b/nanobot/cli/commands.py @@ -1,6 +1,7 @@ """CLI commands for nanobot.""" import asyncio +import sys from pathlib import Path import typer @@ -18,6 +19,12 @@ app = typer.Typer( console = Console() +def _safe_print(text: str) -> None: + encoding = sys.stdout.encoding or "utf-8" + safe_text = text.encode(encoding, errors="replace").decode(encoding, errors="replace") + console.print(safe_text) + + def version_callback(value: bool): if value: console.print(f"{__logo__} nanobot v{__version__}") @@ -82,7 +89,7 @@ def login( console.print(f"[red]Unsupported provider: {provider}[/red]") raise typer.Exit(1) - from nanobot.auth.codex import login_codex_oauth_interactive + from oauth_cli_kit import login_oauth_interactive as login_codex_oauth_interactive console.print("[green]Starting OpenAI Codex OAuth login...[/green]") login_codex_oauth_interactive( @@ -180,7 +187,7 @@ def gateway( from nanobot.bus.queue import MessageBus from nanobot.providers.litellm_provider import LiteLLMProvider from nanobot.providers.openai_codex_provider import OpenAICodexProvider - from nanobot.auth.codex import get_codex_token + from oauth_cli_kit import get_token as get_codex_token from nanobot.agent.loop import AgentLoop from nanobot.channels.manager import ChannelManager from nanobot.cron.service import CronService @@ -316,7 +323,7 @@ def agent( from nanobot.bus.queue import MessageBus from nanobot.providers.litellm_provider import LiteLLMProvider from nanobot.providers.openai_codex_provider import OpenAICodexProvider - from nanobot.auth.codex import get_codex_token + from oauth_cli_kit import get_token as get_codex_token from nanobot.agent.loop import AgentLoop config = load_config() @@ -361,7 +368,7 @@ def agent( # Single message mode async def run_once(): response = await agent_loop.process_direct(message, session_id) - console.print(f"\n{__logo__} {response}") + _safe_print(f"\n{__logo__} {response}") asyncio.run(run_once()) else: @@ -376,7 +383,7 @@ def agent( continue response = await agent_loop.process_direct(user_input, session_id) - console.print(f"\n{__logo__} {response}\n") + _safe_print(f"\n{__logo__} {response}\n") except KeyboardInterrupt: console.print("\nGoodbye!") break @@ -667,7 +674,7 @@ def cron_run( def status(): """Show nanobot status.""" from nanobot.config.loader import load_config, get_config_path - from nanobot.auth.codex import get_codex_token + from oauth_cli_kit import get_token as get_codex_token config_path = get_config_path() config = load_config() @@ -704,4 +711,3 @@ def status(): if __name__ == "__main__": app() - diff --git a/nanobot/providers/openai_codex_provider.py b/nanobot/providers/openai_codex_provider.py index a23becd..f92db09 100644 --- a/nanobot/providers/openai_codex_provider.py +++ b/nanobot/providers/openai_codex_provider.py @@ -9,7 +9,7 @@ from typing import Any, AsyncGenerator import httpx -from nanobot.auth.codex import get_codex_token +from oauth_cli_kit import get_token as get_codex_token from nanobot.providers.base import LLMProvider, LLMResponse, ToolCallRequest DEFAULT_CODEX_BASE_URL = "https://chatgpt.com/backend-api" diff --git a/pyproject.toml b/pyproject.toml index 0c59f66..a1931e5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,6 +24,7 @@ dependencies = [ "websockets>=12.0", "websocket-client>=1.6.0", "httpx>=0.25.0", + "oauth-cli-kit>=0.1.1", "loguru>=0.7.0", "readability-lxml>=0.8.0", "rich>=13.0.0", From c1dc8d3f554a4f299aec01d26f04cd91c89c68ec Mon Sep 17 00:00:00 2001 From: pinhua33 Date: Sun, 8 Feb 2026 16:33:46 +0800 Subject: [PATCH 07/60] fix: integrate OpenAI Codex provider with new registry system - Add OpenAI Codex ProviderSpec to registry.py - Add openai_codex config field to ProvidersConfig in schema.py - Mark Codex as OAuth-based (no API key required) - Set appropriate default_api_base for Codex API This integrates the Codex OAuth provider with the refactored provider registry system introduced in upstream commit 299d8b3. --- nanobot/config/schema.py | 1 + nanobot/providers/registry.py | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/nanobot/config/schema.py b/nanobot/config/schema.py index ea8f8ba..1707797 100644 --- a/nanobot/config/schema.py +++ b/nanobot/config/schema.py @@ -81,6 +81,7 @@ class ProvidersConfig(BaseModel): gemini: ProviderConfig = Field(default_factory=ProviderConfig) moonshot: ProviderConfig = Field(default_factory=ProviderConfig) aihubmix: ProviderConfig = Field(default_factory=ProviderConfig) # AiHubMix API gateway + openai_codex: ProviderConfig = Field(default_factory=ProviderConfig) # OpenAI Codex (OAuth) # AiHubMix API gateway class GatewayConfig(BaseModel): diff --git a/nanobot/providers/registry.py b/nanobot/providers/registry.py index aa4a76e..d7226e7 100644 --- a/nanobot/providers/registry.py +++ b/nanobot/providers/registry.py @@ -141,6 +141,24 @@ PROVIDERS: tuple[ProviderSpec, ...] = ( model_overrides=(), ), + # OpenAI Codex: uses OAuth, not API key. + ProviderSpec( + name="openai_codex", + keywords=("openai-codex", "codex"), + env_key="", # OAuth-based, no API key + display_name="OpenAI Codex", + litellm_prefix="", # Not routed through LiteLLM + skip_prefixes=(), + env_extras=(), + is_gateway=False, + is_local=False, + detect_by_key_prefix="", + detect_by_base_keyword="codex", + default_api_base="https://chatgpt.com/backend-api", + strip_model_prefix=False, + model_overrides=(), + ), + # DeepSeek: needs "deepseek/" prefix for LiteLLM routing. ProviderSpec( name="deepseek", From 08efe6ad3f1a1314765a037ac4c7d1a5757cd6eb Mon Sep 17 00:00:00 2001 From: pinhua33 Date: Sun, 8 Feb 2026 16:48:11 +0800 Subject: [PATCH 08/60] refactor: add OAuth support to provider registry system - Add is_oauth and oauth_provider fields to ProviderSpec - Update _make_provider() to use registry for OAuth provider detection - Update get_provider() to support OAuth providers (no API key required) - Mark OpenAI Codex as OAuth-based provider in registry This improves the provider registry architecture to support OAuth-based authentication flows, making it extensible for future OAuth providers. Benefits: - OAuth providers are now registry-driven (not hardcoded) - Extensible design: new OAuth providers only need registry entry - Backward compatible: existing API key providers unaffected - Clean separation: OAuth logic centralized in registry --- nanobot/cli/commands.py | 31 ++++++++++++++++++++++--------- nanobot/config/schema.py | 10 +++++++--- nanobot/providers/registry.py | 6 ++++++ 3 files changed, 35 insertions(+), 12 deletions(-) diff --git a/nanobot/cli/commands.py b/nanobot/cli/commands.py index 0732d48..855023a 100644 --- a/nanobot/cli/commands.py +++ b/nanobot/cli/commands.py @@ -173,20 +173,33 @@ This file stores important information that should persist across sessions. def _make_provider(config): - """Create LiteLLMProvider from config. Exits if no API key found.""" + """Create provider from config. Exits if no credentials found.""" from nanobot.providers.litellm_provider import LiteLLMProvider from nanobot.providers.openai_codex_provider import OpenAICodexProvider - from oauth_cli_kit import get_token as get_codex_token + from nanobot.providers.registry import PROVIDERS + from oauth_cli_kit import get_token as get_oauth_token - p = config.get_provider() model = config.agents.defaults.model - if model.startswith("openai-codex/"): - try: - _ = get_codex_token() - except Exception: - console.print("Please run: [cyan]nanobot login --provider openai-codex[/cyan]") + model_lower = model.lower() + + # Check for OAuth-based providers first (registry-driven) + for spec in PROVIDERS: + if spec.is_oauth and any(kw in model_lower for kw in spec.keywords): + # OAuth provider matched + try: + _ = get_oauth_token(spec.oauth_provider or spec.name) + except Exception: + console.print(f"Please run: [cyan]nanobot login --provider {spec.name}[/cyan]") + raise typer.Exit(1) + # Return appropriate OAuth provider class + if spec.name == "openai_codex": + return OpenAICodexProvider(default_model=model) + # Future OAuth providers can be added here + console.print(f"[red]Error: OAuth provider '{spec.name}' not fully implemented.[/red]") raise typer.Exit(1) - return OpenAICodexProvider(default_model=model) + + # Standard API key-based providers + p = config.get_provider() if not (p and p.api_key) and not model.startswith("bedrock/"): console.print("[red]Error: No API key configured.[/red]") console.print("Set one in ~/.nanobot/config.json under providers section") diff --git a/nanobot/config/schema.py b/nanobot/config/schema.py index 1707797..cde73f2 100644 --- a/nanobot/config/schema.py +++ b/nanobot/config/schema.py @@ -132,15 +132,19 @@ class Config(BaseSettings): model_lower = (model or self.agents.defaults.model).lower() # Match by keyword (order follows PROVIDERS registry) + # Note: OAuth providers don't require api_key, so we check is_oauth flag for spec in PROVIDERS: p = getattr(self.providers, spec.name, None) - if p and any(kw in model_lower for kw in spec.keywords) and p.api_key: - return p + if p and any(kw in model_lower for kw in spec.keywords): + # OAuth providers don't need api_key + if spec.is_oauth or p.api_key: + return p # Fallback: gateways first, then others (follows registry order) + # OAuth providers are also valid fallbacks for spec in PROVIDERS: p = getattr(self.providers, spec.name, None) - if p and p.api_key: + if p and (spec.is_oauth or p.api_key): return p return None diff --git a/nanobot/providers/registry.py b/nanobot/providers/registry.py index d7226e7..4ccf5da 100644 --- a/nanobot/providers/registry.py +++ b/nanobot/providers/registry.py @@ -51,6 +51,10 @@ class ProviderSpec: # per-model param overrides, e.g. (("kimi-k2.5", {"temperature": 1.0}),) model_overrides: tuple[tuple[str, dict[str, Any]], ...] = () + # OAuth-based providers (e.g., OpenAI Codex) don't use API keys + is_oauth: bool = False # if True, uses OAuth flow instead of API key + oauth_provider: str = "" # OAuth provider name for token retrieval + @property def label(self) -> str: return self.display_name or self.name.title() @@ -157,6 +161,8 @@ PROVIDERS: tuple[ProviderSpec, ...] = ( default_api_base="https://chatgpt.com/backend-api", strip_model_prefix=False, model_overrides=(), + is_oauth=True, # OAuth-based authentication + oauth_provider="openai-codex", # OAuth provider identifier ), # DeepSeek: needs "deepseek/" prefix for LiteLLM routing. From fc67d11da96d7f4e45df0cbe504116a27f900af2 Mon Sep 17 00:00:00 2001 From: pinhua33 Date: Mon, 9 Feb 2026 15:39:30 +0800 Subject: [PATCH 09/60] feat: add OAuth login command for OpenAI Codex --- nanobot/cli/commands.py | 859 +++++++++++++++++++++++++++++++++------- 1 file changed, 706 insertions(+), 153 deletions(-) diff --git a/nanobot/cli/commands.py b/nanobot/cli/commands.py index 40d2ae6..bbdf79c 100644 --- a/nanobot/cli/commands.py +++ b/nanobot/cli/commands.py @@ -4,9 +4,9 @@ import asyncio import atexit import os import signal -import sys from pathlib import Path import select +import sys import typer from rich.console import Console @@ -95,148 +95,382 @@ def _enable_line_editing() -> None: except Exception: pass + history_file = Path.home() / ".nanobot" / "history" / "cli_history" + history_file.parent.mkdir(parents=True, exist_ok=True) + _HISTORY_FILE = history_file + try: - import readline as _READLINE - import atexit - - # Detect libedit (macOS) vs GNU readline (Linux) - if hasattr(_READLINE, "__doc__") and _READLINE.__doc__ and "libedit" in _READLINE.__doc__: - _USING_LIBEDIT = True - - hist_file = Path.home() / ".nanobot_history" - _HISTORY_FILE = hist_file - try: - _READLINE.read_history_file(str(hist_file)) - except FileNotFoundError: - pass - - # Enable common readline settings - _READLINE.parse_and_bind("bind -v" if _USING_LIBEDIT else "set editing-mode vi") - _READLINE.parse_and_bind("set show-all-if-ambiguous on") - _READLINE.parse_and_bind("set colored-completion-prefix on") - - if not _HISTORY_HOOK_REGISTERED: - atexit.register(_save_history) - _HISTORY_HOOK_REGISTERED = True - except Exception: + import readline + except ImportError: return + _READLINE = readline + _USING_LIBEDIT = "libedit" in (readline.__doc__ or "").lower() + + try: + if _USING_LIBEDIT: + readline.parse_and_bind("bind ^I rl_complete") + else: + readline.parse_and_bind("tab: complete") + readline.parse_and_bind("set editing-mode emacs") + except Exception: + pass + + try: + readline.read_history_file(str(history_file)) + except Exception: + pass + + if not _HISTORY_HOOK_REGISTERED: + atexit.register(_save_history) + _HISTORY_HOOK_REGISTERED = True + + +def _prompt_text() -> str: + """Build a readline-friendly colored prompt.""" + if _READLINE is None: + return "You: " + # libedit on macOS does not honor GNU readline non-printing markers. + if _USING_LIBEDIT: + return "\033[1;34mYou:\033[0m " + return "\001\033[1;34m\002You:\001\033[0m\002 " + + +def _print_agent_response(response: str, render_markdown: bool) -> None: + """Render assistant response with consistent terminal styling.""" + content = response or "" + body = Markdown(content) if render_markdown else Text(content) + console.print() + console.print( + Panel( + body, + title=f"{__logo__} nanobot", + title_align="left", + border_style="cyan", + padding=(0, 1), + ) + ) + console.print() + + +def _is_exit_command(command: str) -> bool: + """Return True when input should end interactive chat.""" + return command.lower() in EXIT_COMMANDS + async def _read_interactive_input_async() -> str: - """Async wrapper around synchronous input() (runs in thread pool).""" - loop = asyncio.get_running_loop() - return await loop.run_in_executor(None, lambda: input(f"{__logo__} ")) - - -def _is_exit_command(text: str) -> bool: - return text.strip().lower() in EXIT_COMMANDS - - -# --------------------------------------------------------------------------- -# OAuth and Authentication helpers -# --------------------------------------------------------------------------- - -def _handle_oauth_login(provider: str) -> None: - """Handle OAuth login flow for supported providers.""" - from nanobot.providers.registry import get_oauth_handler - - oauth_handler = get_oauth_handler(provider) - if oauth_handler is None: - console.print(f"[red]OAuth is not supported for provider: {provider}[/red]") - console.print("[yellow]Supported OAuth providers: github-copilot[/yellow]") - raise typer.Exit(1) - + """Read user input with arrow keys and history (runs input() in a thread).""" try: - result = oauth_handler.authenticate() - if result.success: - console.print(f"[green]✓ {result.message}[/green]") - if result.token_path: - console.print(f"[dim]Token saved to: {result.token_path}[/dim]") - else: - console.print(f"[red]✗ {result.message}[/red]") - raise typer.Exit(1) - except Exception as e: - console.print(f"[red]OAuth authentication failed: {e}[/red]") - raise typer.Exit(1) + return await asyncio.to_thread(input, _prompt_text()) + except EOFError as exc: + raise KeyboardInterrupt from exc -# --------------------------------------------------------------------------- -# @agent decorator and public API helpers -# --------------------------------------------------------------------------- - -_agent_registry: dict[str, callable] = {} +def version_callback(value: bool): + if value: + console.print(f"{__logo__} nanobot v{__version__}") + raise typer.Exit() -def _get_agent(name: str | None = None) -> callable | None: - """Retrieve a registered agent function by name.""" - if name is None: - # Return the first registered agent if no name specified - return next(iter(_agent_registry.values())) if _agent_registry else None - return _agent_registry.get(name) +@app.callback() +def main( + version: bool = typer.Option( + None, "--version", "-v", callback=version_callback, is_eager=True + ), +): + """nanobot - Personal AI Assistant.""" + pass -def agent(name: str | None = None, model: str | None = None, prompt: str | None = None): - """Decorator to register an agent function. +# ============================================================================ +# Onboard / Setup +# ============================================================================ + + +@app.command() +def onboard(): + """Initialize nanobot configuration and workspace.""" + from nanobot.config.loader import get_config_path, save_config + from nanobot.config.schema import Config + from nanobot.utils.helpers import get_workspace_path - Args: - name: Optional name for the agent (defaults to function name) - model: Optional model override (e.g., "gpt-4o", "claude-3-opus") - prompt: Optional system prompt for the agent - """ - def decorator(func): - agent_name = name or func.__name__ - _agent_registry[agent_name] = func - func._agent_config = {"model": model, "prompt": prompt} - return func - return decorator + config_path = get_config_path() + + if config_path.exists(): + console.print(f"[yellow]Config already exists at {config_path}[/yellow]") + if not typer.confirm("Overwrite?"): + raise typer.Exit() + + # Create default config + config = Config() + save_config(config) + console.print(f"[green]✓[/green] Created config at {config_path}") + + # Create workspace + workspace = get_workspace_path() + console.print(f"[green]✓[/green] Created workspace at {workspace}") + + # Create default bootstrap files + _create_workspace_templates(workspace) + + console.print(f"\n{__logo__} nanobot is ready!") + console.print("\nNext steps:") + console.print(" 1. Add your API key to [cyan]~/.nanobot/config.json[/cyan]") + console.print(" Get one at: https://openrouter.ai/keys") + console.print(" 2. Chat: [cyan]nanobot agent -m \"Hello!\"[/cyan]") + console.print("\n[dim]Want Telegram/WhatsApp? See: https://github.com/HKUDS/nanobot#-chat-apps[/dim]") -# --------------------------------------------------------------------------- -# Built-in CLI commands -# --------------------------------------------------------------------------- -@app.command() -def login( - provider: str = typer.Argument(..., help="Provider to authenticate with (e.g., 'github-copilot')"), -): - """Authenticate with an OAuth provider.""" - _handle_oauth_login(provider) + +def _create_workspace_templates(workspace: Path): + """Create default workspace template files.""" + templates = { + "AGENTS.md": """# Agent Instructions + +You are a helpful AI assistant. Be concise, accurate, and friendly. + +## Guidelines + +- Always explain what you're doing before taking actions +- Ask for clarification when the request is ambiguous +- Use tools to help accomplish tasks +- Remember important information in your memory files +""", + "SOUL.md": """# Soul + +I am nanobot, a lightweight AI assistant. + +## Personality + +- Helpful and friendly +- Concise and to the point +- Curious and eager to learn + +## Values + +- Accuracy over speed +- User privacy and safety +- Transparency in actions +""", + "USER.md": """# User + +Information about the user goes here. + +## Preferences + +- Communication style: (casual/formal) +- Timezone: (your timezone) +- Language: (your preferred language) +""", + } + + for filename, content in templates.items(): + file_path = workspace / filename + if not file_path.exists(): + file_path.write_text(content) + console.print(f" [dim]Created {filename}[/dim]") + + # Create memory directory and MEMORY.md + memory_dir = workspace / "memory" + memory_dir.mkdir(exist_ok=True) + memory_file = memory_dir / "MEMORY.md" + if not memory_file.exists(): + memory_file.write_text("""# Long-term Memory + +This file stores important information that should persist across sessions. + +## User Information + +(Important facts about the user) + +## Preferences + +(User preferences learned over time) + +## Important Notes + +(Things to remember) +""") + console.print(" [dim]Created memory/MEMORY.md[/dim]") + + +def _make_provider(config): + """Create LiteLLMProvider from config. Exits if no API key found.""" + from nanobot.providers.litellm_provider import LiteLLMProvider + p = config.get_provider() + model = config.agents.defaults.model + if not (p and p.api_key) and not model.startswith("bedrock/"): + console.print("[red]Error: No API key configured.[/red]") + console.print("Set one in ~/.nanobot/config.json under providers section") + raise typer.Exit(1) + return LiteLLMProvider( + api_key=p.api_key if p else None, + api_base=config.get_api_base(), + default_model=model, + extra_headers=p.extra_headers if p else None, + provider_name=config.get_provider_name(), + ) + + +# ============================================================================ +# Gateway / Server +# ============================================================================ @app.command() -def version(): - """Show version information.""" - console.print(f"{__logo__} nanobot {__version__}") - - -@app.command(name="agent") -def run_agent( - name: str | None = typer.Argument(None, help="Name of the agent to run"), - message: str = typer.Option(None, "--message", "-m", help="Single message to send to the agent"), - model: str = typer.Option(None, "--model", help="Override the model for this run"), - markdown: bool = typer.Option(True, "--markdown/--no-markdown", help="Render response as markdown"), - session_id: str = typer.Option("cli", "--session", "-s", help="Session ID for this conversation"), +def gateway( + port: int = typer.Option(18790, "--port", "-p", help="Gateway port"), + verbose: bool = typer.Option(False, "--verbose", "-v", help="Verbose output"), ): - """Run an interactive AI agent session.""" - import asyncio + """Start the nanobot gateway.""" + from nanobot.config.loader import load_config, get_data_dir + from nanobot.bus.queue import MessageBus from nanobot.agent.loop import AgentLoop + from nanobot.channels.manager import ChannelManager + from nanobot.session.manager import SessionManager + from nanobot.cron.service import CronService + from nanobot.cron.types import CronJob + from nanobot.heartbeat.service import HeartbeatService - # Get the agent function - agent_func = _get_agent(name) - if agent_func is None: - if name: - console.print(f"[red]Agent '{name}' not found[/red]") - else: - console.print("[yellow]No agents registered. Use @agent decorator to register agents.[/yellow]") - raise typer.Exit(1) + if verbose: + import logging + logging.basicConfig(level=logging.DEBUG) - # Initialize agent loop - agent_config = getattr(agent_func, '_agent_config', {}) - agent_model = model or agent_config.get('model') - agent_prompt = agent_config.get('prompt') + console.print(f"{__logo__} Starting nanobot gateway on port {port}...") - agent_loop = AgentLoop(model=agent_model, system_prompt=agent_prompt) + config = load_config() + bus = MessageBus() + provider = _make_provider(config) + session_manager = SessionManager(config.workspace_path) + # Create cron service first (callback set after agent creation) + cron_store_path = get_data_dir() / "cron" / "jobs.json" + cron = CronService(cron_store_path) + + # Create agent with cron service + agent = AgentLoop( + bus=bus, + provider=provider, + workspace=config.workspace_path, + model=config.agents.defaults.model, + max_iterations=config.agents.defaults.max_tool_iterations, + brave_api_key=config.tools.web.search.api_key or None, + exec_config=config.tools.exec, + cron_service=cron, + restrict_to_workspace=config.tools.restrict_to_workspace, + session_manager=session_manager, + ) + + # Set cron callback (needs agent) + async def on_cron_job(job: CronJob) -> str | None: + """Execute a cron job through the agent.""" + response = await agent.process_direct( + job.payload.message, + session_key=f"cron:{job.id}", + channel=job.payload.channel or "cli", + chat_id=job.payload.to or "direct", + ) + if job.payload.deliver and job.payload.to: + from nanobot.bus.events import OutboundMessage + await bus.publish_outbound(OutboundMessage( + channel=job.payload.channel or "cli", + chat_id=job.payload.to, + content=response or "" + )) + return response + cron.on_job = on_cron_job + + # Create heartbeat service + async def on_heartbeat(prompt: str) -> str: + """Execute heartbeat through the agent.""" + return await agent.process_direct(prompt, session_key="heartbeat") + + heartbeat = HeartbeatService( + workspace=config.workspace_path, + on_heartbeat=on_heartbeat, + interval_s=30 * 60, # 30 minutes + enabled=True + ) + + # Create channel manager + channels = ChannelManager(config, bus, session_manager=session_manager) + + if channels.enabled_channels: + console.print(f"[green]✓[/green] Channels enabled: {', '.join(channels.enabled_channels)}") + else: + console.print("[yellow]Warning: No channels enabled[/yellow]") + + cron_status = cron.status() + if cron_status["jobs"] > 0: + console.print(f"[green]✓[/green] Cron: {cron_status['jobs']} scheduled jobs") + + console.print(f"[green]✓[/green] Heartbeat: every 30m") + + async def run(): + try: + await cron.start() + await heartbeat.start() + await asyncio.gather( + agent.run(), + channels.start_all(), + ) + except KeyboardInterrupt: + console.print("\nShutting down...") + heartbeat.stop() + cron.stop() + agent.stop() + await channels.stop_all() + + asyncio.run(run()) + + + + +# ============================================================================ +# Agent Commands +# ============================================================================ + + +@app.command() +def agent( + message: str = typer.Option(None, "--message", "-m", help="Message to send to the agent"), + session_id: str = typer.Option("cli:default", "--session", "-s", help="Session ID"), + markdown: bool = typer.Option(True, "--markdown/--no-markdown", help="Render assistant output as Markdown"), + logs: bool = typer.Option(False, "--logs/--no-logs", help="Show nanobot runtime logs during chat"), +): + """Interact with the agent directly.""" + from nanobot.config.loader import load_config + from nanobot.bus.queue import MessageBus + from nanobot.agent.loop import AgentLoop + from loguru import logger + + config = load_config() + + bus = MessageBus() + provider = _make_provider(config) + + if logs: + logger.enable("nanobot") + else: + logger.disable("nanobot") + + agent_loop = AgentLoop( + bus=bus, + provider=provider, + workspace=config.workspace_path, + brave_api_key=config.tools.web.search.api_key or None, + exec_config=config.tools.exec, + restrict_to_workspace=config.tools.restrict_to_workspace, + ) + + # Show spinner when logs are off (no output to miss); skip when logs are on + def _thinking_ctx(): + if logs: + from contextlib import nullcontext + return nullcontext() + return console.status("[dim]nanobot is thinking...[/dim]", spinner="dots") + if message: # Single message mode async def run_once(): @@ -283,55 +517,374 @@ def run_agent( _restore_terminal() console.print("\nGoodbye!") break + except EOFError: + _save_history() + _restore_terminal() + console.print("\nGoodbye!") + break asyncio.run(run_interactive()) -def _thinking_ctx(): - """Context manager for showing thinking indicator.""" - from rich.live import Live - from rich.spinner import Spinner +# ============================================================================ +# Channel Commands +# ============================================================================ + + +channels_app = typer.Typer(help="Manage channels") +app.add_typer(channels_app, name="channels") + + +@channels_app.command("status") +def channels_status(): + """Show channel status.""" + from nanobot.config.loader import load_config + + config = load_config() + + table = Table(title="Channel Status") + table.add_column("Channel", style="cyan") + table.add_column("Enabled", style="green") + table.add_column("Configuration", style="yellow") + + # WhatsApp + wa = config.channels.whatsapp + table.add_row( + "WhatsApp", + "✓" if wa.enabled else "✗", + wa.bridge_url + ) + + dc = config.channels.discord + table.add_row( + "Discord", + "✓" if dc.enabled else "✗", + dc.gateway_url + ) - class ThinkingSpinner: - def __enter__(self): - self.live = Live(Spinner("dots", text="Thinking..."), console=console, refresh_per_second=10) - self.live.start() - return self + # Telegram + tg = config.channels.telegram + tg_config = f"token: {tg.token[:10]}..." if tg.token else "[dim]not configured[/dim]" + table.add_row( + "Telegram", + "✓" if tg.enabled else "✗", + tg_config + ) + + console.print(table) + + +def _get_bridge_dir() -> Path: + """Get the bridge directory, setting it up if needed.""" + import shutil + import subprocess + + # User's bridge location + user_bridge = Path.home() / ".nanobot" / "bridge" + + # Check if already built + if (user_bridge / "dist" / "index.js").exists(): + return user_bridge + + # Check for npm + if not shutil.which("npm"): + console.print("[red]npm not found. Please install Node.js >= 18.[/red]") + raise typer.Exit(1) + + # Find source bridge: first check package data, then source dir + pkg_bridge = Path(__file__).parent.parent / "bridge" # nanobot/bridge (installed) + src_bridge = Path(__file__).parent.parent.parent / "bridge" # repo root/bridge (dev) + + source = None + if (pkg_bridge / "package.json").exists(): + source = pkg_bridge + elif (src_bridge / "package.json").exists(): + source = src_bridge + + if not source: + console.print("[red]Bridge source not found.[/red]") + console.print("Try reinstalling: pip install --force-reinstall nanobot") + raise typer.Exit(1) + + console.print(f"{__logo__} Setting up bridge...") + + # Copy to user directory + user_bridge.parent.mkdir(parents=True, exist_ok=True) + if user_bridge.exists(): + shutil.rmtree(user_bridge) + shutil.copytree(source, user_bridge, ignore=shutil.ignore_patterns("node_modules", "dist")) + + # Install and build + try: + console.print(" Installing dependencies...") + subprocess.run(["npm", "install"], cwd=user_bridge, check=True, capture_output=True) - def __exit__(self, exc_type, exc_val, exc_tb): - self.live.stop() - return False + console.print(" Building...") + subprocess.run(["npm", "run", "build"], cwd=user_bridge, check=True, capture_output=True) + + console.print("[green]✓[/green] Bridge ready\n") + except subprocess.CalledProcessError as e: + console.print(f"[red]Build failed: {e}[/red]") + if e.stderr: + console.print(f"[dim]{e.stderr.decode()[:500]}[/dim]") + raise typer.Exit(1) - return ThinkingSpinner() + return user_bridge -def _print_agent_response(response: str, render_markdown: bool = True): - """Print agent response with optional markdown rendering.""" - if render_markdown: - console.print(Markdown(response)) +@channels_app.command("login") +def channels_login(): + """Link device via QR code.""" + import subprocess + + bridge_dir = _get_bridge_dir() + + console.print(f"{__logo__} Starting bridge...") + console.print("Scan the QR code to connect.\n") + + try: + subprocess.run(["npm", "start"], cwd=bridge_dir, check=True) + except subprocess.CalledProcessError as e: + console.print(f"[red]Bridge failed: {e}[/red]") + except FileNotFoundError: + console.print("[red]npm not found. Please install Node.js.[/red]") + + +# ============================================================================ +# Cron Commands +# ============================================================================ + +cron_app = typer.Typer(help="Manage scheduled tasks") +app.add_typer(cron_app, name="cron") + + +@cron_app.command("list") +def cron_list( + all: bool = typer.Option(False, "--all", "-a", help="Include disabled jobs"), +): + """List scheduled jobs.""" + from nanobot.config.loader import get_data_dir + from nanobot.cron.service import CronService + + store_path = get_data_dir() / "cron" / "jobs.json" + service = CronService(store_path) + + jobs = service.list_jobs(include_disabled=all) + + if not jobs: + console.print("No scheduled jobs.") + return + + table = Table(title="Scheduled Jobs") + table.add_column("ID", style="cyan") + table.add_column("Name") + table.add_column("Schedule") + table.add_column("Status") + table.add_column("Next Run") + + import time + for job in jobs: + # Format schedule + if job.schedule.kind == "every": + sched = f"every {(job.schedule.every_ms or 0) // 1000}s" + elif job.schedule.kind == "cron": + sched = job.schedule.expr or "" + else: + sched = "one-time" + + # Format next run + next_run = "" + if job.state.next_run_at_ms: + next_time = time.strftime("%Y-%m-%d %H:%M", time.localtime(job.state.next_run_at_ms / 1000)) + next_run = next_time + + status = "[green]enabled[/green]" if job.enabled else "[dim]disabled[/dim]" + + table.add_row(job.id, job.name, sched, status, next_run) + + console.print(table) + + +@cron_app.command("add") +def cron_add( + name: str = typer.Option(..., "--name", "-n", help="Job name"), + message: str = typer.Option(..., "--message", "-m", help="Message for agent"), + every: int = typer.Option(None, "--every", "-e", help="Run every N seconds"), + cron_expr: str = typer.Option(None, "--cron", "-c", help="Cron expression (e.g. '0 9 * * *')"), + at: str = typer.Option(None, "--at", help="Run once at time (ISO format)"), + deliver: bool = typer.Option(False, "--deliver", "-d", help="Deliver response to channel"), + to: str = typer.Option(None, "--to", help="Recipient for delivery"), + channel: str = typer.Option(None, "--channel", help="Channel for delivery (e.g. 'telegram', 'whatsapp')"), +): + """Add a scheduled job.""" + from nanobot.config.loader import get_data_dir + from nanobot.cron.service import CronService + from nanobot.cron.types import CronSchedule + + # Determine schedule type + if every: + schedule = CronSchedule(kind="every", every_ms=every * 1000) + elif cron_expr: + schedule = CronSchedule(kind="cron", expr=cron_expr) + elif at: + import datetime + dt = datetime.datetime.fromisoformat(at) + schedule = CronSchedule(kind="at", at_ms=int(dt.timestamp() * 1000)) else: - console.print(response) - console.print() + console.print("[red]Error: Must specify --every, --cron, or --at[/red]") + raise typer.Exit(1) + + store_path = get_data_dir() / "cron" / "jobs.json" + service = CronService(store_path) + + job = service.add_job( + name=name, + schedule=schedule, + message=message, + deliver=deliver, + to=to, + channel=channel, + ) + + console.print(f"[green]✓[/green] Added job '{job.name}' ({job.id})") + + +@cron_app.command("remove") +def cron_remove( + job_id: str = typer.Argument(..., help="Job ID to remove"), +): + """Remove a scheduled job.""" + from nanobot.config.loader import get_data_dir + from nanobot.cron.service import CronService + + store_path = get_data_dir() / "cron" / "jobs.json" + service = CronService(store_path) + + if service.remove_job(job_id): + console.print(f"[green]✓[/green] Removed job {job_id}") + else: + console.print(f"[red]Job {job_id} not found[/red]") + + +@cron_app.command("enable") +def cron_enable( + job_id: str = typer.Argument(..., help="Job ID"), + disable: bool = typer.Option(False, "--disable", help="Disable instead of enable"), +): + """Enable or disable a job.""" + from nanobot.config.loader import get_data_dir + from nanobot.cron.service import CronService + + store_path = get_data_dir() / "cron" / "jobs.json" + service = CronService(store_path) + + job = service.enable_job(job_id, enabled=not disable) + if job: + status = "disabled" if disable else "enabled" + console.print(f"[green]✓[/green] Job '{job.name}' {status}") + else: + console.print(f"[red]Job {job_id} not found[/red]") + + +@cron_app.command("run") +def cron_run( + job_id: str = typer.Argument(..., help="Job ID to run"), + force: bool = typer.Option(False, "--force", "-f", help="Run even if disabled"), +): + """Manually run a job.""" + from nanobot.config.loader import get_data_dir + from nanobot.cron.service import CronService + + store_path = get_data_dir() / "cron" / "jobs.json" + service = CronService(store_path) + + async def run(): + return await service.run_job(job_id, force=force) + + if asyncio.run(run()): + console.print(f"[green]✓[/green] Job executed") + else: + console.print(f"[red]Failed to run job {job_id}[/red]") + + +# ============================================================================ +# Status Commands +# ============================================================================ @app.command() -def setup(): - """Interactive setup wizard for nanobot.""" - console.print(Panel.fit( - f"{__logo__} Welcome to nanobot setup!\n\n" - "This wizard will help you configure nanobot.", - title="Setup", - border_style="green" - )) +def status(): + """Show nanobot status.""" + from nanobot.config.loader import load_config, get_config_path + + config_path = get_config_path() + config = load_config() + workspace = config.workspace_path + + console.print(f"{__logo__} nanobot Status\n") + + console.print(f"Config: {config_path} {'[green]✓[/green]' if config_path.exists() else '[red]✗[/red]'}") + console.print(f"Workspace: {workspace} {'[green]✓[/green]' if workspace.exists() else '[red]✗[/red]'}") + + if config_path.exists(): + from nanobot.providers.registry import PROVIDERS + + console.print(f"Model: {config.agents.defaults.model}") + + # Check API keys from registry + for spec in PROVIDERS: + p = getattr(config.providers, spec.name, None) + if p is None: + continue + if spec.is_local: + # Local deployments show api_base instead of api_key + if p.api_base: + console.print(f"{spec.label}: [green]✓ {p.api_base}[/green]") + else: + console.print(f"{spec.label}: [dim]not set[/dim]") + else: + has_key = bool(p.api_key) + console.print(f"{spec.label}: {'[green]✓[/green]' if has_key else '[dim]not set[/dim]'}") + + +# ============================================================================ +# OAuth Login +# ============================================================================ + + +@app.command() +def login( + provider: str = typer.Argument(..., help="OAuth provider to authenticate with (e.g., 'openai-codex')"), +): + """Authenticate with an OAuth provider.""" + console.print(f"{__logo__} OAuth Login - {provider}\n") - # TODO: Implement setup wizard - console.print("[yellow]Setup wizard coming soon![/yellow]") - - -def main(): - """Main entry point for the CLI.""" - app() + if provider == "openai-codex": + try: + from oauth_cli_kit import get_token as get_codex_token + + console.print("[cyan]Starting OpenAI Codex authentication...[/cyan]") + console.print("A browser window will open for you to authenticate.\n") + + token = get_codex_token() + + if token and token.access: + console.print(f"[green]✓ Successfully authenticated with OpenAI Codex![/green]") + console.print(f"[dim]Account ID: {token.account_id}[/dim]") + else: + console.print("[red]✗ Authentication failed[/red]") + raise typer.Exit(1) + except ImportError: + console.print("[red]oauth_cli_kit not installed. Run: pip install oauth-cli-kit[/red]") + raise typer.Exit(1) + except Exception as e: + console.print(f"[red]Authentication error: {e}[/red]") + raise typer.Exit(1) + else: + console.print(f"[red]Unknown OAuth provider: {provider}[/red]") + console.print("[yellow]Supported providers: openai-codex[/yellow]") + raise typer.Exit(1) if __name__ == "__main__": - main() + app() From 51f97efcb89fab2b3288883df0c5284a3f3ac171 Mon Sep 17 00:00:00 2001 From: pinhua33 Date: Mon, 9 Feb 2026 16:04:04 +0800 Subject: [PATCH 10/60] refactor: simplify Codex URL handling by removing unnecessary function --- nanobot/providers/openai_codex_provider.py | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/nanobot/providers/openai_codex_provider.py b/nanobot/providers/openai_codex_provider.py index f92db09..9c98db5 100644 --- a/nanobot/providers/openai_codex_provider.py +++ b/nanobot/providers/openai_codex_provider.py @@ -12,7 +12,7 @@ import httpx from oauth_cli_kit import get_token as get_codex_token from nanobot.providers.base import LLMProvider, LLMResponse, ToolCallRequest -DEFAULT_CODEX_BASE_URL = "https://chatgpt.com/backend-api" +DEFAULT_CODEX_URL = "https://chatgpt.com/backend-api/codex/responses" DEFAULT_ORIGINATOR = "nanobot" @@ -53,7 +53,7 @@ class OpenAICodexProvider(LLMProvider): if tools: body["tools"] = _convert_tools(tools) - url = _resolve_codex_url(DEFAULT_CODEX_BASE_URL) + url = DEFAULT_CODEX_URL try: try: @@ -84,15 +84,6 @@ def _strip_model_prefix(model: str) -> str: return model -def _resolve_codex_url(base_url: str) -> str: - raw = base_url.rstrip("/") - if raw.endswith("/codex/responses"): - return raw - if raw.endswith("/codex"): - return f"{raw}/responses" - return f"{raw}/codex/responses" - - def _build_headers(account_id: str, token: str) -> dict[str, str]: return { "Authorization": f"Bearer {token}", From cb5964c20149b089f11913b9d33eb8dbe62878ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20S=C3=A1nchez=20Vall=C3=A9s?= Date: Thu, 12 Feb 2026 10:01:30 +0100 Subject: [PATCH 11/60] feat(tools): add mcp support --- README.md | 2 +- nanobot/agent/context.py | 6 ++- nanobot/agent/loop.py | 30 +++++++++++++ nanobot/agent/subagent.py | 15 +++++-- nanobot/agent/tools/cron.py | 19 +++++++-- nanobot/agent/tools/mcp.py | 82 ++++++++++++++++++++++++++++++++++++ nanobot/channels/dingtalk.py | 11 ++++- nanobot/channels/feishu.py | 13 +++--- nanobot/channels/qq.py | 15 ++++--- nanobot/channels/telegram.py | 11 ++++- nanobot/cli/commands.py | 3 ++ nanobot/config/schema.py | 18 ++++++-- nanobot/skills/cron/SKILL.md | 9 +++- pyproject.toml | 1 + 14 files changed, 205 insertions(+), 30 deletions(-) create mode 100644 nanobot/agent/tools/mcp.py diff --git a/README.md b/README.md index fed25c8..ea606de 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ ⚡️ Delivers core agent functionality in just **~4,000** lines of code — **99% smaller** than Clawdbot's 430k+ lines. -📏 Real-time line count: **3,510 lines** (run `bash core_agent_lines.sh` to verify anytime) +📏 Real-time line count: **3,578 lines** (run `bash core_agent_lines.sh` to verify anytime) ## 📢 News diff --git a/nanobot/agent/context.py b/nanobot/agent/context.py index d807854..b9c0790 100644 --- a/nanobot/agent/context.py +++ b/nanobot/agent/context.py @@ -73,7 +73,9 @@ Skills with available="false" need dependencies installed first - you can try in def _get_identity(self) -> str: """Get the core identity section.""" from datetime import datetime + import time as _time now = datetime.now().strftime("%Y-%m-%d %H:%M (%A)") + tz = _time.strftime("%Z") or "UTC" workspace_path = str(self.workspace.expanduser().resolve()) system = platform.system() runtime = f"{'macOS' if system == 'Darwin' else system} {platform.machine()}, Python {platform.python_version()}" @@ -88,7 +90,7 @@ You are nanobot, a helpful AI assistant. You have access to tools that allow you - Spawn subagents for complex background tasks ## Current Time -{now} +{now} ({tz}) ## Runtime {runtime} @@ -103,7 +105,7 @@ IMPORTANT: When responding to direct questions or conversations, reply directly Only use the 'message' tool when you need to send a message to a specific chat channel (like WhatsApp). For normal conversation, just respond with text - do not call the message tool. -Always be helpful, accurate, and concise. When using tools, explain what you're doing. +Always be helpful, accurate, and concise. When using tools, think step by step: what you know, what you need, and why you chose this tool. When remembering something, write to {workspace_path}/memory/MEMORY.md""" def _load_bootstrap_files(self) -> str: diff --git a/nanobot/agent/loop.py b/nanobot/agent/loop.py index b764c3d..a3ab678 100644 --- a/nanobot/agent/loop.py +++ b/nanobot/agent/loop.py @@ -1,6 +1,7 @@ """Agent loop: the core processing engine.""" import asyncio +from contextlib import AsyncExitStack import json from pathlib import Path from typing import Any @@ -46,6 +47,7 @@ class AgentLoop: cron_service: "CronService | None" = None, restrict_to_workspace: bool = False, session_manager: SessionManager | None = None, + mcp_servers: dict | None = None, ): from nanobot.config.schema import ExecToolConfig from nanobot.cron.service import CronService @@ -73,6 +75,9 @@ class AgentLoop: ) self._running = False + self._mcp_servers = mcp_servers or {} + self._mcp_stack: AsyncExitStack | None = None + self._mcp_connected = False self._register_default_tools() def _register_default_tools(self) -> None: @@ -107,9 +112,20 @@ class AgentLoop: if self.cron_service: self.tools.register(CronTool(self.cron_service)) + async def _connect_mcp(self) -> None: + """Connect to configured MCP servers (one-time, lazy).""" + if self._mcp_connected or not self._mcp_servers: + return + self._mcp_connected = True + from nanobot.agent.tools.mcp import connect_mcp_servers + self._mcp_stack = AsyncExitStack() + await self._mcp_stack.__aenter__() + await connect_mcp_servers(self._mcp_servers, self.tools, self._mcp_stack) + async def run(self) -> None: """Run the agent loop, processing messages from the bus.""" self._running = True + await self._connect_mcp() logger.info("Agent loop started") while self._running: @@ -136,6 +152,15 @@ class AgentLoop: except asyncio.TimeoutError: continue + async def _close_mcp(self) -> None: + """Close MCP connections.""" + if self._mcp_stack: + try: + await self._mcp_stack.aclose() + except (RuntimeError, BaseExceptionGroup): + pass # MCP SDK cancel scope cleanup is noisy but harmless + self._mcp_stack = None + def stop(self) -> None: """Stop the agent loop.""" self._running = False @@ -225,6 +250,8 @@ class AgentLoop: messages = self.context.add_tool_result( messages, tool_call.id, tool_call.name, result ) + # Interleaved CoT: reflect before next action + messages.append({"role": "user", "content": "Reflect on the results and decide next steps."}) else: # No tool calls, we're done final_content = response.content @@ -330,6 +357,8 @@ class AgentLoop: messages = self.context.add_tool_result( messages, tool_call.id, tool_call.name, result ) + # Interleaved CoT: reflect before next action + messages.append({"role": "user", "content": "Reflect on the results and decide next steps."}) else: final_content = response.content break @@ -367,6 +396,7 @@ class AgentLoop: Returns: The agent's response. """ + await self._connect_mcp() msg = InboundMessage( channel=channel, sender_id="user", diff --git a/nanobot/agent/subagent.py b/nanobot/agent/subagent.py index 6113efb..9e0cd7c 100644 --- a/nanobot/agent/subagent.py +++ b/nanobot/agent/subagent.py @@ -12,7 +12,7 @@ from nanobot.bus.events import InboundMessage from nanobot.bus.queue import MessageBus from nanobot.providers.base import LLMProvider from nanobot.agent.tools.registry import ToolRegistry -from nanobot.agent.tools.filesystem import ReadFileTool, WriteFileTool, ListDirTool +from nanobot.agent.tools.filesystem import ReadFileTool, WriteFileTool, EditFileTool, ListDirTool from nanobot.agent.tools.shell import ExecTool from nanobot.agent.tools.web import WebSearchTool, WebFetchTool @@ -101,6 +101,7 @@ class SubagentManager: allowed_dir = self.workspace if self.restrict_to_workspace else None tools.register(ReadFileTool(allowed_dir=allowed_dir)) tools.register(WriteFileTool(allowed_dir=allowed_dir)) + tools.register(EditFileTool(allowed_dir=allowed_dir)) tools.register(ListDirTool(allowed_dir=allowed_dir)) tools.register(ExecTool( working_dir=str(self.workspace), @@ -210,12 +211,17 @@ Summarize this naturally for the user. Keep it brief (1-2 sentences). Do not men def _build_subagent_prompt(self, task: str) -> str: """Build a focused system prompt for the subagent.""" + from datetime import datetime + import time as _time + now = datetime.now().strftime("%Y-%m-%d %H:%M (%A)") + tz = _time.strftime("%Z") or "UTC" + return f"""# Subagent -You are a subagent spawned by the main agent to complete a specific task. +## Current Time +{now} ({tz}) -## Your Task -{task} +You are a subagent spawned by the main agent to complete a specific task. ## Rules 1. Stay focused - complete only the assigned task, nothing else @@ -236,6 +242,7 @@ You are a subagent spawned by the main agent to complete a specific task. ## Workspace Your workspace is at: {self.workspace} +Skills are available at: {self.workspace}/skills/ (read SKILL.md files as needed) When you have completed the task, provide a clear summary of your findings or actions.""" diff --git a/nanobot/agent/tools/cron.py b/nanobot/agent/tools/cron.py index ec0d2cd..9f1ecdb 100644 --- a/nanobot/agent/tools/cron.py +++ b/nanobot/agent/tools/cron.py @@ -50,6 +50,10 @@ class CronTool(Tool): "type": "string", "description": "Cron expression like '0 9 * * *' (for scheduled tasks)" }, + "at": { + "type": "string", + "description": "ISO datetime for one-time execution (e.g. '2026-02-12T10:30:00')" + }, "job_id": { "type": "string", "description": "Job ID (for remove)" @@ -64,30 +68,38 @@ class CronTool(Tool): message: str = "", every_seconds: int | None = None, cron_expr: str | None = None, + at: str | None = None, job_id: str | None = None, **kwargs: Any ) -> str: if action == "add": - return self._add_job(message, every_seconds, cron_expr) + return self._add_job(message, every_seconds, cron_expr, at) elif action == "list": return self._list_jobs() elif action == "remove": return self._remove_job(job_id) return f"Unknown action: {action}" - def _add_job(self, message: str, every_seconds: int | None, cron_expr: str | None) -> str: + def _add_job(self, message: str, every_seconds: int | None, cron_expr: str | None, at: str | None) -> str: if not message: return "Error: message is required for add" if not self._channel or not self._chat_id: return "Error: no session context (channel/chat_id)" # Build schedule + delete_after = False if every_seconds: schedule = CronSchedule(kind="every", every_ms=every_seconds * 1000) elif cron_expr: schedule = CronSchedule(kind="cron", expr=cron_expr) + elif at: + from datetime import datetime + dt = datetime.fromisoformat(at) + at_ms = int(dt.timestamp() * 1000) + schedule = CronSchedule(kind="at", at_ms=at_ms) + delete_after = True else: - return "Error: either every_seconds or cron_expr is required" + return "Error: either every_seconds, cron_expr, or at is required" job = self._cron.add_job( name=message[:30], @@ -96,6 +108,7 @@ class CronTool(Tool): deliver=True, channel=self._channel, to=self._chat_id, + delete_after_run=delete_after, ) return f"Created job '{job.name}' (id: {job.id})" diff --git a/nanobot/agent/tools/mcp.py b/nanobot/agent/tools/mcp.py new file mode 100644 index 0000000..bcef4aa --- /dev/null +++ b/nanobot/agent/tools/mcp.py @@ -0,0 +1,82 @@ +"""MCP client: connects to MCP servers and wraps their tools as native nanobot tools.""" + +from contextlib import AsyncExitStack +from typing import Any + +from loguru import logger + +from nanobot.agent.tools.base import Tool +from nanobot.agent.tools.registry import ToolRegistry + + +class MCPToolWrapper(Tool): + """Wraps a single MCP server tool as a nanobot Tool.""" + + def __init__(self, session, server_name: str, tool_def): + self._session = session + self._server = server_name + self._name = f"mcp_{server_name}_{tool_def.name}" + self._description = tool_def.description or tool_def.name + self._parameters = tool_def.inputSchema or {"type": "object", "properties": {}} + + @property + def name(self) -> str: + return self._name + + @property + def description(self) -> str: + return self._description + + @property + def parameters(self) -> dict[str, Any]: + return self._parameters + + async def execute(self, **kwargs: Any) -> str: + from mcp import types + result = await self._session.call_tool( + self._name.removeprefix(f"mcp_{self._server}_"), arguments=kwargs + ) + parts = [] + for block in result.content: + if isinstance(block, types.TextContent): + parts.append(block.text) + else: + parts.append(str(block)) + return "\n".join(parts) or "(no output)" + + +async def connect_mcp_servers( + mcp_servers: dict, registry: ToolRegistry, stack: AsyncExitStack +) -> None: + """Connect to configured MCP servers and register their tools.""" + from mcp import ClientSession, StdioServerParameters + from mcp.client.stdio import stdio_client + + for name, cfg in mcp_servers.items(): + try: + if cfg.command: + params = StdioServerParameters( + command=cfg.command, args=cfg.args, env=cfg.env or None + ) + read, write = await stack.enter_async_context(stdio_client(params)) + elif cfg.url: + from mcp.client.streamable_http import streamable_http_client + read, write, _ = await stack.enter_async_context( + streamable_http_client(cfg.url) + ) + else: + logger.warning(f"MCP server '{name}': no command or url configured, skipping") + continue + + session = await stack.enter_async_context(ClientSession(read, write)) + await session.initialize() + + tools = await session.list_tools() + for tool_def in tools.tools: + wrapper = MCPToolWrapper(session, name, tool_def) + registry.register(wrapper) + logger.debug(f"MCP: registered tool '{wrapper.name}' from server '{name}'") + + logger.info(f"MCP server '{name}': connected, {len(tools.tools)} tools registered") + except Exception as e: + logger.error(f"MCP server '{name}': failed to connect: {e}") diff --git a/nanobot/channels/dingtalk.py b/nanobot/channels/dingtalk.py index 72d3afd..4a8cdd9 100644 --- a/nanobot/channels/dingtalk.py +++ b/nanobot/channels/dingtalk.py @@ -137,8 +137,15 @@ class DingTalkChannel(BaseChannel): logger.info("DingTalk bot started with Stream Mode") - # client.start() is an async infinite loop handling the websocket connection - await self._client.start() + # Reconnect loop: restart stream if SDK exits or crashes + while self._running: + try: + await self._client.start() + except Exception as e: + logger.warning(f"DingTalk stream error: {e}") + if self._running: + logger.info("Reconnecting DingTalk stream in 5 seconds...") + await asyncio.sleep(5) except Exception as e: logger.exception(f"Failed to start DingTalk channel: {e}") diff --git a/nanobot/channels/feishu.py b/nanobot/channels/feishu.py index 1c176a2..23d1415 100644 --- a/nanobot/channels/feishu.py +++ b/nanobot/channels/feishu.py @@ -98,12 +98,15 @@ class FeishuChannel(BaseChannel): log_level=lark.LogLevel.INFO ) - # Start WebSocket client in a separate thread + # Start WebSocket client in a separate thread with reconnect loop def run_ws(): - try: - self._ws_client.start() - except Exception as e: - logger.error(f"Feishu WebSocket error: {e}") + while self._running: + try: + self._ws_client.start() + except Exception as e: + logger.warning(f"Feishu WebSocket error: {e}") + if self._running: + import time; time.sleep(5) self._ws_thread = threading.Thread(target=run_ws, daemon=True) self._ws_thread.start() diff --git a/nanobot/channels/qq.py b/nanobot/channels/qq.py index 5964d30..0e8fe66 100644 --- a/nanobot/channels/qq.py +++ b/nanobot/channels/qq.py @@ -75,12 +75,15 @@ class QQChannel(BaseChannel): logger.info("QQ bot started (C2C private message)") async def _run_bot(self) -> None: - """Run the bot connection.""" - try: - await self._client.start(appid=self.config.app_id, secret=self.config.secret) - except Exception as e: - logger.error(f"QQ auth failed, check AppID/Secret at q.qq.com: {e}") - self._running = False + """Run the bot connection with auto-reconnect.""" + while self._running: + try: + await self._client.start(appid=self.config.app_id, secret=self.config.secret) + except Exception as e: + logger.warning(f"QQ bot error: {e}") + if self._running: + logger.info("Reconnecting QQ bot in 5 seconds...") + await asyncio.sleep(5) async def stop(self) -> None: """Stop the QQ bot.""" diff --git a/nanobot/channels/telegram.py b/nanobot/channels/telegram.py index ff46c86..1abd600 100644 --- a/nanobot/channels/telegram.py +++ b/nanobot/channels/telegram.py @@ -9,6 +9,7 @@ from typing import TYPE_CHECKING from loguru import logger from telegram import BotCommand, Update from telegram.ext import Application, CommandHandler, MessageHandler, filters, ContextTypes +from telegram.request import HTTPXRequest from nanobot.bus.events import OutboundMessage from nanobot.bus.queue import MessageBus @@ -121,11 +122,13 @@ class TelegramChannel(BaseChannel): self._running = True - # Build the application - builder = Application.builder().token(self.config.token) + # Build the application with larger connection pool to avoid pool-timeout on long runs + req = HTTPXRequest(connection_pool_size=16, pool_timeout=5.0, connect_timeout=30.0, read_timeout=30.0) + builder = Application.builder().token(self.config.token).request(req).get_updates_request(req) if self.config.proxy: builder = builder.proxy(self.config.proxy).get_updates_proxy(self.config.proxy) self._app = builder.build() + self._app.add_error_handler(self._on_error) # Add command handlers self._app.add_handler(CommandHandler("start", self._on_start)) @@ -386,6 +389,10 @@ class TelegramChannel(BaseChannel): except Exception as e: logger.debug(f"Typing indicator stopped for {chat_id}: {e}") + async def _on_error(self, update: object, context: ContextTypes.DEFAULT_TYPE) -> None: + """Log polling / handler errors instead of silently swallowing them.""" + logger.error(f"Telegram error: {context.error}") + def _get_extension(self, media_type: str, mime_type: str | None) -> str: """Get file extension based on media type.""" if mime_type: diff --git a/nanobot/cli/commands.py b/nanobot/cli/commands.py index aa99d55..45d5d3f 100644 --- a/nanobot/cli/commands.py +++ b/nanobot/cli/commands.py @@ -329,6 +329,7 @@ def gateway( cron_service=cron, restrict_to_workspace=config.tools.restrict_to_workspace, session_manager=session_manager, + mcp_servers=config.tools.mcp_servers, ) # Set cron callback (needs agent) @@ -431,6 +432,7 @@ def agent( brave_api_key=config.tools.web.search.api_key or None, exec_config=config.tools.exec, restrict_to_workspace=config.tools.restrict_to_workspace, + mcp_servers=config.tools.mcp_servers, ) # Show spinner when logs are off (no output to miss); skip when logs are on @@ -447,6 +449,7 @@ def agent( with _thinking_ctx(): response = await agent_loop.process_direct(message, session_id) _print_agent_response(response, render_markdown=markdown) + await agent_loop._close_mcp() asyncio.run(run_once()) else: diff --git a/nanobot/config/schema.py b/nanobot/config/schema.py index f6c861d..2a206e1 100644 --- a/nanobot/config/schema.py +++ b/nanobot/config/schema.py @@ -1,7 +1,7 @@ """Configuration schema using Pydantic.""" from pathlib import Path -from pydantic import BaseModel, Field +from pydantic import BaseModel, Field, ConfigDict from pydantic_settings import BaseSettings @@ -213,11 +213,20 @@ class ExecToolConfig(BaseModel): timeout: int = 60 +class MCPServerConfig(BaseModel): + """MCP server connection configuration (stdio or HTTP).""" + command: str = "" # Stdio: command to run (e.g. "npx") + args: list[str] = Field(default_factory=list) # Stdio: command arguments + env: dict[str, str] = Field(default_factory=dict) # Stdio: extra env vars + url: str = "" # HTTP: streamable HTTP endpoint URL + + class ToolsConfig(BaseModel): """Tools configuration.""" web: WebToolsConfig = Field(default_factory=WebToolsConfig) exec: ExecToolConfig = Field(default_factory=ExecToolConfig) restrict_to_workspace: bool = False # If true, restrict all tool access to workspace directory + mcp_servers: dict[str, MCPServerConfig] = Field(default_factory=dict) class Config(BaseSettings): @@ -281,6 +290,7 @@ class Config(BaseSettings): return spec.default_api_base return None - class Config: - env_prefix = "NANOBOT_" - env_nested_delimiter = "__" + model_config = ConfigDict( + env_prefix="NANOBOT_", + env_nested_delimiter="__" + ) diff --git a/nanobot/skills/cron/SKILL.md b/nanobot/skills/cron/SKILL.md index c8beecb..7db25d8 100644 --- a/nanobot/skills/cron/SKILL.md +++ b/nanobot/skills/cron/SKILL.md @@ -7,10 +7,11 @@ description: Schedule reminders and recurring tasks. Use the `cron` tool to schedule reminders or recurring tasks. -## Two Modes +## Three Modes 1. **Reminder** - message is sent directly to user 2. **Task** - message is a task description, agent executes and sends result +3. **One-time** - runs once at a specific time, then auto-deletes ## Examples @@ -24,6 +25,11 @@ Dynamic task (agent executes each time): cron(action="add", message="Check HKUDS/nanobot GitHub stars and report", every_seconds=600) ``` +One-time scheduled task (compute ISO datetime from current time): +``` +cron(action="add", message="Remind me about the meeting", at="") +``` + List/remove: ``` cron(action="list") @@ -38,3 +44,4 @@ cron(action="remove", job_id="abc123") | every hour | every_seconds: 3600 | | every day at 8am | cron_expr: "0 8 * * *" | | weekdays at 5pm | cron_expr: "0 17 * * 1-5" | +| at a specific time | at: ISO datetime string (compute from current time) | diff --git a/pyproject.toml b/pyproject.toml index b1b3c81..bdccbf0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,6 +38,7 @@ dependencies = [ "qq-botpy>=1.0.0", "python-socks[asyncio]>=2.4.0", "prompt-toolkit>=3.0.0", + "mcp>=1.0.0", ] [project.optional-dependencies] From e89afe61f1ab87018d488e4677d7d0de0d10bcb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20S=C3=A1nchez=20Vall=C3=A9s?= Date: Thu, 12 Feb 2026 10:01:30 +0100 Subject: [PATCH 12/60] feat(tools): add mcp support --- README.md | 2 +- nanobot/agent/context.py | 6 ++- nanobot/agent/loop.py | 30 ++++++++++++++ nanobot/agent/subagent.py | 15 +++++-- nanobot/agent/tools/mcp.py | 82 ++++++++++++++++++++++++++++++++++++++ nanobot/cli/commands.py | 3 ++ nanobot/config/schema.py | 18 +++++++-- pyproject.toml | 1 + 8 files changed, 146 insertions(+), 11 deletions(-) create mode 100644 nanobot/agent/tools/mcp.py diff --git a/README.md b/README.md index fed25c8..ea606de 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ ⚡️ Delivers core agent functionality in just **~4,000** lines of code — **99% smaller** than Clawdbot's 430k+ lines. -📏 Real-time line count: **3,510 lines** (run `bash core_agent_lines.sh` to verify anytime) +📏 Real-time line count: **3,578 lines** (run `bash core_agent_lines.sh` to verify anytime) ## 📢 News diff --git a/nanobot/agent/context.py b/nanobot/agent/context.py index d807854..b9c0790 100644 --- a/nanobot/agent/context.py +++ b/nanobot/agent/context.py @@ -73,7 +73,9 @@ Skills with available="false" need dependencies installed first - you can try in def _get_identity(self) -> str: """Get the core identity section.""" from datetime import datetime + import time as _time now = datetime.now().strftime("%Y-%m-%d %H:%M (%A)") + tz = _time.strftime("%Z") or "UTC" workspace_path = str(self.workspace.expanduser().resolve()) system = platform.system() runtime = f"{'macOS' if system == 'Darwin' else system} {platform.machine()}, Python {platform.python_version()}" @@ -88,7 +90,7 @@ You are nanobot, a helpful AI assistant. You have access to tools that allow you - Spawn subagents for complex background tasks ## Current Time -{now} +{now} ({tz}) ## Runtime {runtime} @@ -103,7 +105,7 @@ IMPORTANT: When responding to direct questions or conversations, reply directly Only use the 'message' tool when you need to send a message to a specific chat channel (like WhatsApp). For normal conversation, just respond with text - do not call the message tool. -Always be helpful, accurate, and concise. When using tools, explain what you're doing. +Always be helpful, accurate, and concise. When using tools, think step by step: what you know, what you need, and why you chose this tool. When remembering something, write to {workspace_path}/memory/MEMORY.md""" def _load_bootstrap_files(self) -> str: diff --git a/nanobot/agent/loop.py b/nanobot/agent/loop.py index b764c3d..a3ab678 100644 --- a/nanobot/agent/loop.py +++ b/nanobot/agent/loop.py @@ -1,6 +1,7 @@ """Agent loop: the core processing engine.""" import asyncio +from contextlib import AsyncExitStack import json from pathlib import Path from typing import Any @@ -46,6 +47,7 @@ class AgentLoop: cron_service: "CronService | None" = None, restrict_to_workspace: bool = False, session_manager: SessionManager | None = None, + mcp_servers: dict | None = None, ): from nanobot.config.schema import ExecToolConfig from nanobot.cron.service import CronService @@ -73,6 +75,9 @@ class AgentLoop: ) self._running = False + self._mcp_servers = mcp_servers or {} + self._mcp_stack: AsyncExitStack | None = None + self._mcp_connected = False self._register_default_tools() def _register_default_tools(self) -> None: @@ -107,9 +112,20 @@ class AgentLoop: if self.cron_service: self.tools.register(CronTool(self.cron_service)) + async def _connect_mcp(self) -> None: + """Connect to configured MCP servers (one-time, lazy).""" + if self._mcp_connected or not self._mcp_servers: + return + self._mcp_connected = True + from nanobot.agent.tools.mcp import connect_mcp_servers + self._mcp_stack = AsyncExitStack() + await self._mcp_stack.__aenter__() + await connect_mcp_servers(self._mcp_servers, self.tools, self._mcp_stack) + async def run(self) -> None: """Run the agent loop, processing messages from the bus.""" self._running = True + await self._connect_mcp() logger.info("Agent loop started") while self._running: @@ -136,6 +152,15 @@ class AgentLoop: except asyncio.TimeoutError: continue + async def _close_mcp(self) -> None: + """Close MCP connections.""" + if self._mcp_stack: + try: + await self._mcp_stack.aclose() + except (RuntimeError, BaseExceptionGroup): + pass # MCP SDK cancel scope cleanup is noisy but harmless + self._mcp_stack = None + def stop(self) -> None: """Stop the agent loop.""" self._running = False @@ -225,6 +250,8 @@ class AgentLoop: messages = self.context.add_tool_result( messages, tool_call.id, tool_call.name, result ) + # Interleaved CoT: reflect before next action + messages.append({"role": "user", "content": "Reflect on the results and decide next steps."}) else: # No tool calls, we're done final_content = response.content @@ -330,6 +357,8 @@ class AgentLoop: messages = self.context.add_tool_result( messages, tool_call.id, tool_call.name, result ) + # Interleaved CoT: reflect before next action + messages.append({"role": "user", "content": "Reflect on the results and decide next steps."}) else: final_content = response.content break @@ -367,6 +396,7 @@ class AgentLoop: Returns: The agent's response. """ + await self._connect_mcp() msg = InboundMessage( channel=channel, sender_id="user", diff --git a/nanobot/agent/subagent.py b/nanobot/agent/subagent.py index 6113efb..9e0cd7c 100644 --- a/nanobot/agent/subagent.py +++ b/nanobot/agent/subagent.py @@ -12,7 +12,7 @@ from nanobot.bus.events import InboundMessage from nanobot.bus.queue import MessageBus from nanobot.providers.base import LLMProvider from nanobot.agent.tools.registry import ToolRegistry -from nanobot.agent.tools.filesystem import ReadFileTool, WriteFileTool, ListDirTool +from nanobot.agent.tools.filesystem import ReadFileTool, WriteFileTool, EditFileTool, ListDirTool from nanobot.agent.tools.shell import ExecTool from nanobot.agent.tools.web import WebSearchTool, WebFetchTool @@ -101,6 +101,7 @@ class SubagentManager: allowed_dir = self.workspace if self.restrict_to_workspace else None tools.register(ReadFileTool(allowed_dir=allowed_dir)) tools.register(WriteFileTool(allowed_dir=allowed_dir)) + tools.register(EditFileTool(allowed_dir=allowed_dir)) tools.register(ListDirTool(allowed_dir=allowed_dir)) tools.register(ExecTool( working_dir=str(self.workspace), @@ -210,12 +211,17 @@ Summarize this naturally for the user. Keep it brief (1-2 sentences). Do not men def _build_subagent_prompt(self, task: str) -> str: """Build a focused system prompt for the subagent.""" + from datetime import datetime + import time as _time + now = datetime.now().strftime("%Y-%m-%d %H:%M (%A)") + tz = _time.strftime("%Z") or "UTC" + return f"""# Subagent -You are a subagent spawned by the main agent to complete a specific task. +## Current Time +{now} ({tz}) -## Your Task -{task} +You are a subagent spawned by the main agent to complete a specific task. ## Rules 1. Stay focused - complete only the assigned task, nothing else @@ -236,6 +242,7 @@ You are a subagent spawned by the main agent to complete a specific task. ## Workspace Your workspace is at: {self.workspace} +Skills are available at: {self.workspace}/skills/ (read SKILL.md files as needed) When you have completed the task, provide a clear summary of your findings or actions.""" diff --git a/nanobot/agent/tools/mcp.py b/nanobot/agent/tools/mcp.py new file mode 100644 index 0000000..bcef4aa --- /dev/null +++ b/nanobot/agent/tools/mcp.py @@ -0,0 +1,82 @@ +"""MCP client: connects to MCP servers and wraps their tools as native nanobot tools.""" + +from contextlib import AsyncExitStack +from typing import Any + +from loguru import logger + +from nanobot.agent.tools.base import Tool +from nanobot.agent.tools.registry import ToolRegistry + + +class MCPToolWrapper(Tool): + """Wraps a single MCP server tool as a nanobot Tool.""" + + def __init__(self, session, server_name: str, tool_def): + self._session = session + self._server = server_name + self._name = f"mcp_{server_name}_{tool_def.name}" + self._description = tool_def.description or tool_def.name + self._parameters = tool_def.inputSchema or {"type": "object", "properties": {}} + + @property + def name(self) -> str: + return self._name + + @property + def description(self) -> str: + return self._description + + @property + def parameters(self) -> dict[str, Any]: + return self._parameters + + async def execute(self, **kwargs: Any) -> str: + from mcp import types + result = await self._session.call_tool( + self._name.removeprefix(f"mcp_{self._server}_"), arguments=kwargs + ) + parts = [] + for block in result.content: + if isinstance(block, types.TextContent): + parts.append(block.text) + else: + parts.append(str(block)) + return "\n".join(parts) or "(no output)" + + +async def connect_mcp_servers( + mcp_servers: dict, registry: ToolRegistry, stack: AsyncExitStack +) -> None: + """Connect to configured MCP servers and register their tools.""" + from mcp import ClientSession, StdioServerParameters + from mcp.client.stdio import stdio_client + + for name, cfg in mcp_servers.items(): + try: + if cfg.command: + params = StdioServerParameters( + command=cfg.command, args=cfg.args, env=cfg.env or None + ) + read, write = await stack.enter_async_context(stdio_client(params)) + elif cfg.url: + from mcp.client.streamable_http import streamable_http_client + read, write, _ = await stack.enter_async_context( + streamable_http_client(cfg.url) + ) + else: + logger.warning(f"MCP server '{name}': no command or url configured, skipping") + continue + + session = await stack.enter_async_context(ClientSession(read, write)) + await session.initialize() + + tools = await session.list_tools() + for tool_def in tools.tools: + wrapper = MCPToolWrapper(session, name, tool_def) + registry.register(wrapper) + logger.debug(f"MCP: registered tool '{wrapper.name}' from server '{name}'") + + logger.info(f"MCP server '{name}': connected, {len(tools.tools)} tools registered") + except Exception as e: + logger.error(f"MCP server '{name}': failed to connect: {e}") diff --git a/nanobot/cli/commands.py b/nanobot/cli/commands.py index aa99d55..45d5d3f 100644 --- a/nanobot/cli/commands.py +++ b/nanobot/cli/commands.py @@ -329,6 +329,7 @@ def gateway( cron_service=cron, restrict_to_workspace=config.tools.restrict_to_workspace, session_manager=session_manager, + mcp_servers=config.tools.mcp_servers, ) # Set cron callback (needs agent) @@ -431,6 +432,7 @@ def agent( brave_api_key=config.tools.web.search.api_key or None, exec_config=config.tools.exec, restrict_to_workspace=config.tools.restrict_to_workspace, + mcp_servers=config.tools.mcp_servers, ) # Show spinner when logs are off (no output to miss); skip when logs are on @@ -447,6 +449,7 @@ def agent( with _thinking_ctx(): response = await agent_loop.process_direct(message, session_id) _print_agent_response(response, render_markdown=markdown) + await agent_loop._close_mcp() asyncio.run(run_once()) else: diff --git a/nanobot/config/schema.py b/nanobot/config/schema.py index f6c861d..2a206e1 100644 --- a/nanobot/config/schema.py +++ b/nanobot/config/schema.py @@ -1,7 +1,7 @@ """Configuration schema using Pydantic.""" from pathlib import Path -from pydantic import BaseModel, Field +from pydantic import BaseModel, Field, ConfigDict from pydantic_settings import BaseSettings @@ -213,11 +213,20 @@ class ExecToolConfig(BaseModel): timeout: int = 60 +class MCPServerConfig(BaseModel): + """MCP server connection configuration (stdio or HTTP).""" + command: str = "" # Stdio: command to run (e.g. "npx") + args: list[str] = Field(default_factory=list) # Stdio: command arguments + env: dict[str, str] = Field(default_factory=dict) # Stdio: extra env vars + url: str = "" # HTTP: streamable HTTP endpoint URL + + class ToolsConfig(BaseModel): """Tools configuration.""" web: WebToolsConfig = Field(default_factory=WebToolsConfig) exec: ExecToolConfig = Field(default_factory=ExecToolConfig) restrict_to_workspace: bool = False # If true, restrict all tool access to workspace directory + mcp_servers: dict[str, MCPServerConfig] = Field(default_factory=dict) class Config(BaseSettings): @@ -281,6 +290,7 @@ class Config(BaseSettings): return spec.default_api_base return None - class Config: - env_prefix = "NANOBOT_" - env_nested_delimiter = "__" + model_config = ConfigDict( + env_prefix="NANOBOT_", + env_nested_delimiter="__" + ) diff --git a/pyproject.toml b/pyproject.toml index b1b3c81..bdccbf0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,6 +38,7 @@ dependencies = [ "qq-botpy>=1.0.0", "python-socks[asyncio]>=2.4.0", "prompt-toolkit>=3.0.0", + "mcp>=1.0.0", ] [project.optional-dependencies] From 61e9f7f58ad3ce21df408615adadeac43db0205d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20S=C3=A1nchez=20Vall=C3=A9s?= Date: Thu, 12 Feb 2026 10:16:52 +0100 Subject: [PATCH 13/60] chore: revert unrelated changes, keep only MCP support --- README.md | 2 +- nanobot/agent/context.py | 6 ++---- nanobot/agent/loop.py | 4 ---- nanobot/agent/subagent.py | 15 ++++----------- nanobot/agent/tools/cron.py | 19 +++---------------- nanobot/channels/dingtalk.py | 11 ++--------- nanobot/channels/feishu.py | 13 +++++-------- nanobot/channels/qq.py | 15 ++++++--------- nanobot/channels/telegram.py | 11 ++--------- nanobot/skills/cron/SKILL.md | 9 +-------- 10 files changed, 26 insertions(+), 79 deletions(-) diff --git a/README.md b/README.md index ea606de..fed25c8 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ ⚡️ Delivers core agent functionality in just **~4,000** lines of code — **99% smaller** than Clawdbot's 430k+ lines. -📏 Real-time line count: **3,578 lines** (run `bash core_agent_lines.sh` to verify anytime) +📏 Real-time line count: **3,510 lines** (run `bash core_agent_lines.sh` to verify anytime) ## 📢 News diff --git a/nanobot/agent/context.py b/nanobot/agent/context.py index b9c0790..d807854 100644 --- a/nanobot/agent/context.py +++ b/nanobot/agent/context.py @@ -73,9 +73,7 @@ Skills with available="false" need dependencies installed first - you can try in def _get_identity(self) -> str: """Get the core identity section.""" from datetime import datetime - import time as _time now = datetime.now().strftime("%Y-%m-%d %H:%M (%A)") - tz = _time.strftime("%Z") or "UTC" workspace_path = str(self.workspace.expanduser().resolve()) system = platform.system() runtime = f"{'macOS' if system == 'Darwin' else system} {platform.machine()}, Python {platform.python_version()}" @@ -90,7 +88,7 @@ You are nanobot, a helpful AI assistant. You have access to tools that allow you - Spawn subagents for complex background tasks ## Current Time -{now} ({tz}) +{now} ## Runtime {runtime} @@ -105,7 +103,7 @@ IMPORTANT: When responding to direct questions or conversations, reply directly Only use the 'message' tool when you need to send a message to a specific chat channel (like WhatsApp). For normal conversation, just respond with text - do not call the message tool. -Always be helpful, accurate, and concise. When using tools, think step by step: what you know, what you need, and why you chose this tool. +Always be helpful, accurate, and concise. When using tools, explain what you're doing. When remembering something, write to {workspace_path}/memory/MEMORY.md""" def _load_bootstrap_files(self) -> str: diff --git a/nanobot/agent/loop.py b/nanobot/agent/loop.py index a3ab678..b15803a 100644 --- a/nanobot/agent/loop.py +++ b/nanobot/agent/loop.py @@ -250,8 +250,6 @@ class AgentLoop: messages = self.context.add_tool_result( messages, tool_call.id, tool_call.name, result ) - # Interleaved CoT: reflect before next action - messages.append({"role": "user", "content": "Reflect on the results and decide next steps."}) else: # No tool calls, we're done final_content = response.content @@ -357,8 +355,6 @@ class AgentLoop: messages = self.context.add_tool_result( messages, tool_call.id, tool_call.name, result ) - # Interleaved CoT: reflect before next action - messages.append({"role": "user", "content": "Reflect on the results and decide next steps."}) else: final_content = response.content break diff --git a/nanobot/agent/subagent.py b/nanobot/agent/subagent.py index 9e0cd7c..6113efb 100644 --- a/nanobot/agent/subagent.py +++ b/nanobot/agent/subagent.py @@ -12,7 +12,7 @@ from nanobot.bus.events import InboundMessage from nanobot.bus.queue import MessageBus from nanobot.providers.base import LLMProvider from nanobot.agent.tools.registry import ToolRegistry -from nanobot.agent.tools.filesystem import ReadFileTool, WriteFileTool, EditFileTool, ListDirTool +from nanobot.agent.tools.filesystem import ReadFileTool, WriteFileTool, ListDirTool from nanobot.agent.tools.shell import ExecTool from nanobot.agent.tools.web import WebSearchTool, WebFetchTool @@ -101,7 +101,6 @@ class SubagentManager: allowed_dir = self.workspace if self.restrict_to_workspace else None tools.register(ReadFileTool(allowed_dir=allowed_dir)) tools.register(WriteFileTool(allowed_dir=allowed_dir)) - tools.register(EditFileTool(allowed_dir=allowed_dir)) tools.register(ListDirTool(allowed_dir=allowed_dir)) tools.register(ExecTool( working_dir=str(self.workspace), @@ -211,18 +210,13 @@ Summarize this naturally for the user. Keep it brief (1-2 sentences). Do not men def _build_subagent_prompt(self, task: str) -> str: """Build a focused system prompt for the subagent.""" - from datetime import datetime - import time as _time - now = datetime.now().strftime("%Y-%m-%d %H:%M (%A)") - tz = _time.strftime("%Z") or "UTC" - return f"""# Subagent -## Current Time -{now} ({tz}) - You are a subagent spawned by the main agent to complete a specific task. +## Your Task +{task} + ## Rules 1. Stay focused - complete only the assigned task, nothing else 2. Your final response will be reported back to the main agent @@ -242,7 +236,6 @@ You are a subagent spawned by the main agent to complete a specific task. ## Workspace Your workspace is at: {self.workspace} -Skills are available at: {self.workspace}/skills/ (read SKILL.md files as needed) When you have completed the task, provide a clear summary of your findings or actions.""" diff --git a/nanobot/agent/tools/cron.py b/nanobot/agent/tools/cron.py index 9f1ecdb..ec0d2cd 100644 --- a/nanobot/agent/tools/cron.py +++ b/nanobot/agent/tools/cron.py @@ -50,10 +50,6 @@ class CronTool(Tool): "type": "string", "description": "Cron expression like '0 9 * * *' (for scheduled tasks)" }, - "at": { - "type": "string", - "description": "ISO datetime for one-time execution (e.g. '2026-02-12T10:30:00')" - }, "job_id": { "type": "string", "description": "Job ID (for remove)" @@ -68,38 +64,30 @@ class CronTool(Tool): message: str = "", every_seconds: int | None = None, cron_expr: str | None = None, - at: str | None = None, job_id: str | None = None, **kwargs: Any ) -> str: if action == "add": - return self._add_job(message, every_seconds, cron_expr, at) + return self._add_job(message, every_seconds, cron_expr) elif action == "list": return self._list_jobs() elif action == "remove": return self._remove_job(job_id) return f"Unknown action: {action}" - def _add_job(self, message: str, every_seconds: int | None, cron_expr: str | None, at: str | None) -> str: + def _add_job(self, message: str, every_seconds: int | None, cron_expr: str | None) -> str: if not message: return "Error: message is required for add" if not self._channel or not self._chat_id: return "Error: no session context (channel/chat_id)" # Build schedule - delete_after = False if every_seconds: schedule = CronSchedule(kind="every", every_ms=every_seconds * 1000) elif cron_expr: schedule = CronSchedule(kind="cron", expr=cron_expr) - elif at: - from datetime import datetime - dt = datetime.fromisoformat(at) - at_ms = int(dt.timestamp() * 1000) - schedule = CronSchedule(kind="at", at_ms=at_ms) - delete_after = True else: - return "Error: either every_seconds, cron_expr, or at is required" + return "Error: either every_seconds or cron_expr is required" job = self._cron.add_job( name=message[:30], @@ -108,7 +96,6 @@ class CronTool(Tool): deliver=True, channel=self._channel, to=self._chat_id, - delete_after_run=delete_after, ) return f"Created job '{job.name}' (id: {job.id})" diff --git a/nanobot/channels/dingtalk.py b/nanobot/channels/dingtalk.py index 4a8cdd9..72d3afd 100644 --- a/nanobot/channels/dingtalk.py +++ b/nanobot/channels/dingtalk.py @@ -137,15 +137,8 @@ class DingTalkChannel(BaseChannel): logger.info("DingTalk bot started with Stream Mode") - # Reconnect loop: restart stream if SDK exits or crashes - while self._running: - try: - await self._client.start() - except Exception as e: - logger.warning(f"DingTalk stream error: {e}") - if self._running: - logger.info("Reconnecting DingTalk stream in 5 seconds...") - await asyncio.sleep(5) + # client.start() is an async infinite loop handling the websocket connection + await self._client.start() except Exception as e: logger.exception(f"Failed to start DingTalk channel: {e}") diff --git a/nanobot/channels/feishu.py b/nanobot/channels/feishu.py index 23d1415..1c176a2 100644 --- a/nanobot/channels/feishu.py +++ b/nanobot/channels/feishu.py @@ -98,15 +98,12 @@ class FeishuChannel(BaseChannel): log_level=lark.LogLevel.INFO ) - # Start WebSocket client in a separate thread with reconnect loop + # Start WebSocket client in a separate thread def run_ws(): - while self._running: - try: - self._ws_client.start() - except Exception as e: - logger.warning(f"Feishu WebSocket error: {e}") - if self._running: - import time; time.sleep(5) + try: + self._ws_client.start() + except Exception as e: + logger.error(f"Feishu WebSocket error: {e}") self._ws_thread = threading.Thread(target=run_ws, daemon=True) self._ws_thread.start() diff --git a/nanobot/channels/qq.py b/nanobot/channels/qq.py index 0e8fe66..5964d30 100644 --- a/nanobot/channels/qq.py +++ b/nanobot/channels/qq.py @@ -75,15 +75,12 @@ class QQChannel(BaseChannel): logger.info("QQ bot started (C2C private message)") async def _run_bot(self) -> None: - """Run the bot connection with auto-reconnect.""" - while self._running: - try: - await self._client.start(appid=self.config.app_id, secret=self.config.secret) - except Exception as e: - logger.warning(f"QQ bot error: {e}") - if self._running: - logger.info("Reconnecting QQ bot in 5 seconds...") - await asyncio.sleep(5) + """Run the bot connection.""" + try: + await self._client.start(appid=self.config.app_id, secret=self.config.secret) + except Exception as e: + logger.error(f"QQ auth failed, check AppID/Secret at q.qq.com: {e}") + self._running = False async def stop(self) -> None: """Stop the QQ bot.""" diff --git a/nanobot/channels/telegram.py b/nanobot/channels/telegram.py index 1abd600..ff46c86 100644 --- a/nanobot/channels/telegram.py +++ b/nanobot/channels/telegram.py @@ -9,7 +9,6 @@ from typing import TYPE_CHECKING from loguru import logger from telegram import BotCommand, Update from telegram.ext import Application, CommandHandler, MessageHandler, filters, ContextTypes -from telegram.request import HTTPXRequest from nanobot.bus.events import OutboundMessage from nanobot.bus.queue import MessageBus @@ -122,13 +121,11 @@ class TelegramChannel(BaseChannel): self._running = True - # Build the application with larger connection pool to avoid pool-timeout on long runs - req = HTTPXRequest(connection_pool_size=16, pool_timeout=5.0, connect_timeout=30.0, read_timeout=30.0) - builder = Application.builder().token(self.config.token).request(req).get_updates_request(req) + # Build the application + builder = Application.builder().token(self.config.token) if self.config.proxy: builder = builder.proxy(self.config.proxy).get_updates_proxy(self.config.proxy) self._app = builder.build() - self._app.add_error_handler(self._on_error) # Add command handlers self._app.add_handler(CommandHandler("start", self._on_start)) @@ -389,10 +386,6 @@ class TelegramChannel(BaseChannel): except Exception as e: logger.debug(f"Typing indicator stopped for {chat_id}: {e}") - async def _on_error(self, update: object, context: ContextTypes.DEFAULT_TYPE) -> None: - """Log polling / handler errors instead of silently swallowing them.""" - logger.error(f"Telegram error: {context.error}") - def _get_extension(self, media_type: str, mime_type: str | None) -> str: """Get file extension based on media type.""" if mime_type: diff --git a/nanobot/skills/cron/SKILL.md b/nanobot/skills/cron/SKILL.md index 7db25d8..c8beecb 100644 --- a/nanobot/skills/cron/SKILL.md +++ b/nanobot/skills/cron/SKILL.md @@ -7,11 +7,10 @@ description: Schedule reminders and recurring tasks. Use the `cron` tool to schedule reminders or recurring tasks. -## Three Modes +## Two Modes 1. **Reminder** - message is sent directly to user 2. **Task** - message is a task description, agent executes and sends result -3. **One-time** - runs once at a specific time, then auto-deletes ## Examples @@ -25,11 +24,6 @@ Dynamic task (agent executes each time): cron(action="add", message="Check HKUDS/nanobot GitHub stars and report", every_seconds=600) ``` -One-time scheduled task (compute ISO datetime from current time): -``` -cron(action="add", message="Remind me about the meeting", at="") -``` - List/remove: ``` cron(action="list") @@ -44,4 +38,3 @@ cron(action="remove", job_id="abc123") | every hour | every_seconds: 3600 | | every day at 8am | cron_expr: "0 8 * * *" | | weekdays at 5pm | cron_expr: "0 17 * * 1-5" | -| at a specific time | at: ISO datetime string (compute from current time) | From d30523f460b26132091c96ea9ef73003a53e2e9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20S=C3=A1nchez=20Vall=C3=A9s?= Date: Thu, 12 Feb 2026 10:44:25 +0100 Subject: [PATCH 14/60] fix(mcp): clean up connections on exit in interactive and gateway modes --- nanobot/cli/commands.py | 45 +++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/nanobot/cli/commands.py b/nanobot/cli/commands.py index 45d5d3f..cab4d41 100644 --- a/nanobot/cli/commands.py +++ b/nanobot/cli/commands.py @@ -387,6 +387,8 @@ def gateway( ) except KeyboardInterrupt: console.print("\nShutting down...") + finally: + await agent._close_mcp() heartbeat.stop() cron.stop() agent.stop() @@ -465,30 +467,33 @@ def agent( signal.signal(signal.SIGINT, _exit_on_sigint) async def run_interactive(): - while True: - try: - _flush_pending_tty_input() - user_input = await _read_interactive_input_async() - command = user_input.strip() - if not command: - continue + try: + while True: + try: + _flush_pending_tty_input() + user_input = await _read_interactive_input_async() + command = user_input.strip() + if not command: + continue - if _is_exit_command(command): + if _is_exit_command(command): + _restore_terminal() + console.print("\nGoodbye!") + break + + with _thinking_ctx(): + response = await agent_loop.process_direct(user_input, session_id) + _print_agent_response(response, render_markdown=markdown) + except KeyboardInterrupt: _restore_terminal() console.print("\nGoodbye!") break - - with _thinking_ctx(): - response = await agent_loop.process_direct(user_input, session_id) - _print_agent_response(response, render_markdown=markdown) - except KeyboardInterrupt: - _restore_terminal() - console.print("\nGoodbye!") - break - except EOFError: - _restore_terminal() - console.print("\nGoodbye!") - break + except EOFError: + _restore_terminal() + console.print("\nGoodbye!") + break + finally: + await agent_loop._close_mcp() asyncio.run(run_interactive()) From 09c7e7adedb0bbd65a0910d63b8a0502da86ed98 Mon Sep 17 00:00:00 2001 From: qiupinhua Date: Fri, 13 Feb 2026 18:37:21 +0800 Subject: [PATCH 15/60] feat: change OAuth login command for providers --- README.md | 1 + nanobot/cli/commands.py | 36 ++++++++++++++++++++++-------------- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index eb2ff7f..8d0ab4d 100644 --- a/README.md +++ b/README.md @@ -597,6 +597,7 @@ That's it! Environment variables, model prefixing, config matching, and `nanobot | `nanobot agent --logs` | Show runtime logs during chat | | `nanobot gateway` | Start the gateway | | `nanobot status` | Show status | +| `nanobot provider login openai-codex` | OAuth login for providers | | `nanobot channels login` | Link WhatsApp (scan QR) | | `nanobot channels status` | Show channel status | diff --git a/nanobot/cli/commands.py b/nanobot/cli/commands.py index 1ee2332..f2a7ee3 100644 --- a/nanobot/cli/commands.py +++ b/nanobot/cli/commands.py @@ -860,29 +860,37 @@ def status(): # OAuth Login # ============================================================================ +provider_app = typer.Typer(help="Manage providers") +app.add_typer(provider_app, name="provider") -@app.command() -def login( + +@provider_app.command("login") +def provider_login( provider: str = typer.Argument(..., help="OAuth provider to authenticate with (e.g., 'openai-codex')"), ): """Authenticate with an OAuth provider.""" console.print(f"{__logo__} OAuth Login - {provider}\n") - + if provider == "openai-codex": try: - from oauth_cli_kit import get_token as get_codex_token - - console.print("[cyan]Starting OpenAI Codex authentication...[/cyan]") - console.print("A browser window will open for you to authenticate.\n") - - token = get_codex_token() - - if token and token.access: - console.print(f"[green]✓ Successfully authenticated with OpenAI Codex![/green]") - console.print(f"[dim]Account ID: {token.account_id}[/dim]") - else: + from oauth_cli_kit import get_token, login_oauth_interactive + token = None + try: + token = get_token() + except Exception: + token = None + if not (token and token.access): + console.print("[cyan]No valid token found. Starting interactive OAuth login...[/cyan]") + console.print("A browser window may open for you to authenticate.\n") + token = login_oauth_interactive( + print_fn=lambda s: console.print(s), + prompt_fn=lambda s: typer.prompt(s), + ) + if not (token and token.access): console.print("[red]✗ Authentication failed[/red]") raise typer.Exit(1) + console.print("[green]✓ Successfully authenticated with OpenAI Codex![/green]") + console.print(f"[dim]Account ID: {token.account_id}[/dim]") except ImportError: console.print("[red]oauth_cli_kit not installed. Run: pip install oauth-cli-kit[/red]") raise typer.Exit(1) From 1ae47058d9479e2d4e0151ff15ed631a8ab649f5 Mon Sep 17 00:00:00 2001 From: qiupinhua Date: Fri, 13 Feb 2026 18:51:30 +0800 Subject: [PATCH 16/60] fix: refactor code structure for improved readability and maintainability --- nanobot/cli/commands.py | 23 +- nanobot/providers/litellm_provider.py | 3 + nanobot/providers/openai_codex_provider.py | 12 - uv.lock | 2385 ++++++++++++++++++++ 4 files changed, 2406 insertions(+), 17 deletions(-) create mode 100644 uv.lock diff --git a/nanobot/cli/commands.py b/nanobot/cli/commands.py index f2a7ee3..68f2f30 100644 --- a/nanobot/cli/commands.py +++ b/nanobot/cli/commands.py @@ -16,6 +16,7 @@ from rich.table import Table from rich.text import Text from nanobot import __version__, __logo__ +from nanobot.config.schema import Config app = typer.Typer( name="nanobot", @@ -295,21 +296,33 @@ This file stores important information that should persist across sessions. console.print(" [dim]Created memory/MEMORY.md[/dim]") -def _make_provider(config): +def _make_provider(config: Config): """Create LiteLLMProvider from config. Exits if no API key found.""" from nanobot.providers.litellm_provider import LiteLLMProvider - p = config.get_provider() + from nanobot.providers.openai_codex_provider import OpenAICodexProvider + model = config.agents.defaults.model - if not (p and p.api_key) and not model.startswith("bedrock/"): + provider_name = config.get_provider_name(model) + p = config.get_provider(model) + + # OpenAI Codex (OAuth): don't route via LiteLLM; use the dedicated implementation. + if provider_name == "openai_codex" or model.startswith("openai-codex/"): + return OpenAICodexProvider( + default_model=model, + api_base=p.api_base if p else None, + ) + + if not model.startswith("bedrock/") and not (p and p.api_key): console.print("[red]Error: No API key configured.[/red]") console.print("Set one in ~/.nanobot/config.json under providers section") raise typer.Exit(1) + return LiteLLMProvider( api_key=p.api_key if p else None, - api_base=config.get_api_base(), + api_base=config.get_api_base(model), default_model=model, extra_headers=p.extra_headers if p else None, - provider_name=config.get_provider_name(), + provider_name=provider_name, ) diff --git a/nanobot/providers/litellm_provider.py b/nanobot/providers/litellm_provider.py index 9d76c2a..0ad77af 100644 --- a/nanobot/providers/litellm_provider.py +++ b/nanobot/providers/litellm_provider.py @@ -54,6 +54,9 @@ class LiteLLMProvider(LLMProvider): spec = self._gateway or find_by_model(model) if not spec: return + if not spec.env_key: + # OAuth/provider-only specs (for example: openai_codex) + return # Gateway/local overrides existing env; standard provider doesn't if self._gateway: diff --git a/nanobot/providers/openai_codex_provider.py b/nanobot/providers/openai_codex_provider.py index 9c98db5..f6d56aa 100644 --- a/nanobot/providers/openai_codex_provider.py +++ b/nanobot/providers/openai_codex_provider.py @@ -77,7 +77,6 @@ class OpenAICodexProvider(LLMProvider): def get_default_model(self) -> str: return self.default_model - def _strip_model_prefix(model: str) -> str: if model.startswith("openai-codex/"): return model.split("/", 1)[1] @@ -95,7 +94,6 @@ def _build_headers(account_id: str, token: str) -> dict[str, str]: "content-type": "application/json", } - async def _request_codex( url: str, headers: dict[str, str], @@ -109,7 +107,6 @@ async def _request_codex( raise RuntimeError(_friendly_error(response.status_code, text.decode("utf-8", "ignore"))) return await _consume_sse(response) - def _convert_tools(tools: list[dict[str, Any]]) -> list[dict[str, Any]]: # Nanobot tool definitions already use the OpenAI function schema. converted: list[dict[str, Any]] = [] @@ -140,7 +137,6 @@ def _convert_tools(tools: list[dict[str, Any]]) -> list[dict[str, Any]]: ) return converted - def _convert_messages(messages: list[dict[str, Any]]) -> tuple[str, list[dict[str, Any]]]: system_prompt = "" input_items: list[dict[str, Any]] = [] @@ -200,7 +196,6 @@ def _convert_messages(messages: list[dict[str, Any]]) -> tuple[str, list[dict[st return system_prompt, input_items - def _convert_user_message(content: Any) -> dict[str, Any]: if isinstance(content, str): return {"role": "user", "content": [{"type": "input_text", "text": content}]} @@ -234,12 +229,10 @@ def _split_tool_call_id(tool_call_id: Any) -> tuple[str, str | None]: return tool_call_id, None return "call_0", None - def _prompt_cache_key(messages: list[dict[str, Any]]) -> str: raw = json.dumps(messages, ensure_ascii=True, sort_keys=True) return hashlib.sha256(raw.encode("utf-8")).hexdigest() - async def _iter_sse(response: httpx.Response) -> AsyncGenerator[dict[str, Any], None]: buffer: list[str] = [] async for line in response.aiter_lines(): @@ -259,9 +252,6 @@ async def _iter_sse(response: httpx.Response) -> AsyncGenerator[dict[str, Any], continue buffer.append(line) - - - async def _consume_sse(response: httpx.Response) -> tuple[str, list[ToolCallRequest], str]: content = "" tool_calls: list[ToolCallRequest] = [] @@ -318,7 +308,6 @@ async def _consume_sse(response: httpx.Response) -> tuple[str, list[ToolCallRequ return content, tool_calls, finish_reason - def _map_finish_reason(status: str | None) -> str: if not status: return "stop" @@ -330,7 +319,6 @@ def _map_finish_reason(status: str | None) -> str: return "error" return "stop" - def _friendly_error(status_code: int, raw: str) -> str: if status_code == 429: return "ChatGPT usage quota exceeded or rate limit triggered. Please try again later." diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..3eaeaba --- /dev/null +++ b/uv.lock @@ -0,0 +1,2385 @@ +version = 1 +revision = 3 +requires-python = ">=3.11" +resolution-markers = [ + "python_full_version >= '3.14'", + "python_full_version < '3.14'", +] + +[[package]] +name = "aiohappyeyeballs" +version = "2.6.1" +source = { registry = "https://bytedpypi.byted.org/simple/" } +sdist = { url = "https://bytedpypi.byted.org/packages/aiohappyeyeballs/aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/aiohappyeyeballs/aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8" }, +] + +[[package]] +name = "aiohttp" +version = "3.13.3" +source = { registry = "https://bytedpypi.byted.org/simple/" } +dependencies = [ + { name = "aiohappyeyeballs" }, + { name = "aiosignal" }, + { name = "attrs" }, + { name = "frozenlist" }, + { name = "multidict" }, + { name = "propcache" }, + { name = "yarl" }, +] +sdist = { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3.tar.gz", hash = "sha256:a949eee43d3782f2daae4f4a2819b2cb9b0c5d3b7f7a927067cc84dafdbb9f88" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5b6073099fb654e0a068ae678b10feff95c5cae95bbfcbfa7af669d361a8aa6b" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cb93e166e6c28716c8c6aeb5f99dfb6d5ccf482d29fe9bf9a794110e6d0ab64" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:28e027cf2f6b641693a09f631759b4d9ce9165099d2b5d92af9bd4e197690eea" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3b61b7169ababd7802f9568ed96142616a9118dd2be0d1866e920e77ec8fa92a" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:80dd4c21b0f6237676449c6baaa1039abae86b91636b6c91a7f8e61c87f89540" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:65d2ccb7eabee90ce0503c17716fc77226be026dcc3e65cce859a30db715025b" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5b179331a481cb5529fca8b432d8d3c7001cb217513c94cd72d668d1248688a3" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d4c940f02f49483b18b079d1c27ab948721852b281f8b015c058100e9421dd1" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f9444f105664c4ce47a2a7171a2418bce5b7bae45fb610f4e2c36045d85911d3" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:694976222c711d1d00ba131904beb60534f93966562f64440d0c9d41b8cdb440" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:f33ed1a2bf1997a36661874b017f5c4b760f41266341af36febaf271d179f6d7" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e636b3c5f61da31a92bf0d91da83e58fdfa96f178ba682f11d24f31944cdd28c" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:5d2d94f1f5fcbe40838ac51a6ab5704a6f9ea42e72ceda48de5e6b898521da51" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2be0e9ccf23e8a94f6f0650ce06042cefc6ac703d0d7ab6c7a917289f2539ad4" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9af5e68ee47d6534d36791bbe9b646d2a7c7deb6fc24d7943628edfbb3581f29" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp311-cp311-win32.whl", hash = "sha256:a2212ad43c0833a873d0fb3c63fa1bacedd4cf6af2fee62bf4b739ceec3ab239" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp311-cp311-win_amd64.whl", hash = "sha256:642f752c3eb117b105acbd87e2c143de710987e09860d674e068c4c2c441034f" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:b903a4dfee7d347e2d87697d0713be59e0b87925be030c9178c5faa58ea58d5c" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a45530014d7a1e09f4a55f4f43097ba0fd155089372e105e4bff4ca76cb1b168" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:27234ef6d85c914f9efeb77ff616dbf4ad2380be0cda40b4db086ffc7ddd1b7d" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d32764c6c9aafb7fb55366a224756387cd50bfa720f32b88e0e6fa45b27dcf29" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b1a6102b4d3ebc07dad44fbf07b45bb600300f15b552ddf1851b5390202ea2e3" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c014c7ea7fb775dd015b2d3137378b7be0249a448a1612268b5a90c2d81de04d" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2b8d8ddba8f95ba17582226f80e2de99c7a7948e66490ef8d947e272a93e9463" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9ae8dd55c8e6c4257eae3a20fd2c8f41edaea5992ed67156642493b8daf3cecc" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:01ad2529d4b5035578f5081606a465f3b814c542882804e2e8cda61adf5c71bf" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bb4f7475e359992b580559e008c598091c45b5088f28614e855e42d39c2f1033" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:c19b90316ad3b24c69cd78d5c9b4f3aa4497643685901185b65166293d36a00f" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:96d604498a7c782cb15a51c406acaea70d8c027ee6b90c569baa6e7b93073679" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:084911a532763e9d3dd95adf78a78f4096cd5f58cdc18e6fdbc1b58417a45423" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:7a4a94eb787e606d0a09404b9c38c113d3b099d508021faa615d70a0131907ce" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:87797e645d9d8e222e04160ee32aa06bc5c163e8499f24db719e7852ec23093a" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp312-cp312-win32.whl", hash = "sha256:b04be762396457bef43f3597c991e192ee7da460a4953d7e647ee4b1c28e7046" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp312-cp312-win_amd64.whl", hash = "sha256:e3531d63d3bdfa7e3ac5e9b27b2dd7ec9df3206a98e0b3445fa906f233264c57" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:5dff64413671b0d3e7d5918ea490bdccb97a4ad29b3f311ed423200b2203e01c" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:87b9aab6d6ed88235aa2970294f496ff1a1f9adcd724d800e9b952395a80ffd9" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:425c126c0dc43861e22cb1c14ba4c8e45d09516d0a3ae0a3f7494b79f5f233a3" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7f9120f7093c2a32d9647abcaf21e6ad275b4fbec5b55969f978b1a97c7c86bf" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:697753042d57f4bf7122cab985bf15d0cef23c770864580f5af4f52023a56bd6" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6de499a1a44e7de70735d0b39f67c8f25eb3d91eb3103be99ca0fa882cdd987d" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:37239e9f9a7ea9ac5bf6b92b0260b01f8a22281996da609206a84df860bc1261" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f76c1e3fe7d7c8afad7ed193f89a292e1999608170dcc9751a7462a87dfd5bc0" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fc290605db2a917f6e81b0e1e0796469871f5af381ce15c604a3c5c7e51cb730" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4021b51936308aeea0367b8f006dc999ca02bc118a0cc78c303f50a2ff6afb91" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:49a03727c1bba9a97d3e93c9f93ca03a57300f484b6e935463099841261195d3" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3d9908a48eb7416dc1f4524e69f1d32e5d90e3981e4e37eb0aa1cd18f9cfa2a4" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:2712039939ec963c237286113c68dbad80a82a4281543f3abf766d9d73228998" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:7bfdc049127717581866fa4708791220970ce291c23e28ccf3922c700740fdc0" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8057c98e0c8472d8846b9c79f56766bcc57e3e8ac7bfd510482332366c56c591" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp313-cp313-win32.whl", hash = "sha256:1449ceddcdbcf2e0446957863af03ebaaa03f94c090f945411b61269e2cb5daf" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp313-cp313-win_amd64.whl", hash = "sha256:693781c45a4033d31d4187d2436f5ac701e7bbfe5df40d917736108c1cc7436e" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:ea37047c6b367fd4bd632bff8077449b8fa034b69e812a18e0132a00fae6e808" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:6fc0e2337d1a4c3e6acafda6a78a39d4c14caea625124817420abceed36e2415" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c685f2d80bb67ca8c3837823ad76196b3694b0159d232206d1e461d3d434666f" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48e377758516d262bde50c2584fc6c578af272559c409eecbdd2bae1601184d6" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:34749271508078b261c4abb1767d42b8d0c0cc9449c73a4df494777dc55f0687" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:82611aeec80eb144416956ec85b6ca45a64d76429c1ed46ae1b5f86c6e0c9a26" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2fff83cfc93f18f215896e3a190e8e5cb413ce01553901aca925176e7568963a" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bbe7d4cecacb439e2e2a8a1a7b935c25b812af7a5fd26503a66dadf428e79ec1" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b928f30fe49574253644b1ca44b1b8adbd903aa0da4b9054a6c20fc7f4092a25" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7b5e8fe4de30df199155baaf64f2fcd604f4c678ed20910db8e2c66dc4b11603" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:8542f41a62bcc58fc7f11cf7c90e0ec324ce44950003feb70640fc2a9092c32a" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:5e1d8c8b8f1d91cd08d8f4a3c2b067bfca6ec043d3ff36de0f3a715feeedf926" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:90455115e5da1c3c51ab619ac57f877da8fd6d73c05aacd125c5ae9819582aba" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:042e9e0bcb5fba81886c8b4fbb9a09d6b8a00245fd8d88e4d989c1f96c74164c" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2eb752b102b12a76ca02dff751a801f028b4ffbbc478840b473597fc91a9ed43" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314-win32.whl", hash = "sha256:b556c85915d8efaed322bf1bdae9486aa0f3f764195a0fb6ee962e5c71ef5ce1" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314-win_amd64.whl", hash = "sha256:9bf9f7a65e7aa20dd764151fb3d616c81088f91f8df39c3893a536e279b4b984" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:05861afbbec40650d8a07ea324367cb93e9e8cc7762e04dd4405df99fa65159c" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2fc82186fadc4a8316768d61f3722c230e2c1dcab4200d52d2ebdf2482e47592" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0add0900ff220d1d5c5ebbf99ed88b0c1bbf87aa7e4262300ed1376a6b13414f" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:568f416a4072fbfae453dcf9a99194bbb8bdeab718e08ee13dfa2ba0e4bebf29" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:add1da70de90a2569c5e15249ff76a631ccacfe198375eead4aadf3b8dc849dc" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:10b47b7ba335d2e9b1239fa571131a87e2d8ec96b333e68b2a305e7a98b0bae2" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3dd4dce1c718e38081c8f35f323209d4c1df7d4db4bab1b5c88a6b4d12b74587" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:34bac00a67a812570d4a460447e1e9e06fae622946955f939051e7cc895cfab8" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a19884d2ee70b06d9204b2727a7b9f983d0c684c650254679e716b0b77920632" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5f8ca7f2bb6ba8348a3614c7918cc4bb73268c5ac2a207576b7afea19d3d9f64" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:b0d95340658b9d2f11d9697f59b3814a9d3bb4b7a7c20b131df4bcef464037c0" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:a1e53262fd202e4b40b70c3aff944a8155059beedc8a89bba9dc1f9ef06a1b56" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:d60ac9663f44168038586cab2157e122e46bdef09e9368b37f2d82d354c23f72" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:90751b8eed69435bac9ff4e3d2f6b3af1f57e37ecb0fbeee59c0174c9e2d41df" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:fc353029f176fd2b3ec6cfc71be166aba1936fe5d73dd1992ce289ca6647a9aa" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314t-win32.whl", hash = "sha256:2e41b18a58da1e474a057b3d35248d8320029f61d70a37629535b16a0c8f3767" }, + { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314t-win_amd64.whl", hash = "sha256:44531a36aa2264a1860089ffd4dce7baf875ee5a6079d5fb42e261c704ef7344" }, +] + +[[package]] +name = "aiosignal" +version = "1.4.0" +source = { registry = "https://bytedpypi.byted.org/simple/" } +dependencies = [ + { name = "frozenlist" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://bytedpypi.byted.org/packages/aiosignal/aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/aiosignal/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e" }, +] + +[[package]] +name = "annotated-doc" +version = "0.0.4" +source = { registry = "https://bytedpypi.byted.org/simple/" } +sdist = { url = "https://bytedpypi.byted.org/packages/annotated-doc/annotated_doc-0.0.4.tar.gz", hash = "sha256:fbcda96e87e9c92ad167c2e53839e57503ecfda18804ea28102353485033faa4" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/annotated-doc/annotated_doc-0.0.4-py3-none-any.whl", hash = "sha256:571ac1dc6991c450b25a9c2d84a3705e2ae7a53467b5d111c24fa8baabbed320" }, +] + +[[package]] +name = "annotated-types" +version = "0.7.0" +source = { registry = "https://bytedpypi.byted.org/simple/" } +sdist = { url = "https://bytedpypi.byted.org/packages/annotated-types/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/annotated-types/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53" }, +] + +[[package]] +name = "anyio" +version = "4.12.1" +source = { registry = "https://bytedpypi.byted.org/simple/" } +dependencies = [ + { name = "idna" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://bytedpypi.byted.org/packages/anyio/anyio-4.12.1.tar.gz", hash = "sha256:41cfcc3a4c85d3f05c932da7c26d0201ac36f72abd4435ba90d0464a3ffed703" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/anyio/anyio-4.12.1-py3-none-any.whl", hash = "sha256:d405828884fc140aa80a3c667b8beed277f1dfedec42ba031bd6ac3db606ab6c" }, +] + +[[package]] +name = "apscheduler" +version = "3.11.2" +source = { registry = "https://bytedpypi.byted.org/simple/" } +dependencies = [ + { name = "tzlocal" }, +] +sdist = { url = "https://bytedpypi.byted.org/packages/apscheduler/apscheduler-3.11.2.tar.gz", hash = "sha256:2a9966b052ec805f020c8c4c3ae6e6a06e24b1bf19f2e11d91d8cca0473eef41" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/apscheduler/apscheduler-3.11.2-py3-none-any.whl", hash = "sha256:ce005177f741409db4e4dd40a7431b76feb856b9dd69d57e0da49d6715bfd26d" }, +] + +[[package]] +name = "attrs" +version = "25.4.0" +source = { registry = "https://bytedpypi.byted.org/simple/" } +sdist = { url = "https://bytedpypi.byted.org/packages/attrs/attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/attrs/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373" }, +] + +[[package]] +name = "certifi" +version = "2026.1.4" +source = { registry = "https://bytedpypi.byted.org/simple/" } +sdist = { url = "https://bytedpypi.byted.org/packages/certifi/certifi-2026.1.4.tar.gz", hash = "sha256:ac726dd470482006e014ad384921ed6438c457018f4b3d204aea4281258b2120" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/certifi/certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c" }, +] + +[[package]] +name = "chardet" +version = "5.2.0" +source = { registry = "https://bytedpypi.byted.org/simple/" } +sdist = { url = "https://bytedpypi.byted.org/packages/chardet/chardet-5.2.0.tar.gz", hash = "sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/chardet/chardet-5.2.0-py3-none-any.whl", hash = "sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.4" +source = { registry = "https://bytedpypi.byted.org/simple/" } +sdist = { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6e1fcf0720908f200cd21aa4e6750a48ff6ce4afe7ff5a79a90d5ed8a08296f8" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f819d5fe9234f9f82d75bdfa9aef3a3d72c4d24a6e57aeaebba32a704553aa0" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a59cb51917aa591b1c4e6a43c132f0cdc3c76dbad6155df4e28ee626cc77a0a3" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8ef3c867360f88ac904fd3f5e1f902f13307af9052646963ee08ff4f131adafc" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d9e45d7faa48ee908174d8fe84854479ef838fc6a705c9315372eacbc2f02897" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:840c25fb618a231545cbab0564a799f101b63b9901f2569faecd6b222ac72381" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ca5862d5b3928c4940729dacc329aa9102900382fea192fc5e52eb69d6093815" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d9c7f57c3d666a53421049053eaacdd14bbd0a528e2186fcb2e672effd053bb0" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:277e970e750505ed74c832b4bf75dac7476262ee2a013f5574dd49075879e161" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:31fd66405eaf47bb62e8cd575dc621c56c668f27d46a61d975a249930dd5e2a4" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:0d3d8f15c07f86e9ff82319b3d9ef6f4bf907608f53fe9d92b28ea9ae3d1fd89" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:9f7fcd74d410a36883701fafa2482a6af2ff5ba96b9a620e9e0721e28ead5569" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ebf3e58c7ec8a8bed6d66a75d7fb37b55e5015b03ceae72a8e7c74495551e224" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp311-cp311-win32.whl", hash = "sha256:eecbc200c7fd5ddb9a7f16c7decb07b566c29fa2161a16cf67b8d068bd21690a" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:5ae497466c7901d54b639cf42d5b8c1b6a4fead55215500d2f486d34db48d016" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp311-cp311-win_arm64.whl", hash = "sha256:65e2befcd84bc6f37095f5961e68a6f077bf44946771354a28ad434c2cce0ae1" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0a98e6759f854bd25a58a73fa88833fba3b7c491169f86ce1180c948ab3fd394" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b5b290ccc2a263e8d185130284f8501e3e36c5e02750fc6b6bdeb2e9e96f1e25" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74bb723680f9f7a6234dcf67aea57e708ec1fbdf5699fb91dfd6f511b0a320ef" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f1e34719c6ed0b92f418c7c780480b26b5d9c50349e9a9af7d76bf757530350d" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2437418e20515acec67d86e12bf70056a33abdacb5cb1655042f6538d6b085a8" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11d694519d7f29d6cd09f6ac70028dba10f92f6cdd059096db198c283794ac86" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ac1c4a689edcc530fc9d9aa11f5774b9e2f33f9a0c6a57864e90908f5208d30a" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:21d142cc6c0ec30d2efee5068ca36c128a30b0f2c53c1c07bd78cb6bc1d3be5f" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5dbe56a36425d26d6cfb40ce79c314a2e4dd6211d51d6d2191c00bed34f354cc" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5bfbb1b9acf3334612667b61bd3002196fe2a1eb4dd74d247e0f2a4d50ec9bbf" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:d055ec1e26e441f6187acf818b73564e6e6282709e9bcb5b63f5b23068356a15" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:af2d8c67d8e573d6de5bc30cdb27e9b95e49115cd9baad5ddbd1a6207aaa82a9" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:780236ac706e66881f3b7f2f32dfe90507a09e67d1d454c762cf642e6e1586e0" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp312-cp312-win32.whl", hash = "sha256:5833d2c39d8896e4e19b689ffc198f08ea58116bee26dea51e362ecc7cd3ed26" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:a79cfe37875f822425b89a82333404539ae63dbdddf97f84dcbc3d339aae9525" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp312-cp312-win_arm64.whl", hash = "sha256:376bec83a63b8021bb5c8ea75e21c4ccb86e7e45ca4eb81146091b56599b80c3" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b39f987ae8ccdf0d2642338faf2abb1862340facc796048b604ef14919e55ed" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3162d5d8ce1bb98dd51af660f2121c55d0fa541b46dff7bb9b9f86ea1d87de72" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:81d5eb2a312700f4ecaa977a8235b634ce853200e828fbadf3a9c50bab278328" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5bd2293095d766545ec1a8f612559f6b40abc0eb18bb2f5d1171872d34036ede" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc7637e2f80d8530ee4a78e878bce464f70087ce73cf7c1caf142416923b98f1" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f8bf04158c6b607d747e93949aa60618b61312fe647a6369f88ce2ff16043490" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:554af85e960429cf30784dd47447d5125aaa3b99a6f0683589dbd27e2f45da44" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:74018750915ee7ad843a774364e13a3db91682f26142baddf775342c3f5b1133" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c0463276121fdee9c49b98908b3a89c39be45d86d1dbaa22957e38f6321d4ce3" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:362d61fd13843997c1c446760ef36f240cf81d3ebf74ac62652aebaf7838561e" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp313-cp313-win32.whl", hash = "sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:da3326d9e65ef63a817ecbcc0df6e94463713b754fe293eaa03da99befb9a5bd" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8af65f14dc14a79b924524b1e7fffe304517b2bff5a58bf64f30b98bbc5079eb" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74664978bb272435107de04e36db5a9735e78232b85b77d45cfb38f758efd33e" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:752944c7ffbfdd10c074dc58ec2d5a8a4cd9493b314d367c14d24c17684ddd14" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1f13550535ad8cff21b8d757a3257963e951d96e20ec82ab44bc64aeb62a191" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ecaae4149d99b1c9e7b88bb03e3221956f68fd6d50be2ef061b2381b61d20838" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cb6254dc36b47a990e59e1068afacdcd02958bdcce30bb50cc1700a8b9d624a6" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c8ae8a0f02f57a6e61203a31428fa1d677cbe50c93622b4149d5c0f319c1d19e" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:47cc91b2f4dd2833fddaedd2893006b0106129d4b94fdb6af1f4ce5a9965577c" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:82004af6c302b5d3ab2cfc4cc5f29db16123b1a8417f2e25f9066f91d4411090" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b7d8f6c26245217bd2ad053761201e9f9680f8ce52f0fcd8d0755aeae5b2152" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:799a7a5e4fb2d5898c60b640fd4981d6a25f1c11790935a44ce38c54e985f828" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:99ae2cffebb06e6c22bdc25801d7b30f503cc87dbd283479e7b606f70aff57ec" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp314-cp314-win32.whl", hash = "sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2" }, + { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f" }, +] + +[[package]] +name = "click" +version = "8.3.1" +source = { registry = "https://bytedpypi.byted.org/simple/" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://bytedpypi.byted.org/packages/click/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/click/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://bytedpypi.byted.org/simple/" } +sdist = { url = "https://bytedpypi.byted.org/packages/colorama/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/colorama/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6" }, +] + +[[package]] +name = "croniter" +version = "6.0.0" +source = { registry = "https://bytedpypi.byted.org/simple/" } +dependencies = [ + { name = "python-dateutil" }, + { name = "pytz" }, +] +sdist = { url = "https://bytedpypi.byted.org/packages/croniter/croniter-6.0.0.tar.gz", hash = "sha256:37c504b313956114a983ece2c2b07790b1f1094fe9d81cc94739214748255577" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/croniter/croniter-6.0.0-py2.py3-none-any.whl", hash = "sha256:2f878c3856f17896979b2a4379ba1f09c83e374931ea15cc835c5dd2eee9b368" }, +] + +[[package]] +name = "cssselect" +version = "1.4.0" +source = { registry = "https://bytedpypi.byted.org/simple/" } +sdist = { url = "https://bytedpypi.byted.org/packages/cssselect/cssselect-1.4.0.tar.gz", hash = "sha256:fdaf0a1425e17dfe8c5cf66191d211b357cf7872ae8afc4c6762ddd8ac47fc92" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/cssselect/cssselect-1.4.0-py3-none-any.whl", hash = "sha256:c0ec5c0191c8ee39fcc8afc1540331d8b55b0183478c50e9c8a79d44dbceb1d8" }, +] + +[[package]] +name = "dingtalk-stream" +version = "0.24.3" +source = { registry = "https://bytedpypi.byted.org/simple/" } +dependencies = [ + { name = "aiohttp" }, + { name = "requests" }, + { name = "websockets" }, +] +wheels = [ + { url = "https://bytedpypi.byted.org/packages/dingtalk-stream/dingtalk_stream-0.24.3-py3-none-any.whl", hash = "sha256:2160403656985962878bf60cdf5adf41619f21067348e06f07a7c7eebf5943ad" }, +] + +[[package]] +name = "distro" +version = "1.9.0" +source = { registry = "https://bytedpypi.byted.org/simple/" } +sdist = { url = "https://bytedpypi.byted.org/packages/distro/distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/distro/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2" }, +] + +[[package]] +name = "fastuuid" +version = "0.14.0" +source = { registry = "https://bytedpypi.byted.org/simple/" } +sdist = { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0.tar.gz", hash = "sha256:178947fc2f995b38497a74172adee64fdeb8b7ec18f2a5934d037641ba265d26" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp311-cp311-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:73946cb950c8caf65127d4e9a325e2b6be0442a224fd51ba3b6ac44e1912ce34" }, + { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:12ac85024637586a5b69645e7ed986f7535106ed3013640a393a03e461740cb7" }, + { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:05a8dde1f395e0c9b4be515b7a521403d1e8349443e7641761af07c7ad1624b1" }, + { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09378a05020e3e4883dfdab438926f31fea15fd17604908f3d39cbeb22a0b4dc" }, + { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbb0c4b15d66b435d2538f3827f05e44e2baafcc003dd7d8472dc67807ab8fd8" }, + { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cd5a7f648d4365b41dbf0e38fe8da4884e57bed4e77c83598e076ac0c93995e7" }, + { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c0a94245afae4d7af8c43b3159d5e3934c53f47140be0be624b96acd672ceb73" }, + { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:2b29e23c97e77c3a9514d70ce343571e469098ac7f5a269320a0f0b3e193ab36" }, + { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1e690d48f923c253f28151b3a6b4e335f2b06bf669c68a02665bc150b7839e94" }, + { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp311-cp311-win32.whl", hash = "sha256:a6f46790d59ab38c6aa0e35c681c0484b50dc0acf9e2679c005d61e019313c24" }, + { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp311-cp311-win_amd64.whl", hash = "sha256:e150eab56c95dc9e3fefc234a0eedb342fac433dacc273cd4d150a5b0871e1fa" }, + { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:77e94728324b63660ebf8adb27055e92d2e4611645bf12ed9d88d30486471d0a" }, + { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:caa1f14d2102cb8d353096bc6ef6c13b2c81f347e6ab9d6fbd48b9dea41c153d" }, + { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d23ef06f9e67163be38cece704170486715b177f6baae338110983f99a72c070" }, + { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0c9ec605ace243b6dbe3bd27ebdd5d33b00d8d1d3f580b39fdd15cd96fd71796" }, + { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:808527f2407f58a76c916d6aa15d58692a4a019fdf8d4c32ac7ff303b7d7af09" }, + { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2fb3c0d7fef6674bbeacdd6dbd386924a7b60b26de849266d1ff6602937675c8" }, + { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab3f5d36e4393e628a4df337c2c039069344db5f4b9d2a3c9cea48284f1dd741" }, + { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:b9a0ca4f03b7e0b01425281ffd44e99d360e15c895f1907ca105854ed85e2057" }, + { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3acdf655684cc09e60fb7e4cf524e8f42ea760031945aa8086c7eae2eeeabeb8" }, + { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp312-cp312-win32.whl", hash = "sha256:9579618be6280700ae36ac42c3efd157049fe4dd40ca49b021280481c78c3176" }, + { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp312-cp312-win_amd64.whl", hash = "sha256:d9e4332dc4ba054434a9594cbfaf7823b57993d7d8e7267831c3e059857cf397" }, + { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:77a09cb7427e7af74c594e409f7731a0cf887221de2f698e1ca0ebf0f3139021" }, + { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:9bd57289daf7b153bfa3e8013446aa144ce5e8c825e9e366d455155ede5ea2dc" }, + { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ac60fc860cdf3c3f327374db87ab8e064c86566ca8c49d2e30df15eda1b0c2d5" }, + { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ab32f74bd56565b186f036e33129da77db8be09178cd2f5206a5d4035fb2a23f" }, + { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33e678459cf4addaedd9936bbb038e35b3f6b2061330fd8f2f6a1d80414c0f87" }, + { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1e3cc56742f76cd25ecb98e4b82a25f978ccffba02e4bdce8aba857b6d85d87b" }, + { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:cb9a030f609194b679e1660f7e32733b7a0f332d519c5d5a6a0a580991290022" }, + { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:09098762aad4f8da3a888eb9ae01c84430c907a297b97166b8abc07b640f2995" }, + { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:1383fff584fa249b16329a059c68ad45d030d5a4b70fb7c73a08d98fd53bcdab" }, + { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp313-cp313-win32.whl", hash = "sha256:a0809f8cc5731c066c909047f9a314d5f536c871a7a22e815cc4967c110ac9ad" }, + { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp313-cp313-win_amd64.whl", hash = "sha256:0df14e92e7ad3276327631c9e7cec09e32572ce82089c55cb1bb8df71cf394ed" }, + { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp314-cp314-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:b852a870a61cfc26c884af205d502881a2e59cc07076b60ab4a951cc0c94d1ad" }, + { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:c7502d6f54cd08024c3ea9b3514e2d6f190feb2f46e6dbcd3747882264bb5f7b" }, + { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1ca61b592120cf314cfd66e662a5b54a578c5a15b26305e1b8b618a6f22df714" }, + { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa75b6657ec129d0abded3bec745e6f7ab642e6dba3a5272a68247e85f5f316f" }, + { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8a0dfea3972200f72d4c7df02c8ac70bad1bb4c58d7e0ec1e6f341679073a7f" }, + { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1bf539a7a95f35b419f9ad105d5a8a35036df35fdafae48fb2fd2e5f318f0d75" }, + { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:9a133bf9cc78fdbd1179cb58a59ad0100aa32d8675508150f3658814aeefeaa4" }, + { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp314-cp314-musllinux_1_1_i686.whl", hash = "sha256:f54d5b36c56a2d5e1a31e73b950b28a0d83eb0c37b91d10408875a5a29494bad" }, + { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:ec27778c6ca3393ef662e2762dba8af13f4ec1aaa32d08d77f71f2a70ae9feb8" }, + { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp314-cp314-win32.whl", hash = "sha256:e23fc6a83f112de4be0cc1990e5b127c27663ae43f866353166f87df58e73d06" }, + { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp314-cp314-win_amd64.whl", hash = "sha256:df61342889d0f5e7a32f7284e55ef95103f2110fee433c2ae7c2c0956d76ac8a" }, +] + +[[package]] +name = "filelock" +version = "3.21.2" +source = { registry = "https://bytedpypi.byted.org/simple/" } +sdist = { url = "https://bytedpypi.byted.org/packages/filelock/filelock-3.21.2.tar.gz", hash = "sha256:cfd218cfccf8b947fce7837da312ec3359d10ef2a47c8602edd59e0bacffb708" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/filelock/filelock-3.21.2-py3-none-any.whl", hash = "sha256:d6cd4dbef3e1bb63bc16500fc5aa100f16e405bbff3fb4231711851be50c1560" }, +] + +[[package]] +name = "frozenlist" +version = "1.8.0" +source = { registry = "https://bytedpypi.byted.org/simple/" } +sdist = { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0.tar.gz", hash = "sha256:3ede829ed8d842f6cd48fc7081d7a41001a56f1f38603f9d49bf3020d59a31ad" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:09474e9831bc2b2199fad6da3c14c7b0fbdd377cce9d3d77131be28906cb7d84" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:17c883ab0ab67200b5f964d2b9ed6b00971917d5d8a92df149dc2c9779208ee9" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fa47e444b8ba08fffd1c18e8cdb9a75db1b6a27f17507522834ad13ed5922b93" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2552f44204b744fba866e573be4c1f9048d6a324dfe14475103fd51613eb1d1f" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:957e7c38f250991e48a9a73e6423db1bb9dd14e722a10f6b8bb8e16a0f55f695" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8585e3bb2cdea02fc88ffa245069c36555557ad3609e83be0ec71f54fd4abb52" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:edee74874ce20a373d62dc28b0b18b93f645633c2943fd90ee9d898550770581" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c9a63152fe95756b85f31186bddf42e4c02c6321207fd6601a1c89ebac4fe567" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b6db2185db9be0a04fecf2f241c70b63b1a242e2805be291855078f2b404dd6b" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:f4be2e3d8bc8aabd566f8d5b8ba7ecc09249d74ba3c9ed52e54dc23a293f0b92" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c8d1634419f39ea6f5c427ea2f90ca85126b54b50837f31497f3bf38266e853d" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:1a7fa382a4a223773ed64242dbe1c9c326ec09457e6b8428efb4118c685c3dfd" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:11847b53d722050808926e785df837353bd4d75f1d494377e59b23594d834967" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp311-cp311-win32.whl", hash = "sha256:27c6e8077956cf73eadd514be8fb04d77fc946a7fe9f7fe167648b0b9085cc25" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:ac913f8403b36a2c8610bbfd25b8013488533e71e62b4b4adce9c86c8cea905b" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp311-cp311-win_arm64.whl", hash = "sha256:d4d3214a0f8394edfa3e303136d0575eece0745ff2b47bd2cb2e66dd92d4351a" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:78f7b9e5d6f2fdb88cdde9440dc147259b62b9d3b019924def9f6478be254ac1" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:229bf37d2e4acdaf808fd3f06e854a4a7a3661e871b10dc1f8f1896a3b05f18b" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f833670942247a14eafbb675458b4e61c82e002a148f49e68257b79296e865c4" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:494a5952b1c597ba44e0e78113a7266e656b9794eec897b19ead706bd7074383" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96f423a119f4777a4a056b66ce11527366a8bb92f54e541ade21f2374433f6d4" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3462dd9475af2025c31cc61be6652dfa25cbfb56cbbf52f4ccfe029f38decaf8" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4c800524c9cd9bac5166cd6f55285957fcfc907db323e193f2afcd4d9abd69b" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d6a5df73acd3399d893dafc71663ad22534b5aa4f94e8a2fabfe856c3c1b6a52" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:405e8fe955c2280ce66428b3ca55e12b3c4e9c336fb2103a4937e891c69a4a29" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:908bd3f6439f2fef9e85031b59fd4f1297af54415fb60e4254a95f75b3cab3f3" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:294e487f9ec720bd8ffcebc99d575f7eff3568a08a253d1ee1a0378754b74143" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:74c51543498289c0c43656701be6b077f4b265868fa7f8a8859c197006efb608" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:776f352e8329135506a1d6bf16ac3f87bc25b28e765949282dcc627af36123aa" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp312-cp312-win32.whl", hash = "sha256:433403ae80709741ce34038da08511d4a77062aa924baf411ef73d1146e74faf" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:34187385b08f866104f0c0617404c8eb08165ab1272e884abc89c112e9c00746" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp312-cp312-win_arm64.whl", hash = "sha256:fe3c58d2f5db5fbd18c2987cba06d51b0529f52bc3a6cdc33d3f4eab725104bd" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8d92f1a84bb12d9e56f818b3a746f3efba93c1b63c8387a73dde655e1e42282a" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:96153e77a591c8adc2ee805756c61f59fef4cf4073a9275ee86fe8cba41241f7" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f21f00a91358803399890ab167098c131ec2ddd5f8f5fd5fe9c9f2c6fcd91e40" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fb30f9626572a76dfe4293c7194a09fb1fe93ba94c7d4f720dfae3b646b45027" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eaa352d7047a31d87dafcacbabe89df0aa506abb5b1b85a2fb91bc3faa02d822" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:03ae967b4e297f58f8c774c7eabcce57fe3c2434817d4385c50661845a058121" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f6292f1de555ffcc675941d65fffffb0a5bcd992905015f85d0592201793e0e5" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29548f9b5b5e3460ce7378144c3010363d8035cea44bc0bf02d57f5a685e084e" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ec3cc8c5d4084591b4237c0a272cc4f50a5b03396a47d9caaf76f5d7b38a4f11" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:517279f58009d0b1f2e7c1b130b377a349405da3f7621ed6bfae50b10adf20c1" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:db1e72ede2d0d7ccb213f218df6a078a9c09a7de257c2fe8fcef16d5925230b1" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b4dec9482a65c54a5044486847b8a66bf10c9cb4926d42927ec4e8fd5db7fed8" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:21900c48ae04d13d416f0e1e0c4d81f7931f73a9dfa0b7a8746fb2fe7dd970ed" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313-win32.whl", hash = "sha256:8b7b94a067d1c504ee0b16def57ad5738701e4ba10cec90529f13fa03c833496" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:878be833caa6a3821caf85eb39c5ba92d28e85df26d57afb06b35b2efd937231" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313-win_arm64.whl", hash = "sha256:44389d135b3ff43ba8cc89ff7f51f5a0bb6b63d829c8300f79a2fe4fe61bcc62" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:e25ac20a2ef37e91c1b39938b591457666a0fa835c7783c3a8f33ea42870db94" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:07cdca25a91a4386d2e76ad992916a85038a9b97561bf7a3fd12d5d9ce31870c" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4e0c11f2cc6717e0a741f84a527c52616140741cd812a50422f83dc31749fb52" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b3210649ee28062ea6099cfda39e147fa1bc039583c8ee4481cb7811e2448c51" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:581ef5194c48035a7de2aefc72ac6539823bb71508189e5de01d60c9dcd5fa65" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3ef2d026f16a2b1866e1d86fc4e1291e1ed8a387b2c333809419a2f8b3a77b82" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5500ef82073f599ac84d888e3a8c1f77ac831183244bfd7f11eaa0289fb30714" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:50066c3997d0091c411a66e710f4e11752251e6d2d73d70d8d5d4c76442a199d" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:5c1c8e78426e59b3f8005e9b19f6ff46e5845895adbde20ece9218319eca6506" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:eefdba20de0d938cec6a89bd4d70f346a03108a19b9df4248d3cf0d88f1b0f51" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:cf253e0e1c3ceb4aaff6df637ce033ff6535fb8c70a764a8f46aafd3d6ab798e" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:032efa2674356903cd0261c4317a561a6850f3ac864a63fc1583147fb05a79b0" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6da155091429aeba16851ecb10a9104a108bcd32f6c1642867eadaee401c1c41" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313t-win32.whl", hash = "sha256:0f96534f8bfebc1a394209427d0f8a63d343c9779cda6fc25e8e121b5fd8555b" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5d63a068f978fc69421fb0e6eb91a9603187527c86b7cd3f534a5b77a592b888" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313t-win_arm64.whl", hash = "sha256:bf0a7e10b077bf5fb9380ad3ae8ce20ef919a6ad93b4552896419ac7e1d8e042" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:cee686f1f4cadeb2136007ddedd0aaf928ab95216e7691c63e50a8ec066336d0" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:119fb2a1bd47307e899c2fac7f28e85b9a543864df47aa7ec9d3c1b4545f096f" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4970ece02dbc8c3a92fcc5228e36a3e933a01a999f7094ff7c23fbd2beeaa67c" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:cba69cb73723c3f329622e34bdbf5ce1f80c21c290ff04256cff1cd3c2036ed2" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:778a11b15673f6f1df23d9586f83c4846c471a8af693a22e066508b77d201ec8" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0325024fe97f94c41c08872db482cf8ac4800d80e79222c6b0b7b162d5b13686" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:97260ff46b207a82a7567b581ab4190bd4dfa09f4db8a8b49d1a958f6aa4940e" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:54b2077180eb7f83dd52c40b2750d0a9f175e06a42e3213ce047219de902717a" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2f05983daecab868a31e1da44462873306d3cbfd76d1f0b5b69c473d21dbb128" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:33f48f51a446114bc5d251fb2954ab0164d5be02ad3382abcbfe07e2531d650f" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:154e55ec0655291b5dd1b8731c637ecdb50975a2ae70c606d100750a540082f7" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:4314debad13beb564b708b4a496020e5306c7333fa9a3ab90374169a20ffab30" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:073f8bf8becba60aa931eb3bc420b217bb7d5b8f4750e6f8b3be7f3da85d38b7" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314-win32.whl", hash = "sha256:bac9c42ba2ac65ddc115d930c78d24ab8d4f465fd3fc473cdedfccadb9429806" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:3e0761f4d1a44f1d1a47996511752cf3dcec5bbdd9cc2b4fe595caf97754b7a0" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314-win_arm64.whl", hash = "sha256:d1eaff1d00c7751b7c6662e9c5ba6eb2c17a2306ba5e2a37f24ddf3cc953402b" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:d3bb933317c52d7ea5004a1c442eef86f426886fba134ef8cf4226ea6ee1821d" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:8009897cdef112072f93a0efdce29cd819e717fd2f649ee3016efd3cd885a7ed" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2c5dcbbc55383e5883246d11fd179782a9d07a986c40f49abe89ddf865913930" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:39ecbc32f1390387d2aa4f5a995e465e9e2f79ba3adcac92d68e3e0afae6657c" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92db2bf818d5cc8d9c1f1fc56b897662e24ea5adb36ad1f1d82875bd64e03c24" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2dc43a022e555de94c3b68a4ef0b11c4f747d12c024a520c7101709a2144fb37" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cb89a7f2de3602cfed448095bab3f178399646ab7c61454315089787df07733a" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:33139dc858c580ea50e7e60a1b0ea003efa1fd42e6ec7fdbad78fff65fad2fd2" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:168c0969a329b416119507ba30b9ea13688fafffac1b7822802537569a1cb0ef" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:28bd570e8e189d7f7b001966435f9dac6718324b5be2990ac496cf1ea9ddb7fe" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b2a095d45c5d46e5e79ba1e5b9cb787f541a8dee0433836cea4b96a2c439dcd8" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:eab8145831a0d56ec9c4139b6c3e594c7a83c2c8be25d5bcf2d86136a532287a" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:974b28cf63cc99dfb2188d8d222bc6843656188164848c4f679e63dae4b0708e" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314t-win32.whl", hash = "sha256:342c97bf697ac5480c0a7ec73cd700ecfa5a8a40ac923bd035484616efecc2df" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:06be8f67f39c8b1dc671f5d83aaefd3358ae5cdcf8314552c57e7ed3e6475bdd" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314t-win_arm64.whl", hash = "sha256:102e6314ca4da683dca92e3b1355490fed5f313b768500084fbe6371fddfdb79" }, + { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d" }, +] + +[[package]] +name = "fsspec" +version = "2026.2.0" +source = { registry = "https://bytedpypi.byted.org/simple/" } +sdist = { url = "https://bytedpypi.byted.org/packages/fsspec/fsspec-2026.2.0.tar.gz", hash = "sha256:6544e34b16869f5aacd5b90bdf1a71acb37792ea3ddf6125ee69a22a53fb8bff" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/fsspec/fsspec-2026.2.0-py3-none-any.whl", hash = "sha256:98de475b5cb3bd66bedd5c4679e87b4fdfe1a3bf4d707b151b3c07e58c9a2437" }, +] + +[[package]] +name = "h11" +version = "0.16.0" +source = { registry = "https://bytedpypi.byted.org/simple/" } +sdist = { url = "https://bytedpypi.byted.org/packages/h11/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/h11/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86" }, +] + +[[package]] +name = "hf-xet" +version = "1.2.0" +source = { registry = "https://bytedpypi.byted.org/simple/" } +sdist = { url = "https://bytedpypi.byted.org/packages/hf-xet/hf_xet-1.2.0.tar.gz", hash = "sha256:a8c27070ca547293b6890c4bf389f713f80e8c478631432962bb7f4bc0bd7d7f" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/hf-xet/hf_xet-1.2.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:ceeefcd1b7aed4956ae8499e2199607765fbd1c60510752003b6cc0b8413b649" }, + { url = "https://bytedpypi.byted.org/packages/hf-xet/hf_xet-1.2.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b70218dd548e9840224df5638fdc94bd033552963cfa97f9170829381179c813" }, + { url = "https://bytedpypi.byted.org/packages/hf-xet/hf_xet-1.2.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d40b18769bb9a8bc82a9ede575ce1a44c75eb80e7375a01d76259089529b5dc" }, + { url = "https://bytedpypi.byted.org/packages/hf-xet/hf_xet-1.2.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:cd3a6027d59cfb60177c12d6424e31f4b5ff13d8e3a1247b3a584bf8977e6df5" }, + { url = "https://bytedpypi.byted.org/packages/hf-xet/hf_xet-1.2.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6de1fc44f58f6dd937956c8d304d8c2dea264c80680bcfa61ca4a15e7b76780f" }, + { url = "https://bytedpypi.byted.org/packages/hf-xet/hf_xet-1.2.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f182f264ed2acd566c514e45da9f2119110e48a87a327ca271027904c70c5832" }, + { url = "https://bytedpypi.byted.org/packages/hf-xet/hf_xet-1.2.0-cp313-cp313t-win_amd64.whl", hash = "sha256:293a7a3787e5c95d7be1857358a9130694a9c6021de3f27fa233f37267174382" }, + { url = "https://bytedpypi.byted.org/packages/hf-xet/hf_xet-1.2.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:10bfab528b968c70e062607f663e21e34e2bba349e8038db546646875495179e" }, + { url = "https://bytedpypi.byted.org/packages/hf-xet/hf_xet-1.2.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2a212e842647b02eb6a911187dc878e79c4aa0aa397e88dd3b26761676e8c1f8" }, + { url = "https://bytedpypi.byted.org/packages/hf-xet/hf_xet-1.2.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:30e06daccb3a7d4c065f34fc26c14c74f4653069bb2b194e7f18f17cbe9939c0" }, + { url = "https://bytedpypi.byted.org/packages/hf-xet/hf_xet-1.2.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:29c8fc913a529ec0a91867ce3d119ac1aac966e098cf49501800c870328cc090" }, + { url = "https://bytedpypi.byted.org/packages/hf-xet/hf_xet-1.2.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e159cbfcfbb29f920db2c09ed8b660eb894640d284f102ada929b6e3dc410a" }, + { url = "https://bytedpypi.byted.org/packages/hf-xet/hf_xet-1.2.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9c91d5ae931510107f148874e9e2de8a16052b6f1b3ca3c1b12f15ccb491390f" }, + { url = "https://bytedpypi.byted.org/packages/hf-xet/hf_xet-1.2.0-cp314-cp314t-win_amd64.whl", hash = "sha256:210d577732b519ac6ede149d2f2f34049d44e8622bf14eb3d63bbcd2d4b332dc" }, + { url = "https://bytedpypi.byted.org/packages/hf-xet/hf_xet-1.2.0-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:46740d4ac024a7ca9b22bebf77460ff43332868b661186a8e46c227fdae01848" }, + { url = "https://bytedpypi.byted.org/packages/hf-xet/hf_xet-1.2.0-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:27df617a076420d8845bea087f59303da8be17ed7ec0cd7ee3b9b9f579dff0e4" }, + { url = "https://bytedpypi.byted.org/packages/hf-xet/hf_xet-1.2.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3651fd5bfe0281951b988c0facbe726aa5e347b103a675f49a3fa8144c7968fd" }, + { url = "https://bytedpypi.byted.org/packages/hf-xet/hf_xet-1.2.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d06fa97c8562fb3ee7a378dd9b51e343bc5bc8190254202c9771029152f5e08c" }, + { url = "https://bytedpypi.byted.org/packages/hf-xet/hf_xet-1.2.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:4c1428c9ae73ec0939410ec73023c4f842927f39db09b063b9482dac5a3bb737" }, + { url = "https://bytedpypi.byted.org/packages/hf-xet/hf_xet-1.2.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a55558084c16b09b5ed32ab9ed38421e2d87cf3f1f89815764d1177081b99865" }, + { url = "https://bytedpypi.byted.org/packages/hf-xet/hf_xet-1.2.0-cp37-abi3-win_amd64.whl", hash = "sha256:e6584a52253f72c9f52f9e549d5895ca7a471608495c4ecaa6cc73dba2b24d69" }, +] + +[[package]] +name = "httpcore" +version = "1.0.9" +source = { registry = "https://bytedpypi.byted.org/simple/" } +dependencies = [ + { name = "certifi" }, + { name = "h11" }, +] +sdist = { url = "https://bytedpypi.byted.org/packages/httpcore/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/httpcore/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55" }, +] + +[[package]] +name = "httpx" +version = "0.28.1" +source = { registry = "https://bytedpypi.byted.org/simple/" } +dependencies = [ + { name = "anyio" }, + { name = "certifi" }, + { name = "httpcore" }, + { name = "idna" }, +] +sdist = { url = "https://bytedpypi.byted.org/packages/httpx/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/httpx/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad" }, +] + +[package.optional-dependencies] +socks = [ + { name = "socksio" }, +] + +[[package]] +name = "huggingface-hub" +version = "1.4.1" +source = { registry = "https://bytedpypi.byted.org/simple/" } +dependencies = [ + { name = "filelock" }, + { name = "fsspec" }, + { name = "hf-xet", marker = "platform_machine == 'AMD64' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64'" }, + { name = "httpx" }, + { name = "packaging" }, + { name = "pyyaml" }, + { name = "shellingham" }, + { name = "tqdm" }, + { name = "typer-slim" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://bytedpypi.byted.org/packages/huggingface-hub/huggingface_hub-1.4.1.tar.gz", hash = "sha256:b41131ec35e631e7383ab26d6146b8d8972abc8b6309b963b306fbcca87f5ed5" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/huggingface-hub/huggingface_hub-1.4.1-py3-none-any.whl", hash = "sha256:9931d075fb7a79af5abc487106414ec5fba2c0ae86104c0c62fd6cae38873d18" }, +] + +[[package]] +name = "idna" +version = "3.11" +source = { registry = "https://bytedpypi.byted.org/simple/" } +sdist = { url = "https://bytedpypi.byted.org/packages/idna/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/idna/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea" }, +] + +[[package]] +name = "importlib-metadata" +version = "8.7.1" +source = { registry = "https://bytedpypi.byted.org/simple/" } +dependencies = [ + { name = "zipp" }, +] +sdist = { url = "https://bytedpypi.byted.org/packages/importlib-metadata/importlib_metadata-8.7.1.tar.gz", hash = "sha256:49fef1ae6440c182052f407c8d34a68f72efc36db9ca90dc0113398f2fdde8bb" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/importlib-metadata/importlib_metadata-8.7.1-py3-none-any.whl", hash = "sha256:5a1f80bf1daa489495071efbb095d75a634cf28a8bc299581244063b53176151" }, +] + +[[package]] +name = "iniconfig" +version = "2.3.0" +source = { registry = "https://bytedpypi.byted.org/simple/" } +sdist = { url = "https://bytedpypi.byted.org/packages/iniconfig/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/iniconfig/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12" }, +] + +[[package]] +name = "jinja2" +version = "3.1.6" +source = { registry = "https://bytedpypi.byted.org/simple/" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://bytedpypi.byted.org/packages/jinja2/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/jinja2/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67" }, +] + +[[package]] +name = "jiter" +version = "0.13.0" +source = { registry = "https://bytedpypi.byted.org/simple/" } +sdist = { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0.tar.gz", hash = "sha256:f2839f9c2c7e2dffc1bc5929a510e14ce0a946be9365fd1219e7ef342dae14f4" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:ea026e70a9a28ebbdddcbcf0f1323128a8db66898a06eaad3a4e62d2f554d096" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:66aa3e663840152d18cc8ff1e4faad3dd181373491b9cfdc6004b92198d67911" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3524798e70655ff19aec58c7d05adb1f074fecff62da857ea9be2b908b6d701" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ec7e287d7fbd02cb6e22f9a00dd9c9cd504c40a61f2c61e7e1f9690a82726b4c" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:47455245307e4debf2ce6c6e65a717550a0244231240dcf3b8f7d64e4c2f22f4" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ee9da221dca6e0429c2704c1b3655fe7b025204a71d4d9b73390c759d776d165" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24ab43126d5e05f3d53a36a8e11eb2f23304c6c1117844aaaf9a0aa5e40b5018" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9da38b4fedde4fb528c740c2564628fbab737166a0e73d6d46cb4bb5463ff411" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0b34c519e17658ed88d5047999a93547f8889f3c1824120c26ad6be5f27b6cf5" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d2a6394e6af690d462310a86b53c47ad75ac8c21dc79f120714ea449979cb1d3" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp311-cp311-win32.whl", hash = "sha256:0f0c065695f616a27c920a56ad0d4fc46415ef8b806bf8fc1cacf25002bd24e1" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:0733312953b909688ae3c2d58d043aa040f9f1a6a75693defed7bc2cc4bf2654" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp311-cp311-win_arm64.whl", hash = "sha256:5d9b34ad56761b3bf0fbe8f7e55468704107608512350962d3317ffd7a4382d5" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:0a2bd69fc1d902e89925fc34d1da51b2128019423d7b339a45d9e99c894e0663" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f917a04240ef31898182f76a332f508f2cc4b57d2b4d7ad2dbfebbfe167eb505" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1e2b199f446d3e82246b4fd9236d7cb502dc2222b18698ba0d986d2fecc6152" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:04670992b576fa65bd056dbac0c39fe8bd67681c380cb2b48efa885711d9d726" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5a1aff1fbdb803a376d4d22a8f63f8e7ccbce0b4890c26cc7af9e501ab339ef0" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b3fb8c2053acaef8580809ac1d1f7481a0a0bdc012fd7f5d8b18fb696a5a089" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bdaba7d87e66f26a2c45d8cbadcbfc4bf7884182317907baf39cfe9775bb4d93" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7b88d649135aca526da172e48083da915ec086b54e8e73a425ba50999468cc08" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:e404ea551d35438013c64b4f357b0474c7abf9f781c06d44fcaf7a14c69ff9e2" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1f4748aad1b4a93c8bdd70f604d0f748cdc0e8744c5547798acfa52f10e79228" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp312-cp312-win32.whl", hash = "sha256:0bf670e3b1445fc4d31612199f1744f67f889ee1bbae703c4b54dc097e5dd394" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:15db60e121e11fe186c0b15236bd5d18381b9ddacdcf4e659feb96fc6c969c92" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp312-cp312-win_arm64.whl", hash = "sha256:41f92313d17989102f3cb5dd533a02787cdb99454d494344b0361355da52fcb9" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1f8a55b848cbabf97d861495cd65f1e5c590246fabca8b48e1747c4dfc8f85bf" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f556aa591c00f2c45eb1b89f68f52441a016034d18b65da60e2d2875bbbf344a" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7e1d61da332ec412350463891923f960c3073cf1aae93b538f0bb4c8cd46efb" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3097d665a27bc96fd9bbf7f86178037db139f319f785e4757ce7ccbf390db6c2" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d01ecc3a8cbdb6f25a37bd500510550b64ddf9f7d64a107d92f3ccb25035d0f" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ed9bbc30f5d60a3bdf63ae76beb3f9db280d7f195dfcfa61af792d6ce912d159" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98fbafb6e88256f4454de33c1f40203d09fc33ed19162a68b3b257b29ca7f663" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5467696f6b827f1116556cb0db620440380434591e93ecee7fd14d1a491b6daa" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:2d08c9475d48b92892583df9da592a0e2ac49bcd41fae1fec4f39ba6cf107820" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:aed40e099404721d7fcaf5b89bd3b4568a4666358bcac7b6b15c09fb6252ab68" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp313-cp313-win32.whl", hash = "sha256:36ebfbcffafb146d0e6ffb3e74d51e03d9c35ce7c625c8066cdbfc7b953bdc72" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:8d76029f077379374cf0dbc78dbe45b38dec4a2eb78b08b5194ce836b2517afc" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp313-cp313-win_arm64.whl", hash = "sha256:bb7613e1a427cfcb6ea4544f9ac566b93d5bf67e0d48c787eca673ff9c9dff2b" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:fa476ab5dd49f3bf3a168e05f89358c75a17608dbabb080ef65f96b27c19ab10" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ade8cb6ff5632a62b7dbd4757d8c5573f7a2e9ae285d6b5b841707d8363205ef" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9950290340acc1adaded363edd94baebcee7dabdfa8bee4790794cd5cfad2af6" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp313-cp313t-win_amd64.whl", hash = "sha256:2b4972c6df33731aac0742b64fd0d18e0a69bc7d6e03108ce7d40c85fd9e3e6d" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp313-cp313t-win_arm64.whl", hash = "sha256:701a1e77d1e593c1b435315ff625fd071f0998c5f02792038a5ca98899261b7d" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:cc5223ab19fe25e2f0bf2643204ad7318896fe3729bf12fde41b77bfc4fafff0" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9776ebe51713acf438fd9b4405fcd86893ae5d03487546dae7f34993217f8a91" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:879e768938e7b49b5e90b7e3fecc0dbec01b8cb89595861fb39a8967c5220d09" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:682161a67adea11e3aae9038c06c8b4a9a71023228767477d683f69903ebc607" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a13b68cd1cd8cc9de8f244ebae18ccb3e4067ad205220ef324c39181e23bbf66" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87ce0f14c6c08892b610686ae8be350bf368467b6acd5085a5b65441e2bf36d2" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c365005b05505a90d1c47856420980d0237adf82f70c4aff7aebd3c1cc143ad" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1317fdffd16f5873e46ce27d0e0f7f4f90f0cdf1d86bf6abeaea9f63ca2c401d" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:c05b450d37ba0c9e21c77fef1f205f56bcee2330bddca68d344baebfc55ae0df" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:775e10de3849d0631a97c603f996f518159272db00fdda0a780f81752255ee9d" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314-win32.whl", hash = "sha256:632bf7c1d28421c00dd8bbb8a3bac5663e1f57d5cd5ed962bce3c73bf62608e6" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314-win_amd64.whl", hash = "sha256:f22ef501c3f87ede88f23f9b11e608581c14f04db59b6a801f354397ae13739f" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314-win_arm64.whl", hash = "sha256:07b75fe09a4ee8e0c606200622e571e44943f47254f95e2436c8bdcaceb36d7d" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:964538479359059a35fb400e769295d4b315ae61e4105396d355a12f7fef09f0" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e104da1db1c0991b3eaed391ccd650ae8d947eab1480c733e5a3fb28d4313e40" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0e3a5f0cde8ff433b8e88e41aa40131455420fb3649a3c7abdda6145f8cb7202" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:57aab48f40be1db920a582b30b116fe2435d184f77f0e4226f546794cedd9cf0" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7772115877c53f62beeb8fd853cab692dbc04374ef623b30f997959a4c0e7e95" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1211427574b17b633cfceba5040de8081e5abf114f7a7602f73d2e16f9fdaa59" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7beae3a3d3b5212d3a55d2961db3c292e02e302feb43fce6a3f7a31b90ea6dfe" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:e5562a0f0e90a6223b704163ea28e831bd3a9faa3512a711f031611e6b06c939" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:6c26a424569a59140fb51160a56df13f438a2b0967365e987889186d5fc2f6f9" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314t-win32.whl", hash = "sha256:24dc96eca9f84da4131cdf87a95e6ce36765c3b156fc9ae33280873b1c32d5f6" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314t-win_amd64.whl", hash = "sha256:0a8d76c7524087272c8ae913f5d9d608bd839154b62c4322ef65723d2e5bb0b8" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314t-win_arm64.whl", hash = "sha256:2c26cf47e2cad140fa23b6d58d435a7c0161f5c514284802f25e87fddfe11024" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:b1cbfa133241d0e6bdab48dcdc2604e8ba81512f6bbd68ec3e8e1357dd3c316c" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:db367d8be9fad6e8ebbac4a7578b7af562e506211036cba2c06c3b998603c3d2" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45f6f8efb2f3b0603092401dc2df79fa89ccbc027aaba4174d2d4133ed661434" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:597245258e6ad085d064780abfb23a284d418d3e61c57362d9449c6c7317ee2d" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:3d744a6061afba08dd7ae375dcde870cffb14429b7477e10f67e9e6d68772a0a" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:ff732bd0a0e778f43d5009840f20b935e79087b4dc65bd36f1cd0f9b04b8ff7f" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ab44b178f7981fcaea7e0a5df20e773c663d06ffda0198f1a524e91b2fde7e59" }, + { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7bb00b6d26db67a05fe3e12c76edc75f32077fb51deed13822dc648fa373bc19" }, +] + +[[package]] +name = "jsonschema" +version = "4.26.0" +source = { registry = "https://bytedpypi.byted.org/simple/" } +dependencies = [ + { name = "attrs" }, + { name = "jsonschema-specifications" }, + { name = "referencing" }, + { name = "rpds-py" }, +] +sdist = { url = "https://bytedpypi.byted.org/packages/jsonschema/jsonschema-4.26.0.tar.gz", hash = "sha256:0c26707e2efad8aa1bfc5b7ce170f3fccc2e4918ff85989ba9ffa9facb2be326" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/jsonschema/jsonschema-4.26.0-py3-none-any.whl", hash = "sha256:d489f15263b8d200f8387e64b4c3a75f06629559fb73deb8fdfb525f2dab50ce" }, +] + +[[package]] +name = "jsonschema-specifications" +version = "2025.9.1" +source = { registry = "https://bytedpypi.byted.org/simple/" } +dependencies = [ + { name = "referencing" }, +] +sdist = { url = "https://bytedpypi.byted.org/packages/jsonschema-specifications/jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/jsonschema-specifications/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe" }, +] + +[[package]] +name = "lark-oapi" +version = "1.5.3" +source = { registry = "https://bytedpypi.byted.org/simple/" } +dependencies = [ + { name = "httpx" }, + { name = "pycryptodome" }, + { name = "requests" }, + { name = "requests-toolbelt" }, + { name = "websockets" }, +] +wheels = [ + { url = "https://bytedpypi.byted.org/packages/lark-oapi/lark_oapi-1.5.3-py3-none-any.whl", hash = "sha256:fda6b32bb38d21b6bdaae94979c600b94c7c521e985adade63a54e4b3e20cc36" }, +] + +[[package]] +name = "litellm" +version = "1.81.11" +source = { registry = "https://bytedpypi.byted.org/simple/" } +dependencies = [ + { name = "aiohttp" }, + { name = "click" }, + { name = "fastuuid" }, + { name = "httpx" }, + { name = "importlib-metadata" }, + { name = "jinja2" }, + { name = "jsonschema" }, + { name = "openai" }, + { name = "pydantic" }, + { name = "python-dotenv" }, + { name = "tiktoken" }, + { name = "tokenizers" }, +] +sdist = { url = "https://bytedpypi.byted.org/packages/litellm/litellm-1.81.11.tar.gz", hash = "sha256:fc55aceafda325bd5f704ada61c8be5bd322e6dfa5f8bdcab3290b8732c5857e" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/litellm/litellm-1.81.11-py3-none-any.whl", hash = "sha256:06a66c24742e082ddd2813c87f40f5c12fe7baa73ce1f9457eaf453dc44a0f65" }, +] + +[[package]] +name = "loguru" +version = "0.7.3" +source = { registry = "https://bytedpypi.byted.org/simple/" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "win32-setctime", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://bytedpypi.byted.org/packages/loguru/loguru-0.7.3.tar.gz", hash = "sha256:19480589e77d47b8d85b2c827ad95d49bf31b0dcde16593892eb51dd18706eb6" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/loguru/loguru-0.7.3-py3-none-any.whl", hash = "sha256:31a33c10c8e1e10422bfd431aeb5d351c7cf7fa671e3c4df004162264b28220c" }, +] + +[[package]] +name = "lxml" +version = "6.0.2" +source = { registry = "https://bytedpypi.byted.org/simple/" } +sdist = { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2.tar.gz", hash = "sha256:cd79f3367bd74b317dda655dc8fcfa304d9eb6e4fb06b7168c5cf27f96e0cd62" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:13e35cbc684aadf05d8711a5d1b5857c92e5e580efa9a0d2be197199c8def607" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3b1675e096e17c6fe9c0e8c81434f5736c0739ff9ac6123c87c2d452f48fc938" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8ac6e5811ae2870953390452e3476694196f98d447573234592d30488147404d" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5aa0fc67ae19d7a64c3fe725dc9a1bb11f80e01f78289d05c6f62545affec438" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:de496365750cc472b4e7902a485d3f152ecf57bd3ba03ddd5578ed8ceb4c5964" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp311-cp311-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:200069a593c5e40b8f6fc0d84d86d970ba43138c3e68619ffa234bc9bb806a4d" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp311-cp311-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7d2de809c2ee3b888b59f995625385f74629707c9355e0ff856445cdcae682b7" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:b2c3da8d93cf5db60e8858c17684c47d01fee6405e554fb55018dd85fc23b178" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp311-cp311-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:442de7530296ef5e188373a1ea5789a46ce90c4847e597856570439621d9c553" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2593c77efde7bfea7f6389f1ab249b15ed4aa5bc5cb5131faa3b843c429fbedb" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:3e3cb08855967a20f553ff32d147e14329b3ae70ced6edc2f282b94afbc74b2a" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:2ed6c667fcbb8c19c6791bbf40b7268ef8ddf5a96940ba9404b9f9a304832f6c" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b8f18914faec94132e5b91e69d76a5c1d7b0c73e2489ea8929c4aaa10b76bbf7" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp311-cp311-win32.whl", hash = "sha256:6605c604e6daa9e0d7f0a2137bdc47a2e93b59c60a65466353e37f8272f47c46" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e5867f2651016a3afd8dd2c8238baa66f1e2802f44bc17e236f547ace6647078" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp311-cp311-win_arm64.whl", hash = "sha256:4197fb2534ee05fd3e7afaab5d8bfd6c2e186f65ea7f9cd6a82809c887bd1285" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a59f5448ba2ceccd06995c95ea59a7674a10de0810f2ce90c9006f3cbc044456" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e8113639f3296706fbac34a30813929e29247718e88173ad849f57ca59754924" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:a8bef9b9825fa8bc816a6e641bb67219489229ebc648be422af695f6e7a4fa7f" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:65ea18d710fd14e0186c2f973dc60bb52039a275f82d3c44a0e42b43440ea534" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c371aa98126a0d4c739ca93ceffa0fd7a5d732e3ac66a46e74339acd4d334564" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp312-cp312-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:700efd30c0fa1a3581d80a748157397559396090a51d306ea59a70020223d16f" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c33e66d44fe60e72397b487ee92e01da0d09ba2d66df8eae42d77b6d06e5eba0" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp312-cp312-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:90a345bbeaf9d0587a3aaffb7006aa39ccb6ff0e96a57286c0cb2fd1520ea192" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:064fdadaf7a21af3ed1dcaa106b854077fbeada827c18f72aec9346847cd65d0" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp312-cp312-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fbc74f42c3525ac4ffa4b89cbdd00057b6196bcefe8bce794abd42d33a018092" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6ddff43f702905a4e32bc24f3f2e2edfe0f8fde3277d481bffb709a4cced7a1f" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:6da5185951d72e6f5352166e3da7b0dc27aa70bd1090b0eb3f7f7212b53f1bb8" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:57a86e1ebb4020a38d295c04fc79603c7899e0df71588043eb218722dabc087f" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:2047d8234fe735ab77802ce5f2297e410ff40f5238aec569ad7c8e163d7b19a6" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6f91fd2b2ea15a6800c8e24418c0775a1694eefc011392da73bc6cef2623b322" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp312-cp312-win32.whl", hash = "sha256:3ae2ce7d6fedfb3414a2b6c5e20b249c4c607f72cb8d2bb7cc9c6ec7c6f4e849" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:72c87e5ee4e58a8354fb9c7c84cbf95a1c8236c127a5d1b7683f04bed8361e1f" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp312-cp312-win_arm64.whl", hash = "sha256:61cb10eeb95570153e0c0e554f58df92ecf5109f75eacad4a95baa709e26c3d6" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9b33d21594afab46f37ae58dfadd06636f154923c4e8a4d754b0127554eb2e77" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6c8963287d7a4c5c9a432ff487c52e9c5618667179c18a204bdedb27310f022f" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1941354d92699fb5ffe6ed7b32f9649e43c2feb4b97205f75866f7d21aa91452" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bb2f6ca0ae2d983ded09357b84af659c954722bbf04dea98030064996d156048" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eb2a12d704f180a902d7fa778c6d71f36ceb7b0d317f34cdc76a5d05aa1dd1df" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp313-cp313-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:6ec0e3f745021bfed19c456647f0298d60a24c9ff86d9d051f52b509663feeb1" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:846ae9a12d54e368933b9759052d6206a9e8b250291109c48e350c1f1f49d916" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp313-cp313-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ef9266d2aa545d7374938fb5c484531ef5a2ec7f2d573e62f8ce722c735685fd" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:4077b7c79f31755df33b795dc12119cb557a0106bfdab0d2c2d97bd3cf3dffa6" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a7c5d5e5f1081955358533be077166ee97ed2571d6a66bdba6ec2f609a715d1a" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:8f8d0cbd0674ee89863a523e6994ac25fd5be9c8486acfc3e5ccea679bad2679" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:2cbcbf6d6e924c28f04a43f3b6f6e272312a090f269eff68a2982e13e5d57659" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:dfb874cfa53340009af6bdd7e54ebc0d21012a60a4e65d927c2e477112e63484" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:fb8dae0b6b8b7f9e96c26fdd8121522ce5de9bb5538010870bd538683d30e9a2" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:358d9adae670b63e95bc59747c72f4dc97c9ec58881d4627fe0120da0f90d314" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp313-cp313-win32.whl", hash = "sha256:e8cd2415f372e7e5a789d743d133ae474290a90b9023197fd78f32e2dc6873e2" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:b30d46379644fbfc3ab81f8f82ae4de55179414651f110a1514f0b1f8f6cb2d7" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp313-cp313-win_arm64.whl", hash = "sha256:13dcecc9946dca97b11b7c40d29fba63b55ab4170d3c0cf8c0c164343b9bfdcf" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:b0c732aa23de8f8aec23f4b580d1e52905ef468afb4abeafd3fec77042abb6fe" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:4468e3b83e10e0317a89a33d28f7aeba1caa4d1a6fd457d115dd4ffe90c5931d" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:abd44571493973bad4598a3be7e1d807ed45aa2adaf7ab92ab7c62609569b17d" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:370cd78d5855cfbffd57c422851f7d3864e6ae72d0da615fca4dad8c45d375a5" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:901e3b4219fa04ef766885fb40fa516a71662a4c61b80c94d25336b4934b71c0" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:a4bf42d2e4cf52c28cc1812d62426b9503cdb0c87a6de81442626aa7d69707ba" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b2c7fdaa4d7c3d886a42534adec7cfac73860b89b4e5298752f60aa5984641a0" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:98a5e1660dc7de2200b00d53fa00bcd3c35a3608c305d45a7bbcaf29fa16e83d" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:dc051506c30b609238d79eda75ee9cab3e520570ec8219844a72a46020901e37" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8799481bbdd212470d17513a54d568f44416db01250f49449647b5ab5b5dccb9" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9261bb77c2dab42f3ecd9103951aeca2c40277701eb7e912c545c1b16e0e4917" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:65ac4a01aba353cfa6d5725b95d7aed6356ddc0a3cd734de00124d285b04b64f" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:b22a07cbb82fea98f8a2fd814f3d1811ff9ed76d0fc6abc84eb21527596e7cc8" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:d759cdd7f3e055d6bc8d9bec3ad905227b2e4c785dc16c372eb5b5e83123f48a" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:945da35a48d193d27c188037a05fec5492937f66fb1958c24fc761fb9d40d43c" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314-win32.whl", hash = "sha256:be3aaa60da67e6153eb15715cc2e19091af5dc75faef8b8a585aea372507384b" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314-win_amd64.whl", hash = "sha256:fa25afbadead523f7001caf0c2382afd272c315a033a7b06336da2637d92d6ed" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314-win_arm64.whl", hash = "sha256:063eccf89df5b24e361b123e257e437f9e9878f425ee9aae3144c77faf6da6d8" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:6162a86d86893d63084faaf4ff937b3daea233e3682fb4474db07395794fa80d" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:414aaa94e974e23a3e92e7ca5b97d10c0cf37b6481f50911032c69eeb3991bba" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:48461bd21625458dd01e14e2c38dd0aea69addc3c4f960c30d9f59d7f93be601" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:25fcc59afc57d527cfc78a58f40ab4c9b8fd096a9a3f964d2781ffb6eb33f4ed" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5179c60288204e6ddde3f774a93350177e08876eaf3ab78aa3a3649d43eb7d37" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314t-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:967aab75434de148ec80597b75062d8123cadf2943fb4281f385141e18b21338" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d100fcc8930d697c6561156c6810ab4a508fb264c8b6779e6e61e2ed5e7558f9" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2ca59e7e13e5981175b8b3e4ab84d7da57993eeff53c07764dcebda0d0e64ecd" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:957448ac63a42e2e49531b9d6c0fa449a1970dbc32467aaad46f11545be9af1d" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314t-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b7fc49c37f1786284b12af63152fe1d0990722497e2d5817acfe7a877522f9a9" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e19e0643cc936a22e837f79d01a550678da8377d7d801a14487c10c34ee49c7e" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:1db01e5cf14345628e0cbe71067204db658e2fb8e51e7f33631f5f4735fefd8d" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:875c6b5ab39ad5291588aed6925fac99d0097af0dd62f33c7b43736043d4a2ec" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:cdcbed9ad19da81c480dfd6dd161886db6096083c9938ead313d94b30aadf272" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:80dadc234ebc532e09be1975ff538d154a7fa61ea5031c03d25178855544728f" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314t-win32.whl", hash = "sha256:da08e7bb297b04e893d91087df19638dc7a6bb858a954b0cc2b9f5053c922312" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314t-win_amd64.whl", hash = "sha256:252a22982dca42f6155125ac76d3432e548a7625d56f5a273ee78a5057216eca" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314t-win_arm64.whl", hash = "sha256:bb4c1847b303835d89d785a18801a883436cdfd5dc3d62947f9c49e24f0f5a2c" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:1c06035eafa8404b5cf475bb37a9f6088b0aca288d4ccc9d69389750d5543700" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c7d13103045de1bdd6fe5d61802565f1a3537d70cd3abf596aa0af62761921ee" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0a3c150a95fbe5ac91de323aa756219ef9cf7fde5a3f00e2281e30f33fa5fa4f" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:60fa43be34f78bebb27812ed90f1925ec99560b0fa1decdb7d12b84d857d31e9" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-pp311-pypy311_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:21c73b476d3cfe836be731225ec3421fa2f048d84f6df6a8e70433dff1376d5a" }, + { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:27220da5be049e936c3aca06f174e8827ca6445a4353a1995584311487fc4e3e" }, +] + +[package.optional-dependencies] +html-clean = [ + { name = "lxml-html-clean" }, +] + +[[package]] +name = "lxml-html-clean" +version = "0.4.3" +source = { registry = "https://bytedpypi.byted.org/simple/" } +dependencies = [ + { name = "lxml" }, +] +sdist = { url = "https://bytedpypi.byted.org/packages/lxml-html-clean/lxml_html_clean-0.4.3.tar.gz", hash = "sha256:c9df91925b00f836c807beab127aac82575110eacff54d0a75187914f1bd9d8c" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/lxml-html-clean/lxml_html_clean-0.4.3-py3-none-any.whl", hash = "sha256:63fd7b0b9c3a2e4176611c2ca5d61c4c07ffca2de76c14059a81a2825833731e" }, +] + +[[package]] +name = "markdown-it-py" +version = "4.0.0" +source = { registry = "https://bytedpypi.byted.org/simple/" } +dependencies = [ + { name = "mdurl" }, +] +sdist = { url = "https://bytedpypi.byted.org/packages/markdown-it-py/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/markdown-it-py/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147" }, +] + +[[package]] +name = "markupsafe" +version = "3.0.3" +source = { registry = "https://bytedpypi.byted.org/simple/" } +sdist = { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp311-cp311-win32.whl", hash = "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9" }, + { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa" }, +] + +[[package]] +name = "mdurl" +version = "0.1.2" +source = { registry = "https://bytedpypi.byted.org/simple/" } +sdist = { url = "https://bytedpypi.byted.org/packages/mdurl/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/mdurl/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8" }, +] + +[[package]] +name = "multidict" +version = "6.7.1" +source = { registry = "https://bytedpypi.byted.org/simple/" } +sdist = { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1.tar.gz", hash = "sha256:ec6652a1bee61c53a3e5776b6049172c53b6aaba34f18c9ad04f82712bac623d" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7ff981b266af91d7b4b3793ca3382e53229088d193a85dfad6f5f4c27fc73e5d" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:844c5bca0b5444adb44a623fb0a1310c2f4cd41f402126bb269cd44c9b3f3e1e" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f2a0a924d4c2e9afcd7ec64f9de35fcd96915149b2216e1cb2c10a56df483855" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:8be1802715a8e892c784c0197c2ace276ea52702a0ede98b6310c8f255a5afb3" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2e2d2ed645ea29f31c4c7ea1552fcfd7cb7ba656e1eafd4134a6620c9f5fdd9e" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:95922cee9a778659e91db6497596435777bd25ed116701a4c034f8e46544955a" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6b83cabdc375ffaaa15edd97eb7c0c672ad788e2687004990074d7d6c9b140c8" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:38fb49540705369bab8484db0689d86c0a33a0a9f2c1b197f506b71b4b6c19b0" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:439cbebd499f92e9aa6793016a8acaa161dfa749ae86d20960189f5398a19144" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6d3bc717b6fe763b8be3f2bee2701d3c8eb1b2a8ae9f60910f1b2860c82b6c49" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:619e5a1ac57986dbfec9f0b301d865dddf763696435e2962f6d9cf2fdff2bb71" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0b38ebffd9be37c1170d33bc0f36f4f262e0a09bc1aac1c34c7aa51a7293f0b3" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:10ae39c9cfe6adedcdb764f5e8411d4a92b055e35573a2eaa88d3323289ef93c" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:25167cc263257660290fba06b9318d2026e3c910be240a146e1f66dd114af2b0" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:128441d052254f42989ef98b7b6a6ecb1e6f708aa962c7984235316db59f50fa" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp311-cp311-win32.whl", hash = "sha256:d62b7f64ffde3b99d06b707a280db04fb3855b55f5a06df387236051d0668f4a" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:bdbf9f3b332abd0cdb306e7c2113818ab1e922dc84b8f8fd06ec89ed2a19ab8b" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp311-cp311-win_arm64.whl", hash = "sha256:b8c990b037d2fff2f4e33d3f21b9b531c5745b33a49a7d6dbe7a177266af44f6" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a90f75c956e32891a4eda3639ce6dd86e87105271f43d43442a3aedf3cddf172" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3fccb473e87eaa1382689053e4a4618e7ba7b9b9b8d6adf2027ee474597128cd" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b0fa96985700739c4c7853a43c0b3e169360d6855780021bfc6d0f1ce7c123e7" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:cb2a55f408c3043e42b40cc8eecd575afa27b7e0b956dfb190de0f8499a57a53" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eb0ce7b2a32d09892b3dd6cc44877a0d02a33241fafca5f25c8b6b62374f8b75" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c3a32d23520ee37bf327d1e1a656fec76a2edd5c038bf43eddfa0572ec49c60b" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9c90fed18bffc0189ba814749fdcc102b536e83a9f738a9003e569acd540a733" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:da62917e6076f512daccfbbde27f46fed1c98fee202f0559adec8ee0de67f71a" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bfde23ef6ed9db7eaee6c37dcec08524cb43903c60b285b172b6c094711b3961" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3758692429e4e32f1ba0df23219cd0b4fc0a52f476726fff9337d1a57676a582" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:398c1478926eca669f2fd6a5856b6de9c0acf23a2cb59a14c0ba5844fa38077e" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c102791b1c4f3ab36ce4101154549105a53dc828f016356b3e3bcae2e3a039d3" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a088b62bd733e2ad12c50dad01b7d0166c30287c166e137433d3b410add807a6" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3d51ff4785d58d3f6c91bdbffcb5e1f7ddfda557727043aa20d20ec4f65e324a" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fc5907494fccf3e7d3f94f95c91d6336b092b5fc83811720fae5e2765890dfba" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp312-cp312-win32.whl", hash = "sha256:28ca5ce2fd9716631133d0e9a9b9a745ad7f60bac2bccafb56aa380fc0b6c511" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcee94dfbd638784645b066074b338bc9cc155d4b4bffa4adce1615c5a426c19" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp312-cp312-win_arm64.whl", hash = "sha256:ba0a9fb644d0c1a2194cf7ffb043bd852cea63a57f66fbd33959f7dae18517bf" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:2b41f5fed0ed563624f1c17630cb9941cf2309d4df00e494b551b5f3e3d67a23" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:84e61e3af5463c19b67ced91f6c634effb89ef8bfc5ca0267f954451ed4bb6a2" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:935434b9853c7c112eee7ac891bc4cb86455aa631269ae35442cb316790c1445" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:432feb25a1cb67fe82a9680b4d65fb542e4635cb3166cd9c01560651ad60f177" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e82d14e3c948952a1a85503817e038cba5905a3352de76b9a465075d072fba23" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4cfb48c6ea66c83bcaaf7e4dfa7ec1b6bbcf751b7db85a328902796dfde4c060" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1d540e51b7e8e170174555edecddbd5538105443754539193e3e1061864d444d" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:273d23f4b40f3dce4d6c8a821c741a86dec62cded82e1175ba3d99be128147ed" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d624335fd4fa1c08a53f8b4be7676ebde19cd092b3895c421045ca87895b429" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:12fad252f8b267cc75b66e8fc51b3079604e8d43a75428ffe193cd9e2195dfd6" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:03ede2a6ffbe8ef936b92cb4529f27f42be7f56afcdab5ab739cd5f27fb1cbf9" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:90efbcf47dbe33dcf643a1e400d67d59abeac5db07dc3f27d6bdeae497a2198c" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:5c4b9bfc148f5a91be9244d6264c53035c8a0dcd2f51f1c3c6e30e30ebaa1c84" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:401c5a650f3add2472d1d288c26deebc540f99e2fb83e9525007a74cd2116f1d" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:97891f3b1b3ffbded884e2916cacf3c6fc87b66bb0dde46f7357404750559f33" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313-win32.whl", hash = "sha256:e1c5988359516095535c4301af38d8a8838534158f649c05dd1050222321bcb3" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313-win_amd64.whl", hash = "sha256:960c83bf01a95b12b08fd54324a4eb1d5b52c88932b5cba5d6e712bb3ed12eb5" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313-win_arm64.whl", hash = "sha256:563fe25c678aaba333d5399408f5ec3c383ca5b663e7f774dd179a520b8144df" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:c76c4bec1538375dad9d452d246ca5368ad6e1c9039dadcf007ae59c70619ea1" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:57b46b24b5d5ebcc978da4ec23a819a9402b4228b8a90d9c656422b4bdd8a963" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e954b24433c768ce78ab7929e84ccf3422e46deb45a4dc9f93438f8217fa2d34" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3bd231490fa7217cc832528e1cd8752a96f0125ddd2b5749390f7c3ec8721b65" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:253282d70d67885a15c8a7716f3a73edf2d635793ceda8173b9ecc21f2fb8292" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0b4c48648d7649c9335cf1927a8b87fa692de3dcb15faa676c6a6f1f1aabda43" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:98bc624954ec4d2c7cb074b8eefc2b5d0ce7d482e410df446414355d158fe4ca" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1b99af4d9eec0b49927b4402bcbb58dea89d3e0db8806a4086117019939ad3dd" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6aac4f16b472d5b7dc6f66a0d49dd57b0e0902090be16594dc9ebfd3d17c47e7" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:21f830fe223215dffd51f538e78c172ed7c7f60c9b96a2bf05c4848ad49921c3" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f5dd81c45b05518b9aa4da4aa74e1c93d715efa234fd3e8a179df611cc85e5f4" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:eb304767bca2bb92fb9c5bd33cedc95baee5bb5f6c88e63706533a1c06ad08c8" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:c9035dde0f916702850ef66460bc4239d89d08df4d02023a5926e7446724212c" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:af959b9beeb66c822380f222f0e0a1889331597e81f1ded7f374f3ecb0fd6c52" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:41f2952231456154ee479651491e94118229844dd7226541788be783be2b5108" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313t-win32.whl", hash = "sha256:df9f19c28adcb40b6aae30bbaa1478c389efd50c28d541d76760199fc1037c32" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313t-win_amd64.whl", hash = "sha256:d54ecf9f301853f2c5e802da559604b3e95bb7a3b01a9c295c6ee591b9882de8" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313t-win_arm64.whl", hash = "sha256:5a37ca18e360377cfda1d62f5f382ff41f2b8c4ccb329ed974cc2e1643440118" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8f333ec9c5eb1b7105e3b84b53141e66ca05a19a605368c55450b6ba208cb9ee" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:a407f13c188f804c759fc6a9f88286a565c242a76b27626594c133b82883b5c2" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0e161ddf326db5577c3a4cc2d8648f81456e8a20d40415541587a71620d7a7d1" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1e3a8bb24342a8201d178c3b4984c26ba81a577c80d4d525727427460a50c22d" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97231140a50f5d447d3164f994b86a0bed7cd016e2682f8650d6a9158e14fd31" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6b10359683bd8806a200fd2909e7c8ca3a7b24ec1d8132e483d58e791d881048" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:283ddac99f7ac25a4acadbf004cb5ae34480bbeb063520f70ce397b281859362" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:538cec1e18c067d0e6103aa9a74f9e832904c957adc260e61cd9d8cf0c3b3d37" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7eee46ccb30ff48a1e35bb818cc90846c6be2b68240e42a78599166722cea709" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fa263a02f4f2dd2d11a7b1bb4362aa7cb1049f84a9235d31adf63f30143469a0" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:2e1425e2f99ec5bd36c15a01b690a1a2456209c5deed58f95469ffb46039ccbb" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:497394b3239fc6f0e13a78a3e1b61296e72bf1c5f94b4c4eb80b265c37a131cd" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:233b398c29d3f1b9676b4b6f75c518a06fcb2ea0b925119fb2c1bc35c05e1601" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:93b1818e4a6e0930454f0f2af7dfce69307ca03cdcfb3739bf4d91241967b6c1" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f33dc2a3abe9249ea5d8360f969ec7f4142e7ac45ee7014d8f8d5acddf178b7b" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314-win32.whl", hash = "sha256:3ab8b9d8b75aef9df299595d5388b14530839f6422333357af1339443cff777d" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314-win_amd64.whl", hash = "sha256:5e01429a929600e7dab7b166062d9bb54a5eed752384c7384c968c2afab8f50f" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314-win_arm64.whl", hash = "sha256:4885cb0e817aef5d00a2e8451d4665c1808378dc27c2705f1bf4ef8505c0d2e5" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:0458c978acd8e6ea53c81eefaddbbee9c6c5e591f41b3f5e8e194780fe026581" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:c0abd12629b0af3cf590982c0b413b1e7395cd4ec026f30986818ab95bfaa94a" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:14525a5f61d7d0c94b368a42cff4c9a4e7ba2d52e2672a7b23d84dc86fb02b0c" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:17307b22c217b4cf05033dabefe68255a534d637c6c9b0cc8382718f87be4262" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a7e590ff876a3eaf1c02a4dfe0724b6e69a9e9de6d8f556816f29c496046e59" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:5fa6a95dfee63893d80a34758cd0e0c118a30b8dcb46372bf75106c591b77889" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a0543217a6a017692aa6ae5cc39adb75e587af0f3a82288b1492eb73dd6cc2a4" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f99fe611c312b3c1c0ace793f92464d8cd263cc3b26b5721950d977b006b6c4d" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9004d8386d133b7e6135679424c91b0b854d2d164af6ea3f289f8f2761064609" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e628ef0e6859ffd8273c69412a2465c4be4a9517d07261b33334b5ec6f3c7489" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:841189848ba629c3552035a6a7f5bf3b02eb304e9fea7492ca220a8eda6b0e5c" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:ce1bbd7d780bb5a0da032e095c951f7014d6b0a205f8318308140f1a6aba159e" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b26684587228afed0d50cf804cc71062cc9c1cdf55051c4c6345d372947b268c" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:9f9af11306994335398293f9958071019e3ab95e9a707dc1383a35613f6abcb9" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b4938326284c4f1224178a560987b6cf8b4d38458b113d9b8c1db1a836e640a2" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314t-win32.whl", hash = "sha256:98655c737850c064a65e006a3df7c997cd3b220be4ec8fe26215760b9697d4d7" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314t-win_amd64.whl", hash = "sha256:497bde6223c212ba11d462853cfa4f0ae6ef97465033e7dc9940cdb3ab5b48e5" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314t-win_arm64.whl", hash = "sha256:2bbd113e0d4af5db41d5ebfe9ccaff89de2120578164f86a5d17d5a576d1e5b2" }, + { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-py3-none-any.whl", hash = "sha256:55d97cc6dae627efa6a6e548885712d4864b81110ac76fa4e534c03819fa4a56" }, +] + +[[package]] +name = "nanobot-ai" +version = "0.1.3.post5" +source = { editable = "." } +dependencies = [ + { name = "croniter" }, + { name = "dingtalk-stream" }, + { name = "httpx" }, + { name = "lark-oapi" }, + { name = "litellm" }, + { name = "loguru" }, + { name = "oauth-cli-kit" }, + { name = "pydantic" }, + { name = "pydantic-settings" }, + { name = "python-telegram-bot", extra = ["socks"] }, + { name = "qq-botpy" }, + { name = "readability-lxml" }, + { name = "rich" }, + { name = "slack-sdk" }, + { name = "socksio" }, + { name = "typer" }, + { name = "websocket-client" }, + { name = "websockets" }, +] + +[package.optional-dependencies] +dev = [ + { name = "pytest" }, + { name = "pytest-asyncio" }, + { name = "ruff" }, +] + +[package.metadata] +requires-dist = [ + { name = "croniter", specifier = ">=2.0.0" }, + { name = "dingtalk-stream", specifier = ">=0.4.0" }, + { name = "httpx", specifier = ">=0.25.0" }, + { name = "lark-oapi", specifier = ">=1.0.0" }, + { name = "litellm", specifier = ">=1.0.0" }, + { name = "loguru", specifier = ">=0.7.0" }, + { name = "oauth-cli-kit", specifier = ">=0.1.1" }, + { name = "pydantic", specifier = ">=2.0.0" }, + { name = "pydantic-settings", specifier = ">=2.0.0" }, + { name = "pytest", marker = "extra == 'dev'", specifier = ">=7.0.0" }, + { name = "pytest-asyncio", marker = "extra == 'dev'", specifier = ">=0.21.0" }, + { name = "python-telegram-bot", extras = ["socks"], specifier = ">=21.0" }, + { name = "qq-botpy", specifier = ">=1.0.0" }, + { name = "readability-lxml", specifier = ">=0.8.0" }, + { name = "rich", specifier = ">=13.0.0" }, + { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.1.0" }, + { name = "slack-sdk", specifier = ">=3.26.0" }, + { name = "socksio", specifier = ">=1.0.0" }, + { name = "typer", specifier = ">=0.9.0" }, + { name = "websocket-client", specifier = ">=1.6.0" }, + { name = "websockets", specifier = ">=12.0" }, +] +provides-extras = ["dev"] + +[[package]] +name = "oauth-cli-kit" +version = "0.1.1" +source = { registry = "https://bytedpypi.byted.org/simple/" } +dependencies = [ + { name = "httpx" }, + { name = "platformdirs" }, +] +sdist = { url = "https://bytedpypi.byted.org/packages/oauth-cli-kit/oauth_cli_kit-0.1.1.tar.gz", hash = "sha256:6a13f9b9ca738115e46314fff87506887603a21888527d1c0c9e420bc9401925" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/oauth-cli-kit/oauth_cli_kit-0.1.1-py3-none-any.whl", hash = "sha256:4b74633847c24ae677cf404bddd491b92e4ca99b1f7cb6bc5d67a3167e9b9910" }, +] + +[[package]] +name = "openai" +version = "2.20.0" +source = { registry = "https://bytedpypi.byted.org/simple/" } +dependencies = [ + { name = "anyio" }, + { name = "distro" }, + { name = "httpx" }, + { name = "jiter" }, + { name = "pydantic" }, + { name = "sniffio" }, + { name = "tqdm" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://bytedpypi.byted.org/packages/openai/openai-2.20.0.tar.gz", hash = "sha256:2654a689208cd0bf1098bb9462e8d722af5cbe961e6bba54e6f19fb843d88db1" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/openai/openai-2.20.0-py3-none-any.whl", hash = "sha256:38d989c4b1075cd1f76abc68364059d822327cf1a932531d429795f4fc18be99" }, +] + +[[package]] +name = "packaging" +version = "26.0" +source = { registry = "https://bytedpypi.byted.org/simple/" } +sdist = { url = "https://bytedpypi.byted.org/packages/packaging/packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/packaging/packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529" }, +] + +[[package]] +name = "platformdirs" +version = "4.7.0" +source = { registry = "https://bytedpypi.byted.org/simple/" } +sdist = { url = "https://bytedpypi.byted.org/packages/platformdirs/platformdirs-4.7.0.tar.gz", hash = "sha256:fd1a5f8599c85d49b9ac7d6e450bc2f1aaf4a23f1fe86d09952fe20ad365cf36" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/platformdirs/platformdirs-4.7.0-py3-none-any.whl", hash = "sha256:1ed8db354e344c5bb6039cd727f096af975194b508e37177719d562b2b540ee6" }, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://bytedpypi.byted.org/simple/" } +sdist = { url = "https://bytedpypi.byted.org/packages/pluggy/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/pluggy/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746" }, +] + +[[package]] +name = "propcache" +version = "0.4.1" +source = { registry = "https://bytedpypi.byted.org/simple/" } +sdist = { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1.tar.gz", hash = "sha256:f48107a8c637e80362555f37ecf49abe20370e557cc4ab374f04ec4423c97c3d" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:60a8fda9644b7dfd5dece8c61d8a85e271cb958075bfc4e01083c148b61a7caf" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c30b53e7e6bda1d547cabb47c825f3843a0a1a42b0496087bb58d8fedf9f41b5" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6918ecbd897443087a3b7cd978d56546a812517dcaaca51b49526720571fa93e" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3d902a36df4e5989763425a8ab9e98cd8ad5c52c823b34ee7ef307fd50582566" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a9695397f85973bb40427dedddf70d8dc4a44b22f1650dd4af9eedf443d45165" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2bb07ffd7eaad486576430c89f9b215f9e4be68c4866a96e97db9e97fead85dc" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fd6f30fdcf9ae2a70abd34da54f18da086160e4d7d9251f81f3da0ff84fc5a48" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fc38cba02d1acba4e2869eef1a57a43dfbd3d49a59bf90dda7444ec2be6a5570" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:67fad6162281e80e882fb3ec355398cf72864a54069d060321f6cd0ade95fe85" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f10207adf04d08bec185bae14d9606a1444715bc99180f9331c9c02093e1959e" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e9b0d8d0845bbc4cfcdcbcdbf5086886bc8157aa963c31c777ceff7846c77757" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:981333cb2f4c1896a12f4ab92a9cc8f09ea664e9b7dbdc4eff74627af3a11c0f" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp311-cp311-win32.whl", hash = "sha256:f1d2f90aeec838a52f1c1a32fe9a619fefd5e411721a9117fbf82aea638fe8a1" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:364426a62660f3f699949ac8c621aad6977be7126c5807ce48c0aeb8e7333ea6" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:e53f3a38d3510c11953f3e6a33f205c6d1b001129f972805ca9b42fc308bc239" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e153e9cd40cc8945138822807139367f256f89c6810c2634a4f6902b52d3b4e2" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cd547953428f7abb73c5ad82cbb32109566204260d98e41e5dfdc682eb7f8403" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f048da1b4f243fc44f205dfd320933a951b8d89e0afd4c7cacc762a8b9165207" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ec17c65562a827bba85e3872ead335f95405ea1674860d96483a02f5c698fa72" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:405aac25c6394ef275dee4c709be43745d36674b223ba4eb7144bf4d691b7367" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0013cb6f8dde4b2a2f66903b8ba740bdfe378c943c4377a200551ceb27f379e4" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:15932ab57837c3368b024473a525e25d316d8353016e7cc0e5ba9eb343fbb1cf" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:031dce78b9dc099f4c29785d9cf5577a3faf9ebf74ecbd3c856a7b92768c3df3" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ab08df6c9a035bee56e31af99be621526bd237bea9f32def431c656b29e41778" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4d7af63f9f93fe593afbf104c21b3b15868efb2c21d07d8732c0c4287e66b6a6" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:cfc27c945f422e8b5071b6e93169679e4eb5bf73bbcbf1ba3ae3a83d2f78ebd9" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:35c3277624a080cc6ec6f847cbbbb5b49affa3598c4535a0a4682a697aaa5c75" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp312-cp312-win32.whl", hash = "sha256:671538c2262dadb5ba6395e26c1731e1d52534bfe9ae56d0b5573ce539266aa8" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:cb2d222e72399fcf5890d1d5cc1060857b9b236adff2792ff48ca2dfd46c81db" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:204483131fb222bdaaeeea9f9e6c6ed0cac32731f75dfc1d4a567fc1926477c1" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:43eedf29202c08550aac1d14e0ee619b0430aaef78f85864c1a892294fbc28cf" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d62cdfcfd89ccb8de04e0eda998535c406bf5e060ffd56be6c586cbcc05b3311" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cae65ad55793da34db5f54e4029b89d3b9b9490d8abe1b4c7ab5d4b8ec7ebf74" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:333ddb9031d2704a301ee3e506dc46b1fe5f294ec198ed6435ad5b6a085facfe" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:fd0858c20f078a32cf55f7e81473d96dcf3b93fd2ccdb3d40fdf54b8573df3af" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:678ae89ebc632c5c204c794f8dab2837c5f159aeb59e6ed0539500400577298c" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d472aeb4fbf9865e0c6d622d7f4d54a4e101a89715d8904282bb5f9a2f476c3f" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4d3df5fa7e36b3225954fba85589da77a0fe6a53e3976de39caf04a0db4c36f1" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:ee17f18d2498f2673e432faaa71698032b0127ebf23ae5974eeaf806c279df24" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:580e97762b950f993ae618e167e7be9256b8353c2dcd8b99ec100eb50f5286aa" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:501d20b891688eb8e7aa903021f0b72d5a55db40ffaab27edefd1027caaafa61" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a0bd56e5b100aef69bd8562b74b46254e7c8812918d3baa700c8a8009b0af66" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313-win32.whl", hash = "sha256:bcc9aaa5d80322bc2fb24bb7accb4a30f81e90ab8d6ba187aec0744bc302ad81" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:381914df18634f5494334d201e98245c0596067504b9372d8cf93f4bb23e025e" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:8873eb4460fd55333ea49b7d189749ecf6e55bf85080f11b1c4530ed3034cba1" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:92d1935ee1f8d7442da9c0c4fa7ac20d07e94064184811b685f5c4fada64553b" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:473c61b39e1460d386479b9b2f337da492042447c9b685f28be4f74d3529e566" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c0ef0aaafc66fbd87842a3fe3902fd889825646bc21149eafe47be6072725835" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f95393b4d66bfae908c3ca8d169d5f79cd65636ae15b5e7a4f6e67af675adb0e" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c07fda85708bc48578467e85099645167a955ba093be0a2dcba962195676e859" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:af223b406d6d000830c6f65f1e6431783fc3f713ba3e6cc8c024d5ee96170a4b" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a78372c932c90ee474559c5ddfffd718238e8673c340dc21fe45c5b8b54559a0" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:564d9f0d4d9509e1a870c920a89b2fec951b44bf5ba7d537a9e7c1ccec2c18af" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:17612831fda0138059cc5546f4d12a2aacfb9e47068c06af35c400ba58ba7393" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:41a89040cb10bd345b3c1a873b2bf36413d48da1def52f268a055f7398514874" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e35b88984e7fa64aacecea39236cee32dd9bd8c55f57ba8a75cf2399553f9bd7" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6f8b465489f927b0df505cbe26ffbeed4d6d8a2bbc61ce90eb074ff129ef0ab1" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313t-win32.whl", hash = "sha256:2ad890caa1d928c7c2965b48f3a3815c853180831d0e5503d35cf00c472f4717" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313t-win_amd64.whl", hash = "sha256:f7ee0e597f495cf415bcbd3da3caa3bd7e816b74d0d52b8145954c5e6fd3ff37" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313t-win_arm64.whl", hash = "sha256:929d7cbe1f01bb7baffb33dc14eb5691c95831450a26354cd210a8155170c93a" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3f7124c9d820ba5548d431afb4632301acf965db49e666aa21c305cbe8c6de12" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:c0d4b719b7da33599dfe3b22d3db1ef789210a0597bc650b7cee9c77c2be8c5c" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9f302f4783709a78240ebc311b793f123328716a60911d667e0c036bc5dcbded" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c80ee5802e3fb9ea37938e7eecc307fb984837091d5fd262bb37238b1ae97641" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ed5a841e8bb29a55fb8159ed526b26adc5bdd7e8bd7bf793ce647cb08656cdf4" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:55c72fd6ea2da4c318e74ffdf93c4fe4e926051133657459131a95c846d16d44" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8326e144341460402713f91df60ade3c999d601e7eb5ff8f6f7862d54de0610d" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:060b16ae65bc098da7f6d25bf359f1f31f688384858204fe5d652979e0015e5b" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:89eb3fa9524f7bec9de6e83cf3faed9d79bffa560672c118a96a171a6f55831e" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:dee69d7015dc235f526fe80a9c90d65eb0039103fe565776250881731f06349f" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:5558992a00dfd54ccbc64a32726a3357ec93825a418a401f5cc67df0ac5d9e49" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c9b822a577f560fbd9554812526831712c1436d2c046cedee4c3796d3543b144" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314-win32.whl", hash = "sha256:ab4c29b49d560fe48b696cdcb127dd36e0bc2472548f3bf56cc5cb3da2b2984f" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:5a103c3eb905fcea0ab98be99c3a9a5ab2de60228aa5aceedc614c0281cf6153" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:74c1fb26515153e482e00177a1ad654721bf9207da8a494a0c05e797ad27b992" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:824e908bce90fb2743bd6b59db36eb4f45cd350a39637c9f73b1c1ea66f5b75f" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:c2b5e7db5328427c57c8e8831abda175421b709672f6cfc3d630c3b7e2146393" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6f6ff873ed40292cd4969ef5310179afd5db59fdf055897e282485043fc80ad0" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:49a2dc67c154db2c1463013594c458881a069fcf98940e61a0569016a583020a" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:005f08e6a0529984491e37d8dbc3dd86f84bd78a8ceb5fa9a021f4c48d4984be" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5c3310452e0d31390da9035c348633b43d7e7feb2e37be252be6da45abd1abcc" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c3c70630930447f9ef1caac7728c8ad1c56bc5015338b20fed0d08ea2480b3a" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8e57061305815dfc910a3634dcf584f08168a8836e6999983569f51a8544cd89" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:521a463429ef54143092c11a77e04056dd00636f72e8c45b70aaa3140d639726" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:120c964da3fdc75e3731aa392527136d4ad35868cc556fd09bb6d09172d9a367" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:d8f353eb14ee3441ee844ade4277d560cdd68288838673273b978e3d6d2c8f36" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ab2943be7c652f09638800905ee1bab2c544e537edb57d527997a24c13dc1455" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314t-win32.whl", hash = "sha256:05674a162469f31358c30bcaa8883cb7829fa3110bf9c0991fe27d7896c42d85" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:990f6b3e2a27d683cb7602ed6c86f15ee6b43b1194736f9baaeb93d0016633b1" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:ecef2343af4cc68e05131e45024ba34f6095821988a9d0a02aa7c73fcc448aa9" }, + { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237" }, +] + +[[package]] +name = "pycryptodome" +version = "3.23.0" +source = { registry = "https://bytedpypi.byted.org/simple/" } +sdist = { url = "https://bytedpypi.byted.org/packages/pycryptodome/pycryptodome-3.23.0.tar.gz", hash = "sha256:447700a657182d60338bab09fdb27518f8856aecd80ae4c6bdddb67ff5da44ef" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/pycryptodome/pycryptodome-3.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:0011f7f00cdb74879142011f95133274741778abba114ceca229adbf8e62c3e4" }, + { url = "https://bytedpypi.byted.org/packages/pycryptodome/pycryptodome-3.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:90460fc9e088ce095f9ee8356722d4f10f86e5be06e2354230a9880b9c549aae" }, + { url = "https://bytedpypi.byted.org/packages/pycryptodome/pycryptodome-3.23.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4764e64b269fc83b00f682c47443c2e6e85b18273712b98aa43bcb77f8570477" }, + { url = "https://bytedpypi.byted.org/packages/pycryptodome/pycryptodome-3.23.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb8f24adb74984aa0e5d07a2368ad95276cf38051fe2dc6605cbcf482e04f2a7" }, + { url = "https://bytedpypi.byted.org/packages/pycryptodome/pycryptodome-3.23.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d97618c9c6684a97ef7637ba43bdf6663a2e2e77efe0f863cce97a76af396446" }, + { url = "https://bytedpypi.byted.org/packages/pycryptodome/pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9a53a4fe5cb075075d515797d6ce2f56772ea7e6a1e5e4b96cf78a14bac3d265" }, + { url = "https://bytedpypi.byted.org/packages/pycryptodome/pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:763d1d74f56f031788e5d307029caef067febf890cd1f8bf61183ae142f1a77b" }, + { url = "https://bytedpypi.byted.org/packages/pycryptodome/pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:954af0e2bd7cea83ce72243b14e4fb518b18f0c1649b576d114973e2073b273d" }, + { url = "https://bytedpypi.byted.org/packages/pycryptodome/pycryptodome-3.23.0-cp313-cp313t-win32.whl", hash = "sha256:257bb3572c63ad8ba40b89f6fc9d63a2a628e9f9708d31ee26560925ebe0210a" }, + { url = "https://bytedpypi.byted.org/packages/pycryptodome/pycryptodome-3.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:6501790c5b62a29fcb227bd6b62012181d886a767ce9ed03b303d1f22eb5c625" }, + { url = "https://bytedpypi.byted.org/packages/pycryptodome/pycryptodome-3.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:9a77627a330ab23ca43b48b130e202582e91cc69619947840ea4d2d1be21eb39" }, + { url = "https://bytedpypi.byted.org/packages/pycryptodome/pycryptodome-3.23.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:187058ab80b3281b1de11c2e6842a357a1f71b42cb1e15bce373f3d238135c27" }, + { url = "https://bytedpypi.byted.org/packages/pycryptodome/pycryptodome-3.23.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:cfb5cd445280c5b0a4e6187a7ce8de5a07b5f3f897f235caa11f1f435f182843" }, + { url = "https://bytedpypi.byted.org/packages/pycryptodome/pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67bd81fcbe34f43ad9422ee8fd4843c8e7198dd88dd3d40e6de42ee65fbe1490" }, + { url = "https://bytedpypi.byted.org/packages/pycryptodome/pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8987bd3307a39bc03df5c8e0e3d8be0c4c3518b7f044b0f4c15d1aa78f52575" }, + { url = "https://bytedpypi.byted.org/packages/pycryptodome/pycryptodome-3.23.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa0698f65e5b570426fc31b8162ed4603b0c2841cbb9088e2b01641e3065915b" }, + { url = "https://bytedpypi.byted.org/packages/pycryptodome/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:53ecbafc2b55353edcebd64bf5da94a2a2cdf5090a6915bcca6eca6cc452585a" }, + { url = "https://bytedpypi.byted.org/packages/pycryptodome/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:156df9667ad9f2ad26255926524e1c136d6664b741547deb0a86a9acf5ea631f" }, + { url = "https://bytedpypi.byted.org/packages/pycryptodome/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:dea827b4d55ee390dc89b2afe5927d4308a8b538ae91d9c6f7a5090f397af1aa" }, + { url = "https://bytedpypi.byted.org/packages/pycryptodome/pycryptodome-3.23.0-cp37-abi3-win32.whl", hash = "sha256:507dbead45474b62b2bbe318eb1c4c8ee641077532067fec9c1aa82c31f84886" }, + { url = "https://bytedpypi.byted.org/packages/pycryptodome/pycryptodome-3.23.0-cp37-abi3-win_amd64.whl", hash = "sha256:c75b52aacc6c0c260f204cbdd834f76edc9fb0d8e0da9fbf8352ef58202564e2" }, + { url = "https://bytedpypi.byted.org/packages/pycryptodome/pycryptodome-3.23.0-cp37-abi3-win_arm64.whl", hash = "sha256:11eeeb6917903876f134b56ba11abe95c0b0fd5e3330def218083c7d98bbcb3c" }, +] + +[[package]] +name = "pydantic" +version = "2.12.5" +source = { registry = "https://bytedpypi.byted.org/simple/" } +dependencies = [ + { name = "annotated-types" }, + { name = "pydantic-core" }, + { name = "typing-extensions" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://bytedpypi.byted.org/packages/pydantic/pydantic-2.12.5.tar.gz", hash = "sha256:4d351024c75c0f085a9febbb665ce8c0c6ec5d30e903bdb6394b7ede26aebb49" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/pydantic/pydantic-2.12.5-py3-none-any.whl", hash = "sha256:e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d" }, +] + +[[package]] +name = "pydantic-core" +version = "2.41.5" +source = { registry = "https://bytedpypi.byted.org/simple/" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:a3a52f6156e73e7ccb0f8cced536adccb7042be67cb45f9562e12b319c119da6" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7f3bf998340c6d4b0c9a2f02d6a400e51f123b59565d74dc60d252ce888c260b" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:378bec5c66998815d224c9ca994f1e14c0c21cb95d2f52b6021cc0b2a58f2a5a" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e7b576130c69225432866fe2f4a469a85a54ade141d96fd396dffcf607b558f8" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6cb58b9c66f7e4179a2d5e0f849c48eff5c1fca560994d6eb6543abf955a149e" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88942d3a3dff3afc8288c21e565e476fc278902ae4d6d134f1eeda118cc830b1" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f31d95a179f8d64d90f6831d71fa93290893a33148d890ba15de25642c5d075b" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c1df3d34aced70add6f867a8cf413e299177e0c22660cc767218373d0779487b" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4009935984bd36bd2c774e13f9a09563ce8de4abaa7226f5108262fa3e637284" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:34a64bc3441dc1213096a20fe27e8e128bd3ff89921706e83c0b1ac971276594" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c9e19dd6e28fdcaa5a1de679aec4141f691023916427ef9bae8584f9c2fb3b0e" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp311-cp311-win32.whl", hash = "sha256:2c010c6ded393148374c0f6f0bf89d206bf3217f201faa0635dcd56bd1520f6b" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp311-cp311-win_amd64.whl", hash = "sha256:76ee27c6e9c7f16f47db7a94157112a2f3a00e958bc626e2f4ee8bec5c328fbe" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp311-cp311-win_arm64.whl", hash = "sha256:4bc36bbc0b7584de96561184ad7f012478987882ebf9f9c389b23f432ea3d90f" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f41a7489d32336dbf2199c8c0a215390a751c5b014c2c1c5366e817202e9cdf7" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:070259a8818988b9a84a449a2a7337c7f430a22acc0859c6b110aa7212a6d9c0" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e96cea19e34778f8d59fe40775a7a574d95816eb150850a85a7a4c8f4b94ac69" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed2e99c456e3fadd05c991f8f437ef902e00eedf34320ba2b0842bd1c3ca3a75" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65840751b72fbfd82c3c640cff9284545342a4f1eb1586ad0636955b261b0b05" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e536c98a7626a98feb2d3eaf75944ef6f3dbee447e1f841eae16f2f0a72d8ddc" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eceb81a8d74f9267ef4081e246ffd6d129da5d87e37a77c9bde550cb04870c1c" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d38548150c39b74aeeb0ce8ee1d8e82696f4a4e16ddc6de7b1d8823f7de4b9b5" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c23e27686783f60290e36827f9c626e63154b82b116d7fe9adba1fda36da706c" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:482c982f814460eabe1d3bb0adfdc583387bd4691ef00b90575ca0d2b6fe2294" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:bfea2a5f0b4d8d43adf9d7b8bf019fb46fdd10a2e5cde477fbcb9d1fa08c68e1" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp312-cp312-win32.whl", hash = "sha256:b74557b16e390ec12dca509bce9264c3bbd128f8a2c376eaa68003d7f327276d" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp312-cp312-win_amd64.whl", hash = "sha256:1962293292865bca8e54702b08a4f26da73adc83dd1fcf26fbc875b35d81c815" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp312-cp312-win_arm64.whl", hash = "sha256:1746d4a3d9a794cacae06a5eaaccb4b8643a131d45fbc9af23e353dc0a5ba5c3" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:941103c9be18ac8daf7b7adca8228f8ed6bb7a1849020f643b3a14d15b1924d9" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:112e305c3314f40c93998e567879e887a3160bb8689ef3d2c04b6cc62c33ac34" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cbaad15cb0c90aa221d43c00e77bb33c93e8d36e0bf74760cd00e732d10a6a0" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:03ca43e12fab6023fc79d28ca6b39b05f794ad08ec2feccc59a339b02f2b3d33" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc799088c08fa04e43144b164feb0c13f9a0bc40503f8df3e9fde58a3c0c101e" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97aeba56665b4c3235a0e52b2c2f5ae9cd071b8a8310ad27bddb3f7fb30e9aa2" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:406bf18d345822d6c21366031003612b9c77b3e29ffdb0f612367352aab7d586" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b93590ae81f7010dbe380cdeab6f515902ebcbefe0b9327cc4804d74e93ae69d" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:01a3d0ab748ee531f4ea6c3e48ad9dac84ddba4b0d82291f87248f2f9de8d740" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:6561e94ba9dacc9c61bce40e2d6bdc3bfaa0259d3ff36ace3b1e6901936d2e3e" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:915c3d10f81bec3a74fbd4faebe8391013ba61e5a1a8d48c4455b923bdda7858" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp313-cp313-win32.whl", hash = "sha256:650ae77860b45cfa6e2cdafc42618ceafab3a2d9a3811fcfbd3bbf8ac3c40d36" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp313-cp313-win_amd64.whl", hash = "sha256:79ec52ec461e99e13791ec6508c722742ad745571f234ea6255bed38c6480f11" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp313-cp313-win_arm64.whl", hash = "sha256:3f84d5c1b4ab906093bdc1ff10484838aca54ef08de4afa9de0f5f14d69639cd" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:3f37a19d7ebcdd20b96485056ba9e8b304e27d9904d233d7b1015db320e51f0a" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1d1d9764366c73f996edd17abb6d9d7649a7eb690006ab6adbda117717099b14" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25e1c2af0fce638d5f1988b686f3b3ea8cd7de5f244ca147c777769e798a9cd1" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:506d766a8727beef16b7adaeb8ee6217c64fc813646b424d0804d67c16eddb66" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4819fa52133c9aa3c387b3328f25c1facc356491e6135b459f1de698ff64d869" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b761d210c9ea91feda40d25b4efe82a1707da2ef62901466a42492c028553a2" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22f0fb8c1c583a3b6f24df2470833b40207e907b90c928cc8d3594b76f874375" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2782c870e99878c634505236d81e5443092fba820f0373997ff75f90f68cd553" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:0177272f88ab8312479336e1d777f6b124537d47f2123f89cb37e0accea97f90" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:63510af5e38f8955b8ee5687740d6ebf7c2a0886d15a6d65c32814613681bc07" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:e56ba91f47764cc14f1daacd723e3e82d1a89d783f0f5afe9c364b8bb491ccdb" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314-win32.whl", hash = "sha256:aec5cf2fd867b4ff45b9959f8b20ea3993fc93e63c7363fe6851424c8a7e7c23" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314-win_amd64.whl", hash = "sha256:8e7c86f27c585ef37c35e56a96363ab8de4e549a95512445b85c96d3e2f7c1bf" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314-win_arm64.whl", hash = "sha256:e672ba74fbc2dc8eea59fb6d4aed6845e6905fc2a8afe93175d94a83ba2a01a0" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:8566def80554c3faa0e65ac30ab0932b9e3a5cd7f8323764303d468e5c37595a" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b80aa5095cd3109962a298ce14110ae16b8c1aece8b72f9dafe81cf597ad80b3" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3006c3dd9ba34b0c094c544c6006cc79e87d8612999f1a5d43b769b89181f23c" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:72f6c8b11857a856bcfa48c86f5368439f74453563f951e473514579d44aa612" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5cb1b2f9742240e4bb26b652a5aeb840aa4b417c7748b6f8387927bc6e45e40d" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd3d54f38609ff308209bd43acea66061494157703364ae40c951f83ba99a1a9" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ff4321e56e879ee8d2a879501c8e469414d948f4aba74a2d4593184eb326660" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d0d2568a8c11bf8225044aa94409e21da0cb09dcdafe9ecd10250b2baad531a9" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:a39455728aabd58ceabb03c90e12f71fd30fa69615760a075b9fec596456ccc3" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:239edca560d05757817c13dc17c50766136d21f7cd0fac50295499ae24f90fdf" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:2a5e06546e19f24c6a96a129142a75cee553cc018ffee48a460059b1185f4470" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314t-win32.whl", hash = "sha256:b4ececa40ac28afa90871c2cc2b9ffd2ff0bf749380fbdf57d165fd23da353aa" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314t-win_amd64.whl", hash = "sha256:80aa89cad80b32a912a65332f64a4450ed00966111b6615ca6816153d3585a8c" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314t-win_arm64.whl", hash = "sha256:35b44f37a3199f771c3eaa53051bc8a70cd7b54f333531c59e29fd4db5d15008" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:b96d5f26b05d03cc60f11a7761a5ded1741da411e7fe0909e27a5e6a0cb7b034" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:634e8609e89ceecea15e2d61bc9ac3718caaaa71963717bf3c8f38bfde64242c" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:93e8740d7503eb008aa2df04d3b9735f845d43ae845e6dcd2be0b55a2da43cd2" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f15489ba13d61f670dcc96772e733aad1a6f9c429cc27574c6cdaed82d0146ad" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:7da7087d756b19037bc2c06edc6c170eeef3c3bafcb8f532ff17d64dc427adfd" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:aabf5777b5c8ca26f7824cb4a120a740c9588ed58df9b2d196ce92fba42ff8dc" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c007fe8a43d43b3969e8469004e9845944f1a80e6acd47c150856bb87f230c56" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76d0819de158cd855d1cbb8fcafdf6f5cf1eb8e470abe056d5d161106e38062b" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b2379fa7ed44ddecb5bfe4e48577d752db9fc10be00a6b7446e9663ba143de26" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:266fb4cbf5e3cbd0b53669a6d1b039c45e3ce651fd5442eff4d07c2cc8d66808" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58133647260ea01e4d0500089a8c4f07bd7aa6ce109682b1426394988d8aaacc" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:287dad91cfb551c363dc62899a80e9e14da1f0e2b6ebde82c806612ca2a13ef1" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:03b77d184b9eb40240ae9fd676ca364ce1085f203e1b1256f8ab9984dca80a84" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:a668ce24de96165bb239160b3d854943128f4334822900534f2fe947930e5770" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f14f8f046c14563f8eb3f45f499cc658ab8d10072961e07225e507adb700e93f" }, + { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:56121965f7a4dc965bff783d70b907ddf3d57f6eba29b6d2e5dabfaf07799c51" }, +] + +[[package]] +name = "pydantic-settings" +version = "2.12.0" +source = { registry = "https://bytedpypi.byted.org/simple/" } +dependencies = [ + { name = "pydantic" }, + { name = "python-dotenv" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://bytedpypi.byted.org/packages/pydantic-settings/pydantic_settings-2.12.0.tar.gz", hash = "sha256:005538ef951e3c2a68e1c08b292b5f2e71490def8589d4221b95dab00dafcfd0" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/pydantic-settings/pydantic_settings-2.12.0-py3-none-any.whl", hash = "sha256:fddb9fd99a5b18da837b29710391e945b1e30c135477f484084ee513adb93809" }, +] + +[[package]] +name = "pygments" +version = "2.19.2" +source = { registry = "https://bytedpypi.byted.org/simple/" } +sdist = { url = "https://bytedpypi.byted.org/packages/pygments/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/pygments/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b" }, +] + +[[package]] +name = "pytest" +version = "9.0.2" +source = { registry = "https://bytedpypi.byted.org/simple/" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, +] +sdist = { url = "https://bytedpypi.byted.org/packages/pytest/pytest-9.0.2.tar.gz", hash = "sha256:75186651a92bd89611d1d9fc20f0b4345fd827c41ccd5c299a868a05d70edf11" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/pytest/pytest-9.0.2-py3-none-any.whl", hash = "sha256:711ffd45bf766d5264d487b917733b453d917afd2b0ad65223959f59089f875b" }, +] + +[[package]] +name = "pytest-asyncio" +version = "1.3.0" +source = { registry = "https://bytedpypi.byted.org/simple/" } +dependencies = [ + { name = "pytest" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://bytedpypi.byted.org/packages/pytest-asyncio/pytest_asyncio-1.3.0.tar.gz", hash = "sha256:d7f52f36d231b80ee124cd216ffb19369aa168fc10095013c6b014a34d3ee9e5" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/pytest-asyncio/pytest_asyncio-1.3.0-py3-none-any.whl", hash = "sha256:611e26147c7f77640e6d0a92a38ed17c3e9848063698d5c93d5aa7aa11cebff5" }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://bytedpypi.byted.org/simple/" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://bytedpypi.byted.org/packages/python-dateutil/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/python-dateutil/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427" }, +] + +[[package]] +name = "python-dotenv" +version = "1.2.1" +source = { registry = "https://bytedpypi.byted.org/simple/" } +sdist = { url = "https://bytedpypi.byted.org/packages/python-dotenv/python_dotenv-1.2.1.tar.gz", hash = "sha256:42667e897e16ab0d66954af0e60a9caa94f0fd4ecf3aaf6d2d260eec1aa36ad6" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/python-dotenv/python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61" }, +] + +[[package]] +name = "python-telegram-bot" +version = "22.6" +source = { registry = "https://bytedpypi.byted.org/simple/" } +dependencies = [ + { name = "httpcore", marker = "python_full_version >= '3.14'" }, + { name = "httpx" }, +] +sdist = { url = "https://bytedpypi.byted.org/packages/python-telegram-bot/python_telegram_bot-22.6.tar.gz", hash = "sha256:50ae8cc10f8dff01445628687951020721f37956966b92a91df4c1bf2d113742" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/python-telegram-bot/python_telegram_bot-22.6-py3-none-any.whl", hash = "sha256:e598fe171c3dde2dfd0f001619ee9110eece66761a677b34719fb18934935ce0" }, +] + +[package.optional-dependencies] +socks = [ + { name = "httpx", extra = ["socks"] }, +] + +[[package]] +name = "pytz" +version = "2025.2" +source = { registry = "https://bytedpypi.byted.org/simple/" } +sdist = { url = "https://bytedpypi.byted.org/packages/pytz/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/pytz/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.3" +source = { registry = "https://bytedpypi.byted.org/simple/" } +sdist = { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e" }, + { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824" }, + { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c" }, + { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00" }, + { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d" }, + { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a" }, + { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4" }, + { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b" }, + { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf" }, + { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196" }, + { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0" }, + { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28" }, + { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c" }, + { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc" }, + { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e" }, + { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea" }, + { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5" }, + { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b" }, + { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd" }, + { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8" }, + { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1" }, + { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c" }, + { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5" }, + { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6" }, + { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6" }, + { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be" }, + { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26" }, + { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c" }, + { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb" }, + { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac" }, + { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310" }, + { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7" }, + { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788" }, + { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5" }, + { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764" }, + { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35" }, + { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac" }, + { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3" }, + { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3" }, + { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba" }, + { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c" }, + { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702" }, + { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c" }, + { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065" }, + { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65" }, + { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9" }, + { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b" }, +] + +[[package]] +name = "qq-botpy" +version = "1.2.1" +source = { registry = "https://bytedpypi.byted.org/simple/" } +dependencies = [ + { name = "aiohttp" }, + { name = "apscheduler" }, + { name = "pyyaml" }, +] +sdist = { url = "https://bytedpypi.byted.org/packages/qq-botpy/qq-botpy-1.2.1.tar.gz", hash = "sha256:442172a0557a9b43d2777d1c5e072090a9d1a54d588d1c5da8d3efc014f4887f" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/qq-botpy/qq_botpy-1.2.1-py3-none-any.whl", hash = "sha256:18b215690dfed88f711322136ec54b6760040b9b1608eb5db7a44e00f59e4f01" }, +] + +[[package]] +name = "readability-lxml" +version = "0.8.4.1" +source = { registry = "https://bytedpypi.byted.org/simple/" } +dependencies = [ + { name = "chardet" }, + { name = "cssselect" }, + { name = "lxml", extra = ["html-clean"] }, +] +sdist = { url = "https://bytedpypi.byted.org/packages/readability-lxml/readability_lxml-0.8.4.1.tar.gz", hash = "sha256:9d2924f5942dd7f37fb4da353263b22a3e877ccf922d0e45e348e4177b035a53" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/readability-lxml/readability_lxml-0.8.4.1-py3-none-any.whl", hash = "sha256:874c0cea22c3bf2b78c7f8df831bfaad3c0a89b7301d45a188db581652b4b465" }, +] + +[[package]] +name = "referencing" +version = "0.37.0" +source = { registry = "https://bytedpypi.byted.org/simple/" } +dependencies = [ + { name = "attrs" }, + { name = "rpds-py" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://bytedpypi.byted.org/packages/referencing/referencing-0.37.0.tar.gz", hash = "sha256:44aefc3142c5b842538163acb373e24cce6632bd54bdb01b21ad5863489f50d8" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/referencing/referencing-0.37.0-py3-none-any.whl", hash = "sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231" }, +] + +[[package]] +name = "regex" +version = "2026.1.15" +source = { registry = "https://bytedpypi.byted.org/simple/" } +sdist = { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15.tar.gz", hash = "sha256:164759aa25575cbc0651bef59a0b18353e54300d79ace8084c818ad8ac72b7d5" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1ae6020fb311f68d753b7efa9d4b9a5d47a5d6466ea0d5e3b5a471a960ea6e4a" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:eddf73f41225942c1f994914742afa53dc0d01a6e20fe14b878a1b1edc74151f" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e8cd52557603f5c66a548f69421310886b28b7066853089e1a71ee710e1cdc1" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5170907244b14303edc5978f522f16c974f32d3aa92109fabc2af52411c9433b" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2748c1ec0663580b4510bd89941a31560b4b439a0b428b49472a3d9944d11cd8" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2f2775843ca49360508d080eaa87f94fa248e2c946bbcd963bb3aae14f333413" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d9ea2604370efc9a174c1b5dcc81784fb040044232150f7f33756049edfc9026" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0dcd31594264029b57bf16f37fd7248a70b3b764ed9e0839a8f271b2d22c0785" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c08c1f3e34338256732bd6938747daa3c0d5b251e04b6e43b5813e94d503076e" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e43a55f378df1e7a4fa3547c88d9a5a9b7113f653a66821bcea4718fe6c58763" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:f82110ab962a541737bd0ce87978d4c658f06e7591ba899192e2712a517badbb" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:27618391db7bdaf87ac6c92b31e8f0dfb83a9de0075855152b720140bda177a2" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bfb0d6be01fbae8d6655c8ca21b3b72458606c4aec9bbc932db758d47aba6db1" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp311-cp311-win32.whl", hash = "sha256:b10e42a6de0e32559a92f2f8dc908478cc0fa02838d7dbe764c44dca3fa13569" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp311-cp311-win_amd64.whl", hash = "sha256:e9bf3f0bbdb56633c07d7116ae60a576f846efdd86a8848f8d62b749e1209ca7" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp311-cp311-win_arm64.whl", hash = "sha256:41aef6f953283291c4e4e6850607bd71502be67779586a61472beacb315c97ec" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:4c8fcc5793dde01641a35905d6731ee1548f02b956815f8f1cab89e515a5bdf1" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:bfd876041a956e6a90ad7cdb3f6a630c07d491280bfeed4544053cd434901681" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9250d087bc92b7d4899ccd5539a1b2334e44eee85d848c4c1aef8e221d3f8c8f" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c8a154cf6537ebbc110e24dabe53095e714245c272da9c1be05734bdad4a61aa" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8050ba2e3ea1d8731a549e83c18d2f0999fbc99a5f6bd06b4c91449f55291804" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0bf065240704cb8951cc04972cf107063917022511273e0969bdb34fc173456c" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c32bef3e7aeee75746748643667668ef941d28b003bfc89994ecf09a10f7a1b5" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d5eaa4a4c5b1906bd0d2508d68927f15b81821f85092e06f1a34a4254b0e1af3" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:86c1077a3cc60d453d4084d5b9649065f3bf1184e22992bd322e1f081d3117fb" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:2b091aefc05c78d286657cd4db95f2e6313375ff65dcf085e42e4c04d9c8d410" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:57e7d17f59f9ebfa9667e6e5a1c0127b96b87cb9cede8335482451ed00788ba4" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:c6c4dcdfff2c08509faa15d36ba7e5ef5fcfab25f1e8f85a0c8f45bc3a30725d" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:cf8ff04c642716a7f2048713ddc6278c5fd41faa3b9cab12607c7abecd012c22" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp312-cp312-win32.whl", hash = "sha256:82345326b1d8d56afbe41d881fdf62f1926d7264b2fc1537f99ae5da9aad7913" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp312-cp312-win_amd64.whl", hash = "sha256:4def140aa6156bc64ee9912383d4038f3fdd18fee03a6f222abd4de6357ce42a" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp312-cp312-win_arm64.whl", hash = "sha256:c6c565d9a6e1a8d783c1948937ffc377dd5771e83bd56de8317c450a954d2056" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e69d0deeb977ffe7ed3d2e4439360089f9c3f217ada608f0f88ebd67afb6385e" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3601ffb5375de85a16f407854d11cca8fe3f5febbe3ac78fb2866bb220c74d10" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4c5ef43b5c2d4114eb8ea424bb8c9cec01d5d17f242af88b2448f5ee81caadbc" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:968c14d4f03e10b2fd960f1d5168c1f0ac969381d3c1fcc973bc45fb06346599" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:56a5595d0f892f214609c9f76b41b7428bed439d98dc961efafdd1354d42baae" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0bf650f26087363434c4e560011f8e4e738f6f3e029b85d4904c50135b86cfa5" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18388a62989c72ac24de75f1449d0fb0b04dfccd0a1a7c1c43af5eb503d890f6" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6d220a2517f5893f55daac983bfa9fe998a7dbcaee4f5d27a88500f8b7873788" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c9c08c2fbc6120e70abff5d7f28ffb4d969e14294fb2143b4b5c7d20e46d1714" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7ef7d5d4bd49ec7364315167a4134a015f61e8266c6d446fc116a9ac4456e10d" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:6e42844ad64194fa08d5ccb75fe6a459b9b08e6d7296bd704460168d58a388f3" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:cfecdaa4b19f9ca534746eb3b55a5195d5c95b88cac32a205e981ec0a22b7d31" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:08df9722d9b87834a3d701f3fca570b2be115654dbfd30179f30ab2f39d606d3" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313-win32.whl", hash = "sha256:d426616dae0967ca225ab12c22274eb816558f2f99ccb4a1d52ca92e8baf180f" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313-win_amd64.whl", hash = "sha256:febd38857b09867d3ed3f4f1af7d241c5c50362e25ef43034995b77a50df494e" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313-win_arm64.whl", hash = "sha256:8e32f7896f83774f91499d239e24cebfadbc07639c1494bb7213983842348337" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:ec94c04149b6a7b8120f9f44565722c7ae31b7a6d2275569d2eefa76b83da3be" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:40c86d8046915bb9aeb15d3f3f15b6fd500b8ea4485b30e1bbc799dab3fe29f8" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:726ea4e727aba21643205edad8f2187ec682d3305d790f73b7a51c7587b64bdd" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1cb740d044aff31898804e7bf1181cc72c03d11dfd19932b9911ffc19a79070a" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:05d75a668e9ea16f832390d22131fe1e8acc8389a694c8febc3e340b0f810b93" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d991483606f3dbec93287b9f35596f41aa2e92b7c2ebbb935b63f409e243c9af" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:194312a14819d3e44628a44ed6fea6898fdbecb0550089d84c403475138d0a09" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fe2fda4110a3d0bc163c2e0664be44657431440722c5c5315c65155cab92f9e5" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:124dc36c85d34ef2d9164da41a53c1c8c122cfb1f6e1ec377a1f27ee81deb794" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:a1774cd1981cd212506a23a14dba7fdeaee259f5deba2df6229966d9911e767a" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:b5f7d8d2867152cdb625e72a530d2ccb48a3d199159144cbdd63870882fb6f80" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:492534a0ab925d1db998defc3c302dae3616a2fc3fe2e08db1472348f096ddf2" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c661fc820cfb33e166bf2450d3dadbda47c8d8981898adb9b6fe24e5e582ba60" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313t-win32.whl", hash = "sha256:99ad739c3686085e614bf77a508e26954ff1b8f14da0e3765ff7abbf7799f952" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313t-win_amd64.whl", hash = "sha256:32655d17905e7ff8ba5c764c43cb124e34a9245e45b83c22e81041e1071aee10" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313t-win_arm64.whl", hash = "sha256:b2a13dd6a95e95a489ca242319d18fc02e07ceb28fa9ad146385194d95b3c829" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:d920392a6b1f353f4aa54328c867fec3320fa50657e25f64abf17af054fc97ac" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:b5a28980a926fa810dbbed059547b02783952e2efd9c636412345232ddb87ff6" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:621f73a07595d83f28952d7bd1e91e9d1ed7625fb7af0064d3516674ec93a2a2" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3d7d92495f47567a9b1669c51fc8d6d809821849063d168121ef801bbc213846" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8dd16fba2758db7a3780a051f245539c4451ca20910f5a5e6ea1c08d06d4a76b" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1e1808471fbe44c1a63e5f577a1d5f02fe5d66031dcbdf12f093ffc1305a858e" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0751a26ad39d4f2ade8fe16c59b2bf5cb19eb3d2cd543e709e583d559bd9efde" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0f0c7684c7f9ca241344ff95a1de964f257a5251968484270e91c25a755532c5" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:74f45d170a21df41508cb67165456538425185baaf686281fa210d7e729abc34" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:f1862739a1ffb50615c0fde6bae6569b5efbe08d98e59ce009f68a336f64da75" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:453078802f1b9e2b7303fb79222c054cb18e76f7bdc220f7530fdc85d319f99e" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:a30a68e89e5a218b8b23a52292924c1f4b245cb0c68d1cce9aec9bbda6e2c160" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9479cae874c81bf610d72b85bb681a94c95722c127b55445285fb0e2c82db8e1" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314-win32.whl", hash = "sha256:d639a750223132afbfb8f429c60d9d318aeba03281a5f1ab49f877456448dcf1" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314-win_amd64.whl", hash = "sha256:4161d87f85fa831e31469bfd82c186923070fc970b9de75339b68f0c75b51903" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314-win_arm64.whl", hash = "sha256:91c5036ebb62663a6b3999bdd2e559fd8456d17e2b485bf509784cd31a8b1705" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:ee6854c9000a10938c79238de2379bea30c82e4925a371711af45387df35cab8" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2c2b80399a422348ce5de4fe40c418d6299a0fa2803dd61dc0b1a2f28e280fcf" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:dca3582bca82596609959ac39e12b7dad98385b4fefccb1151b937383cec547d" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ef71d476caa6692eea743ae5ea23cde3260677f70122c4d258ca952e5c2d4e84" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c243da3436354f4af6c3058a3f81a97d47ea52c9bd874b52fd30274853a1d5df" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8355ad842a7c7e9e5e55653eade3b7d1885ba86f124dd8ab1f722f9be6627434" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f192a831d9575271a22d804ff1a5355355723f94f31d9eef25f0d45a152fdc1a" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:166551807ec20d47ceaeec380081f843e88c8949780cd42c40f18d16168bed10" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:f9ca1cbdc0fbfe5e6e6f8221ef2309988db5bcede52443aeaee9a4ad555e0dac" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b30bcbd1e1221783c721483953d9e4f3ab9c5d165aa709693d3f3946747b1aea" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:2a8d7b50c34578d0d3bf7ad58cde9652b7d683691876f83aedc002862a35dc5e" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:9d787e3310c6a6425eb346be4ff2ccf6eece63017916fd77fe8328c57be83521" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:619843841e220adca114118533a574a9cd183ed8a28b85627d2844c500a2b0db" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314t-win32.whl", hash = "sha256:e90b8db97f6f2c97eb045b51a6b2c5ed69cedd8392459e0642d4199b94fabd7e" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314t-win_amd64.whl", hash = "sha256:5ef19071f4ac9f0834793af85bd04a920b4407715624e40cb7a0631a11137cdf" }, + { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314t-win_arm64.whl", hash = "sha256:ca89c5e596fc05b015f27561b3793dc2fa0917ea0d7507eebb448efd35274a70" }, +] + +[[package]] +name = "requests" +version = "2.32.5" +source = { registry = "https://bytedpypi.byted.org/simple/" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://bytedpypi.byted.org/packages/requests/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/requests/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6" }, +] + +[[package]] +name = "requests-toolbelt" +version = "1.0.0" +source = { registry = "https://bytedpypi.byted.org/simple/" } +dependencies = [ + { name = "requests" }, +] +sdist = { url = "https://bytedpypi.byted.org/packages/requests-toolbelt/requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/requests-toolbelt/requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06" }, +] + +[[package]] +name = "rich" +version = "14.3.2" +source = { registry = "https://bytedpypi.byted.org/simple/" } +dependencies = [ + { name = "markdown-it-py" }, + { name = "pygments" }, +] +sdist = { url = "https://bytedpypi.byted.org/packages/rich/rich-14.3.2.tar.gz", hash = "sha256:e712f11c1a562a11843306f5ed999475f09ac31ffb64281f73ab29ffdda8b3b8" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/rich/rich-14.3.2-py3-none-any.whl", hash = "sha256:08e67c3e90884651da3239ea668222d19bea7b589149d8014a21c633420dbb69" }, +] + +[[package]] +name = "rpds-py" +version = "0.30.0" +source = { registry = "https://bytedpypi.byted.org/simple/" } +sdist = { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0.tar.gz", hash = "sha256:dd8ff7cf90014af0c0f787eea34794ebf6415242ee1d6fa91eaba725cc441e84" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:a2bffea6a4ca9f01b3f8e548302470306689684e61602aa3d141e34da06cf425" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dc4f992dfe1e2bc3ebc7444f6c7051b4bc13cd8e33e43511e8ffd13bf407010d" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:422c3cb9856d80b09d30d2eb255d0754b23e090034e1deb4083f8004bd0761e4" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:07ae8a593e1c3c6b82ca3292efbe73c30b61332fd612e05abee07c79359f292f" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12f90dd7557b6bd57f40abe7747e81e0c0b119bef015ea7726e69fe550e394a4" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:99b47d6ad9a6da00bec6aabe5a6279ecd3c06a329d4aa4771034a21e335c3a97" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33f559f3104504506a44bb666b93a33f5d33133765b0c216a5bf2f1e1503af89" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:946fe926af6e44f3697abbc305ea168c2c31d3e3ef1058cf68f379bf0335a78d" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:495aeca4b93d465efde585977365187149e75383ad2684f81519f504f5c13038" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d9a0ca5da0386dee0655b4ccdf46119df60e0f10da268d04fe7cc87886872ba7" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8d6d1cc13664ec13c1b84241204ff3b12f9bb82464b8ad6e7a5d3486975c2eed" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3896fa1be39912cf0757753826bc8bdc8ca331a28a7c4ae46b7a21280b06bb85" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp311-cp311-win32.whl", hash = "sha256:55f66022632205940f1827effeff17c4fa7ae1953d2b74a8581baaefb7d16f8c" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp311-cp311-win_amd64.whl", hash = "sha256:a51033ff701fca756439d641c0ad09a41d9242fa69121c7d8769604a0a629825" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp311-cp311-win_arm64.whl", hash = "sha256:47b0ef6231c58f506ef0b74d44e330405caa8428e770fec25329ed2cb971a229" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a161f20d9a43006833cd7068375a94d035714d73a172b681d8881820600abfad" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6abc8880d9d036ecaafe709079969f56e876fcf107f7a8e9920ba6d5a3878d05" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca28829ae5f5d569bb62a79512c842a03a12576375d5ece7d2cadf8abe96ec28" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a1010ed9524c73b94d15919ca4d41d8780980e1765babf85f9a2f90d247153dd" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f8d1736cfb49381ba528cd5baa46f82fdc65c06e843dab24dd70b63d09121b3f" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d948b135c4693daff7bc2dcfc4ec57237a29bd37e60c2fabf5aff2bbacf3e2f1" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47f236970bccb2233267d89173d3ad2703cd36a0e2a6e92d0560d333871a3d23" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:2e6ecb5a5bcacf59c3f912155044479af1d0b6681280048b338b28e364aca1f6" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a8fa71a2e078c527c3e9dc9fc5a98c9db40bcc8a92b4e8858e36d329f8684b51" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:73c67f2db7bc334e518d097c6d1e6fed021bbc9b7d678d6cc433478365d1d5f5" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5ba103fb455be00f3b1c2076c9d4264bfcb037c976167a6047ed82f23153f02e" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7cee9c752c0364588353e627da8a7e808a66873672bcb5f52890c33fd965b394" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp312-cp312-win32.whl", hash = "sha256:1ab5b83dbcf55acc8b08fc62b796ef672c457b17dbd7820a11d6c52c06839bdf" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp312-cp312-win_amd64.whl", hash = "sha256:a090322ca841abd453d43456ac34db46e8b05fd9b3b4ac0c78bcde8b089f959b" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp312-cp312-win_arm64.whl", hash = "sha256:669b1805bd639dd2989b281be2cfd951c6121b65e729d9b843e9639ef1fd555e" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:f83424d738204d9770830d35290ff3273fbb02b41f919870479fab14b9d303b2" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e7536cd91353c5273434b4e003cbda89034d67e7710eab8761fd918ec6c69cf8" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2771c6c15973347f50fece41fc447c054b7ac2ae0502388ce3b6738cd366e3d4" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0a59119fc6e3f460315fe9d08149f8102aa322299deaa5cab5b40092345c2136" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:76fec018282b4ead0364022e3c54b60bf368b9d926877957a8624b58419169b7" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:692bef75a5525db97318e8cd061542b5a79812d711ea03dbc1f6f8dbb0c5f0d2" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9027da1ce107104c50c81383cae773ef5c24d296dd11c99e2629dbd7967a20c6" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:9cf69cdda1f5968a30a359aba2f7f9aa648a9ce4b580d6826437f2b291cfc86e" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a4796a717bf12b9da9d3ad002519a86063dcac8988b030e405704ef7d74d2d9d" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5d4c2aa7c50ad4728a094ebd5eb46c452e9cb7edbfdb18f9e1221f597a73e1e7" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ba81a9203d07805435eb06f536d95a266c21e5b2dfbf6517748ca40c98d19e31" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:945dccface01af02675628334f7cf49c2af4c1c904748efc5cf7bbdf0b579f95" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313-win32.whl", hash = "sha256:b40fb160a2db369a194cb27943582b38f79fc4887291417685f3ad693c5a1d5d" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313-win_amd64.whl", hash = "sha256:806f36b1b605e2d6a72716f321f20036b9489d29c51c91f4dd29a3e3afb73b15" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313-win_arm64.whl", hash = "sha256:d96c2086587c7c30d44f31f42eae4eac89b60dabbac18c7669be3700f13c3ce1" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:eb0b93f2e5c2189ee831ee43f156ed34e2a89a78a66b98cadad955972548be5a" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:922e10f31f303c7c920da8981051ff6d8c1a56207dbdf330d9047f6d30b70e5e" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdc62c8286ba9bf7f47befdcea13ea0e26bf294bda99758fd90535cbaf408000" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:47f9a91efc418b54fb8190a6b4aa7813a23fb79c51f4bb84e418f5476c38b8db" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1f3587eb9b17f3789ad50824084fa6f81921bbf9a795826570bda82cb3ed91f2" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:39c02563fc592411c2c61d26b6c5fe1e51eaa44a75aa2c8735ca88b0d9599daa" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51a1234d8febafdfd33a42d97da7a43f5dcb120c1060e352a3fbc0c6d36e2083" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:eb2c4071ab598733724c08221091e8d80e89064cd472819285a9ab0f24bcedb9" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6bdfdb946967d816e6adf9a3d8201bfad269c67efe6cefd7093ef959683c8de0" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c77afbd5f5250bf27bf516c7c4a016813eb2d3e116139aed0096940c5982da94" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:61046904275472a76c8c90c9ccee9013d70a6d0f73eecefd38c1ae7c39045a08" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4c5f36a861bc4b7da6516dbdf302c55313afa09b81931e8280361a4f6c9a2d27" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313t-win32.whl", hash = "sha256:3d4a69de7a3e50ffc214ae16d79d8fbb0922972da0356dcf4d0fdca2878559c6" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313t-win_amd64.whl", hash = "sha256:f14fc5df50a716f7ece6a80b6c78bb35ea2ca47c499e422aa4463455dd96d56d" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:68f19c879420aa08f61203801423f6cd5ac5f0ac4ac82a2368a9fcd6a9a075e0" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ec7c4490c672c1a0389d319b3a9cfcd098dcdc4783991553c332a15acf7249be" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f251c812357a3fed308d684a5079ddfb9d933860fc6de89f2b7ab00da481e65f" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ac98b175585ecf4c0348fd7b29c3864bda53b805c773cbf7bfdaffc8070c976f" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3e62880792319dbeb7eb866547f2e35973289e7d5696c6e295476448f5b63c87" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4e7fc54e0900ab35d041b0601431b0a0eb495f0851a0639b6ef90f7741b39a18" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47e77dc9822d3ad616c3d5759ea5631a75e5809d5a28707744ef79d7a1bcfcad" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:b4dc1a6ff022ff85ecafef7979a2c6eb423430e05f1165d6688234e62ba99a07" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4559c972db3a360808309e06a74628b95eaccbf961c335c8fe0d590cf587456f" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:0ed177ed9bded28f8deb6ab40c183cd1192aa0de40c12f38be4d59cd33cb5c65" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:ad1fa8db769b76ea911cb4e10f049d80bf518c104f15b3edb2371cc65375c46f" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:46e83c697b1f1c72b50e5ee5adb4353eef7406fb3f2043d64c33f20ad1c2fc53" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314-win32.whl", hash = "sha256:ee454b2a007d57363c2dfd5b6ca4a5d7e2c518938f8ed3b706e37e5d470801ed" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314-win_amd64.whl", hash = "sha256:95f0802447ac2d10bcc69f6dc28fe95fdf17940367b21d34e34c737870758950" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314-win_arm64.whl", hash = "sha256:613aa4771c99f03346e54c3f038e4cc574ac09a3ddfb0e8878487335e96dead6" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:7e6ecfcb62edfd632e56983964e6884851786443739dbfe3582947e87274f7cb" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a1d0bc22a7cdc173fedebb73ef81e07faef93692b8c1ad3733b67e31e1b6e1b8" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d08f00679177226c4cb8c5265012eea897c8ca3b93f429e546600c971bcbae7" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5965af57d5848192c13534f90f9dd16464f3c37aaf166cc1da1cae1fd5a34898" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9a4e86e34e9ab6b667c27f3211ca48f73dba7cd3d90f8d5b11be56e5dbc3fb4e" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5d3e6b26f2c785d65cc25ef1e5267ccbe1b069c5c21b8cc724efee290554419" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:626a7433c34566535b6e56a1b39a7b17ba961e97ce3b80ec62e6f1312c025551" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:acd7eb3f4471577b9b5a41baf02a978e8bdeb08b4b355273994f8b87032000a8" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fe5fa731a1fa8a0a56b0977413f8cacac1768dad38d16b3a296712709476fbd5" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:74a3243a411126362712ee1524dfc90c650a503502f135d54d1b352bd01f2404" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:3e8eeb0544f2eb0d2581774be4c3410356eba189529a6b3e36bbbf9696175856" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:dbd936cde57abfee19ab3213cf9c26be06d60750e60a8e4dd85d1ab12c8b1f40" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314t-win32.whl", hash = "sha256:dc824125c72246d924f7f796b4f63c1e9dc810c7d9e2355864b3c3a73d59ade0" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314t-win_amd64.whl", hash = "sha256:27f4b0e92de5bfbc6f86e43959e6edd1425c33b5e69aab0984a72047f2bcf1e3" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c2262bdba0ad4fc6fb5545660673925c2d2a5d9e2e0fb603aad545427be0fc58" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:ee6af14263f25eedc3bb918a3c04245106a42dfd4f5c2285ea6f997b1fc3f89a" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3adbb8179ce342d235c31ab8ec511e66c73faa27a47e076ccc92421add53e2bb" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:250fa00e9543ac9b97ac258bd37367ff5256666122c2d0f2bc97577c60a1818c" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9854cf4f488b3d57b9aaeb105f06d78e5529d3145b1e4a41750167e8c213c6d3" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:993914b8e560023bc0a8bf742c5f303551992dcb85e247b1e5c7f4a7d145bda5" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58edca431fb9b29950807e301826586e5bbf24163677732429770a697ffe6738" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:dea5b552272a944763b34394d04577cf0f9bd013207bc32323b5a89a53cf9c2f" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ba3af48635eb83d03f6c9735dfb21785303e73d22ad03d489e88adae6eab8877" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:dff13836529b921e22f15cb099751209a60009731a68519630a24d61f0b1b30a" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:1b151685b23929ab7beec71080a8889d4d6d9fa9a983d213f07121205d48e2c4" }, + { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:ac37f9f516c51e5753f27dfdef11a88330f04de2d564be3991384b2f3535d02e" }, +] + +[[package]] +name = "ruff" +version = "0.15.1" +source = { registry = "https://bytedpypi.byted.org/simple/" } +sdist = { url = "https://bytedpypi.byted.org/packages/ruff/ruff-0.15.1.tar.gz", hash = "sha256:c590fe13fb57c97141ae975c03a1aedb3d3156030cabd740d6ff0b0d601e203f" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/ruff/ruff-0.15.1-py3-none-linux_armv6l.whl", hash = "sha256:b101ed7cf4615bda6ffe65bdb59f964e9f4a0d3f85cbf0e54f0ab76d7b90228a" }, + { url = "https://bytedpypi.byted.org/packages/ruff/ruff-0.15.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:939c995e9277e63ea632cc8d3fae17aa758526f49a9a850d2e7e758bfef46602" }, + { url = "https://bytedpypi.byted.org/packages/ruff/ruff-0.15.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:1d83466455fdefe60b8d9c8df81d3c1bbb2115cede53549d3b522ce2bc703899" }, + { url = "https://bytedpypi.byted.org/packages/ruff/ruff-0.15.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9457e3c3291024866222b96108ab2d8265b477e5b1534c7ddb1810904858d16" }, + { url = "https://bytedpypi.byted.org/packages/ruff/ruff-0.15.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:92c92b003e9d4f7fbd33b1867bb15a1b785b1735069108dfc23821ba045b29bc" }, + { url = "https://bytedpypi.byted.org/packages/ruff/ruff-0.15.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fe5c41ab43e3a06778844c586251eb5a510f67125427625f9eb2b9526535779" }, + { url = "https://bytedpypi.byted.org/packages/ruff/ruff-0.15.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:66a6dd6df4d80dc382c6484f8ce1bcceb55c32e9f27a8b94c32f6c7331bf14fb" }, + { url = "https://bytedpypi.byted.org/packages/ruff/ruff-0.15.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6a4a42cbb8af0bda9bcd7606b064d7c0bc311a88d141d02f78920be6acb5aa83" }, + { url = "https://bytedpypi.byted.org/packages/ruff/ruff-0.15.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ab064052c31dddada35079901592dfba2e05f5b1e43af3954aafcbc1096a5b2" }, + { url = "https://bytedpypi.byted.org/packages/ruff/ruff-0.15.1-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:5631c940fe9fe91f817a4c2ea4e81f47bee3ca4aa646134a24374f3c19ad9454" }, + { url = "https://bytedpypi.byted.org/packages/ruff/ruff-0.15.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:68138a4ba184b4691ccdc39f7795c66b3c68160c586519e7e8444cf5a53e1b4c" }, + { url = "https://bytedpypi.byted.org/packages/ruff/ruff-0.15.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:518f9af03bfc33c03bdb4cb63fabc935341bb7f54af500f92ac309ecfbba6330" }, + { url = "https://bytedpypi.byted.org/packages/ruff/ruff-0.15.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:da79f4d6a826caaea95de0237a67e33b81e6ec2e25fc7e1993a4015dffca7c61" }, + { url = "https://bytedpypi.byted.org/packages/ruff/ruff-0.15.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:3dd86dccb83cd7d4dcfac303ffc277e6048600dfc22e38158afa208e8bf94a1f" }, + { url = "https://bytedpypi.byted.org/packages/ruff/ruff-0.15.1-py3-none-win32.whl", hash = "sha256:660975d9cb49b5d5278b12b03bb9951d554543a90b74ed5d366b20e2c57c2098" }, + { url = "https://bytedpypi.byted.org/packages/ruff/ruff-0.15.1-py3-none-win_amd64.whl", hash = "sha256:c820fef9dd5d4172a6570e5721704a96c6679b80cf7be41659ed439653f62336" }, + { url = "https://bytedpypi.byted.org/packages/ruff/ruff-0.15.1-py3-none-win_arm64.whl", hash = "sha256:5ff7d5f0f88567850f45081fac8f4ec212be8d0b963e385c3f7d0d2eb4899416" }, +] + +[[package]] +name = "shellingham" +version = "1.5.4" +source = { registry = "https://bytedpypi.byted.org/simple/" } +sdist = { url = "https://bytedpypi.byted.org/packages/shellingham/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/shellingham/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://bytedpypi.byted.org/simple/" } +sdist = { url = "https://bytedpypi.byted.org/packages/six/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/six/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274" }, +] + +[[package]] +name = "slack-sdk" +version = "3.40.0" +source = { registry = "https://bytedpypi.byted.org/simple/" } +sdist = { url = "https://bytedpypi.byted.org/packages/slack-sdk/slack_sdk-3.40.0.tar.gz", hash = "sha256:87b9a79d1d6e19a2b1877727a0ec6f016d82d30a6a410389fba87c221c99f10e" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/slack-sdk/slack_sdk-3.40.0-py2.py3-none-any.whl", hash = "sha256:f2bada5ed3adb10a01e154e90db01d6d8938d0461b5790c12bcb807b2d28bbe2" }, +] + +[[package]] +name = "sniffio" +version = "1.3.1" +source = { registry = "https://bytedpypi.byted.org/simple/" } +sdist = { url = "https://bytedpypi.byted.org/packages/sniffio/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/sniffio/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2" }, +] + +[[package]] +name = "socksio" +version = "1.0.0" +source = { registry = "https://bytedpypi.byted.org/simple/" } +sdist = { url = "https://bytedpypi.byted.org/packages/socksio/socksio-1.0.0.tar.gz", hash = "sha256:f88beb3da5b5c38b9890469de67d0cb0f9d494b78b106ca1845f96c10b91c4ac" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/socksio/socksio-1.0.0-py3-none-any.whl", hash = "sha256:95dc1f15f9b34e8d7b16f06d74b8ccf48f609af32ab33c608d08761c5dcbb1f3" }, +] + +[[package]] +name = "tiktoken" +version = "0.12.0" +source = { registry = "https://bytedpypi.byted.org/simple/" } +dependencies = [ + { name = "regex" }, + { name = "requests" }, +] +sdist = { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0.tar.gz", hash = "sha256:b18ba7ee2b093863978fcb14f74b3707cdc8d4d4d3836853ce7ec60772139931" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:6e227c7f96925003487c33b1b32265fad2fbcec2b7cf4817afb76d416f40f6bb" }, + { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c06cf0fcc24c2cb2adb5e185c7082a82cba29c17575e828518c2f11a01f445aa" }, + { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:f18f249b041851954217e9fd8e5c00b024ab2315ffda5ed77665a05fa91f42dc" }, + { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:47a5bc270b8c3db00bb46ece01ef34ad050e364b51d406b6f9730b64ac28eded" }, + { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:508fa71810c0efdcd1b898fda574889ee62852989f7c1667414736bcb2b9a4bd" }, + { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a1af81a6c44f008cba48494089dd98cccb8b313f55e961a52f5b222d1e507967" }, + { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:3e68e3e593637b53e56f7237be560f7a394451cb8c11079755e80ae64b9e6def" }, + { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b97f74aca0d78a1ff21b8cd9e9925714c15a9236d6ceacf5c7327c117e6e21e8" }, + { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2b90f5ad190a4bb7c3eb30c5fa32e1e182ca1ca79f05e49b448438c3e225a49b" }, + { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:65b26c7a780e2139e73acc193e5c63ac754021f160df919add909c1492c0fb37" }, + { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:edde1ec917dfd21c1f2f8046b86348b0f54a2c0547f68149d8600859598769ad" }, + { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:35a2f8ddd3824608b3d650a000c1ef71f730d0c56486845705a8248da00f9fe5" }, + { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:83d16643edb7fa2c99eff2ab7733508aae1eebb03d5dfc46f5565862810f24e3" }, + { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:ffc5288f34a8bc02e1ea7047b8d041104791d2ddbf42d1e5fa07822cbffe16bd" }, + { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:775c2c55de2310cc1bc9a3ad8826761cbdc87770e586fd7b6da7d4589e13dab3" }, + { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a01b12f69052fbe4b080a2cfb867c4de12c704b56178edf1d1d7b273561db160" }, + { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:01d99484dc93b129cd0964f9d34eee953f2737301f18b3c7257bf368d7615baa" }, + { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:4a1a4fcd021f022bfc81904a911d3df0f6543b9e7627b51411da75ff2fe7a1be" }, + { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:981a81e39812d57031efdc9ec59fa32b2a5a5524d20d4776574c4b4bd2e9014a" }, + { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9baf52f84a3f42eef3ff4e754a0db79a13a27921b457ca9832cf944c6be4f8f3" }, + { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:b8a0cd0c789a61f31bf44851defbd609e8dd1e2c8589c614cc1060940ef1f697" }, + { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:d5f89ea5680066b68bcb797ae85219c72916c922ef0fcdd3480c7d2315ffff16" }, + { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b4e7ed1c6a7a8a60a3230965bdedba8cc58f68926b835e519341413370e0399a" }, + { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:fc530a28591a2d74bce821d10b418b26a094bf33839e69042a6e86ddb7a7fb27" }, + { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:06a9f4f49884139013b138920a4c393aa6556b2f8f536345f11819389c703ebb" }, + { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:04f0e6a985d95913cabc96a741c5ffec525a2c72e9df086ff17ebe35985c800e" }, + { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:0ee8f9ae00c41770b5f9b0bb1235474768884ae157de3beb5439ca0fd70f3e25" }, + { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp313-cp313t-win_amd64.whl", hash = "sha256:dc2dd125a62cb2b3d858484d6c614d136b5b848976794edfb63688d539b8b93f" }, + { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:a90388128df3b3abeb2bfd1895b0681412a8d7dc644142519e6f0a97c2111646" }, + { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:da900aa0ad52247d8794e307d6446bd3cdea8e192769b56276695d34d2c9aa88" }, + { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:285ba9d73ea0d6171e7f9407039a290ca77efcdb026be7769dccc01d2c8d7fff" }, + { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:d186a5c60c6a0213f04a7a802264083dea1bbde92a2d4c7069e1a56630aef830" }, + { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:604831189bd05480f2b885ecd2d1986dc7686f609de48208ebbbddeea071fc0b" }, + { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:8f317e8530bb3a222547b85a58583238c8f74fd7a7408305f9f63246d1a0958b" }, + { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp314-cp314-win_amd64.whl", hash = "sha256:399c3dd672a6406719d84442299a490420b458c44d3ae65516302a99675888f3" }, + { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:c2c714c72bc00a38ca969dae79e8266ddec999c7ceccd603cc4f0d04ccd76365" }, + { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:cbb9a3ba275165a2cb0f9a83f5d7025afe6b9d0ab01a22b50f0e74fee2ad253e" }, + { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:dfdfaa5ffff8993a3af94d1125870b1d27aed7cb97aa7eb8c1cefdbc87dbee63" }, + { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:584c3ad3d0c74f5269906eb8a659c8bfc6144a52895d9261cdaf90a0ae5f4de0" }, + { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:54c891b416a0e36b8e2045b12b33dd66fb34a4fe7965565f1b482da50da3e86a" }, + { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5edb8743b88d5be814b1a8a8854494719080c28faaa1ccbef02e87354fe71ef0" }, + { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp314-cp314t-win_amd64.whl", hash = "sha256:f61c0aea5565ac82e2ec50a05e02a6c44734e91b51c10510b084ea1b8e633a71" }, +] + +[[package]] +name = "tokenizers" +version = "0.22.2" +source = { registry = "https://bytedpypi.byted.org/simple/" } +dependencies = [ + { name = "huggingface-hub" }, +] +sdist = { url = "https://bytedpypi.byted.org/packages/tokenizers/tokenizers-0.22.2.tar.gz", hash = "sha256:473b83b915e547aa366d1eee11806deaf419e17be16310ac0a14077f1e28f917" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/tokenizers/tokenizers-0.22.2-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:544dd704ae7238755d790de45ba8da072e9af3eea688f698b137915ae959281c" }, + { url = "https://bytedpypi.byted.org/packages/tokenizers/tokenizers-0.22.2-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:1e418a55456beedca4621dbab65a318981467a2b188e982a23e117f115ce5001" }, + { url = "https://bytedpypi.byted.org/packages/tokenizers/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2249487018adec45d6e3554c71d46eb39fa8ea67156c640f7513eb26f318cec7" }, + { url = "https://bytedpypi.byted.org/packages/tokenizers/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25b85325d0815e86e0bac263506dd114578953b7b53d7de09a6485e4a160a7dd" }, + { url = "https://bytedpypi.byted.org/packages/tokenizers/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bfb88f22a209ff7b40a576d5324bf8286b519d7358663db21d6246fb17eea2d5" }, + { url = "https://bytedpypi.byted.org/packages/tokenizers/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1c774b1276f71e1ef716e5486f21e76333464f47bece56bbd554485982a9e03e" }, + { url = "https://bytedpypi.byted.org/packages/tokenizers/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:df6c4265b289083bf710dff49bc51ef252f9d5be33a45ee2bed151114a56207b" }, + { url = "https://bytedpypi.byted.org/packages/tokenizers/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:369cc9fc8cc10cb24143873a0d95438bb8ee257bb80c71989e3ee290e8d72c67" }, + { url = "https://bytedpypi.byted.org/packages/tokenizers/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:29c30b83d8dcd061078b05ae0cb94d3c710555fbb44861139f9f83dcca3dc3e4" }, + { url = "https://bytedpypi.byted.org/packages/tokenizers/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:37ae80a28c1d3265bb1f22464c856bd23c02a05bb211e56d0c5301a435be6c1a" }, + { url = "https://bytedpypi.byted.org/packages/tokenizers/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:791135ee325f2336f498590eb2f11dc5c295232f288e75c99a36c5dbce63088a" }, + { url = "https://bytedpypi.byted.org/packages/tokenizers/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38337540fbbddff8e999d59970f3c6f35a82de10053206a7562f1ea02d046fa5" }, + { url = "https://bytedpypi.byted.org/packages/tokenizers/tokenizers-0.22.2-cp39-abi3-win32.whl", hash = "sha256:a6bf3f88c554a2b653af81f3204491c818ae2ac6fbc09e76ef4773351292bc92" }, + { url = "https://bytedpypi.byted.org/packages/tokenizers/tokenizers-0.22.2-cp39-abi3-win_amd64.whl", hash = "sha256:c9ea31edff2968b44a88f97d784c2f16dc0729b8b143ed004699ebca91f05c48" }, + { url = "https://bytedpypi.byted.org/packages/tokenizers/tokenizers-0.22.2-cp39-abi3-win_arm64.whl", hash = "sha256:9ce725d22864a1e965217204946f830c37876eee3b2ba6fc6255e8e903d5fcbc" }, +] + +[[package]] +name = "tqdm" +version = "4.67.3" +source = { registry = "https://bytedpypi.byted.org/simple/" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://bytedpypi.byted.org/packages/tqdm/tqdm-4.67.3.tar.gz", hash = "sha256:7d825f03f89244ef73f1d4ce193cb1774a8179fd96f31d7e1dcde62092b960bb" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/tqdm/tqdm-4.67.3-py3-none-any.whl", hash = "sha256:ee1e4c0e59148062281c49d80b25b67771a127c85fc9676d3be5f243206826bf" }, +] + +[[package]] +name = "typer" +version = "0.23.0" +source = { registry = "https://bytedpypi.byted.org/simple/" } +dependencies = [ + { name = "annotated-doc" }, + { name = "click" }, + { name = "rich" }, + { name = "shellingham" }, +] +sdist = { url = "https://bytedpypi.byted.org/packages/typer/typer-0.23.0.tar.gz", hash = "sha256:d8378833e47ada5d3d093fa20c4c63427cc4e27127f6b349a6c359463087d8cc" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/typer/typer-0.23.0-py3-none-any.whl", hash = "sha256:79f4bc262b6c37872091072a3cb7cb6d7d79ee98c0c658b4364bdcde3c42c913" }, +] + +[[package]] +name = "typer-slim" +version = "0.23.0" +source = { registry = "https://bytedpypi.byted.org/simple/" } +dependencies = [ + { name = "typer" }, +] +sdist = { url = "https://bytedpypi.byted.org/packages/typer-slim/typer_slim-0.23.0.tar.gz", hash = "sha256:be8b60243df27cfee444c6db1b10a85f4f3e54d940574f31a996f78aa35a8254" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/typer-slim/typer_slim-0.23.0-py3-none-any.whl", hash = "sha256:1d693daf22d998a7b1edab8413cdcb8af07254154ce3956c1664dc11b01e2f8b" }, +] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +source = { registry = "https://bytedpypi.byted.org/simple/" } +sdist = { url = "https://bytedpypi.byted.org/packages/typing-extensions/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/typing-extensions/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548" }, +] + +[[package]] +name = "typing-inspection" +version = "0.4.2" +source = { registry = "https://bytedpypi.byted.org/simple/" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://bytedpypi.byted.org/packages/typing-inspection/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/typing-inspection/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7" }, +] + +[[package]] +name = "tzdata" +version = "2025.3" +source = { registry = "https://bytedpypi.byted.org/simple/" } +sdist = { url = "https://bytedpypi.byted.org/packages/tzdata/tzdata-2025.3.tar.gz", hash = "sha256:de39c2ca5dc7b0344f2eba86f49d614019d29f060fc4ebc8a417896a620b56a7" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/tzdata/tzdata-2025.3-py2.py3-none-any.whl", hash = "sha256:06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1" }, +] + +[[package]] +name = "tzlocal" +version = "5.3.1" +source = { registry = "https://bytedpypi.byted.org/simple/" } +dependencies = [ + { name = "tzdata", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://bytedpypi.byted.org/packages/tzlocal/tzlocal-5.3.1.tar.gz", hash = "sha256:cceffc7edecefea1f595541dbd6e990cb1ea3d19bf01b2809f362a03dd7921fd" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/tzlocal/tzlocal-5.3.1-py3-none-any.whl", hash = "sha256:eb1a66c3ef5847adf7a834f1be0800581b683b5608e74f86ecbcef8ab91bb85d" }, +] + +[[package]] +name = "urllib3" +version = "2.6.3" +source = { registry = "https://bytedpypi.byted.org/simple/" } +sdist = { url = "https://bytedpypi.byted.org/packages/urllib3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/urllib3/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4" }, +] + +[[package]] +name = "websocket-client" +version = "1.9.0" +source = { registry = "https://bytedpypi.byted.org/simple/" } +sdist = { url = "https://bytedpypi.byted.org/packages/websocket-client/websocket_client-1.9.0.tar.gz", hash = "sha256:9e813624b6eb619999a97dc7958469217c3176312b3a16a4bd1bc7e08a46ec98" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/websocket-client/websocket_client-1.9.0-py3-none-any.whl", hash = "sha256:af248a825037ef591efbf6ed20cc5faa03d3b47b9e5a2230a529eeee1c1fc3ef" }, +] + +[[package]] +name = "websockets" +version = "16.0" +source = { registry = "https://bytedpypi.byted.org/simple/" } +sdist = { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0.tar.gz", hash = "sha256:5f6261a5e56e8d5c42a4497b364ea24d94d9563e8fbd44e78ac40879c60179b5" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:31a52addea25187bde0797a97d6fc3d2f92b6f72a9370792d65a6e84615ac8a8" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:417b28978cdccab24f46400586d128366313e8a96312e4b9362a4af504f3bbad" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:af80d74d4edfa3cb9ed973a0a5ba2b2a549371f8a741e0800cb07becdd20f23d" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:08d7af67b64d29823fed316505a89b86705f2b7981c07848fb5e3ea3020c1abe" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7be95cfb0a4dae143eaed2bcba8ac23f4892d8971311f1b06f3c6b78952ee70b" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d6297ce39ce5c2e6feb13c1a996a2ded3b6832155fcfc920265c76f24c7cceb5" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1c1b30e4f497b0b354057f3467f56244c603a79c0d1dafce1d16c283c25f6e64" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp311-cp311-win32.whl", hash = "sha256:5f451484aeb5cafee1ccf789b1b66f535409d038c56966d6101740c1614b86c6" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp311-cp311-win_amd64.whl", hash = "sha256:8d7f0659570eefb578dacde98e24fb60af35350193e4f56e11190787bee77dac" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:71c989cbf3254fbd5e84d3bff31e4da39c43f884e64f2551d14bb3c186230f00" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8b6e209ffee39ff1b6d0fa7bfef6de950c60dfb91b8fcead17da4ee539121a79" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:86890e837d61574c92a97496d590968b23c2ef0aeb8a9bc9421d174cd378ae39" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9b5aca38b67492ef518a8ab76851862488a478602229112c4b0d58d63a7a4d5c" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e0334872c0a37b606418ac52f6ab9cfd17317ac26365f7f65e203e2d0d0d359f" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a0b31e0b424cc6b5a04b8838bbaec1688834b2383256688cf47eb97412531da1" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:485c49116d0af10ac698623c513c1cc01c9446c058a4e61e3bf6c19dff7335a2" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp312-cp312-win32.whl", hash = "sha256:eaded469f5e5b7294e2bdca0ab06becb6756ea86894a47806456089298813c89" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp312-cp312-win_amd64.whl", hash = "sha256:5569417dc80977fc8c2d43a86f78e0a5a22fee17565d78621b6bb264a115d4ea" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:878b336ac47938b474c8f982ac2f7266a540adc3fa4ad74ae96fea9823a02cc9" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:52a0fec0e6c8d9a784c2c78276a48a2bdf099e4ccc2a4cad53b27718dbfd0230" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e6578ed5b6981005df1860a56e3617f14a6c307e6a71b4fff8c48fdc50f3ed2c" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:95724e638f0f9c350bb1c2b0a7ad0e83d9cc0c9259f3ea94e40d7b02a2179ae5" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c0204dc62a89dc9d50d682412c10b3542d748260d743500a85c13cd1ee4bde82" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:52ac480f44d32970d66763115edea932f1c5b1312de36df06d6b219f6741eed8" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6e5a82b677f8f6f59e8dfc34ec06ca6b5b48bc4fcda346acd093694cc2c24d8f" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp313-cp313-win32.whl", hash = "sha256:abf050a199613f64c886ea10f38b47770a65154dc37181bfaff70c160f45315a" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp313-cp313-win_amd64.whl", hash = "sha256:3425ac5cf448801335d6fdc7ae1eb22072055417a96cc6b31b3861f455fbc156" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8cc451a50f2aee53042ac52d2d053d08bf89bcb31ae799cb4487587661c038a0" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:daa3b6ff70a9241cf6c7fc9e949d41232d9d7d26fd3522b1ad2b4d62487e9904" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:fd3cb4adb94a2a6e2b7c0d8d05cb94e6f1c81a0cf9dc2694fb65c7e8d94c42e4" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:781caf5e8eee67f663126490c2f96f40906594cb86b408a703630f95550a8c3e" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:caab51a72c51973ca21fa8a18bd8165e1a0183f1ac7066a182ff27107b71e1a4" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:19c4dc84098e523fd63711e563077d39e90ec6702aff4b5d9e344a60cb3c0cb1" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:a5e18a238a2b2249c9a9235466b90e96ae4795672598a58772dd806edc7ac6d3" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp314-cp314-win32.whl", hash = "sha256:a069d734c4a043182729edd3e9f247c3b2a4035415a9172fd0f1b71658a320a8" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp314-cp314-win_amd64.whl", hash = "sha256:c0ee0e63f23914732c6d7e0cce24915c48f3f1512ec1d079ed01fc629dab269d" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:a35539cacc3febb22b8f4d4a99cc79b104226a756aa7400adc722e83b0d03244" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:b784ca5de850f4ce93ec85d3269d24d4c82f22b7212023c974c401d4980ebc5e" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:569d01a4e7fba956c5ae4fc988f0d4e187900f5497ce46339c996dbf24f17641" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:50f23cdd8343b984957e4077839841146f67a3d31ab0d00e6b824e74c5b2f6e8" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:152284a83a00c59b759697b7f9e9cddf4e3c7861dd0d964b472b70f78f89e80e" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:bc59589ab64b0022385f429b94697348a6a234e8ce22544e3681b2e9331b5944" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:32da954ffa2814258030e5a57bc73a3635463238e797c7375dc8091327434206" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp314-cp314t-win32.whl", hash = "sha256:5a4b4cc550cb665dd8a47f868c8d04c8230f857363ad3c9caf7a0c3bf8c61ca6" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp314-cp314t-win_amd64.whl", hash = "sha256:b14dc141ed6d2dde437cddb216004bcac6a1df0935d79656387bd41632ba0bbd" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:349f83cd6c9a415428ee1005cadb5c2c56f4389bc06a9af16103c3bc3dcc8b7d" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:4a1aba3340a8dca8db6eb5a7986157f52eb9e436b74813764241981ca4888f03" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-pp311-pypy311_pp73-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f4a32d1bd841d4bcbffdcb3d2ce50c09c3909fbead375ab28d0181af89fd04da" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0298d07ee155e2e9fda5be8a9042200dd2e3bb0b8a38482156576f863a9d457c" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:a653aea902e0324b52f1613332ddf50b00c06fdaf7e92624fbf8c77c78fa5767" }, + { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-py3-none-any.whl", hash = "sha256:1637db62fad1dc833276dded54215f2c7fa46912301a24bd94d45d46a011ceec" }, +] + +[[package]] +name = "win32-setctime" +version = "1.2.0" +source = { registry = "https://bytedpypi.byted.org/simple/" } +sdist = { url = "https://bytedpypi.byted.org/packages/win32-setctime/win32_setctime-1.2.0.tar.gz", hash = "sha256:ae1fdf948f5640aae05c511ade119313fb6a30d7eabe25fef9764dca5873c4c0" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/win32-setctime/win32_setctime-1.2.0-py3-none-any.whl", hash = "sha256:95d644c4e708aba81dc3704a116d8cbc974d70b3bdb8be1d150e36be6e9d1390" }, +] + +[[package]] +name = "yarl" +version = "1.22.0" +source = { registry = "https://bytedpypi.byted.org/simple/" } +dependencies = [ + { name = "idna" }, + { name = "multidict" }, + { name = "propcache" }, +] +sdist = { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0.tar.gz", hash = "sha256:bebf8557577d4401ba8bd9ff33906f1376c877aa78d1fe216ad01b4d6745af71" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1ab72135b1f2db3fed3997d7e7dc1b80573c67138023852b6efb336a5eae6511" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:669930400e375570189492dc8d8341301578e8493aec04aebc20d4717f899dd6" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:792a2af6d58177ef7c19cbf0097aba92ca1b9cb3ffdd9c7470e156c8f9b5e028" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3ea66b1c11c9150f1372f69afb6b8116f2dd7286f38e14ea71a44eee9ec51b9d" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3e2daa88dc91870215961e96a039ec73e4937da13cf77ce17f9cad0c18df3503" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ba440ae430c00eee41509353628600212112cd5018d5def7e9b05ea7ac34eb65" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e6438cc8f23a9c1478633d216b16104a586b9761db62bfacb6425bac0a36679e" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c52a6e78aef5cf47a98ef8e934755abf53953379b7d53e68b15ff4420e6683d" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3b06bcadaac49c70f4c88af4ffcfbe3dc155aab3163e75777818092478bcbbe7" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:6944b2dc72c4d7f7052683487e3677456050ff77fcf5e6204e98caf785ad1967" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:d5372ca1df0f91a86b047d1277c2aaf1edb32d78bbcefffc81b40ffd18f027ed" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:51af598701f5299012b8416486b40fceef8c26fc87dc6d7d1f6fc30609ea0aa6" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b266bd01fedeffeeac01a79ae181719ff848a5a13ce10075adbefc8f1daee70e" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp311-cp311-win32.whl", hash = "sha256:a9b1ba5610a4e20f655258d5a1fdc7ebe3d837bb0e45b581398b99eb98b1f5ca" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp311-cp311-win_amd64.whl", hash = "sha256:078278b9b0b11568937d9509b589ee83ef98ed6d561dfe2020e24a9fd08eaa2b" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp311-cp311-win_arm64.whl", hash = "sha256:b6a6f620cfe13ccec221fa312139135166e47ae169f8253f72a0abc0dae94376" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e340382d1afa5d32b892b3ff062436d592ec3d692aeea3bef3a5cfe11bbf8c6f" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f1e09112a2c31ffe8d80be1b0988fa6a18c5d5cad92a9ffbb1c04c91bfe52ad2" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:939fe60db294c786f6b7c2d2e121576628468f65453d86b0fe36cb52f987bd74" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e1651bf8e0398574646744c1885a41198eba53dc8a9312b954073f845c90a8df" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b8a0588521a26bf92a57a1705b77b8b59044cdceccac7151bd8d229e66b8dedb" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:42188e6a615c1a75bcaa6e150c3fe8f3e8680471a6b10150c5f7e83f47cc34d2" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f6d2cb59377d99718913ad9a151030d6f83ef420a2b8f521d94609ecc106ee82" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50678a3b71c751d58d7908edc96d332af328839eea883bb554a43f539101277a" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e8fbaa7cec507aa24ea27a01456e8dd4b6fab829059b69844bd348f2d467124" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:433885ab5431bc3d3d4f2f9bd15bfa1614c522b0f1405d62c4f926ccd69d04fa" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:b790b39c7e9a4192dc2e201a282109ed2985a1ddbd5ac08dc56d0e121400a8f7" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:31f0b53913220599446872d757257be5898019c85e7971599065bc55065dc99d" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a49370e8f711daec68d09b821a34e1167792ee2d24d405cbc2387be4f158b520" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp312-cp312-win32.whl", hash = "sha256:70dfd4f241c04bd9239d53b17f11e6ab672b9f1420364af63e8531198e3f5fe8" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp312-cp312-win_amd64.whl", hash = "sha256:8884d8b332a5e9b88e23f60bb166890009429391864c685e17bd73a9eda9105c" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp312-cp312-win_arm64.whl", hash = "sha256:ea70f61a47f3cc93bdf8b2f368ed359ef02a01ca6393916bc8ff877427181e74" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8dee9c25c74997f6a750cd317b8ca63545169c098faee42c84aa5e506c819b53" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:01e73b85a5434f89fc4fe27dcda2aff08ddf35e4d47bbbea3bdcd25321af538a" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:22965c2af250d20c873cdbee8ff958fb809940aeb2e74ba5f20aaf6b7ac8c70c" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b4f15793aa49793ec8d1c708ab7f9eded1aa72edc5174cae703651555ed1b601" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e5542339dcf2747135c5c85f68680353d5cb9ffd741c0f2e8d832d054d41f35a" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5c401e05ad47a75869c3ab3e35137f8468b846770587e70d71e11de797d113df" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:243dda95d901c733f5b59214d28b0120893d91777cb8aa043e6ef059d3cddfe2" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bec03d0d388060058f5d291a813f21c011041938a441c593374da6077fe21b1b" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b0748275abb8c1e1e09301ee3cf90c8a99678a4e92e4373705f2a2570d581273" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:47fdb18187e2a4e18fda2c25c05d8251a9e4a521edaed757fef033e7d8498d9a" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c7044802eec4524fde550afc28edda0dd5784c4c45f0be151a2d3ba017daca7d" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:139718f35149ff544caba20fce6e8a2f71f1e39b92c700d8438a0b1d2a631a02" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e1b51bebd221006d3d2f95fbe124b22b247136647ae5dcc8c7acafba66e5ee67" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313-win32.whl", hash = "sha256:d3e32536234a95f513bd374e93d717cf6b2231a791758de6c509e3653f234c95" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313-win_amd64.whl", hash = "sha256:47743b82b76d89a1d20b83e60d5c20314cbd5ba2befc9cda8f28300c4a08ed4d" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313-win_arm64.whl", hash = "sha256:5d0fcda9608875f7d052eff120c7a5da474a6796fe4d83e152e0e4d42f6d1a9b" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:719ae08b6972befcba4310e49edb1161a88cdd331e3a694b84466bd938a6ab10" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:47d8a5c446df1c4db9d21b49619ffdba90e77c89ec6e283f453856c74b50b9e3" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:cfebc0ac8333520d2d0423cbbe43ae43c8838862ddb898f5ca68565e395516e9" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4398557cbf484207df000309235979c79c4356518fd5c99158c7d38203c4da4f" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2ca6fd72a8cd803be290d42f2dec5cdcd5299eeb93c2d929bf060ad9efaf5de0" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ca1f59c4e1ab6e72f0a23c13fca5430f889634166be85dbf1013683e49e3278e" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6c5010a52015e7c70f86eb967db0f37f3c8bd503a695a49f8d45700144667708" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d7672ecf7557476642c88497c2f8d8542f8e36596e928e9bcba0e42e1e7d71f" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:3b7c88eeef021579d600e50363e0b6ee4f7f6f728cd3486b9d0f3ee7b946398d" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f4afb5c34f2c6fecdcc182dfcfc6af6cccf1aa923eed4d6a12e9d96904e1a0d8" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:59c189e3e99a59cf8d83cbb31d4db02d66cda5a1a4374e8a012b51255341abf5" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:5a3bf7f62a289fa90f1990422dc8dff5a458469ea71d1624585ec3a4c8d6960f" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:de6b9a04c606978fdfe72666fa216ffcf2d1a9f6a381058d4378f8d7b1e5de62" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313t-win32.whl", hash = "sha256:1834bb90991cc2999f10f97f5f01317f99b143284766d197e43cd5b45eb18d03" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ff86011bd159a9d2dfc89c34cfd8aff12875980e3bd6a39ff097887520e60249" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313t-win_arm64.whl", hash = "sha256:7861058d0582b847bc4e3a4a4c46828a410bca738673f35a29ba3ca5db0b473b" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:34b36c2c57124530884d89d50ed2c1478697ad7473efd59cfd479945c95650e4" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:0dd9a702591ca2e543631c2a017e4a547e38a5c0f29eece37d9097e04a7ac683" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:594fcab1032e2d2cc3321bb2e51271e7cd2b516c7d9aee780ece81b07ff8244b" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f3d7a87a78d46a2e3d5b72587ac14b4c16952dd0887dbb051451eceac774411e" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:852863707010316c973162e703bddabec35e8757e67fcb8ad58829de1ebc8590" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:131a085a53bfe839a477c0845acf21efc77457ba2bcf5899618136d64f3303a2" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:078a8aefd263f4d4f923a9677b942b445a2be970ca24548a8102689a3a8ab8da" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bca03b91c323036913993ff5c738d0842fc9c60c4648e5c8d98331526df89784" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:68986a61557d37bb90d3051a45b91fa3d5c516d177dfc6dd6f2f436a07ff2b6b" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:4792b262d585ff0dff6bcb787f8492e40698443ec982a3568c2096433660c694" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:ebd4549b108d732dba1d4ace67614b9545b21ece30937a63a65dd34efa19732d" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:f87ac53513d22240c7d59203f25cc3beac1e574c6cd681bbfd321987b69f95fd" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:22b029f2881599e2f1b06f8f1db2ee63bd309e2293ba2d566e008ba12778b8da" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314-win32.whl", hash = "sha256:6a635ea45ba4ea8238463b4f7d0e721bad669f80878b7bfd1f89266e2ae63da2" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314-win_amd64.whl", hash = "sha256:0d6e6885777af0f110b0e5d7e5dda8b704efed3894da26220b7f3d887b839a79" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314-win_arm64.whl", hash = "sha256:8218f4e98d3c10d683584cb40f0424f4b9fd6e95610232dd75e13743b070ee33" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:45c2842ff0e0d1b35a6bf1cd6c690939dacb617a70827f715232b2e0494d55d1" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:d947071e6ebcf2e2bee8fce76e10faca8f7a14808ca36a910263acaacef08eca" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:334b8721303e61b00019474cc103bdac3d7b1f65e91f0bfedeec2d56dfe74b53" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e7ce67c34138a058fd092f67d07a72b8e31ff0c9236e751957465a24b28910c" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d77e1b2c6d04711478cb1c4ab90db07f1609ccf06a287d5607fcd90dc9863acf" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4647674b6150d2cae088fc07de2738a84b8bcedebef29802cf0b0a82ab6face" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:efb07073be061c8f79d03d04139a80ba33cbd390ca8f0297aae9cce6411e4c6b" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e51ac5435758ba97ad69617e13233da53908beccc6cfcd6c34bbed8dcbede486" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:33e32a0dd0c8205efa8e83d04fc9f19313772b78522d1bdc7d9aed706bfd6138" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:bf4a21e58b9cde0e401e683ebd00f6ed30a06d14e93f7c8fd059f8b6e8f87b6a" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:e4b582bab49ac33c8deb97e058cd67c2c50dac0dd134874106d9c774fd272529" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:0b5bcc1a9c4839e7e30b7b30dd47fe5e7e44fb7054ec29b5bb8d526aa1041093" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c0232bce2170103ec23c454e54a57008a9a72b5d1c3105dc2496750da8cfa47c" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314t-win32.whl", hash = "sha256:8009b3173bcd637be650922ac455946197d858b3630b6d8787aa9e5c4564533e" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314t-win_amd64.whl", hash = "sha256:9fb17ea16e972c63d25d4a97f016d235c78dd2344820eb35bc034bc32012ee27" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314t-win_arm64.whl", hash = "sha256:9f6d73c1436b934e3f01df1e1b21ff765cd1d28c77dfb9ace207f746d4610ee1" }, + { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-py3-none-any.whl", hash = "sha256:1380560bdba02b6b6c90de54133c81c9f2a453dee9912fe58c1dcced1edb7cff" }, +] + +[[package]] +name = "zipp" +version = "3.23.0" +source = { registry = "https://bytedpypi.byted.org/simple/" } +sdist = { url = "https://bytedpypi.byted.org/packages/zipp/zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166" } +wheels = [ + { url = "https://bytedpypi.byted.org/packages/zipp/zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e" }, +] From 442136a313acd37930296b954e205d44272bc267 Mon Sep 17 00:00:00 2001 From: qiupinhua Date: Fri, 13 Feb 2026 18:52:43 +0800 Subject: [PATCH 17/60] fix: remove uv.lock --- uv.lock | 2385 ------------------------------------------------------- 1 file changed, 2385 deletions(-) delete mode 100644 uv.lock diff --git a/uv.lock b/uv.lock deleted file mode 100644 index 3eaeaba..0000000 --- a/uv.lock +++ /dev/null @@ -1,2385 +0,0 @@ -version = 1 -revision = 3 -requires-python = ">=3.11" -resolution-markers = [ - "python_full_version >= '3.14'", - "python_full_version < '3.14'", -] - -[[package]] -name = "aiohappyeyeballs" -version = "2.6.1" -source = { registry = "https://bytedpypi.byted.org/simple/" } -sdist = { url = "https://bytedpypi.byted.org/packages/aiohappyeyeballs/aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/aiohappyeyeballs/aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8" }, -] - -[[package]] -name = "aiohttp" -version = "3.13.3" -source = { registry = "https://bytedpypi.byted.org/simple/" } -dependencies = [ - { name = "aiohappyeyeballs" }, - { name = "aiosignal" }, - { name = "attrs" }, - { name = "frozenlist" }, - { name = "multidict" }, - { name = "propcache" }, - { name = "yarl" }, -] -sdist = { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3.tar.gz", hash = "sha256:a949eee43d3782f2daae4f4a2819b2cb9b0c5d3b7f7a927067cc84dafdbb9f88" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5b6073099fb654e0a068ae678b10feff95c5cae95bbfcbfa7af669d361a8aa6b" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cb93e166e6c28716c8c6aeb5f99dfb6d5ccf482d29fe9bf9a794110e6d0ab64" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:28e027cf2f6b641693a09f631759b4d9ce9165099d2b5d92af9bd4e197690eea" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3b61b7169ababd7802f9568ed96142616a9118dd2be0d1866e920e77ec8fa92a" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:80dd4c21b0f6237676449c6baaa1039abae86b91636b6c91a7f8e61c87f89540" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:65d2ccb7eabee90ce0503c17716fc77226be026dcc3e65cce859a30db715025b" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5b179331a481cb5529fca8b432d8d3c7001cb217513c94cd72d668d1248688a3" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d4c940f02f49483b18b079d1c27ab948721852b281f8b015c058100e9421dd1" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f9444f105664c4ce47a2a7171a2418bce5b7bae45fb610f4e2c36045d85911d3" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:694976222c711d1d00ba131904beb60534f93966562f64440d0c9d41b8cdb440" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:f33ed1a2bf1997a36661874b017f5c4b760f41266341af36febaf271d179f6d7" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e636b3c5f61da31a92bf0d91da83e58fdfa96f178ba682f11d24f31944cdd28c" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:5d2d94f1f5fcbe40838ac51a6ab5704a6f9ea42e72ceda48de5e6b898521da51" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2be0e9ccf23e8a94f6f0650ce06042cefc6ac703d0d7ab6c7a917289f2539ad4" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9af5e68ee47d6534d36791bbe9b646d2a7c7deb6fc24d7943628edfbb3581f29" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp311-cp311-win32.whl", hash = "sha256:a2212ad43c0833a873d0fb3c63fa1bacedd4cf6af2fee62bf4b739ceec3ab239" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp311-cp311-win_amd64.whl", hash = "sha256:642f752c3eb117b105acbd87e2c143de710987e09860d674e068c4c2c441034f" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:b903a4dfee7d347e2d87697d0713be59e0b87925be030c9178c5faa58ea58d5c" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a45530014d7a1e09f4a55f4f43097ba0fd155089372e105e4bff4ca76cb1b168" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:27234ef6d85c914f9efeb77ff616dbf4ad2380be0cda40b4db086ffc7ddd1b7d" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d32764c6c9aafb7fb55366a224756387cd50bfa720f32b88e0e6fa45b27dcf29" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b1a6102b4d3ebc07dad44fbf07b45bb600300f15b552ddf1851b5390202ea2e3" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c014c7ea7fb775dd015b2d3137378b7be0249a448a1612268b5a90c2d81de04d" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2b8d8ddba8f95ba17582226f80e2de99c7a7948e66490ef8d947e272a93e9463" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9ae8dd55c8e6c4257eae3a20fd2c8f41edaea5992ed67156642493b8daf3cecc" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:01ad2529d4b5035578f5081606a465f3b814c542882804e2e8cda61adf5c71bf" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bb4f7475e359992b580559e008c598091c45b5088f28614e855e42d39c2f1033" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:c19b90316ad3b24c69cd78d5c9b4f3aa4497643685901185b65166293d36a00f" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:96d604498a7c782cb15a51c406acaea70d8c027ee6b90c569baa6e7b93073679" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:084911a532763e9d3dd95adf78a78f4096cd5f58cdc18e6fdbc1b58417a45423" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:7a4a94eb787e606d0a09404b9c38c113d3b099d508021faa615d70a0131907ce" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:87797e645d9d8e222e04160ee32aa06bc5c163e8499f24db719e7852ec23093a" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp312-cp312-win32.whl", hash = "sha256:b04be762396457bef43f3597c991e192ee7da460a4953d7e647ee4b1c28e7046" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp312-cp312-win_amd64.whl", hash = "sha256:e3531d63d3bdfa7e3ac5e9b27b2dd7ec9df3206a98e0b3445fa906f233264c57" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:5dff64413671b0d3e7d5918ea490bdccb97a4ad29b3f311ed423200b2203e01c" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:87b9aab6d6ed88235aa2970294f496ff1a1f9adcd724d800e9b952395a80ffd9" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:425c126c0dc43861e22cb1c14ba4c8e45d09516d0a3ae0a3f7494b79f5f233a3" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7f9120f7093c2a32d9647abcaf21e6ad275b4fbec5b55969f978b1a97c7c86bf" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:697753042d57f4bf7122cab985bf15d0cef23c770864580f5af4f52023a56bd6" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6de499a1a44e7de70735d0b39f67c8f25eb3d91eb3103be99ca0fa882cdd987d" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:37239e9f9a7ea9ac5bf6b92b0260b01f8a22281996da609206a84df860bc1261" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f76c1e3fe7d7c8afad7ed193f89a292e1999608170dcc9751a7462a87dfd5bc0" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fc290605db2a917f6e81b0e1e0796469871f5af381ce15c604a3c5c7e51cb730" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4021b51936308aeea0367b8f006dc999ca02bc118a0cc78c303f50a2ff6afb91" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:49a03727c1bba9a97d3e93c9f93ca03a57300f484b6e935463099841261195d3" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3d9908a48eb7416dc1f4524e69f1d32e5d90e3981e4e37eb0aa1cd18f9cfa2a4" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:2712039939ec963c237286113c68dbad80a82a4281543f3abf766d9d73228998" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:7bfdc049127717581866fa4708791220970ce291c23e28ccf3922c700740fdc0" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8057c98e0c8472d8846b9c79f56766bcc57e3e8ac7bfd510482332366c56c591" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp313-cp313-win32.whl", hash = "sha256:1449ceddcdbcf2e0446957863af03ebaaa03f94c090f945411b61269e2cb5daf" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp313-cp313-win_amd64.whl", hash = "sha256:693781c45a4033d31d4187d2436f5ac701e7bbfe5df40d917736108c1cc7436e" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:ea37047c6b367fd4bd632bff8077449b8fa034b69e812a18e0132a00fae6e808" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:6fc0e2337d1a4c3e6acafda6a78a39d4c14caea625124817420abceed36e2415" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c685f2d80bb67ca8c3837823ad76196b3694b0159d232206d1e461d3d434666f" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48e377758516d262bde50c2584fc6c578af272559c409eecbdd2bae1601184d6" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:34749271508078b261c4abb1767d42b8d0c0cc9449c73a4df494777dc55f0687" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:82611aeec80eb144416956ec85b6ca45a64d76429c1ed46ae1b5f86c6e0c9a26" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2fff83cfc93f18f215896e3a190e8e5cb413ce01553901aca925176e7568963a" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bbe7d4cecacb439e2e2a8a1a7b935c25b812af7a5fd26503a66dadf428e79ec1" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b928f30fe49574253644b1ca44b1b8adbd903aa0da4b9054a6c20fc7f4092a25" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7b5e8fe4de30df199155baaf64f2fcd604f4c678ed20910db8e2c66dc4b11603" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:8542f41a62bcc58fc7f11cf7c90e0ec324ce44950003feb70640fc2a9092c32a" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:5e1d8c8b8f1d91cd08d8f4a3c2b067bfca6ec043d3ff36de0f3a715feeedf926" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:90455115e5da1c3c51ab619ac57f877da8fd6d73c05aacd125c5ae9819582aba" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:042e9e0bcb5fba81886c8b4fbb9a09d6b8a00245fd8d88e4d989c1f96c74164c" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2eb752b102b12a76ca02dff751a801f028b4ffbbc478840b473597fc91a9ed43" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314-win32.whl", hash = "sha256:b556c85915d8efaed322bf1bdae9486aa0f3f764195a0fb6ee962e5c71ef5ce1" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314-win_amd64.whl", hash = "sha256:9bf9f7a65e7aa20dd764151fb3d616c81088f91f8df39c3893a536e279b4b984" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:05861afbbec40650d8a07ea324367cb93e9e8cc7762e04dd4405df99fa65159c" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2fc82186fadc4a8316768d61f3722c230e2c1dcab4200d52d2ebdf2482e47592" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0add0900ff220d1d5c5ebbf99ed88b0c1bbf87aa7e4262300ed1376a6b13414f" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:568f416a4072fbfae453dcf9a99194bbb8bdeab718e08ee13dfa2ba0e4bebf29" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:add1da70de90a2569c5e15249ff76a631ccacfe198375eead4aadf3b8dc849dc" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:10b47b7ba335d2e9b1239fa571131a87e2d8ec96b333e68b2a305e7a98b0bae2" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3dd4dce1c718e38081c8f35f323209d4c1df7d4db4bab1b5c88a6b4d12b74587" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:34bac00a67a812570d4a460447e1e9e06fae622946955f939051e7cc895cfab8" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a19884d2ee70b06d9204b2727a7b9f983d0c684c650254679e716b0b77920632" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5f8ca7f2bb6ba8348a3614c7918cc4bb73268c5ac2a207576b7afea19d3d9f64" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:b0d95340658b9d2f11d9697f59b3814a9d3bb4b7a7c20b131df4bcef464037c0" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:a1e53262fd202e4b40b70c3aff944a8155059beedc8a89bba9dc1f9ef06a1b56" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:d60ac9663f44168038586cab2157e122e46bdef09e9368b37f2d82d354c23f72" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:90751b8eed69435bac9ff4e3d2f6b3af1f57e37ecb0fbeee59c0174c9e2d41df" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:fc353029f176fd2b3ec6cfc71be166aba1936fe5d73dd1992ce289ca6647a9aa" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314t-win32.whl", hash = "sha256:2e41b18a58da1e474a057b3d35248d8320029f61d70a37629535b16a0c8f3767" }, - { url = "https://bytedpypi.byted.org/packages/aiohttp/aiohttp-3.13.3-cp314-cp314t-win_amd64.whl", hash = "sha256:44531a36aa2264a1860089ffd4dce7baf875ee5a6079d5fb42e261c704ef7344" }, -] - -[[package]] -name = "aiosignal" -version = "1.4.0" -source = { registry = "https://bytedpypi.byted.org/simple/" } -dependencies = [ - { name = "frozenlist" }, - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, -] -sdist = { url = "https://bytedpypi.byted.org/packages/aiosignal/aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/aiosignal/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e" }, -] - -[[package]] -name = "annotated-doc" -version = "0.0.4" -source = { registry = "https://bytedpypi.byted.org/simple/" } -sdist = { url = "https://bytedpypi.byted.org/packages/annotated-doc/annotated_doc-0.0.4.tar.gz", hash = "sha256:fbcda96e87e9c92ad167c2e53839e57503ecfda18804ea28102353485033faa4" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/annotated-doc/annotated_doc-0.0.4-py3-none-any.whl", hash = "sha256:571ac1dc6991c450b25a9c2d84a3705e2ae7a53467b5d111c24fa8baabbed320" }, -] - -[[package]] -name = "annotated-types" -version = "0.7.0" -source = { registry = "https://bytedpypi.byted.org/simple/" } -sdist = { url = "https://bytedpypi.byted.org/packages/annotated-types/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/annotated-types/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53" }, -] - -[[package]] -name = "anyio" -version = "4.12.1" -source = { registry = "https://bytedpypi.byted.org/simple/" } -dependencies = [ - { name = "idna" }, - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, -] -sdist = { url = "https://bytedpypi.byted.org/packages/anyio/anyio-4.12.1.tar.gz", hash = "sha256:41cfcc3a4c85d3f05c932da7c26d0201ac36f72abd4435ba90d0464a3ffed703" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/anyio/anyio-4.12.1-py3-none-any.whl", hash = "sha256:d405828884fc140aa80a3c667b8beed277f1dfedec42ba031bd6ac3db606ab6c" }, -] - -[[package]] -name = "apscheduler" -version = "3.11.2" -source = { registry = "https://bytedpypi.byted.org/simple/" } -dependencies = [ - { name = "tzlocal" }, -] -sdist = { url = "https://bytedpypi.byted.org/packages/apscheduler/apscheduler-3.11.2.tar.gz", hash = "sha256:2a9966b052ec805f020c8c4c3ae6e6a06e24b1bf19f2e11d91d8cca0473eef41" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/apscheduler/apscheduler-3.11.2-py3-none-any.whl", hash = "sha256:ce005177f741409db4e4dd40a7431b76feb856b9dd69d57e0da49d6715bfd26d" }, -] - -[[package]] -name = "attrs" -version = "25.4.0" -source = { registry = "https://bytedpypi.byted.org/simple/" } -sdist = { url = "https://bytedpypi.byted.org/packages/attrs/attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/attrs/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373" }, -] - -[[package]] -name = "certifi" -version = "2026.1.4" -source = { registry = "https://bytedpypi.byted.org/simple/" } -sdist = { url = "https://bytedpypi.byted.org/packages/certifi/certifi-2026.1.4.tar.gz", hash = "sha256:ac726dd470482006e014ad384921ed6438c457018f4b3d204aea4281258b2120" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/certifi/certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c" }, -] - -[[package]] -name = "chardet" -version = "5.2.0" -source = { registry = "https://bytedpypi.byted.org/simple/" } -sdist = { url = "https://bytedpypi.byted.org/packages/chardet/chardet-5.2.0.tar.gz", hash = "sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/chardet/chardet-5.2.0-py3-none-any.whl", hash = "sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970" }, -] - -[[package]] -name = "charset-normalizer" -version = "3.4.4" -source = { registry = "https://bytedpypi.byted.org/simple/" } -sdist = { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6e1fcf0720908f200cd21aa4e6750a48ff6ce4afe7ff5a79a90d5ed8a08296f8" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f819d5fe9234f9f82d75bdfa9aef3a3d72c4d24a6e57aeaebba32a704553aa0" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a59cb51917aa591b1c4e6a43c132f0cdc3c76dbad6155df4e28ee626cc77a0a3" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8ef3c867360f88ac904fd3f5e1f902f13307af9052646963ee08ff4f131adafc" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d9e45d7faa48ee908174d8fe84854479ef838fc6a705c9315372eacbc2f02897" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:840c25fb618a231545cbab0564a799f101b63b9901f2569faecd6b222ac72381" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ca5862d5b3928c4940729dacc329aa9102900382fea192fc5e52eb69d6093815" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d9c7f57c3d666a53421049053eaacdd14bbd0a528e2186fcb2e672effd053bb0" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:277e970e750505ed74c832b4bf75dac7476262ee2a013f5574dd49075879e161" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:31fd66405eaf47bb62e8cd575dc621c56c668f27d46a61d975a249930dd5e2a4" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:0d3d8f15c07f86e9ff82319b3d9ef6f4bf907608f53fe9d92b28ea9ae3d1fd89" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:9f7fcd74d410a36883701fafa2482a6af2ff5ba96b9a620e9e0721e28ead5569" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ebf3e58c7ec8a8bed6d66a75d7fb37b55e5015b03ceae72a8e7c74495551e224" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp311-cp311-win32.whl", hash = "sha256:eecbc200c7fd5ddb9a7f16c7decb07b566c29fa2161a16cf67b8d068bd21690a" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:5ae497466c7901d54b639cf42d5b8c1b6a4fead55215500d2f486d34db48d016" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp311-cp311-win_arm64.whl", hash = "sha256:65e2befcd84bc6f37095f5961e68a6f077bf44946771354a28ad434c2cce0ae1" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0a98e6759f854bd25a58a73fa88833fba3b7c491169f86ce1180c948ab3fd394" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b5b290ccc2a263e8d185130284f8501e3e36c5e02750fc6b6bdeb2e9e96f1e25" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74bb723680f9f7a6234dcf67aea57e708ec1fbdf5699fb91dfd6f511b0a320ef" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f1e34719c6ed0b92f418c7c780480b26b5d9c50349e9a9af7d76bf757530350d" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2437418e20515acec67d86e12bf70056a33abdacb5cb1655042f6538d6b085a8" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11d694519d7f29d6cd09f6ac70028dba10f92f6cdd059096db198c283794ac86" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ac1c4a689edcc530fc9d9aa11f5774b9e2f33f9a0c6a57864e90908f5208d30a" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:21d142cc6c0ec30d2efee5068ca36c128a30b0f2c53c1c07bd78cb6bc1d3be5f" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5dbe56a36425d26d6cfb40ce79c314a2e4dd6211d51d6d2191c00bed34f354cc" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5bfbb1b9acf3334612667b61bd3002196fe2a1eb4dd74d247e0f2a4d50ec9bbf" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:d055ec1e26e441f6187acf818b73564e6e6282709e9bcb5b63f5b23068356a15" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:af2d8c67d8e573d6de5bc30cdb27e9b95e49115cd9baad5ddbd1a6207aaa82a9" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:780236ac706e66881f3b7f2f32dfe90507a09e67d1d454c762cf642e6e1586e0" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp312-cp312-win32.whl", hash = "sha256:5833d2c39d8896e4e19b689ffc198f08ea58116bee26dea51e362ecc7cd3ed26" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:a79cfe37875f822425b89a82333404539ae63dbdddf97f84dcbc3d339aae9525" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp312-cp312-win_arm64.whl", hash = "sha256:376bec83a63b8021bb5c8ea75e21c4ccb86e7e45ca4eb81146091b56599b80c3" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b39f987ae8ccdf0d2642338faf2abb1862340facc796048b604ef14919e55ed" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3162d5d8ce1bb98dd51af660f2121c55d0fa541b46dff7bb9b9f86ea1d87de72" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:81d5eb2a312700f4ecaa977a8235b634ce853200e828fbadf3a9c50bab278328" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5bd2293095d766545ec1a8f612559f6b40abc0eb18bb2f5d1171872d34036ede" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc7637e2f80d8530ee4a78e878bce464f70087ce73cf7c1caf142416923b98f1" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f8bf04158c6b607d747e93949aa60618b61312fe647a6369f88ce2ff16043490" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:554af85e960429cf30784dd47447d5125aaa3b99a6f0683589dbd27e2f45da44" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:74018750915ee7ad843a774364e13a3db91682f26142baddf775342c3f5b1133" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c0463276121fdee9c49b98908b3a89c39be45d86d1dbaa22957e38f6321d4ce3" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:362d61fd13843997c1c446760ef36f240cf81d3ebf74ac62652aebaf7838561e" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp313-cp313-win32.whl", hash = "sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:da3326d9e65ef63a817ecbcc0df6e94463713b754fe293eaa03da99befb9a5bd" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8af65f14dc14a79b924524b1e7fffe304517b2bff5a58bf64f30b98bbc5079eb" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74664978bb272435107de04e36db5a9735e78232b85b77d45cfb38f758efd33e" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:752944c7ffbfdd10c074dc58ec2d5a8a4cd9493b314d367c14d24c17684ddd14" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1f13550535ad8cff21b8d757a3257963e951d96e20ec82ab44bc64aeb62a191" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ecaae4149d99b1c9e7b88bb03e3221956f68fd6d50be2ef061b2381b61d20838" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cb6254dc36b47a990e59e1068afacdcd02958bdcce30bb50cc1700a8b9d624a6" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c8ae8a0f02f57a6e61203a31428fa1d677cbe50c93622b4149d5c0f319c1d19e" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:47cc91b2f4dd2833fddaedd2893006b0106129d4b94fdb6af1f4ce5a9965577c" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:82004af6c302b5d3ab2cfc4cc5f29db16123b1a8417f2e25f9066f91d4411090" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b7d8f6c26245217bd2ad053761201e9f9680f8ce52f0fcd8d0755aeae5b2152" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:799a7a5e4fb2d5898c60b640fd4981d6a25f1c11790935a44ce38c54e985f828" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:99ae2cffebb06e6c22bdc25801d7b30f503cc87dbd283479e7b606f70aff57ec" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp314-cp314-win32.whl", hash = "sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2" }, - { url = "https://bytedpypi.byted.org/packages/charset-normalizer/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f" }, -] - -[[package]] -name = "click" -version = "8.3.1" -source = { registry = "https://bytedpypi.byted.org/simple/" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, -] -sdist = { url = "https://bytedpypi.byted.org/packages/click/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/click/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6" }, -] - -[[package]] -name = "colorama" -version = "0.4.6" -source = { registry = "https://bytedpypi.byted.org/simple/" } -sdist = { url = "https://bytedpypi.byted.org/packages/colorama/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/colorama/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6" }, -] - -[[package]] -name = "croniter" -version = "6.0.0" -source = { registry = "https://bytedpypi.byted.org/simple/" } -dependencies = [ - { name = "python-dateutil" }, - { name = "pytz" }, -] -sdist = { url = "https://bytedpypi.byted.org/packages/croniter/croniter-6.0.0.tar.gz", hash = "sha256:37c504b313956114a983ece2c2b07790b1f1094fe9d81cc94739214748255577" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/croniter/croniter-6.0.0-py2.py3-none-any.whl", hash = "sha256:2f878c3856f17896979b2a4379ba1f09c83e374931ea15cc835c5dd2eee9b368" }, -] - -[[package]] -name = "cssselect" -version = "1.4.0" -source = { registry = "https://bytedpypi.byted.org/simple/" } -sdist = { url = "https://bytedpypi.byted.org/packages/cssselect/cssselect-1.4.0.tar.gz", hash = "sha256:fdaf0a1425e17dfe8c5cf66191d211b357cf7872ae8afc4c6762ddd8ac47fc92" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/cssselect/cssselect-1.4.0-py3-none-any.whl", hash = "sha256:c0ec5c0191c8ee39fcc8afc1540331d8b55b0183478c50e9c8a79d44dbceb1d8" }, -] - -[[package]] -name = "dingtalk-stream" -version = "0.24.3" -source = { registry = "https://bytedpypi.byted.org/simple/" } -dependencies = [ - { name = "aiohttp" }, - { name = "requests" }, - { name = "websockets" }, -] -wheels = [ - { url = "https://bytedpypi.byted.org/packages/dingtalk-stream/dingtalk_stream-0.24.3-py3-none-any.whl", hash = "sha256:2160403656985962878bf60cdf5adf41619f21067348e06f07a7c7eebf5943ad" }, -] - -[[package]] -name = "distro" -version = "1.9.0" -source = { registry = "https://bytedpypi.byted.org/simple/" } -sdist = { url = "https://bytedpypi.byted.org/packages/distro/distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/distro/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2" }, -] - -[[package]] -name = "fastuuid" -version = "0.14.0" -source = { registry = "https://bytedpypi.byted.org/simple/" } -sdist = { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0.tar.gz", hash = "sha256:178947fc2f995b38497a74172adee64fdeb8b7ec18f2a5934d037641ba265d26" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp311-cp311-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:73946cb950c8caf65127d4e9a325e2b6be0442a224fd51ba3b6ac44e1912ce34" }, - { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:12ac85024637586a5b69645e7ed986f7535106ed3013640a393a03e461740cb7" }, - { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:05a8dde1f395e0c9b4be515b7a521403d1e8349443e7641761af07c7ad1624b1" }, - { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09378a05020e3e4883dfdab438926f31fea15fd17604908f3d39cbeb22a0b4dc" }, - { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbb0c4b15d66b435d2538f3827f05e44e2baafcc003dd7d8472dc67807ab8fd8" }, - { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cd5a7f648d4365b41dbf0e38fe8da4884e57bed4e77c83598e076ac0c93995e7" }, - { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c0a94245afae4d7af8c43b3159d5e3934c53f47140be0be624b96acd672ceb73" }, - { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:2b29e23c97e77c3a9514d70ce343571e469098ac7f5a269320a0f0b3e193ab36" }, - { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1e690d48f923c253f28151b3a6b4e335f2b06bf669c68a02665bc150b7839e94" }, - { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp311-cp311-win32.whl", hash = "sha256:a6f46790d59ab38c6aa0e35c681c0484b50dc0acf9e2679c005d61e019313c24" }, - { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp311-cp311-win_amd64.whl", hash = "sha256:e150eab56c95dc9e3fefc234a0eedb342fac433dacc273cd4d150a5b0871e1fa" }, - { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:77e94728324b63660ebf8adb27055e92d2e4611645bf12ed9d88d30486471d0a" }, - { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:caa1f14d2102cb8d353096bc6ef6c13b2c81f347e6ab9d6fbd48b9dea41c153d" }, - { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d23ef06f9e67163be38cece704170486715b177f6baae338110983f99a72c070" }, - { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0c9ec605ace243b6dbe3bd27ebdd5d33b00d8d1d3f580b39fdd15cd96fd71796" }, - { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:808527f2407f58a76c916d6aa15d58692a4a019fdf8d4c32ac7ff303b7d7af09" }, - { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2fb3c0d7fef6674bbeacdd6dbd386924a7b60b26de849266d1ff6602937675c8" }, - { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab3f5d36e4393e628a4df337c2c039069344db5f4b9d2a3c9cea48284f1dd741" }, - { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:b9a0ca4f03b7e0b01425281ffd44e99d360e15c895f1907ca105854ed85e2057" }, - { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3acdf655684cc09e60fb7e4cf524e8f42ea760031945aa8086c7eae2eeeabeb8" }, - { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp312-cp312-win32.whl", hash = "sha256:9579618be6280700ae36ac42c3efd157049fe4dd40ca49b021280481c78c3176" }, - { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp312-cp312-win_amd64.whl", hash = "sha256:d9e4332dc4ba054434a9594cbfaf7823b57993d7d8e7267831c3e059857cf397" }, - { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:77a09cb7427e7af74c594e409f7731a0cf887221de2f698e1ca0ebf0f3139021" }, - { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:9bd57289daf7b153bfa3e8013446aa144ce5e8c825e9e366d455155ede5ea2dc" }, - { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ac60fc860cdf3c3f327374db87ab8e064c86566ca8c49d2e30df15eda1b0c2d5" }, - { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ab32f74bd56565b186f036e33129da77db8be09178cd2f5206a5d4035fb2a23f" }, - { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33e678459cf4addaedd9936bbb038e35b3f6b2061330fd8f2f6a1d80414c0f87" }, - { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1e3cc56742f76cd25ecb98e4b82a25f978ccffba02e4bdce8aba857b6d85d87b" }, - { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:cb9a030f609194b679e1660f7e32733b7a0f332d519c5d5a6a0a580991290022" }, - { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:09098762aad4f8da3a888eb9ae01c84430c907a297b97166b8abc07b640f2995" }, - { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:1383fff584fa249b16329a059c68ad45d030d5a4b70fb7c73a08d98fd53bcdab" }, - { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp313-cp313-win32.whl", hash = "sha256:a0809f8cc5731c066c909047f9a314d5f536c871a7a22e815cc4967c110ac9ad" }, - { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp313-cp313-win_amd64.whl", hash = "sha256:0df14e92e7ad3276327631c9e7cec09e32572ce82089c55cb1bb8df71cf394ed" }, - { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp314-cp314-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:b852a870a61cfc26c884af205d502881a2e59cc07076b60ab4a951cc0c94d1ad" }, - { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:c7502d6f54cd08024c3ea9b3514e2d6f190feb2f46e6dbcd3747882264bb5f7b" }, - { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1ca61b592120cf314cfd66e662a5b54a578c5a15b26305e1b8b618a6f22df714" }, - { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa75b6657ec129d0abded3bec745e6f7ab642e6dba3a5272a68247e85f5f316f" }, - { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8a0dfea3972200f72d4c7df02c8ac70bad1bb4c58d7e0ec1e6f341679073a7f" }, - { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1bf539a7a95f35b419f9ad105d5a8a35036df35fdafae48fb2fd2e5f318f0d75" }, - { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:9a133bf9cc78fdbd1179cb58a59ad0100aa32d8675508150f3658814aeefeaa4" }, - { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp314-cp314-musllinux_1_1_i686.whl", hash = "sha256:f54d5b36c56a2d5e1a31e73b950b28a0d83eb0c37b91d10408875a5a29494bad" }, - { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:ec27778c6ca3393ef662e2762dba8af13f4ec1aaa32d08d77f71f2a70ae9feb8" }, - { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp314-cp314-win32.whl", hash = "sha256:e23fc6a83f112de4be0cc1990e5b127c27663ae43f866353166f87df58e73d06" }, - { url = "https://bytedpypi.byted.org/packages/fastuuid/fastuuid-0.14.0-cp314-cp314-win_amd64.whl", hash = "sha256:df61342889d0f5e7a32f7284e55ef95103f2110fee433c2ae7c2c0956d76ac8a" }, -] - -[[package]] -name = "filelock" -version = "3.21.2" -source = { registry = "https://bytedpypi.byted.org/simple/" } -sdist = { url = "https://bytedpypi.byted.org/packages/filelock/filelock-3.21.2.tar.gz", hash = "sha256:cfd218cfccf8b947fce7837da312ec3359d10ef2a47c8602edd59e0bacffb708" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/filelock/filelock-3.21.2-py3-none-any.whl", hash = "sha256:d6cd4dbef3e1bb63bc16500fc5aa100f16e405bbff3fb4231711851be50c1560" }, -] - -[[package]] -name = "frozenlist" -version = "1.8.0" -source = { registry = "https://bytedpypi.byted.org/simple/" } -sdist = { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0.tar.gz", hash = "sha256:3ede829ed8d842f6cd48fc7081d7a41001a56f1f38603f9d49bf3020d59a31ad" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:09474e9831bc2b2199fad6da3c14c7b0fbdd377cce9d3d77131be28906cb7d84" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:17c883ab0ab67200b5f964d2b9ed6b00971917d5d8a92df149dc2c9779208ee9" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fa47e444b8ba08fffd1c18e8cdb9a75db1b6a27f17507522834ad13ed5922b93" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2552f44204b744fba866e573be4c1f9048d6a324dfe14475103fd51613eb1d1f" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:957e7c38f250991e48a9a73e6423db1bb9dd14e722a10f6b8bb8e16a0f55f695" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8585e3bb2cdea02fc88ffa245069c36555557ad3609e83be0ec71f54fd4abb52" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:edee74874ce20a373d62dc28b0b18b93f645633c2943fd90ee9d898550770581" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c9a63152fe95756b85f31186bddf42e4c02c6321207fd6601a1c89ebac4fe567" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b6db2185db9be0a04fecf2f241c70b63b1a242e2805be291855078f2b404dd6b" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:f4be2e3d8bc8aabd566f8d5b8ba7ecc09249d74ba3c9ed52e54dc23a293f0b92" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c8d1634419f39ea6f5c427ea2f90ca85126b54b50837f31497f3bf38266e853d" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:1a7fa382a4a223773ed64242dbe1c9c326ec09457e6b8428efb4118c685c3dfd" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:11847b53d722050808926e785df837353bd4d75f1d494377e59b23594d834967" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp311-cp311-win32.whl", hash = "sha256:27c6e8077956cf73eadd514be8fb04d77fc946a7fe9f7fe167648b0b9085cc25" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:ac913f8403b36a2c8610bbfd25b8013488533e71e62b4b4adce9c86c8cea905b" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp311-cp311-win_arm64.whl", hash = "sha256:d4d3214a0f8394edfa3e303136d0575eece0745ff2b47bd2cb2e66dd92d4351a" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:78f7b9e5d6f2fdb88cdde9440dc147259b62b9d3b019924def9f6478be254ac1" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:229bf37d2e4acdaf808fd3f06e854a4a7a3661e871b10dc1f8f1896a3b05f18b" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f833670942247a14eafbb675458b4e61c82e002a148f49e68257b79296e865c4" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:494a5952b1c597ba44e0e78113a7266e656b9794eec897b19ead706bd7074383" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96f423a119f4777a4a056b66ce11527366a8bb92f54e541ade21f2374433f6d4" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3462dd9475af2025c31cc61be6652dfa25cbfb56cbbf52f4ccfe029f38decaf8" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4c800524c9cd9bac5166cd6f55285957fcfc907db323e193f2afcd4d9abd69b" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d6a5df73acd3399d893dafc71663ad22534b5aa4f94e8a2fabfe856c3c1b6a52" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:405e8fe955c2280ce66428b3ca55e12b3c4e9c336fb2103a4937e891c69a4a29" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:908bd3f6439f2fef9e85031b59fd4f1297af54415fb60e4254a95f75b3cab3f3" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:294e487f9ec720bd8ffcebc99d575f7eff3568a08a253d1ee1a0378754b74143" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:74c51543498289c0c43656701be6b077f4b265868fa7f8a8859c197006efb608" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:776f352e8329135506a1d6bf16ac3f87bc25b28e765949282dcc627af36123aa" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp312-cp312-win32.whl", hash = "sha256:433403ae80709741ce34038da08511d4a77062aa924baf411ef73d1146e74faf" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:34187385b08f866104f0c0617404c8eb08165ab1272e884abc89c112e9c00746" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp312-cp312-win_arm64.whl", hash = "sha256:fe3c58d2f5db5fbd18c2987cba06d51b0529f52bc3a6cdc33d3f4eab725104bd" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8d92f1a84bb12d9e56f818b3a746f3efba93c1b63c8387a73dde655e1e42282a" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:96153e77a591c8adc2ee805756c61f59fef4cf4073a9275ee86fe8cba41241f7" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f21f00a91358803399890ab167098c131ec2ddd5f8f5fd5fe9c9f2c6fcd91e40" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fb30f9626572a76dfe4293c7194a09fb1fe93ba94c7d4f720dfae3b646b45027" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eaa352d7047a31d87dafcacbabe89df0aa506abb5b1b85a2fb91bc3faa02d822" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:03ae967b4e297f58f8c774c7eabcce57fe3c2434817d4385c50661845a058121" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f6292f1de555ffcc675941d65fffffb0a5bcd992905015f85d0592201793e0e5" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29548f9b5b5e3460ce7378144c3010363d8035cea44bc0bf02d57f5a685e084e" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ec3cc8c5d4084591b4237c0a272cc4f50a5b03396a47d9caaf76f5d7b38a4f11" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:517279f58009d0b1f2e7c1b130b377a349405da3f7621ed6bfae50b10adf20c1" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:db1e72ede2d0d7ccb213f218df6a078a9c09a7de257c2fe8fcef16d5925230b1" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b4dec9482a65c54a5044486847b8a66bf10c9cb4926d42927ec4e8fd5db7fed8" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:21900c48ae04d13d416f0e1e0c4d81f7931f73a9dfa0b7a8746fb2fe7dd970ed" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313-win32.whl", hash = "sha256:8b7b94a067d1c504ee0b16def57ad5738701e4ba10cec90529f13fa03c833496" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:878be833caa6a3821caf85eb39c5ba92d28e85df26d57afb06b35b2efd937231" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313-win_arm64.whl", hash = "sha256:44389d135b3ff43ba8cc89ff7f51f5a0bb6b63d829c8300f79a2fe4fe61bcc62" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:e25ac20a2ef37e91c1b39938b591457666a0fa835c7783c3a8f33ea42870db94" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:07cdca25a91a4386d2e76ad992916a85038a9b97561bf7a3fd12d5d9ce31870c" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4e0c11f2cc6717e0a741f84a527c52616140741cd812a50422f83dc31749fb52" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b3210649ee28062ea6099cfda39e147fa1bc039583c8ee4481cb7811e2448c51" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:581ef5194c48035a7de2aefc72ac6539823bb71508189e5de01d60c9dcd5fa65" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3ef2d026f16a2b1866e1d86fc4e1291e1ed8a387b2c333809419a2f8b3a77b82" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5500ef82073f599ac84d888e3a8c1f77ac831183244bfd7f11eaa0289fb30714" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:50066c3997d0091c411a66e710f4e11752251e6d2d73d70d8d5d4c76442a199d" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:5c1c8e78426e59b3f8005e9b19f6ff46e5845895adbde20ece9218319eca6506" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:eefdba20de0d938cec6a89bd4d70f346a03108a19b9df4248d3cf0d88f1b0f51" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:cf253e0e1c3ceb4aaff6df637ce033ff6535fb8c70a764a8f46aafd3d6ab798e" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:032efa2674356903cd0261c4317a561a6850f3ac864a63fc1583147fb05a79b0" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6da155091429aeba16851ecb10a9104a108bcd32f6c1642867eadaee401c1c41" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313t-win32.whl", hash = "sha256:0f96534f8bfebc1a394209427d0f8a63d343c9779cda6fc25e8e121b5fd8555b" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5d63a068f978fc69421fb0e6eb91a9603187527c86b7cd3f534a5b77a592b888" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp313-cp313t-win_arm64.whl", hash = "sha256:bf0a7e10b077bf5fb9380ad3ae8ce20ef919a6ad93b4552896419ac7e1d8e042" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:cee686f1f4cadeb2136007ddedd0aaf928ab95216e7691c63e50a8ec066336d0" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:119fb2a1bd47307e899c2fac7f28e85b9a543864df47aa7ec9d3c1b4545f096f" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4970ece02dbc8c3a92fcc5228e36a3e933a01a999f7094ff7c23fbd2beeaa67c" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:cba69cb73723c3f329622e34bdbf5ce1f80c21c290ff04256cff1cd3c2036ed2" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:778a11b15673f6f1df23d9586f83c4846c471a8af693a22e066508b77d201ec8" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0325024fe97f94c41c08872db482cf8ac4800d80e79222c6b0b7b162d5b13686" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:97260ff46b207a82a7567b581ab4190bd4dfa09f4db8a8b49d1a958f6aa4940e" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:54b2077180eb7f83dd52c40b2750d0a9f175e06a42e3213ce047219de902717a" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2f05983daecab868a31e1da44462873306d3cbfd76d1f0b5b69c473d21dbb128" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:33f48f51a446114bc5d251fb2954ab0164d5be02ad3382abcbfe07e2531d650f" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:154e55ec0655291b5dd1b8731c637ecdb50975a2ae70c606d100750a540082f7" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:4314debad13beb564b708b4a496020e5306c7333fa9a3ab90374169a20ffab30" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:073f8bf8becba60aa931eb3bc420b217bb7d5b8f4750e6f8b3be7f3da85d38b7" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314-win32.whl", hash = "sha256:bac9c42ba2ac65ddc115d930c78d24ab8d4f465fd3fc473cdedfccadb9429806" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:3e0761f4d1a44f1d1a47996511752cf3dcec5bbdd9cc2b4fe595caf97754b7a0" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314-win_arm64.whl", hash = "sha256:d1eaff1d00c7751b7c6662e9c5ba6eb2c17a2306ba5e2a37f24ddf3cc953402b" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:d3bb933317c52d7ea5004a1c442eef86f426886fba134ef8cf4226ea6ee1821d" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:8009897cdef112072f93a0efdce29cd819e717fd2f649ee3016efd3cd885a7ed" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2c5dcbbc55383e5883246d11fd179782a9d07a986c40f49abe89ddf865913930" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:39ecbc32f1390387d2aa4f5a995e465e9e2f79ba3adcac92d68e3e0afae6657c" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92db2bf818d5cc8d9c1f1fc56b897662e24ea5adb36ad1f1d82875bd64e03c24" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2dc43a022e555de94c3b68a4ef0b11c4f747d12c024a520c7101709a2144fb37" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cb89a7f2de3602cfed448095bab3f178399646ab7c61454315089787df07733a" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:33139dc858c580ea50e7e60a1b0ea003efa1fd42e6ec7fdbad78fff65fad2fd2" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:168c0969a329b416119507ba30b9ea13688fafffac1b7822802537569a1cb0ef" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:28bd570e8e189d7f7b001966435f9dac6718324b5be2990ac496cf1ea9ddb7fe" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b2a095d45c5d46e5e79ba1e5b9cb787f541a8dee0433836cea4b96a2c439dcd8" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:eab8145831a0d56ec9c4139b6c3e594c7a83c2c8be25d5bcf2d86136a532287a" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:974b28cf63cc99dfb2188d8d222bc6843656188164848c4f679e63dae4b0708e" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314t-win32.whl", hash = "sha256:342c97bf697ac5480c0a7ec73cd700ecfa5a8a40ac923bd035484616efecc2df" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:06be8f67f39c8b1dc671f5d83aaefd3358ae5cdcf8314552c57e7ed3e6475bdd" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-cp314-cp314t-win_arm64.whl", hash = "sha256:102e6314ca4da683dca92e3b1355490fed5f313b768500084fbe6371fddfdb79" }, - { url = "https://bytedpypi.byted.org/packages/frozenlist/frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d" }, -] - -[[package]] -name = "fsspec" -version = "2026.2.0" -source = { registry = "https://bytedpypi.byted.org/simple/" } -sdist = { url = "https://bytedpypi.byted.org/packages/fsspec/fsspec-2026.2.0.tar.gz", hash = "sha256:6544e34b16869f5aacd5b90bdf1a71acb37792ea3ddf6125ee69a22a53fb8bff" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/fsspec/fsspec-2026.2.0-py3-none-any.whl", hash = "sha256:98de475b5cb3bd66bedd5c4679e87b4fdfe1a3bf4d707b151b3c07e58c9a2437" }, -] - -[[package]] -name = "h11" -version = "0.16.0" -source = { registry = "https://bytedpypi.byted.org/simple/" } -sdist = { url = "https://bytedpypi.byted.org/packages/h11/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/h11/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86" }, -] - -[[package]] -name = "hf-xet" -version = "1.2.0" -source = { registry = "https://bytedpypi.byted.org/simple/" } -sdist = { url = "https://bytedpypi.byted.org/packages/hf-xet/hf_xet-1.2.0.tar.gz", hash = "sha256:a8c27070ca547293b6890c4bf389f713f80e8c478631432962bb7f4bc0bd7d7f" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/hf-xet/hf_xet-1.2.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:ceeefcd1b7aed4956ae8499e2199607765fbd1c60510752003b6cc0b8413b649" }, - { url = "https://bytedpypi.byted.org/packages/hf-xet/hf_xet-1.2.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b70218dd548e9840224df5638fdc94bd033552963cfa97f9170829381179c813" }, - { url = "https://bytedpypi.byted.org/packages/hf-xet/hf_xet-1.2.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d40b18769bb9a8bc82a9ede575ce1a44c75eb80e7375a01d76259089529b5dc" }, - { url = "https://bytedpypi.byted.org/packages/hf-xet/hf_xet-1.2.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:cd3a6027d59cfb60177c12d6424e31f4b5ff13d8e3a1247b3a584bf8977e6df5" }, - { url = "https://bytedpypi.byted.org/packages/hf-xet/hf_xet-1.2.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6de1fc44f58f6dd937956c8d304d8c2dea264c80680bcfa61ca4a15e7b76780f" }, - { url = "https://bytedpypi.byted.org/packages/hf-xet/hf_xet-1.2.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f182f264ed2acd566c514e45da9f2119110e48a87a327ca271027904c70c5832" }, - { url = "https://bytedpypi.byted.org/packages/hf-xet/hf_xet-1.2.0-cp313-cp313t-win_amd64.whl", hash = "sha256:293a7a3787e5c95d7be1857358a9130694a9c6021de3f27fa233f37267174382" }, - { url = "https://bytedpypi.byted.org/packages/hf-xet/hf_xet-1.2.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:10bfab528b968c70e062607f663e21e34e2bba349e8038db546646875495179e" }, - { url = "https://bytedpypi.byted.org/packages/hf-xet/hf_xet-1.2.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2a212e842647b02eb6a911187dc878e79c4aa0aa397e88dd3b26761676e8c1f8" }, - { url = "https://bytedpypi.byted.org/packages/hf-xet/hf_xet-1.2.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:30e06daccb3a7d4c065f34fc26c14c74f4653069bb2b194e7f18f17cbe9939c0" }, - { url = "https://bytedpypi.byted.org/packages/hf-xet/hf_xet-1.2.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:29c8fc913a529ec0a91867ce3d119ac1aac966e098cf49501800c870328cc090" }, - { url = "https://bytedpypi.byted.org/packages/hf-xet/hf_xet-1.2.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e159cbfcfbb29f920db2c09ed8b660eb894640d284f102ada929b6e3dc410a" }, - { url = "https://bytedpypi.byted.org/packages/hf-xet/hf_xet-1.2.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9c91d5ae931510107f148874e9e2de8a16052b6f1b3ca3c1b12f15ccb491390f" }, - { url = "https://bytedpypi.byted.org/packages/hf-xet/hf_xet-1.2.0-cp314-cp314t-win_amd64.whl", hash = "sha256:210d577732b519ac6ede149d2f2f34049d44e8622bf14eb3d63bbcd2d4b332dc" }, - { url = "https://bytedpypi.byted.org/packages/hf-xet/hf_xet-1.2.0-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:46740d4ac024a7ca9b22bebf77460ff43332868b661186a8e46c227fdae01848" }, - { url = "https://bytedpypi.byted.org/packages/hf-xet/hf_xet-1.2.0-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:27df617a076420d8845bea087f59303da8be17ed7ec0cd7ee3b9b9f579dff0e4" }, - { url = "https://bytedpypi.byted.org/packages/hf-xet/hf_xet-1.2.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3651fd5bfe0281951b988c0facbe726aa5e347b103a675f49a3fa8144c7968fd" }, - { url = "https://bytedpypi.byted.org/packages/hf-xet/hf_xet-1.2.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d06fa97c8562fb3ee7a378dd9b51e343bc5bc8190254202c9771029152f5e08c" }, - { url = "https://bytedpypi.byted.org/packages/hf-xet/hf_xet-1.2.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:4c1428c9ae73ec0939410ec73023c4f842927f39db09b063b9482dac5a3bb737" }, - { url = "https://bytedpypi.byted.org/packages/hf-xet/hf_xet-1.2.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a55558084c16b09b5ed32ab9ed38421e2d87cf3f1f89815764d1177081b99865" }, - { url = "https://bytedpypi.byted.org/packages/hf-xet/hf_xet-1.2.0-cp37-abi3-win_amd64.whl", hash = "sha256:e6584a52253f72c9f52f9e549d5895ca7a471608495c4ecaa6cc73dba2b24d69" }, -] - -[[package]] -name = "httpcore" -version = "1.0.9" -source = { registry = "https://bytedpypi.byted.org/simple/" } -dependencies = [ - { name = "certifi" }, - { name = "h11" }, -] -sdist = { url = "https://bytedpypi.byted.org/packages/httpcore/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/httpcore/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55" }, -] - -[[package]] -name = "httpx" -version = "0.28.1" -source = { registry = "https://bytedpypi.byted.org/simple/" } -dependencies = [ - { name = "anyio" }, - { name = "certifi" }, - { name = "httpcore" }, - { name = "idna" }, -] -sdist = { url = "https://bytedpypi.byted.org/packages/httpx/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/httpx/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad" }, -] - -[package.optional-dependencies] -socks = [ - { name = "socksio" }, -] - -[[package]] -name = "huggingface-hub" -version = "1.4.1" -source = { registry = "https://bytedpypi.byted.org/simple/" } -dependencies = [ - { name = "filelock" }, - { name = "fsspec" }, - { name = "hf-xet", marker = "platform_machine == 'AMD64' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64'" }, - { name = "httpx" }, - { name = "packaging" }, - { name = "pyyaml" }, - { name = "shellingham" }, - { name = "tqdm" }, - { name = "typer-slim" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://bytedpypi.byted.org/packages/huggingface-hub/huggingface_hub-1.4.1.tar.gz", hash = "sha256:b41131ec35e631e7383ab26d6146b8d8972abc8b6309b963b306fbcca87f5ed5" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/huggingface-hub/huggingface_hub-1.4.1-py3-none-any.whl", hash = "sha256:9931d075fb7a79af5abc487106414ec5fba2c0ae86104c0c62fd6cae38873d18" }, -] - -[[package]] -name = "idna" -version = "3.11" -source = { registry = "https://bytedpypi.byted.org/simple/" } -sdist = { url = "https://bytedpypi.byted.org/packages/idna/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/idna/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea" }, -] - -[[package]] -name = "importlib-metadata" -version = "8.7.1" -source = { registry = "https://bytedpypi.byted.org/simple/" } -dependencies = [ - { name = "zipp" }, -] -sdist = { url = "https://bytedpypi.byted.org/packages/importlib-metadata/importlib_metadata-8.7.1.tar.gz", hash = "sha256:49fef1ae6440c182052f407c8d34a68f72efc36db9ca90dc0113398f2fdde8bb" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/importlib-metadata/importlib_metadata-8.7.1-py3-none-any.whl", hash = "sha256:5a1f80bf1daa489495071efbb095d75a634cf28a8bc299581244063b53176151" }, -] - -[[package]] -name = "iniconfig" -version = "2.3.0" -source = { registry = "https://bytedpypi.byted.org/simple/" } -sdist = { url = "https://bytedpypi.byted.org/packages/iniconfig/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/iniconfig/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12" }, -] - -[[package]] -name = "jinja2" -version = "3.1.6" -source = { registry = "https://bytedpypi.byted.org/simple/" } -dependencies = [ - { name = "markupsafe" }, -] -sdist = { url = "https://bytedpypi.byted.org/packages/jinja2/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/jinja2/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67" }, -] - -[[package]] -name = "jiter" -version = "0.13.0" -source = { registry = "https://bytedpypi.byted.org/simple/" } -sdist = { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0.tar.gz", hash = "sha256:f2839f9c2c7e2dffc1bc5929a510e14ce0a946be9365fd1219e7ef342dae14f4" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:ea026e70a9a28ebbdddcbcf0f1323128a8db66898a06eaad3a4e62d2f554d096" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:66aa3e663840152d18cc8ff1e4faad3dd181373491b9cfdc6004b92198d67911" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3524798e70655ff19aec58c7d05adb1f074fecff62da857ea9be2b908b6d701" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ec7e287d7fbd02cb6e22f9a00dd9c9cd504c40a61f2c61e7e1f9690a82726b4c" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:47455245307e4debf2ce6c6e65a717550a0244231240dcf3b8f7d64e4c2f22f4" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ee9da221dca6e0429c2704c1b3655fe7b025204a71d4d9b73390c759d776d165" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24ab43126d5e05f3d53a36a8e11eb2f23304c6c1117844aaaf9a0aa5e40b5018" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9da38b4fedde4fb528c740c2564628fbab737166a0e73d6d46cb4bb5463ff411" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0b34c519e17658ed88d5047999a93547f8889f3c1824120c26ad6be5f27b6cf5" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d2a6394e6af690d462310a86b53c47ad75ac8c21dc79f120714ea449979cb1d3" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp311-cp311-win32.whl", hash = "sha256:0f0c065695f616a27c920a56ad0d4fc46415ef8b806bf8fc1cacf25002bd24e1" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:0733312953b909688ae3c2d58d043aa040f9f1a6a75693defed7bc2cc4bf2654" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp311-cp311-win_arm64.whl", hash = "sha256:5d9b34ad56761b3bf0fbe8f7e55468704107608512350962d3317ffd7a4382d5" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:0a2bd69fc1d902e89925fc34d1da51b2128019423d7b339a45d9e99c894e0663" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f917a04240ef31898182f76a332f508f2cc4b57d2b4d7ad2dbfebbfe167eb505" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1e2b199f446d3e82246b4fd9236d7cb502dc2222b18698ba0d986d2fecc6152" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:04670992b576fa65bd056dbac0c39fe8bd67681c380cb2b48efa885711d9d726" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5a1aff1fbdb803a376d4d22a8f63f8e7ccbce0b4890c26cc7af9e501ab339ef0" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b3fb8c2053acaef8580809ac1d1f7481a0a0bdc012fd7f5d8b18fb696a5a089" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bdaba7d87e66f26a2c45d8cbadcbfc4bf7884182317907baf39cfe9775bb4d93" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7b88d649135aca526da172e48083da915ec086b54e8e73a425ba50999468cc08" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:e404ea551d35438013c64b4f357b0474c7abf9f781c06d44fcaf7a14c69ff9e2" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1f4748aad1b4a93c8bdd70f604d0f748cdc0e8744c5547798acfa52f10e79228" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp312-cp312-win32.whl", hash = "sha256:0bf670e3b1445fc4d31612199f1744f67f889ee1bbae703c4b54dc097e5dd394" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:15db60e121e11fe186c0b15236bd5d18381b9ddacdcf4e659feb96fc6c969c92" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp312-cp312-win_arm64.whl", hash = "sha256:41f92313d17989102f3cb5dd533a02787cdb99454d494344b0361355da52fcb9" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1f8a55b848cbabf97d861495cd65f1e5c590246fabca8b48e1747c4dfc8f85bf" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f556aa591c00f2c45eb1b89f68f52441a016034d18b65da60e2d2875bbbf344a" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7e1d61da332ec412350463891923f960c3073cf1aae93b538f0bb4c8cd46efb" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3097d665a27bc96fd9bbf7f86178037db139f319f785e4757ce7ccbf390db6c2" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d01ecc3a8cbdb6f25a37bd500510550b64ddf9f7d64a107d92f3ccb25035d0f" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ed9bbc30f5d60a3bdf63ae76beb3f9db280d7f195dfcfa61af792d6ce912d159" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98fbafb6e88256f4454de33c1f40203d09fc33ed19162a68b3b257b29ca7f663" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5467696f6b827f1116556cb0db620440380434591e93ecee7fd14d1a491b6daa" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:2d08c9475d48b92892583df9da592a0e2ac49bcd41fae1fec4f39ba6cf107820" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:aed40e099404721d7fcaf5b89bd3b4568a4666358bcac7b6b15c09fb6252ab68" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp313-cp313-win32.whl", hash = "sha256:36ebfbcffafb146d0e6ffb3e74d51e03d9c35ce7c625c8066cdbfc7b953bdc72" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:8d76029f077379374cf0dbc78dbe45b38dec4a2eb78b08b5194ce836b2517afc" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp313-cp313-win_arm64.whl", hash = "sha256:bb7613e1a427cfcb6ea4544f9ac566b93d5bf67e0d48c787eca673ff9c9dff2b" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:fa476ab5dd49f3bf3a168e05f89358c75a17608dbabb080ef65f96b27c19ab10" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ade8cb6ff5632a62b7dbd4757d8c5573f7a2e9ae285d6b5b841707d8363205ef" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9950290340acc1adaded363edd94baebcee7dabdfa8bee4790794cd5cfad2af6" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp313-cp313t-win_amd64.whl", hash = "sha256:2b4972c6df33731aac0742b64fd0d18e0a69bc7d6e03108ce7d40c85fd9e3e6d" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp313-cp313t-win_arm64.whl", hash = "sha256:701a1e77d1e593c1b435315ff625fd071f0998c5f02792038a5ca98899261b7d" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:cc5223ab19fe25e2f0bf2643204ad7318896fe3729bf12fde41b77bfc4fafff0" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9776ebe51713acf438fd9b4405fcd86893ae5d03487546dae7f34993217f8a91" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:879e768938e7b49b5e90b7e3fecc0dbec01b8cb89595861fb39a8967c5220d09" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:682161a67adea11e3aae9038c06c8b4a9a71023228767477d683f69903ebc607" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a13b68cd1cd8cc9de8f244ebae18ccb3e4067ad205220ef324c39181e23bbf66" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87ce0f14c6c08892b610686ae8be350bf368467b6acd5085a5b65441e2bf36d2" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c365005b05505a90d1c47856420980d0237adf82f70c4aff7aebd3c1cc143ad" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1317fdffd16f5873e46ce27d0e0f7f4f90f0cdf1d86bf6abeaea9f63ca2c401d" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:c05b450d37ba0c9e21c77fef1f205f56bcee2330bddca68d344baebfc55ae0df" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:775e10de3849d0631a97c603f996f518159272db00fdda0a780f81752255ee9d" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314-win32.whl", hash = "sha256:632bf7c1d28421c00dd8bbb8a3bac5663e1f57d5cd5ed962bce3c73bf62608e6" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314-win_amd64.whl", hash = "sha256:f22ef501c3f87ede88f23f9b11e608581c14f04db59b6a801f354397ae13739f" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314-win_arm64.whl", hash = "sha256:07b75fe09a4ee8e0c606200622e571e44943f47254f95e2436c8bdcaceb36d7d" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:964538479359059a35fb400e769295d4b315ae61e4105396d355a12f7fef09f0" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e104da1db1c0991b3eaed391ccd650ae8d947eab1480c733e5a3fb28d4313e40" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0e3a5f0cde8ff433b8e88e41aa40131455420fb3649a3c7abdda6145f8cb7202" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:57aab48f40be1db920a582b30b116fe2435d184f77f0e4226f546794cedd9cf0" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7772115877c53f62beeb8fd853cab692dbc04374ef623b30f997959a4c0e7e95" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1211427574b17b633cfceba5040de8081e5abf114f7a7602f73d2e16f9fdaa59" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7beae3a3d3b5212d3a55d2961db3c292e02e302feb43fce6a3f7a31b90ea6dfe" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:e5562a0f0e90a6223b704163ea28e831bd3a9faa3512a711f031611e6b06c939" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:6c26a424569a59140fb51160a56df13f438a2b0967365e987889186d5fc2f6f9" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314t-win32.whl", hash = "sha256:24dc96eca9f84da4131cdf87a95e6ce36765c3b156fc9ae33280873b1c32d5f6" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314t-win_amd64.whl", hash = "sha256:0a8d76c7524087272c8ae913f5d9d608bd839154b62c4322ef65723d2e5bb0b8" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-cp314-cp314t-win_arm64.whl", hash = "sha256:2c26cf47e2cad140fa23b6d58d435a7c0161f5c514284802f25e87fddfe11024" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:b1cbfa133241d0e6bdab48dcdc2604e8ba81512f6bbd68ec3e8e1357dd3c316c" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:db367d8be9fad6e8ebbac4a7578b7af562e506211036cba2c06c3b998603c3d2" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45f6f8efb2f3b0603092401dc2df79fa89ccbc027aaba4174d2d4133ed661434" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:597245258e6ad085d064780abfb23a284d418d3e61c57362d9449c6c7317ee2d" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:3d744a6061afba08dd7ae375dcde870cffb14429b7477e10f67e9e6d68772a0a" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:ff732bd0a0e778f43d5009840f20b935e79087b4dc65bd36f1cd0f9b04b8ff7f" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ab44b178f7981fcaea7e0a5df20e773c663d06ffda0198f1a524e91b2fde7e59" }, - { url = "https://bytedpypi.byted.org/packages/jiter/jiter-0.13.0-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7bb00b6d26db67a05fe3e12c76edc75f32077fb51deed13822dc648fa373bc19" }, -] - -[[package]] -name = "jsonschema" -version = "4.26.0" -source = { registry = "https://bytedpypi.byted.org/simple/" } -dependencies = [ - { name = "attrs" }, - { name = "jsonschema-specifications" }, - { name = "referencing" }, - { name = "rpds-py" }, -] -sdist = { url = "https://bytedpypi.byted.org/packages/jsonschema/jsonschema-4.26.0.tar.gz", hash = "sha256:0c26707e2efad8aa1bfc5b7ce170f3fccc2e4918ff85989ba9ffa9facb2be326" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/jsonschema/jsonschema-4.26.0-py3-none-any.whl", hash = "sha256:d489f15263b8d200f8387e64b4c3a75f06629559fb73deb8fdfb525f2dab50ce" }, -] - -[[package]] -name = "jsonschema-specifications" -version = "2025.9.1" -source = { registry = "https://bytedpypi.byted.org/simple/" } -dependencies = [ - { name = "referencing" }, -] -sdist = { url = "https://bytedpypi.byted.org/packages/jsonschema-specifications/jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/jsonschema-specifications/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe" }, -] - -[[package]] -name = "lark-oapi" -version = "1.5.3" -source = { registry = "https://bytedpypi.byted.org/simple/" } -dependencies = [ - { name = "httpx" }, - { name = "pycryptodome" }, - { name = "requests" }, - { name = "requests-toolbelt" }, - { name = "websockets" }, -] -wheels = [ - { url = "https://bytedpypi.byted.org/packages/lark-oapi/lark_oapi-1.5.3-py3-none-any.whl", hash = "sha256:fda6b32bb38d21b6bdaae94979c600b94c7c521e985adade63a54e4b3e20cc36" }, -] - -[[package]] -name = "litellm" -version = "1.81.11" -source = { registry = "https://bytedpypi.byted.org/simple/" } -dependencies = [ - { name = "aiohttp" }, - { name = "click" }, - { name = "fastuuid" }, - { name = "httpx" }, - { name = "importlib-metadata" }, - { name = "jinja2" }, - { name = "jsonschema" }, - { name = "openai" }, - { name = "pydantic" }, - { name = "python-dotenv" }, - { name = "tiktoken" }, - { name = "tokenizers" }, -] -sdist = { url = "https://bytedpypi.byted.org/packages/litellm/litellm-1.81.11.tar.gz", hash = "sha256:fc55aceafda325bd5f704ada61c8be5bd322e6dfa5f8bdcab3290b8732c5857e" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/litellm/litellm-1.81.11-py3-none-any.whl", hash = "sha256:06a66c24742e082ddd2813c87f40f5c12fe7baa73ce1f9457eaf453dc44a0f65" }, -] - -[[package]] -name = "loguru" -version = "0.7.3" -source = { registry = "https://bytedpypi.byted.org/simple/" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "win32-setctime", marker = "sys_platform == 'win32'" }, -] -sdist = { url = "https://bytedpypi.byted.org/packages/loguru/loguru-0.7.3.tar.gz", hash = "sha256:19480589e77d47b8d85b2c827ad95d49bf31b0dcde16593892eb51dd18706eb6" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/loguru/loguru-0.7.3-py3-none-any.whl", hash = "sha256:31a33c10c8e1e10422bfd431aeb5d351c7cf7fa671e3c4df004162264b28220c" }, -] - -[[package]] -name = "lxml" -version = "6.0.2" -source = { registry = "https://bytedpypi.byted.org/simple/" } -sdist = { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2.tar.gz", hash = "sha256:cd79f3367bd74b317dda655dc8fcfa304d9eb6e4fb06b7168c5cf27f96e0cd62" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:13e35cbc684aadf05d8711a5d1b5857c92e5e580efa9a0d2be197199c8def607" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3b1675e096e17c6fe9c0e8c81434f5736c0739ff9ac6123c87c2d452f48fc938" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8ac6e5811ae2870953390452e3476694196f98d447573234592d30488147404d" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5aa0fc67ae19d7a64c3fe725dc9a1bb11f80e01f78289d05c6f62545affec438" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:de496365750cc472b4e7902a485d3f152ecf57bd3ba03ddd5578ed8ceb4c5964" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp311-cp311-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:200069a593c5e40b8f6fc0d84d86d970ba43138c3e68619ffa234bc9bb806a4d" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp311-cp311-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7d2de809c2ee3b888b59f995625385f74629707c9355e0ff856445cdcae682b7" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:b2c3da8d93cf5db60e8858c17684c47d01fee6405e554fb55018dd85fc23b178" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp311-cp311-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:442de7530296ef5e188373a1ea5789a46ce90c4847e597856570439621d9c553" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2593c77efde7bfea7f6389f1ab249b15ed4aa5bc5cb5131faa3b843c429fbedb" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:3e3cb08855967a20f553ff32d147e14329b3ae70ced6edc2f282b94afbc74b2a" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:2ed6c667fcbb8c19c6791bbf40b7268ef8ddf5a96940ba9404b9f9a304832f6c" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b8f18914faec94132e5b91e69d76a5c1d7b0c73e2489ea8929c4aaa10b76bbf7" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp311-cp311-win32.whl", hash = "sha256:6605c604e6daa9e0d7f0a2137bdc47a2e93b59c60a65466353e37f8272f47c46" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e5867f2651016a3afd8dd2c8238baa66f1e2802f44bc17e236f547ace6647078" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp311-cp311-win_arm64.whl", hash = "sha256:4197fb2534ee05fd3e7afaab5d8bfd6c2e186f65ea7f9cd6a82809c887bd1285" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a59f5448ba2ceccd06995c95ea59a7674a10de0810f2ce90c9006f3cbc044456" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e8113639f3296706fbac34a30813929e29247718e88173ad849f57ca59754924" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:a8bef9b9825fa8bc816a6e641bb67219489229ebc648be422af695f6e7a4fa7f" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:65ea18d710fd14e0186c2f973dc60bb52039a275f82d3c44a0e42b43440ea534" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c371aa98126a0d4c739ca93ceffa0fd7a5d732e3ac66a46e74339acd4d334564" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp312-cp312-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:700efd30c0fa1a3581d80a748157397559396090a51d306ea59a70020223d16f" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c33e66d44fe60e72397b487ee92e01da0d09ba2d66df8eae42d77b6d06e5eba0" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp312-cp312-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:90a345bbeaf9d0587a3aaffb7006aa39ccb6ff0e96a57286c0cb2fd1520ea192" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:064fdadaf7a21af3ed1dcaa106b854077fbeada827c18f72aec9346847cd65d0" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp312-cp312-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fbc74f42c3525ac4ffa4b89cbdd00057b6196bcefe8bce794abd42d33a018092" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6ddff43f702905a4e32bc24f3f2e2edfe0f8fde3277d481bffb709a4cced7a1f" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:6da5185951d72e6f5352166e3da7b0dc27aa70bd1090b0eb3f7f7212b53f1bb8" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:57a86e1ebb4020a38d295c04fc79603c7899e0df71588043eb218722dabc087f" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:2047d8234fe735ab77802ce5f2297e410ff40f5238aec569ad7c8e163d7b19a6" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6f91fd2b2ea15a6800c8e24418c0775a1694eefc011392da73bc6cef2623b322" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp312-cp312-win32.whl", hash = "sha256:3ae2ce7d6fedfb3414a2b6c5e20b249c4c607f72cb8d2bb7cc9c6ec7c6f4e849" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:72c87e5ee4e58a8354fb9c7c84cbf95a1c8236c127a5d1b7683f04bed8361e1f" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp312-cp312-win_arm64.whl", hash = "sha256:61cb10eeb95570153e0c0e554f58df92ecf5109f75eacad4a95baa709e26c3d6" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9b33d21594afab46f37ae58dfadd06636f154923c4e8a4d754b0127554eb2e77" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6c8963287d7a4c5c9a432ff487c52e9c5618667179c18a204bdedb27310f022f" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1941354d92699fb5ffe6ed7b32f9649e43c2feb4b97205f75866f7d21aa91452" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bb2f6ca0ae2d983ded09357b84af659c954722bbf04dea98030064996d156048" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eb2a12d704f180a902d7fa778c6d71f36ceb7b0d317f34cdc76a5d05aa1dd1df" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp313-cp313-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:6ec0e3f745021bfed19c456647f0298d60a24c9ff86d9d051f52b509663feeb1" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:846ae9a12d54e368933b9759052d6206a9e8b250291109c48e350c1f1f49d916" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp313-cp313-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ef9266d2aa545d7374938fb5c484531ef5a2ec7f2d573e62f8ce722c735685fd" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:4077b7c79f31755df33b795dc12119cb557a0106bfdab0d2c2d97bd3cf3dffa6" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a7c5d5e5f1081955358533be077166ee97ed2571d6a66bdba6ec2f609a715d1a" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:8f8d0cbd0674ee89863a523e6994ac25fd5be9c8486acfc3e5ccea679bad2679" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:2cbcbf6d6e924c28f04a43f3b6f6e272312a090f269eff68a2982e13e5d57659" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:dfb874cfa53340009af6bdd7e54ebc0d21012a60a4e65d927c2e477112e63484" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:fb8dae0b6b8b7f9e96c26fdd8121522ce5de9bb5538010870bd538683d30e9a2" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:358d9adae670b63e95bc59747c72f4dc97c9ec58881d4627fe0120da0f90d314" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp313-cp313-win32.whl", hash = "sha256:e8cd2415f372e7e5a789d743d133ae474290a90b9023197fd78f32e2dc6873e2" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:b30d46379644fbfc3ab81f8f82ae4de55179414651f110a1514f0b1f8f6cb2d7" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp313-cp313-win_arm64.whl", hash = "sha256:13dcecc9946dca97b11b7c40d29fba63b55ab4170d3c0cf8c0c164343b9bfdcf" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:b0c732aa23de8f8aec23f4b580d1e52905ef468afb4abeafd3fec77042abb6fe" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:4468e3b83e10e0317a89a33d28f7aeba1caa4d1a6fd457d115dd4ffe90c5931d" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:abd44571493973bad4598a3be7e1d807ed45aa2adaf7ab92ab7c62609569b17d" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:370cd78d5855cfbffd57c422851f7d3864e6ae72d0da615fca4dad8c45d375a5" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:901e3b4219fa04ef766885fb40fa516a71662a4c61b80c94d25336b4934b71c0" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:a4bf42d2e4cf52c28cc1812d62426b9503cdb0c87a6de81442626aa7d69707ba" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b2c7fdaa4d7c3d886a42534adec7cfac73860b89b4e5298752f60aa5984641a0" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:98a5e1660dc7de2200b00d53fa00bcd3c35a3608c305d45a7bbcaf29fa16e83d" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:dc051506c30b609238d79eda75ee9cab3e520570ec8219844a72a46020901e37" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8799481bbdd212470d17513a54d568f44416db01250f49449647b5ab5b5dccb9" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9261bb77c2dab42f3ecd9103951aeca2c40277701eb7e912c545c1b16e0e4917" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:65ac4a01aba353cfa6d5725b95d7aed6356ddc0a3cd734de00124d285b04b64f" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:b22a07cbb82fea98f8a2fd814f3d1811ff9ed76d0fc6abc84eb21527596e7cc8" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:d759cdd7f3e055d6bc8d9bec3ad905227b2e4c785dc16c372eb5b5e83123f48a" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:945da35a48d193d27c188037a05fec5492937f66fb1958c24fc761fb9d40d43c" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314-win32.whl", hash = "sha256:be3aaa60da67e6153eb15715cc2e19091af5dc75faef8b8a585aea372507384b" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314-win_amd64.whl", hash = "sha256:fa25afbadead523f7001caf0c2382afd272c315a033a7b06336da2637d92d6ed" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314-win_arm64.whl", hash = "sha256:063eccf89df5b24e361b123e257e437f9e9878f425ee9aae3144c77faf6da6d8" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:6162a86d86893d63084faaf4ff937b3daea233e3682fb4474db07395794fa80d" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:414aaa94e974e23a3e92e7ca5b97d10c0cf37b6481f50911032c69eeb3991bba" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:48461bd21625458dd01e14e2c38dd0aea69addc3c4f960c30d9f59d7f93be601" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:25fcc59afc57d527cfc78a58f40ab4c9b8fd096a9a3f964d2781ffb6eb33f4ed" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5179c60288204e6ddde3f774a93350177e08876eaf3ab78aa3a3649d43eb7d37" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314t-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:967aab75434de148ec80597b75062d8123cadf2943fb4281f385141e18b21338" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d100fcc8930d697c6561156c6810ab4a508fb264c8b6779e6e61e2ed5e7558f9" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2ca59e7e13e5981175b8b3e4ab84d7da57993eeff53c07764dcebda0d0e64ecd" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:957448ac63a42e2e49531b9d6c0fa449a1970dbc32467aaad46f11545be9af1d" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314t-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b7fc49c37f1786284b12af63152fe1d0990722497e2d5817acfe7a877522f9a9" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e19e0643cc936a22e837f79d01a550678da8377d7d801a14487c10c34ee49c7e" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:1db01e5cf14345628e0cbe71067204db658e2fb8e51e7f33631f5f4735fefd8d" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:875c6b5ab39ad5291588aed6925fac99d0097af0dd62f33c7b43736043d4a2ec" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:cdcbed9ad19da81c480dfd6dd161886db6096083c9938ead313d94b30aadf272" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:80dadc234ebc532e09be1975ff538d154a7fa61ea5031c03d25178855544728f" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314t-win32.whl", hash = "sha256:da08e7bb297b04e893d91087df19638dc7a6bb858a954b0cc2b9f5053c922312" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314t-win_amd64.whl", hash = "sha256:252a22982dca42f6155125ac76d3432e548a7625d56f5a273ee78a5057216eca" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-cp314-cp314t-win_arm64.whl", hash = "sha256:bb4c1847b303835d89d785a18801a883436cdfd5dc3d62947f9c49e24f0f5a2c" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:1c06035eafa8404b5cf475bb37a9f6088b0aca288d4ccc9d69389750d5543700" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c7d13103045de1bdd6fe5d61802565f1a3537d70cd3abf596aa0af62761921ee" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0a3c150a95fbe5ac91de323aa756219ef9cf7fde5a3f00e2281e30f33fa5fa4f" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:60fa43be34f78bebb27812ed90f1925ec99560b0fa1decdb7d12b84d857d31e9" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-pp311-pypy311_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:21c73b476d3cfe836be731225ec3421fa2f048d84f6df6a8e70433dff1376d5a" }, - { url = "https://bytedpypi.byted.org/packages/lxml/lxml-6.0.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:27220da5be049e936c3aca06f174e8827ca6445a4353a1995584311487fc4e3e" }, -] - -[package.optional-dependencies] -html-clean = [ - { name = "lxml-html-clean" }, -] - -[[package]] -name = "lxml-html-clean" -version = "0.4.3" -source = { registry = "https://bytedpypi.byted.org/simple/" } -dependencies = [ - { name = "lxml" }, -] -sdist = { url = "https://bytedpypi.byted.org/packages/lxml-html-clean/lxml_html_clean-0.4.3.tar.gz", hash = "sha256:c9df91925b00f836c807beab127aac82575110eacff54d0a75187914f1bd9d8c" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/lxml-html-clean/lxml_html_clean-0.4.3-py3-none-any.whl", hash = "sha256:63fd7b0b9c3a2e4176611c2ca5d61c4c07ffca2de76c14059a81a2825833731e" }, -] - -[[package]] -name = "markdown-it-py" -version = "4.0.0" -source = { registry = "https://bytedpypi.byted.org/simple/" } -dependencies = [ - { name = "mdurl" }, -] -sdist = { url = "https://bytedpypi.byted.org/packages/markdown-it-py/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/markdown-it-py/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147" }, -] - -[[package]] -name = "markupsafe" -version = "3.0.3" -source = { registry = "https://bytedpypi.byted.org/simple/" } -sdist = { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp311-cp311-win32.whl", hash = "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9" }, - { url = "https://bytedpypi.byted.org/packages/markupsafe/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa" }, -] - -[[package]] -name = "mdurl" -version = "0.1.2" -source = { registry = "https://bytedpypi.byted.org/simple/" } -sdist = { url = "https://bytedpypi.byted.org/packages/mdurl/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/mdurl/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8" }, -] - -[[package]] -name = "multidict" -version = "6.7.1" -source = { registry = "https://bytedpypi.byted.org/simple/" } -sdist = { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1.tar.gz", hash = "sha256:ec6652a1bee61c53a3e5776b6049172c53b6aaba34f18c9ad04f82712bac623d" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7ff981b266af91d7b4b3793ca3382e53229088d193a85dfad6f5f4c27fc73e5d" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:844c5bca0b5444adb44a623fb0a1310c2f4cd41f402126bb269cd44c9b3f3e1e" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f2a0a924d4c2e9afcd7ec64f9de35fcd96915149b2216e1cb2c10a56df483855" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:8be1802715a8e892c784c0197c2ace276ea52702a0ede98b6310c8f255a5afb3" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2e2d2ed645ea29f31c4c7ea1552fcfd7cb7ba656e1eafd4134a6620c9f5fdd9e" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:95922cee9a778659e91db6497596435777bd25ed116701a4c034f8e46544955a" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6b83cabdc375ffaaa15edd97eb7c0c672ad788e2687004990074d7d6c9b140c8" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:38fb49540705369bab8484db0689d86c0a33a0a9f2c1b197f506b71b4b6c19b0" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:439cbebd499f92e9aa6793016a8acaa161dfa749ae86d20960189f5398a19144" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6d3bc717b6fe763b8be3f2bee2701d3c8eb1b2a8ae9f60910f1b2860c82b6c49" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:619e5a1ac57986dbfec9f0b301d865dddf763696435e2962f6d9cf2fdff2bb71" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0b38ebffd9be37c1170d33bc0f36f4f262e0a09bc1aac1c34c7aa51a7293f0b3" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:10ae39c9cfe6adedcdb764f5e8411d4a92b055e35573a2eaa88d3323289ef93c" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:25167cc263257660290fba06b9318d2026e3c910be240a146e1f66dd114af2b0" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:128441d052254f42989ef98b7b6a6ecb1e6f708aa962c7984235316db59f50fa" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp311-cp311-win32.whl", hash = "sha256:d62b7f64ffde3b99d06b707a280db04fb3855b55f5a06df387236051d0668f4a" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:bdbf9f3b332abd0cdb306e7c2113818ab1e922dc84b8f8fd06ec89ed2a19ab8b" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp311-cp311-win_arm64.whl", hash = "sha256:b8c990b037d2fff2f4e33d3f21b9b531c5745b33a49a7d6dbe7a177266af44f6" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a90f75c956e32891a4eda3639ce6dd86e87105271f43d43442a3aedf3cddf172" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3fccb473e87eaa1382689053e4a4618e7ba7b9b9b8d6adf2027ee474597128cd" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b0fa96985700739c4c7853a43c0b3e169360d6855780021bfc6d0f1ce7c123e7" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:cb2a55f408c3043e42b40cc8eecd575afa27b7e0b956dfb190de0f8499a57a53" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eb0ce7b2a32d09892b3dd6cc44877a0d02a33241fafca5f25c8b6b62374f8b75" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c3a32d23520ee37bf327d1e1a656fec76a2edd5c038bf43eddfa0572ec49c60b" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9c90fed18bffc0189ba814749fdcc102b536e83a9f738a9003e569acd540a733" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:da62917e6076f512daccfbbde27f46fed1c98fee202f0559adec8ee0de67f71a" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bfde23ef6ed9db7eaee6c37dcec08524cb43903c60b285b172b6c094711b3961" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3758692429e4e32f1ba0df23219cd0b4fc0a52f476726fff9337d1a57676a582" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:398c1478926eca669f2fd6a5856b6de9c0acf23a2cb59a14c0ba5844fa38077e" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c102791b1c4f3ab36ce4101154549105a53dc828f016356b3e3bcae2e3a039d3" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a088b62bd733e2ad12c50dad01b7d0166c30287c166e137433d3b410add807a6" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3d51ff4785d58d3f6c91bdbffcb5e1f7ddfda557727043aa20d20ec4f65e324a" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fc5907494fccf3e7d3f94f95c91d6336b092b5fc83811720fae5e2765890dfba" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp312-cp312-win32.whl", hash = "sha256:28ca5ce2fd9716631133d0e9a9b9a745ad7f60bac2bccafb56aa380fc0b6c511" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcee94dfbd638784645b066074b338bc9cc155d4b4bffa4adce1615c5a426c19" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp312-cp312-win_arm64.whl", hash = "sha256:ba0a9fb644d0c1a2194cf7ffb043bd852cea63a57f66fbd33959f7dae18517bf" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:2b41f5fed0ed563624f1c17630cb9941cf2309d4df00e494b551b5f3e3d67a23" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:84e61e3af5463c19b67ced91f6c634effb89ef8bfc5ca0267f954451ed4bb6a2" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:935434b9853c7c112eee7ac891bc4cb86455aa631269ae35442cb316790c1445" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:432feb25a1cb67fe82a9680b4d65fb542e4635cb3166cd9c01560651ad60f177" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e82d14e3c948952a1a85503817e038cba5905a3352de76b9a465075d072fba23" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4cfb48c6ea66c83bcaaf7e4dfa7ec1b6bbcf751b7db85a328902796dfde4c060" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1d540e51b7e8e170174555edecddbd5538105443754539193e3e1061864d444d" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:273d23f4b40f3dce4d6c8a821c741a86dec62cded82e1175ba3d99be128147ed" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d624335fd4fa1c08a53f8b4be7676ebde19cd092b3895c421045ca87895b429" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:12fad252f8b267cc75b66e8fc51b3079604e8d43a75428ffe193cd9e2195dfd6" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:03ede2a6ffbe8ef936b92cb4529f27f42be7f56afcdab5ab739cd5f27fb1cbf9" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:90efbcf47dbe33dcf643a1e400d67d59abeac5db07dc3f27d6bdeae497a2198c" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:5c4b9bfc148f5a91be9244d6264c53035c8a0dcd2f51f1c3c6e30e30ebaa1c84" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:401c5a650f3add2472d1d288c26deebc540f99e2fb83e9525007a74cd2116f1d" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:97891f3b1b3ffbded884e2916cacf3c6fc87b66bb0dde46f7357404750559f33" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313-win32.whl", hash = "sha256:e1c5988359516095535c4301af38d8a8838534158f649c05dd1050222321bcb3" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313-win_amd64.whl", hash = "sha256:960c83bf01a95b12b08fd54324a4eb1d5b52c88932b5cba5d6e712bb3ed12eb5" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313-win_arm64.whl", hash = "sha256:563fe25c678aaba333d5399408f5ec3c383ca5b663e7f774dd179a520b8144df" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:c76c4bec1538375dad9d452d246ca5368ad6e1c9039dadcf007ae59c70619ea1" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:57b46b24b5d5ebcc978da4ec23a819a9402b4228b8a90d9c656422b4bdd8a963" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e954b24433c768ce78ab7929e84ccf3422e46deb45a4dc9f93438f8217fa2d34" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3bd231490fa7217cc832528e1cd8752a96f0125ddd2b5749390f7c3ec8721b65" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:253282d70d67885a15c8a7716f3a73edf2d635793ceda8173b9ecc21f2fb8292" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0b4c48648d7649c9335cf1927a8b87fa692de3dcb15faa676c6a6f1f1aabda43" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:98bc624954ec4d2c7cb074b8eefc2b5d0ce7d482e410df446414355d158fe4ca" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1b99af4d9eec0b49927b4402bcbb58dea89d3e0db8806a4086117019939ad3dd" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6aac4f16b472d5b7dc6f66a0d49dd57b0e0902090be16594dc9ebfd3d17c47e7" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:21f830fe223215dffd51f538e78c172ed7c7f60c9b96a2bf05c4848ad49921c3" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f5dd81c45b05518b9aa4da4aa74e1c93d715efa234fd3e8a179df611cc85e5f4" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:eb304767bca2bb92fb9c5bd33cedc95baee5bb5f6c88e63706533a1c06ad08c8" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:c9035dde0f916702850ef66460bc4239d89d08df4d02023a5926e7446724212c" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:af959b9beeb66c822380f222f0e0a1889331597e81f1ded7f374f3ecb0fd6c52" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:41f2952231456154ee479651491e94118229844dd7226541788be783be2b5108" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313t-win32.whl", hash = "sha256:df9f19c28adcb40b6aae30bbaa1478c389efd50c28d541d76760199fc1037c32" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313t-win_amd64.whl", hash = "sha256:d54ecf9f301853f2c5e802da559604b3e95bb7a3b01a9c295c6ee591b9882de8" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp313-cp313t-win_arm64.whl", hash = "sha256:5a37ca18e360377cfda1d62f5f382ff41f2b8c4ccb329ed974cc2e1643440118" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8f333ec9c5eb1b7105e3b84b53141e66ca05a19a605368c55450b6ba208cb9ee" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:a407f13c188f804c759fc6a9f88286a565c242a76b27626594c133b82883b5c2" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0e161ddf326db5577c3a4cc2d8648f81456e8a20d40415541587a71620d7a7d1" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1e3a8bb24342a8201d178c3b4984c26ba81a577c80d4d525727427460a50c22d" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97231140a50f5d447d3164f994b86a0bed7cd016e2682f8650d6a9158e14fd31" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6b10359683bd8806a200fd2909e7c8ca3a7b24ec1d8132e483d58e791d881048" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:283ddac99f7ac25a4acadbf004cb5ae34480bbeb063520f70ce397b281859362" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:538cec1e18c067d0e6103aa9a74f9e832904c957adc260e61cd9d8cf0c3b3d37" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7eee46ccb30ff48a1e35bb818cc90846c6be2b68240e42a78599166722cea709" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fa263a02f4f2dd2d11a7b1bb4362aa7cb1049f84a9235d31adf63f30143469a0" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:2e1425e2f99ec5bd36c15a01b690a1a2456209c5deed58f95469ffb46039ccbb" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:497394b3239fc6f0e13a78a3e1b61296e72bf1c5f94b4c4eb80b265c37a131cd" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:233b398c29d3f1b9676b4b6f75c518a06fcb2ea0b925119fb2c1bc35c05e1601" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:93b1818e4a6e0930454f0f2af7dfce69307ca03cdcfb3739bf4d91241967b6c1" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f33dc2a3abe9249ea5d8360f969ec7f4142e7ac45ee7014d8f8d5acddf178b7b" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314-win32.whl", hash = "sha256:3ab8b9d8b75aef9df299595d5388b14530839f6422333357af1339443cff777d" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314-win_amd64.whl", hash = "sha256:5e01429a929600e7dab7b166062d9bb54a5eed752384c7384c968c2afab8f50f" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314-win_arm64.whl", hash = "sha256:4885cb0e817aef5d00a2e8451d4665c1808378dc27c2705f1bf4ef8505c0d2e5" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:0458c978acd8e6ea53c81eefaddbbee9c6c5e591f41b3f5e8e194780fe026581" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:c0abd12629b0af3cf590982c0b413b1e7395cd4ec026f30986818ab95bfaa94a" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:14525a5f61d7d0c94b368a42cff4c9a4e7ba2d52e2672a7b23d84dc86fb02b0c" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:17307b22c217b4cf05033dabefe68255a534d637c6c9b0cc8382718f87be4262" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a7e590ff876a3eaf1c02a4dfe0724b6e69a9e9de6d8f556816f29c496046e59" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:5fa6a95dfee63893d80a34758cd0e0c118a30b8dcb46372bf75106c591b77889" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a0543217a6a017692aa6ae5cc39adb75e587af0f3a82288b1492eb73dd6cc2a4" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f99fe611c312b3c1c0ace793f92464d8cd263cc3b26b5721950d977b006b6c4d" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9004d8386d133b7e6135679424c91b0b854d2d164af6ea3f289f8f2761064609" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e628ef0e6859ffd8273c69412a2465c4be4a9517d07261b33334b5ec6f3c7489" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:841189848ba629c3552035a6a7f5bf3b02eb304e9fea7492ca220a8eda6b0e5c" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:ce1bbd7d780bb5a0da032e095c951f7014d6b0a205f8318308140f1a6aba159e" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b26684587228afed0d50cf804cc71062cc9c1cdf55051c4c6345d372947b268c" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:9f9af11306994335398293f9958071019e3ab95e9a707dc1383a35613f6abcb9" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b4938326284c4f1224178a560987b6cf8b4d38458b113d9b8c1db1a836e640a2" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314t-win32.whl", hash = "sha256:98655c737850c064a65e006a3df7c997cd3b220be4ec8fe26215760b9697d4d7" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314t-win_amd64.whl", hash = "sha256:497bde6223c212ba11d462853cfa4f0ae6ef97465033e7dc9940cdb3ab5b48e5" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-cp314-cp314t-win_arm64.whl", hash = "sha256:2bbd113e0d4af5db41d5ebfe9ccaff89de2120578164f86a5d17d5a576d1e5b2" }, - { url = "https://bytedpypi.byted.org/packages/multidict/multidict-6.7.1-py3-none-any.whl", hash = "sha256:55d97cc6dae627efa6a6e548885712d4864b81110ac76fa4e534c03819fa4a56" }, -] - -[[package]] -name = "nanobot-ai" -version = "0.1.3.post5" -source = { editable = "." } -dependencies = [ - { name = "croniter" }, - { name = "dingtalk-stream" }, - { name = "httpx" }, - { name = "lark-oapi" }, - { name = "litellm" }, - { name = "loguru" }, - { name = "oauth-cli-kit" }, - { name = "pydantic" }, - { name = "pydantic-settings" }, - { name = "python-telegram-bot", extra = ["socks"] }, - { name = "qq-botpy" }, - { name = "readability-lxml" }, - { name = "rich" }, - { name = "slack-sdk" }, - { name = "socksio" }, - { name = "typer" }, - { name = "websocket-client" }, - { name = "websockets" }, -] - -[package.optional-dependencies] -dev = [ - { name = "pytest" }, - { name = "pytest-asyncio" }, - { name = "ruff" }, -] - -[package.metadata] -requires-dist = [ - { name = "croniter", specifier = ">=2.0.0" }, - { name = "dingtalk-stream", specifier = ">=0.4.0" }, - { name = "httpx", specifier = ">=0.25.0" }, - { name = "lark-oapi", specifier = ">=1.0.0" }, - { name = "litellm", specifier = ">=1.0.0" }, - { name = "loguru", specifier = ">=0.7.0" }, - { name = "oauth-cli-kit", specifier = ">=0.1.1" }, - { name = "pydantic", specifier = ">=2.0.0" }, - { name = "pydantic-settings", specifier = ">=2.0.0" }, - { name = "pytest", marker = "extra == 'dev'", specifier = ">=7.0.0" }, - { name = "pytest-asyncio", marker = "extra == 'dev'", specifier = ">=0.21.0" }, - { name = "python-telegram-bot", extras = ["socks"], specifier = ">=21.0" }, - { name = "qq-botpy", specifier = ">=1.0.0" }, - { name = "readability-lxml", specifier = ">=0.8.0" }, - { name = "rich", specifier = ">=13.0.0" }, - { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.1.0" }, - { name = "slack-sdk", specifier = ">=3.26.0" }, - { name = "socksio", specifier = ">=1.0.0" }, - { name = "typer", specifier = ">=0.9.0" }, - { name = "websocket-client", specifier = ">=1.6.0" }, - { name = "websockets", specifier = ">=12.0" }, -] -provides-extras = ["dev"] - -[[package]] -name = "oauth-cli-kit" -version = "0.1.1" -source = { registry = "https://bytedpypi.byted.org/simple/" } -dependencies = [ - { name = "httpx" }, - { name = "platformdirs" }, -] -sdist = { url = "https://bytedpypi.byted.org/packages/oauth-cli-kit/oauth_cli_kit-0.1.1.tar.gz", hash = "sha256:6a13f9b9ca738115e46314fff87506887603a21888527d1c0c9e420bc9401925" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/oauth-cli-kit/oauth_cli_kit-0.1.1-py3-none-any.whl", hash = "sha256:4b74633847c24ae677cf404bddd491b92e4ca99b1f7cb6bc5d67a3167e9b9910" }, -] - -[[package]] -name = "openai" -version = "2.20.0" -source = { registry = "https://bytedpypi.byted.org/simple/" } -dependencies = [ - { name = "anyio" }, - { name = "distro" }, - { name = "httpx" }, - { name = "jiter" }, - { name = "pydantic" }, - { name = "sniffio" }, - { name = "tqdm" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://bytedpypi.byted.org/packages/openai/openai-2.20.0.tar.gz", hash = "sha256:2654a689208cd0bf1098bb9462e8d722af5cbe961e6bba54e6f19fb843d88db1" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/openai/openai-2.20.0-py3-none-any.whl", hash = "sha256:38d989c4b1075cd1f76abc68364059d822327cf1a932531d429795f4fc18be99" }, -] - -[[package]] -name = "packaging" -version = "26.0" -source = { registry = "https://bytedpypi.byted.org/simple/" } -sdist = { url = "https://bytedpypi.byted.org/packages/packaging/packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/packaging/packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529" }, -] - -[[package]] -name = "platformdirs" -version = "4.7.0" -source = { registry = "https://bytedpypi.byted.org/simple/" } -sdist = { url = "https://bytedpypi.byted.org/packages/platformdirs/platformdirs-4.7.0.tar.gz", hash = "sha256:fd1a5f8599c85d49b9ac7d6e450bc2f1aaf4a23f1fe86d09952fe20ad365cf36" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/platformdirs/platformdirs-4.7.0-py3-none-any.whl", hash = "sha256:1ed8db354e344c5bb6039cd727f096af975194b508e37177719d562b2b540ee6" }, -] - -[[package]] -name = "pluggy" -version = "1.6.0" -source = { registry = "https://bytedpypi.byted.org/simple/" } -sdist = { url = "https://bytedpypi.byted.org/packages/pluggy/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/pluggy/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746" }, -] - -[[package]] -name = "propcache" -version = "0.4.1" -source = { registry = "https://bytedpypi.byted.org/simple/" } -sdist = { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1.tar.gz", hash = "sha256:f48107a8c637e80362555f37ecf49abe20370e557cc4ab374f04ec4423c97c3d" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:60a8fda9644b7dfd5dece8c61d8a85e271cb958075bfc4e01083c148b61a7caf" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c30b53e7e6bda1d547cabb47c825f3843a0a1a42b0496087bb58d8fedf9f41b5" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6918ecbd897443087a3b7cd978d56546a812517dcaaca51b49526720571fa93e" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3d902a36df4e5989763425a8ab9e98cd8ad5c52c823b34ee7ef307fd50582566" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a9695397f85973bb40427dedddf70d8dc4a44b22f1650dd4af9eedf443d45165" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2bb07ffd7eaad486576430c89f9b215f9e4be68c4866a96e97db9e97fead85dc" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fd6f30fdcf9ae2a70abd34da54f18da086160e4d7d9251f81f3da0ff84fc5a48" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fc38cba02d1acba4e2869eef1a57a43dfbd3d49a59bf90dda7444ec2be6a5570" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:67fad6162281e80e882fb3ec355398cf72864a54069d060321f6cd0ade95fe85" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f10207adf04d08bec185bae14d9606a1444715bc99180f9331c9c02093e1959e" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e9b0d8d0845bbc4cfcdcbcdbf5086886bc8157aa963c31c777ceff7846c77757" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:981333cb2f4c1896a12f4ab92a9cc8f09ea664e9b7dbdc4eff74627af3a11c0f" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp311-cp311-win32.whl", hash = "sha256:f1d2f90aeec838a52f1c1a32fe9a619fefd5e411721a9117fbf82aea638fe8a1" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:364426a62660f3f699949ac8c621aad6977be7126c5807ce48c0aeb8e7333ea6" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:e53f3a38d3510c11953f3e6a33f205c6d1b001129f972805ca9b42fc308bc239" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e153e9cd40cc8945138822807139367f256f89c6810c2634a4f6902b52d3b4e2" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cd547953428f7abb73c5ad82cbb32109566204260d98e41e5dfdc682eb7f8403" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f048da1b4f243fc44f205dfd320933a951b8d89e0afd4c7cacc762a8b9165207" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ec17c65562a827bba85e3872ead335f95405ea1674860d96483a02f5c698fa72" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:405aac25c6394ef275dee4c709be43745d36674b223ba4eb7144bf4d691b7367" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0013cb6f8dde4b2a2f66903b8ba740bdfe378c943c4377a200551ceb27f379e4" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:15932ab57837c3368b024473a525e25d316d8353016e7cc0e5ba9eb343fbb1cf" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:031dce78b9dc099f4c29785d9cf5577a3faf9ebf74ecbd3c856a7b92768c3df3" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ab08df6c9a035bee56e31af99be621526bd237bea9f32def431c656b29e41778" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4d7af63f9f93fe593afbf104c21b3b15868efb2c21d07d8732c0c4287e66b6a6" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:cfc27c945f422e8b5071b6e93169679e4eb5bf73bbcbf1ba3ae3a83d2f78ebd9" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:35c3277624a080cc6ec6f847cbbbb5b49affa3598c4535a0a4682a697aaa5c75" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp312-cp312-win32.whl", hash = "sha256:671538c2262dadb5ba6395e26c1731e1d52534bfe9ae56d0b5573ce539266aa8" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:cb2d222e72399fcf5890d1d5cc1060857b9b236adff2792ff48ca2dfd46c81db" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:204483131fb222bdaaeeea9f9e6c6ed0cac32731f75dfc1d4a567fc1926477c1" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:43eedf29202c08550aac1d14e0ee619b0430aaef78f85864c1a892294fbc28cf" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d62cdfcfd89ccb8de04e0eda998535c406bf5e060ffd56be6c586cbcc05b3311" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cae65ad55793da34db5f54e4029b89d3b9b9490d8abe1b4c7ab5d4b8ec7ebf74" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:333ddb9031d2704a301ee3e506dc46b1fe5f294ec198ed6435ad5b6a085facfe" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:fd0858c20f078a32cf55f7e81473d96dcf3b93fd2ccdb3d40fdf54b8573df3af" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:678ae89ebc632c5c204c794f8dab2837c5f159aeb59e6ed0539500400577298c" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d472aeb4fbf9865e0c6d622d7f4d54a4e101a89715d8904282bb5f9a2f476c3f" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4d3df5fa7e36b3225954fba85589da77a0fe6a53e3976de39caf04a0db4c36f1" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:ee17f18d2498f2673e432faaa71698032b0127ebf23ae5974eeaf806c279df24" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:580e97762b950f993ae618e167e7be9256b8353c2dcd8b99ec100eb50f5286aa" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:501d20b891688eb8e7aa903021f0b72d5a55db40ffaab27edefd1027caaafa61" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a0bd56e5b100aef69bd8562b74b46254e7c8812918d3baa700c8a8009b0af66" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313-win32.whl", hash = "sha256:bcc9aaa5d80322bc2fb24bb7accb4a30f81e90ab8d6ba187aec0744bc302ad81" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:381914df18634f5494334d201e98245c0596067504b9372d8cf93f4bb23e025e" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:8873eb4460fd55333ea49b7d189749ecf6e55bf85080f11b1c4530ed3034cba1" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:92d1935ee1f8d7442da9c0c4fa7ac20d07e94064184811b685f5c4fada64553b" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:473c61b39e1460d386479b9b2f337da492042447c9b685f28be4f74d3529e566" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c0ef0aaafc66fbd87842a3fe3902fd889825646bc21149eafe47be6072725835" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f95393b4d66bfae908c3ca8d169d5f79cd65636ae15b5e7a4f6e67af675adb0e" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c07fda85708bc48578467e85099645167a955ba093be0a2dcba962195676e859" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:af223b406d6d000830c6f65f1e6431783fc3f713ba3e6cc8c024d5ee96170a4b" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a78372c932c90ee474559c5ddfffd718238e8673c340dc21fe45c5b8b54559a0" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:564d9f0d4d9509e1a870c920a89b2fec951b44bf5ba7d537a9e7c1ccec2c18af" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:17612831fda0138059cc5546f4d12a2aacfb9e47068c06af35c400ba58ba7393" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:41a89040cb10bd345b3c1a873b2bf36413d48da1def52f268a055f7398514874" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e35b88984e7fa64aacecea39236cee32dd9bd8c55f57ba8a75cf2399553f9bd7" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6f8b465489f927b0df505cbe26ffbeed4d6d8a2bbc61ce90eb074ff129ef0ab1" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313t-win32.whl", hash = "sha256:2ad890caa1d928c7c2965b48f3a3815c853180831d0e5503d35cf00c472f4717" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313t-win_amd64.whl", hash = "sha256:f7ee0e597f495cf415bcbd3da3caa3bd7e816b74d0d52b8145954c5e6fd3ff37" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp313-cp313t-win_arm64.whl", hash = "sha256:929d7cbe1f01bb7baffb33dc14eb5691c95831450a26354cd210a8155170c93a" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3f7124c9d820ba5548d431afb4632301acf965db49e666aa21c305cbe8c6de12" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:c0d4b719b7da33599dfe3b22d3db1ef789210a0597bc650b7cee9c77c2be8c5c" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9f302f4783709a78240ebc311b793f123328716a60911d667e0c036bc5dcbded" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c80ee5802e3fb9ea37938e7eecc307fb984837091d5fd262bb37238b1ae97641" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ed5a841e8bb29a55fb8159ed526b26adc5bdd7e8bd7bf793ce647cb08656cdf4" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:55c72fd6ea2da4c318e74ffdf93c4fe4e926051133657459131a95c846d16d44" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8326e144341460402713f91df60ade3c999d601e7eb5ff8f6f7862d54de0610d" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:060b16ae65bc098da7f6d25bf359f1f31f688384858204fe5d652979e0015e5b" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:89eb3fa9524f7bec9de6e83cf3faed9d79bffa560672c118a96a171a6f55831e" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:dee69d7015dc235f526fe80a9c90d65eb0039103fe565776250881731f06349f" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:5558992a00dfd54ccbc64a32726a3357ec93825a418a401f5cc67df0ac5d9e49" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c9b822a577f560fbd9554812526831712c1436d2c046cedee4c3796d3543b144" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314-win32.whl", hash = "sha256:ab4c29b49d560fe48b696cdcb127dd36e0bc2472548f3bf56cc5cb3da2b2984f" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:5a103c3eb905fcea0ab98be99c3a9a5ab2de60228aa5aceedc614c0281cf6153" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:74c1fb26515153e482e00177a1ad654721bf9207da8a494a0c05e797ad27b992" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:824e908bce90fb2743bd6b59db36eb4f45cd350a39637c9f73b1c1ea66f5b75f" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:c2b5e7db5328427c57c8e8831abda175421b709672f6cfc3d630c3b7e2146393" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6f6ff873ed40292cd4969ef5310179afd5db59fdf055897e282485043fc80ad0" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:49a2dc67c154db2c1463013594c458881a069fcf98940e61a0569016a583020a" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:005f08e6a0529984491e37d8dbc3dd86f84bd78a8ceb5fa9a021f4c48d4984be" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5c3310452e0d31390da9035c348633b43d7e7feb2e37be252be6da45abd1abcc" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c3c70630930447f9ef1caac7728c8ad1c56bc5015338b20fed0d08ea2480b3a" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8e57061305815dfc910a3634dcf584f08168a8836e6999983569f51a8544cd89" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:521a463429ef54143092c11a77e04056dd00636f72e8c45b70aaa3140d639726" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:120c964da3fdc75e3731aa392527136d4ad35868cc556fd09bb6d09172d9a367" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:d8f353eb14ee3441ee844ade4277d560cdd68288838673273b978e3d6d2c8f36" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ab2943be7c652f09638800905ee1bab2c544e537edb57d527997a24c13dc1455" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314t-win32.whl", hash = "sha256:05674a162469f31358c30bcaa8883cb7829fa3110bf9c0991fe27d7896c42d85" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:990f6b3e2a27d683cb7602ed6c86f15ee6b43b1194736f9baaeb93d0016633b1" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:ecef2343af4cc68e05131e45024ba34f6095821988a9d0a02aa7c73fcc448aa9" }, - { url = "https://bytedpypi.byted.org/packages/propcache/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237" }, -] - -[[package]] -name = "pycryptodome" -version = "3.23.0" -source = { registry = "https://bytedpypi.byted.org/simple/" } -sdist = { url = "https://bytedpypi.byted.org/packages/pycryptodome/pycryptodome-3.23.0.tar.gz", hash = "sha256:447700a657182d60338bab09fdb27518f8856aecd80ae4c6bdddb67ff5da44ef" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/pycryptodome/pycryptodome-3.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:0011f7f00cdb74879142011f95133274741778abba114ceca229adbf8e62c3e4" }, - { url = "https://bytedpypi.byted.org/packages/pycryptodome/pycryptodome-3.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:90460fc9e088ce095f9ee8356722d4f10f86e5be06e2354230a9880b9c549aae" }, - { url = "https://bytedpypi.byted.org/packages/pycryptodome/pycryptodome-3.23.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4764e64b269fc83b00f682c47443c2e6e85b18273712b98aa43bcb77f8570477" }, - { url = "https://bytedpypi.byted.org/packages/pycryptodome/pycryptodome-3.23.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb8f24adb74984aa0e5d07a2368ad95276cf38051fe2dc6605cbcf482e04f2a7" }, - { url = "https://bytedpypi.byted.org/packages/pycryptodome/pycryptodome-3.23.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d97618c9c6684a97ef7637ba43bdf6663a2e2e77efe0f863cce97a76af396446" }, - { url = "https://bytedpypi.byted.org/packages/pycryptodome/pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9a53a4fe5cb075075d515797d6ce2f56772ea7e6a1e5e4b96cf78a14bac3d265" }, - { url = "https://bytedpypi.byted.org/packages/pycryptodome/pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:763d1d74f56f031788e5d307029caef067febf890cd1f8bf61183ae142f1a77b" }, - { url = "https://bytedpypi.byted.org/packages/pycryptodome/pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:954af0e2bd7cea83ce72243b14e4fb518b18f0c1649b576d114973e2073b273d" }, - { url = "https://bytedpypi.byted.org/packages/pycryptodome/pycryptodome-3.23.0-cp313-cp313t-win32.whl", hash = "sha256:257bb3572c63ad8ba40b89f6fc9d63a2a628e9f9708d31ee26560925ebe0210a" }, - { url = "https://bytedpypi.byted.org/packages/pycryptodome/pycryptodome-3.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:6501790c5b62a29fcb227bd6b62012181d886a767ce9ed03b303d1f22eb5c625" }, - { url = "https://bytedpypi.byted.org/packages/pycryptodome/pycryptodome-3.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:9a77627a330ab23ca43b48b130e202582e91cc69619947840ea4d2d1be21eb39" }, - { url = "https://bytedpypi.byted.org/packages/pycryptodome/pycryptodome-3.23.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:187058ab80b3281b1de11c2e6842a357a1f71b42cb1e15bce373f3d238135c27" }, - { url = "https://bytedpypi.byted.org/packages/pycryptodome/pycryptodome-3.23.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:cfb5cd445280c5b0a4e6187a7ce8de5a07b5f3f897f235caa11f1f435f182843" }, - { url = "https://bytedpypi.byted.org/packages/pycryptodome/pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67bd81fcbe34f43ad9422ee8fd4843c8e7198dd88dd3d40e6de42ee65fbe1490" }, - { url = "https://bytedpypi.byted.org/packages/pycryptodome/pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8987bd3307a39bc03df5c8e0e3d8be0c4c3518b7f044b0f4c15d1aa78f52575" }, - { url = "https://bytedpypi.byted.org/packages/pycryptodome/pycryptodome-3.23.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa0698f65e5b570426fc31b8162ed4603b0c2841cbb9088e2b01641e3065915b" }, - { url = "https://bytedpypi.byted.org/packages/pycryptodome/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:53ecbafc2b55353edcebd64bf5da94a2a2cdf5090a6915bcca6eca6cc452585a" }, - { url = "https://bytedpypi.byted.org/packages/pycryptodome/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:156df9667ad9f2ad26255926524e1c136d6664b741547deb0a86a9acf5ea631f" }, - { url = "https://bytedpypi.byted.org/packages/pycryptodome/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:dea827b4d55ee390dc89b2afe5927d4308a8b538ae91d9c6f7a5090f397af1aa" }, - { url = "https://bytedpypi.byted.org/packages/pycryptodome/pycryptodome-3.23.0-cp37-abi3-win32.whl", hash = "sha256:507dbead45474b62b2bbe318eb1c4c8ee641077532067fec9c1aa82c31f84886" }, - { url = "https://bytedpypi.byted.org/packages/pycryptodome/pycryptodome-3.23.0-cp37-abi3-win_amd64.whl", hash = "sha256:c75b52aacc6c0c260f204cbdd834f76edc9fb0d8e0da9fbf8352ef58202564e2" }, - { url = "https://bytedpypi.byted.org/packages/pycryptodome/pycryptodome-3.23.0-cp37-abi3-win_arm64.whl", hash = "sha256:11eeeb6917903876f134b56ba11abe95c0b0fd5e3330def218083c7d98bbcb3c" }, -] - -[[package]] -name = "pydantic" -version = "2.12.5" -source = { registry = "https://bytedpypi.byted.org/simple/" } -dependencies = [ - { name = "annotated-types" }, - { name = "pydantic-core" }, - { name = "typing-extensions" }, - { name = "typing-inspection" }, -] -sdist = { url = "https://bytedpypi.byted.org/packages/pydantic/pydantic-2.12.5.tar.gz", hash = "sha256:4d351024c75c0f085a9febbb665ce8c0c6ec5d30e903bdb6394b7ede26aebb49" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/pydantic/pydantic-2.12.5-py3-none-any.whl", hash = "sha256:e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d" }, -] - -[[package]] -name = "pydantic-core" -version = "2.41.5" -source = { registry = "https://bytedpypi.byted.org/simple/" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:a3a52f6156e73e7ccb0f8cced536adccb7042be67cb45f9562e12b319c119da6" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7f3bf998340c6d4b0c9a2f02d6a400e51f123b59565d74dc60d252ce888c260b" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:378bec5c66998815d224c9ca994f1e14c0c21cb95d2f52b6021cc0b2a58f2a5a" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e7b576130c69225432866fe2f4a469a85a54ade141d96fd396dffcf607b558f8" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6cb58b9c66f7e4179a2d5e0f849c48eff5c1fca560994d6eb6543abf955a149e" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88942d3a3dff3afc8288c21e565e476fc278902ae4d6d134f1eeda118cc830b1" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f31d95a179f8d64d90f6831d71fa93290893a33148d890ba15de25642c5d075b" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c1df3d34aced70add6f867a8cf413e299177e0c22660cc767218373d0779487b" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4009935984bd36bd2c774e13f9a09563ce8de4abaa7226f5108262fa3e637284" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:34a64bc3441dc1213096a20fe27e8e128bd3ff89921706e83c0b1ac971276594" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c9e19dd6e28fdcaa5a1de679aec4141f691023916427ef9bae8584f9c2fb3b0e" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp311-cp311-win32.whl", hash = "sha256:2c010c6ded393148374c0f6f0bf89d206bf3217f201faa0635dcd56bd1520f6b" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp311-cp311-win_amd64.whl", hash = "sha256:76ee27c6e9c7f16f47db7a94157112a2f3a00e958bc626e2f4ee8bec5c328fbe" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp311-cp311-win_arm64.whl", hash = "sha256:4bc36bbc0b7584de96561184ad7f012478987882ebf9f9c389b23f432ea3d90f" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f41a7489d32336dbf2199c8c0a215390a751c5b014c2c1c5366e817202e9cdf7" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:070259a8818988b9a84a449a2a7337c7f430a22acc0859c6b110aa7212a6d9c0" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e96cea19e34778f8d59fe40775a7a574d95816eb150850a85a7a4c8f4b94ac69" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed2e99c456e3fadd05c991f8f437ef902e00eedf34320ba2b0842bd1c3ca3a75" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65840751b72fbfd82c3c640cff9284545342a4f1eb1586ad0636955b261b0b05" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e536c98a7626a98feb2d3eaf75944ef6f3dbee447e1f841eae16f2f0a72d8ddc" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eceb81a8d74f9267ef4081e246ffd6d129da5d87e37a77c9bde550cb04870c1c" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d38548150c39b74aeeb0ce8ee1d8e82696f4a4e16ddc6de7b1d8823f7de4b9b5" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c23e27686783f60290e36827f9c626e63154b82b116d7fe9adba1fda36da706c" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:482c982f814460eabe1d3bb0adfdc583387bd4691ef00b90575ca0d2b6fe2294" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:bfea2a5f0b4d8d43adf9d7b8bf019fb46fdd10a2e5cde477fbcb9d1fa08c68e1" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp312-cp312-win32.whl", hash = "sha256:b74557b16e390ec12dca509bce9264c3bbd128f8a2c376eaa68003d7f327276d" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp312-cp312-win_amd64.whl", hash = "sha256:1962293292865bca8e54702b08a4f26da73adc83dd1fcf26fbc875b35d81c815" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp312-cp312-win_arm64.whl", hash = "sha256:1746d4a3d9a794cacae06a5eaaccb4b8643a131d45fbc9af23e353dc0a5ba5c3" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:941103c9be18ac8daf7b7adca8228f8ed6bb7a1849020f643b3a14d15b1924d9" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:112e305c3314f40c93998e567879e887a3160bb8689ef3d2c04b6cc62c33ac34" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cbaad15cb0c90aa221d43c00e77bb33c93e8d36e0bf74760cd00e732d10a6a0" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:03ca43e12fab6023fc79d28ca6b39b05f794ad08ec2feccc59a339b02f2b3d33" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc799088c08fa04e43144b164feb0c13f9a0bc40503f8df3e9fde58a3c0c101e" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97aeba56665b4c3235a0e52b2c2f5ae9cd071b8a8310ad27bddb3f7fb30e9aa2" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:406bf18d345822d6c21366031003612b9c77b3e29ffdb0f612367352aab7d586" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b93590ae81f7010dbe380cdeab6f515902ebcbefe0b9327cc4804d74e93ae69d" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:01a3d0ab748ee531f4ea6c3e48ad9dac84ddba4b0d82291f87248f2f9de8d740" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:6561e94ba9dacc9c61bce40e2d6bdc3bfaa0259d3ff36ace3b1e6901936d2e3e" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:915c3d10f81bec3a74fbd4faebe8391013ba61e5a1a8d48c4455b923bdda7858" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp313-cp313-win32.whl", hash = "sha256:650ae77860b45cfa6e2cdafc42618ceafab3a2d9a3811fcfbd3bbf8ac3c40d36" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp313-cp313-win_amd64.whl", hash = "sha256:79ec52ec461e99e13791ec6508c722742ad745571f234ea6255bed38c6480f11" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp313-cp313-win_arm64.whl", hash = "sha256:3f84d5c1b4ab906093bdc1ff10484838aca54ef08de4afa9de0f5f14d69639cd" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:3f37a19d7ebcdd20b96485056ba9e8b304e27d9904d233d7b1015db320e51f0a" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1d1d9764366c73f996edd17abb6d9d7649a7eb690006ab6adbda117717099b14" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25e1c2af0fce638d5f1988b686f3b3ea8cd7de5f244ca147c777769e798a9cd1" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:506d766a8727beef16b7adaeb8ee6217c64fc813646b424d0804d67c16eddb66" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4819fa52133c9aa3c387b3328f25c1facc356491e6135b459f1de698ff64d869" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b761d210c9ea91feda40d25b4efe82a1707da2ef62901466a42492c028553a2" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22f0fb8c1c583a3b6f24df2470833b40207e907b90c928cc8d3594b76f874375" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2782c870e99878c634505236d81e5443092fba820f0373997ff75f90f68cd553" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:0177272f88ab8312479336e1d777f6b124537d47f2123f89cb37e0accea97f90" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:63510af5e38f8955b8ee5687740d6ebf7c2a0886d15a6d65c32814613681bc07" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:e56ba91f47764cc14f1daacd723e3e82d1a89d783f0f5afe9c364b8bb491ccdb" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314-win32.whl", hash = "sha256:aec5cf2fd867b4ff45b9959f8b20ea3993fc93e63c7363fe6851424c8a7e7c23" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314-win_amd64.whl", hash = "sha256:8e7c86f27c585ef37c35e56a96363ab8de4e549a95512445b85c96d3e2f7c1bf" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314-win_arm64.whl", hash = "sha256:e672ba74fbc2dc8eea59fb6d4aed6845e6905fc2a8afe93175d94a83ba2a01a0" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:8566def80554c3faa0e65ac30ab0932b9e3a5cd7f8323764303d468e5c37595a" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b80aa5095cd3109962a298ce14110ae16b8c1aece8b72f9dafe81cf597ad80b3" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3006c3dd9ba34b0c094c544c6006cc79e87d8612999f1a5d43b769b89181f23c" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:72f6c8b11857a856bcfa48c86f5368439f74453563f951e473514579d44aa612" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5cb1b2f9742240e4bb26b652a5aeb840aa4b417c7748b6f8387927bc6e45e40d" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd3d54f38609ff308209bd43acea66061494157703364ae40c951f83ba99a1a9" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ff4321e56e879ee8d2a879501c8e469414d948f4aba74a2d4593184eb326660" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d0d2568a8c11bf8225044aa94409e21da0cb09dcdafe9ecd10250b2baad531a9" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:a39455728aabd58ceabb03c90e12f71fd30fa69615760a075b9fec596456ccc3" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:239edca560d05757817c13dc17c50766136d21f7cd0fac50295499ae24f90fdf" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:2a5e06546e19f24c6a96a129142a75cee553cc018ffee48a460059b1185f4470" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314t-win32.whl", hash = "sha256:b4ececa40ac28afa90871c2cc2b9ffd2ff0bf749380fbdf57d165fd23da353aa" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314t-win_amd64.whl", hash = "sha256:80aa89cad80b32a912a65332f64a4450ed00966111b6615ca6816153d3585a8c" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-cp314-cp314t-win_arm64.whl", hash = "sha256:35b44f37a3199f771c3eaa53051bc8a70cd7b54f333531c59e29fd4db5d15008" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:b96d5f26b05d03cc60f11a7761a5ded1741da411e7fe0909e27a5e6a0cb7b034" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:634e8609e89ceecea15e2d61bc9ac3718caaaa71963717bf3c8f38bfde64242c" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:93e8740d7503eb008aa2df04d3b9735f845d43ae845e6dcd2be0b55a2da43cd2" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f15489ba13d61f670dcc96772e733aad1a6f9c429cc27574c6cdaed82d0146ad" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:7da7087d756b19037bc2c06edc6c170eeef3c3bafcb8f532ff17d64dc427adfd" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:aabf5777b5c8ca26f7824cb4a120a740c9588ed58df9b2d196ce92fba42ff8dc" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c007fe8a43d43b3969e8469004e9845944f1a80e6acd47c150856bb87f230c56" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76d0819de158cd855d1cbb8fcafdf6f5cf1eb8e470abe056d5d161106e38062b" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b2379fa7ed44ddecb5bfe4e48577d752db9fc10be00a6b7446e9663ba143de26" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:266fb4cbf5e3cbd0b53669a6d1b039c45e3ce651fd5442eff4d07c2cc8d66808" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58133647260ea01e4d0500089a8c4f07bd7aa6ce109682b1426394988d8aaacc" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:287dad91cfb551c363dc62899a80e9e14da1f0e2b6ebde82c806612ca2a13ef1" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:03b77d184b9eb40240ae9fd676ca364ce1085f203e1b1256f8ab9984dca80a84" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:a668ce24de96165bb239160b3d854943128f4334822900534f2fe947930e5770" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f14f8f046c14563f8eb3f45f499cc658ab8d10072961e07225e507adb700e93f" }, - { url = "https://bytedpypi.byted.org/packages/pydantic-core/pydantic_core-2.41.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:56121965f7a4dc965bff783d70b907ddf3d57f6eba29b6d2e5dabfaf07799c51" }, -] - -[[package]] -name = "pydantic-settings" -version = "2.12.0" -source = { registry = "https://bytedpypi.byted.org/simple/" } -dependencies = [ - { name = "pydantic" }, - { name = "python-dotenv" }, - { name = "typing-inspection" }, -] -sdist = { url = "https://bytedpypi.byted.org/packages/pydantic-settings/pydantic_settings-2.12.0.tar.gz", hash = "sha256:005538ef951e3c2a68e1c08b292b5f2e71490def8589d4221b95dab00dafcfd0" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/pydantic-settings/pydantic_settings-2.12.0-py3-none-any.whl", hash = "sha256:fddb9fd99a5b18da837b29710391e945b1e30c135477f484084ee513adb93809" }, -] - -[[package]] -name = "pygments" -version = "2.19.2" -source = { registry = "https://bytedpypi.byted.org/simple/" } -sdist = { url = "https://bytedpypi.byted.org/packages/pygments/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/pygments/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b" }, -] - -[[package]] -name = "pytest" -version = "9.0.2" -source = { registry = "https://bytedpypi.byted.org/simple/" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "iniconfig" }, - { name = "packaging" }, - { name = "pluggy" }, - { name = "pygments" }, -] -sdist = { url = "https://bytedpypi.byted.org/packages/pytest/pytest-9.0.2.tar.gz", hash = "sha256:75186651a92bd89611d1d9fc20f0b4345fd827c41ccd5c299a868a05d70edf11" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/pytest/pytest-9.0.2-py3-none-any.whl", hash = "sha256:711ffd45bf766d5264d487b917733b453d917afd2b0ad65223959f59089f875b" }, -] - -[[package]] -name = "pytest-asyncio" -version = "1.3.0" -source = { registry = "https://bytedpypi.byted.org/simple/" } -dependencies = [ - { name = "pytest" }, - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, -] -sdist = { url = "https://bytedpypi.byted.org/packages/pytest-asyncio/pytest_asyncio-1.3.0.tar.gz", hash = "sha256:d7f52f36d231b80ee124cd216ffb19369aa168fc10095013c6b014a34d3ee9e5" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/pytest-asyncio/pytest_asyncio-1.3.0-py3-none-any.whl", hash = "sha256:611e26147c7f77640e6d0a92a38ed17c3e9848063698d5c93d5aa7aa11cebff5" }, -] - -[[package]] -name = "python-dateutil" -version = "2.9.0.post0" -source = { registry = "https://bytedpypi.byted.org/simple/" } -dependencies = [ - { name = "six" }, -] -sdist = { url = "https://bytedpypi.byted.org/packages/python-dateutil/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/python-dateutil/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427" }, -] - -[[package]] -name = "python-dotenv" -version = "1.2.1" -source = { registry = "https://bytedpypi.byted.org/simple/" } -sdist = { url = "https://bytedpypi.byted.org/packages/python-dotenv/python_dotenv-1.2.1.tar.gz", hash = "sha256:42667e897e16ab0d66954af0e60a9caa94f0fd4ecf3aaf6d2d260eec1aa36ad6" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/python-dotenv/python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61" }, -] - -[[package]] -name = "python-telegram-bot" -version = "22.6" -source = { registry = "https://bytedpypi.byted.org/simple/" } -dependencies = [ - { name = "httpcore", marker = "python_full_version >= '3.14'" }, - { name = "httpx" }, -] -sdist = { url = "https://bytedpypi.byted.org/packages/python-telegram-bot/python_telegram_bot-22.6.tar.gz", hash = "sha256:50ae8cc10f8dff01445628687951020721f37956966b92a91df4c1bf2d113742" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/python-telegram-bot/python_telegram_bot-22.6-py3-none-any.whl", hash = "sha256:e598fe171c3dde2dfd0f001619ee9110eece66761a677b34719fb18934935ce0" }, -] - -[package.optional-dependencies] -socks = [ - { name = "httpx", extra = ["socks"] }, -] - -[[package]] -name = "pytz" -version = "2025.2" -source = { registry = "https://bytedpypi.byted.org/simple/" } -sdist = { url = "https://bytedpypi.byted.org/packages/pytz/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/pytz/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00" }, -] - -[[package]] -name = "pyyaml" -version = "6.0.3" -source = { registry = "https://bytedpypi.byted.org/simple/" } -sdist = { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e" }, - { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824" }, - { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c" }, - { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00" }, - { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d" }, - { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a" }, - { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4" }, - { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b" }, - { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf" }, - { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196" }, - { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0" }, - { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28" }, - { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c" }, - { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc" }, - { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e" }, - { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea" }, - { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5" }, - { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b" }, - { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd" }, - { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8" }, - { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1" }, - { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c" }, - { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5" }, - { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6" }, - { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6" }, - { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be" }, - { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26" }, - { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c" }, - { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb" }, - { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac" }, - { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310" }, - { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7" }, - { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788" }, - { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5" }, - { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764" }, - { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35" }, - { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac" }, - { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3" }, - { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3" }, - { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba" }, - { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c" }, - { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702" }, - { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c" }, - { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065" }, - { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65" }, - { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9" }, - { url = "https://bytedpypi.byted.org/packages/pyyaml/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b" }, -] - -[[package]] -name = "qq-botpy" -version = "1.2.1" -source = { registry = "https://bytedpypi.byted.org/simple/" } -dependencies = [ - { name = "aiohttp" }, - { name = "apscheduler" }, - { name = "pyyaml" }, -] -sdist = { url = "https://bytedpypi.byted.org/packages/qq-botpy/qq-botpy-1.2.1.tar.gz", hash = "sha256:442172a0557a9b43d2777d1c5e072090a9d1a54d588d1c5da8d3efc014f4887f" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/qq-botpy/qq_botpy-1.2.1-py3-none-any.whl", hash = "sha256:18b215690dfed88f711322136ec54b6760040b9b1608eb5db7a44e00f59e4f01" }, -] - -[[package]] -name = "readability-lxml" -version = "0.8.4.1" -source = { registry = "https://bytedpypi.byted.org/simple/" } -dependencies = [ - { name = "chardet" }, - { name = "cssselect" }, - { name = "lxml", extra = ["html-clean"] }, -] -sdist = { url = "https://bytedpypi.byted.org/packages/readability-lxml/readability_lxml-0.8.4.1.tar.gz", hash = "sha256:9d2924f5942dd7f37fb4da353263b22a3e877ccf922d0e45e348e4177b035a53" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/readability-lxml/readability_lxml-0.8.4.1-py3-none-any.whl", hash = "sha256:874c0cea22c3bf2b78c7f8df831bfaad3c0a89b7301d45a188db581652b4b465" }, -] - -[[package]] -name = "referencing" -version = "0.37.0" -source = { registry = "https://bytedpypi.byted.org/simple/" } -dependencies = [ - { name = "attrs" }, - { name = "rpds-py" }, - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, -] -sdist = { url = "https://bytedpypi.byted.org/packages/referencing/referencing-0.37.0.tar.gz", hash = "sha256:44aefc3142c5b842538163acb373e24cce6632bd54bdb01b21ad5863489f50d8" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/referencing/referencing-0.37.0-py3-none-any.whl", hash = "sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231" }, -] - -[[package]] -name = "regex" -version = "2026.1.15" -source = { registry = "https://bytedpypi.byted.org/simple/" } -sdist = { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15.tar.gz", hash = "sha256:164759aa25575cbc0651bef59a0b18353e54300d79ace8084c818ad8ac72b7d5" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1ae6020fb311f68d753b7efa9d4b9a5d47a5d6466ea0d5e3b5a471a960ea6e4a" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:eddf73f41225942c1f994914742afa53dc0d01a6e20fe14b878a1b1edc74151f" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e8cd52557603f5c66a548f69421310886b28b7066853089e1a71ee710e1cdc1" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5170907244b14303edc5978f522f16c974f32d3aa92109fabc2af52411c9433b" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2748c1ec0663580b4510bd89941a31560b4b439a0b428b49472a3d9944d11cd8" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2f2775843ca49360508d080eaa87f94fa248e2c946bbcd963bb3aae14f333413" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d9ea2604370efc9a174c1b5dcc81784fb040044232150f7f33756049edfc9026" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0dcd31594264029b57bf16f37fd7248a70b3b764ed9e0839a8f271b2d22c0785" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c08c1f3e34338256732bd6938747daa3c0d5b251e04b6e43b5813e94d503076e" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e43a55f378df1e7a4fa3547c88d9a5a9b7113f653a66821bcea4718fe6c58763" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:f82110ab962a541737bd0ce87978d4c658f06e7591ba899192e2712a517badbb" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:27618391db7bdaf87ac6c92b31e8f0dfb83a9de0075855152b720140bda177a2" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bfb0d6be01fbae8d6655c8ca21b3b72458606c4aec9bbc932db758d47aba6db1" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp311-cp311-win32.whl", hash = "sha256:b10e42a6de0e32559a92f2f8dc908478cc0fa02838d7dbe764c44dca3fa13569" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp311-cp311-win_amd64.whl", hash = "sha256:e9bf3f0bbdb56633c07d7116ae60a576f846efdd86a8848f8d62b749e1209ca7" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp311-cp311-win_arm64.whl", hash = "sha256:41aef6f953283291c4e4e6850607bd71502be67779586a61472beacb315c97ec" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:4c8fcc5793dde01641a35905d6731ee1548f02b956815f8f1cab89e515a5bdf1" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:bfd876041a956e6a90ad7cdb3f6a630c07d491280bfeed4544053cd434901681" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9250d087bc92b7d4899ccd5539a1b2334e44eee85d848c4c1aef8e221d3f8c8f" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c8a154cf6537ebbc110e24dabe53095e714245c272da9c1be05734bdad4a61aa" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8050ba2e3ea1d8731a549e83c18d2f0999fbc99a5f6bd06b4c91449f55291804" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0bf065240704cb8951cc04972cf107063917022511273e0969bdb34fc173456c" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c32bef3e7aeee75746748643667668ef941d28b003bfc89994ecf09a10f7a1b5" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d5eaa4a4c5b1906bd0d2508d68927f15b81821f85092e06f1a34a4254b0e1af3" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:86c1077a3cc60d453d4084d5b9649065f3bf1184e22992bd322e1f081d3117fb" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:2b091aefc05c78d286657cd4db95f2e6313375ff65dcf085e42e4c04d9c8d410" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:57e7d17f59f9ebfa9667e6e5a1c0127b96b87cb9cede8335482451ed00788ba4" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:c6c4dcdfff2c08509faa15d36ba7e5ef5fcfab25f1e8f85a0c8f45bc3a30725d" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:cf8ff04c642716a7f2048713ddc6278c5fd41faa3b9cab12607c7abecd012c22" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp312-cp312-win32.whl", hash = "sha256:82345326b1d8d56afbe41d881fdf62f1926d7264b2fc1537f99ae5da9aad7913" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp312-cp312-win_amd64.whl", hash = "sha256:4def140aa6156bc64ee9912383d4038f3fdd18fee03a6f222abd4de6357ce42a" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp312-cp312-win_arm64.whl", hash = "sha256:c6c565d9a6e1a8d783c1948937ffc377dd5771e83bd56de8317c450a954d2056" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e69d0deeb977ffe7ed3d2e4439360089f9c3f217ada608f0f88ebd67afb6385e" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3601ffb5375de85a16f407854d11cca8fe3f5febbe3ac78fb2866bb220c74d10" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4c5ef43b5c2d4114eb8ea424bb8c9cec01d5d17f242af88b2448f5ee81caadbc" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:968c14d4f03e10b2fd960f1d5168c1f0ac969381d3c1fcc973bc45fb06346599" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:56a5595d0f892f214609c9f76b41b7428bed439d98dc961efafdd1354d42baae" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0bf650f26087363434c4e560011f8e4e738f6f3e029b85d4904c50135b86cfa5" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18388a62989c72ac24de75f1449d0fb0b04dfccd0a1a7c1c43af5eb503d890f6" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6d220a2517f5893f55daac983bfa9fe998a7dbcaee4f5d27a88500f8b7873788" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c9c08c2fbc6120e70abff5d7f28ffb4d969e14294fb2143b4b5c7d20e46d1714" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7ef7d5d4bd49ec7364315167a4134a015f61e8266c6d446fc116a9ac4456e10d" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:6e42844ad64194fa08d5ccb75fe6a459b9b08e6d7296bd704460168d58a388f3" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:cfecdaa4b19f9ca534746eb3b55a5195d5c95b88cac32a205e981ec0a22b7d31" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:08df9722d9b87834a3d701f3fca570b2be115654dbfd30179f30ab2f39d606d3" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313-win32.whl", hash = "sha256:d426616dae0967ca225ab12c22274eb816558f2f99ccb4a1d52ca92e8baf180f" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313-win_amd64.whl", hash = "sha256:febd38857b09867d3ed3f4f1af7d241c5c50362e25ef43034995b77a50df494e" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313-win_arm64.whl", hash = "sha256:8e32f7896f83774f91499d239e24cebfadbc07639c1494bb7213983842348337" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:ec94c04149b6a7b8120f9f44565722c7ae31b7a6d2275569d2eefa76b83da3be" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:40c86d8046915bb9aeb15d3f3f15b6fd500b8ea4485b30e1bbc799dab3fe29f8" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:726ea4e727aba21643205edad8f2187ec682d3305d790f73b7a51c7587b64bdd" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1cb740d044aff31898804e7bf1181cc72c03d11dfd19932b9911ffc19a79070a" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:05d75a668e9ea16f832390d22131fe1e8acc8389a694c8febc3e340b0f810b93" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d991483606f3dbec93287b9f35596f41aa2e92b7c2ebbb935b63f409e243c9af" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:194312a14819d3e44628a44ed6fea6898fdbecb0550089d84c403475138d0a09" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fe2fda4110a3d0bc163c2e0664be44657431440722c5c5315c65155cab92f9e5" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:124dc36c85d34ef2d9164da41a53c1c8c122cfb1f6e1ec377a1f27ee81deb794" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:a1774cd1981cd212506a23a14dba7fdeaee259f5deba2df6229966d9911e767a" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:b5f7d8d2867152cdb625e72a530d2ccb48a3d199159144cbdd63870882fb6f80" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:492534a0ab925d1db998defc3c302dae3616a2fc3fe2e08db1472348f096ddf2" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c661fc820cfb33e166bf2450d3dadbda47c8d8981898adb9b6fe24e5e582ba60" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313t-win32.whl", hash = "sha256:99ad739c3686085e614bf77a508e26954ff1b8f14da0e3765ff7abbf7799f952" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313t-win_amd64.whl", hash = "sha256:32655d17905e7ff8ba5c764c43cb124e34a9245e45b83c22e81041e1071aee10" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp313-cp313t-win_arm64.whl", hash = "sha256:b2a13dd6a95e95a489ca242319d18fc02e07ceb28fa9ad146385194d95b3c829" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:d920392a6b1f353f4aa54328c867fec3320fa50657e25f64abf17af054fc97ac" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:b5a28980a926fa810dbbed059547b02783952e2efd9c636412345232ddb87ff6" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:621f73a07595d83f28952d7bd1e91e9d1ed7625fb7af0064d3516674ec93a2a2" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3d7d92495f47567a9b1669c51fc8d6d809821849063d168121ef801bbc213846" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8dd16fba2758db7a3780a051f245539c4451ca20910f5a5e6ea1c08d06d4a76b" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1e1808471fbe44c1a63e5f577a1d5f02fe5d66031dcbdf12f093ffc1305a858e" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0751a26ad39d4f2ade8fe16c59b2bf5cb19eb3d2cd543e709e583d559bd9efde" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0f0c7684c7f9ca241344ff95a1de964f257a5251968484270e91c25a755532c5" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:74f45d170a21df41508cb67165456538425185baaf686281fa210d7e729abc34" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:f1862739a1ffb50615c0fde6bae6569b5efbe08d98e59ce009f68a336f64da75" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:453078802f1b9e2b7303fb79222c054cb18e76f7bdc220f7530fdc85d319f99e" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:a30a68e89e5a218b8b23a52292924c1f4b245cb0c68d1cce9aec9bbda6e2c160" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9479cae874c81bf610d72b85bb681a94c95722c127b55445285fb0e2c82db8e1" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314-win32.whl", hash = "sha256:d639a750223132afbfb8f429c60d9d318aeba03281a5f1ab49f877456448dcf1" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314-win_amd64.whl", hash = "sha256:4161d87f85fa831e31469bfd82c186923070fc970b9de75339b68f0c75b51903" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314-win_arm64.whl", hash = "sha256:91c5036ebb62663a6b3999bdd2e559fd8456d17e2b485bf509784cd31a8b1705" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:ee6854c9000a10938c79238de2379bea30c82e4925a371711af45387df35cab8" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2c2b80399a422348ce5de4fe40c418d6299a0fa2803dd61dc0b1a2f28e280fcf" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:dca3582bca82596609959ac39e12b7dad98385b4fefccb1151b937383cec547d" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ef71d476caa6692eea743ae5ea23cde3260677f70122c4d258ca952e5c2d4e84" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c243da3436354f4af6c3058a3f81a97d47ea52c9bd874b52fd30274853a1d5df" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8355ad842a7c7e9e5e55653eade3b7d1885ba86f124dd8ab1f722f9be6627434" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f192a831d9575271a22d804ff1a5355355723f94f31d9eef25f0d45a152fdc1a" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:166551807ec20d47ceaeec380081f843e88c8949780cd42c40f18d16168bed10" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:f9ca1cbdc0fbfe5e6e6f8221ef2309988db5bcede52443aeaee9a4ad555e0dac" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b30bcbd1e1221783c721483953d9e4f3ab9c5d165aa709693d3f3946747b1aea" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:2a8d7b50c34578d0d3bf7ad58cde9652b7d683691876f83aedc002862a35dc5e" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:9d787e3310c6a6425eb346be4ff2ccf6eece63017916fd77fe8328c57be83521" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:619843841e220adca114118533a574a9cd183ed8a28b85627d2844c500a2b0db" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314t-win32.whl", hash = "sha256:e90b8db97f6f2c97eb045b51a6b2c5ed69cedd8392459e0642d4199b94fabd7e" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314t-win_amd64.whl", hash = "sha256:5ef19071f4ac9f0834793af85bd04a920b4407715624e40cb7a0631a11137cdf" }, - { url = "https://bytedpypi.byted.org/packages/regex/regex-2026.1.15-cp314-cp314t-win_arm64.whl", hash = "sha256:ca89c5e596fc05b015f27561b3793dc2fa0917ea0d7507eebb448efd35274a70" }, -] - -[[package]] -name = "requests" -version = "2.32.5" -source = { registry = "https://bytedpypi.byted.org/simple/" } -dependencies = [ - { name = "certifi" }, - { name = "charset-normalizer" }, - { name = "idna" }, - { name = "urllib3" }, -] -sdist = { url = "https://bytedpypi.byted.org/packages/requests/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/requests/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6" }, -] - -[[package]] -name = "requests-toolbelt" -version = "1.0.0" -source = { registry = "https://bytedpypi.byted.org/simple/" } -dependencies = [ - { name = "requests" }, -] -sdist = { url = "https://bytedpypi.byted.org/packages/requests-toolbelt/requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/requests-toolbelt/requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06" }, -] - -[[package]] -name = "rich" -version = "14.3.2" -source = { registry = "https://bytedpypi.byted.org/simple/" } -dependencies = [ - { name = "markdown-it-py" }, - { name = "pygments" }, -] -sdist = { url = "https://bytedpypi.byted.org/packages/rich/rich-14.3.2.tar.gz", hash = "sha256:e712f11c1a562a11843306f5ed999475f09ac31ffb64281f73ab29ffdda8b3b8" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/rich/rich-14.3.2-py3-none-any.whl", hash = "sha256:08e67c3e90884651da3239ea668222d19bea7b589149d8014a21c633420dbb69" }, -] - -[[package]] -name = "rpds-py" -version = "0.30.0" -source = { registry = "https://bytedpypi.byted.org/simple/" } -sdist = { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0.tar.gz", hash = "sha256:dd8ff7cf90014af0c0f787eea34794ebf6415242ee1d6fa91eaba725cc441e84" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:a2bffea6a4ca9f01b3f8e548302470306689684e61602aa3d141e34da06cf425" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dc4f992dfe1e2bc3ebc7444f6c7051b4bc13cd8e33e43511e8ffd13bf407010d" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:422c3cb9856d80b09d30d2eb255d0754b23e090034e1deb4083f8004bd0761e4" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:07ae8a593e1c3c6b82ca3292efbe73c30b61332fd612e05abee07c79359f292f" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12f90dd7557b6bd57f40abe7747e81e0c0b119bef015ea7726e69fe550e394a4" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:99b47d6ad9a6da00bec6aabe5a6279ecd3c06a329d4aa4771034a21e335c3a97" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33f559f3104504506a44bb666b93a33f5d33133765b0c216a5bf2f1e1503af89" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:946fe926af6e44f3697abbc305ea168c2c31d3e3ef1058cf68f379bf0335a78d" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:495aeca4b93d465efde585977365187149e75383ad2684f81519f504f5c13038" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d9a0ca5da0386dee0655b4ccdf46119df60e0f10da268d04fe7cc87886872ba7" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8d6d1cc13664ec13c1b84241204ff3b12f9bb82464b8ad6e7a5d3486975c2eed" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3896fa1be39912cf0757753826bc8bdc8ca331a28a7c4ae46b7a21280b06bb85" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp311-cp311-win32.whl", hash = "sha256:55f66022632205940f1827effeff17c4fa7ae1953d2b74a8581baaefb7d16f8c" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp311-cp311-win_amd64.whl", hash = "sha256:a51033ff701fca756439d641c0ad09a41d9242fa69121c7d8769604a0a629825" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp311-cp311-win_arm64.whl", hash = "sha256:47b0ef6231c58f506ef0b74d44e330405caa8428e770fec25329ed2cb971a229" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a161f20d9a43006833cd7068375a94d035714d73a172b681d8881820600abfad" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6abc8880d9d036ecaafe709079969f56e876fcf107f7a8e9920ba6d5a3878d05" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca28829ae5f5d569bb62a79512c842a03a12576375d5ece7d2cadf8abe96ec28" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a1010ed9524c73b94d15919ca4d41d8780980e1765babf85f9a2f90d247153dd" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f8d1736cfb49381ba528cd5baa46f82fdc65c06e843dab24dd70b63d09121b3f" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d948b135c4693daff7bc2dcfc4ec57237a29bd37e60c2fabf5aff2bbacf3e2f1" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47f236970bccb2233267d89173d3ad2703cd36a0e2a6e92d0560d333871a3d23" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:2e6ecb5a5bcacf59c3f912155044479af1d0b6681280048b338b28e364aca1f6" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a8fa71a2e078c527c3e9dc9fc5a98c9db40bcc8a92b4e8858e36d329f8684b51" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:73c67f2db7bc334e518d097c6d1e6fed021bbc9b7d678d6cc433478365d1d5f5" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5ba103fb455be00f3b1c2076c9d4264bfcb037c976167a6047ed82f23153f02e" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7cee9c752c0364588353e627da8a7e808a66873672bcb5f52890c33fd965b394" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp312-cp312-win32.whl", hash = "sha256:1ab5b83dbcf55acc8b08fc62b796ef672c457b17dbd7820a11d6c52c06839bdf" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp312-cp312-win_amd64.whl", hash = "sha256:a090322ca841abd453d43456ac34db46e8b05fd9b3b4ac0c78bcde8b089f959b" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp312-cp312-win_arm64.whl", hash = "sha256:669b1805bd639dd2989b281be2cfd951c6121b65e729d9b843e9639ef1fd555e" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:f83424d738204d9770830d35290ff3273fbb02b41f919870479fab14b9d303b2" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e7536cd91353c5273434b4e003cbda89034d67e7710eab8761fd918ec6c69cf8" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2771c6c15973347f50fece41fc447c054b7ac2ae0502388ce3b6738cd366e3d4" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0a59119fc6e3f460315fe9d08149f8102aa322299deaa5cab5b40092345c2136" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:76fec018282b4ead0364022e3c54b60bf368b9d926877957a8624b58419169b7" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:692bef75a5525db97318e8cd061542b5a79812d711ea03dbc1f6f8dbb0c5f0d2" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9027da1ce107104c50c81383cae773ef5c24d296dd11c99e2629dbd7967a20c6" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:9cf69cdda1f5968a30a359aba2f7f9aa648a9ce4b580d6826437f2b291cfc86e" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a4796a717bf12b9da9d3ad002519a86063dcac8988b030e405704ef7d74d2d9d" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5d4c2aa7c50ad4728a094ebd5eb46c452e9cb7edbfdb18f9e1221f597a73e1e7" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ba81a9203d07805435eb06f536d95a266c21e5b2dfbf6517748ca40c98d19e31" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:945dccface01af02675628334f7cf49c2af4c1c904748efc5cf7bbdf0b579f95" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313-win32.whl", hash = "sha256:b40fb160a2db369a194cb27943582b38f79fc4887291417685f3ad693c5a1d5d" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313-win_amd64.whl", hash = "sha256:806f36b1b605e2d6a72716f321f20036b9489d29c51c91f4dd29a3e3afb73b15" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313-win_arm64.whl", hash = "sha256:d96c2086587c7c30d44f31f42eae4eac89b60dabbac18c7669be3700f13c3ce1" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:eb0b93f2e5c2189ee831ee43f156ed34e2a89a78a66b98cadad955972548be5a" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:922e10f31f303c7c920da8981051ff6d8c1a56207dbdf330d9047f6d30b70e5e" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdc62c8286ba9bf7f47befdcea13ea0e26bf294bda99758fd90535cbaf408000" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:47f9a91efc418b54fb8190a6b4aa7813a23fb79c51f4bb84e418f5476c38b8db" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1f3587eb9b17f3789ad50824084fa6f81921bbf9a795826570bda82cb3ed91f2" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:39c02563fc592411c2c61d26b6c5fe1e51eaa44a75aa2c8735ca88b0d9599daa" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51a1234d8febafdfd33a42d97da7a43f5dcb120c1060e352a3fbc0c6d36e2083" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:eb2c4071ab598733724c08221091e8d80e89064cd472819285a9ab0f24bcedb9" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6bdfdb946967d816e6adf9a3d8201bfad269c67efe6cefd7093ef959683c8de0" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c77afbd5f5250bf27bf516c7c4a016813eb2d3e116139aed0096940c5982da94" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:61046904275472a76c8c90c9ccee9013d70a6d0f73eecefd38c1ae7c39045a08" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4c5f36a861bc4b7da6516dbdf302c55313afa09b81931e8280361a4f6c9a2d27" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313t-win32.whl", hash = "sha256:3d4a69de7a3e50ffc214ae16d79d8fbb0922972da0356dcf4d0fdca2878559c6" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp313-cp313t-win_amd64.whl", hash = "sha256:f14fc5df50a716f7ece6a80b6c78bb35ea2ca47c499e422aa4463455dd96d56d" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:68f19c879420aa08f61203801423f6cd5ac5f0ac4ac82a2368a9fcd6a9a075e0" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ec7c4490c672c1a0389d319b3a9cfcd098dcdc4783991553c332a15acf7249be" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f251c812357a3fed308d684a5079ddfb9d933860fc6de89f2b7ab00da481e65f" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ac98b175585ecf4c0348fd7b29c3864bda53b805c773cbf7bfdaffc8070c976f" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3e62880792319dbeb7eb866547f2e35973289e7d5696c6e295476448f5b63c87" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4e7fc54e0900ab35d041b0601431b0a0eb495f0851a0639b6ef90f7741b39a18" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47e77dc9822d3ad616c3d5759ea5631a75e5809d5a28707744ef79d7a1bcfcad" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:b4dc1a6ff022ff85ecafef7979a2c6eb423430e05f1165d6688234e62ba99a07" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4559c972db3a360808309e06a74628b95eaccbf961c335c8fe0d590cf587456f" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:0ed177ed9bded28f8deb6ab40c183cd1192aa0de40c12f38be4d59cd33cb5c65" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:ad1fa8db769b76ea911cb4e10f049d80bf518c104f15b3edb2371cc65375c46f" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:46e83c697b1f1c72b50e5ee5adb4353eef7406fb3f2043d64c33f20ad1c2fc53" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314-win32.whl", hash = "sha256:ee454b2a007d57363c2dfd5b6ca4a5d7e2c518938f8ed3b706e37e5d470801ed" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314-win_amd64.whl", hash = "sha256:95f0802447ac2d10bcc69f6dc28fe95fdf17940367b21d34e34c737870758950" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314-win_arm64.whl", hash = "sha256:613aa4771c99f03346e54c3f038e4cc574ac09a3ddfb0e8878487335e96dead6" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:7e6ecfcb62edfd632e56983964e6884851786443739dbfe3582947e87274f7cb" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a1d0bc22a7cdc173fedebb73ef81e07faef93692b8c1ad3733b67e31e1b6e1b8" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d08f00679177226c4cb8c5265012eea897c8ca3b93f429e546600c971bcbae7" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5965af57d5848192c13534f90f9dd16464f3c37aaf166cc1da1cae1fd5a34898" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9a4e86e34e9ab6b667c27f3211ca48f73dba7cd3d90f8d5b11be56e5dbc3fb4e" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5d3e6b26f2c785d65cc25ef1e5267ccbe1b069c5c21b8cc724efee290554419" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:626a7433c34566535b6e56a1b39a7b17ba961e97ce3b80ec62e6f1312c025551" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:acd7eb3f4471577b9b5a41baf02a978e8bdeb08b4b355273994f8b87032000a8" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fe5fa731a1fa8a0a56b0977413f8cacac1768dad38d16b3a296712709476fbd5" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:74a3243a411126362712ee1524dfc90c650a503502f135d54d1b352bd01f2404" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:3e8eeb0544f2eb0d2581774be4c3410356eba189529a6b3e36bbbf9696175856" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:dbd936cde57abfee19ab3213cf9c26be06d60750e60a8e4dd85d1ab12c8b1f40" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314t-win32.whl", hash = "sha256:dc824125c72246d924f7f796b4f63c1e9dc810c7d9e2355864b3c3a73d59ade0" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-cp314-cp314t-win_amd64.whl", hash = "sha256:27f4b0e92de5bfbc6f86e43959e6edd1425c33b5e69aab0984a72047f2bcf1e3" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c2262bdba0ad4fc6fb5545660673925c2d2a5d9e2e0fb603aad545427be0fc58" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:ee6af14263f25eedc3bb918a3c04245106a42dfd4f5c2285ea6f997b1fc3f89a" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3adbb8179ce342d235c31ab8ec511e66c73faa27a47e076ccc92421add53e2bb" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:250fa00e9543ac9b97ac258bd37367ff5256666122c2d0f2bc97577c60a1818c" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9854cf4f488b3d57b9aaeb105f06d78e5529d3145b1e4a41750167e8c213c6d3" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:993914b8e560023bc0a8bf742c5f303551992dcb85e247b1e5c7f4a7d145bda5" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58edca431fb9b29950807e301826586e5bbf24163677732429770a697ffe6738" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:dea5b552272a944763b34394d04577cf0f9bd013207bc32323b5a89a53cf9c2f" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ba3af48635eb83d03f6c9735dfb21785303e73d22ad03d489e88adae6eab8877" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:dff13836529b921e22f15cb099751209a60009731a68519630a24d61f0b1b30a" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:1b151685b23929ab7beec71080a8889d4d6d9fa9a983d213f07121205d48e2c4" }, - { url = "https://bytedpypi.byted.org/packages/rpds-py/rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:ac37f9f516c51e5753f27dfdef11a88330f04de2d564be3991384b2f3535d02e" }, -] - -[[package]] -name = "ruff" -version = "0.15.1" -source = { registry = "https://bytedpypi.byted.org/simple/" } -sdist = { url = "https://bytedpypi.byted.org/packages/ruff/ruff-0.15.1.tar.gz", hash = "sha256:c590fe13fb57c97141ae975c03a1aedb3d3156030cabd740d6ff0b0d601e203f" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/ruff/ruff-0.15.1-py3-none-linux_armv6l.whl", hash = "sha256:b101ed7cf4615bda6ffe65bdb59f964e9f4a0d3f85cbf0e54f0ab76d7b90228a" }, - { url = "https://bytedpypi.byted.org/packages/ruff/ruff-0.15.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:939c995e9277e63ea632cc8d3fae17aa758526f49a9a850d2e7e758bfef46602" }, - { url = "https://bytedpypi.byted.org/packages/ruff/ruff-0.15.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:1d83466455fdefe60b8d9c8df81d3c1bbb2115cede53549d3b522ce2bc703899" }, - { url = "https://bytedpypi.byted.org/packages/ruff/ruff-0.15.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9457e3c3291024866222b96108ab2d8265b477e5b1534c7ddb1810904858d16" }, - { url = "https://bytedpypi.byted.org/packages/ruff/ruff-0.15.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:92c92b003e9d4f7fbd33b1867bb15a1b785b1735069108dfc23821ba045b29bc" }, - { url = "https://bytedpypi.byted.org/packages/ruff/ruff-0.15.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fe5c41ab43e3a06778844c586251eb5a510f67125427625f9eb2b9526535779" }, - { url = "https://bytedpypi.byted.org/packages/ruff/ruff-0.15.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:66a6dd6df4d80dc382c6484f8ce1bcceb55c32e9f27a8b94c32f6c7331bf14fb" }, - { url = "https://bytedpypi.byted.org/packages/ruff/ruff-0.15.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6a4a42cbb8af0bda9bcd7606b064d7c0bc311a88d141d02f78920be6acb5aa83" }, - { url = "https://bytedpypi.byted.org/packages/ruff/ruff-0.15.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ab064052c31dddada35079901592dfba2e05f5b1e43af3954aafcbc1096a5b2" }, - { url = "https://bytedpypi.byted.org/packages/ruff/ruff-0.15.1-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:5631c940fe9fe91f817a4c2ea4e81f47bee3ca4aa646134a24374f3c19ad9454" }, - { url = "https://bytedpypi.byted.org/packages/ruff/ruff-0.15.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:68138a4ba184b4691ccdc39f7795c66b3c68160c586519e7e8444cf5a53e1b4c" }, - { url = "https://bytedpypi.byted.org/packages/ruff/ruff-0.15.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:518f9af03bfc33c03bdb4cb63fabc935341bb7f54af500f92ac309ecfbba6330" }, - { url = "https://bytedpypi.byted.org/packages/ruff/ruff-0.15.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:da79f4d6a826caaea95de0237a67e33b81e6ec2e25fc7e1993a4015dffca7c61" }, - { url = "https://bytedpypi.byted.org/packages/ruff/ruff-0.15.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:3dd86dccb83cd7d4dcfac303ffc277e6048600dfc22e38158afa208e8bf94a1f" }, - { url = "https://bytedpypi.byted.org/packages/ruff/ruff-0.15.1-py3-none-win32.whl", hash = "sha256:660975d9cb49b5d5278b12b03bb9951d554543a90b74ed5d366b20e2c57c2098" }, - { url = "https://bytedpypi.byted.org/packages/ruff/ruff-0.15.1-py3-none-win_amd64.whl", hash = "sha256:c820fef9dd5d4172a6570e5721704a96c6679b80cf7be41659ed439653f62336" }, - { url = "https://bytedpypi.byted.org/packages/ruff/ruff-0.15.1-py3-none-win_arm64.whl", hash = "sha256:5ff7d5f0f88567850f45081fac8f4ec212be8d0b963e385c3f7d0d2eb4899416" }, -] - -[[package]] -name = "shellingham" -version = "1.5.4" -source = { registry = "https://bytedpypi.byted.org/simple/" } -sdist = { url = "https://bytedpypi.byted.org/packages/shellingham/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/shellingham/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686" }, -] - -[[package]] -name = "six" -version = "1.17.0" -source = { registry = "https://bytedpypi.byted.org/simple/" } -sdist = { url = "https://bytedpypi.byted.org/packages/six/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/six/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274" }, -] - -[[package]] -name = "slack-sdk" -version = "3.40.0" -source = { registry = "https://bytedpypi.byted.org/simple/" } -sdist = { url = "https://bytedpypi.byted.org/packages/slack-sdk/slack_sdk-3.40.0.tar.gz", hash = "sha256:87b9a79d1d6e19a2b1877727a0ec6f016d82d30a6a410389fba87c221c99f10e" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/slack-sdk/slack_sdk-3.40.0-py2.py3-none-any.whl", hash = "sha256:f2bada5ed3adb10a01e154e90db01d6d8938d0461b5790c12bcb807b2d28bbe2" }, -] - -[[package]] -name = "sniffio" -version = "1.3.1" -source = { registry = "https://bytedpypi.byted.org/simple/" } -sdist = { url = "https://bytedpypi.byted.org/packages/sniffio/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/sniffio/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2" }, -] - -[[package]] -name = "socksio" -version = "1.0.0" -source = { registry = "https://bytedpypi.byted.org/simple/" } -sdist = { url = "https://bytedpypi.byted.org/packages/socksio/socksio-1.0.0.tar.gz", hash = "sha256:f88beb3da5b5c38b9890469de67d0cb0f9d494b78b106ca1845f96c10b91c4ac" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/socksio/socksio-1.0.0-py3-none-any.whl", hash = "sha256:95dc1f15f9b34e8d7b16f06d74b8ccf48f609af32ab33c608d08761c5dcbb1f3" }, -] - -[[package]] -name = "tiktoken" -version = "0.12.0" -source = { registry = "https://bytedpypi.byted.org/simple/" } -dependencies = [ - { name = "regex" }, - { name = "requests" }, -] -sdist = { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0.tar.gz", hash = "sha256:b18ba7ee2b093863978fcb14f74b3707cdc8d4d4d3836853ce7ec60772139931" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:6e227c7f96925003487c33b1b32265fad2fbcec2b7cf4817afb76d416f40f6bb" }, - { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c06cf0fcc24c2cb2adb5e185c7082a82cba29c17575e828518c2f11a01f445aa" }, - { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:f18f249b041851954217e9fd8e5c00b024ab2315ffda5ed77665a05fa91f42dc" }, - { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:47a5bc270b8c3db00bb46ece01ef34ad050e364b51d406b6f9730b64ac28eded" }, - { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:508fa71810c0efdcd1b898fda574889ee62852989f7c1667414736bcb2b9a4bd" }, - { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a1af81a6c44f008cba48494089dd98cccb8b313f55e961a52f5b222d1e507967" }, - { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:3e68e3e593637b53e56f7237be560f7a394451cb8c11079755e80ae64b9e6def" }, - { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b97f74aca0d78a1ff21b8cd9e9925714c15a9236d6ceacf5c7327c117e6e21e8" }, - { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2b90f5ad190a4bb7c3eb30c5fa32e1e182ca1ca79f05e49b448438c3e225a49b" }, - { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:65b26c7a780e2139e73acc193e5c63ac754021f160df919add909c1492c0fb37" }, - { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:edde1ec917dfd21c1f2f8046b86348b0f54a2c0547f68149d8600859598769ad" }, - { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:35a2f8ddd3824608b3d650a000c1ef71f730d0c56486845705a8248da00f9fe5" }, - { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:83d16643edb7fa2c99eff2ab7733508aae1eebb03d5dfc46f5565862810f24e3" }, - { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:ffc5288f34a8bc02e1ea7047b8d041104791d2ddbf42d1e5fa07822cbffe16bd" }, - { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:775c2c55de2310cc1bc9a3ad8826761cbdc87770e586fd7b6da7d4589e13dab3" }, - { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a01b12f69052fbe4b080a2cfb867c4de12c704b56178edf1d1d7b273561db160" }, - { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:01d99484dc93b129cd0964f9d34eee953f2737301f18b3c7257bf368d7615baa" }, - { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:4a1a4fcd021f022bfc81904a911d3df0f6543b9e7627b51411da75ff2fe7a1be" }, - { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:981a81e39812d57031efdc9ec59fa32b2a5a5524d20d4776574c4b4bd2e9014a" }, - { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9baf52f84a3f42eef3ff4e754a0db79a13a27921b457ca9832cf944c6be4f8f3" }, - { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:b8a0cd0c789a61f31bf44851defbd609e8dd1e2c8589c614cc1060940ef1f697" }, - { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:d5f89ea5680066b68bcb797ae85219c72916c922ef0fcdd3480c7d2315ffff16" }, - { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b4e7ed1c6a7a8a60a3230965bdedba8cc58f68926b835e519341413370e0399a" }, - { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:fc530a28591a2d74bce821d10b418b26a094bf33839e69042a6e86ddb7a7fb27" }, - { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:06a9f4f49884139013b138920a4c393aa6556b2f8f536345f11819389c703ebb" }, - { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:04f0e6a985d95913cabc96a741c5ffec525a2c72e9df086ff17ebe35985c800e" }, - { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:0ee8f9ae00c41770b5f9b0bb1235474768884ae157de3beb5439ca0fd70f3e25" }, - { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp313-cp313t-win_amd64.whl", hash = "sha256:dc2dd125a62cb2b3d858484d6c614d136b5b848976794edfb63688d539b8b93f" }, - { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:a90388128df3b3abeb2bfd1895b0681412a8d7dc644142519e6f0a97c2111646" }, - { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:da900aa0ad52247d8794e307d6446bd3cdea8e192769b56276695d34d2c9aa88" }, - { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:285ba9d73ea0d6171e7f9407039a290ca77efcdb026be7769dccc01d2c8d7fff" }, - { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:d186a5c60c6a0213f04a7a802264083dea1bbde92a2d4c7069e1a56630aef830" }, - { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:604831189bd05480f2b885ecd2d1986dc7686f609de48208ebbbddeea071fc0b" }, - { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:8f317e8530bb3a222547b85a58583238c8f74fd7a7408305f9f63246d1a0958b" }, - { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp314-cp314-win_amd64.whl", hash = "sha256:399c3dd672a6406719d84442299a490420b458c44d3ae65516302a99675888f3" }, - { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:c2c714c72bc00a38ca969dae79e8266ddec999c7ceccd603cc4f0d04ccd76365" }, - { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:cbb9a3ba275165a2cb0f9a83f5d7025afe6b9d0ab01a22b50f0e74fee2ad253e" }, - { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:dfdfaa5ffff8993a3af94d1125870b1d27aed7cb97aa7eb8c1cefdbc87dbee63" }, - { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:584c3ad3d0c74f5269906eb8a659c8bfc6144a52895d9261cdaf90a0ae5f4de0" }, - { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:54c891b416a0e36b8e2045b12b33dd66fb34a4fe7965565f1b482da50da3e86a" }, - { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5edb8743b88d5be814b1a8a8854494719080c28faaa1ccbef02e87354fe71ef0" }, - { url = "https://bytedpypi.byted.org/packages/tiktoken/tiktoken-0.12.0-cp314-cp314t-win_amd64.whl", hash = "sha256:f61c0aea5565ac82e2ec50a05e02a6c44734e91b51c10510b084ea1b8e633a71" }, -] - -[[package]] -name = "tokenizers" -version = "0.22.2" -source = { registry = "https://bytedpypi.byted.org/simple/" } -dependencies = [ - { name = "huggingface-hub" }, -] -sdist = { url = "https://bytedpypi.byted.org/packages/tokenizers/tokenizers-0.22.2.tar.gz", hash = "sha256:473b83b915e547aa366d1eee11806deaf419e17be16310ac0a14077f1e28f917" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/tokenizers/tokenizers-0.22.2-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:544dd704ae7238755d790de45ba8da072e9af3eea688f698b137915ae959281c" }, - { url = "https://bytedpypi.byted.org/packages/tokenizers/tokenizers-0.22.2-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:1e418a55456beedca4621dbab65a318981467a2b188e982a23e117f115ce5001" }, - { url = "https://bytedpypi.byted.org/packages/tokenizers/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2249487018adec45d6e3554c71d46eb39fa8ea67156c640f7513eb26f318cec7" }, - { url = "https://bytedpypi.byted.org/packages/tokenizers/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25b85325d0815e86e0bac263506dd114578953b7b53d7de09a6485e4a160a7dd" }, - { url = "https://bytedpypi.byted.org/packages/tokenizers/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bfb88f22a209ff7b40a576d5324bf8286b519d7358663db21d6246fb17eea2d5" }, - { url = "https://bytedpypi.byted.org/packages/tokenizers/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1c774b1276f71e1ef716e5486f21e76333464f47bece56bbd554485982a9e03e" }, - { url = "https://bytedpypi.byted.org/packages/tokenizers/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:df6c4265b289083bf710dff49bc51ef252f9d5be33a45ee2bed151114a56207b" }, - { url = "https://bytedpypi.byted.org/packages/tokenizers/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:369cc9fc8cc10cb24143873a0d95438bb8ee257bb80c71989e3ee290e8d72c67" }, - { url = "https://bytedpypi.byted.org/packages/tokenizers/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:29c30b83d8dcd061078b05ae0cb94d3c710555fbb44861139f9f83dcca3dc3e4" }, - { url = "https://bytedpypi.byted.org/packages/tokenizers/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:37ae80a28c1d3265bb1f22464c856bd23c02a05bb211e56d0c5301a435be6c1a" }, - { url = "https://bytedpypi.byted.org/packages/tokenizers/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:791135ee325f2336f498590eb2f11dc5c295232f288e75c99a36c5dbce63088a" }, - { url = "https://bytedpypi.byted.org/packages/tokenizers/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38337540fbbddff8e999d59970f3c6f35a82de10053206a7562f1ea02d046fa5" }, - { url = "https://bytedpypi.byted.org/packages/tokenizers/tokenizers-0.22.2-cp39-abi3-win32.whl", hash = "sha256:a6bf3f88c554a2b653af81f3204491c818ae2ac6fbc09e76ef4773351292bc92" }, - { url = "https://bytedpypi.byted.org/packages/tokenizers/tokenizers-0.22.2-cp39-abi3-win_amd64.whl", hash = "sha256:c9ea31edff2968b44a88f97d784c2f16dc0729b8b143ed004699ebca91f05c48" }, - { url = "https://bytedpypi.byted.org/packages/tokenizers/tokenizers-0.22.2-cp39-abi3-win_arm64.whl", hash = "sha256:9ce725d22864a1e965217204946f830c37876eee3b2ba6fc6255e8e903d5fcbc" }, -] - -[[package]] -name = "tqdm" -version = "4.67.3" -source = { registry = "https://bytedpypi.byted.org/simple/" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, -] -sdist = { url = "https://bytedpypi.byted.org/packages/tqdm/tqdm-4.67.3.tar.gz", hash = "sha256:7d825f03f89244ef73f1d4ce193cb1774a8179fd96f31d7e1dcde62092b960bb" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/tqdm/tqdm-4.67.3-py3-none-any.whl", hash = "sha256:ee1e4c0e59148062281c49d80b25b67771a127c85fc9676d3be5f243206826bf" }, -] - -[[package]] -name = "typer" -version = "0.23.0" -source = { registry = "https://bytedpypi.byted.org/simple/" } -dependencies = [ - { name = "annotated-doc" }, - { name = "click" }, - { name = "rich" }, - { name = "shellingham" }, -] -sdist = { url = "https://bytedpypi.byted.org/packages/typer/typer-0.23.0.tar.gz", hash = "sha256:d8378833e47ada5d3d093fa20c4c63427cc4e27127f6b349a6c359463087d8cc" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/typer/typer-0.23.0-py3-none-any.whl", hash = "sha256:79f4bc262b6c37872091072a3cb7cb6d7d79ee98c0c658b4364bdcde3c42c913" }, -] - -[[package]] -name = "typer-slim" -version = "0.23.0" -source = { registry = "https://bytedpypi.byted.org/simple/" } -dependencies = [ - { name = "typer" }, -] -sdist = { url = "https://bytedpypi.byted.org/packages/typer-slim/typer_slim-0.23.0.tar.gz", hash = "sha256:be8b60243df27cfee444c6db1b10a85f4f3e54d940574f31a996f78aa35a8254" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/typer-slim/typer_slim-0.23.0-py3-none-any.whl", hash = "sha256:1d693daf22d998a7b1edab8413cdcb8af07254154ce3956c1664dc11b01e2f8b" }, -] - -[[package]] -name = "typing-extensions" -version = "4.15.0" -source = { registry = "https://bytedpypi.byted.org/simple/" } -sdist = { url = "https://bytedpypi.byted.org/packages/typing-extensions/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/typing-extensions/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548" }, -] - -[[package]] -name = "typing-inspection" -version = "0.4.2" -source = { registry = "https://bytedpypi.byted.org/simple/" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://bytedpypi.byted.org/packages/typing-inspection/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/typing-inspection/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7" }, -] - -[[package]] -name = "tzdata" -version = "2025.3" -source = { registry = "https://bytedpypi.byted.org/simple/" } -sdist = { url = "https://bytedpypi.byted.org/packages/tzdata/tzdata-2025.3.tar.gz", hash = "sha256:de39c2ca5dc7b0344f2eba86f49d614019d29f060fc4ebc8a417896a620b56a7" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/tzdata/tzdata-2025.3-py2.py3-none-any.whl", hash = "sha256:06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1" }, -] - -[[package]] -name = "tzlocal" -version = "5.3.1" -source = { registry = "https://bytedpypi.byted.org/simple/" } -dependencies = [ - { name = "tzdata", marker = "sys_platform == 'win32'" }, -] -sdist = { url = "https://bytedpypi.byted.org/packages/tzlocal/tzlocal-5.3.1.tar.gz", hash = "sha256:cceffc7edecefea1f595541dbd6e990cb1ea3d19bf01b2809f362a03dd7921fd" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/tzlocal/tzlocal-5.3.1-py3-none-any.whl", hash = "sha256:eb1a66c3ef5847adf7a834f1be0800581b683b5608e74f86ecbcef8ab91bb85d" }, -] - -[[package]] -name = "urllib3" -version = "2.6.3" -source = { registry = "https://bytedpypi.byted.org/simple/" } -sdist = { url = "https://bytedpypi.byted.org/packages/urllib3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/urllib3/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4" }, -] - -[[package]] -name = "websocket-client" -version = "1.9.0" -source = { registry = "https://bytedpypi.byted.org/simple/" } -sdist = { url = "https://bytedpypi.byted.org/packages/websocket-client/websocket_client-1.9.0.tar.gz", hash = "sha256:9e813624b6eb619999a97dc7958469217c3176312b3a16a4bd1bc7e08a46ec98" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/websocket-client/websocket_client-1.9.0-py3-none-any.whl", hash = "sha256:af248a825037ef591efbf6ed20cc5faa03d3b47b9e5a2230a529eeee1c1fc3ef" }, -] - -[[package]] -name = "websockets" -version = "16.0" -source = { registry = "https://bytedpypi.byted.org/simple/" } -sdist = { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0.tar.gz", hash = "sha256:5f6261a5e56e8d5c42a4497b364ea24d94d9563e8fbd44e78ac40879c60179b5" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:31a52addea25187bde0797a97d6fc3d2f92b6f72a9370792d65a6e84615ac8a8" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:417b28978cdccab24f46400586d128366313e8a96312e4b9362a4af504f3bbad" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:af80d74d4edfa3cb9ed973a0a5ba2b2a549371f8a741e0800cb07becdd20f23d" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:08d7af67b64d29823fed316505a89b86705f2b7981c07848fb5e3ea3020c1abe" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7be95cfb0a4dae143eaed2bcba8ac23f4892d8971311f1b06f3c6b78952ee70b" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d6297ce39ce5c2e6feb13c1a996a2ded3b6832155fcfc920265c76f24c7cceb5" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1c1b30e4f497b0b354057f3467f56244c603a79c0d1dafce1d16c283c25f6e64" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp311-cp311-win32.whl", hash = "sha256:5f451484aeb5cafee1ccf789b1b66f535409d038c56966d6101740c1614b86c6" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp311-cp311-win_amd64.whl", hash = "sha256:8d7f0659570eefb578dacde98e24fb60af35350193e4f56e11190787bee77dac" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:71c989cbf3254fbd5e84d3bff31e4da39c43f884e64f2551d14bb3c186230f00" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8b6e209ffee39ff1b6d0fa7bfef6de950c60dfb91b8fcead17da4ee539121a79" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:86890e837d61574c92a97496d590968b23c2ef0aeb8a9bc9421d174cd378ae39" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9b5aca38b67492ef518a8ab76851862488a478602229112c4b0d58d63a7a4d5c" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e0334872c0a37b606418ac52f6ab9cfd17317ac26365f7f65e203e2d0d0d359f" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a0b31e0b424cc6b5a04b8838bbaec1688834b2383256688cf47eb97412531da1" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:485c49116d0af10ac698623c513c1cc01c9446c058a4e61e3bf6c19dff7335a2" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp312-cp312-win32.whl", hash = "sha256:eaded469f5e5b7294e2bdca0ab06becb6756ea86894a47806456089298813c89" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp312-cp312-win_amd64.whl", hash = "sha256:5569417dc80977fc8c2d43a86f78e0a5a22fee17565d78621b6bb264a115d4ea" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:878b336ac47938b474c8f982ac2f7266a540adc3fa4ad74ae96fea9823a02cc9" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:52a0fec0e6c8d9a784c2c78276a48a2bdf099e4ccc2a4cad53b27718dbfd0230" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e6578ed5b6981005df1860a56e3617f14a6c307e6a71b4fff8c48fdc50f3ed2c" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:95724e638f0f9c350bb1c2b0a7ad0e83d9cc0c9259f3ea94e40d7b02a2179ae5" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c0204dc62a89dc9d50d682412c10b3542d748260d743500a85c13cd1ee4bde82" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:52ac480f44d32970d66763115edea932f1c5b1312de36df06d6b219f6741eed8" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6e5a82b677f8f6f59e8dfc34ec06ca6b5b48bc4fcda346acd093694cc2c24d8f" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp313-cp313-win32.whl", hash = "sha256:abf050a199613f64c886ea10f38b47770a65154dc37181bfaff70c160f45315a" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp313-cp313-win_amd64.whl", hash = "sha256:3425ac5cf448801335d6fdc7ae1eb22072055417a96cc6b31b3861f455fbc156" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8cc451a50f2aee53042ac52d2d053d08bf89bcb31ae799cb4487587661c038a0" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:daa3b6ff70a9241cf6c7fc9e949d41232d9d7d26fd3522b1ad2b4d62487e9904" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:fd3cb4adb94a2a6e2b7c0d8d05cb94e6f1c81a0cf9dc2694fb65c7e8d94c42e4" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:781caf5e8eee67f663126490c2f96f40906594cb86b408a703630f95550a8c3e" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:caab51a72c51973ca21fa8a18bd8165e1a0183f1ac7066a182ff27107b71e1a4" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:19c4dc84098e523fd63711e563077d39e90ec6702aff4b5d9e344a60cb3c0cb1" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:a5e18a238a2b2249c9a9235466b90e96ae4795672598a58772dd806edc7ac6d3" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp314-cp314-win32.whl", hash = "sha256:a069d734c4a043182729edd3e9f247c3b2a4035415a9172fd0f1b71658a320a8" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp314-cp314-win_amd64.whl", hash = "sha256:c0ee0e63f23914732c6d7e0cce24915c48f3f1512ec1d079ed01fc629dab269d" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:a35539cacc3febb22b8f4d4a99cc79b104226a756aa7400adc722e83b0d03244" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:b784ca5de850f4ce93ec85d3269d24d4c82f22b7212023c974c401d4980ebc5e" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:569d01a4e7fba956c5ae4fc988f0d4e187900f5497ce46339c996dbf24f17641" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:50f23cdd8343b984957e4077839841146f67a3d31ab0d00e6b824e74c5b2f6e8" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:152284a83a00c59b759697b7f9e9cddf4e3c7861dd0d964b472b70f78f89e80e" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:bc59589ab64b0022385f429b94697348a6a234e8ce22544e3681b2e9331b5944" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:32da954ffa2814258030e5a57bc73a3635463238e797c7375dc8091327434206" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp314-cp314t-win32.whl", hash = "sha256:5a4b4cc550cb665dd8a47f868c8d04c8230f857363ad3c9caf7a0c3bf8c61ca6" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-cp314-cp314t-win_amd64.whl", hash = "sha256:b14dc141ed6d2dde437cddb216004bcac6a1df0935d79656387bd41632ba0bbd" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:349f83cd6c9a415428ee1005cadb5c2c56f4389bc06a9af16103c3bc3dcc8b7d" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:4a1aba3340a8dca8db6eb5a7986157f52eb9e436b74813764241981ca4888f03" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-pp311-pypy311_pp73-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f4a32d1bd841d4bcbffdcb3d2ce50c09c3909fbead375ab28d0181af89fd04da" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0298d07ee155e2e9fda5be8a9042200dd2e3bb0b8a38482156576f863a9d457c" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:a653aea902e0324b52f1613332ddf50b00c06fdaf7e92624fbf8c77c78fa5767" }, - { url = "https://bytedpypi.byted.org/packages/websockets/websockets-16.0-py3-none-any.whl", hash = "sha256:1637db62fad1dc833276dded54215f2c7fa46912301a24bd94d45d46a011ceec" }, -] - -[[package]] -name = "win32-setctime" -version = "1.2.0" -source = { registry = "https://bytedpypi.byted.org/simple/" } -sdist = { url = "https://bytedpypi.byted.org/packages/win32-setctime/win32_setctime-1.2.0.tar.gz", hash = "sha256:ae1fdf948f5640aae05c511ade119313fb6a30d7eabe25fef9764dca5873c4c0" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/win32-setctime/win32_setctime-1.2.0-py3-none-any.whl", hash = "sha256:95d644c4e708aba81dc3704a116d8cbc974d70b3bdb8be1d150e36be6e9d1390" }, -] - -[[package]] -name = "yarl" -version = "1.22.0" -source = { registry = "https://bytedpypi.byted.org/simple/" } -dependencies = [ - { name = "idna" }, - { name = "multidict" }, - { name = "propcache" }, -] -sdist = { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0.tar.gz", hash = "sha256:bebf8557577d4401ba8bd9ff33906f1376c877aa78d1fe216ad01b4d6745af71" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1ab72135b1f2db3fed3997d7e7dc1b80573c67138023852b6efb336a5eae6511" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:669930400e375570189492dc8d8341301578e8493aec04aebc20d4717f899dd6" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:792a2af6d58177ef7c19cbf0097aba92ca1b9cb3ffdd9c7470e156c8f9b5e028" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3ea66b1c11c9150f1372f69afb6b8116f2dd7286f38e14ea71a44eee9ec51b9d" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3e2daa88dc91870215961e96a039ec73e4937da13cf77ce17f9cad0c18df3503" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ba440ae430c00eee41509353628600212112cd5018d5def7e9b05ea7ac34eb65" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e6438cc8f23a9c1478633d216b16104a586b9761db62bfacb6425bac0a36679e" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c52a6e78aef5cf47a98ef8e934755abf53953379b7d53e68b15ff4420e6683d" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3b06bcadaac49c70f4c88af4ffcfbe3dc155aab3163e75777818092478bcbbe7" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:6944b2dc72c4d7f7052683487e3677456050ff77fcf5e6204e98caf785ad1967" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:d5372ca1df0f91a86b047d1277c2aaf1edb32d78bbcefffc81b40ffd18f027ed" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:51af598701f5299012b8416486b40fceef8c26fc87dc6d7d1f6fc30609ea0aa6" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b266bd01fedeffeeac01a79ae181719ff848a5a13ce10075adbefc8f1daee70e" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp311-cp311-win32.whl", hash = "sha256:a9b1ba5610a4e20f655258d5a1fdc7ebe3d837bb0e45b581398b99eb98b1f5ca" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp311-cp311-win_amd64.whl", hash = "sha256:078278b9b0b11568937d9509b589ee83ef98ed6d561dfe2020e24a9fd08eaa2b" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp311-cp311-win_arm64.whl", hash = "sha256:b6a6f620cfe13ccec221fa312139135166e47ae169f8253f72a0abc0dae94376" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e340382d1afa5d32b892b3ff062436d592ec3d692aeea3bef3a5cfe11bbf8c6f" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f1e09112a2c31ffe8d80be1b0988fa6a18c5d5cad92a9ffbb1c04c91bfe52ad2" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:939fe60db294c786f6b7c2d2e121576628468f65453d86b0fe36cb52f987bd74" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e1651bf8e0398574646744c1885a41198eba53dc8a9312b954073f845c90a8df" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b8a0588521a26bf92a57a1705b77b8b59044cdceccac7151bd8d229e66b8dedb" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:42188e6a615c1a75bcaa6e150c3fe8f3e8680471a6b10150c5f7e83f47cc34d2" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f6d2cb59377d99718913ad9a151030d6f83ef420a2b8f521d94609ecc106ee82" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50678a3b71c751d58d7908edc96d332af328839eea883bb554a43f539101277a" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e8fbaa7cec507aa24ea27a01456e8dd4b6fab829059b69844bd348f2d467124" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:433885ab5431bc3d3d4f2f9bd15bfa1614c522b0f1405d62c4f926ccd69d04fa" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:b790b39c7e9a4192dc2e201a282109ed2985a1ddbd5ac08dc56d0e121400a8f7" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:31f0b53913220599446872d757257be5898019c85e7971599065bc55065dc99d" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a49370e8f711daec68d09b821a34e1167792ee2d24d405cbc2387be4f158b520" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp312-cp312-win32.whl", hash = "sha256:70dfd4f241c04bd9239d53b17f11e6ab672b9f1420364af63e8531198e3f5fe8" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp312-cp312-win_amd64.whl", hash = "sha256:8884d8b332a5e9b88e23f60bb166890009429391864c685e17bd73a9eda9105c" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp312-cp312-win_arm64.whl", hash = "sha256:ea70f61a47f3cc93bdf8b2f368ed359ef02a01ca6393916bc8ff877427181e74" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8dee9c25c74997f6a750cd317b8ca63545169c098faee42c84aa5e506c819b53" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:01e73b85a5434f89fc4fe27dcda2aff08ddf35e4d47bbbea3bdcd25321af538a" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:22965c2af250d20c873cdbee8ff958fb809940aeb2e74ba5f20aaf6b7ac8c70c" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b4f15793aa49793ec8d1c708ab7f9eded1aa72edc5174cae703651555ed1b601" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e5542339dcf2747135c5c85f68680353d5cb9ffd741c0f2e8d832d054d41f35a" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5c401e05ad47a75869c3ab3e35137f8468b846770587e70d71e11de797d113df" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:243dda95d901c733f5b59214d28b0120893d91777cb8aa043e6ef059d3cddfe2" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bec03d0d388060058f5d291a813f21c011041938a441c593374da6077fe21b1b" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b0748275abb8c1e1e09301ee3cf90c8a99678a4e92e4373705f2a2570d581273" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:47fdb18187e2a4e18fda2c25c05d8251a9e4a521edaed757fef033e7d8498d9a" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c7044802eec4524fde550afc28edda0dd5784c4c45f0be151a2d3ba017daca7d" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:139718f35149ff544caba20fce6e8a2f71f1e39b92c700d8438a0b1d2a631a02" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e1b51bebd221006d3d2f95fbe124b22b247136647ae5dcc8c7acafba66e5ee67" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313-win32.whl", hash = "sha256:d3e32536234a95f513bd374e93d717cf6b2231a791758de6c509e3653f234c95" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313-win_amd64.whl", hash = "sha256:47743b82b76d89a1d20b83e60d5c20314cbd5ba2befc9cda8f28300c4a08ed4d" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313-win_arm64.whl", hash = "sha256:5d0fcda9608875f7d052eff120c7a5da474a6796fe4d83e152e0e4d42f6d1a9b" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:719ae08b6972befcba4310e49edb1161a88cdd331e3a694b84466bd938a6ab10" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:47d8a5c446df1c4db9d21b49619ffdba90e77c89ec6e283f453856c74b50b9e3" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:cfebc0ac8333520d2d0423cbbe43ae43c8838862ddb898f5ca68565e395516e9" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4398557cbf484207df000309235979c79c4356518fd5c99158c7d38203c4da4f" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2ca6fd72a8cd803be290d42f2dec5cdcd5299eeb93c2d929bf060ad9efaf5de0" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ca1f59c4e1ab6e72f0a23c13fca5430f889634166be85dbf1013683e49e3278e" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6c5010a52015e7c70f86eb967db0f37f3c8bd503a695a49f8d45700144667708" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d7672ecf7557476642c88497c2f8d8542f8e36596e928e9bcba0e42e1e7d71f" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:3b7c88eeef021579d600e50363e0b6ee4f7f6f728cd3486b9d0f3ee7b946398d" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f4afb5c34f2c6fecdcc182dfcfc6af6cccf1aa923eed4d6a12e9d96904e1a0d8" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:59c189e3e99a59cf8d83cbb31d4db02d66cda5a1a4374e8a012b51255341abf5" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:5a3bf7f62a289fa90f1990422dc8dff5a458469ea71d1624585ec3a4c8d6960f" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:de6b9a04c606978fdfe72666fa216ffcf2d1a9f6a381058d4378f8d7b1e5de62" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313t-win32.whl", hash = "sha256:1834bb90991cc2999f10f97f5f01317f99b143284766d197e43cd5b45eb18d03" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ff86011bd159a9d2dfc89c34cfd8aff12875980e3bd6a39ff097887520e60249" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp313-cp313t-win_arm64.whl", hash = "sha256:7861058d0582b847bc4e3a4a4c46828a410bca738673f35a29ba3ca5db0b473b" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:34b36c2c57124530884d89d50ed2c1478697ad7473efd59cfd479945c95650e4" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:0dd9a702591ca2e543631c2a017e4a547e38a5c0f29eece37d9097e04a7ac683" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:594fcab1032e2d2cc3321bb2e51271e7cd2b516c7d9aee780ece81b07ff8244b" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f3d7a87a78d46a2e3d5b72587ac14b4c16952dd0887dbb051451eceac774411e" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:852863707010316c973162e703bddabec35e8757e67fcb8ad58829de1ebc8590" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:131a085a53bfe839a477c0845acf21efc77457ba2bcf5899618136d64f3303a2" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:078a8aefd263f4d4f923a9677b942b445a2be970ca24548a8102689a3a8ab8da" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bca03b91c323036913993ff5c738d0842fc9c60c4648e5c8d98331526df89784" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:68986a61557d37bb90d3051a45b91fa3d5c516d177dfc6dd6f2f436a07ff2b6b" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:4792b262d585ff0dff6bcb787f8492e40698443ec982a3568c2096433660c694" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:ebd4549b108d732dba1d4ace67614b9545b21ece30937a63a65dd34efa19732d" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:f87ac53513d22240c7d59203f25cc3beac1e574c6cd681bbfd321987b69f95fd" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:22b029f2881599e2f1b06f8f1db2ee63bd309e2293ba2d566e008ba12778b8da" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314-win32.whl", hash = "sha256:6a635ea45ba4ea8238463b4f7d0e721bad669f80878b7bfd1f89266e2ae63da2" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314-win_amd64.whl", hash = "sha256:0d6e6885777af0f110b0e5d7e5dda8b704efed3894da26220b7f3d887b839a79" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314-win_arm64.whl", hash = "sha256:8218f4e98d3c10d683584cb40f0424f4b9fd6e95610232dd75e13743b070ee33" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:45c2842ff0e0d1b35a6bf1cd6c690939dacb617a70827f715232b2e0494d55d1" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:d947071e6ebcf2e2bee8fce76e10faca8f7a14808ca36a910263acaacef08eca" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:334b8721303e61b00019474cc103bdac3d7b1f65e91f0bfedeec2d56dfe74b53" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e7ce67c34138a058fd092f67d07a72b8e31ff0c9236e751957465a24b28910c" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d77e1b2c6d04711478cb1c4ab90db07f1609ccf06a287d5607fcd90dc9863acf" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4647674b6150d2cae088fc07de2738a84b8bcedebef29802cf0b0a82ab6face" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:efb07073be061c8f79d03d04139a80ba33cbd390ca8f0297aae9cce6411e4c6b" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e51ac5435758ba97ad69617e13233da53908beccc6cfcd6c34bbed8dcbede486" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:33e32a0dd0c8205efa8e83d04fc9f19313772b78522d1bdc7d9aed706bfd6138" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:bf4a21e58b9cde0e401e683ebd00f6ed30a06d14e93f7c8fd059f8b6e8f87b6a" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:e4b582bab49ac33c8deb97e058cd67c2c50dac0dd134874106d9c774fd272529" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:0b5bcc1a9c4839e7e30b7b30dd47fe5e7e44fb7054ec29b5bb8d526aa1041093" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c0232bce2170103ec23c454e54a57008a9a72b5d1c3105dc2496750da8cfa47c" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314t-win32.whl", hash = "sha256:8009b3173bcd637be650922ac455946197d858b3630b6d8787aa9e5c4564533e" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314t-win_amd64.whl", hash = "sha256:9fb17ea16e972c63d25d4a97f016d235c78dd2344820eb35bc034bc32012ee27" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-cp314-cp314t-win_arm64.whl", hash = "sha256:9f6d73c1436b934e3f01df1e1b21ff765cd1d28c77dfb9ace207f746d4610ee1" }, - { url = "https://bytedpypi.byted.org/packages/yarl/yarl-1.22.0-py3-none-any.whl", hash = "sha256:1380560bdba02b6b6c90de54133c81c9f2a453dee9912fe58c1dcced1edb7cff" }, -] - -[[package]] -name = "zipp" -version = "3.23.0" -source = { registry = "https://bytedpypi.byted.org/simple/" } -sdist = { url = "https://bytedpypi.byted.org/packages/zipp/zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166" } -wheels = [ - { url = "https://bytedpypi.byted.org/packages/zipp/zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e" }, -] From 10e9e0cdc9ecc75fd360830abcc3c9f8ccfc20e5 Mon Sep 17 00:00:00 2001 From: The Mavik <179817126+themavik@users.noreply.github.com> Date: Fri, 13 Feb 2026 17:08:10 -0500 Subject: [PATCH 18/60] fix(providers): clamp max_tokens to >= 1 before calling LiteLLM (#523) --- nanobot/providers/litellm_provider.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/nanobot/providers/litellm_provider.py b/nanobot/providers/litellm_provider.py index 7865139..a39893b 100644 --- a/nanobot/providers/litellm_provider.py +++ b/nanobot/providers/litellm_provider.py @@ -122,6 +122,10 @@ class LiteLLMProvider(LLMProvider): """ model = self._resolve_model(model or self.default_model) + # Clamp max_tokens to at least 1 — negative or zero values cause + # LiteLLM to reject the request with "max_tokens must be at least 1". + max_tokens = max(1, max_tokens) + kwargs: dict[str, Any] = { "model": model, "messages": messages, From 153c83e340c518209cfe879f296dc99f742ad778 Mon Sep 17 00:00:00 2001 From: Ahwei Date: Sat, 14 Feb 2026 10:23:54 +0800 Subject: [PATCH 19/60] fix(cron): add timezone support for accurate next run time calculation When schedule.tz is present, use the specified timezone to calculate the next execution time, ensuring scheduled tasks trigger correctly across different timezones. --- nanobot/cron/service.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/nanobot/cron/service.py b/nanobot/cron/service.py index d1965a9..6fea4de 100644 --- a/nanobot/cron/service.py +++ b/nanobot/cron/service.py @@ -4,6 +4,7 @@ import asyncio import json import time import uuid +from datetime import datetime from pathlib import Path from typing import Any, Callable, Coroutine @@ -30,9 +31,18 @@ def _compute_next_run(schedule: CronSchedule, now_ms: int) -> int | None: if schedule.kind == "cron" and schedule.expr: try: from croniter import croniter - cron = croniter(schedule.expr, time.time()) - next_time = cron.get_next() - return int(next_time * 1000) + from zoneinfo import ZoneInfo + base_time = time.time() + if schedule.tz: + tz = ZoneInfo(schedule.tz) + base_dt = datetime.fromtimestamp(base_time, tz=tz) + cron = croniter(schedule.expr, base_dt) + next_dt = cron.get_next(datetime) + return int(next_dt.timestamp() * 1000) + else: + cron = croniter(schedule.expr, base_time) + next_time = cron.get_next() + return int(next_time * 1000) except Exception: return None From d3f6c95cebaf17d04f0d04655a98c0e795777bb1 Mon Sep 17 00:00:00 2001 From: Ahwei Date: Sat, 14 Feb 2026 10:27:09 +0800 Subject: [PATCH 20/60] refactor(cron): simplify timezone logic and merge conditional branches With tz: Use the specified timezone (e.g., "Asia/Shanghai"). Without tz: Use the local timezone (datetime.now().astimezone().tzinfo) instead of defaulting to UTC --- nanobot/cron/service.py | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/nanobot/cron/service.py b/nanobot/cron/service.py index 6fea4de..4da845a 100644 --- a/nanobot/cron/service.py +++ b/nanobot/cron/service.py @@ -33,16 +33,11 @@ def _compute_next_run(schedule: CronSchedule, now_ms: int) -> int | None: from croniter import croniter from zoneinfo import ZoneInfo base_time = time.time() - if schedule.tz: - tz = ZoneInfo(schedule.tz) - base_dt = datetime.fromtimestamp(base_time, tz=tz) - cron = croniter(schedule.expr, base_dt) - next_dt = cron.get_next(datetime) - return int(next_dt.timestamp() * 1000) - else: - cron = croniter(schedule.expr, base_time) - next_time = cron.get_next() - return int(next_time * 1000) + tz = ZoneInfo(schedule.tz) if schedule.tz else datetime.now().astimezone().tzinfo + base_dt = datetime.fromtimestamp(base_time, tz=tz) + cron = croniter(schedule.expr, base_dt) + next_dt = cron.get_next(datetime) + return int(next_dt.timestamp() * 1000) except Exception: return None From 4e4eb21d23bbeef284438e252e9a88acef973f50 Mon Sep 17 00:00:00 2001 From: Ahwei Date: Sat, 14 Feb 2026 12:14:31 +0800 Subject: [PATCH 21/60] feat(feishu): Add rich text message content extraction feature Newly added the _extract_post_text function to extract plain text content from Feishu rich text messages, supporting the parsing of titles, text, links, and @mentions. --- nanobot/channels/feishu.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/nanobot/channels/feishu.py b/nanobot/channels/feishu.py index 9017b40..5d6c33b 100644 --- a/nanobot/channels/feishu.py +++ b/nanobot/channels/feishu.py @@ -39,6 +39,35 @@ MSG_TYPE_MAP = { } +def _extract_post_text(content_json: dict) -> str: + """Extract plain text from Feishu post (rich text) message content.""" + for lang_key in ("zh_cn", "en_us", "ja_jp"): + lang_content = content_json.get(lang_key) + if not isinstance(lang_content, dict): + continue + title = lang_content.get("title", "") + content_blocks = lang_content.get("content", []) + if not isinstance(content_blocks, list): + continue + text_parts = [] + if title: + text_parts.append(title) + for block in content_blocks: + if not isinstance(block, list): + continue + for element in block: + if isinstance(element, dict): + tag = element.get("tag") + if tag == "text": + text_parts.append(element.get("text", "")) + elif tag == "a": + text_parts.append(element.get("text", "")) + elif tag == "at": + text_parts.append(f"@{element.get('user_name', 'user')}") + return " ".join(text_parts).strip() + return "" + + class FeishuChannel(BaseChannel): """ Feishu/Lark channel using WebSocket long connection. @@ -326,6 +355,12 @@ class FeishuChannel(BaseChannel): content = json.loads(message.content).get("text", "") except json.JSONDecodeError: content = message.content or "" + elif msg_type == "post": + try: + content_json = json.loads(message.content) + content = _extract_post_text(content_json) + except (json.JSONDecodeError, TypeError): + content = message.content or "" else: content = MSG_TYPE_MAP.get(msg_type, f"[{msg_type}]") From 5e082690d8bee4ca6f2bfe6881fc5a0579262dd5 Mon Sep 17 00:00:00 2001 From: Ahwei Date: Sat, 14 Feb 2026 14:37:23 +0800 Subject: [PATCH 22/60] refactor(feishu): support both direct and localized post content formats --- nanobot/channels/feishu.py | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/nanobot/channels/feishu.py b/nanobot/channels/feishu.py index 5d6c33b..bc4a2b8 100644 --- a/nanobot/channels/feishu.py +++ b/nanobot/channels/feishu.py @@ -40,15 +40,19 @@ MSG_TYPE_MAP = { def _extract_post_text(content_json: dict) -> str: - """Extract plain text from Feishu post (rich text) message content.""" - for lang_key in ("zh_cn", "en_us", "ja_jp"): - lang_content = content_json.get(lang_key) + """Extract plain text from Feishu post (rich text) message content. + + Supports two formats: + 1. Direct format: {"title": "...", "content": [...]} + 2. Localized format: {"zh_cn": {"title": "...", "content": [...]}} + """ + def extract_from_lang(lang_content: dict) -> str | None: if not isinstance(lang_content, dict): - continue + return None title = lang_content.get("title", "") content_blocks = lang_content.get("content", []) if not isinstance(content_blocks, list): - continue + return None text_parts = [] if title: text_parts.append(title) @@ -64,7 +68,21 @@ def _extract_post_text(content_json: dict) -> str: text_parts.append(element.get("text", "")) elif tag == "at": text_parts.append(f"@{element.get('user_name', 'user')}") - return " ".join(text_parts).strip() + return " ".join(text_parts).strip() if text_parts else None + + # Try direct format first + if "content" in content_json: + result = extract_from_lang(content_json) + if result: + return result + + # Try localized format + for lang_key in ("zh_cn", "en_us", "ja_jp"): + lang_content = content_json.get(lang_key) + result = extract_from_lang(lang_content) + if result: + return result + return "" From e2ef1f9d4846246472d2c8454b40d4dbf239dd4c Mon Sep 17 00:00:00 2001 From: Re-bin Date: Sun, 15 Feb 2026 06:02:45 +0000 Subject: [PATCH 23/60] docs: add custom provider guideline --- README.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/README.md b/README.md index e73beb5..47702c1 100644 --- a/README.md +++ b/README.md @@ -599,6 +599,7 @@ Config file: `~/.nanobot/config.json` | Provider | Purpose | Get API Key | |----------|---------|-------------| +| `custom` | Any OpenAI-compatible endpoint | — | | `openrouter` | LLM (recommended, access to all models) | [openrouter.ai](https://openrouter.ai) | | `anthropic` | LLM (Claude direct) | [console.anthropic.com](https://console.anthropic.com) | | `openai` | LLM (GPT direct) | [platform.openai.com](https://platform.openai.com) | @@ -612,6 +613,31 @@ Config file: `~/.nanobot/config.json` | `zhipu` | LLM (Zhipu GLM) | [open.bigmodel.cn](https://open.bigmodel.cn) | | `vllm` | LLM (local, any OpenAI-compatible server) | — | +
+Custom Provider (Any OpenAI-compatible API) + +If your provider is not listed above but exposes an **OpenAI-compatible API** (e.g. Together AI, Fireworks, Azure OpenAI, self-hosted endpoints), use the `custom` provider: + +```json +{ + "providers": { + "custom": { + "apiKey": "your-api-key", + "apiBase": "https://api.your-provider.com/v1" + } + }, + "agents": { + "defaults": { + "model": "your-model-name" + } + } +} +``` + +> The `custom` provider routes through LiteLLM's OpenAI-compatible path. It works with any endpoint that follows the OpenAI chat completions API format. The model name is passed directly to the endpoint without any prefix. + +
+
Adding a New Provider (Developer Guide) From 52cf1da30a408ac4ec91fac5e9249a72f01ee1d2 Mon Sep 17 00:00:00 2001 From: Re-bin Date: Sun, 15 Feb 2026 07:00:27 +0000 Subject: [PATCH 24/60] fix: store original MCP tool name, make close_mcp public --- README.md | 36 +++++++++++++++++++++++++++++++++++- nanobot/agent/loop.py | 2 +- nanobot/agent/tools/mcp.py | 6 ++---- nanobot/cli/commands.py | 6 +++--- 4 files changed, 41 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 47702c1..c08d3af 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ ⚡️ Delivers core agent functionality in just **~4,000** lines of code — **99% smaller** than Clawdbot's 430k+ lines. -📏 Real-time line count: **3,536 lines** (run `bash core_agent_lines.sh` to verify anytime) +📏 Real-time line count: **3,656 lines** (run `bash core_agent_lines.sh` to verify anytime) ## 📢 News @@ -683,6 +683,40 @@ That's it! Environment variables, model prefixing, config matching, and `nanobot
+### MCP (Model Context Protocol) + +> [!TIP] +> The config format is compatible with Claude Desktop / Cursor. You can copy MCP server configs directly from any MCP server's README. + +nanobot supports [MCP](https://modelcontextprotocol.io/) — connect external tool servers and use them as native agent tools. + +Add MCP servers to your `config.json`: + +```json +{ + "tools": { + "mcpServers": { + "filesystem": { + "command": "npx", + "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/dir"] + } + } + } +} +``` + +Two transport modes are supported: + +| Mode | Config | Example | +|------|--------|---------| +| **Stdio** | `command` + `args` | Local process via `npx` / `uvx` | +| **HTTP** | `url` | Remote endpoint (`https://mcp.example.com/sse`) | + +MCP tools are automatically discovered and registered on startup. The LLM can use them alongside built-in tools — no extra configuration needed. + + + + ### Security > For production deployments, set `"restrictToWorkspace": true` in your config to sandbox the agent. diff --git a/nanobot/agent/loop.py b/nanobot/agent/loop.py index cc7a0d0..7deef59 100644 --- a/nanobot/agent/loop.py +++ b/nanobot/agent/loop.py @@ -229,7 +229,7 @@ class AgentLoop: except asyncio.TimeoutError: continue - async def _close_mcp(self) -> None: + async def close_mcp(self) -> None: """Close MCP connections.""" if self._mcp_stack: try: diff --git a/nanobot/agent/tools/mcp.py b/nanobot/agent/tools/mcp.py index bcef4aa..1c8eac4 100644 --- a/nanobot/agent/tools/mcp.py +++ b/nanobot/agent/tools/mcp.py @@ -14,7 +14,7 @@ class MCPToolWrapper(Tool): def __init__(self, session, server_name: str, tool_def): self._session = session - self._server = server_name + self._original_name = tool_def.name self._name = f"mcp_{server_name}_{tool_def.name}" self._description = tool_def.description or tool_def.name self._parameters = tool_def.inputSchema or {"type": "object", "properties": {}} @@ -33,9 +33,7 @@ class MCPToolWrapper(Tool): async def execute(self, **kwargs: Any) -> str: from mcp import types - result = await self._session.call_tool( - self._name.removeprefix(f"mcp_{self._server}_"), arguments=kwargs - ) + result = await self._session.call_tool(self._original_name, arguments=kwargs) parts = [] for block in result.content: if isinstance(block, types.TextContent): diff --git a/nanobot/cli/commands.py b/nanobot/cli/commands.py index 34bfde8..6a9c92f 100644 --- a/nanobot/cli/commands.py +++ b/nanobot/cli/commands.py @@ -405,7 +405,7 @@ def gateway( except KeyboardInterrupt: console.print("\nShutting down...") finally: - await agent._close_mcp() + await agent.close_mcp() heartbeat.stop() cron.stop() agent.stop() @@ -473,7 +473,7 @@ def agent( with _thinking_ctx(): response = await agent_loop.process_direct(message, session_id) _print_agent_response(response, render_markdown=markdown) - await agent_loop._close_mcp() + await agent_loop.close_mcp() asyncio.run(run_once()) else: @@ -515,7 +515,7 @@ def agent( console.print("\nGoodbye!") break finally: - await agent_loop._close_mcp() + await agent_loop.close_mcp() asyncio.run(run_interactive()) From 49fec3684ad100e44203ded5fa2a3c2113d0094b Mon Sep 17 00:00:00 2001 From: Re-bin Date: Sun, 15 Feb 2026 08:11:33 +0000 Subject: [PATCH 25/60] fix: use json_repair for robust LLM response parsing --- README.md | 2 +- nanobot/agent/loop.py | 9 ++++++++- nanobot/providers/litellm_provider.py | 6 ++---- pyproject.toml | 1 + 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index c08d3af..9066d5a 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ ⚡️ Delivers core agent functionality in just **~4,000** lines of code — **99% smaller** than Clawdbot's 430k+ lines. -📏 Real-time line count: **3,656 lines** (run `bash core_agent_lines.sh` to verify anytime) +📏 Real-time line count: **3,663 lines** (run `bash core_agent_lines.sh` to verify anytime) ## 📢 News diff --git a/nanobot/agent/loop.py b/nanobot/agent/loop.py index 7deef59..6342f56 100644 --- a/nanobot/agent/loop.py +++ b/nanobot/agent/loop.py @@ -3,6 +3,7 @@ import asyncio from contextlib import AsyncExitStack import json +import json_repair from pathlib import Path from typing import Any @@ -420,9 +421,15 @@ Respond with ONLY valid JSON, no markdown fences.""" model=self.model, ) text = (response.content or "").strip() + if not text: + logger.warning("Memory consolidation: LLM returned empty response, skipping") + return if text.startswith("```"): text = text.split("\n", 1)[-1].rsplit("```", 1)[0].strip() - result = json.loads(text) + result = json_repair.loads(text) + if not isinstance(result, dict): + logger.warning(f"Memory consolidation: unexpected response type, skipping. Response: {text[:200]}") + return if entry := result.get("history_entry"): memory.append_history(entry) diff --git a/nanobot/providers/litellm_provider.py b/nanobot/providers/litellm_provider.py index a39893b..ed4cf49 100644 --- a/nanobot/providers/litellm_provider.py +++ b/nanobot/providers/litellm_provider.py @@ -1,6 +1,7 @@ """LiteLLM provider implementation for multi-provider support.""" import json +import json_repair import os from typing import Any @@ -173,10 +174,7 @@ class LiteLLMProvider(LLMProvider): # Parse arguments from JSON string if needed args = tc.function.arguments if isinstance(args, str): - try: - args = json.loads(args) - except json.JSONDecodeError: - args = {"raw": args} + args = json_repair.loads(args) tool_calls.append(ToolCallRequest( id=tc.id, diff --git a/pyproject.toml b/pyproject.toml index 17c739f..147e799 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,6 +39,7 @@ dependencies = [ "python-socks[asyncio]>=2.4.0", "prompt-toolkit>=3.0.0", "mcp>=1.0.0", + "json-repair>=0.30.0", ] [project.optional-dependencies] From 82074a7715cd7e3b8c4810f861401926b64139cf Mon Sep 17 00:00:00 2001 From: Re-bin Date: Sun, 15 Feb 2026 14:03:51 +0000 Subject: [PATCH 26/60] docs: update news section --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 9066d5a..e75f080 100644 --- a/README.md +++ b/README.md @@ -20,8 +20,10 @@ ## 📢 News +- **2026-02-14** 🔌 nanobot now supports MCP! See [MCP section](#mcp-model-context-protocol) for details. - **2026-02-13** 🎉 Released v0.1.3.post7 — includes security hardening and multiple improvements. All users are recommended to upgrade to the latest version. See [release notes](https://github.com/HKUDS/nanobot/releases/tag/v0.1.3.post7) for more details. - **2026-02-12** 🧠 Redesigned memory system — Less code, more reliable. Join the [discussion](https://github.com/HKUDS/nanobot/discussions/566) about it! +- **2026-02-11** ✨ Enhanced CLI experience and added MiniMax support! - **2026-02-10** 🎉 Released v0.1.3.post6 with improvements! Check the updates [notes](https://github.com/HKUDS/nanobot/releases/tag/v0.1.3.post6) and our [roadmap](https://github.com/HKUDS/nanobot/discussions/431). - **2026-02-09** 💬 Added Slack, Email, and QQ support — nanobot now supports multiple chat platforms! - **2026-02-08** 🔧 Refactored Providers—adding a new LLM provider now takes just 2 simple steps! Check [here](#providers). From 7e2d801ffc5071d68b07a30c06d8a3f97ce58e62 Mon Sep 17 00:00:00 2001 From: "Aleksander W. Oleszkiewicz (Alek)" <24917047+alekwo@users.noreply.github.com> Date: Sun, 15 Feb 2026 15:51:19 +0100 Subject: [PATCH 27/60] Implement markdown conversion for Slack messages Add markdown conversion for Slack messages including italics, bold, and table formatting. --- nanobot/channels/slack.py | 114 +++++++++++++++++++++++++++++++++++++- 1 file changed, 113 insertions(+), 1 deletion(-) diff --git a/nanobot/channels/slack.py b/nanobot/channels/slack.py index be95dd2..7298435 100644 --- a/nanobot/channels/slack.py +++ b/nanobot/channels/slack.py @@ -84,7 +84,7 @@ class SlackChannel(BaseChannel): use_thread = thread_ts and channel_type != "im" await self._web_client.chat_postMessage( channel=msg.chat_id, - text=msg.content or "", + text=self._convert_markdown(msg.content) or "", thread_ts=thread_ts if use_thread else None, ) except Exception as e: @@ -203,3 +203,115 @@ class SlackChannel(BaseChannel): if not text or not self._bot_user_id: return text return re.sub(rf"<@{re.escape(self._bot_user_id)}>\s*", "", text).strip() + + def _convert_markdown(self, text: str) -> str: + if not text: + return text + def convert_formatting(input: str) -> str: + # Convert italics + # Step 1: *text* -> _text_ + converted_text = re.sub( + r"(?m)(^|[^\*])\*([^\*].+?[^\*])\*([^\*]|$)", r"\1_\2_\3", input) + # Convert bold + # Step 2.a: **text** -> *text* + converted_text = re.sub( + r"(?m)(^|[^\*])\*\*([^\*].+?[^\*])\*\*([^\*]|$)", r"\1*\2*\3", converted_text) + # Step 2.b: __text__ -> *text* + converted_text = re.sub( + r"(?m)(^|[^_])__([^_].+?[^_])__([^_]|$)", r"\1*\2*\3", converted_text) + # convert bold italics + # Step 3.a: ***text*** -> *_text_* + converted_text = re.sub( + r"(?m)(^|[^\*])\*\*\*([^\*].+?[^\*])\*\*\*([^\*]|$)", r"\1*_\2_*\3", converted_text) + # Step 3.b - ___text___ to *_text_* + converted_text = re.sub( + r"(?m)(^|[^_])___([^_].+?[^_])___([^_]|$)", r"\1*_\2_*\3", converted_text) + return converted_text + def escape_mrkdwn(text: str) -> str: + return (text.replace('&', '&') + .replace('<', '<') + .replace('>', '>')) + def convert_table(match: re.Match) -> str: + # Slack doesn't support Markdown tables + # Convert table to bulleted list with sections + # -- input_md: + # Some text before the table. + # | Col1 | Col2 | Col3 | + # |-----|----------|------| + # | Row1 - A | Row1 - B | Row1 - C | + # | Row2 - D | Row2 - E | Row2 - F | + # + # Some text after the table. + # + # -- will be converted to: + # Some text before the table. + # > *Col1* : Row1 - A + # • *Col2*: Row1 - B + # • *Col3*: Row1 - C + # > *Col1* : Row2 - D + # • *Col2*: Row2 - E + # • *Col3*: Row2 - F + # + # Some text after the table. + + block = match.group(0).strip() + lines = [line.strip() + for line in block.split('\n') if line.strip()] + + if len(lines) < 2: + return block + + # 1. Parse Headers from the first line + # Split by pipe, filtering out empty start/end strings caused by outer pipes + header_line = lines[0].strip('|') + headers = [escape_mrkdwn(h.strip()) + for h in header_line.split('|')] + + # 2. Identify Data Start (Skip Separator) + data_start_idx = 1 + # If line 2 contains only separator chars (|-: ), skip it + if len(lines) > 1 and not re.search(r'[^|\-\s:]', lines[1]): + data_start_idx = 2 + + # 3. Process Data Rows + slack_lines = [] + for line in lines[data_start_idx:]: + # Clean and split cells + clean_line = line.strip('|') + cells = [escape_mrkdwn(c.strip()) + for c in clean_line.split('|')] + + # Normalize cell count to match headers + if len(cells) < len(headers): + cells += [''] * (len(headers) - len(cells)) + cells = cells[:len(headers)] + + # Skip empty rows + if not any(cells): + continue + + # Key is the first column + key = cells[0] + label = headers[0] + slack_lines.append( + f"> *{label}* : {key}" if key else "> *{label}* : --") + + # Sub-bullets for remaining columns + for i, cell in enumerate(cells[1:], 1): + if cell: + label = headers[i] if i < len(headers) else "Col" + slack_lines.append(f" • *{label}*: {cell}") + + slack_lines.append("") # Spacer between items + + return "\n".join(slack_lines).rstrip() + + # (?m) : Multiline mode so ^ matches start of line and $ end of line + # ^\| : Start of line and a literal pipe + # .*?\|$ : Rest of the line and a pipe at the end + # (?:\n(?:\|\:?-{3,}\:?)*?\|$) : A heading line with at least three dashes in each column, pipes, and : e.g. |:---|----|:---:| + # (?:\n\|.*?\|$)* : Zero or more subsequent lines that ALSO start and end with a pipe + table_pattern = r'(?m)^\|.*?\|$(?:\n(?:\|\:?-{3,}\:?)*?\|$)(?:\n\|.*?\|$)*' + + input_md = convert_formatting(text) + return re.sub(table_pattern, convert_table, input_md) From a5265c263d1ea277dc3197e63364105be0503d79 Mon Sep 17 00:00:00 2001 From: Re-bin Date: Sun, 15 Feb 2026 16:41:27 +0000 Subject: [PATCH 28/60] docs: update readme structure --- README.md | 90 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 49 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index e75f080..c1b7e46 100644 --- a/README.md +++ b/README.md @@ -109,14 +109,22 @@ nanobot onboard **2. Configure** (`~/.nanobot/config.json`) -For OpenRouter - recommended for global users: +Add or merge these **two parts** into your config (other options have defaults). + +*Set your API key* (e.g. OpenRouter, recommended for global users): ```json { "providers": { "openrouter": { "apiKey": "sk-or-v1-xxx" } - }, + } +} +``` + +*Set your model*: +```json +{ "agents": { "defaults": { "model": "anthropic/claude-opus-4-5" @@ -128,48 +136,11 @@ For OpenRouter - recommended for global users: **3. Chat** ```bash -nanobot agent -m "What is 2+2?" +nanobot agent ``` That's it! You have a working AI assistant in 2 minutes. -## 🖥️ Local Models (vLLM) - -Run nanobot with your own local models using vLLM or any OpenAI-compatible server. - -**1. Start your vLLM server** - -```bash -vllm serve meta-llama/Llama-3.1-8B-Instruct --port 8000 -``` - -**2. Configure** (`~/.nanobot/config.json`) - -```json -{ - "providers": { - "vllm": { - "apiKey": "dummy", - "apiBase": "http://localhost:8000/v1" - } - }, - "agents": { - "defaults": { - "model": "meta-llama/Llama-3.1-8B-Instruct" - } - } -} -``` - -**3. Chat** - -```bash -nanobot agent -m "Hello from my local LLM!" -``` - -> [!TIP] -> The `apiKey` can be any non-empty string for local servers that don't require authentication. - ## 💬 Chat Apps Talk to your nanobot through Telegram, Discord, WhatsApp, Feishu, Mochat, DingTalk, Slack, Email, or QQ — anytime, anywhere. @@ -640,6 +611,43 @@ If your provider is not listed above but exposes an **OpenAI-compatible API** (e +
+vLLM (local / OpenAI-compatible) + +Run your own model with vLLM or any OpenAI-compatible server, then add to config: + +**1. Start the server** (example): +```bash +vllm serve meta-llama/Llama-3.1-8B-Instruct --port 8000 +``` + +**2. Add to config** (partial — merge into `~/.nanobot/config.json`): + +*Provider (key can be any non-empty string for local):* +```json +{ + "providers": { + "vllm": { + "apiKey": "dummy", + "apiBase": "http://localhost:8000/v1" + } + } +} +``` + +*Model:* +```json +{ + "agents": { + "defaults": { + "model": "meta-llama/Llama-3.1-8B-Instruct" + } + } +} +``` + +
+
Adding a New Provider (Developer Guide) @@ -721,6 +729,7 @@ MCP tools are automatically discovered and registered on startup. The LLM can us ### Security +> [!TIP] > For production deployments, set `"restrictToWorkspace": true` in your config to sandbox the agent. | Option | Default | Description | @@ -815,7 +824,6 @@ PRs welcome! The codebase is intentionally small and readable. 🤗 **Roadmap** — Pick an item and [open a PR](https://github.com/HKUDS/nanobot/pulls)! -- [x] **Voice Transcription** — Support for Groq Whisper (Issue #13) - [ ] **Multi-modal** — See and hear (images, voice, video) - [ ] **Long-term memory** — Never forget important context - [ ] **Better reasoning** — Multi-step planning and reflection From 203aa154d4c26b5c49a07923b74a5d928bb14300 Mon Sep 17 00:00:00 2001 From: zhouzhuojie Date: Sun, 15 Feb 2026 22:39:31 +0000 Subject: [PATCH 29/60] fix(telegram): split long messages to avoid Message is too long error Telegram has a 4096 character limit per message. This fix: - Splits messages longer than 4000 chars into multiple chunks - Prefers breaking at newline boundaries to preserve formatting - Falls back to space boundaries if no newlines available - Forces split at max length if no good boundaries exist - Adds comprehensive tests for message splitting logic --- .gitignore | 2 +- nanobot/channels/telegram.py | 57 +++-- tests/test_telegram_channel.py | 416 +++++++++++++++++++++++++++++++++ 3 files changed, 459 insertions(+), 16 deletions(-) create mode 100644 tests/test_telegram_channel.py diff --git a/.gitignore b/.gitignore index d7b930d..742d593 100644 --- a/.gitignore +++ b/.gitignore @@ -19,4 +19,4 @@ __pycache__/ poetry.lock .pytest_cache/ botpy.log -tests/ + diff --git a/nanobot/channels/telegram.py b/nanobot/channels/telegram.py index 32f8c67..a45178b 100644 --- a/nanobot/channels/telegram.py +++ b/nanobot/channels/telegram.py @@ -188,27 +188,54 @@ class TelegramChannel(BaseChannel): self._stop_typing(msg.chat_id) try: - # chat_id should be the Telegram chat ID (integer) chat_id = int(msg.chat_id) - # Convert markdown to Telegram HTML - html_content = _markdown_to_telegram_html(msg.content) - await self._app.bot.send_message( - chat_id=chat_id, - text=html_content, - parse_mode="HTML" - ) except ValueError: logger.error(f"Invalid chat_id: {msg.chat_id}") - except Exception as e: - # Fallback to plain text if HTML parsing fails - logger.warning(f"HTML parse failed, falling back to plain text: {e}") + return + + # Split content into chunks (Telegram limit: 4096 chars) + MAX_LENGTH = 4000 # Leave some margin for safety + content = msg.content + chunks = [] + + while content: + if len(content) <= MAX_LENGTH: + chunks.append(content) + break + + # Find a good break point (newline or space) + chunk = content[:MAX_LENGTH] + # Prefer breaking at newline + break_pos = chunk.rfind('\n') + if break_pos == -1: + # Fall back to last space + break_pos = chunk.rfind(' ') + if break_pos == -1: + # No good break point, force break at limit + break_pos = MAX_LENGTH + + chunks.append(content[:break_pos]) + content = content[break_pos:].lstrip() + + # Send each chunk + for i, chunk in enumerate(chunks): try: + html_content = _markdown_to_telegram_html(chunk) await self._app.bot.send_message( - chat_id=int(msg.chat_id), - text=msg.content + chat_id=chat_id, + text=html_content, + parse_mode="HTML" ) - except Exception as e2: - logger.error(f"Error sending Telegram message: {e2}") + except Exception as e: + # Fallback to plain text if HTML parsing fails + logger.warning(f"HTML parse failed for chunk {i+1}, falling back to plain text: {e}") + try: + await self._app.bot.send_message( + chat_id=chat_id, + text=chunk + ) + except Exception as e2: + logger.error(f"Error sending Telegram chunk {i+1}: {e2}") async def _on_start(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: """Handle /start command.""" diff --git a/tests/test_telegram_channel.py b/tests/test_telegram_channel.py new file mode 100644 index 0000000..8e9a4d4 --- /dev/null +++ b/tests/test_telegram_channel.py @@ -0,0 +1,416 @@ +"""Tests for Telegram channel implementation.""" + +import pytest +from unittest.mock import AsyncMock, MagicMock + +from nanobot.bus.events import OutboundMessage +from nanobot.bus.queue import MessageBus +from nanobot.channels.telegram import TelegramChannel, _markdown_to_telegram_html +from nanobot.config.schema import TelegramConfig + + +def _make_config() -> TelegramConfig: + return TelegramConfig( + enabled=True, + token="fake-token", + allow_from=[], + proxy=None, + ) + + +class TestMarkdownToTelegramHtml: + """Tests for markdown to Telegram HTML conversion.""" + + def test_empty_text(self) -> None: + assert _markdown_to_telegram_html("") == "" + + def test_plain_text_passthrough(self) -> None: + text = "Hello world" + assert _markdown_to_telegram_html(text) == "Hello world" + + def test_bold_double_asterisks(self) -> None: + text = "This is **bold** text" + assert _markdown_to_telegram_html(text) == "This is bold text" + + def test_bold_double_underscore(self) -> None: + text = "This is __bold__ text" + assert _markdown_to_telegram_html(text) == "This is bold text" + + def test_italic_underscore(self) -> None: + text = "This is _italic_ text" + assert _markdown_to_telegram_html(text) == "This is italic text" + + def test_italic_not_inside_words(self) -> None: + text = "some_var_name" + assert _markdown_to_telegram_html(text) == "some_var_name" + + def test_strikethrough(self) -> None: + text = "This is ~~deleted~~ text" + assert _markdown_to_telegram_html(text) == "This is deleted text" + + def test_inline_code(self) -> None: + text = "Use `print()` function" + result = _markdown_to_telegram_html(text) + assert "print()" in result + + def test_inline_code_escapes_html(self) -> None: + text = "Use `
` tag" + result = _markdown_to_telegram_html(text) + assert "<div>" in result + + def test_code_block(self) -> None: + text = """Here is code: +```python +def hello(): + return "world" +``` +Done. +""" + result = _markdown_to_telegram_html(text) + assert "
" in result
+        assert "def hello():" in result
+        assert "
" in result + + def test_code_block_escapes_html(self) -> None: + text = """``` +
test
+```""" + result = _markdown_to_telegram_html(text) + assert "<div>test</div>" in result + + def test_headers_stripped(self) -> None: + text = "# Header 1\n## Header 2\n### Header 3" + result = _markdown_to_telegram_html(text) + assert "# Header 1" not in result + assert "Header 1" in result + assert "Header 2" in result + assert "Header 3" in result + + def test_blockquotes_stripped(self) -> None: + text = "> This is a quote\nMore text" + result = _markdown_to_telegram_html(text) + assert "> " not in result + assert "This is a quote" in result + + def test_links_converted(self) -> None: + text = "Check [this link](https://example.com) out" + result = _markdown_to_telegram_html(text) + assert 'this link' in result + + def test_bullet_list_converted(self) -> None: + text = "- Item 1\n* Item 2" + result = _markdown_to_telegram_html(text) + assert "• Item 1" in result + assert "• Item 2" in result + + def test_html_special_chars_escaped(self) -> None: + text = "5 < 10 and 10 > 5" + result = _markdown_to_telegram_html(text) + assert "5 < 10" in result + assert "10 > 5" in result + + def test_complex_nested_formatting(self) -> None: + text = "**Bold _and italic_** and `code`" + result = _markdown_to_telegram_html(text) + assert "Bold and italic" in result + assert "code" in result + + +class TestTelegramChannelSend: + """Tests for TelegramChannel.send() method.""" + + @pytest.mark.asyncio + async def test_send_short_message_single_chunk(self, monkeypatch) -> None: + """Short messages are sent as a single message.""" + sent_messages = [] + + class FakeBot: + async def send_message(self, chat_id, text, parse_mode=None): + sent_messages.append({"chat_id": chat_id, "text": text, "parse_mode": parse_mode}) + + fake_app = MagicMock() + fake_app.bot = FakeBot() + + channel = TelegramChannel(_make_config(), MessageBus()) + channel._app = fake_app + + await channel.send(OutboundMessage( + channel="telegram", + chat_id="123456", + content="Hello world" + )) + + assert len(sent_messages) == 1 + assert sent_messages[0]["chat_id"] == 123456 + assert "Hello world" in sent_messages[0]["text"] + assert sent_messages[0]["parse_mode"] == "HTML" + + @pytest.mark.asyncio + async def test_send_long_message_split_into_chunks(self, monkeypatch) -> None: + """Long messages exceeding 4000 chars are split.""" + sent_messages = [] + + class FakeBot: + async def send_message(self, chat_id, text, parse_mode=None): + sent_messages.append({"chat_id": chat_id, "text": text, "parse_mode": parse_mode}) + + fake_app = MagicMock() + fake_app.bot = FakeBot() + + channel = TelegramChannel(_make_config(), MessageBus()) + channel._app = fake_app + + # Create a message longer than 4000 chars + long_content = "A" * 1000 + "\n" + "B" * 1000 + "\n" + "C" * 1000 + "\n" + "D" * 1000 + "\n" + "E" * 1000 + + await channel.send(OutboundMessage( + channel="telegram", + chat_id="123456", + content=long_content + )) + + assert len(sent_messages) == 2 # Should be split into 2 messages + assert all(m["chat_id"] == 123456 for m in sent_messages) + + @pytest.mark.asyncio + async def test_send_splits_at_newline_when_possible(self, monkeypatch) -> None: + """Message splitting prefers newline boundaries.""" + sent_messages = [] + + class FakeBot: + async def send_message(self, chat_id, text, parse_mode=None): + sent_messages.append({"chat_id": chat_id, "text": text, "parse_mode": parse_mode}) + + fake_app = MagicMock() + fake_app.bot = FakeBot() + + channel = TelegramChannel(_make_config(), MessageBus()) + channel._app = fake_app + + # Create content with clear paragraph breaks + paragraphs = [f"Paragraph {i}: " + "x" * 100 for i in range(50)] + content = "\n".join(paragraphs) + + await channel.send(OutboundMessage( + channel="telegram", + chat_id="123456", + content=content + )) + + # Each chunk should end with a complete paragraph (no partial lines) + for msg in sent_messages: + # Message should not start with whitespace after stripping + text = msg["text"] + assert text == text.lstrip() + + @pytest.mark.asyncio + async def test_send_falls_back_to_space_boundary(self, monkeypatch) -> None: + """When no newline available, split at space boundary.""" + sent_messages = [] + + class FakeBot: + async def send_message(self, chat_id, text, parse_mode=None): + sent_messages.append({"chat_id": chat_id, "text": text, "parse_mode": parse_mode}) + + fake_app = MagicMock() + fake_app.bot = FakeBot() + + channel = TelegramChannel(_make_config(), MessageBus()) + channel._app = fake_app + + # Long content without newlines but with spaces + content = "word " * 2000 # ~10000 chars + + await channel.send(OutboundMessage( + channel="telegram", + chat_id="123456", + content=content + )) + + assert len(sent_messages) >= 2 + + @pytest.mark.asyncio + async def test_send_forces_split_when_no_good_boundary(self, monkeypatch) -> None: + """When no newline or space, force split at max length.""" + sent_messages = [] + + class FakeBot: + async def send_message(self, chat_id, text, parse_mode=None): + sent_messages.append({"chat_id": chat_id, "text": text, "parse_mode": parse_mode}) + + fake_app = MagicMock() + fake_app.bot = FakeBot() + + channel = TelegramChannel(_make_config(), MessageBus()) + channel._app = fake_app + + # Long content without any spaces or newlines + content = "A" * 10000 + + await channel.send(OutboundMessage( + channel="telegram", + chat_id="123456", + content=content + )) + + assert len(sent_messages) >= 2 + # Verify all chunks combined equal original + combined = "".join(m["text"] for m in sent_messages) + assert combined == content + + @pytest.mark.asyncio + async def test_send_invalid_chat_id_logs_error(self, monkeypatch) -> None: + """Invalid chat_id should log error and not send.""" + sent_messages = [] + + class FakeBot: + async def send_message(self, chat_id, text, parse_mode=None): + sent_messages.append({"chat_id": chat_id, "text": text}) + + fake_app = MagicMock() + fake_app.bot = FakeBot() + + channel = TelegramChannel(_make_config(), MessageBus()) + channel._app = fake_app + + await channel.send(OutboundMessage( + channel="telegram", + chat_id="not-a-number", + content="Hello" + )) + + assert len(sent_messages) == 0 + + @pytest.mark.asyncio + async def test_send_html_parse_error_falls_back_to_plain_text(self, monkeypatch) -> None: + """When HTML parsing fails, fall back to plain text.""" + sent_messages = [] + call_count = 0 + + class FakeBot: + async def send_message(self, chat_id, text, parse_mode=None): + nonlocal call_count + call_count += 1 + if parse_mode == "HTML" and call_count == 1: + raise Exception("Bad markup") + sent_messages.append({"chat_id": chat_id, "text": text, "parse_mode": parse_mode}) + + fake_app = MagicMock() + fake_app.bot = FakeBot() + + channel = TelegramChannel(_make_config(), MessageBus()) + channel._app = fake_app + + await channel.send(OutboundMessage( + channel="telegram", + chat_id="123456", + content="Hello **world**" + )) + + # Should have 2 calls: first HTML (fails), second plain text (succeeds) + assert call_count == 2 + assert len(sent_messages) == 1 + assert sent_messages[0]["parse_mode"] is None # Plain text + assert "Hello **world**" in sent_messages[0]["text"] + + @pytest.mark.asyncio + async def test_send_not_running_warns(self, monkeypatch) -> None: + """If bot not running, log warning.""" + warning_logged = [] + + def mock_warning(msg, *args): + warning_logged.append(msg) + + monkeypatch.setattr("nanobot.channels.telegram.logger", MagicMock(warning=mock_warning)) + + channel = TelegramChannel(_make_config(), MessageBus()) + channel._app = None # Not running + + await channel.send(OutboundMessage( + channel="telegram", + chat_id="123456", + content="Hello" + )) + + assert any("not running" in str(m) for m in warning_logged) + + @pytest.mark.asyncio + async def test_send_stops_typing_indicator(self, monkeypatch) -> None: + """Sending message should stop typing indicator.""" + stopped_chats = [] + + class FakeBot: + async def send_message(self, chat_id, text, parse_mode=None): + pass + + fake_app = MagicMock() + fake_app.bot = FakeBot() + + channel = TelegramChannel(_make_config(), MessageBus()) + channel._app = fake_app + channel._stop_typing = lambda chat_id: stopped_chats.append(chat_id) + + await channel.send(OutboundMessage( + channel="telegram", + chat_id="123456", + content="Hello" + )) + + assert "123456" in stopped_chats + + +class TestTelegramChannelTyping: + """Tests for typing indicator functionality.""" + + @pytest.mark.asyncio + async def test_start_typing_creates_task(self) -> None: + channel = TelegramChannel(_make_config(), MessageBus()) + + # Mock _typing_loop to avoid actual async execution + channel._typing_loop = AsyncMock() + + channel._start_typing("123456") + + assert "123456" in channel._typing_tasks + assert not channel._typing_tasks["123456"].done() + + # Clean up + channel._stop_typing("123456") + + def test_stop_typing_cancels_task(self) -> None: + channel = TelegramChannel(_make_config(), MessageBus()) + + # Create a mock task + mock_task = MagicMock() + mock_task.done.return_value = False + channel._typing_tasks["123456"] = mock_task + + channel._stop_typing("123456") + + mock_task.cancel.assert_called_once() + assert "123456" not in channel._typing_tasks + + +class TestTelegramChannelMediaExtensions: + """Tests for media file extension detection.""" + + def test_get_extension_from_mime_type(self) -> None: + channel = TelegramChannel(_make_config(), MessageBus()) + + assert channel._get_extension("image", "image/jpeg") == ".jpg" + assert channel._get_extension("image", "image/png") == ".png" + assert channel._get_extension("image", "image/gif") == ".gif" + assert channel._get_extension("audio", "audio/ogg") == ".ogg" + assert channel._get_extension("audio", "audio/mpeg") == ".mp3" + + def test_get_extension_fallback_to_type(self) -> None: + channel = TelegramChannel(_make_config(), MessageBus()) + + assert channel._get_extension("image", None) == ".jpg" + assert channel._get_extension("voice", None) == ".ogg" + assert channel._get_extension("audio", None) == ".mp3" + + def test_get_extension_unknown_type(self) -> None: + channel = TelegramChannel(_make_config(), MessageBus()) + + assert channel._get_extension("unknown", None) == "" From 9bfc86af41144a2cc74ac0c5390156e29302cb26 Mon Sep 17 00:00:00 2001 From: zhouzhuojie Date: Sun, 15 Feb 2026 22:49:01 +0000 Subject: [PATCH 30/60] refactor(telegram): extract message splitting into helper function - Added _split_message() helper for cleaner separation of concerns - Simplified send() method by using the helper - Net -18 lines for the message splitting feature --- nanobot/channels/telegram.py | 68 +++++++++++++----------------------- 1 file changed, 25 insertions(+), 43 deletions(-) diff --git a/nanobot/channels/telegram.py b/nanobot/channels/telegram.py index a45178b..09467af 100644 --- a/nanobot/channels/telegram.py +++ b/nanobot/channels/telegram.py @@ -78,6 +78,23 @@ def _markdown_to_telegram_html(text: str) -> str: return text +def _split_message(content: str, max_len: int = 4000) -> list[str]: + """Split content into chunks within max_len, preferring line breaks.""" + if len(content) <= max_len: + return [content] + chunks = [] + while len(content) > max_len: + chunk = content[:max_len] + break_pos = chunk.rfind('\n') + if break_pos == -1: + break_pos = chunk.rfind(' ') + if break_pos == -1: + break_pos = max_len + chunks.append(chunk[:break_pos]) + content = content[break_pos:].lstrip() + return chunks + [content] + + class TelegramChannel(BaseChannel): """ Telegram channel using long polling. @@ -183,59 +200,24 @@ class TelegramChannel(BaseChannel): if not self._app: logger.warning("Telegram bot not running") return - - # Stop typing indicator for this chat + self._stop_typing(msg.chat_id) - + try: chat_id = int(msg.chat_id) except ValueError: logger.error(f"Invalid chat_id: {msg.chat_id}") return - - # Split content into chunks (Telegram limit: 4096 chars) - MAX_LENGTH = 4000 # Leave some margin for safety - content = msg.content - chunks = [] - - while content: - if len(content) <= MAX_LENGTH: - chunks.append(content) - break - - # Find a good break point (newline or space) - chunk = content[:MAX_LENGTH] - # Prefer breaking at newline - break_pos = chunk.rfind('\n') - if break_pos == -1: - # Fall back to last space - break_pos = chunk.rfind(' ') - if break_pos == -1: - # No good break point, force break at limit - break_pos = MAX_LENGTH - - chunks.append(content[:break_pos]) - content = content[break_pos:].lstrip() - - # Send each chunk - for i, chunk in enumerate(chunks): + + for chunk in _split_message(msg.content): try: - html_content = _markdown_to_telegram_html(chunk) - await self._app.bot.send_message( - chat_id=chat_id, - text=html_content, - parse_mode="HTML" - ) + await self._app.bot.send_message(chat_id=chat_id, text=_markdown_to_telegram_html(chunk), parse_mode="HTML") except Exception as e: - # Fallback to plain text if HTML parsing fails - logger.warning(f"HTML parse failed for chunk {i+1}, falling back to plain text: {e}") + logger.warning(f"HTML parse failed, falling back to plain text: {e}") try: - await self._app.bot.send_message( - chat_id=chat_id, - text=chunk - ) + await self._app.bot.send_message(chat_id=chat_id, text=chunk) except Exception as e2: - logger.error(f"Error sending Telegram chunk {i+1}: {e2}") + logger.error(f"Error sending Telegram message: {e2}") async def _on_start(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: """Handle /start command.""" From 51d22b7ef46cfcd188068422cbc6bb23937382d9 Mon Sep 17 00:00:00 2001 From: Thomas Lisankie Date: Mon, 16 Feb 2026 00:14:34 -0500 Subject: [PATCH 31/60] Fix: _forward_command now builds sender_id with username for allowlist matching --- nanobot/channels/telegram.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/nanobot/channels/telegram.py b/nanobot/channels/telegram.py index 32f8c67..efd009e 100644 --- a/nanobot/channels/telegram.py +++ b/nanobot/channels/telegram.py @@ -226,8 +226,14 @@ class TelegramChannel(BaseChannel): """Forward slash commands to the bus for unified handling in AgentLoop.""" if not update.message or not update.effective_user: return + + user = update.effective_user + sender_id = str(user.id) + if user.username: + sender_id = f"{sender_id}|{user.username}" + await self._handle_message( - sender_id=str(update.effective_user.id), + sender_id=sender_id, chat_id=str(update.message.chat_id), content=update.message.text, ) From 90be9004487f74060bcb7f8a605a3656c5b4dfdf Mon Sep 17 00:00:00 2001 From: "Aleksander W. Oleszkiewicz (Alek)" <24917047+alekwo@users.noreply.github.com> Date: Mon, 16 Feb 2026 09:49:44 +0100 Subject: [PATCH 32/60] Enhance Slack message formatting with new regex rules Added regex substitutions for strikethrough, URL formatting, and image URLs in Slack message conversion. --- nanobot/channels/slack.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/nanobot/channels/slack.py b/nanobot/channels/slack.py index 7298435..6b685d1 100644 --- a/nanobot/channels/slack.py +++ b/nanobot/channels/slack.py @@ -223,9 +223,21 @@ class SlackChannel(BaseChannel): # Step 3.a: ***text*** -> *_text_* converted_text = re.sub( r"(?m)(^|[^\*])\*\*\*([^\*].+?[^\*])\*\*\*([^\*]|$)", r"\1*_\2_*\3", converted_text) - # Step 3.b - ___text___ to *_text_* + # Step 3.b - ___text___ -> *_text_* converted_text = re.sub( r"(?m)(^|[^_])___([^_].+?[^_])___([^_]|$)", r"\1*_\2_*\3", converted_text) + # Convert strikethrough + # Step 4: ~~text~~ -> ~text~ + converted_text = re.sub( + r"(?m)(^|[^~])~~([^~].+?[^~])~~([^~]|$)", r"\1~\2~\3", converted_text) + # Convert URL formatting + # Step 6: [text](URL) -> + converted_text = re.sub( + r"(^|[^!])\[(.+?)\]\((http.+?)\)", r"<\2|\1>", converted_text) + # Convert image URL + # Step 6: ![alt text](URL "title") -> + converted_text = re.sub( + r"[!]\[.+?\]\((http.+?)(?: \".*?\")?\)", r"<\2>", converted_text) return converted_text def escape_mrkdwn(text: str) -> str: return (text.replace('&', '&') From 5d683da38f577a66a3ae7f1ceacbcdffcb4c56df Mon Sep 17 00:00:00 2001 From: "Aleksander W. Oleszkiewicz (Alek)" <24917047+alekwo@users.noreply.github.com> Date: Mon, 16 Feb 2026 09:53:20 +0100 Subject: [PATCH 33/60] Fix regex for URL and image URL formatting --- nanobot/channels/slack.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nanobot/channels/slack.py b/nanobot/channels/slack.py index 6b685d1..ef78887 100644 --- a/nanobot/channels/slack.py +++ b/nanobot/channels/slack.py @@ -233,11 +233,11 @@ class SlackChannel(BaseChannel): # Convert URL formatting # Step 6: [text](URL) -> converted_text = re.sub( - r"(^|[^!])\[(.+?)\]\((http.+?)\)", r"<\2|\1>", converted_text) + r"(^|[^!])\[(.+?)\]\((http.+?)\)", r"\1<\3|\2>", converted_text) # Convert image URL # Step 6: ![alt text](URL "title") -> converted_text = re.sub( - r"[!]\[.+?\]\((http.+?)(?: \".*?\")?\)", r"<\2>", converted_text) + r"[!]\[.+?\]\((http.+?)(?: \".*?\")?\)", r"<\1>", converted_text) return converted_text def escape_mrkdwn(text: str) -> str: return (text.replace('&', '&') From fe0341da5ba862bd206821467118f29cec9640d9 Mon Sep 17 00:00:00 2001 From: "Aleksander W. Oleszkiewicz (Alek)" <24917047+alekwo@users.noreply.github.com> Date: Mon, 16 Feb 2026 09:58:38 +0100 Subject: [PATCH 34/60] Fix regex for URL formatting in Slack channel --- nanobot/channels/slack.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nanobot/channels/slack.py b/nanobot/channels/slack.py index ef78887..25af83b 100644 --- a/nanobot/channels/slack.py +++ b/nanobot/channels/slack.py @@ -233,7 +233,7 @@ class SlackChannel(BaseChannel): # Convert URL formatting # Step 6: [text](URL) -> converted_text = re.sub( - r"(^|[^!])\[(.+?)\]\((http.+?)\)", r"\1<\3|\2>", converted_text) + r"(?m)(^|[^!])\[(.+?)\]\((http.+?)\)", r"\1<\3|\2>", converted_text) # Convert image URL # Step 6: ![alt text](URL "title") -> converted_text = re.sub( From 1ce586e9f515ca537353331f726307844e1b4e2f Mon Sep 17 00:00:00 2001 From: Re-bin Date: Mon, 16 Feb 2026 11:43:36 +0000 Subject: [PATCH 35/60] fix: resolve Codex provider bugs and simplify implementation --- README.md | 31 ++++++++++ nanobot/cli/commands.py | 5 +- nanobot/config/schema.py | 10 ++-- nanobot/providers/openai_codex_provider.py | 69 +++++++++------------- nanobot/providers/registry.py | 2 - 5 files changed, 65 insertions(+), 52 deletions(-) diff --git a/README.md b/README.md index f6362bb..6a3ec3e 100644 --- a/README.md +++ b/README.md @@ -585,6 +585,37 @@ Config file: `~/.nanobot/config.json` | `moonshot` | LLM (Moonshot/Kimi) | [platform.moonshot.cn](https://platform.moonshot.cn) | | `zhipu` | LLM (Zhipu GLM) | [open.bigmodel.cn](https://open.bigmodel.cn) | | `vllm` | LLM (local, any OpenAI-compatible server) | — | +| `openai_codex` | LLM (Codex, OAuth) | `nanobot provider login openai-codex` | + +
+OpenAI Codex (OAuth) + +Codex uses OAuth instead of API keys. Requires a ChatGPT Plus or Pro account. + +**1. Login:** +```bash +nanobot provider login openai-codex +``` + +**2. Set model** (merge into `~/.nanobot/config.json`): +```json +{ + "agents": { + "defaults": { + "model": "openai-codex/gpt-5.1-codex" + } + } +} +``` + +**3. Chat:** +```bash +nanobot agent -m "Hello!" +``` + +> Docker users: use `docker run -it` for interactive OAuth login. + +
Custom Provider (Any OpenAI-compatible API) diff --git a/nanobot/cli/commands.py b/nanobot/cli/commands.py index b2d3f5a..235bfdc 100644 --- a/nanobot/cli/commands.py +++ b/nanobot/cli/commands.py @@ -290,10 +290,7 @@ def _make_provider(config: Config): # OpenAI Codex (OAuth): don't route via LiteLLM; use the dedicated implementation. if provider_name == "openai_codex" or model.startswith("openai-codex/"): - return OpenAICodexProvider( - default_model=model, - api_base=p.api_base if p else None, - ) + return OpenAICodexProvider(default_model=model) if not model.startswith("bedrock/") and not (p and p.api_key): console.print("[red]Error: No API key configured.[/red]") diff --git a/nanobot/config/schema.py b/nanobot/config/schema.py index 9d648be..15b6bb2 100644 --- a/nanobot/config/schema.py +++ b/nanobot/config/schema.py @@ -192,7 +192,7 @@ class ProvidersConfig(BaseModel): moonshot: ProviderConfig = Field(default_factory=ProviderConfig) minimax: ProviderConfig = Field(default_factory=ProviderConfig) aihubmix: ProviderConfig = Field(default_factory=ProviderConfig) # AiHubMix API gateway - openai_codex: ProviderConfig = Field(default_factory=ProviderConfig) # OpenAI Codex (OAuth) # AiHubMix API gateway + openai_codex: ProviderConfig = Field(default_factory=ProviderConfig) # OpenAI Codex (OAuth) class GatewayConfig(BaseModel): @@ -252,19 +252,19 @@ class Config(BaseSettings): model_lower = (model or self.agents.defaults.model).lower() # Match by keyword (order follows PROVIDERS registry) - # Note: OAuth providers don't require api_key, so we check is_oauth flag for spec in PROVIDERS: p = getattr(self.providers, spec.name, None) if p and any(kw in model_lower for kw in spec.keywords): - # OAuth providers don't need api_key if spec.is_oauth or p.api_key: return p, spec.name # Fallback: gateways first, then others (follows registry order) - # OAuth providers are also valid fallbacks + # OAuth providers are NOT valid fallbacks — they require explicit model selection for spec in PROVIDERS: + if spec.is_oauth: + continue p = getattr(self.providers, spec.name, None) - if p and (spec.is_oauth or p.api_key): + if p and p.api_key: return p, spec.name return None, None diff --git a/nanobot/providers/openai_codex_provider.py b/nanobot/providers/openai_codex_provider.py index f6d56aa..5067438 100644 --- a/nanobot/providers/openai_codex_provider.py +++ b/nanobot/providers/openai_codex_provider.py @@ -8,6 +8,7 @@ import json from typing import Any, AsyncGenerator import httpx +from loguru import logger from oauth_cli_kit import get_token as get_codex_token from nanobot.providers.base import LLMProvider, LLMResponse, ToolCallRequest @@ -59,9 +60,9 @@ class OpenAICodexProvider(LLMProvider): try: content, tool_calls, finish_reason = await _request_codex(url, headers, body, verify=True) except Exception as e: - # Certificate verification failed, downgrade to disable verification (security risk) if "CERTIFICATE_VERIFY_FAILED" not in str(e): raise + logger.warning("SSL certificate verification failed for Codex API; retrying with verify=False") content, tool_calls, finish_reason = await _request_codex(url, headers, body, verify=False) return LLMResponse( content=content, @@ -77,6 +78,7 @@ class OpenAICodexProvider(LLMProvider): def get_default_model(self) -> str: return self.default_model + def _strip_model_prefix(model: str) -> str: if model.startswith("openai-codex/"): return model.split("/", 1)[1] @@ -94,6 +96,7 @@ def _build_headers(account_id: str, token: str) -> dict[str, str]: "content-type": "application/json", } + async def _request_codex( url: str, headers: dict[str, str], @@ -107,36 +110,25 @@ async def _request_codex( raise RuntimeError(_friendly_error(response.status_code, text.decode("utf-8", "ignore"))) return await _consume_sse(response) + def _convert_tools(tools: list[dict[str, Any]]) -> list[dict[str, Any]]: - # Nanobot tool definitions already use the OpenAI function schema. + """Convert OpenAI function-calling schema to Codex flat format.""" converted: list[dict[str, Any]] = [] for tool in tools: - fn = tool.get("function") if isinstance(tool, dict) and tool.get("type") == "function" else None - if fn and isinstance(fn, dict): - name = fn.get("name") - desc = fn.get("description") - params = fn.get("parameters") - else: - name = tool.get("name") - desc = tool.get("description") - params = tool.get("parameters") - if not isinstance(name, str) or not name: - # Skip invalid tools to avoid Codex rejection. + fn = (tool.get("function") or {}) if tool.get("type") == "function" else tool + name = fn.get("name") + if not name: continue - params = params or {} - if not isinstance(params, dict): - # Parameters must be a JSON Schema object. - params = {} - converted.append( - { - "type": "function", - "name": name, - "description": desc or "", - "parameters": params, - } - ) + params = fn.get("parameters") or {} + converted.append({ + "type": "function", + "name": name, + "description": fn.get("description") or "", + "parameters": params if isinstance(params, dict) else {}, + }) return converted + def _convert_messages(messages: list[dict[str, Any]]) -> tuple[str, list[dict[str, Any]]]: system_prompt = "" input_items: list[dict[str, Any]] = [] @@ -183,7 +175,7 @@ def _convert_messages(messages: list[dict[str, Any]]) -> tuple[str, list[dict[st continue if role == "tool": - call_id = _extract_call_id(msg.get("tool_call_id")) + call_id, _ = _split_tool_call_id(msg.get("tool_call_id")) output_text = content if isinstance(content, str) else json.dumps(content) input_items.append( { @@ -196,6 +188,7 @@ def _convert_messages(messages: list[dict[str, Any]]) -> tuple[str, list[dict[st return system_prompt, input_items + def _convert_user_message(content: Any) -> dict[str, Any]: if isinstance(content, str): return {"role": "user", "content": [{"type": "input_text", "text": content}]} @@ -215,12 +208,6 @@ def _convert_user_message(content: Any) -> dict[str, Any]: return {"role": "user", "content": [{"type": "input_text", "text": ""}]} -def _extract_call_id(tool_call_id: Any) -> str: - if isinstance(tool_call_id, str) and tool_call_id: - return tool_call_id.split("|", 1)[0] - return "call_0" - - def _split_tool_call_id(tool_call_id: Any) -> tuple[str, str | None]: if isinstance(tool_call_id, str) and tool_call_id: if "|" in tool_call_id: @@ -229,10 +216,12 @@ def _split_tool_call_id(tool_call_id: Any) -> tuple[str, str | None]: return tool_call_id, None return "call_0", None + def _prompt_cache_key(messages: list[dict[str, Any]]) -> str: raw = json.dumps(messages, ensure_ascii=True, sort_keys=True) return hashlib.sha256(raw.encode("utf-8")).hexdigest() + async def _iter_sse(response: httpx.Response) -> AsyncGenerator[dict[str, Any], None]: buffer: list[str] = [] async for line in response.aiter_lines(): @@ -252,6 +241,7 @@ async def _iter_sse(response: httpx.Response) -> AsyncGenerator[dict[str, Any], continue buffer.append(line) + async def _consume_sse(response: httpx.Response) -> tuple[str, list[ToolCallRequest], str]: content = "" tool_calls: list[ToolCallRequest] = [] @@ -308,16 +298,13 @@ async def _consume_sse(response: httpx.Response) -> tuple[str, list[ToolCallRequ return content, tool_calls, finish_reason + +_FINISH_REASON_MAP = {"completed": "stop", "incomplete": "length", "failed": "error", "cancelled": "error"} + + def _map_finish_reason(status: str | None) -> str: - if not status: - return "stop" - if status == "completed": - return "stop" - if status == "incomplete": - return "length" - if status in {"failed", "cancelled"}: - return "error" - return "stop" + return _FINISH_REASON_MAP.get(status or "completed", "stop") + def _friendly_error(status_code: int, raw: str) -> str: if status_code == 429: diff --git a/nanobot/providers/registry.py b/nanobot/providers/registry.py index 1b4a776..59af5e1 100644 --- a/nanobot/providers/registry.py +++ b/nanobot/providers/registry.py @@ -53,7 +53,6 @@ class ProviderSpec: # OAuth-based providers (e.g., OpenAI Codex) don't use API keys is_oauth: bool = False # if True, uses OAuth flow instead of API key - oauth_provider: str = "" # OAuth provider name for token retrieval @property def label(self) -> str: @@ -176,7 +175,6 @@ PROVIDERS: tuple[ProviderSpec, ...] = ( strip_model_prefix=False, model_overrides=(), is_oauth=True, # OAuth-based authentication - oauth_provider="openai-codex", # OAuth provider identifier ), # DeepSeek: needs "deepseek/" prefix for LiteLLM routing. From e8e7215d3ea2a99ec36859603a40c06b8fec26a9 Mon Sep 17 00:00:00 2001 From: Re-bin Date: Mon, 16 Feb 2026 11:57:55 +0000 Subject: [PATCH 36/60] refactor: simplify Slack markdown-to-mrkdwn conversion --- nanobot/channels/slack.py | 154 +++++++++----------------------------- 1 file changed, 37 insertions(+), 117 deletions(-) diff --git a/nanobot/channels/slack.py b/nanobot/channels/slack.py index 25af83b..dd18e79 100644 --- a/nanobot/channels/slack.py +++ b/nanobot/channels/slack.py @@ -204,126 +204,46 @@ class SlackChannel(BaseChannel): return text return re.sub(rf"<@{re.escape(self._bot_user_id)}>\s*", "", text).strip() + # Markdown → Slack mrkdwn formatting rules (order matters: longest markers first) + _MD_TO_SLACK = ( + (r'(?m)(^|[^\*])\*\*\*(.+?)\*\*\*([^\*]|$)', r'\1*_\2_*\3'), # ***bold italic*** + (r'(?m)(^|[^_])___(.+?)___([^_]|$)', r'\1*_\2_*\3'), # ___bold italic___ + (r'(?m)(^|[^\*])\*\*(.+?)\*\*([^\*]|$)', r'\1*\2*\3'), # **bold** + (r'(?m)(^|[^_])__(.+?)__([^_]|$)', r'\1*\2*\3'), # __bold__ + (r'(?m)(^|[^\*])\*(.+?)\*([^\*]|$)', r'\1_\2_\3'), # *italic* + (r'(?m)(^|[^~])~~(.+?)~~([^~]|$)', r'\1~\2~\3'), # ~~strike~~ + (r'(?m)(^|[^!])\[(.+?)\]\((http.+?)\)', r'\1<\3|\2>'), # [text](url) + (r'!\[.+?\]\((http.+?)(?:\s".*?")?\)', r'<\1>'), # ![alt](url) + ) + _TABLE_RE = re.compile(r'(?m)^\|.*?\|$(?:\n(?:\|\:?-{3,}\:?)*?\|$)(?:\n\|.*?\|$)*') + def _convert_markdown(self, text: str) -> str: + """Convert standard Markdown to Slack mrkdwn format.""" if not text: return text - def convert_formatting(input: str) -> str: - # Convert italics - # Step 1: *text* -> _text_ - converted_text = re.sub( - r"(?m)(^|[^\*])\*([^\*].+?[^\*])\*([^\*]|$)", r"\1_\2_\3", input) - # Convert bold - # Step 2.a: **text** -> *text* - converted_text = re.sub( - r"(?m)(^|[^\*])\*\*([^\*].+?[^\*])\*\*([^\*]|$)", r"\1*\2*\3", converted_text) - # Step 2.b: __text__ -> *text* - converted_text = re.sub( - r"(?m)(^|[^_])__([^_].+?[^_])__([^_]|$)", r"\1*\2*\3", converted_text) - # convert bold italics - # Step 3.a: ***text*** -> *_text_* - converted_text = re.sub( - r"(?m)(^|[^\*])\*\*\*([^\*].+?[^\*])\*\*\*([^\*]|$)", r"\1*_\2_*\3", converted_text) - # Step 3.b - ___text___ -> *_text_* - converted_text = re.sub( - r"(?m)(^|[^_])___([^_].+?[^_])___([^_]|$)", r"\1*_\2_*\3", converted_text) - # Convert strikethrough - # Step 4: ~~text~~ -> ~text~ - converted_text = re.sub( - r"(?m)(^|[^~])~~([^~].+?[^~])~~([^~]|$)", r"\1~\2~\3", converted_text) - # Convert URL formatting - # Step 6: [text](URL) -> - converted_text = re.sub( - r"(?m)(^|[^!])\[(.+?)\]\((http.+?)\)", r"\1<\3|\2>", converted_text) - # Convert image URL - # Step 6: ![alt text](URL "title") -> - converted_text = re.sub( - r"[!]\[.+?\]\((http.+?)(?: \".*?\")?\)", r"<\1>", converted_text) - return converted_text - def escape_mrkdwn(text: str) -> str: - return (text.replace('&', '&') - .replace('<', '<') - .replace('>', '>')) - def convert_table(match: re.Match) -> str: - # Slack doesn't support Markdown tables - # Convert table to bulleted list with sections - # -- input_md: - # Some text before the table. - # | Col1 | Col2 | Col3 | - # |-----|----------|------| - # | Row1 - A | Row1 - B | Row1 - C | - # | Row2 - D | Row2 - E | Row2 - F | - # - # Some text after the table. - # - # -- will be converted to: - # Some text before the table. - # > *Col1* : Row1 - A - # • *Col2*: Row1 - B - # • *Col3*: Row1 - C - # > *Col1* : Row2 - D - # • *Col2*: Row2 - E - # • *Col3*: Row2 - F - # - # Some text after the table. - - block = match.group(0).strip() - lines = [line.strip() - for line in block.split('\n') if line.strip()] + for pattern, repl in self._MD_TO_SLACK: + text = re.sub(pattern, repl, text) + return self._TABLE_RE.sub(self._convert_table, text) - if len(lines) < 2: - return block + @staticmethod + def _convert_table(match: re.Match) -> str: + """Convert Markdown table to Slack quote + bullet format.""" + lines = [l.strip() for l in match.group(0).strip().split('\n') if l.strip()] + if len(lines) < 2: + return match.group(0) - # 1. Parse Headers from the first line - # Split by pipe, filtering out empty start/end strings caused by outer pipes - header_line = lines[0].strip('|') - headers = [escape_mrkdwn(h.strip()) - for h in header_line.split('|')] + headers = [h.strip() for h in lines[0].strip('|').split('|')] + start = 2 if not re.search(r'[^|\-\s:]', lines[1]) else 1 - # 2. Identify Data Start (Skip Separator) - data_start_idx = 1 - # If line 2 contains only separator chars (|-: ), skip it - if len(lines) > 1 and not re.search(r'[^|\-\s:]', lines[1]): - data_start_idx = 2 - - # 3. Process Data Rows - slack_lines = [] - for line in lines[data_start_idx:]: - # Clean and split cells - clean_line = line.strip('|') - cells = [escape_mrkdwn(c.strip()) - for c in clean_line.split('|')] - - # Normalize cell count to match headers - if len(cells) < len(headers): - cells += [''] * (len(headers) - len(cells)) - cells = cells[:len(headers)] - - # Skip empty rows - if not any(cells): - continue - - # Key is the first column - key = cells[0] - label = headers[0] - slack_lines.append( - f"> *{label}* : {key}" if key else "> *{label}* : --") - - # Sub-bullets for remaining columns - for i, cell in enumerate(cells[1:], 1): - if cell: - label = headers[i] if i < len(headers) else "Col" - slack_lines.append(f" • *{label}*: {cell}") - - slack_lines.append("") # Spacer between items - - return "\n".join(slack_lines).rstrip() - - # (?m) : Multiline mode so ^ matches start of line and $ end of line - # ^\| : Start of line and a literal pipe - # .*?\|$ : Rest of the line and a pipe at the end - # (?:\n(?:\|\:?-{3,}\:?)*?\|$) : A heading line with at least three dashes in each column, pipes, and : e.g. |:---|----|:---:| - # (?:\n\|.*?\|$)* : Zero or more subsequent lines that ALSO start and end with a pipe - table_pattern = r'(?m)^\|.*?\|$(?:\n(?:\|\:?-{3,}\:?)*?\|$)(?:\n\|.*?\|$)*' - - input_md = convert_formatting(text) - return re.sub(table_pattern, convert_table, input_md) + result: list[str] = [] + for line in lines[start:]: + cells = [c.strip() for c in line.strip('|').split('|')] + cells = (cells + [''] * len(headers))[:len(headers)] + if not any(cells): + continue + result.append(f"> *{headers[0]}*: {cells[0] or '--'}") + for i, cell in enumerate(cells[1:], 1): + if cell and i < len(headers): + result.append(f" \u2022 *{headers[i]}*: {cell}") + result.append("") + return '\n'.join(result).rstrip() From ffbb264a5d41941f793ba4910de26df04874ec26 Mon Sep 17 00:00:00 2001 From: Re-bin Date: Mon, 16 Feb 2026 12:11:03 +0000 Subject: [PATCH 37/60] fix: consistent sender_id for Telegram command allowlist matching --- nanobot/channels/telegram.py | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/nanobot/channels/telegram.py b/nanobot/channels/telegram.py index efd009e..d2ce74c 100644 --- a/nanobot/channels/telegram.py +++ b/nanobot/channels/telegram.py @@ -222,18 +222,18 @@ class TelegramChannel(BaseChannel): "Type /help to see available commands." ) + @staticmethod + def _sender_id(user) -> str: + """Build sender_id with username for allowlist matching.""" + sid = str(user.id) + return f"{sid}|{user.username}" if user.username else sid + async def _forward_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: """Forward slash commands to the bus for unified handling in AgentLoop.""" if not update.message or not update.effective_user: return - - user = update.effective_user - sender_id = str(user.id) - if user.username: - sender_id = f"{sender_id}|{user.username}" - await self._handle_message( - sender_id=sender_id, + sender_id=self._sender_id(update.effective_user), chat_id=str(update.message.chat_id), content=update.message.text, ) @@ -246,11 +246,7 @@ class TelegramChannel(BaseChannel): message = update.message user = update.effective_user chat_id = message.chat_id - - # Use stable numeric ID, but keep username for allowlist compatibility - sender_id = str(user.id) - if user.username: - sender_id = f"{sender_id}|{user.username}" + sender_id = self._sender_id(user) # Store chat_id for replies self._chat_ids[sender_id] = chat_id From db0e8aa61b2a69fc81a43a04c86dfbe67d3b2631 Mon Sep 17 00:00:00 2001 From: Re-bin Date: Mon, 16 Feb 2026 12:39:39 +0000 Subject: [PATCH 38/60] fix: handle Telegram message length limit with smart splitting --- .gitignore | 2 +- README.md | 2 +- nanobot/channels/telegram.py | 28 ++- tests/test_telegram_channel.py | 416 --------------------------------- 4 files changed, 18 insertions(+), 430 deletions(-) delete mode 100644 tests/test_telegram_channel.py diff --git a/.gitignore b/.gitignore index 742d593..d7b930d 100644 --- a/.gitignore +++ b/.gitignore @@ -19,4 +19,4 @@ __pycache__/ poetry.lock .pytest_cache/ botpy.log - +tests/ diff --git a/README.md b/README.md index 6a3ec3e..0584dd8 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ ⚡️ Delivers core agent functionality in just **~4,000** lines of code — **99% smaller** than Clawdbot's 430k+ lines. -📏 Real-time line count: **3,663 lines** (run `bash core_agent_lines.sh` to verify anytime) +📏 Real-time line count: **3,668 lines** (run `bash core_agent_lines.sh` to verify anytime) ## 📢 News diff --git a/nanobot/channels/telegram.py b/nanobot/channels/telegram.py index 8166a9d..c9978c2 100644 --- a/nanobot/channels/telegram.py +++ b/nanobot/channels/telegram.py @@ -82,17 +82,20 @@ def _split_message(content: str, max_len: int = 4000) -> list[str]: """Split content into chunks within max_len, preferring line breaks.""" if len(content) <= max_len: return [content] - chunks = [] - while len(content) > max_len: - chunk = content[:max_len] - break_pos = chunk.rfind('\n') - if break_pos == -1: - break_pos = chunk.rfind(' ') - if break_pos == -1: - break_pos = max_len - chunks.append(chunk[:break_pos]) - content = content[break_pos:].lstrip() - return chunks + [content] + chunks: list[str] = [] + while content: + if len(content) <= max_len: + chunks.append(content) + break + cut = content[:max_len] + pos = cut.rfind('\n') + if pos == -1: + pos = cut.rfind(' ') + if pos == -1: + pos = max_len + chunks.append(content[:pos]) + content = content[pos:].lstrip() + return chunks class TelegramChannel(BaseChannel): @@ -211,7 +214,8 @@ class TelegramChannel(BaseChannel): for chunk in _split_message(msg.content): try: - await self._app.bot.send_message(chat_id=chat_id, text=_markdown_to_telegram_html(chunk), parse_mode="HTML") + html = _markdown_to_telegram_html(chunk) + await self._app.bot.send_message(chat_id=chat_id, text=html, parse_mode="HTML") except Exception as e: logger.warning(f"HTML parse failed, falling back to plain text: {e}") try: diff --git a/tests/test_telegram_channel.py b/tests/test_telegram_channel.py deleted file mode 100644 index 8e9a4d4..0000000 --- a/tests/test_telegram_channel.py +++ /dev/null @@ -1,416 +0,0 @@ -"""Tests for Telegram channel implementation.""" - -import pytest -from unittest.mock import AsyncMock, MagicMock - -from nanobot.bus.events import OutboundMessage -from nanobot.bus.queue import MessageBus -from nanobot.channels.telegram import TelegramChannel, _markdown_to_telegram_html -from nanobot.config.schema import TelegramConfig - - -def _make_config() -> TelegramConfig: - return TelegramConfig( - enabled=True, - token="fake-token", - allow_from=[], - proxy=None, - ) - - -class TestMarkdownToTelegramHtml: - """Tests for markdown to Telegram HTML conversion.""" - - def test_empty_text(self) -> None: - assert _markdown_to_telegram_html("") == "" - - def test_plain_text_passthrough(self) -> None: - text = "Hello world" - assert _markdown_to_telegram_html(text) == "Hello world" - - def test_bold_double_asterisks(self) -> None: - text = "This is **bold** text" - assert _markdown_to_telegram_html(text) == "This is bold text" - - def test_bold_double_underscore(self) -> None: - text = "This is __bold__ text" - assert _markdown_to_telegram_html(text) == "This is bold text" - - def test_italic_underscore(self) -> None: - text = "This is _italic_ text" - assert _markdown_to_telegram_html(text) == "This is italic text" - - def test_italic_not_inside_words(self) -> None: - text = "some_var_name" - assert _markdown_to_telegram_html(text) == "some_var_name" - - def test_strikethrough(self) -> None: - text = "This is ~~deleted~~ text" - assert _markdown_to_telegram_html(text) == "This is deleted text" - - def test_inline_code(self) -> None: - text = "Use `print()` function" - result = _markdown_to_telegram_html(text) - assert "print()" in result - - def test_inline_code_escapes_html(self) -> None: - text = "Use `
` tag" - result = _markdown_to_telegram_html(text) - assert "<div>" in result - - def test_code_block(self) -> None: - text = """Here is code: -```python -def hello(): - return "world" -``` -Done. -""" - result = _markdown_to_telegram_html(text) - assert "
" in result
-        assert "def hello():" in result
-        assert "
" in result - - def test_code_block_escapes_html(self) -> None: - text = """``` -
test
-```""" - result = _markdown_to_telegram_html(text) - assert "<div>test</div>" in result - - def test_headers_stripped(self) -> None: - text = "# Header 1\n## Header 2\n### Header 3" - result = _markdown_to_telegram_html(text) - assert "# Header 1" not in result - assert "Header 1" in result - assert "Header 2" in result - assert "Header 3" in result - - def test_blockquotes_stripped(self) -> None: - text = "> This is a quote\nMore text" - result = _markdown_to_telegram_html(text) - assert "> " not in result - assert "This is a quote" in result - - def test_links_converted(self) -> None: - text = "Check [this link](https://example.com) out" - result = _markdown_to_telegram_html(text) - assert 'this link' in result - - def test_bullet_list_converted(self) -> None: - text = "- Item 1\n* Item 2" - result = _markdown_to_telegram_html(text) - assert "• Item 1" in result - assert "• Item 2" in result - - def test_html_special_chars_escaped(self) -> None: - text = "5 < 10 and 10 > 5" - result = _markdown_to_telegram_html(text) - assert "5 < 10" in result - assert "10 > 5" in result - - def test_complex_nested_formatting(self) -> None: - text = "**Bold _and italic_** and `code`" - result = _markdown_to_telegram_html(text) - assert "Bold and italic" in result - assert "code" in result - - -class TestTelegramChannelSend: - """Tests for TelegramChannel.send() method.""" - - @pytest.mark.asyncio - async def test_send_short_message_single_chunk(self, monkeypatch) -> None: - """Short messages are sent as a single message.""" - sent_messages = [] - - class FakeBot: - async def send_message(self, chat_id, text, parse_mode=None): - sent_messages.append({"chat_id": chat_id, "text": text, "parse_mode": parse_mode}) - - fake_app = MagicMock() - fake_app.bot = FakeBot() - - channel = TelegramChannel(_make_config(), MessageBus()) - channel._app = fake_app - - await channel.send(OutboundMessage( - channel="telegram", - chat_id="123456", - content="Hello world" - )) - - assert len(sent_messages) == 1 - assert sent_messages[0]["chat_id"] == 123456 - assert "Hello world" in sent_messages[0]["text"] - assert sent_messages[0]["parse_mode"] == "HTML" - - @pytest.mark.asyncio - async def test_send_long_message_split_into_chunks(self, monkeypatch) -> None: - """Long messages exceeding 4000 chars are split.""" - sent_messages = [] - - class FakeBot: - async def send_message(self, chat_id, text, parse_mode=None): - sent_messages.append({"chat_id": chat_id, "text": text, "parse_mode": parse_mode}) - - fake_app = MagicMock() - fake_app.bot = FakeBot() - - channel = TelegramChannel(_make_config(), MessageBus()) - channel._app = fake_app - - # Create a message longer than 4000 chars - long_content = "A" * 1000 + "\n" + "B" * 1000 + "\n" + "C" * 1000 + "\n" + "D" * 1000 + "\n" + "E" * 1000 - - await channel.send(OutboundMessage( - channel="telegram", - chat_id="123456", - content=long_content - )) - - assert len(sent_messages) == 2 # Should be split into 2 messages - assert all(m["chat_id"] == 123456 for m in sent_messages) - - @pytest.mark.asyncio - async def test_send_splits_at_newline_when_possible(self, monkeypatch) -> None: - """Message splitting prefers newline boundaries.""" - sent_messages = [] - - class FakeBot: - async def send_message(self, chat_id, text, parse_mode=None): - sent_messages.append({"chat_id": chat_id, "text": text, "parse_mode": parse_mode}) - - fake_app = MagicMock() - fake_app.bot = FakeBot() - - channel = TelegramChannel(_make_config(), MessageBus()) - channel._app = fake_app - - # Create content with clear paragraph breaks - paragraphs = [f"Paragraph {i}: " + "x" * 100 for i in range(50)] - content = "\n".join(paragraphs) - - await channel.send(OutboundMessage( - channel="telegram", - chat_id="123456", - content=content - )) - - # Each chunk should end with a complete paragraph (no partial lines) - for msg in sent_messages: - # Message should not start with whitespace after stripping - text = msg["text"] - assert text == text.lstrip() - - @pytest.mark.asyncio - async def test_send_falls_back_to_space_boundary(self, monkeypatch) -> None: - """When no newline available, split at space boundary.""" - sent_messages = [] - - class FakeBot: - async def send_message(self, chat_id, text, parse_mode=None): - sent_messages.append({"chat_id": chat_id, "text": text, "parse_mode": parse_mode}) - - fake_app = MagicMock() - fake_app.bot = FakeBot() - - channel = TelegramChannel(_make_config(), MessageBus()) - channel._app = fake_app - - # Long content without newlines but with spaces - content = "word " * 2000 # ~10000 chars - - await channel.send(OutboundMessage( - channel="telegram", - chat_id="123456", - content=content - )) - - assert len(sent_messages) >= 2 - - @pytest.mark.asyncio - async def test_send_forces_split_when_no_good_boundary(self, monkeypatch) -> None: - """When no newline or space, force split at max length.""" - sent_messages = [] - - class FakeBot: - async def send_message(self, chat_id, text, parse_mode=None): - sent_messages.append({"chat_id": chat_id, "text": text, "parse_mode": parse_mode}) - - fake_app = MagicMock() - fake_app.bot = FakeBot() - - channel = TelegramChannel(_make_config(), MessageBus()) - channel._app = fake_app - - # Long content without any spaces or newlines - content = "A" * 10000 - - await channel.send(OutboundMessage( - channel="telegram", - chat_id="123456", - content=content - )) - - assert len(sent_messages) >= 2 - # Verify all chunks combined equal original - combined = "".join(m["text"] for m in sent_messages) - assert combined == content - - @pytest.mark.asyncio - async def test_send_invalid_chat_id_logs_error(self, monkeypatch) -> None: - """Invalid chat_id should log error and not send.""" - sent_messages = [] - - class FakeBot: - async def send_message(self, chat_id, text, parse_mode=None): - sent_messages.append({"chat_id": chat_id, "text": text}) - - fake_app = MagicMock() - fake_app.bot = FakeBot() - - channel = TelegramChannel(_make_config(), MessageBus()) - channel._app = fake_app - - await channel.send(OutboundMessage( - channel="telegram", - chat_id="not-a-number", - content="Hello" - )) - - assert len(sent_messages) == 0 - - @pytest.mark.asyncio - async def test_send_html_parse_error_falls_back_to_plain_text(self, monkeypatch) -> None: - """When HTML parsing fails, fall back to plain text.""" - sent_messages = [] - call_count = 0 - - class FakeBot: - async def send_message(self, chat_id, text, parse_mode=None): - nonlocal call_count - call_count += 1 - if parse_mode == "HTML" and call_count == 1: - raise Exception("Bad markup") - sent_messages.append({"chat_id": chat_id, "text": text, "parse_mode": parse_mode}) - - fake_app = MagicMock() - fake_app.bot = FakeBot() - - channel = TelegramChannel(_make_config(), MessageBus()) - channel._app = fake_app - - await channel.send(OutboundMessage( - channel="telegram", - chat_id="123456", - content="Hello **world**" - )) - - # Should have 2 calls: first HTML (fails), second plain text (succeeds) - assert call_count == 2 - assert len(sent_messages) == 1 - assert sent_messages[0]["parse_mode"] is None # Plain text - assert "Hello **world**" in sent_messages[0]["text"] - - @pytest.mark.asyncio - async def test_send_not_running_warns(self, monkeypatch) -> None: - """If bot not running, log warning.""" - warning_logged = [] - - def mock_warning(msg, *args): - warning_logged.append(msg) - - monkeypatch.setattr("nanobot.channels.telegram.logger", MagicMock(warning=mock_warning)) - - channel = TelegramChannel(_make_config(), MessageBus()) - channel._app = None # Not running - - await channel.send(OutboundMessage( - channel="telegram", - chat_id="123456", - content="Hello" - )) - - assert any("not running" in str(m) for m in warning_logged) - - @pytest.mark.asyncio - async def test_send_stops_typing_indicator(self, monkeypatch) -> None: - """Sending message should stop typing indicator.""" - stopped_chats = [] - - class FakeBot: - async def send_message(self, chat_id, text, parse_mode=None): - pass - - fake_app = MagicMock() - fake_app.bot = FakeBot() - - channel = TelegramChannel(_make_config(), MessageBus()) - channel._app = fake_app - channel._stop_typing = lambda chat_id: stopped_chats.append(chat_id) - - await channel.send(OutboundMessage( - channel="telegram", - chat_id="123456", - content="Hello" - )) - - assert "123456" in stopped_chats - - -class TestTelegramChannelTyping: - """Tests for typing indicator functionality.""" - - @pytest.mark.asyncio - async def test_start_typing_creates_task(self) -> None: - channel = TelegramChannel(_make_config(), MessageBus()) - - # Mock _typing_loop to avoid actual async execution - channel._typing_loop = AsyncMock() - - channel._start_typing("123456") - - assert "123456" in channel._typing_tasks - assert not channel._typing_tasks["123456"].done() - - # Clean up - channel._stop_typing("123456") - - def test_stop_typing_cancels_task(self) -> None: - channel = TelegramChannel(_make_config(), MessageBus()) - - # Create a mock task - mock_task = MagicMock() - mock_task.done.return_value = False - channel._typing_tasks["123456"] = mock_task - - channel._stop_typing("123456") - - mock_task.cancel.assert_called_once() - assert "123456" not in channel._typing_tasks - - -class TestTelegramChannelMediaExtensions: - """Tests for media file extension detection.""" - - def test_get_extension_from_mime_type(self) -> None: - channel = TelegramChannel(_make_config(), MessageBus()) - - assert channel._get_extension("image", "image/jpeg") == ".jpg" - assert channel._get_extension("image", "image/png") == ".png" - assert channel._get_extension("image", "image/gif") == ".gif" - assert channel._get_extension("audio", "audio/ogg") == ".ogg" - assert channel._get_extension("audio", "audio/mpeg") == ".mp3" - - def test_get_extension_fallback_to_type(self) -> None: - channel = TelegramChannel(_make_config(), MessageBus()) - - assert channel._get_extension("image", None) == ".jpg" - assert channel._get_extension("voice", None) == ".ogg" - assert channel._get_extension("audio", None) == ".mp3" - - def test_get_extension_unknown_type(self) -> None: - channel = TelegramChannel(_make_config(), MessageBus()) - - assert channel._get_extension("unknown", None) == "" From ed5593bbe094683135078407acd2d263d056f6c3 Mon Sep 17 00:00:00 2001 From: Grzegorz Grasza Date: Mon, 16 Feb 2026 13:53:24 +0100 Subject: [PATCH 39/60] slack: use slackify-markdown for proper mrkdwn formatting Replace the regex-based Markdown-to-Slack converter with the slackify-markdown library, which uses a proper Markdown parser (markdown-it-py, already a dependency) to correctly handle headings, bold/italic, code blocks, links, bullet lists, and strikethrough. The regex approach didn't handle headings (###), bullet lists (* ), or code block protection, causing raw Markdown to leak into Slack messages. Net -40 lines. Assisted-by: Claude 4.6 Opus (Anthropic) --- nanobot/channels/slack.py | 47 +++------------------------------------ pyproject.toml | 1 + 2 files changed, 4 insertions(+), 44 deletions(-) diff --git a/nanobot/channels/slack.py b/nanobot/channels/slack.py index dd18e79..a56ee1a 100644 --- a/nanobot/channels/slack.py +++ b/nanobot/channels/slack.py @@ -10,6 +10,8 @@ from slack_sdk.socket_mode.request import SocketModeRequest from slack_sdk.socket_mode.response import SocketModeResponse from slack_sdk.web.async_client import AsyncWebClient +from slackify_markdown import slackify_markdown + from nanobot.bus.events import OutboundMessage from nanobot.bus.queue import MessageBus from nanobot.channels.base import BaseChannel @@ -84,7 +86,7 @@ class SlackChannel(BaseChannel): use_thread = thread_ts and channel_type != "im" await self._web_client.chat_postMessage( channel=msg.chat_id, - text=self._convert_markdown(msg.content) or "", + text=slackify_markdown(msg.content) if msg.content else "", thread_ts=thread_ts if use_thread else None, ) except Exception as e: @@ -204,46 +206,3 @@ class SlackChannel(BaseChannel): return text return re.sub(rf"<@{re.escape(self._bot_user_id)}>\s*", "", text).strip() - # Markdown → Slack mrkdwn formatting rules (order matters: longest markers first) - _MD_TO_SLACK = ( - (r'(?m)(^|[^\*])\*\*\*(.+?)\*\*\*([^\*]|$)', r'\1*_\2_*\3'), # ***bold italic*** - (r'(?m)(^|[^_])___(.+?)___([^_]|$)', r'\1*_\2_*\3'), # ___bold italic___ - (r'(?m)(^|[^\*])\*\*(.+?)\*\*([^\*]|$)', r'\1*\2*\3'), # **bold** - (r'(?m)(^|[^_])__(.+?)__([^_]|$)', r'\1*\2*\3'), # __bold__ - (r'(?m)(^|[^\*])\*(.+?)\*([^\*]|$)', r'\1_\2_\3'), # *italic* - (r'(?m)(^|[^~])~~(.+?)~~([^~]|$)', r'\1~\2~\3'), # ~~strike~~ - (r'(?m)(^|[^!])\[(.+?)\]\((http.+?)\)', r'\1<\3|\2>'), # [text](url) - (r'!\[.+?\]\((http.+?)(?:\s".*?")?\)', r'<\1>'), # ![alt](url) - ) - _TABLE_RE = re.compile(r'(?m)^\|.*?\|$(?:\n(?:\|\:?-{3,}\:?)*?\|$)(?:\n\|.*?\|$)*') - - def _convert_markdown(self, text: str) -> str: - """Convert standard Markdown to Slack mrkdwn format.""" - if not text: - return text - for pattern, repl in self._MD_TO_SLACK: - text = re.sub(pattern, repl, text) - return self._TABLE_RE.sub(self._convert_table, text) - - @staticmethod - def _convert_table(match: re.Match) -> str: - """Convert Markdown table to Slack quote + bullet format.""" - lines = [l.strip() for l in match.group(0).strip().split('\n') if l.strip()] - if len(lines) < 2: - return match.group(0) - - headers = [h.strip() for h in lines[0].strip('|').split('|')] - start = 2 if not re.search(r'[^|\-\s:]', lines[1]) else 1 - - result: list[str] = [] - for line in lines[start:]: - cells = [c.strip() for c in line.strip('|').split('|')] - cells = (cells + [''] * len(headers))[:len(headers)] - if not any(cells): - continue - result.append(f"> *{headers[0]}*: {cells[0] or '--'}") - for i, cell in enumerate(cells[1:], 1): - if cell and i < len(headers): - result.append(f" \u2022 *{headers[i]}*: {cell}") - result.append("") - return '\n'.join(result).rstrip() diff --git a/pyproject.toml b/pyproject.toml index f5fd60c..6261653 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,6 +36,7 @@ dependencies = [ "python-socketio>=5.11.0", "msgpack>=1.0.8", "slack-sdk>=3.26.0", + "slackify-markdown>=0.2.0", "qq-botpy>=1.0.0", "python-socks[asyncio]>=2.4.0", "prompt-toolkit>=3.0.0", From c9926153b263e0a451c37de89a75024ab5a2d4bf Mon Sep 17 00:00:00 2001 From: Grzegorz Grasza Date: Mon, 16 Feb 2026 14:03:33 +0100 Subject: [PATCH 40/60] Add table-to-text conversion for Slack messages Slack has no native table support, so Markdown tables are passed through verbatim by slackify-markdown. Pre-process tables into readable key-value rows before converting to mrkdwn. Assisted-by: Claude 4.6 Opus (Anthropic) --- nanobot/channels/slack.py | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/nanobot/channels/slack.py b/nanobot/channels/slack.py index a56ee1a..e5fff63 100644 --- a/nanobot/channels/slack.py +++ b/nanobot/channels/slack.py @@ -86,7 +86,7 @@ class SlackChannel(BaseChannel): use_thread = thread_ts and channel_type != "im" await self._web_client.chat_postMessage( channel=msg.chat_id, - text=slackify_markdown(msg.content) if msg.content else "", + text=self._to_mrkdwn(msg.content), thread_ts=thread_ts if use_thread else None, ) except Exception as e: @@ -206,3 +206,30 @@ class SlackChannel(BaseChannel): return text return re.sub(rf"<@{re.escape(self._bot_user_id)}>\s*", "", text).strip() + _TABLE_RE = re.compile(r"(?m)^\|.*\|$(?:\n\|[\s:|-]*\|$)(?:\n\|.*\|$)*") + + @classmethod + def _to_mrkdwn(cls, text: str) -> str: + """Convert Markdown to Slack mrkdwn, including tables.""" + if not text: + return "" + text = cls._TABLE_RE.sub(cls._convert_table, text) + return slackify_markdown(text) + + @staticmethod + def _convert_table(match: re.Match) -> str: + """Convert a Markdown table to a Slack-readable list.""" + lines = [ln.strip() for ln in match.group(0).strip().splitlines() if ln.strip()] + if len(lines) < 2: + return match.group(0) + headers = [h.strip() for h in lines[0].strip("|").split("|")] + start = 2 if re.fullmatch(r"[|\s:\-]+", lines[1]) else 1 + rows: list[str] = [] + for line in lines[start:]: + cells = [c.strip() for c in line.strip("|").split("|")] + cells = (cells + [""] * len(headers))[: len(headers)] + parts = [f"**{headers[i]}**: {cells[i]}" for i in range(len(headers)) if cells[i]] + if parts: + rows.append(" · ".join(parts)) + return "\n".join(rows) + From a219a91bc5e41a311d7e48b752aa489039ccd281 Mon Sep 17 00:00:00 2001 From: Re-bin Date: Mon, 16 Feb 2026 13:42:33 +0000 Subject: [PATCH 41/60] feat: support openclaw/clawhub skill metadata format --- nanobot/agent/skills.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nanobot/agent/skills.py b/nanobot/agent/skills.py index ead9f5b..5b841f3 100644 --- a/nanobot/agent/skills.py +++ b/nanobot/agent/skills.py @@ -167,10 +167,10 @@ class SkillsLoader: return content def _parse_nanobot_metadata(self, raw: str) -> dict: - """Parse nanobot metadata JSON from frontmatter.""" + """Parse skill metadata JSON from frontmatter (supports nanobot and openclaw keys).""" try: data = json.loads(raw) - return data.get("nanobot", {}) if isinstance(data, dict) else {} + return data.get("nanobot", data.get("openclaw", {})) if isinstance(data, dict) else {} except (json.JSONDecodeError, TypeError): return {} From 5033ac175987d08f8e28f39c1fe346a593d72d73 Mon Sep 17 00:00:00 2001 From: Darye <54469750+DaryeDev@users.noreply.github.com> Date: Mon, 16 Feb 2026 15:02:12 +0100 Subject: [PATCH 42/60] Added Github Copilot Provider --- nanobot/cli/commands.py | 2 +- nanobot/config/schema.py | 1 + nanobot/providers/registry.py | 19 +++++++++++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/nanobot/cli/commands.py b/nanobot/cli/commands.py index 235bfdc..affd421 100644 --- a/nanobot/cli/commands.py +++ b/nanobot/cli/commands.py @@ -292,7 +292,7 @@ def _make_provider(config: Config): if provider_name == "openai_codex" or model.startswith("openai-codex/"): return OpenAICodexProvider(default_model=model) - if not model.startswith("bedrock/") and not (p and p.api_key): + if not model.startswith("bedrock/") and not (p and p.api_key) and provider_name != "github_copilot": console.print("[red]Error: No API key configured.[/red]") console.print("Set one in ~/.nanobot/config.json under providers section") raise typer.Exit(1) diff --git a/nanobot/config/schema.py b/nanobot/config/schema.py index 15b6bb2..64609ec 100644 --- a/nanobot/config/schema.py +++ b/nanobot/config/schema.py @@ -193,6 +193,7 @@ class ProvidersConfig(BaseModel): minimax: ProviderConfig = Field(default_factory=ProviderConfig) aihubmix: ProviderConfig = Field(default_factory=ProviderConfig) # AiHubMix API gateway openai_codex: ProviderConfig = Field(default_factory=ProviderConfig) # OpenAI Codex (OAuth) + github_copilot: ProviderConfig = Field(default_factory=ProviderConfig) # Github Copilot (OAuth) class GatewayConfig(BaseModel): diff --git a/nanobot/providers/registry.py b/nanobot/providers/registry.py index 59af5e1..1e760d6 100644 --- a/nanobot/providers/registry.py +++ b/nanobot/providers/registry.py @@ -177,6 +177,25 @@ PROVIDERS: tuple[ProviderSpec, ...] = ( is_oauth=True, # OAuth-based authentication ), + # Github Copilot: uses OAuth, not API key. + ProviderSpec( + name="github_copilot", + keywords=("github_copilot", "copilot"), + env_key="", # OAuth-based, no API key + display_name="Github Copilot", + litellm_prefix="github_copilot", # github_copilot/model → github_copilot/model + skip_prefixes=("github_copilot/",), + env_extras=(), + is_gateway=False, + is_local=False, + detect_by_key_prefix="", + detect_by_base_keyword="", + default_api_base="", + strip_model_prefix=False, + model_overrides=(), + is_oauth=True, # OAuth-based authentication + ), + # DeepSeek: needs "deepseek/" prefix for LiteLLM routing. ProviderSpec( name="deepseek", From 23b7e1ef5e944a05653342a70efa2e1fbba9109f Mon Sep 17 00:00:00 2001 From: Darye <54469750+DaryeDev@users.noreply.github.com> Date: Mon, 16 Feb 2026 16:29:03 +0100 Subject: [PATCH 43/60] Handle media files (voice messages, audio, images, documents) on Telegram Channel --- nanobot/agent/tools/message.py | 12 +++++-- nanobot/channels/telegram.py | 64 +++++++++++++++++++++++++++++----- 2 files changed, 65 insertions(+), 11 deletions(-) diff --git a/nanobot/agent/tools/message.py b/nanobot/agent/tools/message.py index 347830f..3853725 100644 --- a/nanobot/agent/tools/message.py +++ b/nanobot/agent/tools/message.py @@ -52,6 +52,11 @@ class MessageTool(Tool): "chat_id": { "type": "string", "description": "Optional: target chat/user ID" + }, + "media": { + "type": "array", + "items": {"type": "string"}, + "description": "Optional: list of file paths to attach (images, audio, documents)" } }, "required": ["content"] @@ -62,6 +67,7 @@ class MessageTool(Tool): content: str, channel: str | None = None, chat_id: str | None = None, + media: list[str] | None = None, **kwargs: Any ) -> str: channel = channel or self._default_channel @@ -76,11 +82,13 @@ class MessageTool(Tool): msg = OutboundMessage( channel=channel, chat_id=chat_id, - content=content + content=content, + media=media or [] ) try: await self._send_callback(msg) - return f"Message sent to {channel}:{chat_id}" + media_info = f" with {len(media)} attachments" if media else "" + return f"Message sent to {channel}:{chat_id}{media_info}" except Exception as e: return f"Error sending message: {str(e)}" diff --git a/nanobot/channels/telegram.py b/nanobot/channels/telegram.py index c9978c2..8f135e4 100644 --- a/nanobot/channels/telegram.py +++ b/nanobot/channels/telegram.py @@ -198,6 +198,18 @@ class TelegramChannel(BaseChannel): await self._app.shutdown() self._app = None + def _get_media_type(self, path: str) -> str: + """Guess media type from file extension.""" + path = path.lower() + if path.endswith(('.jpg', '.jpeg', '.png', '.gif', '.webp')): + return "photo" + elif path.endswith('.ogg'): + return "voice" + elif path.endswith(('.mp3', '.m4a', '.wav', '.aac')): + return "audio" + else: + return "document" + async def send(self, msg: OutboundMessage) -> None: """Send a message through Telegram.""" if not self._app: @@ -212,16 +224,50 @@ class TelegramChannel(BaseChannel): logger.error(f"Invalid chat_id: {msg.chat_id}") return - for chunk in _split_message(msg.content): - try: - html = _markdown_to_telegram_html(chunk) - await self._app.bot.send_message(chat_id=chat_id, text=html, parse_mode="HTML") - except Exception as e: - logger.warning(f"HTML parse failed, falling back to plain text: {e}") + # Handle media files + if msg.media: + for media_path in msg.media: try: - await self._app.bot.send_message(chat_id=chat_id, text=chunk) - except Exception as e2: - logger.error(f"Error sending Telegram message: {e2}") + media_type = self._get_media_type(media_path) + + # Determine caption (only for first media or if explicitly set, + # but here we keep it simple: content is sent separately if media is present + # to avoid length issues, unless we want to attach it to the first media) + # For simplicity: send media first, then text if present. + # Or: if single media, attach text as caption. + + # Let's attach content as caption to the last media if single, + # otherwise send text separately. + + with open(media_path, 'rb') as f: + if media_type == "photo": + await self._app.bot.send_photo(chat_id=chat_id, photo=f) + elif media_type == "voice": + await self._app.bot.send_voice(chat_id=chat_id, voice=f) + elif media_type == "audio": + await self._app.bot.send_audio(chat_id=chat_id, audio=f) + else: + await self._app.bot.send_document(chat_id=chat_id, document=f) + + except Exception as e: + logger.error(f"Failed to send media {media_path}: {e}") + await self._app.bot.send_message( + chat_id=chat_id, + text=f"[Failed to send file: {media_path}]" + ) + + # Send text content if present + if msg.content and msg.content != "[empty message]": + for chunk in _split_message(msg.content): + try: + html = _markdown_to_telegram_html(chunk) + await self._app.bot.send_message(chat_id=chat_id, text=html, parse_mode="HTML") + except Exception as e: + logger.warning(f"HTML parse failed, falling back to plain text: {e}") + try: + await self._app.bot.send_message(chat_id=chat_id, text=chunk) + except Exception as e2: + logger.error(f"Error sending Telegram message: {e2}") async def _on_start(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: """Handle /start command.""" From ae903e983c2c0a7aac3f57fc9a66f7e13dbf4456 Mon Sep 17 00:00:00 2001 From: jopo Date: Mon, 16 Feb 2026 17:49:19 -0800 Subject: [PATCH 44/60] fix(cron): improve timezone scheduling and tz propagation --- nanobot/agent/tools/cron.py | 20 +++++++++++++++++--- nanobot/cli/commands.py | 22 +++++++++++++++++++--- nanobot/cron/service.py | 3 ++- 3 files changed, 38 insertions(+), 7 deletions(-) diff --git a/nanobot/agent/tools/cron.py b/nanobot/agent/tools/cron.py index 9f1ecdb..9dc31c2 100644 --- a/nanobot/agent/tools/cron.py +++ b/nanobot/agent/tools/cron.py @@ -50,6 +50,10 @@ class CronTool(Tool): "type": "string", "description": "Cron expression like '0 9 * * *' (for scheduled tasks)" }, + "tz": { + "type": "string", + "description": "IANA timezone for cron expressions (e.g. 'America/Vancouver')" + }, "at": { "type": "string", "description": "ISO datetime for one-time execution (e.g. '2026-02-12T10:30:00')" @@ -68,30 +72,40 @@ class CronTool(Tool): message: str = "", every_seconds: int | None = None, cron_expr: str | None = None, + tz: str | None = None, at: str | None = None, job_id: str | None = None, **kwargs: Any ) -> str: if action == "add": - return self._add_job(message, every_seconds, cron_expr, at) + return self._add_job(message, every_seconds, cron_expr, tz, at) elif action == "list": return self._list_jobs() elif action == "remove": return self._remove_job(job_id) return f"Unknown action: {action}" - def _add_job(self, message: str, every_seconds: int | None, cron_expr: str | None, at: str | None) -> str: + def _add_job( + self, + message: str, + every_seconds: int | None, + cron_expr: str | None, + tz: str | None, + at: str | None, + ) -> str: if not message: return "Error: message is required for add" if not self._channel or not self._chat_id: return "Error: no session context (channel/chat_id)" + if tz and not cron_expr: + return "Error: tz can only be used with cron_expr" # Build schedule delete_after = False if every_seconds: schedule = CronSchedule(kind="every", every_ms=every_seconds * 1000) elif cron_expr: - schedule = CronSchedule(kind="cron", expr=cron_expr) + schedule = CronSchedule(kind="cron", expr=cron_expr, tz=tz) elif at: from datetime import datetime dt = datetime.fromisoformat(at) diff --git a/nanobot/cli/commands.py b/nanobot/cli/commands.py index 235bfdc..3b58db5 100644 --- a/nanobot/cli/commands.py +++ b/nanobot/cli/commands.py @@ -719,21 +719,32 @@ def cron_list( table.add_column("Status") table.add_column("Next Run") + import datetime import time + from zoneinfo import ZoneInfo for job in jobs: # Format schedule if job.schedule.kind == "every": sched = f"every {(job.schedule.every_ms or 0) // 1000}s" elif job.schedule.kind == "cron": sched = job.schedule.expr or "" + if job.schedule.tz: + sched = f"{sched} ({job.schedule.tz})" else: sched = "one-time" # Format next run next_run = "" if job.state.next_run_at_ms: - next_time = time.strftime("%Y-%m-%d %H:%M", time.localtime(job.state.next_run_at_ms / 1000)) - next_run = next_time + ts = job.state.next_run_at_ms / 1000 + if job.schedule.kind == "cron" and job.schedule.tz: + try: + dt = datetime.fromtimestamp(ts, ZoneInfo(job.schedule.tz)) + next_run = dt.strftime("%Y-%m-%d %H:%M") + except Exception: + next_run = time.strftime("%Y-%m-%d %H:%M", time.localtime(ts)) + else: + next_run = time.strftime("%Y-%m-%d %H:%M", time.localtime(ts)) status = "[green]enabled[/green]" if job.enabled else "[dim]disabled[/dim]" @@ -748,6 +759,7 @@ def cron_add( message: str = typer.Option(..., "--message", "-m", help="Message for agent"), every: int = typer.Option(None, "--every", "-e", help="Run every N seconds"), cron_expr: str = typer.Option(None, "--cron", "-c", help="Cron expression (e.g. '0 9 * * *')"), + tz: str | None = typer.Option(None, "--tz", help="IANA timezone for cron (e.g. 'America/Vancouver')"), at: str = typer.Option(None, "--at", help="Run once at time (ISO format)"), deliver: bool = typer.Option(False, "--deliver", "-d", help="Deliver response to channel"), to: str = typer.Option(None, "--to", help="Recipient for delivery"), @@ -758,11 +770,15 @@ def cron_add( from nanobot.cron.service import CronService from nanobot.cron.types import CronSchedule + if tz and not cron_expr: + console.print("[red]Error: --tz can only be used with --cron[/red]") + raise typer.Exit(1) + # Determine schedule type if every: schedule = CronSchedule(kind="every", every_ms=every * 1000) elif cron_expr: - schedule = CronSchedule(kind="cron", expr=cron_expr) + schedule = CronSchedule(kind="cron", expr=cron_expr, tz=tz) elif at: import datetime dt = datetime.datetime.fromisoformat(at) diff --git a/nanobot/cron/service.py b/nanobot/cron/service.py index 4da845a..9fda214 100644 --- a/nanobot/cron/service.py +++ b/nanobot/cron/service.py @@ -32,7 +32,8 @@ def _compute_next_run(schedule: CronSchedule, now_ms: int) -> int | None: try: from croniter import croniter from zoneinfo import ZoneInfo - base_time = time.time() + # Use the caller-provided reference time for deterministic scheduling. + base_time = now_ms / 1000 tz = ZoneInfo(schedule.tz) if schedule.tz else datetime.now().astimezone().tzinfo base_dt = datetime.fromtimestamp(base_time, tz=tz) cron = croniter(schedule.expr, base_dt) From 778a93370a7cfaa17c5efdec09487d1ff67f8389 Mon Sep 17 00:00:00 2001 From: Darye <54469750+DaryeDev@users.noreply.github.com> Date: Tue, 17 Feb 2026 03:52:54 +0100 Subject: [PATCH 45/60] Enable Cron management on CLI Agent. --- nanobot/cli/commands.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/nanobot/cli/commands.py b/nanobot/cli/commands.py index 235bfdc..1f6b2f5 100644 --- a/nanobot/cli/commands.py +++ b/nanobot/cli/commands.py @@ -439,9 +439,10 @@ def agent( logs: bool = typer.Option(False, "--logs/--no-logs", help="Show nanobot runtime logs during chat"), ): """Interact with the agent directly.""" - from nanobot.config.loader import load_config + from nanobot.config.loader import load_config, get_data_dir from nanobot.bus.queue import MessageBus from nanobot.agent.loop import AgentLoop + from nanobot.cron.service import CronService from loguru import logger config = load_config() @@ -449,6 +450,10 @@ def agent( bus = MessageBus() provider = _make_provider(config) + # Create cron service for tool usage (no callback needed for CLI unless running) + cron_store_path = get_data_dir() / "cron" / "jobs.json" + cron = CronService(cron_store_path) + if logs: logger.enable("nanobot") else: @@ -465,6 +470,7 @@ def agent( memory_window=config.agents.defaults.memory_window, brave_api_key=config.tools.web.search.api_key or None, exec_config=config.tools.exec, + cron_service=cron, restrict_to_workspace=config.tools.restrict_to_workspace, mcp_servers=config.tools.mcp_servers, ) From 56bc8b567733480091d0f4eb4636d8bd31ded1ac Mon Sep 17 00:00:00 2001 From: nano bot Date: Tue, 17 Feb 2026 03:52:08 +0000 Subject: [PATCH 46/60] fix: avoid sending empty content entries in assistant messages --- nanobot/agent/context.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/nanobot/agent/context.py b/nanobot/agent/context.py index f460f2b..bed9e36 100644 --- a/nanobot/agent/context.py +++ b/nanobot/agent/context.py @@ -225,14 +225,20 @@ To recall past events, grep {workspace_path}/memory/HISTORY.md""" Returns: Updated message list. """ - msg: dict[str, Any] = {"role": "assistant", "content": content or ""} - + msg: dict[str, Any] = {"role": "assistant"} + + # Only include the content key when there is non-empty text. + # Some LLM backends reject empty text blocks, so omit the key + # to avoid sending empty content entries. + if content is not None and content != "": + msg["content"] = content + if tool_calls: msg["tool_calls"] = tool_calls - - # Thinking models reject history without this + + # Include reasoning content when provided (required by some thinking models) if reasoning_content: msg["reasoning_content"] = reasoning_content - + messages.append(msg) return messages From 5735f9bdcee8f7a415cad6b206dd315c1f94f5f1 Mon Sep 17 00:00:00 2001 From: Re-bin Date: Tue, 17 Feb 2026 08:14:16 +0000 Subject: [PATCH 47/60] feat: add ClawHub skill for searching and installing agent skills from the public registry --- nanobot/skills/README.md | 1 + nanobot/skills/clawhub/SKILL.md | 53 +++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 nanobot/skills/clawhub/SKILL.md diff --git a/nanobot/skills/README.md b/nanobot/skills/README.md index f0dcea7..5192796 100644 --- a/nanobot/skills/README.md +++ b/nanobot/skills/README.md @@ -21,4 +21,5 @@ The skill format and metadata structure follow OpenClaw's conventions to maintai | `weather` | Get weather info using wttr.in and Open-Meteo | | `summarize` | Summarize URLs, files, and YouTube videos | | `tmux` | Remote-control tmux sessions | +| `clawhub` | Search and install skills from ClawHub registry | | `skill-creator` | Create new skills | \ No newline at end of file diff --git a/nanobot/skills/clawhub/SKILL.md b/nanobot/skills/clawhub/SKILL.md new file mode 100644 index 0000000..7409bf4 --- /dev/null +++ b/nanobot/skills/clawhub/SKILL.md @@ -0,0 +1,53 @@ +--- +name: clawhub +description: Search and install agent skills from ClawHub, the public skill registry. +homepage: https://clawhub.ai +metadata: {"nanobot":{"emoji":"🦞"}} +--- + +# ClawHub + +Public skill registry for AI agents. Search by natural language (vector search). + +## When to use + +Use this skill when the user asks any of: +- "find a skill for …" +- "search for skills" +- "install a skill" +- "what skills are available?" +- "update my skills" + +## Search + +```bash +npx --yes clawhub@latest search "web scraping" --limit 5 +``` + +## Install + +```bash +npx --yes clawhub@latest install --workdir ~/.nanobot/workspace +``` + +Replace `` with the skill name from search results. This places the skill into `~/.nanobot/workspace/skills/`, where nanobot loads workspace skills from. Always include `--workdir`. + +## Update + +```bash +npx --yes clawhub@latest update --all --workdir ~/.nanobot/workspace +``` + +## List installed + +```bash +npx --yes clawhub@latest list --workdir ~/.nanobot/workspace +``` + +## Notes + +- Requires Node.js (`npx` comes with it). +- No API key needed for search and install. +- Login (`npx --yes clawhub@latest login`) is only required for publishing. +- `--workdir ~/.nanobot/workspace` is critical — without it, skills install to the current directory instead of the nanobot workspace. +- After install, remind the user to start a new session to load the skill. From 8509a81120201dd4783277f202698984fe9ee151 Mon Sep 17 00:00:00 2001 From: Re-bin Date: Tue, 17 Feb 2026 08:19:23 +0000 Subject: [PATCH 48/60] docs: update 15/16 Feb news --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 0584dd8..a27bbc8 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,8 @@ ## 📢 News +- **2026-02-16** 🦞 nanobot now integrates with [ClawHub](https://clawhub.ai) — search and install agent skills from the public registry. +- **2026-02-15** 🔑 nanobot now supports OpenAI Codex provider with OAuth login support. - **2026-02-14** 🔌 nanobot now supports MCP! See [MCP section](#mcp-model-context-protocol) for details. - **2026-02-13** 🎉 Released v0.1.3.post7 — includes security hardening and multiple improvements. All users are recommended to upgrade to the latest version. See [release notes](https://github.com/HKUDS/nanobot/releases/tag/v0.1.3.post7) for more details. - **2026-02-12** 🧠 Redesigned memory system — Less code, more reliable. Join the [discussion](https://github.com/HKUDS/nanobot/discussions/566) about it! From cf4dce5df05008b2da0b88445a1b4bd76e1aaf5a Mon Sep 17 00:00:00 2001 From: Re-bin Date: Tue, 17 Feb 2026 08:20:50 +0000 Subject: [PATCH 49/60] docs: update clawhub news --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a27bbc8..38afa82 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ ## 📢 News -- **2026-02-16** 🦞 nanobot now integrates with [ClawHub](https://clawhub.ai) — search and install agent skills from the public registry. +- **2026-02-16** 🦞 nanobot now integrates a [ClawHub](https://clawhub.ai) skill — search and install public agent skills. - **2026-02-15** 🔑 nanobot now supports OpenAI Codex provider with OAuth login support. - **2026-02-14** 🔌 nanobot now supports MCP! See [MCP section](#mcp-model-context-protocol) for details. - **2026-02-13** 🎉 Released v0.1.3.post7 — includes security hardening and multiple improvements. All users are recommended to upgrade to the latest version. See [release notes](https://github.com/HKUDS/nanobot/releases/tag/v0.1.3.post7) for more details. From 6bae6a617f7130e0a1021811b8cd8b379c2c0820 Mon Sep 17 00:00:00 2001 From: Re-bin Date: Tue, 17 Feb 2026 08:30:52 +0000 Subject: [PATCH 50/60] fix(cron): fix timezone display bug, add tz validation and skill docs --- README.md | 2 +- nanobot/agent/tools/cron.py | 6 ++++++ nanobot/cli/commands.py | 17 ++++++----------- nanobot/cron/service.py | 2 +- nanobot/skills/cron/SKILL.md | 10 ++++++++++ 5 files changed, 24 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 38afa82..de517d7 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ ⚡️ Delivers core agent functionality in just **~4,000** lines of code — **99% smaller** than Clawdbot's 430k+ lines. -📏 Real-time line count: **3,668 lines** (run `bash core_agent_lines.sh` to verify anytime) +📏 Real-time line count: **3,689 lines** (run `bash core_agent_lines.sh` to verify anytime) ## 📢 News diff --git a/nanobot/agent/tools/cron.py b/nanobot/agent/tools/cron.py index 9dc31c2..b10e34b 100644 --- a/nanobot/agent/tools/cron.py +++ b/nanobot/agent/tools/cron.py @@ -99,6 +99,12 @@ class CronTool(Tool): return "Error: no session context (channel/chat_id)" if tz and not cron_expr: return "Error: tz can only be used with cron_expr" + if tz: + from zoneinfo import ZoneInfo + try: + ZoneInfo(tz) + except (KeyError, Exception): + return f"Error: unknown timezone '{tz}'" # Build schedule delete_after = False diff --git a/nanobot/cli/commands.py b/nanobot/cli/commands.py index 3b58db5..3798813 100644 --- a/nanobot/cli/commands.py +++ b/nanobot/cli/commands.py @@ -719,17 +719,15 @@ def cron_list( table.add_column("Status") table.add_column("Next Run") - import datetime import time + from datetime import datetime as _dt from zoneinfo import ZoneInfo for job in jobs: # Format schedule if job.schedule.kind == "every": sched = f"every {(job.schedule.every_ms or 0) // 1000}s" elif job.schedule.kind == "cron": - sched = job.schedule.expr or "" - if job.schedule.tz: - sched = f"{sched} ({job.schedule.tz})" + sched = f"{job.schedule.expr or ''} ({job.schedule.tz})" if job.schedule.tz else (job.schedule.expr or "") else: sched = "one-time" @@ -737,13 +735,10 @@ def cron_list( next_run = "" if job.state.next_run_at_ms: ts = job.state.next_run_at_ms / 1000 - if job.schedule.kind == "cron" and job.schedule.tz: - try: - dt = datetime.fromtimestamp(ts, ZoneInfo(job.schedule.tz)) - next_run = dt.strftime("%Y-%m-%d %H:%M") - except Exception: - next_run = time.strftime("%Y-%m-%d %H:%M", time.localtime(ts)) - else: + try: + tz = ZoneInfo(job.schedule.tz) if job.schedule.tz else None + next_run = _dt.fromtimestamp(ts, tz).strftime("%Y-%m-%d %H:%M") + except Exception: next_run = time.strftime("%Y-%m-%d %H:%M", time.localtime(ts)) status = "[green]enabled[/green]" if job.enabled else "[dim]disabled[/dim]" diff --git a/nanobot/cron/service.py b/nanobot/cron/service.py index 9fda214..14666e8 100644 --- a/nanobot/cron/service.py +++ b/nanobot/cron/service.py @@ -32,7 +32,7 @@ def _compute_next_run(schedule: CronSchedule, now_ms: int) -> int | None: try: from croniter import croniter from zoneinfo import ZoneInfo - # Use the caller-provided reference time for deterministic scheduling. + # Use caller-provided reference time for deterministic scheduling base_time = now_ms / 1000 tz = ZoneInfo(schedule.tz) if schedule.tz else datetime.now().astimezone().tzinfo base_dt = datetime.fromtimestamp(base_time, tz=tz) diff --git a/nanobot/skills/cron/SKILL.md b/nanobot/skills/cron/SKILL.md index 7db25d8..cc3516e 100644 --- a/nanobot/skills/cron/SKILL.md +++ b/nanobot/skills/cron/SKILL.md @@ -30,6 +30,11 @@ One-time scheduled task (compute ISO datetime from current time): cron(action="add", message="Remind me about the meeting", at="") ``` +Timezone-aware cron: +``` +cron(action="add", message="Morning standup", cron_expr="0 9 * * 1-5", tz="America/Vancouver") +``` + List/remove: ``` cron(action="list") @@ -44,4 +49,9 @@ cron(action="remove", job_id="abc123") | every hour | every_seconds: 3600 | | every day at 8am | cron_expr: "0 8 * * *" | | weekdays at 5pm | cron_expr: "0 17 * * 1-5" | +| 9am Vancouver time daily | cron_expr: "0 9 * * *", tz: "America/Vancouver" | | at a specific time | at: ISO datetime string (compute from current time) | + +## Timezone + +Use `tz` with `cron_expr` to schedule in a specific IANA timezone. Without `tz`, the server's local timezone is used. From f5c5b13ff03316b925bd37b58adce144d4153c92 Mon Sep 17 00:00:00 2001 From: Re-bin Date: Tue, 17 Feb 2026 08:41:09 +0000 Subject: [PATCH 51/60] refactor: use is_oauth flag instead of hardcoded provider name check --- README.md | 25 +++++++++++++------------ nanobot/cli/commands.py | 4 +++- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index de517d7..0e20449 100644 --- a/README.md +++ b/README.md @@ -145,19 +145,19 @@ That's it! You have a working AI assistant in 2 minutes. ## 💬 Chat Apps -Talk to your nanobot through Telegram, Discord, WhatsApp, Feishu, Mochat, DingTalk, Slack, Email, or QQ — anytime, anywhere. +Connect nanobot to your favorite chat platform. -| Channel | Setup | -|---------|-------| -| **Telegram** | Easy (just a token) | -| **Discord** | Easy (bot token + intents) | -| **WhatsApp** | Medium (scan QR) | -| **Feishu** | Medium (app credentials) | -| **Mochat** | Medium (claw token + websocket) | -| **DingTalk** | Medium (app credentials) | -| **Slack** | Medium (bot + app tokens) | -| **Email** | Medium (IMAP/SMTP credentials) | -| **QQ** | Easy (app credentials) | +| Channel | What you need | +|---------|---------------| +| **Telegram** | Bot token from @BotFather | +| **Discord** | Bot token + Message Content intent | +| **WhatsApp** | QR code scan | +| **Feishu** | App ID + App Secret | +| **Mochat** | Claw token (auto-setup available) | +| **DingTalk** | App Key + App Secret | +| **Slack** | Bot token + App-Level token | +| **Email** | IMAP/SMTP credentials | +| **QQ** | App ID + App Secret |
Telegram (Recommended) @@ -588,6 +588,7 @@ Config file: `~/.nanobot/config.json` | `zhipu` | LLM (Zhipu GLM) | [open.bigmodel.cn](https://open.bigmodel.cn) | | `vllm` | LLM (local, any OpenAI-compatible server) | — | | `openai_codex` | LLM (Codex, OAuth) | `nanobot provider login openai-codex` | +| `github_copilot` | LLM (GitHub Copilot, OAuth) | Requires [GitHub Copilot](https://github.com/features/copilot) subscription |
OpenAI Codex (OAuth) diff --git a/nanobot/cli/commands.py b/nanobot/cli/commands.py index a24929f..b61d9aa 100644 --- a/nanobot/cli/commands.py +++ b/nanobot/cli/commands.py @@ -292,7 +292,9 @@ def _make_provider(config: Config): if provider_name == "openai_codex" or model.startswith("openai-codex/"): return OpenAICodexProvider(default_model=model) - if not model.startswith("bedrock/") and not (p and p.api_key) and provider_name != "github_copilot": + from nanobot.providers.registry import find_by_name + spec = find_by_name(provider_name) + if not model.startswith("bedrock/") and not (p and p.api_key) and not (spec and spec.is_oauth): console.print("[red]Error: No API key configured.[/red]") console.print("Set one in ~/.nanobot/config.json under providers section") raise typer.Exit(1) From 1db05c881ddf7b3958edda7f99ff02cd49581f5f Mon Sep 17 00:00:00 2001 From: Re-bin Date: Tue, 17 Feb 2026 08:59:05 +0000 Subject: [PATCH 52/60] fix: omit empty content in assistant messages --- nanobot/agent/context.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/nanobot/agent/context.py b/nanobot/agent/context.py index bed9e36..cfd6318 100644 --- a/nanobot/agent/context.py +++ b/nanobot/agent/context.py @@ -227,10 +227,8 @@ To recall past events, grep {workspace_path}/memory/HISTORY.md""" """ msg: dict[str, Any] = {"role": "assistant"} - # Only include the content key when there is non-empty text. - # Some LLM backends reject empty text blocks, so omit the key - # to avoid sending empty content entries. - if content is not None and content != "": + # Omit empty content — some backends reject empty text blocks + if content: msg["content"] = content if tool_calls: From 5ad9c837df8879717a01760530b830dd3c67cd7b Mon Sep 17 00:00:00 2001 From: Re-bin Date: Tue, 17 Feb 2026 10:37:55 +0000 Subject: [PATCH 53/60] refactor: clean up telegram media sending logic --- nanobot/channels/telegram.py | 63 ++++++++++++++---------------------- 1 file changed, 24 insertions(+), 39 deletions(-) diff --git a/nanobot/channels/telegram.py b/nanobot/channels/telegram.py index 8f135e4..39924b3 100644 --- a/nanobot/channels/telegram.py +++ b/nanobot/channels/telegram.py @@ -198,17 +198,17 @@ class TelegramChannel(BaseChannel): await self._app.shutdown() self._app = None - def _get_media_type(self, path: str) -> str: + @staticmethod + def _get_media_type(path: str) -> str: """Guess media type from file extension.""" - path = path.lower() - if path.endswith(('.jpg', '.jpeg', '.png', '.gif', '.webp')): + ext = path.rsplit(".", 1)[-1].lower() if "." in path else "" + if ext in ("jpg", "jpeg", "png", "gif", "webp"): return "photo" - elif path.endswith('.ogg'): + if ext == "ogg": return "voice" - elif path.endswith(('.mp3', '.m4a', '.wav', '.aac')): + if ext in ("mp3", "m4a", "wav", "aac"): return "audio" - else: - return "document" + return "document" async def send(self, msg: OutboundMessage) -> None: """Send a message through Telegram.""" @@ -224,39 +224,24 @@ class TelegramChannel(BaseChannel): logger.error(f"Invalid chat_id: {msg.chat_id}") return - # Handle media files - if msg.media: - for media_path in msg.media: - try: - media_type = self._get_media_type(media_path) - - # Determine caption (only for first media or if explicitly set, - # but here we keep it simple: content is sent separately if media is present - # to avoid length issues, unless we want to attach it to the first media) - # For simplicity: send media first, then text if present. - # Or: if single media, attach text as caption. - - # Let's attach content as caption to the last media if single, - # otherwise send text separately. - - with open(media_path, 'rb') as f: - if media_type == "photo": - await self._app.bot.send_photo(chat_id=chat_id, photo=f) - elif media_type == "voice": - await self._app.bot.send_voice(chat_id=chat_id, voice=f) - elif media_type == "audio": - await self._app.bot.send_audio(chat_id=chat_id, audio=f) - else: - await self._app.bot.send_document(chat_id=chat_id, document=f) - - except Exception as e: - logger.error(f"Failed to send media {media_path}: {e}") - await self._app.bot.send_message( - chat_id=chat_id, - text=f"[Failed to send file: {media_path}]" - ) + # Send media files + for media_path in (msg.media or []): + try: + media_type = self._get_media_type(media_path) + sender = { + "photo": self._app.bot.send_photo, + "voice": self._app.bot.send_voice, + "audio": self._app.bot.send_audio, + }.get(media_type, self._app.bot.send_document) + param = "photo" if media_type == "photo" else media_type if media_type in ("voice", "audio") else "document" + with open(media_path, 'rb') as f: + await sender(chat_id=chat_id, **{param: f}) + except Exception as e: + filename = media_path.rsplit("/", 1)[-1] + logger.error(f"Failed to send media {media_path}: {e}") + await self._app.bot.send_message(chat_id=chat_id, text=f"[Failed to send: {filename}]") - # Send text content if present + # Send text content if msg.content and msg.content != "[empty message]": for chunk in _split_message(msg.content): try: From c03f2b670bda14557a75e77865b8a89a6670c409 Mon Sep 17 00:00:00 2001 From: Rajasimman S Date: Tue, 17 Feb 2026 18:50:03 +0530 Subject: [PATCH 54/60] =?UTF-8?q?=F0=9F=90=B3=20feat:=20add=20Docker=20Com?= =?UTF-8?q?pose=20support=20for=20easy=20deployment?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add docker-compose.yml with gateway and CLI services, resource limits, and comprehensive documentation for Docker Compose usage. --- README.md | 33 +++++++++++++++++++++++++++++++++ docker-compose.yml | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 docker-compose.yml diff --git a/README.md b/README.md index 0e20449..f5a92fd 100644 --- a/README.md +++ b/README.md @@ -811,6 +811,39 @@ nanobot cron remove > [!TIP] > The `-v ~/.nanobot:/root/.nanobot` flag mounts your local config directory into the container, so your config and workspace persist across container restarts. +### Using Docker Compose (Recommended) + +The easiest way to run nanobot with Docker: + +```bash +# 1. Initialize config (first time only) +docker compose run --rm nanobot-cli onboard + +# 2. Edit config to add API keys +vim ~/.nanobot/config.json + +# 3. Start gateway service +docker compose up -d nanobot-gateway + +# 4. Check logs +docker compose logs -f nanobot-gateway + +# 5. Run CLI commands +docker compose run --rm nanobot-cli status +docker compose run --rm nanobot-cli agent -m "Hello!" + +# 6. Stop services +docker compose down +``` + +**Features:** +- ✅ Resource limits (1 CPU, 1GB memory) +- ✅ Auto-restart on failure +- ✅ Shared configuration using YAML anchors +- ✅ Separate CLI profile for on-demand commands + +### Using Docker directly + Build and run nanobot in a container: ```bash diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..446f5e3 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,32 @@ +x-common-config: &common-config + build: + context: . + dockerfile: Dockerfile + volumes: + - ~/.nanobot:/root/.nanobot + +services: + nanobot-gateway: + container_name: nanobot-gateway + <<: *common-config + command: ["gateway"] + restart: unless-stopped + ports: + - 18790:18790 + deploy: + resources: + limits: + cpus: '1' + memory: 1G + reservations: + cpus: '0.25' + memory: 256M + + nanobot-cli: + container_name: nanobot-cli + <<: *common-config + profiles: + - cli + command: ["status"] + stdin_open: true + tty: true From 4d4d6299283f51c31357984e3a34d75518fd0501 Mon Sep 17 00:00:00 2001 From: Simon Guigui Date: Tue, 17 Feb 2026 15:19:21 +0100 Subject: [PATCH 55/60] fix(config): mcpServers env variables should not be converted to snake case --- nanobot/config/loader.py | 55 ++++---------------- nanobot/config/schema.py | 109 ++++++++++++++++++++++++++------------- 2 files changed, 83 insertions(+), 81 deletions(-) diff --git a/nanobot/config/loader.py b/nanobot/config/loader.py index fd7d1e8..560c1f5 100644 --- a/nanobot/config/loader.py +++ b/nanobot/config/loader.py @@ -2,7 +2,6 @@ import json from pathlib import Path -from typing import Any from nanobot.config.schema import Config @@ -21,43 +20,41 @@ def get_data_dir() -> Path: def load_config(config_path: Path | None = None) -> Config: """ Load configuration from file or create default. - + Args: config_path: Optional path to config file. Uses default if not provided. - + Returns: Loaded configuration object. """ path = config_path or get_config_path() - + if path.exists(): try: with open(path) as f: data = json.load(f) data = _migrate_config(data) - return Config.model_validate(convert_keys(data)) + return Config.model_validate(data) except (json.JSONDecodeError, ValueError) as e: print(f"Warning: Failed to load config from {path}: {e}") print("Using default configuration.") - + return Config() def save_config(config: Config, config_path: Path | None = None) -> None: """ Save configuration to file. - + Args: config: Configuration to save. config_path: Optional path to save to. Uses default if not provided. """ path = config_path or get_config_path() path.parent.mkdir(parents=True, exist_ok=True) - - # Convert to camelCase format - data = config.model_dump() - data = convert_to_camel(data) - + + data = config.model_dump(by_alias=True) + with open(path, "w") as f: json.dump(data, f, indent=2) @@ -70,37 +67,3 @@ def _migrate_config(data: dict) -> dict: if "restrictToWorkspace" in exec_cfg and "restrictToWorkspace" not in tools: tools["restrictToWorkspace"] = exec_cfg.pop("restrictToWorkspace") return data - - -def convert_keys(data: Any) -> Any: - """Convert camelCase keys to snake_case for Pydantic.""" - if isinstance(data, dict): - return {camel_to_snake(k): convert_keys(v) for k, v in data.items()} - if isinstance(data, list): - return [convert_keys(item) for item in data] - return data - - -def convert_to_camel(data: Any) -> Any: - """Convert snake_case keys to camelCase.""" - if isinstance(data, dict): - return {snake_to_camel(k): convert_to_camel(v) for k, v in data.items()} - if isinstance(data, list): - return [convert_to_camel(item) for item in data] - return data - - -def camel_to_snake(name: str) -> str: - """Convert camelCase to snake_case.""" - result = [] - for i, char in enumerate(name): - if char.isupper() and i > 0: - result.append("_") - result.append(char.lower()) - return "".join(result) - - -def snake_to_camel(name: str) -> str: - """Convert snake_case to camelCase.""" - components = name.split("_") - return components[0] + "".join(x.title() for x in components[1:]) diff --git a/nanobot/config/schema.py b/nanobot/config/schema.py index 64609ec..0786080 100644 --- a/nanobot/config/schema.py +++ b/nanobot/config/schema.py @@ -2,27 +2,39 @@ from pathlib import Path from pydantic import BaseModel, Field, ConfigDict +from pydantic.alias_generators import to_camel from pydantic_settings import BaseSettings -class WhatsAppConfig(BaseModel): +class Base(BaseModel): + """Base model that accepts both camelCase and snake_case keys.""" + + model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True) + + +class WhatsAppConfig(Base): """WhatsApp channel configuration.""" + enabled: bool = False bridge_url: str = "ws://localhost:3001" bridge_token: str = "" # Shared token for bridge auth (optional, recommended) allow_from: list[str] = Field(default_factory=list) # Allowed phone numbers -class TelegramConfig(BaseModel): +class TelegramConfig(Base): """Telegram channel configuration.""" + enabled: bool = False token: str = "" # Bot token from @BotFather allow_from: list[str] = Field(default_factory=list) # Allowed user IDs or usernames - proxy: str | None = None # HTTP/SOCKS5 proxy URL, e.g. "http://127.0.0.1:7890" or "socks5://127.0.0.1:1080" + proxy: str | None = ( + None # HTTP/SOCKS5 proxy URL, e.g. "http://127.0.0.1:7890" or "socks5://127.0.0.1:1080" + ) -class FeishuConfig(BaseModel): +class FeishuConfig(Base): """Feishu/Lark channel configuration using WebSocket long connection.""" + enabled: bool = False app_id: str = "" # App ID from Feishu Open Platform app_secret: str = "" # App Secret from Feishu Open Platform @@ -31,24 +43,28 @@ class FeishuConfig(BaseModel): allow_from: list[str] = Field(default_factory=list) # Allowed user open_ids -class DingTalkConfig(BaseModel): +class DingTalkConfig(Base): """DingTalk channel configuration using Stream mode.""" + enabled: bool = False client_id: str = "" # AppKey client_secret: str = "" # AppSecret allow_from: list[str] = Field(default_factory=list) # Allowed staff_ids -class DiscordConfig(BaseModel): +class DiscordConfig(Base): """Discord channel configuration.""" + enabled: bool = False token: str = "" # Bot token from Discord Developer Portal allow_from: list[str] = Field(default_factory=list) # Allowed user IDs gateway_url: str = "wss://gateway.discord.gg/?v=10&encoding=json" intents: int = 37377 # GUILDS + GUILD_MESSAGES + DIRECT_MESSAGES + MESSAGE_CONTENT -class EmailConfig(BaseModel): + +class EmailConfig(Base): """Email channel configuration (IMAP inbound + SMTP outbound).""" + enabled: bool = False consent_granted: bool = False # Explicit owner permission to access mailbox data @@ -70,7 +86,9 @@ class EmailConfig(BaseModel): from_address: str = "" # Behavior - auto_reply_enabled: bool = True # If false, inbound email is read but no automatic reply is sent + auto_reply_enabled: bool = ( + True # If false, inbound email is read but no automatic reply is sent + ) poll_interval_seconds: int = 30 mark_seen: bool = True max_body_chars: int = 12000 @@ -78,18 +96,21 @@ class EmailConfig(BaseModel): allow_from: list[str] = Field(default_factory=list) # Allowed sender email addresses -class MochatMentionConfig(BaseModel): +class MochatMentionConfig(Base): """Mochat mention behavior configuration.""" + require_in_groups: bool = False -class MochatGroupRule(BaseModel): +class MochatGroupRule(Base): """Mochat per-group mention requirement.""" + require_mention: bool = False -class MochatConfig(BaseModel): +class MochatConfig(Base): """Mochat channel configuration.""" + enabled: bool = False base_url: str = "https://mochat.io" socket_url: str = "" @@ -114,15 +135,17 @@ class MochatConfig(BaseModel): reply_delay_ms: int = 120000 -class SlackDMConfig(BaseModel): +class SlackDMConfig(Base): """Slack DM policy configuration.""" + enabled: bool = True policy: str = "open" # "open" or "allowlist" allow_from: list[str] = Field(default_factory=list) # Allowed Slack user IDs -class SlackConfig(BaseModel): +class SlackConfig(Base): """Slack channel configuration.""" + enabled: bool = False mode: str = "socket" # "socket" supported webhook_path: str = "/slack/events" @@ -134,16 +157,20 @@ class SlackConfig(BaseModel): dm: SlackDMConfig = Field(default_factory=SlackDMConfig) -class QQConfig(BaseModel): +class QQConfig(Base): """QQ channel configuration using botpy SDK.""" + enabled: bool = False app_id: str = "" # 机器人 ID (AppID) from q.qq.com secret: str = "" # 机器人密钥 (AppSecret) from q.qq.com - allow_from: list[str] = Field(default_factory=list) # Allowed user openids (empty = public access) + allow_from: list[str] = Field( + default_factory=list + ) # Allowed user openids (empty = public access) -class ChannelsConfig(BaseModel): +class ChannelsConfig(Base): """Configuration for chat channels.""" + whatsapp: WhatsAppConfig = Field(default_factory=WhatsAppConfig) telegram: TelegramConfig = Field(default_factory=TelegramConfig) discord: DiscordConfig = Field(default_factory=DiscordConfig) @@ -155,8 +182,9 @@ class ChannelsConfig(BaseModel): qq: QQConfig = Field(default_factory=QQConfig) -class AgentDefaults(BaseModel): +class AgentDefaults(Base): """Default agent configuration.""" + workspace: str = "~/.nanobot/workspace" model: str = "anthropic/claude-opus-4-5" max_tokens: int = 8192 @@ -165,20 +193,23 @@ class AgentDefaults(BaseModel): memory_window: int = 50 -class AgentsConfig(BaseModel): +class AgentsConfig(Base): """Agent configuration.""" + defaults: AgentDefaults = Field(default_factory=AgentDefaults) -class ProviderConfig(BaseModel): +class ProviderConfig(Base): """LLM provider configuration.""" + api_key: str = "" api_base: str | None = None extra_headers: dict[str, str] | None = None # Custom headers (e.g. APP-Code for AiHubMix) -class ProvidersConfig(BaseModel): +class ProvidersConfig(Base): """Configuration for LLM providers.""" + custom: ProviderConfig = Field(default_factory=ProviderConfig) # Any OpenAI-compatible endpoint anthropic: ProviderConfig = Field(default_factory=ProviderConfig) openai: ProviderConfig = Field(default_factory=ProviderConfig) @@ -196,38 +227,44 @@ class ProvidersConfig(BaseModel): github_copilot: ProviderConfig = Field(default_factory=ProviderConfig) # Github Copilot (OAuth) -class GatewayConfig(BaseModel): +class GatewayConfig(Base): """Gateway/server configuration.""" + host: str = "0.0.0.0" port: int = 18790 -class WebSearchConfig(BaseModel): +class WebSearchConfig(Base): """Web search tool configuration.""" + api_key: str = "" # Brave Search API key max_results: int = 5 -class WebToolsConfig(BaseModel): +class WebToolsConfig(Base): """Web tools configuration.""" + search: WebSearchConfig = Field(default_factory=WebSearchConfig) -class ExecToolConfig(BaseModel): +class ExecToolConfig(Base): """Shell exec tool configuration.""" + timeout: int = 60 -class MCPServerConfig(BaseModel): +class MCPServerConfig(Base): """MCP server connection configuration (stdio or HTTP).""" + command: str = "" # Stdio: command to run (e.g. "npx") args: list[str] = Field(default_factory=list) # Stdio: command arguments env: dict[str, str] = Field(default_factory=dict) # Stdio: extra env vars url: str = "" # HTTP: streamable HTTP endpoint URL -class ToolsConfig(BaseModel): +class ToolsConfig(Base): """Tools configuration.""" + web: WebToolsConfig = Field(default_factory=WebToolsConfig) exec: ExecToolConfig = Field(default_factory=ExecToolConfig) restrict_to_workspace: bool = False # If true, restrict all tool access to workspace directory @@ -236,20 +273,24 @@ class ToolsConfig(BaseModel): class Config(BaseSettings): """Root configuration for nanobot.""" + agents: AgentsConfig = Field(default_factory=AgentsConfig) channels: ChannelsConfig = Field(default_factory=ChannelsConfig) providers: ProvidersConfig = Field(default_factory=ProvidersConfig) gateway: GatewayConfig = Field(default_factory=GatewayConfig) tools: ToolsConfig = Field(default_factory=ToolsConfig) - + @property def workspace_path(self) -> Path: """Get expanded workspace path.""" return Path(self.agents.defaults.workspace).expanduser() - - def _match_provider(self, model: str | None = None) -> tuple["ProviderConfig | None", str | None]: + + def _match_provider( + self, model: str | None = None + ) -> tuple["ProviderConfig | None", str | None]: """Match provider config and its registry name. Returns (config, spec_name).""" from nanobot.providers.registry import PROVIDERS + model_lower = (model or self.agents.defaults.model).lower() # Match by keyword (order follows PROVIDERS registry) @@ -283,10 +324,11 @@ class Config(BaseSettings): """Get API key for the given model. Falls back to first available key.""" p = self.get_provider(model) return p.api_key if p else None - + def get_api_base(self, model: str | None = None) -> str | None: """Get API base URL for the given model. Applies default URLs for known gateways.""" from nanobot.providers.registry import find_by_name + p, name = self._match_provider(model) if p and p.api_base: return p.api_base @@ -298,8 +340,5 @@ class Config(BaseSettings): if spec and spec.is_gateway and spec.default_api_base: return spec.default_api_base return None - - model_config = ConfigDict( - env_prefix="NANOBOT_", - env_nested_delimiter="__" - ) + + model_config = ConfigDict(env_prefix="NANOBOT_", env_nested_delimiter="__") From 941c3d98264303c7494b98c306c2696499bdc45a Mon Sep 17 00:00:00 2001 From: Re-bin Date: Tue, 17 Feb 2026 17:34:24 +0000 Subject: [PATCH 56/60] style: restore single-line formatting for readability --- nanobot/config/schema.py | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/nanobot/config/schema.py b/nanobot/config/schema.py index 0786080..76ec74d 100644 --- a/nanobot/config/schema.py +++ b/nanobot/config/schema.py @@ -27,9 +27,7 @@ class TelegramConfig(Base): enabled: bool = False token: str = "" # Bot token from @BotFather allow_from: list[str] = Field(default_factory=list) # Allowed user IDs or usernames - proxy: str | None = ( - None # HTTP/SOCKS5 proxy URL, e.g. "http://127.0.0.1:7890" or "socks5://127.0.0.1:1080" - ) + proxy: str | None = None # HTTP/SOCKS5 proxy URL, e.g. "http://127.0.0.1:7890" or "socks5://127.0.0.1:1080" class FeishuConfig(Base): @@ -86,9 +84,7 @@ class EmailConfig(Base): from_address: str = "" # Behavior - auto_reply_enabled: bool = ( - True # If false, inbound email is read but no automatic reply is sent - ) + auto_reply_enabled: bool = True # If false, inbound email is read but no automatic reply is sent poll_interval_seconds: int = 30 mark_seen: bool = True max_body_chars: int = 12000 @@ -163,9 +159,7 @@ class QQConfig(Base): enabled: bool = False app_id: str = "" # 机器人 ID (AppID) from q.qq.com secret: str = "" # 机器人密钥 (AppSecret) from q.qq.com - allow_from: list[str] = Field( - default_factory=list - ) # Allowed user openids (empty = public access) + allow_from: list[str] = Field(default_factory=list) # Allowed user openids (empty = public access) class ChannelsConfig(Base): @@ -285,9 +279,7 @@ class Config(BaseSettings): """Get expanded workspace path.""" return Path(self.agents.defaults.workspace).expanduser() - def _match_provider( - self, model: str | None = None - ) -> tuple["ProviderConfig | None", str | None]: + def _match_provider(self, model: str | None = None) -> tuple["ProviderConfig | None", str | None]: """Match provider config and its registry name. Returns (config, spec_name).""" from nanobot.providers.registry import PROVIDERS From aad1df5b9b13f8bd0e233af7cc26cc47e0615ff4 Mon Sep 17 00:00:00 2001 From: Re-bin Date: Tue, 17 Feb 2026 17:55:48 +0000 Subject: [PATCH 57/60] Simplify Docker Compose docs and remove fixed CLI container name --- README.md | 39 ++++++++++----------------------------- docker-compose.yml | 1 - 2 files changed, 10 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index f5a92fd..96ff557 100644 --- a/README.md +++ b/README.md @@ -811,40 +811,21 @@ nanobot cron remove > [!TIP] > The `-v ~/.nanobot:/root/.nanobot` flag mounts your local config directory into the container, so your config and workspace persist across container restarts. -### Using Docker Compose (Recommended) - -The easiest way to run nanobot with Docker: +### Docker Compose ```bash -# 1. Initialize config (first time only) -docker compose run --rm nanobot-cli onboard - -# 2. Edit config to add API keys -vim ~/.nanobot/config.json - -# 3. Start gateway service -docker compose up -d nanobot-gateway - -# 4. Check logs -docker compose logs -f nanobot-gateway - -# 5. Run CLI commands -docker compose run --rm nanobot-cli status -docker compose run --rm nanobot-cli agent -m "Hello!" - -# 6. Stop services -docker compose down +docker compose run --rm nanobot-cli onboard # first-time setup +vim ~/.nanobot/config.json # add API keys +docker compose up -d nanobot-gateway # start gateway ``` -**Features:** -- ✅ Resource limits (1 CPU, 1GB memory) -- ✅ Auto-restart on failure -- ✅ Shared configuration using YAML anchors -- ✅ Separate CLI profile for on-demand commands +```bash +docker compose run --rm nanobot-cli agent -m "Hello!" # run CLI +docker compose logs -f nanobot-gateway # view logs +docker compose down # stop +``` -### Using Docker directly - -Build and run nanobot in a container: +### Docker ```bash # Build the image diff --git a/docker-compose.yml b/docker-compose.yml index 446f5e3..5c27f81 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -23,7 +23,6 @@ services: memory: 256M nanobot-cli: - container_name: nanobot-cli <<: *common-config profiles: - cli From 05d06b1eb8a2492992da89f7dc0534df158cff4f Mon Sep 17 00:00:00 2001 From: Re-bin Date: Tue, 17 Feb 2026 17:58:36 +0000 Subject: [PATCH 58/60] docs: update line count --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 96ff557..325aa64 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ ⚡️ Delivers core agent functionality in just **~4,000** lines of code — **99% smaller** than Clawdbot's 430k+ lines. -📏 Real-time line count: **3,689 lines** (run `bash core_agent_lines.sh` to verify anytime) +📏 Real-time line count: **3,696 lines** (run `bash core_agent_lines.sh` to verify anytime) ## 📢 News From 831eb07945e0ee4cfb8bdfd927cf2e25cf7ed433 Mon Sep 17 00:00:00 2001 From: Xubin Ren <52506698+Re-bin@users.noreply.github.com> Date: Wed, 18 Feb 2026 02:00:30 +0800 Subject: [PATCH 59/60] docs: update security guideline --- SECURITY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SECURITY.md b/SECURITY.md index af3448c..405ce52 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -5,7 +5,7 @@ If you discover a security vulnerability in nanobot, please report it by: 1. **DO NOT** open a public GitHub issue -2. Create a private security advisory on GitHub or contact the repository maintainers +2. Create a private security advisory on GitHub or contact the repository maintainers (xubinrencs@gmail.com) 3. Include: - Description of the vulnerability - Steps to reproduce From e2a0d639099372e4da89173a9a3ce5c76d3264ba Mon Sep 17 00:00:00 2001 From: Re-bin Date: Wed, 18 Feb 2026 02:39:15 +0000 Subject: [PATCH 60/60] feat: add custom provider with direct openai-compatible support --- README.md | 6 ++-- nanobot/cli/commands.py | 13 ++++++-- nanobot/providers/custom_provider.py | 47 ++++++++++++++++++++++++++++ nanobot/providers/registry.py | 15 +++++---- 4 files changed, 68 insertions(+), 13 deletions(-) create mode 100644 nanobot/providers/custom_provider.py diff --git a/README.md b/README.md index 325aa64..30210a7 100644 --- a/README.md +++ b/README.md @@ -574,7 +574,7 @@ Config file: `~/.nanobot/config.json` | Provider | Purpose | Get API Key | |----------|---------|-------------| -| `custom` | Any OpenAI-compatible endpoint | — | +| `custom` | Any OpenAI-compatible endpoint (direct, no LiteLLM) | — | | `openrouter` | LLM (recommended, access to all models) | [openrouter.ai](https://openrouter.ai) | | `anthropic` | LLM (Claude direct) | [console.anthropic.com](https://console.anthropic.com) | | `openai` | LLM (GPT direct) | [platform.openai.com](https://platform.openai.com) | @@ -623,7 +623,7 @@ nanobot agent -m "Hello!"
Custom Provider (Any OpenAI-compatible API) -If your provider is not listed above but exposes an **OpenAI-compatible API** (e.g. Together AI, Fireworks, Azure OpenAI, self-hosted endpoints), use the `custom` provider: +Connects directly to any OpenAI-compatible endpoint — LM Studio, llama.cpp, Together AI, Fireworks, Azure OpenAI, or any self-hosted server. Bypasses LiteLLM; model name is passed as-is. ```json { @@ -641,7 +641,7 @@ If your provider is not listed above but exposes an **OpenAI-compatible API** (e } ``` -> The `custom` provider routes through LiteLLM's OpenAI-compatible path. It works with any endpoint that follows the OpenAI chat completions API format. The model name is passed directly to the endpoint without any prefix. +> For local servers that don't require a key, set `apiKey` to any non-empty string (e.g. `"no-key"`).
diff --git a/nanobot/cli/commands.py b/nanobot/cli/commands.py index 5280d0f..6b245bf 100644 --- a/nanobot/cli/commands.py +++ b/nanobot/cli/commands.py @@ -280,18 +280,27 @@ This file stores important information that should persist across sessions. def _make_provider(config: Config): - """Create LiteLLMProvider from config. Exits if no API key found.""" + """Create the appropriate LLM provider from config.""" from nanobot.providers.litellm_provider import LiteLLMProvider from nanobot.providers.openai_codex_provider import OpenAICodexProvider + from nanobot.providers.custom_provider import CustomProvider model = config.agents.defaults.model provider_name = config.get_provider_name(model) p = config.get_provider(model) - # OpenAI Codex (OAuth): don't route via LiteLLM; use the dedicated implementation. + # OpenAI Codex (OAuth) if provider_name == "openai_codex" or model.startswith("openai-codex/"): return OpenAICodexProvider(default_model=model) + # Custom: direct OpenAI-compatible endpoint, bypasses LiteLLM + if provider_name == "custom": + return CustomProvider( + api_key=p.api_key if p else "no-key", + api_base=config.get_api_base(model) or "http://localhost:8000/v1", + default_model=model, + ) + from nanobot.providers.registry import find_by_name spec = find_by_name(provider_name) if not model.startswith("bedrock/") and not (p and p.api_key) and not (spec and spec.is_oauth): diff --git a/nanobot/providers/custom_provider.py b/nanobot/providers/custom_provider.py new file mode 100644 index 0000000..f190ccf --- /dev/null +++ b/nanobot/providers/custom_provider.py @@ -0,0 +1,47 @@ +"""Direct OpenAI-compatible provider — bypasses LiteLLM.""" + +from __future__ import annotations + +from typing import Any + +import json_repair +from openai import AsyncOpenAI + +from nanobot.providers.base import LLMProvider, LLMResponse, ToolCallRequest + + +class CustomProvider(LLMProvider): + + def __init__(self, api_key: str = "no-key", api_base: str = "http://localhost:8000/v1", default_model: str = "default"): + super().__init__(api_key, api_base) + self.default_model = default_model + self._client = AsyncOpenAI(api_key=api_key, base_url=api_base) + + async def chat(self, messages: list[dict[str, Any]], tools: list[dict[str, Any]] | None = None, + model: str | None = None, max_tokens: int = 4096, temperature: float = 0.7) -> LLMResponse: + kwargs: dict[str, Any] = {"model": model or self.default_model, "messages": messages, + "max_tokens": max(1, max_tokens), "temperature": temperature} + if tools: + kwargs.update(tools=tools, tool_choice="auto") + try: + return self._parse(await self._client.chat.completions.create(**kwargs)) + except Exception as e: + return LLMResponse(content=f"Error: {e}", finish_reason="error") + + def _parse(self, response: Any) -> LLMResponse: + choice = response.choices[0] + msg = choice.message + tool_calls = [ + ToolCallRequest(id=tc.id, name=tc.function.name, + arguments=json_repair.loads(tc.function.arguments) if isinstance(tc.function.arguments, str) else tc.function.arguments) + for tc in (msg.tool_calls or []) + ] + u = response.usage + return LLMResponse( + content=msg.content, tool_calls=tool_calls, finish_reason=choice.finish_reason or "stop", + usage={"prompt_tokens": u.prompt_tokens, "completion_tokens": u.completion_tokens, "total_tokens": u.total_tokens} if u else {}, + reasoning_content=getattr(msg, "reasoning_content", None), + ) + + def get_default_model(self) -> str: + return self.default_model diff --git a/nanobot/providers/registry.py b/nanobot/providers/registry.py index 1e760d6..7d951fa 100644 --- a/nanobot/providers/registry.py +++ b/nanobot/providers/registry.py @@ -54,6 +54,9 @@ class ProviderSpec: # OAuth-based providers (e.g., OpenAI Codex) don't use API keys is_oauth: bool = False # if True, uses OAuth flow instead of API key + # Direct providers bypass LiteLLM entirely (e.g., CustomProvider) + is_direct: bool = False + @property def label(self) -> str: return self.display_name or self.name.title() @@ -65,18 +68,14 @@ class ProviderSpec: PROVIDERS: tuple[ProviderSpec, ...] = ( - # === Custom (user-provided OpenAI-compatible endpoint) ================= - # No auto-detection — only activates when user explicitly configures "custom". - + # === Custom (direct OpenAI-compatible endpoint, bypasses LiteLLM) ====== ProviderSpec( name="custom", keywords=(), - env_key="OPENAI_API_KEY", + env_key="", display_name="Custom", - litellm_prefix="openai", - skip_prefixes=("openai/",), - is_gateway=True, - strip_model_prefix=True, + litellm_prefix="", + is_direct=True, ), # === Gateways (detected by api_key / api_base, not model name) =========