From ac8a5e5a30d8f59b40860305bd1759683b8903d4 Mon Sep 17 00:00:00 2001 From: zcr Date: Thu, 19 Mar 2026 17:55:39 +0800 Subject: [PATCH] =?UTF-8?q?1.=E4=BC=98=E5=8C=96=E9=9A=94=E7=A6=BB=E5=B7=A5?= =?UTF-8?q?=E4=BD=9C=E7=9B=AE=E5=BD=952.=E6=96=B0=E5=A2=9E=E5=9B=BE?= =?UTF-8?q?=E5=83=8F=E7=94=9F=E6=88=90=E5=92=8C=E7=BC=96=E8=BE=91=E5=8A=9F?= =?UTF-8?q?=E8=83=BD3.=E7=94=9F=E6=88=90=E6=A8=A1=E5=9E=8B=E6=9B=BF?= =?UTF-8?q?=E6=8D=A2=E4=B8=BA=E6=9C=AC=E5=9C=B0flux2=20klein?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main.py | 5 +- pyproject.toml | 2 + src/core/config.py | 6 + src/routers/deep_agent_chat.py | 11 +- src/schemas/deep_agent_chat.py | 1 + src/server/deep_agent/agents/main_agent.py | 45 +- src/server/deep_agent/agents/painter.py | 23 +- src/server/deep_agent/agents/researcher.py | 38 +- .../deep_agent/agents/vision_subagent.py | 77 +++ src/server/deep_agent/init_llm.py | 9 + src/server/deep_agent/init_prompt.py | 36 +- src/server/deep_agent/tools/crawl_tool.py | 86 ++- .../tools/generate_furniture_sketch.py | 228 ++++++-- .../deep_agent/tools/report_generator_tool.py | 190 +++---- .../tools/structured_retrieval_tool.py | 238 ++++---- .../deep_agent/tools/vision_analyze_tool.py | 21 + src/server/utils/new_oss_client.py | 41 +- uv.lock | 513 ++++++++++++++++-- 18 files changed, 1167 insertions(+), 403 deletions(-) create mode 100644 src/server/deep_agent/agents/vision_subagent.py create mode 100644 src/server/deep_agent/tools/vision_analyze_tool.py diff --git a/main.py b/main.py index ee49aa8..f17207b 100644 --- a/main.py +++ b/main.py @@ -1,11 +1,11 @@ import logging.config +from pathlib import Path import uvicorn from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware - from logging_env import LOGGER_CONFIG_DICT -from src.routers import chat, deep_agent_chat +from src.routers import deep_agent_chat from src.routers import generate_3D from src.routers import flux2_gen_img @@ -26,7 +26,6 @@ app_server.add_middleware( ) # 包含路由 -app_server.include_router(chat.router) app_server.include_router(deep_agent_chat.router) app_server.include_router(generate_3D.router) app_server.include_router(flux2_gen_img.router) diff --git a/pyproject.toml b/pyproject.toml index f774018..f76d9d9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,4 +48,6 @@ dependencies = [ "path>=17.1.1", "langgraph-checkpoint-postgres>=3.0.4", "langgraph-store-mongodb>=0.2.0", + "tool>=0.8.0", + "langchain-daytona>=0.0.3", ] diff --git a/src/core/config.py b/src/core/config.py index 2394b06..12af83d 100644 --- a/src/core/config.py +++ b/src/core/config.py @@ -1,3 +1,5 @@ +from pathlib import Path + from pydantic_settings import BaseSettings, SettingsConfigDict from pydantic import Field @@ -44,3 +46,7 @@ class Settings(BaseSettings): settings = Settings() MONGO_URI = f"mongodb://{settings.MONGODB_USERNAME}:{settings.MONGODB_PASSWORD}@{settings.MONGODB_HOST}:{settings.MONGODB_PORT}" + +TOOL_DIR = Path(__file__).resolve().parent +PROJECT_ROOT = TOOL_DIR.parent +print(f"PROJECT_ROOT : {PROJECT_ROOT}") diff --git a/src/routers/deep_agent_chat.py b/src/routers/deep_agent_chat.py index 6f881e5..1896820 100644 --- a/src/routers/deep_agent_chat.py +++ b/src/routers/deep_agent_chat.py @@ -1,4 +1,5 @@ import logging +import os import random import uuid import json @@ -6,6 +7,8 @@ from typing import AsyncGenerator from fastapi import APIRouter from fastapi.responses import StreamingResponse + +from src.core.config import PROJECT_ROOT from src.schemas.deep_agent_chat import DeepAgentChatRequest, HistoryResponse, HistoryItem from langchain_core.messages import HumanMessage, SystemMessage, AIMessageChunk, ToolMessage, AIMessage, ToolMessageChunk @@ -77,13 +80,15 @@ async def chat_stream(request: DeepAgentChatRequest): source_thread_id = request.thread_id checkpoint_id = request.checkpoint_id - # 构建主agent - main_agent = build_main_agent(request.use_report) - # 1. 確定目標 thread_id is_branching = source_thread_id and checkpoint_id target_thread_id = str(uuid.uuid4())[:8] if is_branching else (source_thread_id or str(uuid.uuid4())[:8]) + # 构建主agent + workspace_dir = os.path.join(PROJECT_ROOT, f"agent_workspace/{target_thread_id}") + print(f"target_thread_id : workspace_dir: {workspace_dir}") + main_agent = build_main_agent(request.use_report, workspace_dir) + # 2. 配置參數 temp = request.config_params.temperature if request.config_params else 0.7 diff --git a/src/schemas/deep_agent_chat.py b/src/schemas/deep_agent_chat.py index 2ce5f86..49a37a1 100644 --- a/src/schemas/deep_agent_chat.py +++ b/src/schemas/deep_agent_chat.py @@ -11,6 +11,7 @@ class AgentConfig(BaseModel): class DeepAgentChatRequest(BaseModel): message: str = Field(..., description="用户的输入指令") + # image_url: Optional[str] = Field(None, description="图片地址") # ✅ 新增 thread_id: Optional[str] = Field(None, description="会话线程ID,不传则开启新会话") checkpoint_id: Optional[str] = Field(None, description="回溯点的ID,用于从历史点开启新对话") config_params: Optional[AgentConfig] = None diff --git a/src/server/deep_agent/agents/main_agent.py b/src/server/deep_agent/agents/main_agent.py index 73943ff..4b43b33 100644 --- a/src/server/deep_agent/agents/main_agent.py +++ b/src/server/deep_agent/agents/main_agent.py @@ -1,21 +1,22 @@ from pathlib import Path +from daytona import Daytona from deepagents import create_deep_agent from deepagents.backends import FilesystemBackend from langchain.agents.middleware import SummarizationMiddleware from langgraph.checkpoint.mongodb import MongoDBSaver from langgraph.checkpoint.serde.jsonplus import JsonPlusSerializer from pymongo import MongoClient +from daytona import CreateSandboxFromSnapshotParams, Daytona +from langchain_daytona import DaytonaSandbox from src.core.config import MONGO_URI -from src.server.deep_agent.agents.painter import painter_subagent -from src.server.deep_agent.agents.researcher import research_subagent +from src.server.deep_agent.agents.painter import build_painter_subagent +from src.server.deep_agent.agents.researcher import build_researcher_subagent from src.server.deep_agent.agents.user_profile import user_profile_subagent from src.server.deep_agent.init_llm import main_llm from src.server.deep_agent.init_prompt import build_system_prompt -TOOL_DIR = Path(__file__).resolve().parent -PROJECT_ROOT = TOOL_DIR.parent client = MongoClient(MONGO_URI) checkpointer = MongoDBSaver( client=client["furniture_agent_db"], @@ -23,22 +24,42 @@ checkpointer = MongoDBSaver( collection_name="fida_agent_collection", serde=JsonPlusSerializer(pickle_fallback=True), # ← 關鍵這一行 ) -subagents = [ - painter_subagent, - research_subagent, - user_profile_subagent -] -def build_main_agent(use_report): +class CanvasMiddleware: + def before_agent(self, state, agent_input, **kwargs): + canvas = state.get("canvas", {}) + + info = f""" + 当前画布状态: + - image_path: {canvas.get("image_path")} + - 是否已有图片: {bool(canvas.get("image_path"))} + """ + + agent_input["messages"].append({ + "role": "system", + "content": info + }) + + return state, agent_input + + +def build_main_agent(use_report, workspace_dir): + research_subagent = build_researcher_subagent(workspace_dir) + painter_subagent = build_painter_subagent(workspace_dir) + subagents = [ + painter_subagent, + research_subagent, + user_profile_subagent + ] main_agent = create_deep_agent( model=main_llm, system_prompt=build_system_prompt(use_report=use_report), subagents=subagents, checkpointer=checkpointer, backend=FilesystemBackend( - root_dir=str(PROJECT_ROOT / "agent_workspace"), - virtual_mode=False, # 重要:關掉虛擬模式 → 真的寫硬碟 + root_dir=workspace_dir, + virtual_mode=True, # 重要:關掉虛擬模式 → 真的寫硬碟 ), middleware=[ SummarizationMiddleware( diff --git a/src/server/deep_agent/agents/painter.py b/src/server/deep_agent/agents/painter.py index 94025ab..328b568 100644 --- a/src/server/deep_agent/agents/painter.py +++ b/src/server/deep_agent/agents/painter.py @@ -2,7 +2,7 @@ from langchain.agents.middleware import wrap_tool_call from src.server.deep_agent.init_llm import llm from src.server.deep_agent.init_prompt import build_painter_prompt -from src.server.deep_agent.tools.generate_furniture_sketch import generate_furniture +from src.server.deep_agent.tools.generate_furniture_sketch import create_generate_furniture_tool, create_edit_furniture_tool @wrap_tool_call @@ -12,11 +12,16 @@ async def log_tool_calls(request, handler): return handler(request) -painter_subagent = { - "name": "painter_subagent", - "description": "理解用户意图,使用prompt,调用generate_furniture工具生成家具sketch草图.", - "system_prompt": build_painter_prompt(), - "tools": [generate_furniture], - "model": llm, - # "middleware": [log_tool_calls], -} +def build_painter_subagent(workspace_dir): + generate_furniture = create_generate_furniture_tool(workspace_dir) + edit_furniture = create_edit_furniture_tool(workspace_dir) + + painter_subagent = { + "name": "painter_subagent", + "description": "理解用户意图,利用prompt编辑或生成家具sketch图像", + "system_prompt": build_painter_prompt(), + "tools": [generate_furniture, edit_furniture], + "model": llm, + # "middleware": [log_tool_calls], + } + return painter_subagent diff --git a/src/server/deep_agent/agents/researcher.py b/src/server/deep_agent/agents/researcher.py index ef3e69d..f6a95c0 100644 --- a/src/server/deep_agent/agents/researcher.py +++ b/src/server/deep_agent/agents/researcher.py @@ -1,21 +1,27 @@ from src.server.deep_agent.init_llm import llm from src.server.deep_agent.init_prompt import build_researcher_prompt -from src.server.deep_agent.tools.crawl_tool import crawl4ai_batch -from src.server.deep_agent.tools.report_generator_tool import report_generator +from src.server.deep_agent.tools.crawl_tool import create_crawl4ai_batch_tool +from src.server.deep_agent.tools.report_generator_tool import create_report_generator_tool from src.server.deep_agent.tools.research_tool import topic_research -from src.server.deep_agent.tools.structured_retrieval_tool import structured_retrieval +from src.server.deep_agent.tools.structured_retrieval_tool import create_structured_retrieval_tool from src.server.deep_agent.tools.user_persona_tool import query_report_profile -research_subagent = { - "name": "research_subagent", - "description": "通过网络搜索对家具设计开展深度研究并整合结论", - "system_prompt": build_researcher_prompt(), - "tools": [ - query_report_profile, - topic_research, - crawl4ai_batch, - structured_retrieval, - report_generator - ], - "model": llm -} + +def build_researcher_subagent(workspace_dir): + crawl4ai_batch = create_crawl4ai_batch_tool(workspace_dir) + structured_retrieval = create_structured_retrieval_tool(workspace_dir) + report_generator = create_report_generator_tool(workspace_dir) + research_subagent = { + "name": "research_subagent", + "description": "通过网络搜索对家具设计开展深度研究并整合结论", + "system_prompt": build_researcher_prompt(), + "tools": [ + query_report_profile, + topic_research, + crawl4ai_batch, + structured_retrieval, + report_generator + ], + "model": llm + } + return research_subagent diff --git a/src/server/deep_agent/agents/vision_subagent.py b/src/server/deep_agent/agents/vision_subagent.py new file mode 100644 index 0000000..e075fc1 --- /dev/null +++ b/src/server/deep_agent/agents/vision_subagent.py @@ -0,0 +1,77 @@ +import json + +from src.server.deep_agent.init_llm import vision_llm +from src.server.deep_agent.tools.vision_analyze_tool import vision_analyze_tool + +vision_subagent = { + "name": "vision_subagent", + "description": "分析用户上传的图片,提取家具、风格、颜色、材质等信息", + "system_prompt": """ + 你是一个专业的视觉分析助手(家具设计方向)。 + + 你的任务: + 1. 理解用户提供的图片(路径或URL) + 2. 分析家具内容 + 3. 输出结构化JSON(不要解释) + + 格式: + { + "objects": [], + "style": "", + "color": [], + "material": [], + "room_type": "", + "description": "" + } + """, + "tools": [], # ❗这里不用tool,直接用多模态模型 + "model": vision_llm, +} + + +def vision_execute(state): + image = state.get("image") + + if image is None: + return { + "error": "NO_IMAGE" + } + + prompt = """ +你是一个家具视觉分析模型。 + +任务:分析图片并输出JSON: + +{ + "objects": [], + "style": "", + "color": [], + "material": [], + "room_type": "", + "description": "" +} + +规则: +- 只基于图像内容 +- 不允许编造 +- objects 最多5个 +- color 最多3个 +- 只输出JSON +""" + + result = vision_llm.generate( + image=image, # ⭐ 关键:真正喂图 + prompt=prompt + ) + + return safe_parse_json(result) + + +def safe_parse_json(text): + try: + return json.loads(text) + except: + return { + "error": "INVALID_JSON", + "raw": text + } diff --git a/src/server/deep_agent/init_llm.py b/src/server/deep_agent/init_llm.py index a598715..adaa50f 100644 --- a/src/server/deep_agent/init_llm.py +++ b/src/server/deep_agent/init_llm.py @@ -49,3 +49,12 @@ repoer_llm = ChatQwen( timeout=None, max_retries=2, api_key=settings.QWEN_API_KEY) + +vision_llm = ChatQwen( + enable_thinking=False, + model="qwen3-vl-plus", + temperature=0.2, + max_tokens=3_000, + timeout=None, + max_retries=2, + api_key=settings.QWEN_API_KEY) diff --git a/src/server/deep_agent/init_prompt.py b/src/server/deep_agent/init_prompt.py index 260d033..3fb8674 100644 --- a/src/server/deep_agent/init_prompt.py +++ b/src/server/deep_agent/init_prompt.py @@ -15,7 +15,10 @@ def build_system_prompt(use_report): 负责生成完整报告、调研、总结、分析。 3. painter_subagent - 负责根据用户描述,构造适用于生成家具sketch的prompt,使用prompt用工具生成图片. + 负责根据用户描述,构造适用于 生成家具sketch的prompt或编辑家具sketch的prompt + 1.利用prompt用工具生成图片. + 2.利用prompt和图片路径用工具编辑图片. + ======================== 执行规则 @@ -51,31 +54,26 @@ def build_system_prompt(use_report): - research-subagent 只负责 **报告生成** 不要混用职责。 ======================== - 严格输出规则 - ======================== - - 当生成图片时,绝对不要输出图片路径、file:// 地址、URL、本地链接 - - 只输出文字描述,不输出任何图片链接或路径 """ return system_prompt def build_painter_prompt(): prompt = """ - 你是一名专业的prompt优化专家,专注于家具设计草图生成。你的任务是: - 1. 分析用户查询,理解核心意图,包括家具类型、风格、尺寸、颜色、材料等关键元素 - 2. 基于意图,优化并生成一个详细、精确的prompt,适合用于AI图片生成工具创建家具sketch草图(例如,线条简洁、手绘风格、焦点在设计细节上) - 3. 使用优化的prompt调用图片生成工具,生成并返回草图图片 - 4. 如果需要,建议额外变体或改进 - - 输出格式: - - 用户意图总结(1–2段) - - 优化后的prompt(完整文本) - - 生成的图片描述(如果工具返回) - - 建议改进(项目符号,可选) - 【严格输出规则】 - - 当生成图片时,**绝对不要输出图片路径、file:// 地址、URL、本地链接**。 - - 只输出文字描述,不输出任何图片链接或路径。 + 你是 painter_subagent,专门生成或编辑 sketch 图。 + 1. 每次开始决策前,先调用工具 read_file("/current_sketch_path.txt") 获取当前路径。 + - 如果文件不存在或返回空 → 当前没有历史图,使用 generate_sketch。 + - 如果有路径 → 检查用户意图是否为「修改/编辑/改成/调整/优化/把...变成」,如果是则必须使用 edit_sketch,并传入 image_path = 读取到的路径。 + 2. 生成或编辑完成后,**必须立即**调用 write_file("/current_sketch_path.txt", content=本次生成的图片完整路径) 来更新状态。 + 3. 【对用户隐藏路径】: + - 永远不要在最终回复给用户的任何消息中出现路径、/tmp/、/current_sketch_path.txt 等字符串! + - 回复格式只能是: + "图片已成功生成!" + 或 + "已按你的要求把狗改成猫,图片更新完成!" + - 如果前端支持图片展示,你可以直接返回图片(但不要带路径文字)。 + 现在开始严格遵守以上规则。 """ return prompt diff --git a/src/server/deep_agent/tools/crawl_tool.py b/src/server/deep_agent/tools/crawl_tool.py index 7ef9a0d..2696b44 100644 --- a/src/server/deep_agent/tools/crawl_tool.py +++ b/src/server/deep_agent/tools/crawl_tool.py @@ -1,3 +1,4 @@ +import os import time import asyncio from typing import List, Dict, Any @@ -8,19 +9,6 @@ import uuid from crawl4ai import AsyncWebCrawler, BrowserConfig, CrawlerRunConfig, CacheMode from langchain_core.tools import tool -# ───────────────────────────────────── -# 路径配置 -# ───────────────────────────────────── - -TOOL_DIR = Path(__file__).resolve().parent -PROJECT_ROOT = TOOL_DIR.parent - -# DeepAgents 推荐目录 -SAVE_DIR = PROJECT_ROOT / "agent_workspace" / "raw_data" -SAVE_DIR.mkdir(parents=True, exist_ok=True) - -print(f"tool save : {str(PROJECT_ROOT / "agent_workspace")}") - # ───────────────────────────────────── # Browser 配置 # ───────────────────────────────────── @@ -65,7 +53,7 @@ def build_filename(url: str) -> str: # 单个 URL 抓取 # ───────────────────────────────────── -async def crawl_one(crawler, url: str, sem: asyncio.Semaphore) -> Dict[str, Any]: +async def crawl_one(crawler, url: str, sem: asyncio.Semaphore, save_dir: str) -> Dict[str, Any]: async with sem: try: result = await crawler.arun(url=url, config=run_config) @@ -87,7 +75,7 @@ async def crawl_one(crawler, url: str, sem: asyncio.Semaphore) -> Dict[str, Any] } filename = build_filename(url) - filepath = SAVE_DIR / filename + filepath = os.path.join(save_dir, filename) header = ( f"\n" @@ -115,7 +103,7 @@ async def crawl_one(crawler, url: str, sem: asyncio.Semaphore) -> Dict[str, Any] # Async 主逻辑 # ───────────────────────────────────── -async def _crawl4ai_batch(urls: List[str]) -> Dict[str, Any]: +async def _crawl4ai_batch(urls: List[str], save_dir: str) -> Dict[str, Any]: urls = list(set(urls)) # 去重 if not urls: @@ -126,7 +114,7 @@ async def _crawl4ai_batch(urls: List[str]) -> Dict[str, Any]: async with AsyncWebCrawler(config=browser_config) as crawler: tasks = [ - crawl_one(crawler, url, sem) + crawl_one(crawler, url, sem, save_dir) for url in urls ] @@ -150,42 +138,46 @@ async def _crawl4ai_batch(urls: List[str]) -> Dict[str, Any]: } -# ───────────────────────────────────── -# Tool(同步) -# ───────────────────────────────────── -@tool -def crawl4ai_batch(urls: List[str]) -> str: - """ - Batch crawl webpages and save their content as markdown files. +def create_crawl4ai_batch_tool(workspace_dir): + @tool + def crawl4ai_batch(urls: List[str]) -> str: + """ + Batch crawl webpages and save their content as markdown files. - Args: - urls: List of webpage URLs to crawl. + Args: + urls: List of webpage URLs to crawl. - Returns: - A summary of crawling results and saved file paths. - """ + Returns: + A summary of crawling results and saved file paths. + """ - try: - result = asyncio.run(_crawl4ai_batch(urls)) + try: + save_dir = os.path.join(workspace_dir, "raw_data") + if not os.path.exists(save_dir): + os.makedirs(save_dir, exist_ok=True) - if "error" in result: - return f"❌ Error: {result['error']}" + result = asyncio.run(_crawl4ai_batch(urls, save_dir)) - output = [ - "### 批量抓取完成 ###", - f"成功保存文件: {result['count']}", - f"保存目录: {SAVE_DIR}", - "", - "抓取详情:" - ] + if "error" in result: + return f"❌ Error: {result['error']}" - output.extend(result["summary"]) + output = [ + "### 批量抓取完成 ###", + f"成功保存文件: {result['count']}", + f"保存目录: {workspace_dir}", + "", + "抓取详情:" + ] - if result["saved_files"]: - output.append("\n可读取文件:") - output.extend(result["saved_files"]) + output.extend(result["summary"]) - return "\n".join(output) + if result["saved_files"]: + output.append("\n可读取文件:") + output.extend(result["saved_files"]) - except Exception as e: - return f"🚨 爬虫系统异常: {str(e)}" + return "\n".join(output) + + except Exception as e: + return f"🚨 爬虫系统异常: {str(e)}" + + return crawl4ai_batch diff --git a/src/server/deep_agent/tools/generate_furniture_sketch.py b/src/server/deep_agent/tools/generate_furniture_sketch.py index 76b9521..0e1e30a 100644 --- a/src/server/deep_agent/tools/generate_furniture_sketch.py +++ b/src/server/deep_agent/tools/generate_furniture_sketch.py @@ -1,15 +1,21 @@ import json import logging +import os import uuid +from pathlib import Path +from typing import Annotated + +import httpx from google.oauth2 import service_account from langchain_core.tools import tool from google import genai from google.genai.types import GenerateContentConfig, Modality +from langgraph.prebuilt import ToolRuntime from minio import Minio from src.core.config import settings -from src.server.utils.new_oss_client import oss_upload_image +from src.server.utils.new_oss_client import oss_upload_image, oss_get_image, is_minio_file_exist, oss_upload_image_file logger = logging.getLogger(__name__) # 初始化全局凭证和客户端 @@ -27,47 +33,187 @@ client = genai.Client( ) -@tool -async def generate_furniture(prompt: str) -> str: - """ - 使用 Gemini 图像生成模型根据详细的英文提示词生成家具设计草图。 - """ - print(f"\n[系统日志] 正在调用 Nano Banana (Gemini Image Gen) ...") - +def is_image_path_exist(image_path): try: - response = client.models.generate_content( - model="gemini-2.5-flash-image", - contents=(f"Generate a professional furniture design sketch: {prompt}"), - config=GenerateContentConfig( - response_modalities=[Modality.TEXT, Modality.IMAGE], - ), - ) + return Path(image_path).exists() + except: + return False - image_bytes = None - for part in response.candidates[0].content.parts: - if part.inline_data: - image_bytes = part.inline_data.data - break - if not image_bytes: - return "未能生成图像数据。" - object_name = f"furniture/sketches/{uuid.uuid4()}.png" - bucket = "fida-test" # 替换为你的 bucket 名称 - # 3. 调用你的上传函数 - upload_res = oss_upload_image( - oss_client=minio_client, - bucket=bucket, - object_name=object_name, - image_bytes=image_bytes - ) +def create_generate_furniture_tool(workspace_dir, width: int = 1024, height: int = 1024): + @tool + async def generate_furniture(prompt: str, runtime: ToolRuntime) -> str: + """ + 使用 Gemini 图像生成模型根据详细的英文提示词生成家具设计草图。 + """ + logger.info(f"\n[系统日志] 正在调用 generate_furniture ...") + try: + # 1. 生成图像 - local flux2-klein + object_name = f"furniture/sketches/{uuid.uuid4()}.png" + bucket_name = "fida-test" # 替换为你的 bucket 名称 + request_data = { + "prompt": prompt, + "bucket_name": bucket_name, + "object_name": object_name, + "width": width, + "height": height + } + async with httpx.AsyncClient(timeout=120) as client: + resp = await client.post( + f"http://{settings.FLUX2_GEN_IMG_MODEL_URL}/predict", + json=request_data, + ) + result = resp.json() + image_url = result.get("output_path", None) - if upload_res: - # 4. 构造访问链接 (如果是私有 bucket,需使用 presigned_get_object) - # 这里简单示例为直接访问地址 - image_url = f"{bucket}/{object_name}" - return image_url - else: - return "图片生成成功,但上传至存储服务器失败。" - except Exception as e: - logger.warning(e) - return "绘图流程异常" + if image_url: + filename = os.path.join(workspace_dir, image_url) + # 2. 创建本地目录(确保目录存在) + local_dir = os.path.dirname(filename) + if not os.path.exists(local_dir): + os.makedirs(local_dir, exist_ok=True) + + img = oss_get_image(oss_client=minio_client, bucket=image_url.split('/')[0], object_name=image_url[image_url.find('/') + 1:]) + img.save(filename) + + return image_url + else: + return f"Image generation failed." + + except Exception as e: + logger.warning(f"绘图流程异常:{e}") + return "绘图流程异常" + + return generate_furniture + + +def create_edit_furniture_tool(workspace_dir, width: int = 1024, height: int = 1024): + @tool + async def edit_furniture(prompt: str, input_image_path) -> str: + """ + 使用图像生成模型根据详细的英文提示词编辑家具设计草图。 + """ + logger.info(f"\n[系统日志] 正在调用 edit_furniture ...") + + try: + # 0. 编辑前先检查工作环境和minio上是否存在该图像 + input_image_path = input_image_path.lstrip('/') + filename = os.path.join(workspace_dir, input_image_path) + local_exist = is_image_path_exist(filename) + minio_exist = is_minio_file_exist(minio_client=minio_client, bucket_name=input_image_path.split('/')[0], object_name=input_image_path.split('/')[0]) + + if not local_exist and not minio_exist: + # 两个地方都不存在 直接报错 + return f"Image generation failed." + elif local_exist and not minio_exist: + # 把本地的上传到minio + oss_upload_image_file(oss_client=minio_client, bucket=input_image_path.split('/')[0], object_name=input_image_path.split('/')[0], file_path=filename) + elif not local_exist and minio_exist: + # minio的下载到本地 + img = oss_get_image(oss_client=minio_client, bucket=input_image_path.split('/')[0], object_name=input_image_path.split('/')[0], ) + img.save(filename) + elif minio_exist and local_exist: + # 两个地方都存在 直接跳过 + pass + + # 1. 生成图像 - local flux2-klein + object_name = f"furniture/sketches/{uuid.uuid4()}.png" + bucket_name = "fida-test" # 替换为你的 bucket 名称 + request_data = { + "input_image_paths": [input_image_path], + "prompt": prompt, + "bucket_name": bucket_name, + "object_name": object_name, + "width": width, + "height": height + } + async with httpx.AsyncClient(timeout=120) as client: + resp = await client.post( + f"http://{settings.FLUX2_GEN_IMG_MODEL_URL}/predict", + json=request_data, + ) + result = resp.json() + image_url = result.get("output_path", None) + + if image_url: + filename = os.path.join(workspace_dir, image_url) + # 2. 创建本地目录(确保目录存在) + local_dir = os.path.dirname(filename) + if not os.path.exists(local_dir): + os.makedirs(local_dir, exist_ok=True) + + img = oss_get_image(oss_client=minio_client, bucket=image_url.split('/')[0], object_name=image_url[image_url.find('/') + 1:]) + img.save(filename) + return image_url + else: + return f"Image generation failed." + + except Exception as e: + logger.warning(f"edit_furniture error :{e}") + return "edit_furniture error" + + return edit_furniture + +# def create_generate_furniture_tool(workspace_dir): +# @tool +# async def generate_furniture(prompt: str) -> str: +# """ +# 使用 Gemini 图像生成模型根据详细的英文提示词生成家具设计草图。 +# """ +# print(f"\n[系统日志] 正在调用 Nano Banana (Gemini Image Gen) ...") +# +# try: +# response = client.models.generate_content( +# model="gemini-2.5-flash-image", +# contents=(f"Generate a professional furniture design sketch: {prompt}"), +# config=GenerateContentConfig( +# response_modalities=[Modality.TEXT, Modality.IMAGE], +# ), +# ) +# +# image_bytes = None +# for part in response.candidates[0].content.parts: +# if part.inline_data: +# image_bytes = part.inline_data.data +# break +# +# if not image_bytes: +# return "未能生成图像数据。" +# # 1. 定义OSS存储路径和本地保存路径 +# object_name = f"furniture/sketches/{uuid.uuid4()}.png" +# bucket = "fida-test" # 替换为你的 bucket 名称 +# filename = os.path.join(workspace_dir, f"{bucket}/{object_name}") +# +# # 2. 创建本地目录(确保目录存在) +# local_dir = os.path.dirname(filename) +# if not os.path.exists(local_dir): +# os.makedirs(local_dir, exist_ok=True) +# +# # 3. 保存图片到本地文件(新增核心逻辑) +# try: +# with open(filename, "wb") as f: +# f.write(image_bytes) +# print(f"[系统日志] 图片已保存到本地:{filename}") +# except Exception as save_e: +# logger.warning(f"保存图片到本地失败:{save_e}") +# # 本地保存失败不中断上传流程,仅记录日志 +# +# # 4. 上传图片到OSS(原有逻辑) +# upload_res = oss_upload_image( +# oss_client=minio_client, +# bucket=bucket, +# object_name=object_name, +# image_bytes=image_bytes +# ) +# +# if upload_res: +# image_url = f"{bucket}/{object_name}" +# return image_url +# else: +# return f"图片生成成功(本地路径:{filename}),但上传至存储服务器失败。" +# +# except Exception as e: +# logger.warning(f"绘图流程异常:{e}") +# return "绘图流程异常" +# +# return generate_furniture diff --git a/src/server/deep_agent/tools/report_generator_tool.py b/src/server/deep_agent/tools/report_generator_tool.py index 05a8828..b17eae4 100644 --- a/src/server/deep_agent/tools/report_generator_tool.py +++ b/src/server/deep_agent/tools/report_generator_tool.py @@ -32,104 +32,108 @@ class ReportInput(BaseModel): # LangGraph Tool # ========================= -@tool("report_generator", args_schema=ReportInput) -async def report_generator( - report_topic: str, - structured_data: List[Dict], - language: str = "English" -) -> dict: - """ - Generate a professional design/market report - directly from structured retrieval results. - """ +def create_report_generator_tool(workspace_dir): + @tool("report_generator", args_schema=ReportInput) + async def report_generator( + report_topic: str, + structured_data: List[Dict], + language: str = "English" + ) -> dict: + """ + Generate a professional design/market report + directly from structured retrieval results. + """ - writer = get_stream_writer() - if not structured_data: - error_msg = "Error: No structured data provided." - writer({"type": "report_error", "message": error_msg}) - return error_msg + writer = get_stream_writer() + if not structured_data: + error_msg = "Error: No structured data provided." + writer({"type": "report_error", "message": error_msg}) + return error_msg - collected_data_str = json.dumps( - structured_data, - ensure_ascii=False, - indent=2 - ) - - # ========================= - # Prompt - # ========================= - - system_prompt = f""" - You are a professional design trend analyst. - - Generate a long, structured Markdown report. - - REQUIREMENTS: - - 1. Follow MECE principle. - 2. Embed images ONLY if they start with https:// - using: ![alt](url) - 3. Insert images inline. - 4. Every key insight must cite source: - [Website Name](url) - 5. Use Markdown headings. - 6. Start directly with title. - 7. Be detailed and analytical. - - Output Language: {language} - """ - - user_prompt = f""" - Topic: {report_topic} - - Input Data: - {collected_data_str} - """ - - # ========================= - # 调用 LLM - # ========================= - writer({"type": "report_start", "topic": report_topic, "language": language}) - - full_report = "" - try: - report_llm = repoer_llm.with_config( - callbacks=[] + collected_data_str = json.dumps( + structured_data, + ensure_ascii=False, + indent=2 ) - async for chunk in report_llm.astream( - [ - SystemMessage(content=system_prompt), - HumanMessage(content=user_prompt) - ] - ): - if chunk.content: # Gemini 返回的 chunk.content - delta = chunk.content - full_report += delta - # return {"type": "report_delta", "delta": delta} - writer({"type": "report_delta", "delta": delta}) # ← 实时推送给前端 - writer({"type": "report_stop", "topic": report_topic, "language": language}) - except Exception as e: - error_msg = f"LLM generation failed: {str(e)}" - writer({"type": "report_error", "message": error_msg}) - return error_msg - report_content = full_report.strip() + # ========================= + # Prompt + # ========================= - # ========================= - # 保存报告 - # ========================= - output_dir = "workspace/reports" - os.makedirs(output_dir, exist_ok=True) + system_prompt = f""" + You are a professional design trend analyst. - safe_topic = re.sub(r'[\\/*?:"<>|]', "", report_topic.replace(" ", "_")) - filename = f"{output_dir}/{safe_topic}.md" + Generate a long, structured Markdown report. - try: - with open(filename, "w", encoding="utf-8") as f: - f.write(report_content) - writer({"type": "report_complete", "file_path": filename}) - except Exception as e: - writer({"type": "report_save_warning", "message": str(e)}) + REQUIREMENTS: - # 返回完整内容(作为 tool result),同时正文已通过 delta 流式输出 - return report_content + f"\n\n✅ Report saved to: {filename}" + 1. Follow MECE principle. + 2. Embed images ONLY if they start with https:// + using: ![alt](url) + 3. Insert images inline. + 4. Every key insight must cite source: + [Website Name](url) + 5. Use Markdown headings. + 6. Start directly with title. + 7. Be detailed and analytical. + + Output Language: {language} + """ + + user_prompt = f""" + Topic: {report_topic} + + Input Data: + {collected_data_str} + """ + + # ========================= + # 调用 LLM + # ========================= + writer({"type": "report_start", "topic": report_topic, "language": language}) + + full_report = "" + try: + report_llm = repoer_llm.with_config( + callbacks=[] + ) + async for chunk in report_llm.astream( + [ + SystemMessage(content=system_prompt), + HumanMessage(content=user_prompt) + ] + ): + if chunk.content: # Gemini 返回的 chunk.content + delta = chunk.content + full_report += delta + # return {"type": "report_delta", "delta": delta} + writer({"type": "report_delta", "delta": delta}) # ← 实时推送给前端 + writer({"type": "report_stop", "topic": report_topic, "language": language}) + except Exception as e: + error_msg = f"LLM generation failed: {str(e)}" + writer({"type": "report_error", "message": error_msg}) + return error_msg + + report_content = full_report.strip() + + # ========================= + # 保存报告 + # ========================= + output_dir = os.path.join(workspace_dir, "reports") + if not os.path.exists(output_dir): + os.makedirs(output_dir, exist_ok=True) + + safe_topic = re.sub(r'[\\/*?:"<>|]', "", report_topic.replace(" ", "_")) + filename = f"{output_dir}/{safe_topic}.md" + + try: + with open(filename, "w", encoding="utf-8") as f: + f.write(report_content) + writer({"type": "report_complete", "file_path": filename}) + except Exception as e: + writer({"type": "report_save_warning", "message": str(e)}) + + # 返回完整内容(作为 tool result),同时正文已通过 delta 流式输出 + return report_content + f"\n\n✅ Report saved to: {filename}" + + return report_generator diff --git a/src/server/deep_agent/tools/structured_retrieval_tool.py b/src/server/deep_agent/tools/structured_retrieval_tool.py index 8288146..22bc1aa 100644 --- a/src/server/deep_agent/tools/structured_retrieval_tool.py +++ b/src/server/deep_agent/tools/structured_retrieval_tool.py @@ -32,121 +32,6 @@ class StructuredRetrievalInput(BaseModel): source_url: Optional[str] = Field(None, description="Optional global source URL") -@tool("structured_retrieval", args_schema=StructuredRetrievalInput) -def structured_retrieval( - file_paths: List[str], - query: str, - source_url: Optional[str] = None -) -> Dict: - """ - Batch structured extraction from markdown files. - - Performs vector search + re-ranking - - Saves extracted structured data as JSON file to disk - - Returns ONLY summary (status, count, file path) - """ - - # ── 1. 收集所有文件內容 ────────────────────────────────────── - all_docs_pool: List[Document] = [] - - for path in file_paths: - if not os.path.exists(path) or not path.endswith((".md", ".markdown")): - continue - - file_name = os.path.basename(path) - - with open(path, "r", encoding="utf-8") as f: - content = f.read() - - current_source = source_url or _extract_source_from_md(content) or "unknown" - - sections = _split_markdown_by_headers(content) - - for sec in sections: - all_docs_pool.append( - Document( - page_content=sec, - metadata={"source_url": current_source, "file_name": file_name} - ) - ) - - if not all_docs_pool: - return {"status": "no_documents_found", "items_count": 0, "json_path": None} - - # ── 2. Vector search ──────────────────────────────────────────── - vector_store = FAISS.from_documents(all_docs_pool, _EMBEDDING_MODEL) - retrieved = vector_store.similarity_search(query, k=200) - - # ── 3. 提取結構化片段 ────────────────────────────────────────── - structured_items = [] - - for doc in retrieved: - text = doc.page_content.strip() - if len(text) < 30: - continue - - images = list(set(re.findall(r"!\[.*?\]\((.*?)\)", text))) - - structured_items.append( - { - "text": text, - "images": images, - "source_url": doc.metadata.get("source_url"), - "file_name": doc.metadata.get("file_name") - } - ) - - # ── 4. Re-rank ────────────────────────────────────────────────── - if structured_items: - unique_items = {item["text"]: item for item in structured_items}.values() - pairs = [[query, item["text"]] for item in unique_items] - scores = _RERANK_MODEL.predict(pairs) - - sorted_items = sorted( - zip(scores, unique_items), - key=lambda x: x[0], - reverse=True - ) - top_items = [item for _, item in sorted_items[:50]] - else: - top_items = [] - - # ── 5. 寫入 JSON 文件 ────────────────────────────────────────── - if not top_items: - return {"status": "no_relevant_content", "items_count": 0, "json_path": None} - - # 產生有意義的檔名 - safe_query = re.sub(r'[^a-zA-Z0-9\u4e00-\u9fa5]', '_', query)[:40] - timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") - json_filename = f"extracted_{safe_query}_{timestamp}.json" - - # 建議的儲存目錄(與 crawl4ai_batch 對齊) - output_dir = os.path.join(os.path.dirname(file_paths[0]), "..", "extracted") - os.makedirs(output_dir, exist_ok=True) - - json_path = os.path.join(output_dir, json_filename) - - with open(json_path, "w", encoding="utf-8") as f: - json.dump( - { - "query": query, - "extracted_at": timestamp, - "item_count": len(top_items), - "items": top_items - }, - f, - ensure_ascii=False, - indent=2 - ) - - # ── 6. 只回傳摘要 ────────────────────────────────────────────── - return { - "status": "success", - "items_count": len(top_items), - "json_path": json_path, - "summary": f"已提取 {len(top_items)} 個高相關片段,儲存於 {json_path}" - } - - def _extract_source_from_md(content: str) -> Optional[str]: match = re.search(r"", content) return match.group(1).strip() if match else None @@ -223,3 +108,126 @@ def _chunk_text( start = max(0, end - overlap) return chunks + + +def create_structured_retrieval_tool(workspace_dir): + @tool("structured_retrieval", args_schema=StructuredRetrievalInput) + def structured_retrieval( + file_paths: List[str], + query: str, + source_url: Optional[str] = None + ) -> Dict: + """ + Batch structured extraction from markdown files. + - Performs vector search + re-ranking + - Saves extracted structured data as JSON file to disk + - Returns ONLY summary (status, count, file path) + """ + + # ── 1. 收集所有文件內容 ────────────────────────────────────── + all_docs_pool: List[Document] = [] + + for path in file_paths: + if not os.path.exists(path) or not path.endswith((".md", ".markdown")): + continue + + file_name = os.path.basename(path) + + with open(path, "r", encoding="utf-8") as f: + content = f.read() + + current_source = source_url or _extract_source_from_md(content) or "unknown" + + sections = _split_markdown_by_headers(content) + + for sec in sections: + all_docs_pool.append( + Document( + page_content=sec, + metadata={"source_url": current_source, "file_name": file_name} + ) + ) + + if not all_docs_pool: + return {"status": "no_documents_found", "items_count": 0, "json_path": None} + + # ── 2. Vector search ──────────────────────────────────────────── + vector_store = FAISS.from_documents(all_docs_pool, _EMBEDDING_MODEL) + retrieved = vector_store.similarity_search(query, k=200) + + # ── 3. 提取結構化片段 ────────────────────────────────────────── + structured_items = [] + + for doc in retrieved: + text = doc.page_content.strip() + if len(text) < 30: + continue + + images = list(set(re.findall(r"!\[.*?\]\((.*?)\)", text))) + + structured_items.append( + { + "text": text, + "images": images, + "source_url": doc.metadata.get("source_url"), + "file_name": doc.metadata.get("file_name") + } + ) + + # ── 4. Re-rank ────────────────────────────────────────────────── + if structured_items: + unique_items = {item["text"]: item for item in structured_items}.values() + pairs = [[query, item["text"]] for item in unique_items] + scores = _RERANK_MODEL.predict(pairs) + + sorted_items = sorted( + zip(scores, unique_items), + key=lambda x: x[0], + reverse=True + ) + top_items = [item for _, item in sorted_items[:50]] + else: + top_items = [] + + # ── 5. 寫入 JSON 文件 ────────────────────────────────────────── + if not top_items: + return {"status": "no_relevant_content", "items_count": 0, "json_path": None} + + # 產生有意義的檔名 + safe_query = re.sub(r'[^a-zA-Z0-9\u4e00-\u9fa5]', '_', query)[:40] + timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") + json_filename = f"extracted_{safe_query}_{timestamp}.json" + + # 建議的儲存目錄(與 crawl4ai_batch 對齊) + output_dir = os.path.join(workspace_dir, "extracted") + if not os.path.exists(output_dir): + os.makedirs(output_dir, exist_ok=True) + + if not os.path.exists(output_dir): + # 2. 不存在则创建(makedirs 支持创建多级目录,mkdir 只能创建单级) + os.makedirs(output_dir, exist_ok=True) + + json_path = os.path.join(output_dir, json_filename) + + with open(json_path, "w", encoding="utf-8") as f: + json.dump( + { + "query": query, + "extracted_at": timestamp, + "item_count": len(top_items), + "items": top_items + }, + f, + ensure_ascii=False, + indent=2 + ) + + # ── 6. 只回傳摘要 ────────────────────────────────────────────── + return { + "status": "success", + "items_count": len(top_items), + "json_path": json_path, + "summary": f"已提取 {len(top_items)} 個高相關片段,儲存於 {json_path}" + } + + return structured_retrieval diff --git a/src/server/deep_agent/tools/vision_analyze_tool.py b/src/server/deep_agent/tools/vision_analyze_tool.py new file mode 100644 index 0000000..9d1aafd --- /dev/null +++ b/src/server/deep_agent/tools/vision_analyze_tool.py @@ -0,0 +1,21 @@ +from langchain.tools import tool +from langchain_core.messages import HumanMessage +from PIL import Image +import requests +from io import BytesIO + +from src.server.deep_agent.init_llm import vision_llm + + +@tool +def analyze_image(image_url: str) -> str: + """分析给定URL的图像。输入图像URL,输出图像描述和关键观察。""" + response = requests.get(image_url) + image = Image.open(BytesIO(response.content)) + # 这里使用模型直接分析图像(简化示例) + msg = HumanMessage(content=[ + {"type": "text", "text": "详细描述这张图像,包括物体、颜色、场景和任何文本。"}, + {"type": "image_url", "image_url": {"url": image_url}} + ]) + result = vision_llm.invoke([msg]) + return result.content diff --git a/src/server/utils/new_oss_client.py b/src/server/utils/new_oss_client.py index 49696cb..cb22834 100644 --- a/src/server/utils/new_oss_client.py +++ b/src/server/utils/new_oss_client.py @@ -36,7 +36,7 @@ http_client = urllib3.PoolManager( # 获取图片 -def oss_get_image(oss_client, bucket, object_name, data_type): +def oss_get_image(oss_client, bucket, object_name): # cv2 默认全通道读取 image_object = None try: @@ -57,9 +57,44 @@ def oss_upload_image(oss_client, bucket, object_name, image_bytes): return req +def oss_upload_image_file(oss_client, bucket, object_name, file_path): + req = None + try: + req = oss_client.fput_object( + bucket_name=bucket, + object_name=object_name, + file_path=file_path + ) + except Exception as e: + logger.warning(f" | 上传图片出现异常 ######: {e}") + return req + + +def get_presigned_url(oss_client, bucket, object_name): + try: + presigned_url = oss_client.presigned_get_object( + bucket_name=bucket, + object_name=object_name, + expires=3600 + ) + return presigned_url + except Exception as e: + print(f"get_presigned_url exception :{e}") + return "object not found" + + +def is_minio_file_exist(minio_client: Minio, bucket_name: str, object_name: str) -> bool: + try: + # 核心判断:检查MinIO中指定bucket+object是否存在 + minio_client.stat_object(bucket_name, object_name) + return True + except Exception as e: + return False + + if __name__ == '__main__': - url = "fida-test/furniture/sketches/4449a66d-6267-43f7-86a2-1e42bd19ec61.png" + url = 'fida-test/furniture/sketches/9356e3d8-d56e-4478-adde-61b29119979b.png' read_type = "2" - img = oss_get_image(oss_client=minio_client, bucket=url.split('/')[0], object_name=url[url.find('/') + 1:], data_type=read_type) + img = oss_get_image(oss_client=minio_client, bucket=url.split('/')[0], object_name=url[url.find('/') + 1:]) img.show() img.save("result.png") diff --git a/uv.lock b/uv.lock index f69a09a..151636b 100644 --- a/uv.lock +++ b/uv.lock @@ -21,11 +21,11 @@ wheels = [ [[package]] name = "aiofiles" -version = "25.1.0" +version = "24.1.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/41/c3/534eac40372d8ee36ef40df62ec129bee4fdb5ad9706e58a29be53b2c970/aiofiles-25.1.0.tar.gz", hash = "sha256:a8d728f0a29de45dc521f18f07297428d56992a742f0cd2701ba86e44d23d5b2", size = 46354, upload-time = "2025-10-09T20:51:04.358Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0b/03/a88171e277e8caa88a4c77808c20ebb04ba74cc4681bf1e9416c862de237/aiofiles-24.1.0.tar.gz", hash = "sha256:22a075c9e5a3810f0c2e48f3008c94d68c65d763b9b03857924c99e57355166c", size = 30247, upload-time = "2024-06-24T11:02:03.584Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl", hash = "sha256:abe311e527c862958650f9438e859c1fa7568a141b22abcd015e120e86a85695", size = 14668, upload-time = "2025-10-09T20:51:03.174Z" }, + { url = "https://files.pythonhosted.org/packages/a5/45/30bb92d442636f570cb5651bc661f52b610e2eec3f891a5dc3a4c3667db0/aiofiles-24.1.0-py3-none-any.whl", hash = "sha256:b4ec55f4195e3eb5d7abd1bf7e061763e864dd4954231fb8539a0ef8bb8260e5", size = 15896, upload-time = "2024-06-24T11:02:01.529Z" }, ] [[package]] @@ -122,6 +122,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b4/63/278a98c715ae467624eafe375542d8ba9b4383a016df8fdefe0ae28382a7/aiohttp-3.13.3-cp314-cp314t-win_amd64.whl", hash = "sha256:44531a36aa2264a1860089ffd4dce7baf875ee5a6079d5fb42e261c704ef7344", size = 499694, upload-time = "2026-01-03T17:32:24.546Z" }, ] +[[package]] +name = "aiohttp-retry" +version = "2.9.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohttp" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9d/61/ebda4d8e3d8cfa1fd3db0fb428db2dd7461d5742cea35178277ad180b033/aiohttp_retry-2.9.1.tar.gz", hash = "sha256:8eb75e904ed4ee5c2ec242fefe85bf04240f685391c4879d8f541d6028ff01f1", size = 13608, upload-time = "2024-11-06T10:44:54.574Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1a/99/84ba7273339d0f3dfa57901b846489d2e5c2cd731470167757f1935fffbd/aiohttp_retry-2.9.1-py3-none-any.whl", hash = "sha256:66d2759d1921838256a05a3f80ad7e724936f083e35be5abb5e16eed6be6dc54", size = 9981, upload-time = "2024-11-06T10:44:52.917Z" }, +] + [[package]] name = "aiosignal" version = "1.4.0" @@ -213,6 +225,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl", hash = "sha256:d405828884fc140aa80a3c667b8beed277f1dfedec42ba031bd6ac3db606ab6c", size = 113592, upload-time = "2026-01-06T11:45:19.497Z" }, ] +[[package]] +name = "argh" +version = "0.31.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4f/34/bc0b3577a818b4b70c6e318d23fe3c81fc3bb25f978ca8a3965cd8ee3af9/argh-0.31.3.tar.gz", hash = "sha256:f30023d8be14ca5ee6b1b3eeab829151d7bbda464ae07dc4dd5347919c5892f9", size = 57570, upload-time = "2024-07-13T17:54:59.729Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d2/52/fcd83710b6f8786df80e5d335882d1b24d1f610f397703e94a6ffb0d6f66/argh-0.31.3-py3-none-any.whl", hash = "sha256:2edac856ff50126f6e47d884751328c9f466bacbbb6cbfdac322053d94705494", size = 44844, upload-time = "2024-07-13T17:54:57.706Z" }, +] + [[package]] name = "argon2-cffi" version = "25.1.0" @@ -678,6 +699,98 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/cf/7a/ea0f3e3ea74be36fc7cf54f966cde732a3de72697983cdb5646b0a4dacde/datetime-6.0-py3-none-any.whl", hash = "sha256:d19988f0657a4e72c9438344157254a8dcad6aea8cd5ae70a5d1b5a75e5dc930", size = 52637, upload-time = "2025-11-25T08:00:33.077Z" }, ] +[[package]] +name = "daytona" +version = "0.152.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiofiles" }, + { name = "daytona-api-client" }, + { name = "daytona-api-client-async" }, + { name = "daytona-toolbox-api-client" }, + { name = "daytona-toolbox-api-client-async" }, + { name = "deprecated" }, + { name = "environs" }, + { name = "httpx" }, + { name = "obstore" }, + { name = "opentelemetry-api" }, + { name = "opentelemetry-exporter-otlp-proto-http" }, + { name = "opentelemetry-instrumentation-aiohttp-client" }, + { name = "opentelemetry-sdk" }, + { name = "pydantic" }, + { name = "python-multipart" }, + { name = "toml" }, + { name = "websockets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d2/af/5e9245a5c801cac274e1050681fe06a6d48ffcd11343ea575575653316f5/daytona-0.152.1.tar.gz", hash = "sha256:8fe79095ace9652120e18eb2093798067a4afb4ec609922b24d07a154e573265", size = 124193, upload-time = "2026-03-18T18:25:32.206Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/96/ad/617ad1872fe2318d6c8da56f18654646c34d7b78864dfc14cdaf4208e9f7/daytona-0.152.1-py3-none-any.whl", hash = "sha256:16fa90aa6bb521cd767a5dc241bba1e4b69f63090169b7c40c35bb6ff2746c80", size = 153889, upload-time = "2026-03-18T18:25:30.412Z" }, +] + +[[package]] +name = "daytona-api-client" +version = "0.152.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pydantic" }, + { name = "python-dateutil" }, + { name = "typing-extensions" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cb/5e/3a90e14684954975a36adf0aeec08eff87e461f058d27360587d5c1afaad/daytona_api_client-0.152.1.tar.gz", hash = "sha256:4be68957de15f3ae44e5f043c7a04d2e375541d1d307b0ceda9fc40414fbe5e7", size = 140769, upload-time = "2026-03-18T18:24:38.241Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/98/01/40388deba155d40765b1e5eb49c04063b1024fe1eae7f77252f4f4a88452/daytona_api_client-0.152.1-py3-none-any.whl", hash = "sha256:99ef79c00aa23f58dd1438d9f33f632f310749ceaf2c698f256556317f3acab7", size = 394605, upload-time = "2026-03-18T18:24:36.571Z" }, +] + +[[package]] +name = "daytona-api-client-async" +version = "0.152.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohttp" }, + { name = "aiohttp-retry" }, + { name = "pydantic" }, + { name = "python-dateutil" }, + { name = "typing-extensions" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/11/f2/34dffdc9da9f9cd5c4b50242f4500ddc0f944d4ef237e3aadccbcf5e85c2/daytona_api_client_async-0.152.1.tar.gz", hash = "sha256:954b1700c96205233b9fa5f33309c9bc074108a99d87f2b5b1ad26a570989d98", size = 140921, upload-time = "2026-03-18T18:24:40.807Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b8/54/a037af7d48b1eea0a21677d92923436adc9f8bf53902424bc35b0e9bbcf1/daytona_api_client_async-0.152.1-py3-none-any.whl", hash = "sha256:af97afc9bc4a08168bf3d4760655151ad4515f1e46fa6cd08f5ce1a1f365324c", size = 397596, upload-time = "2026-03-18T18:24:39.153Z" }, +] + +[[package]] +name = "daytona-toolbox-api-client" +version = "0.152.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pydantic" }, + { name = "python-dateutil" }, + { name = "typing-extensions" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ac/9e/8a3fd8fa74953a8008dfb43cb210684177972bb57ef6c7a1439f5fe2812d/daytona_toolbox_api_client-0.152.1.tar.gz", hash = "sha256:a62afd4ca65c6bec21442a33bfb116cff0ec2a0427c495459be3dcd4ce6c60cd", size = 64628, upload-time = "2026-03-18T18:24:34.67Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/17/03/27d0a688fb39a2ed57506f6fe154eee7cc766a569474a7537f9526f37a5b/daytona_toolbox_api_client-0.152.1-py3-none-any.whl", hash = "sha256:7ec9091c137f15a0e632771bf64904b1a88f83d915dcb234f08800599d523df6", size = 174402, upload-time = "2026-03-18T18:24:33.315Z" }, +] + +[[package]] +name = "daytona-toolbox-api-client-async" +version = "0.152.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohttp" }, + { name = "aiohttp-retry" }, + { name = "pydantic" }, + { name = "python-dateutil" }, + { name = "typing-extensions" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a6/9c/9970b2b9e9bd7e3dfc91d4b0b9d5648ad56c905256b614c2f99a169c3567/daytona_toolbox_api_client_async-0.152.1.tar.gz", hash = "sha256:36ea58e25ff2824348ad7c164cc4246143c8a712cd9bb88a5c9d5c0d2b122459", size = 61702, upload-time = "2026-03-18T18:24:59.143Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/60/10/56875085063b974dcdc27350bb9d13314f8ff8a5e47329041b8f2d42f364/daytona_toolbox_api_client_async-0.152.1-py3-none-any.whl", hash = "sha256:086f58e708c3b4ab2d99fa5f4ea62711a70b5d7f0cc94f393e4fd96529cf7d6f", size = 175773, upload-time = "2026-03-18T18:24:57.961Z" }, +] + [[package]] name = "deepagents" version = "0.4.5" @@ -694,6 +807,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a1/4d/9f5e021492fc17e46e5ebd3f21a83d1a56725c0ccce95f427a18edcfbe8f/deepagents-0.4.5-py3-none-any.whl", hash = "sha256:378e401be3ce79b8da1ce1ef792460501a28969c5b78b00985ed4b2a6dbb7605", size = 99261, upload-time = "2026-03-03T21:41:53.737Z" }, ] +[[package]] +name = "deprecated" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "wrapt" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/49/85/12f0a49a7c4ffb70572b6c2ef13c90c88fd190debda93b23f026b25f9634/deprecated-1.3.1.tar.gz", hash = "sha256:b1b50e0ff0c1fddaa5708a2c6b0a6588bb09b892825ab2b214ac9ea9d92a5223", size = 2932523, upload-time = "2025-10-30T08:19:02.757Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/84/d0/205d54408c08b13550c733c4b85429e7ead111c7f0014309637425520a9a/deprecated-1.3.1-py2.py3-none-any.whl", hash = "sha256:597bfef186b6f60181535a29fbe44865ce137a5079f295b479886c82729d5f3f", size = 11298, upload-time = "2025-10-30T08:19:00.758Z" }, +] + [[package]] name = "distro" version = "1.9.0" @@ -748,6 +873,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl", hash = "sha256:80f13f623413e6b197ae73bb10bf4eb0908faf509ad8362c5edeb0be7fd450b4", size = 35604, upload-time = "2025-08-26T13:09:05.858Z" }, ] +[[package]] +name = "environs" +version = "14.6.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "marshmallow" }, + { name = "python-dotenv" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fb/c7/94f97e6e74482a50b5fc798856b6cc06e8d072ab05a0b74cb5d87bd0d065/environs-14.6.0.tar.gz", hash = "sha256:ed2767588deb503209ffe4dd9bb2b39311c2e4e7e27ce2c64bf62ca83328d068", size = 35563, upload-time = "2026-02-20T04:02:08.869Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/97/a8/c070e1340636acb38d4e6a7e45c46d168a462b48b9b3257e14ca0e5af79b/environs-14.6.0-py3-none-any.whl", hash = "sha256:f8fb3d6c6a55872b0c6db077a28f5a8c7b8984b7c32029613d44cef95cfc0812", size = 17205, upload-time = "2026-02-20T04:02:07.299Z" }, +] + [[package]] name = "faiss-cpu" version = "1.13.2" @@ -983,6 +1121,7 @@ dependencies = [ { name = "langchain-classic" }, { name = "langchain-community" }, { name = "langchain-core" }, + { name = "langchain-daytona" }, { name = "langchain-google-genai" }, { name = "langchain-huggingface" }, { name = "langchain-qwq" }, @@ -1009,6 +1148,7 @@ dependencies = [ { name = "sentence-transformers" }, { name = "tavily-python" }, { name = "terminate" }, + { name = "tool" }, { name = "torch" }, { name = "uuid" }, { name = "uvicorn" }, @@ -1030,6 +1170,7 @@ requires-dist = [ { name = "langchain-classic", specifier = ">=1.0.1" }, { name = "langchain-community", specifier = ">=0.4.1" }, { name = "langchain-core", specifier = ">=1.2.8" }, + { name = "langchain-daytona", specifier = ">=0.0.3" }, { name = "langchain-google-genai", specifier = ">=4.2.0" }, { name = "langchain-huggingface", specifier = ">=1.2.0" }, { name = "langchain-qwq", specifier = ">=0.3.4" }, @@ -1056,6 +1197,7 @@ requires-dist = [ { name = "sentence-transformers", specifier = ">=5.2.3" }, { name = "tavily-python", specifier = ">=0.7.21" }, { name = "terminate", specifier = ">=0.0.9" }, + { name = "tool", specifier = ">=0.8.0" }, { name = "torch", specifier = ">=2.10.0" }, { name = "uuid", specifier = ">=1.30" }, { name = "uvicorn", specifier = ">=0.40.0" }, @@ -1217,6 +1359,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/dd/403949d922d4e261b08b64aaa132af4e456c3b15c8e2a2d9e6ef693f66e2/google_genai-1.66.0-py3-none-any.whl", hash = "sha256:7f127a39cf695277104ce4091bb26e417c59bb46e952ff3699c3a982d9c474ee", size = 732174, upload-time = "2026-03-04T22:15:26.63Z" }, ] +[[package]] +name = "googleapis-common-protos" +version = "1.73.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/99/96/a0205167fa0154f4a542fd6925bdc63d039d88dab3588b875078107e6f06/googleapis_common_protos-1.73.0.tar.gz", hash = "sha256:778d07cd4fbeff84c6f7c72102f0daf98fa2bfd3fa8bea426edc545588da0b5a", size = 147323, upload-time = "2026-03-06T21:53:09.727Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/69/28/23eea8acd65972bbfe295ce3666b28ac510dfcb115fac089d3edb0feb00a/googleapis_common_protos-1.73.0-py3-none-any.whl", hash = "sha256:dfdaaa2e860f242046be561e6d6cb5c5f1541ae02cfbcb034371aadb2942b4e8", size = 297578, upload-time = "2026-03-06T21:52:33.933Z" }, +] + [[package]] name = "greenlet" version = "3.3.2" @@ -1710,6 +1864,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/be/90/073f33ab383a62908eca7ea699586dfea280e77182176e33199c80ddf22a/langchain_core-1.2.17-py3-none-any.whl", hash = "sha256:bf6bd6ce503874e9c2da1669a69383e967c3de1ea808921d19a9a6bff1a9fbbe", size = 502727, upload-time = "2026-03-02T22:47:54.537Z" }, ] +[[package]] +name = "langchain-daytona" +version = "0.0.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "daytona" }, + { name = "deepagents" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/62/cd/294fdd58be04d08fecb4f191ac8901d06fabb1096b083ef5f757180749d8/langchain_daytona-0.0.3.tar.gz", hash = "sha256:5d89f5158ef30b7dcb168b5f7de742658e59265c59697e13c4d09dbe86a38384", size = 185650, upload-time = "2026-03-06T21:51:52.617Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/67/d7/2783b771cae9e4dc54f5677e89d5b9c38c7b69a78786256185694b62c87c/langchain_daytona-0.0.3-py3-none-any.whl", hash = "sha256:85bd0f35d7e0dbb269446aa537dc784ed082d718572e6167c36a27f351bf10ca", size = 4288, upload-time = "2026-03-06T21:51:51.642Z" }, +] + [[package]] name = "langchain-google-genai" version = "4.2.1" @@ -2462,6 +2629,55 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a2/eb/86626c1bbc2edb86323022371c39aa48df6fd8b0a1647bc274577f72e90b/nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5b17e2001cc0d751a5bc2c6ec6d26ad95913324a4adb86788c944f8ce9ba441f", size = 89954, upload-time = "2025-03-07T01:42:44.131Z" }, ] +[[package]] +name = "obstore" +version = "0.8.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a3/8c/9ec984edd0f3b72226adfaa19b1c61b15823b35b52f311ca4af36d009d15/obstore-0.8.2.tar.gz", hash = "sha256:a467bc4e97169e2ba749981b4fd0936015428d9b8f3fb83a5528536b1b6f377f", size = 168852, upload-time = "2025-09-16T15:34:55.786Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2b/dc/60fefbb5736e69eab56657bca04ca64dc07fdeccb3814164a31b62ad066b/obstore-0.8.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:bb70ce297a47392b1d9a3e310f18d59cd5ebbb9453428210fef02ed60e4d75d1", size = 3612955, upload-time = "2025-09-16T15:33:29.527Z" }, + { url = "https://files.pythonhosted.org/packages/d2/8b/844e8f382e5a12b8a3796a05d76a03e12c7aedc13d6900419e39207d7868/obstore-0.8.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1619bf618428abf1f607e0b219b2e230a966dcf697b717deccfa0983dd91f646", size = 3346564, upload-time = "2025-09-16T15:33:30.698Z" }, + { url = "https://files.pythonhosted.org/packages/89/73/8537f99e09a38a54a6a15ede907aa25d4da089f767a808f0b2edd9c03cec/obstore-0.8.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a4605c3ed7c9515aeb4c619b5f7f2c9986ed4a79fe6045e536b5e59b804b1476", size = 3460809, upload-time = "2025-09-16T15:33:31.837Z" }, + { url = "https://files.pythonhosted.org/packages/b4/99/7714dec721e43f521d6325a82303a002cddad089437640f92542b84e9cc8/obstore-0.8.2-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce42670417876dd8668cbb8659e860e9725e5f26bbc86449fd259970e2dd9d18", size = 3692081, upload-time = "2025-09-16T15:33:33.028Z" }, + { url = "https://files.pythonhosted.org/packages/ec/bd/4ac4175fe95a24c220a96021c25c432bcc0c0212f618be0737184eebbaad/obstore-0.8.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4a3e893b2a06585f651c541c1972fe1e3bf999ae2a5fda052ee55eb7e6516f5", size = 3957466, upload-time = "2025-09-16T15:33:34.528Z" }, + { url = "https://files.pythonhosted.org/packages/4e/04/caa288fb735484fc5cb019bdf3d896eaccfae0ac4622e520d05692c46790/obstore-0.8.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08462b32f95a9948ed56ed63e88406e2e5a4cae1fde198f9682e0fb8487100ed", size = 3951293, upload-time = "2025-09-16T15:33:35.733Z" }, + { url = "https://files.pythonhosted.org/packages/44/2f/d380239da2d6a1fda82e17df5dae600a404e8a93a065784518ff8325d5f6/obstore-0.8.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a0bf7763292a8fc47d01cd66e6f19002c5c6ad4b3ed4e6b2729f5e190fa8a0d", size = 3766199, upload-time = "2025-09-16T15:33:36.904Z" }, + { url = "https://files.pythonhosted.org/packages/28/41/d391be069d3da82969b54266948b2582aeca5dd735abeda4d63dba36e07b/obstore-0.8.2-cp312-cp312-manylinux_2_24_aarch64.whl", hash = "sha256:bcd47f8126cb192cbe86942b8f73b1c45a651ce7e14c9a82c5641dfbf8be7603", size = 3529678, upload-time = "2025-09-16T15:33:38.221Z" }, + { url = "https://files.pythonhosted.org/packages/b9/4c/4862fdd1a3abde459ee8eea699b1797df638a460af235b18ca82c8fffb72/obstore-0.8.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:57eda9fd8c757c3b4fe36cf3918d7e589cc1286591295cc10b34122fa36dd3fd", size = 3698079, upload-time = "2025-09-16T15:33:39.696Z" }, + { url = "https://files.pythonhosted.org/packages/68/ca/014e747bc53b570059c27e3565b2316fbe5c107d4134551f4cd3e24aa667/obstore-0.8.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ea44442aad8992166baa69f5069750979e4c5d9ffce772e61565945eea5774b9", size = 3687154, upload-time = "2025-09-16T15:33:40.92Z" }, + { url = "https://files.pythonhosted.org/packages/6f/89/6db5f8edd93028e5b8bfbeee15e6bd3e56f72106107d31cb208b57659de4/obstore-0.8.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:41496a3ab8527402db4142aaaf0d42df9d7d354b13ba10d9c33e0e48dd49dd96", size = 3773444, upload-time = "2025-09-16T15:33:42.123Z" }, + { url = "https://files.pythonhosted.org/packages/26/e5/c9e2cc540689c873beb61246e1615d6e38301e6a34dec424f5a5c63c1afd/obstore-0.8.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:43da209803f052df96c7c3cbec512d310982efd2407e4a435632841a51143170", size = 3939315, upload-time = "2025-09-16T15:33:43.252Z" }, + { url = "https://files.pythonhosted.org/packages/4d/c9/bb53280ca50103c1ffda373cdc9b0f835431060039c2897cbc87ddd92e42/obstore-0.8.2-cp312-cp312-win_amd64.whl", hash = "sha256:1836f5dcd49f9f2950c75889ab5c51fb290d3ea93cdc39a514541e0be3af016e", size = 3978234, upload-time = "2025-09-16T15:33:44.393Z" }, + { url = "https://files.pythonhosted.org/packages/f0/5d/8c3316cc958d386d5e6ab03e9db9ddc27f8e2141cee4a6777ae5b92f3aac/obstore-0.8.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:212f033e53fe6e53d64957923c5c88949a400e9027f7038c705ec2e9038be563", size = 3612027, upload-time = "2025-09-16T15:33:45.6Z" }, + { url = "https://files.pythonhosted.org/packages/ea/4d/699359774ce6330130536d008bfc32827fab0c25a00238d015a5974a3d1d/obstore-0.8.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bee21fa4ba148d08fa90e47a96df11161661ed31e09c056a373cb2154b0f2852", size = 3344686, upload-time = "2025-09-16T15:33:47.185Z" }, + { url = "https://files.pythonhosted.org/packages/82/37/55437341f10512906e02fd9fa69a8a95ad3f2f6a916d3233fda01763d110/obstore-0.8.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4c66594b59832ff1ced4c72575d9beb8b5f9b4e404ac1150a42bfb226617fd50", size = 3459860, upload-time = "2025-09-16T15:33:48.382Z" }, + { url = "https://files.pythonhosted.org/packages/7a/51/4245a616c94ee4851965e33f7a563ab4090cc81f52cc73227ff9ceca2e46/obstore-0.8.2-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:089f33af5c2fe132d00214a0c1f40601b28f23a38e24ef9f79fb0576f2730b74", size = 3691648, upload-time = "2025-09-16T15:33:49.524Z" }, + { url = "https://files.pythonhosted.org/packages/4e/f1/4e2fb24171e3ca3641a4653f006be826e7e17634b11688a5190553b00b83/obstore-0.8.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d87f658dfd340d5d9ea2d86a7c90d44da77a0db9e00c034367dca335735110cf", size = 3956867, upload-time = "2025-09-16T15:33:51.082Z" }, + { url = "https://files.pythonhosted.org/packages/42/f5/b703115361c798c9c1744e1e700d5908d904a8c2e2bd38bec759c9ffb469/obstore-0.8.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6e2e4fa92828c4fbc2d487f3da2d3588701a1b67d9f6ca3c97cc2afc912e9c63", size = 3950599, upload-time = "2025-09-16T15:33:52.173Z" }, + { url = "https://files.pythonhosted.org/packages/53/20/08c6dc0f20c1394e2324b9344838e4e7af770cdcb52c30757a475f50daeb/obstore-0.8.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab440e89c5c37a8ec230857dd65147d4b923e0cada33297135d05e0f937d696a", size = 3765865, upload-time = "2025-09-16T15:33:53.291Z" }, + { url = "https://files.pythonhosted.org/packages/77/20/77907765e29b2eba6bd8821872284d91170d7084f670855b2dfcb249ea14/obstore-0.8.2-cp313-cp313-manylinux_2_24_aarch64.whl", hash = "sha256:b9beed107c5c9cd995d4a73263861fcfbc414d58773ed65c14f80eb18258a932", size = 3529807, upload-time = "2025-09-16T15:33:54.535Z" }, + { url = "https://files.pythonhosted.org/packages/a5/f5/f629d39cc30d050f52b1bf927e4d65c1cc7d7ffbb8a635cd546b5c5219a0/obstore-0.8.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b75b4e7746292c785e31edcd5aadc8b758238372a19d4c5e394db5c305d7d175", size = 3693629, upload-time = "2025-09-16T15:33:56.016Z" }, + { url = "https://files.pythonhosted.org/packages/30/ff/106763fd10f2a1cb47f2ef1162293c78ad52f4e73223d8d43fc6b755445d/obstore-0.8.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:f33e6c366869d05ab0b7f12efe63269e631c5450d95d6b4ba4c5faf63f69de70", size = 3686176, upload-time = "2025-09-16T15:33:57.247Z" }, + { url = "https://files.pythonhosted.org/packages/ce/0c/d2ccb6f32feeca906d5a7c4255340df5262af8838441ca06c9e4e37b67d5/obstore-0.8.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:12c885a9ce5ceb09d13cc186586c0c10b62597eff21b985f6ce8ff9dab963ad3", size = 3773081, upload-time = "2025-09-16T15:33:58.475Z" }, + { url = "https://files.pythonhosted.org/packages/fa/79/40d1cc504cefc89c9b3dd8874287f3fddc7d963a8748d6dffc5880222013/obstore-0.8.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4accc883b93349a81c9931e15dd318cc703b02bbef2805d964724c73d006d00e", size = 3938589, upload-time = "2025-09-16T15:33:59.734Z" }, + { url = "https://files.pythonhosted.org/packages/14/dd/916c6777222db3271e9fb3cf9a97ed92b3a9b3e465bdeec96de9ab809d53/obstore-0.8.2-cp313-cp313-win_amd64.whl", hash = "sha256:ec850adf9980e5788a826ccfd5819989724e2a2f712bfa3258e85966c8d9981e", size = 3977768, upload-time = "2025-09-16T15:34:01.25Z" }, + { url = "https://files.pythonhosted.org/packages/f1/61/66f8dc98bbf5613bbfe5bf21747b4c8091442977f4bd897945895ab7325c/obstore-0.8.2-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:1431e40e9bb4773a261e51b192ea6489d0799b9d4d7dbdf175cdf813eb8c0503", size = 3623364, upload-time = "2025-09-16T15:34:02.957Z" }, + { url = "https://files.pythonhosted.org/packages/1a/66/6d527b3027e42f625c8fc816ac7d19b0d6228f95bfe7666e4d6b081d2348/obstore-0.8.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ddb39d4da303f50b959da000aa42734f6da7ac0cc0be2d5a7838b62c97055bb9", size = 3347764, upload-time = "2025-09-16T15:34:04.236Z" }, + { url = "https://files.pythonhosted.org/packages/0d/79/c00103302b620192ea447a948921ad3fed031ce3d19e989f038e1183f607/obstore-0.8.2-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e01f4e13783db453e17e005a4a3ceff09c41c262e44649ba169d253098c775e8", size = 3460981, upload-time = "2025-09-16T15:34:05.595Z" }, + { url = "https://files.pythonhosted.org/packages/3d/d9/bfe4ed4b1aebc45b56644dd5b943cf8e1673505cccb352e66878a457e807/obstore-0.8.2-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:df0fc2d0bc17caff9b538564ddc26d7616f7e8b7c65b1a3c90b5048a8ad2e797", size = 3692711, upload-time = "2025-09-16T15:34:06.796Z" }, + { url = "https://files.pythonhosted.org/packages/13/47/cd6c2cbb18e1f40c77e7957a4a03d2d83f1859a2e876a408f1ece81cad4c/obstore-0.8.2-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e439d06c99a140348f046c9f598ee349cc2dcd9105c15540a4b231f9cc48bbae", size = 3958362, upload-time = "2025-09-16T15:34:08.277Z" }, + { url = "https://files.pythonhosted.org/packages/3d/ea/5ee82bf23abd71c7d6a3f2d008197ae8f8f569d41314c26a8f75318245be/obstore-0.8.2-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0e37d9046669fcc59522d0faf1d105fcbfd09c84cccaaa1e809227d8e030f32c", size = 3957082, upload-time = "2025-09-16T15:34:09.477Z" }, + { url = "https://files.pythonhosted.org/packages/cb/ee/46650405e50fdaa8d95f30375491f9c91fac9517980e8a28a4a6af66927f/obstore-0.8.2-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2646fdcc4bbe92dc2bb5bcdff15574da1211f5806c002b66d514cee2a23c7cb8", size = 3775539, upload-time = "2025-09-16T15:34:10.726Z" }, + { url = "https://files.pythonhosted.org/packages/35/d6/348a7ebebe2ca3d94dfc75344ea19675ae45472823e372c1852844078307/obstore-0.8.2-cp314-cp314-manylinux_2_24_aarch64.whl", hash = "sha256:e31a7d37675056d93dfc244605089dee67f5bba30f37c88436623c8c5ad9ba9d", size = 3535048, upload-time = "2025-09-16T15:34:12.076Z" }, + { url = "https://files.pythonhosted.org/packages/41/07/b7a16cc0da91a4b902d47880ad24016abfe7880c63f7cdafda45d89a2f91/obstore-0.8.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:656313dd8170dde0f0cd471433283337a63912e8e790a121f7cc7639c83e3816", size = 3699035, upload-time = "2025-09-16T15:34:13.331Z" }, + { url = "https://files.pythonhosted.org/packages/7f/74/3269a3a58347e0b019742d888612c4b765293c9c75efa44e144b1e884c0d/obstore-0.8.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:329038c9645d6d1741e77fe1a53e28a14b1a5c1461cfe4086082ad39ebabf981", size = 3687307, upload-time = "2025-09-16T15:34:14.501Z" }, + { url = "https://files.pythonhosted.org/packages/01/f9/4fd4819ad6a49d2f462a45be453561f4caebded0dc40112deeffc34b89b1/obstore-0.8.2-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:1e4df99b369790c97c752d126b286dc86484ea49bff5782843a265221406566f", size = 3776076, upload-time = "2025-09-16T15:34:16.207Z" }, + { url = "https://files.pythonhosted.org/packages/14/dd/7c4f958fa0b9fc4778fb3d232e38b37db8c6b260f641022fbba48b049d7e/obstore-0.8.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9e1c65c65e20cc990414a8a9af88209b1bbc0dd9521b5f6b0293c60e19439bb7", size = 3947445, upload-time = "2025-09-16T15:34:17.423Z" }, +] + [[package]] name = "openai" version = "2.26.0" @@ -2481,6 +2697,128 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c6/2e/3f73e8ca53718952222cacd0cf7eecc9db439d020f0c1fe7ae717e4e199a/openai-2.26.0-py3-none-any.whl", hash = "sha256:6151bf8f83802f036117f06cc8a57b3a4da60da9926826cc96747888b57f394f", size = 1136409, upload-time = "2026-03-05T23:17:34.072Z" }, ] +[[package]] +name = "opentelemetry-api" +version = "1.40.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "importlib-metadata" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2c/1d/4049a9e8698361cc1a1aa03a6c59e4fa4c71e0c0f94a30f988a6876a2ae6/opentelemetry_api-1.40.0.tar.gz", hash = "sha256:159be641c0b04d11e9ecd576906462773eb97ae1b657730f0ecf64d32071569f", size = 70851, upload-time = "2026-03-04T14:17:21.555Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5f/bf/93795954016c522008da367da292adceed71cca6ee1717e1d64c83089099/opentelemetry_api-1.40.0-py3-none-any.whl", hash = "sha256:82dd69331ae74b06f6a874704be0cfaa49a1650e1537d4a813b86ecef7d0ecf9", size = 68676, upload-time = "2026-03-04T14:17:01.24Z" }, +] + +[[package]] +name = "opentelemetry-exporter-otlp-proto-common" +version = "1.40.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "opentelemetry-proto" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/51/bc/1559d46557fe6eca0b46c88d4c2676285f1f3be2e8d06bb5d15fbffc814a/opentelemetry_exporter_otlp_proto_common-1.40.0.tar.gz", hash = "sha256:1cbee86a4064790b362a86601ee7934f368b81cd4cc2f2e163902a6e7818a0fa", size = 20416, upload-time = "2026-03-04T14:17:23.801Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8b/ca/8f122055c97a932311a3f640273f084e738008933503d0c2563cd5d591fc/opentelemetry_exporter_otlp_proto_common-1.40.0-py3-none-any.whl", hash = "sha256:7081ff453835a82417bf38dccf122c827c3cbc94f2079b03bba02a3165f25149", size = 18369, upload-time = "2026-03-04T14:17:04.796Z" }, +] + +[[package]] +name = "opentelemetry-exporter-otlp-proto-http" +version = "1.40.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "googleapis-common-protos" }, + { name = "opentelemetry-api" }, + { name = "opentelemetry-exporter-otlp-proto-common" }, + { name = "opentelemetry-proto" }, + { name = "opentelemetry-sdk" }, + { name = "requests" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2e/fa/73d50e2c15c56be4d000c98e24221d494674b0cc95524e2a8cb3856d95a4/opentelemetry_exporter_otlp_proto_http-1.40.0.tar.gz", hash = "sha256:db48f5e0f33217588bbc00274a31517ba830da576e59503507c839b38fa0869c", size = 17772, upload-time = "2026-03-04T14:17:25.324Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/3a/8865d6754e61c9fb170cdd530a124a53769ee5f740236064816eb0ca7301/opentelemetry_exporter_otlp_proto_http-1.40.0-py3-none-any.whl", hash = "sha256:a8d1dab28f504c5d96577d6509f80a8150e44e8f45f82cdbe0e34c99ab040069", size = 19960, upload-time = "2026-03-04T14:17:07.153Z" }, +] + +[[package]] +name = "opentelemetry-instrumentation" +version = "0.61b0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "opentelemetry-api" }, + { name = "opentelemetry-semantic-conventions" }, + { name = "packaging" }, + { name = "wrapt" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/da/37/6bf8e66bfcee5d3c6515b79cb2ee9ad05fe573c20f7ceb288d0e7eeec28c/opentelemetry_instrumentation-0.61b0.tar.gz", hash = "sha256:cb21b48db738c9de196eba6b805b4ff9de3b7f187e4bbf9a466fa170514f1fc7", size = 32606, upload-time = "2026-03-04T14:20:16.825Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d8/3e/f6f10f178b6316de67f0dfdbbb699a24fbe8917cf1743c1595fb9dcdd461/opentelemetry_instrumentation-0.61b0-py3-none-any.whl", hash = "sha256:92a93a280e69788e8f88391247cc530fd81f16f2b011979d4d6398f805cfbc63", size = 33448, upload-time = "2026-03-04T14:19:02.447Z" }, +] + +[[package]] +name = "opentelemetry-instrumentation-aiohttp-client" +version = "0.61b0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "opentelemetry-api" }, + { name = "opentelemetry-instrumentation" }, + { name = "opentelemetry-semantic-conventions" }, + { name = "opentelemetry-util-http" }, + { name = "wrapt" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/24fed4de661de107f2426b28bbd87b51eaab28a2339b62f269a36ae24505/opentelemetry_instrumentation_aiohttp_client-0.61b0.tar.gz", hash = "sha256:c53ab3b88efcb7ce98c1129cc0389f0a1f214eb3675269b6c157770adcf47877", size = 19292, upload-time = "2026-03-04T14:20:18.408Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/df/f3/1edc42716521a3f754ac32ffb908f102e0f131f8e43fcd9ab29cab286723/opentelemetry_instrumentation_aiohttp_client-0.61b0-py3-none-any.whl", hash = "sha256:09bc47514c162507b357366ce15578743fd6305078cf7d872db1c99c13fa6972", size = 14534, upload-time = "2026-03-04T14:19:05.165Z" }, +] + +[[package]] +name = "opentelemetry-proto" +version = "1.40.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4c/77/dd38991db037fdfce45849491cb61de5ab000f49824a00230afb112a4392/opentelemetry_proto-1.40.0.tar.gz", hash = "sha256:03f639ca129ba513f5819810f5b1f42bcb371391405d99c168fe6937c62febcd", size = 45667, upload-time = "2026-03-04T14:17:31.194Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b9/b2/189b2577dde745b15625b3214302605b1353436219d42b7912e77fa8dc24/opentelemetry_proto-1.40.0-py3-none-any.whl", hash = "sha256:266c4385d88923a23d63e353e9761af0f47a6ed0d486979777fe4de59dc9b25f", size = 72073, upload-time = "2026-03-04T14:17:16.673Z" }, +] + +[[package]] +name = "opentelemetry-sdk" +version = "1.40.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "opentelemetry-api" }, + { name = "opentelemetry-semantic-conventions" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/58/fd/3c3125b20ba18ce2155ba9ea74acb0ae5d25f8cd39cfd37455601b7955cc/opentelemetry_sdk-1.40.0.tar.gz", hash = "sha256:18e9f5ec20d859d268c7cb3c5198c8d105d073714db3de50b593b8c1345a48f2", size = 184252, upload-time = "2026-03-04T14:17:31.87Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/c5/6a852903d8bfac758c6dc6e9a68b015d3c33f2f1be5e9591e0f4b69c7e0a/opentelemetry_sdk-1.40.0-py3-none-any.whl", hash = "sha256:787d2154a71f4b3d81f20524a8ce061b7db667d24e46753f32a7bc48f1c1f3f1", size = 141951, upload-time = "2026-03-04T14:17:17.961Z" }, +] + +[[package]] +name = "opentelemetry-semantic-conventions" +version = "0.61b0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "opentelemetry-api" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6d/c0/4ae7973f3c2cfd2b6e321f1675626f0dab0a97027cc7a297474c9c8f3d04/opentelemetry_semantic_conventions-0.61b0.tar.gz", hash = "sha256:072f65473c5d7c6dc0355b27d6c9d1a679d63b6d4b4b16a9773062cb7e31192a", size = 145755, upload-time = "2026-03-04T14:17:32.664Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b2/37/cc6a55e448deaa9b27377d087da8615a3416d8ad523d5960b78dbeadd02a/opentelemetry_semantic_conventions-0.61b0-py3-none-any.whl", hash = "sha256:fa530a96be229795f8cef353739b618148b0fe2b4b3f005e60e262926c4d38e2", size = 231621, upload-time = "2026-03-04T14:17:19.33Z" }, +] + +[[package]] +name = "opentelemetry-util-http" +version = "0.61b0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/57/3c/f0196223efc5c4ca19f8fad3d5462b171ac6333013335ce540c01af419e9/opentelemetry_util_http-0.61b0.tar.gz", hash = "sha256:1039cb891334ad2731affdf034d8fb8b48c239af9b6dd295e5fabd07f1c95572", size = 11361, upload-time = "2026-03-04T14:20:57.01Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0d/e5/c08aaaf2f64288d2b6ef65741d2de5454e64af3e050f34285fb1907492fe/opentelemetry_util_http-0.61b0-py3-none-any.whl", hash = "sha256:8e715e848233e9527ea47e275659ea60a57a75edf5206a3b937e236a6da5fc33", size = 9281, upload-time = "2026-03-04T14:20:08.364Z" }, +] + [[package]] name = "orjson" version = "3.11.7" @@ -2804,6 +3142,21 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5b/5a/bc7b4a4ef808fa59a816c17b20c4bef6884daebbdf627ff2a161da67da19/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237", size = 13305, upload-time = "2025-10-08T19:49:00.792Z" }, ] +[[package]] +name = "protobuf" +version = "6.33.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/66/70/e908e9c5e52ef7c3a6c7902c9dfbb34c7e29c25d2f81ade3856445fd5c94/protobuf-6.33.6.tar.gz", hash = "sha256:a6768d25248312c297558af96a9f9c929e8c4cee0659cb07e780731095f38135", size = 444531, upload-time = "2026-03-18T19:05:00.988Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fc/9f/2f509339e89cfa6f6a4c4ff50438db9ca488dec341f7e454adad60150b00/protobuf-6.33.6-cp310-abi3-win32.whl", hash = "sha256:7d29d9b65f8afef196f8334e80d6bc1d5d4adedb449971fefd3723824e6e77d3", size = 425739, upload-time = "2026-03-18T19:04:48.373Z" }, + { url = "https://files.pythonhosted.org/packages/76/5d/683efcd4798e0030c1bab27374fd13a89f7c2515fb1f3123efdfaa5eab57/protobuf-6.33.6-cp310-abi3-win_amd64.whl", hash = "sha256:0cd27b587afca21b7cfa59a74dcbd48a50f0a6400cfb59391340ad729d91d326", size = 437089, upload-time = "2026-03-18T19:04:50.381Z" }, + { url = "https://files.pythonhosted.org/packages/5c/01/a3c3ed5cd186f39e7880f8303cc51385a198a81469d53d0fdecf1f64d929/protobuf-6.33.6-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:9720e6961b251bde64edfdab7d500725a2af5280f3f4c87e57c0208376aa8c3a", size = 427737, upload-time = "2026-03-18T19:04:51.866Z" }, + { url = "https://files.pythonhosted.org/packages/ee/90/b3c01fdec7d2f627b3a6884243ba328c1217ed2d978def5c12dc50d328a3/protobuf-6.33.6-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:e2afbae9b8e1825e3529f88d514754e094278bb95eadc0e199751cdd9a2e82a2", size = 324610, upload-time = "2026-03-18T19:04:53.096Z" }, + { url = "https://files.pythonhosted.org/packages/9b/ca/25afc144934014700c52e05103c2421997482d561f3101ff352e1292fb81/protobuf-6.33.6-cp39-abi3-manylinux2014_s390x.whl", hash = "sha256:c96c37eec15086b79762ed265d59ab204dabc53056e3443e702d2681f4b39ce3", size = 339381, upload-time = "2026-03-18T19:04:54.616Z" }, + { url = "https://files.pythonhosted.org/packages/16/92/d1e32e3e0d894fe00b15ce28ad4944ab692713f2e7f0a99787405e43533a/protobuf-6.33.6-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:e9db7e292e0ab79dd108d7f1a94fe31601ce1ee3f7b79e0692043423020b0593", size = 323436, upload-time = "2026-03-18T19:04:55.768Z" }, + { url = "https://files.pythonhosted.org/packages/c4/72/02445137af02769918a93807b2b7890047c32bfb9f90371cbc12688819eb/protobuf-6.33.6-py3-none-any.whl", hash = "sha256:77179e006c476e69bf8e8ce866640091ec42e1beb80b213c3900006ecfba6901", size = 170656, upload-time = "2026-03-18T19:04:59.826Z" }, +] + [[package]] name = "psutil" version = "7.2.2" @@ -3133,6 +3486,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/00/4b/ccc026168948fec4f7555b9164c724cf4125eac006e176541483d2c959be/pydantic_settings-2.13.1-py3-none-any.whl", hash = "sha256:d56fd801823dbeae7f0975e1f8c8e25c258eb75d278ea7abb5d9cebb01b56237", size = 58929, upload-time = "2026-02-19T13:45:06.034Z" }, ] +[[package]] +name = "pydispatcher" +version = "2.0.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/21/db/030d0700ae90d2f9d52c2f3c1f864881e19cef8cba3b0a08759c8494c19c/PyDispatcher-2.0.7.tar.gz", hash = "sha256:b777c6ad080dc1bad74a4c29d6a46914fa6701ac70f94b0d66fbcfde62f5be31", size = 38891, upload-time = "2023-02-17T20:11:13.106Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/66/0e/9ee7bc0b48ec45d93b302fa2d787830dca4dc454d31a237faa5815995988/PyDispatcher-2.0.7-py3-none-any.whl", hash = "sha256:96543bea04115ffde08f851e1d45cacbfd1ee866ac42127d9b476dc5aefa7de0", size = 12040, upload-time = "2023-02-17T20:11:11.991Z" }, +] + [[package]] name = "pyee" version = "13.0.1" @@ -3230,6 +3592,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/81/ef2b1dfd1862567d573a4fdbc9f969067621764fbb74338496840a1d2977/pyopenssl-25.3.0-py3-none-any.whl", hash = "sha256:1fda6fc034d5e3d179d39e59c1895c9faeaf40a79de5fc4cbbfbe0d36f4a77b6", size = 57268, upload-time = "2025-09-17T00:32:19.474Z" }, ] +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, +] + [[package]] name = "python-dotenv" version = "1.2.2" @@ -4128,6 +4502,26 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/72/f4/0de46cfa12cdcbcd464cc59fde36912af405696f687e53a091fb432f694c/tokenizers-0.22.2-cp39-abi3-win_arm64.whl", hash = "sha256:9ce725d22864a1e965217204946f830c37876eee3b2ba6fc6255e8e903d5fcbc", size = 2612133, upload-time = "2026-01-05T10:45:17.232Z" }, ] +[[package]] +name = "toml" +version = "0.10.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/be/ba/1f744cdc819428fc6b5084ec34d9b30660f6f9daaf70eead706e3203ec3c/toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f", size = 22253, upload-time = "2020-11-01T01:40:22.204Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", size = 16588, upload-time = "2020-11-01T01:40:20.672Z" }, +] + +[[package]] +name = "tool" +version = "0.8.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "argh" }, + { name = "pydispatcher" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ab/ec/2b258e54a13bc53a4352e538276b4b9ffdf0d08b3f2972ee062e71dc55a0/tool-0.8.0.tar.gz", hash = "sha256:5c596600abac4dc93d7854b0640fcc7577b7387f5b5f13bc873aed130aa8e881", size = 51557, upload-time = "2011-11-25T14:50:47.079Z" } + [[package]] name = "torch" version = "2.10.0" @@ -4488,47 +4882,82 @@ wheels = [ [[package]] name = "websockets" -version = "16.0" +version = "15.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/04/24/4b2031d72e840ce4c1ccb255f693b15c334757fc50023e4db9537080b8c4/websockets-16.0.tar.gz", hash = "sha256:5f6261a5e56e8d5c42a4497b364ea24d94d9563e8fbd44e78ac40879c60179b5", size = 179346, upload-time = "2026-01-10T09:23:47.181Z" } +sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016, upload-time = "2025-03-05T20:03:41.606Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/84/7b/bac442e6b96c9d25092695578dda82403c77936104b5682307bd4deb1ad4/websockets-16.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:71c989cbf3254fbd5e84d3bff31e4da39c43f884e64f2551d14bb3c186230f00", size = 177365, upload-time = "2026-01-10T09:22:46.787Z" }, - { url = "https://files.pythonhosted.org/packages/b0/fe/136ccece61bd690d9c1f715baaeefd953bb2360134de73519d5df19d29ca/websockets-16.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8b6e209ffee39ff1b6d0fa7bfef6de950c60dfb91b8fcead17da4ee539121a79", size = 175038, upload-time = "2026-01-10T09:22:47.999Z" }, - { url = "https://files.pythonhosted.org/packages/40/1e/9771421ac2286eaab95b8575b0cb701ae3663abf8b5e1f64f1fd90d0a673/websockets-16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:86890e837d61574c92a97496d590968b23c2ef0aeb8a9bc9421d174cd378ae39", size = 175328, upload-time = "2026-01-10T09:22:49.809Z" }, - { url = "https://files.pythonhosted.org/packages/18/29/71729b4671f21e1eaa5d6573031ab810ad2936c8175f03f97f3ff164c802/websockets-16.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9b5aca38b67492ef518a8ab76851862488a478602229112c4b0d58d63a7a4d5c", size = 184915, upload-time = "2026-01-10T09:22:51.071Z" }, - { url = "https://files.pythonhosted.org/packages/97/bb/21c36b7dbbafc85d2d480cd65df02a1dc93bf76d97147605a8e27ff9409d/websockets-16.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e0334872c0a37b606418ac52f6ab9cfd17317ac26365f7f65e203e2d0d0d359f", size = 186152, upload-time = "2026-01-10T09:22:52.224Z" }, - { url = "https://files.pythonhosted.org/packages/4a/34/9bf8df0c0cf88fa7bfe36678dc7b02970c9a7d5e065a3099292db87b1be2/websockets-16.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a0b31e0b424cc6b5a04b8838bbaec1688834b2383256688cf47eb97412531da1", size = 185583, upload-time = "2026-01-10T09:22:53.443Z" }, - { url = "https://files.pythonhosted.org/packages/47/88/4dd516068e1a3d6ab3c7c183288404cd424a9a02d585efbac226cb61ff2d/websockets-16.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:485c49116d0af10ac698623c513c1cc01c9446c058a4e61e3bf6c19dff7335a2", size = 184880, upload-time = "2026-01-10T09:22:55.033Z" }, - { url = "https://files.pythonhosted.org/packages/91/d6/7d4553ad4bf1c0421e1ebd4b18de5d9098383b5caa1d937b63df8d04b565/websockets-16.0-cp312-cp312-win32.whl", hash = "sha256:eaded469f5e5b7294e2bdca0ab06becb6756ea86894a47806456089298813c89", size = 178261, upload-time = "2026-01-10T09:22:56.251Z" }, - { url = "https://files.pythonhosted.org/packages/c3/f0/f3a17365441ed1c27f850a80b2bc680a0fa9505d733fe152fdf5e98c1c0b/websockets-16.0-cp312-cp312-win_amd64.whl", hash = "sha256:5569417dc80977fc8c2d43a86f78e0a5a22fee17565d78621b6bb264a115d4ea", size = 178693, upload-time = "2026-01-10T09:22:57.478Z" }, - { url = "https://files.pythonhosted.org/packages/cc/9c/baa8456050d1c1b08dd0ec7346026668cbc6f145ab4e314d707bb845bf0d/websockets-16.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:878b336ac47938b474c8f982ac2f7266a540adc3fa4ad74ae96fea9823a02cc9", size = 177364, upload-time = "2026-01-10T09:22:59.333Z" }, - { url = "https://files.pythonhosted.org/packages/7e/0c/8811fc53e9bcff68fe7de2bcbe75116a8d959ac699a3200f4847a8925210/websockets-16.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:52a0fec0e6c8d9a784c2c78276a48a2bdf099e4ccc2a4cad53b27718dbfd0230", size = 175039, upload-time = "2026-01-10T09:23:01.171Z" }, - { url = "https://files.pythonhosted.org/packages/aa/82/39a5f910cb99ec0b59e482971238c845af9220d3ab9fa76dd9162cda9d62/websockets-16.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e6578ed5b6981005df1860a56e3617f14a6c307e6a71b4fff8c48fdc50f3ed2c", size = 175323, upload-time = "2026-01-10T09:23:02.341Z" }, - { url = "https://files.pythonhosted.org/packages/bd/28/0a25ee5342eb5d5f297d992a77e56892ecb65e7854c7898fb7d35e9b33bd/websockets-16.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:95724e638f0f9c350bb1c2b0a7ad0e83d9cc0c9259f3ea94e40d7b02a2179ae5", size = 184975, upload-time = "2026-01-10T09:23:03.756Z" }, - { url = "https://files.pythonhosted.org/packages/f9/66/27ea52741752f5107c2e41fda05e8395a682a1e11c4e592a809a90c6a506/websockets-16.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c0204dc62a89dc9d50d682412c10b3542d748260d743500a85c13cd1ee4bde82", size = 186203, upload-time = "2026-01-10T09:23:05.01Z" }, - { url = "https://files.pythonhosted.org/packages/37/e5/8e32857371406a757816a2b471939d51c463509be73fa538216ea52b792a/websockets-16.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:52ac480f44d32970d66763115edea932f1c5b1312de36df06d6b219f6741eed8", size = 185653, upload-time = "2026-01-10T09:23:06.301Z" }, - { url = "https://files.pythonhosted.org/packages/9b/67/f926bac29882894669368dc73f4da900fcdf47955d0a0185d60103df5737/websockets-16.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6e5a82b677f8f6f59e8dfc34ec06ca6b5b48bc4fcda346acd093694cc2c24d8f", size = 184920, upload-time = "2026-01-10T09:23:07.492Z" }, - { url = "https://files.pythonhosted.org/packages/3c/a1/3d6ccdcd125b0a42a311bcd15a7f705d688f73b2a22d8cf1c0875d35d34a/websockets-16.0-cp313-cp313-win32.whl", hash = "sha256:abf050a199613f64c886ea10f38b47770a65154dc37181bfaff70c160f45315a", size = 178255, upload-time = "2026-01-10T09:23:09.245Z" }, - { url = "https://files.pythonhosted.org/packages/6b/ae/90366304d7c2ce80f9b826096a9e9048b4bb760e44d3b873bb272cba696b/websockets-16.0-cp313-cp313-win_amd64.whl", hash = "sha256:3425ac5cf448801335d6fdc7ae1eb22072055417a96cc6b31b3861f455fbc156", size = 178689, upload-time = "2026-01-10T09:23:10.483Z" }, - { url = "https://files.pythonhosted.org/packages/f3/1d/e88022630271f5bd349ed82417136281931e558d628dd52c4d8621b4a0b2/websockets-16.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8cc451a50f2aee53042ac52d2d053d08bf89bcb31ae799cb4487587661c038a0", size = 177406, upload-time = "2026-01-10T09:23:12.178Z" }, - { url = "https://files.pythonhosted.org/packages/f2/78/e63be1bf0724eeb4616efb1ae1c9044f7c3953b7957799abb5915bffd38e/websockets-16.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:daa3b6ff70a9241cf6c7fc9e949d41232d9d7d26fd3522b1ad2b4d62487e9904", size = 175085, upload-time = "2026-01-10T09:23:13.511Z" }, - { url = "https://files.pythonhosted.org/packages/bb/f4/d3c9220d818ee955ae390cf319a7c7a467beceb24f05ee7aaaa2414345ba/websockets-16.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:fd3cb4adb94a2a6e2b7c0d8d05cb94e6f1c81a0cf9dc2694fb65c7e8d94c42e4", size = 175328, upload-time = "2026-01-10T09:23:14.727Z" }, - { url = "https://files.pythonhosted.org/packages/63/bc/d3e208028de777087e6fb2b122051a6ff7bbcca0d6df9d9c2bf1dd869ae9/websockets-16.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:781caf5e8eee67f663126490c2f96f40906594cb86b408a703630f95550a8c3e", size = 185044, upload-time = "2026-01-10T09:23:15.939Z" }, - { url = "https://files.pythonhosted.org/packages/ad/6e/9a0927ac24bd33a0a9af834d89e0abc7cfd8e13bed17a86407a66773cc0e/websockets-16.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:caab51a72c51973ca21fa8a18bd8165e1a0183f1ac7066a182ff27107b71e1a4", size = 186279, upload-time = "2026-01-10T09:23:17.148Z" }, - { url = "https://files.pythonhosted.org/packages/b9/ca/bf1c68440d7a868180e11be653c85959502efd3a709323230314fda6e0b3/websockets-16.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:19c4dc84098e523fd63711e563077d39e90ec6702aff4b5d9e344a60cb3c0cb1", size = 185711, upload-time = "2026-01-10T09:23:18.372Z" }, - { url = "https://files.pythonhosted.org/packages/c4/f8/fdc34643a989561f217bb477cbc47a3a07212cbda91c0e4389c43c296ebf/websockets-16.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:a5e18a238a2b2249c9a9235466b90e96ae4795672598a58772dd806edc7ac6d3", size = 184982, upload-time = "2026-01-10T09:23:19.652Z" }, - { url = "https://files.pythonhosted.org/packages/dd/d1/574fa27e233764dbac9c52730d63fcf2823b16f0856b3329fc6268d6ae4f/websockets-16.0-cp314-cp314-win32.whl", hash = "sha256:a069d734c4a043182729edd3e9f247c3b2a4035415a9172fd0f1b71658a320a8", size = 177915, upload-time = "2026-01-10T09:23:21.458Z" }, - { url = "https://files.pythonhosted.org/packages/8a/f1/ae6b937bf3126b5134ce1f482365fde31a357c784ac51852978768b5eff4/websockets-16.0-cp314-cp314-win_amd64.whl", hash = "sha256:c0ee0e63f23914732c6d7e0cce24915c48f3f1512ec1d079ed01fc629dab269d", size = 178381, upload-time = "2026-01-10T09:23:22.715Z" }, - { url = "https://files.pythonhosted.org/packages/06/9b/f791d1db48403e1f0a27577a6beb37afae94254a8c6f08be4a23e4930bc0/websockets-16.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:a35539cacc3febb22b8f4d4a99cc79b104226a756aa7400adc722e83b0d03244", size = 177737, upload-time = "2026-01-10T09:23:24.523Z" }, - { url = "https://files.pythonhosted.org/packages/bd/40/53ad02341fa33b3ce489023f635367a4ac98b73570102ad2cdd770dacc9a/websockets-16.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:b784ca5de850f4ce93ec85d3269d24d4c82f22b7212023c974c401d4980ebc5e", size = 175268, upload-time = "2026-01-10T09:23:25.781Z" }, - { url = "https://files.pythonhosted.org/packages/74/9b/6158d4e459b984f949dcbbb0c5d270154c7618e11c01029b9bbd1bb4c4f9/websockets-16.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:569d01a4e7fba956c5ae4fc988f0d4e187900f5497ce46339c996dbf24f17641", size = 175486, upload-time = "2026-01-10T09:23:27.033Z" }, - { url = "https://files.pythonhosted.org/packages/e5/2d/7583b30208b639c8090206f95073646c2c9ffd66f44df967981a64f849ad/websockets-16.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:50f23cdd8343b984957e4077839841146f67a3d31ab0d00e6b824e74c5b2f6e8", size = 185331, upload-time = "2026-01-10T09:23:28.259Z" }, - { url = "https://files.pythonhosted.org/packages/45/b0/cce3784eb519b7b5ad680d14b9673a31ab8dcb7aad8b64d81709d2430aa8/websockets-16.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:152284a83a00c59b759697b7f9e9cddf4e3c7861dd0d964b472b70f78f89e80e", size = 186501, upload-time = "2026-01-10T09:23:29.449Z" }, - { url = "https://files.pythonhosted.org/packages/19/60/b8ebe4c7e89fb5f6cdf080623c9d92789a53636950f7abacfc33fe2b3135/websockets-16.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:bc59589ab64b0022385f429b94697348a6a234e8ce22544e3681b2e9331b5944", size = 186062, upload-time = "2026-01-10T09:23:31.368Z" }, - { url = "https://files.pythonhosted.org/packages/88/a8/a080593f89b0138b6cba1b28f8df5673b5506f72879322288b031337c0b8/websockets-16.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:32da954ffa2814258030e5a57bc73a3635463238e797c7375dc8091327434206", size = 185356, upload-time = "2026-01-10T09:23:32.627Z" }, - { url = "https://files.pythonhosted.org/packages/c2/b6/b9afed2afadddaf5ebb2afa801abf4b0868f42f8539bfe4b071b5266c9fe/websockets-16.0-cp314-cp314t-win32.whl", hash = "sha256:5a4b4cc550cb665dd8a47f868c8d04c8230f857363ad3c9caf7a0c3bf8c61ca6", size = 178085, upload-time = "2026-01-10T09:23:33.816Z" }, - { url = "https://files.pythonhosted.org/packages/9f/3e/28135a24e384493fa804216b79a6a6759a38cc4ff59118787b9fb693df93/websockets-16.0-cp314-cp314t-win_amd64.whl", hash = "sha256:b14dc141ed6d2dde437cddb216004bcac6a1df0935d79656387bd41632ba0bbd", size = 178531, upload-time = "2026-01-10T09:23:35.016Z" }, - { url = "https://files.pythonhosted.org/packages/6f/28/258ebab549c2bf3e64d2b0217b973467394a9cea8c42f70418ca2c5d0d2e/websockets-16.0-py3-none-any.whl", hash = "sha256:1637db62fad1dc833276dded54215f2c7fa46912301a24bd94d45d46a011ceec", size = 171598, upload-time = "2026-01-10T09:23:45.395Z" }, + { url = "https://files.pythonhosted.org/packages/51/6b/4545a0d843594f5d0771e86463606a3988b5a09ca5123136f8a76580dd63/websockets-15.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3e90baa811a5d73f3ca0bcbf32064d663ed81318ab225ee4f427ad4e26e5aff3", size = 175437, upload-time = "2025-03-05T20:02:16.706Z" }, + { url = "https://files.pythonhosted.org/packages/f4/71/809a0f5f6a06522af902e0f2ea2757f71ead94610010cf570ab5c98e99ed/websockets-15.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:592f1a9fe869c778694f0aa806ba0374e97648ab57936f092fd9d87f8bc03665", size = 173096, upload-time = "2025-03-05T20:02:18.832Z" }, + { url = "https://files.pythonhosted.org/packages/3d/69/1a681dd6f02180916f116894181eab8b2e25b31e484c5d0eae637ec01f7c/websockets-15.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0701bc3cfcb9164d04a14b149fd74be7347a530ad3bbf15ab2c678a2cd3dd9a2", size = 173332, upload-time = "2025-03-05T20:02:20.187Z" }, + { url = "https://files.pythonhosted.org/packages/a6/02/0073b3952f5bce97eafbb35757f8d0d54812b6174ed8dd952aa08429bcc3/websockets-15.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8b56bdcdb4505c8078cb6c7157d9811a85790f2f2b3632c7d1462ab5783d215", size = 183152, upload-time = "2025-03-05T20:02:22.286Z" }, + { url = "https://files.pythonhosted.org/packages/74/45/c205c8480eafd114b428284840da0b1be9ffd0e4f87338dc95dc6ff961a1/websockets-15.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0af68c55afbd5f07986df82831c7bff04846928ea8d1fd7f30052638788bc9b5", size = 182096, upload-time = "2025-03-05T20:02:24.368Z" }, + { url = "https://files.pythonhosted.org/packages/14/8f/aa61f528fba38578ec553c145857a181384c72b98156f858ca5c8e82d9d3/websockets-15.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64dee438fed052b52e4f98f76c5790513235efaa1ef7f3f2192c392cd7c91b65", size = 182523, upload-time = "2025-03-05T20:02:25.669Z" }, + { url = "https://files.pythonhosted.org/packages/ec/6d/0267396610add5bc0d0d3e77f546d4cd287200804fe02323797de77dbce9/websockets-15.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d5f6b181bb38171a8ad1d6aa58a67a6aa9d4b38d0f8c5f496b9e42561dfc62fe", size = 182790, upload-time = "2025-03-05T20:02:26.99Z" }, + { url = "https://files.pythonhosted.org/packages/02/05/c68c5adbf679cf610ae2f74a9b871ae84564462955d991178f95a1ddb7dd/websockets-15.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5d54b09eba2bada6011aea5375542a157637b91029687eb4fdb2dab11059c1b4", size = 182165, upload-time = "2025-03-05T20:02:30.291Z" }, + { url = "https://files.pythonhosted.org/packages/29/93/bb672df7b2f5faac89761cb5fa34f5cec45a4026c383a4b5761c6cea5c16/websockets-15.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3be571a8b5afed347da347bfcf27ba12b069d9d7f42cb8c7028b5e98bbb12597", size = 182160, upload-time = "2025-03-05T20:02:31.634Z" }, + { url = "https://files.pythonhosted.org/packages/ff/83/de1f7709376dc3ca9b7eeb4b9a07b4526b14876b6d372a4dc62312bebee0/websockets-15.0.1-cp312-cp312-win32.whl", hash = "sha256:c338ffa0520bdb12fbc527265235639fb76e7bc7faafbb93f6ba80d9c06578a9", size = 176395, upload-time = "2025-03-05T20:02:33.017Z" }, + { url = "https://files.pythonhosted.org/packages/7d/71/abf2ebc3bbfa40f391ce1428c7168fb20582d0ff57019b69ea20fa698043/websockets-15.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcd5cf9e305d7b8338754470cf69cf81f420459dbae8a3b40cee57417f4614a7", size = 176841, upload-time = "2025-03-05T20:02:34.498Z" }, + { url = "https://files.pythonhosted.org/packages/cb/9f/51f0cf64471a9d2b4d0fc6c534f323b664e7095640c34562f5182e5a7195/websockets-15.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee443ef070bb3b6ed74514f5efaa37a252af57c90eb33b956d35c8e9c10a1931", size = 175440, upload-time = "2025-03-05T20:02:36.695Z" }, + { url = "https://files.pythonhosted.org/packages/8a/05/aa116ec9943c718905997412c5989f7ed671bc0188ee2ba89520e8765d7b/websockets-15.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5a939de6b7b4e18ca683218320fc67ea886038265fd1ed30173f5ce3f8e85675", size = 173098, upload-time = "2025-03-05T20:02:37.985Z" }, + { url = "https://files.pythonhosted.org/packages/ff/0b/33cef55ff24f2d92924923c99926dcce78e7bd922d649467f0eda8368923/websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:746ee8dba912cd6fc889a8147168991d50ed70447bf18bcda7039f7d2e3d9151", size = 173329, upload-time = "2025-03-05T20:02:39.298Z" }, + { url = "https://files.pythonhosted.org/packages/31/1d/063b25dcc01faa8fada1469bdf769de3768b7044eac9d41f734fd7b6ad6d/websockets-15.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:595b6c3969023ecf9041b2936ac3827e4623bfa3ccf007575f04c5a6aa318c22", size = 183111, upload-time = "2025-03-05T20:02:40.595Z" }, + { url = "https://files.pythonhosted.org/packages/93/53/9a87ee494a51bf63e4ec9241c1ccc4f7c2f45fff85d5bde2ff74fcb68b9e/websockets-15.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c714d2fc58b5ca3e285461a4cc0c9a66bd0e24c5da9911e30158286c9b5be7f", size = 182054, upload-time = "2025-03-05T20:02:41.926Z" }, + { url = "https://files.pythonhosted.org/packages/ff/b2/83a6ddf56cdcbad4e3d841fcc55d6ba7d19aeb89c50f24dd7e859ec0805f/websockets-15.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f3c1e2ab208db911594ae5b4f79addeb3501604a165019dd221c0bdcabe4db8", size = 182496, upload-time = "2025-03-05T20:02:43.304Z" }, + { url = "https://files.pythonhosted.org/packages/98/41/e7038944ed0abf34c45aa4635ba28136f06052e08fc2168520bb8b25149f/websockets-15.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:229cf1d3ca6c1804400b0a9790dc66528e08a6a1feec0d5040e8b9eb14422375", size = 182829, upload-time = "2025-03-05T20:02:48.812Z" }, + { url = "https://files.pythonhosted.org/packages/e0/17/de15b6158680c7623c6ef0db361da965ab25d813ae54fcfeae2e5b9ef910/websockets-15.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:756c56e867a90fb00177d530dca4b097dd753cde348448a1012ed6c5131f8b7d", size = 182217, upload-time = "2025-03-05T20:02:50.14Z" }, + { url = "https://files.pythonhosted.org/packages/33/2b/1f168cb6041853eef0362fb9554c3824367c5560cbdaad89ac40f8c2edfc/websockets-15.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4", size = 182195, upload-time = "2025-03-05T20:02:51.561Z" }, + { url = "https://files.pythonhosted.org/packages/86/eb/20b6cdf273913d0ad05a6a14aed4b9a85591c18a987a3d47f20fa13dcc47/websockets-15.0.1-cp313-cp313-win32.whl", hash = "sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa", size = 176393, upload-time = "2025-03-05T20:02:53.814Z" }, + { url = "https://files.pythonhosted.org/packages/1b/6c/c65773d6cab416a64d191d6ee8a8b1c68a09970ea6909d16965d26bfed1e/websockets-15.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561", size = 176837, upload-time = "2025-03-05T20:02:55.237Z" }, + { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743, upload-time = "2025-03-05T20:03:39.41Z" }, +] + +[[package]] +name = "wrapt" +version = "1.17.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/95/8f/aeb76c5b46e273670962298c23e7ddde79916cb74db802131d49a85e4b7d/wrapt-1.17.3.tar.gz", hash = "sha256:f66eb08feaa410fe4eebd17f2a2c8e2e46d3476e9f8c783daa8e09e0faa666d0", size = 55547, upload-time = "2025-08-12T05:53:21.714Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9f/41/cad1aba93e752f1f9268c77270da3c469883d56e2798e7df6240dcb2287b/wrapt-1.17.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ab232e7fdb44cdfbf55fc3afa31bcdb0d8980b9b95c38b6405df2acb672af0e0", size = 53998, upload-time = "2025-08-12T05:51:47.138Z" }, + { url = "https://files.pythonhosted.org/packages/60/f8/096a7cc13097a1869fe44efe68dace40d2a16ecb853141394047f0780b96/wrapt-1.17.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:9baa544e6acc91130e926e8c802a17f3b16fbea0fd441b5a60f5cf2cc5c3deba", size = 39020, upload-time = "2025-08-12T05:51:35.906Z" }, + { url = "https://files.pythonhosted.org/packages/33/df/bdf864b8997aab4febb96a9ae5c124f700a5abd9b5e13d2a3214ec4be705/wrapt-1.17.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6b538e31eca1a7ea4605e44f81a48aa24c4632a277431a6ed3f328835901f4fd", size = 39098, upload-time = "2025-08-12T05:51:57.474Z" }, + { url = "https://files.pythonhosted.org/packages/9f/81/5d931d78d0eb732b95dc3ddaeeb71c8bb572fb01356e9133916cd729ecdd/wrapt-1.17.3-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:042ec3bb8f319c147b1301f2393bc19dba6e176b7da446853406d041c36c7828", size = 88036, upload-time = "2025-08-12T05:52:34.784Z" }, + { url = "https://files.pythonhosted.org/packages/ca/38/2e1785df03b3d72d34fc6252d91d9d12dc27a5c89caef3335a1bbb8908ca/wrapt-1.17.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3af60380ba0b7b5aeb329bc4e402acd25bd877e98b3727b0135cb5c2efdaefe9", size = 88156, upload-time = "2025-08-12T05:52:13.599Z" }, + { url = "https://files.pythonhosted.org/packages/b3/8b/48cdb60fe0603e34e05cffda0b2a4adab81fd43718e11111a4b0100fd7c1/wrapt-1.17.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0b02e424deef65c9f7326d8c19220a2c9040c51dc165cddb732f16198c168396", size = 87102, upload-time = "2025-08-12T05:52:14.56Z" }, + { url = "https://files.pythonhosted.org/packages/3c/51/d81abca783b58f40a154f1b2c56db1d2d9e0d04fa2d4224e357529f57a57/wrapt-1.17.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:74afa28374a3c3a11b3b5e5fca0ae03bef8450d6aa3ab3a1e2c30e3a75d023dc", size = 87732, upload-time = "2025-08-12T05:52:36.165Z" }, + { url = "https://files.pythonhosted.org/packages/9e/b1/43b286ca1392a006d5336412d41663eeef1ad57485f3e52c767376ba7e5a/wrapt-1.17.3-cp312-cp312-win32.whl", hash = "sha256:4da9f45279fff3543c371d5ababc57a0384f70be244de7759c85a7f989cb4ebe", size = 36705, upload-time = "2025-08-12T05:53:07.123Z" }, + { url = "https://files.pythonhosted.org/packages/28/de/49493f962bd3c586ab4b88066e967aa2e0703d6ef2c43aa28cb83bf7b507/wrapt-1.17.3-cp312-cp312-win_amd64.whl", hash = "sha256:e71d5c6ebac14875668a1e90baf2ea0ef5b7ac7918355850c0908ae82bcb297c", size = 38877, upload-time = "2025-08-12T05:53:05.436Z" }, + { url = "https://files.pythonhosted.org/packages/f1/48/0f7102fe9cb1e8a5a77f80d4f0956d62d97034bbe88d33e94699f99d181d/wrapt-1.17.3-cp312-cp312-win_arm64.whl", hash = "sha256:604d076c55e2fdd4c1c03d06dc1a31b95130010517b5019db15365ec4a405fc6", size = 36885, upload-time = "2025-08-12T05:52:54.367Z" }, + { url = "https://files.pythonhosted.org/packages/fc/f6/759ece88472157acb55fc195e5b116e06730f1b651b5b314c66291729193/wrapt-1.17.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a47681378a0439215912ef542c45a783484d4dd82bac412b71e59cf9c0e1cea0", size = 54003, upload-time = "2025-08-12T05:51:48.627Z" }, + { url = "https://files.pythonhosted.org/packages/4f/a9/49940b9dc6d47027dc850c116d79b4155f15c08547d04db0f07121499347/wrapt-1.17.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:54a30837587c6ee3cd1a4d1c2ec5d24e77984d44e2f34547e2323ddb4e22eb77", size = 39025, upload-time = "2025-08-12T05:51:37.156Z" }, + { url = "https://files.pythonhosted.org/packages/45/35/6a08de0f2c96dcdd7fe464d7420ddb9a7655a6561150e5fc4da9356aeaab/wrapt-1.17.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:16ecf15d6af39246fe33e507105d67e4b81d8f8d2c6598ff7e3ca1b8a37213f7", size = 39108, upload-time = "2025-08-12T05:51:58.425Z" }, + { url = "https://files.pythonhosted.org/packages/0c/37/6faf15cfa41bf1f3dba80cd3f5ccc6622dfccb660ab26ed79f0178c7497f/wrapt-1.17.3-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6fd1ad24dc235e4ab88cda009e19bf347aabb975e44fd5c2fb22a3f6e4141277", size = 88072, upload-time = "2025-08-12T05:52:37.53Z" }, + { url = "https://files.pythonhosted.org/packages/78/f2/efe19ada4a38e4e15b6dff39c3e3f3f73f5decf901f66e6f72fe79623a06/wrapt-1.17.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ed61b7c2d49cee3c027372df5809a59d60cf1b6c2f81ee980a091f3afed6a2d", size = 88214, upload-time = "2025-08-12T05:52:15.886Z" }, + { url = "https://files.pythonhosted.org/packages/40/90/ca86701e9de1622b16e09689fc24b76f69b06bb0150990f6f4e8b0eeb576/wrapt-1.17.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:423ed5420ad5f5529db9ce89eac09c8a2f97da18eb1c870237e84c5a5c2d60aa", size = 87105, upload-time = "2025-08-12T05:52:17.914Z" }, + { url = "https://files.pythonhosted.org/packages/fd/e0/d10bd257c9a3e15cbf5523025252cc14d77468e8ed644aafb2d6f54cb95d/wrapt-1.17.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e01375f275f010fcbf7f643b4279896d04e571889b8a5b3f848423d91bf07050", size = 87766, upload-time = "2025-08-12T05:52:39.243Z" }, + { url = "https://files.pythonhosted.org/packages/e8/cf/7d848740203c7b4b27eb55dbfede11aca974a51c3d894f6cc4b865f42f58/wrapt-1.17.3-cp313-cp313-win32.whl", hash = "sha256:53e5e39ff71b3fc484df8a522c933ea2b7cdd0d5d15ae82e5b23fde87d44cbd8", size = 36711, upload-time = "2025-08-12T05:53:10.074Z" }, + { url = "https://files.pythonhosted.org/packages/57/54/35a84d0a4d23ea675994104e667ceff49227ce473ba6a59ba2c84f250b74/wrapt-1.17.3-cp313-cp313-win_amd64.whl", hash = "sha256:1f0b2f40cf341ee8cc1a97d51ff50dddb9fcc73241b9143ec74b30fc4f44f6cb", size = 38885, upload-time = "2025-08-12T05:53:08.695Z" }, + { url = "https://files.pythonhosted.org/packages/01/77/66e54407c59d7b02a3c4e0af3783168fff8e5d61def52cda8728439d86bc/wrapt-1.17.3-cp313-cp313-win_arm64.whl", hash = "sha256:7425ac3c54430f5fc5e7b6f41d41e704db073309acfc09305816bc6a0b26bb16", size = 36896, upload-time = "2025-08-12T05:52:55.34Z" }, + { url = "https://files.pythonhosted.org/packages/02/a2/cd864b2a14f20d14f4c496fab97802001560f9f41554eef6df201cd7f76c/wrapt-1.17.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:cf30f6e3c077c8e6a9a7809c94551203c8843e74ba0c960f4a98cd80d4665d39", size = 54132, upload-time = "2025-08-12T05:51:49.864Z" }, + { url = "https://files.pythonhosted.org/packages/d5/46/d011725b0c89e853dc44cceb738a307cde5d240d023d6d40a82d1b4e1182/wrapt-1.17.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e228514a06843cae89621384cfe3a80418f3c04aadf8a3b14e46a7be704e4235", size = 39091, upload-time = "2025-08-12T05:51:38.935Z" }, + { url = "https://files.pythonhosted.org/packages/2e/9e/3ad852d77c35aae7ddebdbc3b6d35ec8013af7d7dddad0ad911f3d891dae/wrapt-1.17.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:5ea5eb3c0c071862997d6f3e02af1d055f381b1d25b286b9d6644b79db77657c", size = 39172, upload-time = "2025-08-12T05:51:59.365Z" }, + { url = "https://files.pythonhosted.org/packages/c3/f7/c983d2762bcce2326c317c26a6a1e7016f7eb039c27cdf5c4e30f4160f31/wrapt-1.17.3-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:281262213373b6d5e4bb4353bc36d1ba4084e6d6b5d242863721ef2bf2c2930b", size = 87163, upload-time = "2025-08-12T05:52:40.965Z" }, + { url = "https://files.pythonhosted.org/packages/e4/0f/f673f75d489c7f22d17fe0193e84b41540d962f75fce579cf6873167c29b/wrapt-1.17.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dc4a8d2b25efb6681ecacad42fca8859f88092d8732b170de6a5dddd80a1c8fa", size = 87963, upload-time = "2025-08-12T05:52:20.326Z" }, + { url = "https://files.pythonhosted.org/packages/df/61/515ad6caca68995da2fac7a6af97faab8f78ebe3bf4f761e1b77efbc47b5/wrapt-1.17.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:373342dd05b1d07d752cecbec0c41817231f29f3a89aa8b8843f7b95992ed0c7", size = 86945, upload-time = "2025-08-12T05:52:21.581Z" }, + { url = "https://files.pythonhosted.org/packages/d3/bd/4e70162ce398462a467bc09e768bee112f1412e563620adc353de9055d33/wrapt-1.17.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d40770d7c0fd5cbed9d84b2c3f2e156431a12c9a37dc6284060fb4bec0b7ffd4", size = 86857, upload-time = "2025-08-12T05:52:43.043Z" }, + { url = "https://files.pythonhosted.org/packages/2b/b8/da8560695e9284810b8d3df8a19396a6e40e7518059584a1a394a2b35e0a/wrapt-1.17.3-cp314-cp314-win32.whl", hash = "sha256:fbd3c8319de8e1dc79d346929cd71d523622da527cca14e0c1d257e31c2b8b10", size = 37178, upload-time = "2025-08-12T05:53:12.605Z" }, + { url = "https://files.pythonhosted.org/packages/db/c8/b71eeb192c440d67a5a0449aaee2310a1a1e8eca41676046f99ed2487e9f/wrapt-1.17.3-cp314-cp314-win_amd64.whl", hash = "sha256:e1a4120ae5705f673727d3253de3ed0e016f7cd78dc463db1b31e2463e1f3cf6", size = 39310, upload-time = "2025-08-12T05:53:11.106Z" }, + { url = "https://files.pythonhosted.org/packages/45/20/2cda20fd4865fa40f86f6c46ed37a2a8356a7a2fde0773269311f2af56c7/wrapt-1.17.3-cp314-cp314-win_arm64.whl", hash = "sha256:507553480670cab08a800b9463bdb881b2edeed77dc677b0a5915e6106e91a58", size = 37266, upload-time = "2025-08-12T05:52:56.531Z" }, + { url = "https://files.pythonhosted.org/packages/77/ed/dd5cf21aec36c80443c6f900449260b80e2a65cf963668eaef3b9accce36/wrapt-1.17.3-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:ed7c635ae45cfbc1a7371f708727bf74690daedc49b4dba310590ca0bd28aa8a", size = 56544, upload-time = "2025-08-12T05:51:51.109Z" }, + { url = "https://files.pythonhosted.org/packages/8d/96/450c651cc753877ad100c7949ab4d2e2ecc4d97157e00fa8f45df682456a/wrapt-1.17.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:249f88ed15503f6492a71f01442abddd73856a0032ae860de6d75ca62eed8067", size = 40283, upload-time = "2025-08-12T05:51:39.912Z" }, + { url = "https://files.pythonhosted.org/packages/d1/86/2fcad95994d9b572db57632acb6f900695a648c3e063f2cd344b3f5c5a37/wrapt-1.17.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5a03a38adec8066d5a37bea22f2ba6bbf39fcdefbe2d91419ab864c3fb515454", size = 40366, upload-time = "2025-08-12T05:52:00.693Z" }, + { url = "https://files.pythonhosted.org/packages/64/0e/f4472f2fdde2d4617975144311f8800ef73677a159be7fe61fa50997d6c0/wrapt-1.17.3-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:5d4478d72eb61c36e5b446e375bbc49ed002430d17cdec3cecb36993398e1a9e", size = 108571, upload-time = "2025-08-12T05:52:44.521Z" }, + { url = "https://files.pythonhosted.org/packages/cc/01/9b85a99996b0a97c8a17484684f206cbb6ba73c1ce6890ac668bcf3838fb/wrapt-1.17.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:223db574bb38637e8230eb14b185565023ab624474df94d2af18f1cdb625216f", size = 113094, upload-time = "2025-08-12T05:52:22.618Z" }, + { url = "https://files.pythonhosted.org/packages/25/02/78926c1efddcc7b3aa0bc3d6b33a822f7d898059f7cd9ace8c8318e559ef/wrapt-1.17.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e405adefb53a435f01efa7ccdec012c016b5a1d3f35459990afc39b6be4d5056", size = 110659, upload-time = "2025-08-12T05:52:24.057Z" }, + { url = "https://files.pythonhosted.org/packages/dc/ee/c414501ad518ac3e6fe184753632fe5e5ecacdcf0effc23f31c1e4f7bfcf/wrapt-1.17.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:88547535b787a6c9ce4086917b6e1d291aa8ed914fdd3a838b3539dc95c12804", size = 106946, upload-time = "2025-08-12T05:52:45.976Z" }, + { url = "https://files.pythonhosted.org/packages/be/44/a1bd64b723d13bb151d6cc91b986146a1952385e0392a78567e12149c7b4/wrapt-1.17.3-cp314-cp314t-win32.whl", hash = "sha256:41b1d2bc74c2cac6f9074df52b2efbef2b30bdfe5f40cb78f8ca22963bc62977", size = 38717, upload-time = "2025-08-12T05:53:15.214Z" }, + { url = "https://files.pythonhosted.org/packages/79/d9/7cfd5a312760ac4dd8bf0184a6ee9e43c33e47f3dadc303032ce012b8fa3/wrapt-1.17.3-cp314-cp314t-win_amd64.whl", hash = "sha256:73d496de46cd2cdbdbcce4ae4bcdb4afb6a11234a1df9c085249d55166b95116", size = 41334, upload-time = "2025-08-12T05:53:14.178Z" }, + { url = "https://files.pythonhosted.org/packages/46/78/10ad9781128ed2f99dbc474f43283b13fea8ba58723e98844367531c18e9/wrapt-1.17.3-cp314-cp314t-win_arm64.whl", hash = "sha256:f38e60678850c42461d4202739f9bf1e3a737c7ad283638251e79cc49effb6b6", size = 38471, upload-time = "2025-08-12T05:52:57.784Z" }, + { url = "https://files.pythonhosted.org/packages/1f/f6/a933bd70f98e9cf3e08167fc5cd7aaaca49147e48411c0bd5ae701bb2194/wrapt-1.17.3-py3-none-any.whl", hash = "sha256:7171ae35d2c33d326ac19dd8facb1e82e5fd04ef8c6c0e394d7af55a55051c22", size = 23591, upload-time = "2025-08-12T05:53:20.674Z" }, ] [[package]]