From 3b4e993531feb5084f0e382ce4463eb5b8304cef Mon Sep 17 00:00:00 2001 From: zgjja <86761877+zgjja@users.noreply.github.com> Date: Sun, 17 Aug 2025 22:57:23 +0800 Subject: [PATCH] feat: 1. replace black with ruff for fomatting and sort import (#489) 2. use tavily from`langchain-tavily` rather than the older one from `langchain-community` Co-authored-by: Willem Jiang --- Makefile | 5 +- pyproject.toml | 19 +-- server.py | 1 + src/agents/agents.py | 4 +- src/config/__init__.py | 8 +- src/config/configuration.py | 2 +- src/config/loader.py | 3 +- src/config/tools.py | 3 +- src/graph/__init__.py | 2 +- src/graph/builder.py | 11 +- src/graph/nodes.py | 21 ++- src/llms/llm.py | 9 +- src/prompt_enhancer/graph/enhancer_node.py | 3 +- src/prompt_enhancer/graph/state.py | 3 +- src/prompts/template.py | 4 +- src/prose/graph/builder.py | 1 + src/prose/graph/prose_improve_node.py | 2 +- src/rag/__init__.py | 6 +- src/rag/builder.py | 2 +- src/rag/ragflow.py | 6 +- src/rag/retriever.py | 1 + src/rag/vikingdb_knowledge_base.py | 10 +- src/server/chat_request.py | 2 +- src/server/mcp_utils.py | 2 +- src/tools/crawl.py | 3 +- src/tools/decorators.py | 2 +- src/tools/python_repl.py | 2 + src/tools/retriever.py | 9 +- src/tools/search.py | 12 +- src/tools/tavily_search/__init__.py | 4 +- .../tavily_search_api_wrapper.py | 4 +- .../tavily_search_results_with_images.py | 14 +- src/tools/tts.py | 5 +- src/utils/json_utils.py | 2 +- src/workflow.py | 1 + tests/integration/test_nodes.py | 29 ++-- tests/integration/test_template.py | 3 +- tests/integration/test_tts.py | 4 +- tests/test_state.py | 2 +- tests/unit/config/test_configuration.py | 1 + tests/unit/config/test_loader.py | 1 + tests/unit/graph/test_builder.py | 5 +- tests/unit/llms/test_llm.py | 1 + .../prompt_enhancer/graph/test_builder.py | 3 +- .../graph/test_enhancer_node.py | 5 +- .../unit/prompt_enhancer/graph/test_state.py | 2 +- tests/unit/rag/test_ragflow.py | 4 +- tests/unit/rag/test_retriever.py | 1 + .../unit/rag/test_vikingdb_knowledge_base.py | 10 +- tests/unit/server/test_app.py | 20 +-- tests/unit/server/test_chat_request.py | 15 +- tests/unit/server/test_mcp_request.py | 1 + tests/unit/server/test_mcp_utils.py | 3 +- tests/unit/tools/test_crawl.py | 2 +- tests/unit/tools/test_decorators.py | 2 +- tests/unit/tools/test_python_repl.py | 5 +- tests/unit/tools/test_search.py | 7 +- .../tools/test_tavily_search_api_wrapper.py | 5 +- .../test_tavily_search_results_with_images.py | 23 ++-- tests/unit/tools/test_tools_retriever.py | 12 +- tests/unit/utils/test_json_utils.py | 2 +- uv.lock | 129 ++++++++---------- 62 files changed, 251 insertions(+), 234 deletions(-) diff --git a/Makefile b/Makefile index 3a5fb48..9feb0f8 100644 --- a/Makefile +++ b/Makefile @@ -4,11 +4,10 @@ install-dev: uv pip install -e ".[dev]" && uv pip install -e ".[test]" format: - uv run black --preview . + uv run ruff format --config pyproject.toml . lint: - uv run black --check . - uv run ruff check . + uv run ruff check --fix --select I --config pyproject.toml . serve: uv run server.py --reload diff --git a/pyproject.toml b/pyproject.toml index f0b21a3..284d373 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,6 +34,7 @@ dependencies = [ "langchain-mcp-adapters>=0.0.9", "langchain-deepseek>=0.1.3", "wikipedia>=1.4.0", + "langchain-tavily<0.3", "langgraph-checkpoint-mongodb>=0.1.4", "langgraph-checkpoint-postgres==2.0.21", ] @@ -41,7 +42,6 @@ dependencies = [ [project.optional-dependencies] dev = [ "ruff", - "black>=24.2.0", "langgraph-cli[inmem]>=0.2.10", ] test = [ @@ -68,12 +68,13 @@ fail_under = 25 [tool.hatch.build.targets.wheel] packages = ["src"] -[tool.black] +[tool.ruff] line-length = 88 -target-version = ["py312"] -include = '\.pyi?$' -extend-exclude = ''' -# A regex preceded with ^/ will apply only to files and directories -# in the root of the project. -^/build/ -''' +indent-width = 4 +target-version = "py312" +extend-include = ["*.pyi"] + +[tool.ruff.format] +indent-style = "space" +line-ending = "auto" +exclude = ['^/build/'] diff --git a/server.py b/server.py index 727c840..f965b54 100644 --- a/server.py +++ b/server.py @@ -10,6 +10,7 @@ import argparse import logging import signal import sys + import uvicorn # Configure logging diff --git a/src/agents/agents.py b/src/agents/agents.py index e8fb3a8..53c10f5 100644 --- a/src/agents/agents.py +++ b/src/agents/agents.py @@ -3,9 +3,9 @@ from langgraph.prebuilt import create_react_agent -from src.prompts import apply_prompt_template -from src.llms.llm import get_llm_by_type from src.config.agents import AGENT_LLM_MAP +from src.llms.llm import get_llm_by_type +from src.prompts import apply_prompt_template # Create agents using configured LLM types diff --git a/src/config/__init__.py b/src/config/__init__.py index 104a580..88ccbe6 100644 --- a/src/config/__init__.py +++ b/src/config/__init__.py @@ -1,12 +1,12 @@ # Copyright (c) 2025 Bytedance Ltd. and/or its affiliates # SPDX-License-Identifier: MIT -from .loader import load_yaml_config -from .tools import SELECTED_SEARCH_ENGINE, SearchEngine -from .questions import BUILT_IN_QUESTIONS, BUILT_IN_QUESTIONS_ZH_CN - from dotenv import load_dotenv +from .loader import load_yaml_config +from .questions import BUILT_IN_QUESTIONS, BUILT_IN_QUESTIONS_ZH_CN +from .tools import SELECTED_SEARCH_ENGINE, SearchEngine + # Load environment variables load_dotenv() diff --git a/src/config/configuration.py b/src/config/configuration.py index ba39af3..e9ebd96 100644 --- a/src/config/configuration.py +++ b/src/config/configuration.py @@ -8,8 +8,8 @@ from typing import Any, Optional from langchain_core.runnables import RunnableConfig -from src.rag.retriever import Resource from src.config.report_style import ReportStyle +from src.rag.retriever import Resource logger = logging.getLogger(__name__) diff --git a/src/config/loader.py b/src/config/loader.py index 6f7d46e..d9c5e0b 100644 --- a/src/config/loader.py +++ b/src/config/loader.py @@ -2,8 +2,9 @@ # SPDX-License-Identifier: MIT import os +from typing import Any, Dict + import yaml -from typing import Dict, Any def replace_env_vars(value: str) -> str: diff --git a/src/config/tools.py b/src/config/tools.py index fef0111..3fea088 100644 --- a/src/config/tools.py +++ b/src/config/tools.py @@ -1,8 +1,9 @@ # Copyright (c) 2025 Bytedance Ltd. and/or its affiliates # SPDX-License-Identifier: MIT -import os import enum +import os + from dotenv import load_dotenv load_dotenv() diff --git a/src/graph/__init__.py b/src/graph/__init__.py index 365ab78..92022cf 100644 --- a/src/graph/__init__.py +++ b/src/graph/__init__.py @@ -1,7 +1,7 @@ # Copyright (c) 2025 Bytedance Ltd. and/or its affiliates # SPDX-License-Identifier: MIT -from .builder import build_graph_with_memory, build_graph +from .builder import build_graph, build_graph_with_memory __all__ = [ "build_graph_with_memory", diff --git a/src/graph/builder.py b/src/graph/builder.py index defe879..45576b7 100644 --- a/src/graph/builder.py +++ b/src/graph/builder.py @@ -1,21 +1,22 @@ # Copyright (c) 2025 Bytedance Ltd. and/or its affiliates # SPDX-License-Identifier: MIT -from langgraph.graph import StateGraph, START, END from langgraph.checkpoint.memory import MemorySaver +from langgraph.graph import END, START, StateGraph + from src.prompts.planner_model import StepType -from .types import State from .nodes import ( + background_investigation_node, + coder_node, coordinator_node, + human_feedback_node, planner_node, reporter_node, research_team_node, researcher_node, - coder_node, - human_feedback_node, - background_investigation_node, ) +from .types import State def continue_to_running_research_team(state: State): diff --git a/src/graph/nodes.py b/src/graph/nodes.py index 92d30ac..2062eac 100644 --- a/src/graph/nodes.py +++ b/src/graph/nodes.py @@ -9,27 +9,26 @@ from typing import Annotated, Literal from langchain_core.messages import AIMessage, HumanMessage from langchain_core.runnables import RunnableConfig from langchain_core.tools import tool -from langgraph.types import Command, interrupt from langchain_mcp_adapters.client import MultiServerMCPClient +from langgraph.types import Command, interrupt from src.agents import create_agent -from src.tools.search import LoggedTavilySearch -from src.tools import ( - crawl_tool, - get_web_search_tool, - get_retriever_tool, - python_repl_tool, -) - from src.config.agents import AGENT_LLM_MAP from src.config.configuration import Configuration from src.llms.llm import get_llm_by_type from src.prompts.planner_model import Plan from src.prompts.template import apply_prompt_template +from src.tools import ( + crawl_tool, + get_retriever_tool, + get_web_search_tool, + python_repl_tool, +) +from src.tools.search import LoggedTavilySearch from src.utils.json_utils import repair_json_output -from .types import State from ..config import SELECTED_SEARCH_ENGINE, SearchEngine +from .types import State logger = logging.getLogger(__name__) @@ -106,7 +105,7 @@ def planner_node( elif AGENT_LLM_MAP["planner"] == "basic": llm = get_llm_by_type("basic").with_structured_output( Plan, - method="json_mode", + # method="json_mode", ) else: llm = get_llm_by_type(AGENT_LLM_MAP["planner"]) diff --git a/src/llms/llm.py b/src/llms/llm.py index fe30719..8730411 100644 --- a/src/llms/llm.py +++ b/src/llms/llm.py @@ -1,15 +1,14 @@ # Copyright (c) 2025 Bytedance Ltd. and/or its affiliates # SPDX-License-Identifier: MIT -from pathlib import Path -from typing import Any, Dict import os -import httpx +from pathlib import Path +from typing import Any, Dict, get_args +import httpx from langchain_core.language_models import BaseChatModel -from langchain_openai import ChatOpenAI, AzureChatOpenAI from langchain_deepseek import ChatDeepSeek -from typing import get_args +from langchain_openai import AzureChatOpenAI, ChatOpenAI from src.config import load_yaml_config from src.config.agents import LLMType diff --git a/src/prompt_enhancer/graph/enhancer_node.py b/src/prompt_enhancer/graph/enhancer_node.py index bafbd36..0ccfd20 100644 --- a/src/prompt_enhancer/graph/enhancer_node.py +++ b/src/prompt_enhancer/graph/enhancer_node.py @@ -8,8 +8,8 @@ from langchain.schema import HumanMessage from src.config.agents import AGENT_LLM_MAP from src.llms.llm import get_llm_by_type -from src.prompts.template import apply_prompt_template from src.prompt_enhancer.graph.state import PromptEnhancerState +from src.prompts.template import apply_prompt_template logger = logging.getLogger(__name__) @@ -21,7 +21,6 @@ def prompt_enhancer_node(state: PromptEnhancerState): model = get_llm_by_type(AGENT_LLM_MAP["prompt_enhancer"]) try: - # Create messages with context if provided context_info = "" if state.get("context"): diff --git a/src/prompt_enhancer/graph/state.py b/src/prompt_enhancer/graph/state.py index b3ca3be..19993fc 100644 --- a/src/prompt_enhancer/graph/state.py +++ b/src/prompt_enhancer/graph/state.py @@ -1,7 +1,8 @@ # Copyright (c) 2025 Bytedance Ltd. and/or its affiliates # SPDX-License-Identifier: MIT -from typing import TypedDict, Optional +from typing import Optional, TypedDict + from src.config.report_style import ReportStyle diff --git a/src/prompts/template.py b/src/prompts/template.py index beafe27..93093ca 100644 --- a/src/prompts/template.py +++ b/src/prompts/template.py @@ -1,11 +1,13 @@ # Copyright (c) 2025 Bytedance Ltd. and/or its affiliates # SPDX-License-Identifier: MIT -import os import dataclasses +import os from datetime import datetime + from jinja2 import Environment, FileSystemLoader, select_autoescape from langgraph.prebuilt.chat_agent_executor import AgentState + from src.config.configuration import Configuration # Initialize Jinja2 environment diff --git a/src/prose/graph/builder.py b/src/prose/graph/builder.py index d9bad5d..5cceba8 100644 --- a/src/prose/graph/builder.py +++ b/src/prose/graph/builder.py @@ -3,6 +3,7 @@ import asyncio import logging + from langgraph.graph import END, START, StateGraph from src.prose.graph.prose_continue_node import prose_continue_node diff --git a/src/prose/graph/prose_improve_node.py b/src/prose/graph/prose_improve_node.py index b9ae166..6ff07dc 100644 --- a/src/prose/graph/prose_improve_node.py +++ b/src/prose/graph/prose_improve_node.py @@ -7,8 +7,8 @@ from langchain.schema import HumanMessage, SystemMessage from src.config.agents import AGENT_LLM_MAP from src.llms.llm import get_llm_by_type -from src.prose.graph.state import ProseState from src.prompts.template import get_prompt_template +from src.prose.graph.state import ProseState logger = logging.getLogger(__name__) diff --git a/src/rag/__init__.py b/src/rag/__init__.py index eed21ca..33519dc 100644 --- a/src/rag/__init__.py +++ b/src/rag/__init__.py @@ -1,10 +1,10 @@ # Copyright (c) 2025 Bytedance Ltd. and/or its affiliates # SPDX-License-Identifier: MIT -from .retriever import Retriever, Document, Resource, Chunk -from .ragflow import RAGFlowProvider -from .vikingdb_knowledge_base import VikingDBKnowledgeBaseProvider from .builder import build_retriever +from .ragflow import RAGFlowProvider +from .retriever import Chunk, Document, Resource, Retriever +from .vikingdb_knowledge_base import VikingDBKnowledgeBaseProvider __all__ = [ Retriever, diff --git a/src/rag/builder.py b/src/rag/builder.py index b7a6a07..314d9d5 100644 --- a/src/rag/builder.py +++ b/src/rag/builder.py @@ -3,8 +3,8 @@ from src.config.tools import SELECTED_RAG_PROVIDER, RAGProvider from src.rag.ragflow import RAGFlowProvider -from src.rag.vikingdb_knowledge_base import VikingDBKnowledgeBaseProvider from src.rag.retriever import Retriever +from src.rag.vikingdb_knowledge_base import VikingDBKnowledgeBaseProvider def build_retriever() -> Retriever | None: diff --git a/src/rag/ragflow.py b/src/rag/ragflow.py index ecb791e..ad8b81c 100644 --- a/src/rag/ragflow.py +++ b/src/rag/ragflow.py @@ -2,11 +2,13 @@ # SPDX-License-Identifier: MIT import os -import requests -from src.rag.retriever import Chunk, Document, Resource, Retriever from typing import List, Optional from urllib.parse import urlparse +import requests + +from src.rag.retriever import Chunk, Document, Resource, Retriever + class RAGFlowProvider(Retriever): """ diff --git a/src/rag/retriever.py b/src/rag/retriever.py index 233b25f..df349d9 100644 --- a/src/rag/retriever.py +++ b/src/rag/retriever.py @@ -2,6 +2,7 @@ # SPDX-License-Identifier: MIT import abc + from pydantic import BaseModel, Field diff --git a/src/rag/vikingdb_knowledge_base.py b/src/rag/vikingdb_knowledge_base.py index 23f68cc..bbab88b 100644 --- a/src/rag/vikingdb_knowledge_base.py +++ b/src/rag/vikingdb_knowledge_base.py @@ -1,16 +1,18 @@ # Copyright (c) 2025 Bytedance Ltd. and/or its affiliates # SPDX-License-Identifier: MIT -import os -import requests -import json import hashlib import hmac +import json +import os import urllib.parse from datetime import datetime -from src.rag.retriever import Chunk, Document, Resource, Retriever from urllib.parse import urlparse +import requests + +from src.rag.retriever import Chunk, Document, Resource, Retriever + class VikingDBKnowledgeBaseProvider(Retriever): """ diff --git a/src/server/chat_request.py b/src/server/chat_request.py index 0368717..df904e3 100644 --- a/src/server/chat_request.py +++ b/src/server/chat_request.py @@ -5,8 +5,8 @@ from typing import List, Optional, Union from pydantic import BaseModel, Field -from src.rag.retriever import Resource from src.config.report_style import ReportStyle +from src.rag.retriever import Resource class ContentItem(BaseModel): diff --git a/src/server/mcp_utils.py b/src/server/mcp_utils.py index d485688..c18c6b5 100644 --- a/src/server/mcp_utils.py +++ b/src/server/mcp_utils.py @@ -7,8 +7,8 @@ from typing import Any, Dict, List, Optional from fastapi import HTTPException from mcp import ClientSession, StdioServerParameters -from mcp.client.stdio import stdio_client from mcp.client.sse import sse_client +from mcp.client.stdio import stdio_client from mcp.client.streamable_http import streamablehttp_client logger = logging.getLogger(__name__) diff --git a/src/tools/crawl.py b/src/tools/crawl.py index 9b1aa97..552e813 100644 --- a/src/tools/crawl.py +++ b/src/tools/crawl.py @@ -5,10 +5,11 @@ import logging from typing import Annotated from langchain_core.tools import tool -from .decorators import log_io from src.crawler import Crawler +from .decorators import log_io + logger = logging.getLogger(__name__) diff --git a/src/tools/decorators.py b/src/tools/decorators.py index a37e82e..9d66d5c 100644 --- a/src/tools/decorators.py +++ b/src/tools/decorators.py @@ -1,8 +1,8 @@ # Copyright (c) 2025 Bytedance Ltd. and/or its affiliates # SPDX-License-Identifier: MIT -import logging import functools +import logging from typing import Any, Callable, Type, TypeVar logger = logging.getLogger(__name__) diff --git a/src/tools/python_repl.py b/src/tools/python_repl.py index 02a6a60..6629e1f 100644 --- a/src/tools/python_repl.py +++ b/src/tools/python_repl.py @@ -4,8 +4,10 @@ import logging import os from typing import Annotated, Optional + from langchain_core.tools import tool from langchain_experimental.utilities import PythonREPL + from .decorators import log_io diff --git a/src/tools/retriever.py b/src/tools/retriever.py index 12dfd49..091185e 100644 --- a/src/tools/retriever.py +++ b/src/tools/retriever.py @@ -3,15 +3,16 @@ import logging from typing import List, Optional, Type -from langchain_core.tools import BaseTool + from langchain_core.callbacks import ( AsyncCallbackManagerForToolRun, CallbackManagerForToolRun, ) +from langchain_core.tools import BaseTool from pydantic import BaseModel, Field from src.config.tools import SELECTED_RAG_PROVIDER -from src.rag import Document, Retriever, Resource, build_retriever +from src.rag import Document, Resource, Retriever, build_retriever logger = logging.getLogger(__name__) @@ -22,9 +23,7 @@ class RetrieverInput(BaseModel): class RetrieverTool(BaseTool): name: str = "local_search_tool" - description: str = ( - "Useful for retrieving information from the file with `rag://` uri prefix, it should be higher priority than the web search or writing code. Input should be a search keywords." - ) + description: str = "Useful for retrieving information from the file with `rag://` uri prefix, it should be higher priority than the web search or writing code. Input should be a search keywords." args_schema: Type[BaseModel] = RetrieverInput retriever: Retriever = Field(default_factory=Retriever) diff --git a/src/tools/search.py b/src/tools/search.py index 54a86b9..73c4128 100644 --- a/src/tools/search.py +++ b/src/tools/search.py @@ -17,18 +17,16 @@ from langchain_community.utilities import ( WikipediaAPIWrapper, ) -from src.config import SearchEngine, SELECTED_SEARCH_ENGINE -from src.config import load_yaml_config -from src.tools.tavily_search.tavily_search_results_with_images import ( - TavilySearchResultsWithImages, -) - +from src.config import SELECTED_SEARCH_ENGINE, SearchEngine, load_yaml_config from src.tools.decorators import create_logged_tool +from src.tools.tavily_search.tavily_search_results_with_images import ( + TavilySearchWithImages, +) logger = logging.getLogger(__name__) # Create logged versions of the search tools -LoggedTavilySearch = create_logged_tool(TavilySearchResultsWithImages) +LoggedTavilySearch = create_logged_tool(TavilySearchWithImages) LoggedDuckDuckGoSearch = create_logged_tool(DuckDuckGoSearchResults) LoggedBraveSearch = create_logged_tool(BraveSearch) LoggedArxivSearch = create_logged_tool(ArxivQueryRun) diff --git a/src/tools/tavily_search/__init__.py b/src/tools/tavily_search/__init__.py index ae24c27..ebaed27 100644 --- a/src/tools/tavily_search/__init__.py +++ b/src/tools/tavily_search/__init__.py @@ -1,4 +1,4 @@ from .tavily_search_api_wrapper import EnhancedTavilySearchAPIWrapper -from .tavily_search_results_with_images import TavilySearchResultsWithImages +from .tavily_search_results_with_images import TavilySearchWithImages -__all__ = ["EnhancedTavilySearchAPIWrapper", "TavilySearchResultsWithImages"] +__all__ = ["EnhancedTavilySearchAPIWrapper", "TavilySearchWithImages"] diff --git a/src/tools/tavily_search/tavily_search_api_wrapper.py b/src/tools/tavily_search/tavily_search_api_wrapper.py index 191d3c2..f1945a5 100644 --- a/src/tools/tavily_search/tavily_search_api_wrapper.py +++ b/src/tools/tavily_search/tavily_search_api_wrapper.py @@ -7,8 +7,8 @@ from typing import Dict, List, Optional import aiohttp import requests -from langchain_community.utilities.tavily_search import TAVILY_API_URL -from langchain_community.utilities.tavily_search import ( +from langchain_tavily._utilities import TAVILY_API_URL +from langchain_tavily.tavily_search import ( TavilySearchAPIWrapper as OriginalTavilySearchAPIWrapper, ) diff --git a/src/tools/tavily_search/tavily_search_results_with_images.py b/src/tools/tavily_search/tavily_search_results_with_images.py index edd4a07..c24fb0f 100644 --- a/src/tools/tavily_search/tavily_search_results_with_images.py +++ b/src/tools/tavily_search/tavily_search_results_with_images.py @@ -1,15 +1,15 @@ # Copyright (c) 2025 Bytedance Ltd. and/or its affiliates # SPDX-License-Identifier: MIT -import logging import json +import logging from typing import Dict, List, Optional, Tuple, Union from langchain.callbacks.manager import ( AsyncCallbackManagerForToolRun, CallbackManagerForToolRun, ) -from langchain_community.tools.tavily_search.tool import TavilySearchResults +from langchain_tavily.tavily_search import TavilySearch from pydantic import Field from src.tools.tavily_search.tavily_search_api_wrapper import ( @@ -19,7 +19,7 @@ from src.tools.tavily_search.tavily_search_api_wrapper import ( logger = logging.getLogger(__name__) -class TavilySearchResultsWithImages(TavilySearchResults): # type: ignore[override, override] +class TavilySearchWithImages(TavilySearch): # type: ignore[override, override] """Tool that queries the Tavily Search API and gets back json. Setup: @@ -34,9 +34,9 @@ class TavilySearchResultsWithImages(TavilySearchResults): # type: ignore[overri .. code-block:: python - from langchain_community.tools import TavilySearchResults + from langchain_tavily.tavily_search import TavilySearch - tool = TavilySearchResults( + tool = TavilySearch( max_results=5, include_answer=True, include_raw_content=True, @@ -102,7 +102,9 @@ class TavilySearchResultsWithImages(TavilySearchResults): # type: ignore[overri Default is False. """ - api_wrapper: EnhancedTavilySearchAPIWrapper = Field(default_factory=EnhancedTavilySearchAPIWrapper) # type: ignore[arg-type] + api_wrapper: EnhancedTavilySearchAPIWrapper = Field( + default_factory=EnhancedTavilySearchAPIWrapper + ) # type: ignore[arg-type] def _run( self, diff --git a/src/tools/tts.py b/src/tools/tts.py index d5f2565..ee60677 100644 --- a/src/tools/tts.py +++ b/src/tools/tts.py @@ -6,10 +6,11 @@ Text-to-Speech module using volcengine TTS API. """ import json -import uuid import logging +import uuid +from typing import Any, Dict, Optional + import requests -from typing import Optional, Dict, Any logger = logging.getLogger(__name__) diff --git a/src/utils/json_utils.py b/src/utils/json_utils.py index 946b526..a8a2257 100644 --- a/src/utils/json_utils.py +++ b/src/utils/json_utils.py @@ -1,8 +1,8 @@ # Copyright (c) 2025 Bytedance Ltd. and/or its affiliates # SPDX-License-Identifier: MIT -import logging import json +import logging from typing import Any import json_repair diff --git a/src/workflow.py b/src/workflow.py index 1279846..6fc173b 100644 --- a/src/workflow.py +++ b/src/workflow.py @@ -2,6 +2,7 @@ # SPDX-License-Identifier: MIT import logging + from src.config.configuration import get_recursion_limit from src.graph import build_graph diff --git a/tests/integration/test_nodes.py b/tests/integration/test_nodes.py index 8c2597f..161e556 100644 --- a/tests/integration/test_nodes.py +++ b/tests/integration/test_nodes.py @@ -1,21 +1,26 @@ -from collections import namedtuple import json +from collections import namedtuple +from unittest.mock import MagicMock, patch + import pytest -from unittest.mock import patch, MagicMock -from src.graph.nodes import planner_node -from src.graph.nodes import human_feedback_node -from src.graph.nodes import coordinator_node -from src.graph.nodes import reporter_node -from src.graph.nodes import _execute_agent_step -from src.graph.nodes import _setup_and_execute_agent_step -from src.graph.nodes import researcher_node + +from src.graph.nodes import ( + _execute_agent_step, + _setup_and_execute_agent_step, + coordinator_node, + human_feedback_node, + planner_node, + reporter_node, + researcher_node, +) # 在这里 mock 掉 get_llm_by_type,避免 ValueError with patch("src.llms.llm.get_llm_by_type", return_value=MagicMock()): - from langgraph.types import Command - from src.graph.nodes import background_investigation_node - from src.config import SearchEngine from langchain_core.messages import HumanMessage + from langgraph.types import Command + + from src.config import SearchEngine + from src.graph.nodes import background_investigation_node # Mock data diff --git a/tests/integration/test_template.py b/tests/integration/test_template.py index 431fe60..a234a5e 100644 --- a/tests/integration/test_template.py +++ b/tests/integration/test_template.py @@ -2,7 +2,8 @@ # SPDX-License-Identifier: MIT import pytest -from src.prompts.template import get_prompt_template, apply_prompt_template + +from src.prompts.template import apply_prompt_template, get_prompt_template def test_get_prompt_template_success(): diff --git a/tests/integration/test_tts.py b/tests/integration/test_tts.py index 16a4d9f..f75a8fb 100644 --- a/tests/integration/test_tts.py +++ b/tests/integration/test_tts.py @@ -1,9 +1,9 @@ # Copyright (c) 2025 Bytedance Ltd. and/or its affiliates # SPDX-License-Identifier: MIT -import json -from unittest.mock import patch, MagicMock import base64 +import json +from unittest.mock import MagicMock, patch from src.tools.tts import VolcengineTTS diff --git a/tests/test_state.py b/tests/test_state.py index 598ba1c..7adabdc 100644 --- a/tests/test_state.py +++ b/tests/test_state.py @@ -1,8 +1,8 @@ # Copyright (c) 2025 Bytedance Ltd. and/or its affiliates # SPDX-License-Identifier: MIT -import sys import os +import sys from typing import Annotated # Import MessagesState directly from langgraph rather than through our application diff --git a/tests/unit/config/test_configuration.py b/tests/unit/config/test_configuration.py index 324e9e2..8fa551d 100644 --- a/tests/unit/config/test_configuration.py +++ b/tests/unit/config/test_configuration.py @@ -3,6 +3,7 @@ import sys import types + from src.config.configuration import Configuration # Patch sys.path so relative import works diff --git a/tests/unit/config/test_loader.py b/tests/unit/config/test_loader.py index 3d5538d..be50bf8 100644 --- a/tests/unit/config/test_loader.py +++ b/tests/unit/config/test_loader.py @@ -3,6 +3,7 @@ import os import tempfile + from src.config.loader import load_yaml_config, process_dict, replace_env_vars diff --git a/tests/unit/graph/test_builder.py b/tests/unit/graph/test_builder.py index 079cac0..e76b41c 100644 --- a/tests/unit/graph/test_builder.py +++ b/tests/unit/graph/test_builder.py @@ -1,10 +1,11 @@ # Copyright (c) 2025 Bytedance Ltd. and/or its affiliates # SPDX-License-Identifier: MIT -import pytest -from unittest.mock import MagicMock, patch import importlib import sys +from unittest.mock import MagicMock, patch + +import pytest import src.graph.builder as builder_mod diff --git a/tests/unit/llms/test_llm.py b/tests/unit/llms/test_llm.py index 397ca72..714b7dc 100644 --- a/tests/unit/llms/test_llm.py +++ b/tests/unit/llms/test_llm.py @@ -2,6 +2,7 @@ # SPDX-License-Identifier: MIT import pytest + from src.llms import llm diff --git a/tests/unit/prompt_enhancer/graph/test_builder.py b/tests/unit/prompt_enhancer/graph/test_builder.py index f661f8b..8cf9721 100644 --- a/tests/unit/prompt_enhancer/graph/test_builder.py +++ b/tests/unit/prompt_enhancer/graph/test_builder.py @@ -1,8 +1,9 @@ # Copyright (c) 2025 Bytedance Ltd. and/or its affiliates # SPDX-License-Identifier: MIT +from unittest.mock import MagicMock, patch + import pytest -from unittest.mock import patch, MagicMock from src.prompt_enhancer.graph.builder import build_graph from src.prompt_enhancer.graph.state import PromptEnhancerState diff --git a/tests/unit/prompt_enhancer/graph/test_enhancer_node.py b/tests/unit/prompt_enhancer/graph/test_enhancer_node.py index a703801..b69350d 100644 --- a/tests/unit/prompt_enhancer/graph/test_enhancer_node.py +++ b/tests/unit/prompt_enhancer/graph/test_enhancer_node.py @@ -1,13 +1,14 @@ # Copyright (c) 2025 Bytedance Ltd. and/or its affiliates # SPDX-License-Identifier: MIT +from unittest.mock import MagicMock, patch + import pytest -from unittest.mock import patch, MagicMock from langchain.schema import HumanMessage, SystemMessage +from src.config.report_style import ReportStyle from src.prompt_enhancer.graph.enhancer_node import prompt_enhancer_node from src.prompt_enhancer.graph.state import PromptEnhancerState -from src.config.report_style import ReportStyle @pytest.fixture diff --git a/tests/unit/prompt_enhancer/graph/test_state.py b/tests/unit/prompt_enhancer/graph/test_state.py index 3006b78..04f018f 100644 --- a/tests/unit/prompt_enhancer/graph/test_state.py +++ b/tests/unit/prompt_enhancer/graph/test_state.py @@ -1,8 +1,8 @@ # Copyright (c) 2025 Bytedance Ltd. and/or its affiliates # SPDX-License-Identifier: MIT -from src.prompt_enhancer.graph.state import PromptEnhancerState from src.config.report_style import ReportStyle +from src.prompt_enhancer.graph.state import PromptEnhancerState def test_prompt_enhancer_state_creation(): diff --git a/tests/unit/rag/test_ragflow.py b/tests/unit/rag/test_ragflow.py index 42b04de..d36222a 100644 --- a/tests/unit/rag/test_ragflow.py +++ b/tests/unit/rag/test_ragflow.py @@ -1,8 +1,10 @@ # Copyright (c) 2025 Bytedance Ltd. and/or its affiliates # SPDX-License-Identifier: MIT +from unittest.mock import MagicMock, patch + import pytest -from unittest.mock import patch, MagicMock + from src.rag.ragflow import RAGFlowProvider, parse_uri diff --git a/tests/unit/rag/test_retriever.py b/tests/unit/rag/test_retriever.py index 4c4964d..582f2af 100644 --- a/tests/unit/rag/test_retriever.py +++ b/tests/unit/rag/test_retriever.py @@ -2,6 +2,7 @@ # SPDX-License-Identifier: MIT import pytest + from src.rag.retriever import Chunk, Document, Resource, Retriever diff --git a/tests/unit/rag/test_vikingdb_knowledge_base.py b/tests/unit/rag/test_vikingdb_knowledge_base.py index a60fb58..8a451ca 100644 --- a/tests/unit/rag/test_vikingdb_knowledge_base.py +++ b/tests/unit/rag/test_vikingdb_knowledge_base.py @@ -1,13 +1,15 @@ # Copyright (c) 2025 Bytedance Ltd. and/or its affiliates # SPDX-License-Identifier: MIT -import os -import pytest -import json import hashlib import hmac -from unittest.mock import patch, MagicMock +import json +import os from datetime import datetime +from unittest.mock import MagicMock, patch + +import pytest + from src.rag.vikingdb_knowledge_base import VikingDBKnowledgeBaseProvider, parse_uri diff --git a/tests/unit/server/test_app.py b/tests/unit/server/test_app.py index 3df498d..a82fbef 100644 --- a/tests/unit/server/test_app.py +++ b/tests/unit/server/test_app.py @@ -3,15 +3,16 @@ import base64 import os -from unittest.mock import MagicMock, patch, mock_open +from unittest.mock import MagicMock, mock_open, patch + import pytest -from fastapi.testclient import TestClient from fastapi import HTTPException -from src.server.app import app, _make_event, _astream_workflow_generator -from src.config.report_style import ReportStyle +from fastapi.testclient import TestClient +from langchain_core.messages import AIMessageChunk, ToolMessage from langgraph.types import Command -from langchain_core.messages import ToolMessage -from langchain_core.messages import AIMessageChunk + +from src.config.report_style import ReportStyle +from src.server.app import _astream_workflow_generator, _make_event, app @pytest.fixture @@ -333,7 +334,6 @@ class TestMCPEndpoint: def test_mcp_server_metadata_without_enable_configuration( self, mock_load_tools, client ): - request_data = { "transport": "stdio", "command": "test_command", @@ -547,7 +547,6 @@ class TestAstreamWorkflowGenerator: @pytest.mark.asyncio @patch("src.server.app.graph") async def test_astream_workflow_generator_with_interrupt_feedback(self, mock_graph): - # Mock the async stream async def mock_astream(*args, **kwargs): # Verify that Command is passed as input when interrupt_feedback is provided @@ -620,7 +619,6 @@ class TestAstreamWorkflowGenerator: @pytest.mark.asyncio @patch("src.server.app.graph") async def test_astream_workflow_generator_tool_message(self, mock_graph): - # Mock tool message mock_tool_message = ToolMessage(content="Tool result", tool_call_id="tool_123") mock_tool_message.id = "msg_456" @@ -659,7 +657,6 @@ class TestAstreamWorkflowGenerator: async def test_astream_workflow_generator_ai_message_with_tool_calls( self, mock_graph ): - # Mock AI message with tool calls mock_ai_message = AIMessageChunk(content="Making tool call") mock_ai_message.id = "msg_789" @@ -701,7 +698,6 @@ class TestAstreamWorkflowGenerator: async def test_astream_workflow_generator_ai_message_with_tool_call_chunks( self, mock_graph ): - # Mock AI message with only tool call chunks mock_ai_message = AIMessageChunk(content="Streaming tool call") mock_ai_message.id = "msg_101" @@ -740,7 +736,6 @@ class TestAstreamWorkflowGenerator: @pytest.mark.asyncio @patch("src.server.app.graph") async def test_astream_workflow_generator_with_finish_reason(self, mock_graph): - # Mock AI message with finish reason mock_ai_message = AIMessageChunk(content="Complete response") mock_ai_message.id = "msg_finish" @@ -780,7 +775,6 @@ class TestAstreamWorkflowGenerator: @pytest.mark.asyncio @patch("src.server.app.graph") async def test_astream_workflow_generator_config_passed_correctly(self, mock_graph): - mock_ai_message = AIMessageChunk(content="Test") mock_ai_message.id = "test_id" mock_ai_message.response_metadata = {} diff --git a/tests/unit/server/test_chat_request.py b/tests/unit/server/test_chat_request.py index d3f5363..69bce54 100644 --- a/tests/unit/server/test_chat_request.py +++ b/tests/unit/server/test_chat_request.py @@ -1,24 +1,25 @@ # Copyright (c) 2025 Bytedance Ltd. and/or its affiliates # SPDX-License-Identifier: MIT +from unittest.mock import AsyncMock, MagicMock, patch + import pytest +from fastapi import HTTPException from pydantic import ValidationError + +import src.server.mcp_utils as mcp_utils # Assuming mcp_utils is the module to test from src.config.report_style import ReportStyle from src.rag.retriever import Resource -from unittest.mock import AsyncMock, patch, MagicMock -from fastapi import HTTPException - from src.server.chat_request import ( - ContentItem, ChatMessage, ChatRequest, - TTSRequest, + ContentItem, + EnhancePromptRequest, GeneratePodcastRequest, GeneratePPTRequest, GenerateProseRequest, - EnhancePromptRequest, + TTSRequest, ) -import src.server.mcp_utils as mcp_utils # Assuming mcp_utils is the module to test def test_content_item_text_and_image(): diff --git a/tests/unit/server/test_mcp_request.py b/tests/unit/server/test_mcp_request.py index eb43128..266017f 100644 --- a/tests/unit/server/test_mcp_request.py +++ b/tests/unit/server/test_mcp_request.py @@ -3,6 +3,7 @@ import pytest from pydantic import ValidationError + from src.server.mcp_request import MCPServerMetadataRequest, MCPServerMetadataResponse diff --git a/tests/unit/server/test_mcp_utils.py b/tests/unit/server/test_mcp_utils.py index cb130b1..c37ed8d 100644 --- a/tests/unit/server/test_mcp_utils.py +++ b/tests/unit/server/test_mcp_utils.py @@ -1,8 +1,9 @@ # Copyright (c) 2025 Bytedance Ltd. and/or its affiliates # SPDX-License-Identifier: MIT +from unittest.mock import AsyncMock, MagicMock, patch + import pytest -from unittest.mock import AsyncMock, patch, MagicMock from fastapi import HTTPException import src.server.mcp_utils as mcp_utils diff --git a/tests/unit/tools/test_crawl.py b/tests/unit/tools/test_crawl.py index cdbe4cf..f43b11c 100644 --- a/tests/unit/tools/test_crawl.py +++ b/tests/unit/tools/test_crawl.py @@ -1,9 +1,9 @@ from unittest.mock import Mock, patch + from src.tools.crawl import crawl_tool class TestCrawlTool: - @patch("src.tools.crawl.Crawler") def test_crawl_tool_success(self, mock_crawler_class): # Arrange diff --git a/tests/unit/tools/test_decorators.py b/tests/unit/tools/test_decorators.py index 5864dcb..36a7414 100644 --- a/tests/unit/tools/test_decorators.py +++ b/tests/unit/tools/test_decorators.py @@ -2,6 +2,7 @@ # SPDX-License-Identifier: MIT from unittest.mock import Mock, call, patch + from src.tools.decorators import create_logged_tool @@ -13,7 +14,6 @@ class MockBaseTool: class TestLoggedToolMixin: - def test_run_calls_log_operation(self): """Test that _run calls _log_operation with correct parameters.""" # Create a logged tool instance diff --git a/tests/unit/tools/test_python_repl.py b/tests/unit/tools/test_python_repl.py index d1ed6e8..3a77f54 100644 --- a/tests/unit/tools/test_python_repl.py +++ b/tests/unit/tools/test_python_repl.py @@ -2,13 +2,14 @@ # SPDX-License-Identifier: MIT import os -import pytest from unittest.mock import patch + +import pytest + from src.tools.python_repl import python_repl_tool class TestPythonReplTool: - @patch.dict(os.environ, {"ENABLE_PYTHON_REPL": "true"}) @patch("src.tools.python_repl.repl") @patch("src.tools.python_repl.logger") diff --git a/tests/unit/tools/test_search.py b/tests/unit/tools/test_search.py index 1fb5c20..78ac14a 100644 --- a/tests/unit/tools/test_search.py +++ b/tests/unit/tools/test_search.py @@ -2,14 +2,15 @@ # SPDX-License-Identifier: MIT import os -import pytest from unittest.mock import patch -from src.tools.search import get_web_search_tool + +import pytest + from src.config import SearchEngine +from src.tools.search import get_web_search_tool class TestGetWebSearchTool: - @patch("src.tools.search.SELECTED_SEARCH_ENGINE", SearchEngine.TAVILY.value) def test_get_web_search_tool_tavily(self): tool = get_web_search_tool(max_search_results=5) diff --git a/tests/unit/tools/test_tavily_search_api_wrapper.py b/tests/unit/tools/test_tavily_search_api_wrapper.py index eb60316..5481eaa 100644 --- a/tests/unit/tools/test_tavily_search_api_wrapper.py +++ b/tests/unit/tools/test_tavily_search_api_wrapper.py @@ -1,16 +1,17 @@ # Copyright (c) 2025 Bytedance Ltd. and/or its affiliates # SPDX-License-Identifier: MIT import json +from unittest.mock import AsyncMock, MagicMock, Mock, patch + import pytest -from unittest.mock import Mock, patch, AsyncMock, MagicMock import requests + from src.tools.tavily_search.tavily_search_api_wrapper import ( EnhancedTavilySearchAPIWrapper, ) class TestEnhancedTavilySearchAPIWrapper: - @pytest.fixture def wrapper(self): with patch( diff --git a/tests/unit/tools/test_tavily_search_results_with_images.py b/tests/unit/tools/test_tavily_search_results_with_images.py index 562089c..1e24f04 100644 --- a/tests/unit/tools/test_tavily_search_results_with_images.py +++ b/tests/unit/tools/test_tavily_search_results_with_images.py @@ -1,18 +1,19 @@ # Copyright (c) 2025 Bytedance Ltd. and/or its affiliates # SPDX-License-Identifier: MIT +from unittest.mock import AsyncMock, Mock, patch + import pytest -from unittest.mock import Mock, AsyncMock -from src.tools.tavily_search.tavily_search_results_with_images import ( - TavilySearchResultsWithImages, -) + from src.tools.tavily_search.tavily_search_api_wrapper import ( EnhancedTavilySearchAPIWrapper, ) +from src.tools.tavily_search.tavily_search_results_with_images import ( + TavilySearchWithImages, +) -class TestTavilySearchResultsWithImages: - +class TestTavilySearchWithImages: @pytest.fixture def mock_api_wrapper(self): """Create a mock API wrapper.""" @@ -21,8 +22,8 @@ class TestTavilySearchResultsWithImages: @pytest.fixture def search_tool(self, mock_api_wrapper): - """Create a TavilySearchResultsWithImages instance with mocked dependencies.""" - tool = TavilySearchResultsWithImages( + """Create a TavilySearchWithImages instance with mocked dependencies.""" + tool = TavilySearchWithImages( max_results=5, include_answer=True, include_raw_content=True, @@ -64,15 +65,13 @@ class TestTavilySearchResultsWithImages: def test_init_default_values(self): """Test initialization with default values.""" - tool = TavilySearchResultsWithImages() + tool = TavilySearchWithImages() assert tool.include_image_descriptions is False assert isinstance(tool.api_wrapper, EnhancedTavilySearchAPIWrapper) def test_init_custom_values(self): """Test initialization with custom values.""" - tool = TavilySearchResultsWithImages( - max_results=10, include_image_descriptions=True - ) + tool = TavilySearchWithImages(max_results=10, include_image_descriptions=True) assert tool.max_results == 10 assert tool.include_image_descriptions is True diff --git a/tests/unit/tools/test_tools_retriever.py b/tests/unit/tools/test_tools_retriever.py index 052504a..e4aaee0 100644 --- a/tests/unit/tools/test_tools_retriever.py +++ b/tests/unit/tools/test_tools_retriever.py @@ -2,13 +2,15 @@ # SPDX-License-Identifier: MIT from unittest.mock import Mock, patch -from langchain_core.callbacks import ( - CallbackManagerForToolRun, - AsyncCallbackManagerForToolRun, -) + import pytest +from langchain_core.callbacks import ( + AsyncCallbackManagerForToolRun, + CallbackManagerForToolRun, +) + +from src.rag import Chunk, Document, Resource, Retriever from src.tools.retriever import RetrieverInput, RetrieverTool, get_retriever_tool -from src.rag import Document, Retriever, Resource, Chunk def test_retriever_input_model(): diff --git a/tests/unit/utils/test_json_utils.py b/tests/unit/utils/test_json_utils.py index f90707a..60e2d1d 100644 --- a/tests/unit/utils/test_json_utils.py +++ b/tests/unit/utils/test_json_utils.py @@ -2,11 +2,11 @@ # SPDX-License-Identifier: MIT import json + from src.utils.json_utils import repair_json_output class TestRepairJsonOutput: - def test_valid_json_object(self): """Test with valid JSON object""" content = '{"key": "value", "number": 123}' diff --git a/uv.lock b/uv.lock index e01e8c2..91f14d7 100644 --- a/uv.lock +++ b/uv.lock @@ -18,7 +18,7 @@ wheels = [ [[package]] name = "aiohttp" -version = "3.11.13" +version = "3.12.14" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohappyeyeballs" }, @@ -29,52 +29,55 @@ dependencies = [ { name = "propcache" }, { name = "yarl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b3/3f/c4a667d184c69667b8f16e0704127efc5f1e60577df429382b4d95fd381e/aiohttp-3.11.13.tar.gz", hash = "sha256:8ce789231404ca8fff7f693cdce398abf6d90fd5dae2b1847477196c243b1fbb", size = 7674284, upload-time = "2025-02-24T16:02:06.91Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e6/0b/e39ad954107ebf213a2325038a3e7a506be3d98e1435e1f82086eec4cde2/aiohttp-3.12.14.tar.gz", hash = "sha256:6e06e120e34d93100de448fd941522e11dafa78ef1a893c179901b7d66aa29f2", size = 7822921, upload-time = "2025-07-10T13:05:33.968Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9a/a9/6657664a55f78db8767e396cc9723782ed3311eb57704b0a5dacfa731916/aiohttp-3.11.13-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:2eabb269dc3852537d57589b36d7f7362e57d1ece308842ef44d9830d2dc3c90", size = 705054, upload-time = "2025-02-24T16:00:06.227Z" }, - { url = "https://files.pythonhosted.org/packages/3b/06/f7df1fe062d16422f70af5065b76264f40b382605cf7477fa70553a9c9c1/aiohttp-3.11.13-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7b77ee42addbb1c36d35aca55e8cc6d0958f8419e458bb70888d8c69a4ca833d", size = 464440, upload-time = "2025-02-24T16:00:08.028Z" }, - { url = "https://files.pythonhosted.org/packages/22/3a/8773ea866735754004d9f79e501fe988bdd56cfac7fdecbc8de17fc093eb/aiohttp-3.11.13-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55789e93c5ed71832e7fac868167276beadf9877b85697020c46e9a75471f55f", size = 456394, upload-time = "2025-02-24T16:00:10.809Z" }, - { url = "https://files.pythonhosted.org/packages/7f/61/8e2f2af2327e8e475a2b0890f15ef0bbfd117e321cce1e1ed210df81bbac/aiohttp-3.11.13-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c929f9a7249a11e4aa5c157091cfad7f49cc6b13f4eecf9b747104befd9f56f2", size = 1682752, upload-time = "2025-02-24T16:00:12.681Z" }, - { url = "https://files.pythonhosted.org/packages/24/ed/84fce816bc8da39aa3f6c1196fe26e47065fea882b1a67a808282029c079/aiohttp-3.11.13-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d33851d85537bbf0f6291ddc97926a754c8f041af759e0aa0230fe939168852b", size = 1737375, upload-time = "2025-02-24T16:00:14.483Z" }, - { url = "https://files.pythonhosted.org/packages/d9/de/35a5ba9e3d21ebfda1ebbe66f6cc5cbb4d3ff9bd6a03e5e8a788954f8f27/aiohttp-3.11.13-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9229d8613bd8401182868fe95688f7581673e1c18ff78855671a4b8284f47bcb", size = 1793660, upload-time = "2025-02-24T16:00:16.379Z" }, - { url = "https://files.pythonhosted.org/packages/ff/fe/0f650a8c7c72c8a07edf8ab164786f936668acd71786dd5885fc4b1ca563/aiohttp-3.11.13-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:669dd33f028e54fe4c96576f406ebb242ba534dd3a981ce009961bf49960f117", size = 1692233, upload-time = "2025-02-24T16:00:18.354Z" }, - { url = "https://files.pythonhosted.org/packages/a8/20/185378b3483f968c6303aafe1e33b0da0d902db40731b2b2b2680a631131/aiohttp-3.11.13-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7c1b20a1ace54af7db1f95af85da530fe97407d9063b7aaf9ce6a32f44730778", size = 1619708, upload-time = "2025-02-24T16:00:20.214Z" }, - { url = "https://files.pythonhosted.org/packages/a4/f9/d9c181750980b17e1e13e522d7e82a8d08d3d28a2249f99207ef5d8d738f/aiohttp-3.11.13-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5724cc77f4e648362ebbb49bdecb9e2b86d9b172c68a295263fa072e679ee69d", size = 1641802, upload-time = "2025-02-24T16:00:22.154Z" }, - { url = "https://files.pythonhosted.org/packages/50/c7/1cb46b72b1788710343b6e59eaab9642bd2422f2d87ede18b1996e0aed8f/aiohttp-3.11.13-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:aa36c35e94ecdb478246dd60db12aba57cfcd0abcad43c927a8876f25734d496", size = 1684678, upload-time = "2025-02-24T16:00:24.884Z" }, - { url = "https://files.pythonhosted.org/packages/71/87/89b979391de840c5d7c34e78e1148cc731b8aafa84b6a51d02f44b4c66e2/aiohttp-3.11.13-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:9b5b37c863ad5b0892cc7a4ceb1e435e5e6acd3f2f8d3e11fa56f08d3c67b820", size = 1646921, upload-time = "2025-02-24T16:00:27.756Z" }, - { url = "https://files.pythonhosted.org/packages/a7/db/a463700ac85b72f8cf68093e988538faaf4e865e3150aa165cf80ee29d6e/aiohttp-3.11.13-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:e06cf4852ce8c4442a59bae5a3ea01162b8fcb49ab438d8548b8dc79375dad8a", size = 1702493, upload-time = "2025-02-24T16:00:30.641Z" }, - { url = "https://files.pythonhosted.org/packages/b8/32/1084e65da3adfb08c7e1b3e94f3e4ded8bd707dee265a412bc377b7cd000/aiohttp-3.11.13-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5194143927e494616e335d074e77a5dac7cd353a04755330c9adc984ac5a628e", size = 1735004, upload-time = "2025-02-24T16:00:35.127Z" }, - { url = "https://files.pythonhosted.org/packages/a0/bb/a634cbdd97ce5d05c2054a9a35bfc32792d7e4f69d600ad7e820571d095b/aiohttp-3.11.13-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:afcb6b275c2d2ba5d8418bf30a9654fa978b4f819c2e8db6311b3525c86fe637", size = 1694964, upload-time = "2025-02-24T16:00:40.008Z" }, - { url = "https://files.pythonhosted.org/packages/fd/cf/7d29db4e5c28ec316e5d2ac9ac9df0e2e278e9ea910e5c4205b9b64c2c42/aiohttp-3.11.13-cp312-cp312-win32.whl", hash = "sha256:7104d5b3943c6351d1ad7027d90bdd0ea002903e9f610735ac99df3b81f102ee", size = 411746, upload-time = "2025-02-24T16:00:43.168Z" }, - { url = "https://files.pythonhosted.org/packages/65/a9/13e69ad4fd62104ebd94617f9f2be58231b50bb1e6bac114f024303ac23b/aiohttp-3.11.13-cp312-cp312-win_amd64.whl", hash = "sha256:47dc018b1b220c48089b5b9382fbab94db35bef2fa192995be22cbad3c5730c8", size = 438078, upload-time = "2025-02-24T16:00:45.977Z" }, - { url = "https://files.pythonhosted.org/packages/87/dc/7d58d33cec693f1ddf407d4ab975445f5cb507af95600f137b81683a18d8/aiohttp-3.11.13-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9862d077b9ffa015dbe3ce6c081bdf35135948cb89116e26667dd183550833d1", size = 698372, upload-time = "2025-02-24T16:00:47.742Z" }, - { url = "https://files.pythonhosted.org/packages/84/e7/5d88514c9e24fbc8dd6117350a8ec4a9314f4adae6e89fe32e3e639b0c37/aiohttp-3.11.13-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:fbfef0666ae9e07abfa2c54c212ac18a1f63e13e0760a769f70b5717742f3ece", size = 461057, upload-time = "2025-02-24T16:00:49.467Z" }, - { url = "https://files.pythonhosted.org/packages/96/1a/8143c48a929fa00c6324f85660cb0f47a55ed9385f0c1b72d4b8043acf8e/aiohttp-3.11.13-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:93a1f7d857c4fcf7cabb1178058182c789b30d85de379e04f64c15b7e88d66fb", size = 453340, upload-time = "2025-02-24T16:00:52.274Z" }, - { url = "https://files.pythonhosted.org/packages/2f/1c/b8010e4d65c5860d62681088e5376f3c0a940c5e3ca8989cae36ce8c3ea8/aiohttp-3.11.13-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba40b7ae0f81c7029583a338853f6607b6d83a341a3dcde8bed1ea58a3af1df9", size = 1665561, upload-time = "2025-02-24T16:00:53.954Z" }, - { url = "https://files.pythonhosted.org/packages/19/ed/a68c3ab2f92fdc17dfc2096117d1cfaa7f7bdded2a57bacbf767b104165b/aiohttp-3.11.13-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b5b95787335c483cd5f29577f42bbe027a412c5431f2f80a749c80d040f7ca9f", size = 1718335, upload-time = "2025-02-24T16:00:56.885Z" }, - { url = "https://files.pythonhosted.org/packages/27/4f/3a0b6160ce663b8ebdb65d1eedff60900cd7108838c914d25952fe2b909f/aiohttp-3.11.13-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7d474c5c1f0b9405c1565fafdc4429fa7d986ccbec7ce55bc6a330f36409cad", size = 1775522, upload-time = "2025-02-24T16:00:58.94Z" }, - { url = "https://files.pythonhosted.org/packages/0b/58/9da09291e19696c452e7224c1ce8c6d23a291fe8cd5c6b247b51bcda07db/aiohttp-3.11.13-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e83fb1991e9d8982b3b36aea1e7ad27ea0ce18c14d054c7a404d68b0319eebb", size = 1677566, upload-time = "2025-02-24T16:01:01.987Z" }, - { url = "https://files.pythonhosted.org/packages/3d/18/6184f2bf8bbe397acbbbaa449937d61c20a6b85765f48e5eddc6d84957fe/aiohttp-3.11.13-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4586a68730bd2f2b04a83e83f79d271d8ed13763f64b75920f18a3a677b9a7f0", size = 1603590, upload-time = "2025-02-24T16:01:04.164Z" }, - { url = "https://files.pythonhosted.org/packages/04/94/91e0d1ca0793012ccd927e835540aa38cca98bdce2389256ab813ebd64a3/aiohttp-3.11.13-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9fe4eb0e7f50cdb99b26250d9328faef30b1175a5dbcfd6d0578d18456bac567", size = 1618688, upload-time = "2025-02-24T16:01:07.565Z" }, - { url = "https://files.pythonhosted.org/packages/71/85/d13c3ea2e48a10b43668305d4903838834c3d4112e5229177fbcc23a56cd/aiohttp-3.11.13-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:2a8a6bc19818ac3e5596310ace5aa50d918e1ebdcc204dc96e2f4d505d51740c", size = 1658053, upload-time = "2025-02-24T16:01:10.495Z" }, - { url = "https://files.pythonhosted.org/packages/12/6a/3242a35100de23c1e8d9e05e8605e10f34268dee91b00d9d1e278c58eb80/aiohttp-3.11.13-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:7f27eec42f6c3c1df09cfc1f6786308f8b525b8efaaf6d6bd76c1f52c6511f6a", size = 1616917, upload-time = "2025-02-24T16:01:13.685Z" }, - { url = "https://files.pythonhosted.org/packages/f5/b3/3f99b6f0a9a79590a7ba5655dbde8408c685aa462247378c977603464d0a/aiohttp-3.11.13-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:2a4a13dfbb23977a51853b419141cd0a9b9573ab8d3a1455c6e63561387b52ff", size = 1685872, upload-time = "2025-02-24T16:01:15.649Z" }, - { url = "https://files.pythonhosted.org/packages/8a/2e/99672181751f280a85e24fcb9a2c2469e8b1a0de1746b7b5c45d1eb9a999/aiohttp-3.11.13-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:02876bf2f69b062584965507b07bc06903c2dc93c57a554b64e012d636952654", size = 1715719, upload-time = "2025-02-24T16:01:17.649Z" }, - { url = "https://files.pythonhosted.org/packages/7a/cd/68030356eb9a7d57b3e2823c8a852709d437abb0fbff41a61ebc351b7625/aiohttp-3.11.13-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b992778d95b60a21c4d8d4a5f15aaab2bd3c3e16466a72d7f9bfd86e8cea0d4b", size = 1673166, upload-time = "2025-02-24T16:01:19.618Z" }, - { url = "https://files.pythonhosted.org/packages/03/61/425397a9a2839c609d09fdb53d940472f316a2dbeaa77a35b2628dae6284/aiohttp-3.11.13-cp313-cp313-win32.whl", hash = "sha256:507ab05d90586dacb4f26a001c3abf912eb719d05635cbfad930bdbeb469b36c", size = 410615, upload-time = "2025-02-24T16:01:21.567Z" }, - { url = "https://files.pythonhosted.org/packages/9c/54/ebb815bc0fe057d8e7a11c086c479e972e827082f39aeebc6019dd4f0862/aiohttp-3.11.13-cp313-cp313-win_amd64.whl", hash = "sha256:5ceb81a4db2decdfa087381b5fc5847aa448244f973e5da232610304e199e7b2", size = 436452, upload-time = "2025-02-24T16:01:23.611Z" }, + { url = "https://files.pythonhosted.org/packages/c3/0d/29026524e9336e33d9767a1e593ae2b24c2b8b09af7c2bd8193762f76b3e/aiohttp-3.12.14-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a0ecbb32fc3e69bc25efcda7d28d38e987d007096cbbeed04f14a6662d0eee22", size = 701055, upload-time = "2025-07-10T13:03:45.59Z" }, + { url = "https://files.pythonhosted.org/packages/0a/b8/a5e8e583e6c8c1056f4b012b50a03c77a669c2e9bf012b7cf33d6bc4b141/aiohttp-3.12.14-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0400f0ca9bb3e0b02f6466421f253797f6384e9845820c8b05e976398ac1d81a", size = 475670, upload-time = "2025-07-10T13:03:47.249Z" }, + { url = "https://files.pythonhosted.org/packages/29/e8/5202890c9e81a4ec2c2808dd90ffe024952e72c061729e1d49917677952f/aiohttp-3.12.14-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a56809fed4c8a830b5cae18454b7464e1529dbf66f71c4772e3cfa9cbec0a1ff", size = 468513, upload-time = "2025-07-10T13:03:49.377Z" }, + { url = "https://files.pythonhosted.org/packages/23/e5/d11db8c23d8923d3484a27468a40737d50f05b05eebbb6288bafcb467356/aiohttp-3.12.14-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27f2e373276e4755691a963e5d11756d093e346119f0627c2d6518208483fb6d", size = 1715309, upload-time = "2025-07-10T13:03:51.556Z" }, + { url = "https://files.pythonhosted.org/packages/53/44/af6879ca0eff7a16b1b650b7ea4a827301737a350a464239e58aa7c387ef/aiohttp-3.12.14-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:ca39e433630e9a16281125ef57ece6817afd1d54c9f1bf32e901f38f16035869", size = 1697961, upload-time = "2025-07-10T13:03:53.511Z" }, + { url = "https://files.pythonhosted.org/packages/bb/94/18457f043399e1ec0e59ad8674c0372f925363059c276a45a1459e17f423/aiohttp-3.12.14-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9c748b3f8b14c77720132b2510a7d9907a03c20ba80f469e58d5dfd90c079a1c", size = 1753055, upload-time = "2025-07-10T13:03:55.368Z" }, + { url = "https://files.pythonhosted.org/packages/26/d9/1d3744dc588fafb50ff8a6226d58f484a2242b5dd93d8038882f55474d41/aiohttp-3.12.14-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f0a568abe1b15ce69d4cc37e23020720423f0728e3cb1f9bcd3f53420ec3bfe7", size = 1799211, upload-time = "2025-07-10T13:03:57.216Z" }, + { url = "https://files.pythonhosted.org/packages/73/12/2530fb2b08773f717ab2d249ca7a982ac66e32187c62d49e2c86c9bba9b4/aiohttp-3.12.14-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9888e60c2c54eaf56704b17feb558c7ed6b7439bca1e07d4818ab878f2083660", size = 1718649, upload-time = "2025-07-10T13:03:59.469Z" }, + { url = "https://files.pythonhosted.org/packages/b9/34/8d6015a729f6571341a311061b578e8b8072ea3656b3d72329fa0faa2c7c/aiohttp-3.12.14-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3006a1dc579b9156de01e7916d38c63dc1ea0679b14627a37edf6151bc530088", size = 1634452, upload-time = "2025-07-10T13:04:01.698Z" }, + { url = "https://files.pythonhosted.org/packages/ff/4b/08b83ea02595a582447aeb0c1986792d0de35fe7a22fb2125d65091cbaf3/aiohttp-3.12.14-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:aa8ec5c15ab80e5501a26719eb48a55f3c567da45c6ea5bb78c52c036b2655c7", size = 1695511, upload-time = "2025-07-10T13:04:04.165Z" }, + { url = "https://files.pythonhosted.org/packages/b5/66/9c7c31037a063eec13ecf1976185c65d1394ded4a5120dd5965e3473cb21/aiohttp-3.12.14-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:39b94e50959aa07844c7fe2206b9f75d63cc3ad1c648aaa755aa257f6f2498a9", size = 1716967, upload-time = "2025-07-10T13:04:06.132Z" }, + { url = "https://files.pythonhosted.org/packages/ba/02/84406e0ad1acb0fb61fd617651ab6de760b2d6a31700904bc0b33bd0894d/aiohttp-3.12.14-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:04c11907492f416dad9885d503fbfc5dcb6768d90cad8639a771922d584609d3", size = 1657620, upload-time = "2025-07-10T13:04:07.944Z" }, + { url = "https://files.pythonhosted.org/packages/07/53/da018f4013a7a179017b9a274b46b9a12cbeb387570f116964f498a6f211/aiohttp-3.12.14-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:88167bd9ab69bb46cee91bd9761db6dfd45b6e76a0438c7e884c3f8160ff21eb", size = 1737179, upload-time = "2025-07-10T13:04:10.182Z" }, + { url = "https://files.pythonhosted.org/packages/49/e8/ca01c5ccfeaafb026d85fa4f43ceb23eb80ea9c1385688db0ef322c751e9/aiohttp-3.12.14-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:791504763f25e8f9f251e4688195e8b455f8820274320204f7eafc467e609425", size = 1765156, upload-time = "2025-07-10T13:04:12.029Z" }, + { url = "https://files.pythonhosted.org/packages/22/32/5501ab525a47ba23c20613e568174d6c63aa09e2caa22cded5c6ea8e3ada/aiohttp-3.12.14-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2785b112346e435dd3a1a67f67713a3fe692d288542f1347ad255683f066d8e0", size = 1724766, upload-time = "2025-07-10T13:04:13.961Z" }, + { url = "https://files.pythonhosted.org/packages/06/af/28e24574801fcf1657945347ee10df3892311c2829b41232be6089e461e7/aiohttp-3.12.14-cp312-cp312-win32.whl", hash = "sha256:15f5f4792c9c999a31d8decf444e79fcfd98497bf98e94284bf390a7bb8c1729", size = 422641, upload-time = "2025-07-10T13:04:16.018Z" }, + { url = "https://files.pythonhosted.org/packages/98/d5/7ac2464aebd2eecac38dbe96148c9eb487679c512449ba5215d233755582/aiohttp-3.12.14-cp312-cp312-win_amd64.whl", hash = "sha256:3b66e1a182879f579b105a80d5c4bd448b91a57e8933564bf41665064796a338", size = 449316, upload-time = "2025-07-10T13:04:18.289Z" }, + { url = "https://files.pythonhosted.org/packages/06/48/e0d2fa8ac778008071e7b79b93ab31ef14ab88804d7ba71b5c964a7c844e/aiohttp-3.12.14-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:3143a7893d94dc82bc409f7308bc10d60285a3cd831a68faf1aa0836c5c3c767", size = 695471, upload-time = "2025-07-10T13:04:20.124Z" }, + { url = "https://files.pythonhosted.org/packages/8d/e7/f73206afa33100804f790b71092888f47df65fd9a4cd0e6800d7c6826441/aiohttp-3.12.14-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3d62ac3d506cef54b355bd34c2a7c230eb693880001dfcda0bf88b38f5d7af7e", size = 473128, upload-time = "2025-07-10T13:04:21.928Z" }, + { url = "https://files.pythonhosted.org/packages/df/e2/4dd00180be551a6e7ee979c20fc7c32727f4889ee3fd5b0586e0d47f30e1/aiohttp-3.12.14-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:48e43e075c6a438937c4de48ec30fa8ad8e6dfef122a038847456bfe7b947b63", size = 465426, upload-time = "2025-07-10T13:04:24.071Z" }, + { url = "https://files.pythonhosted.org/packages/de/dd/525ed198a0bb674a323e93e4d928443a680860802c44fa7922d39436b48b/aiohttp-3.12.14-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:077b4488411a9724cecc436cbc8c133e0d61e694995b8de51aaf351c7578949d", size = 1704252, upload-time = "2025-07-10T13:04:26.049Z" }, + { url = "https://files.pythonhosted.org/packages/d8/b1/01e542aed560a968f692ab4fc4323286e8bc4daae83348cd63588e4f33e3/aiohttp-3.12.14-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d8c35632575653f297dcbc9546305b2c1133391089ab925a6a3706dfa775ccab", size = 1685514, upload-time = "2025-07-10T13:04:28.186Z" }, + { url = "https://files.pythonhosted.org/packages/b3/06/93669694dc5fdabdc01338791e70452d60ce21ea0946a878715688d5a191/aiohttp-3.12.14-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6b8ce87963f0035c6834b28f061df90cf525ff7c9b6283a8ac23acee6502afd4", size = 1737586, upload-time = "2025-07-10T13:04:30.195Z" }, + { url = "https://files.pythonhosted.org/packages/a5/3a/18991048ffc1407ca51efb49ba8bcc1645961f97f563a6c480cdf0286310/aiohttp-3.12.14-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f0a2cf66e32a2563bb0766eb24eae7e9a269ac0dc48db0aae90b575dc9583026", size = 1786958, upload-time = "2025-07-10T13:04:32.482Z" }, + { url = "https://files.pythonhosted.org/packages/30/a8/81e237f89a32029f9b4a805af6dffc378f8459c7b9942712c809ff9e76e5/aiohttp-3.12.14-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdea089caf6d5cde975084a884c72d901e36ef9c2fd972c9f51efbbc64e96fbd", size = 1709287, upload-time = "2025-07-10T13:04:34.493Z" }, + { url = "https://files.pythonhosted.org/packages/8c/e3/bd67a11b0fe7fc12c6030473afd9e44223d456f500f7cf526dbaa259ae46/aiohttp-3.12.14-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8a7865f27db67d49e81d463da64a59365ebd6b826e0e4847aa111056dcb9dc88", size = 1622990, upload-time = "2025-07-10T13:04:36.433Z" }, + { url = "https://files.pythonhosted.org/packages/83/ba/e0cc8e0f0d9ce0904e3cf2d6fa41904e379e718a013c721b781d53dcbcca/aiohttp-3.12.14-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0ab5b38a6a39781d77713ad930cb5e7feea6f253de656a5f9f281a8f5931b086", size = 1676015, upload-time = "2025-07-10T13:04:38.958Z" }, + { url = "https://files.pythonhosted.org/packages/d8/b3/1e6c960520bda094c48b56de29a3d978254637ace7168dd97ddc273d0d6c/aiohttp-3.12.14-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:9b3b15acee5c17e8848d90a4ebc27853f37077ba6aec4d8cb4dbbea56d156933", size = 1707678, upload-time = "2025-07-10T13:04:41.275Z" }, + { url = "https://files.pythonhosted.org/packages/0a/19/929a3eb8c35b7f9f076a462eaa9830b32c7f27d3395397665caa5e975614/aiohttp-3.12.14-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:e4c972b0bdaac167c1e53e16a16101b17c6d0ed7eac178e653a07b9f7fad7151", size = 1650274, upload-time = "2025-07-10T13:04:43.483Z" }, + { url = "https://files.pythonhosted.org/packages/22/e5/81682a6f20dd1b18ce3d747de8eba11cbef9b270f567426ff7880b096b48/aiohttp-3.12.14-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7442488b0039257a3bdbc55f7209587911f143fca11df9869578db6c26feeeb8", size = 1726408, upload-time = "2025-07-10T13:04:45.577Z" }, + { url = "https://files.pythonhosted.org/packages/8c/17/884938dffaa4048302985483f77dfce5ac18339aad9b04ad4aaa5e32b028/aiohttp-3.12.14-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:f68d3067eecb64c5e9bab4a26aa11bd676f4c70eea9ef6536b0a4e490639add3", size = 1759879, upload-time = "2025-07-10T13:04:47.663Z" }, + { url = "https://files.pythonhosted.org/packages/95/78/53b081980f50b5cf874359bde707a6eacd6c4be3f5f5c93937e48c9d0025/aiohttp-3.12.14-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f88d3704c8b3d598a08ad17d06006cb1ca52a1182291f04979e305c8be6c9758", size = 1708770, upload-time = "2025-07-10T13:04:49.944Z" }, + { url = "https://files.pythonhosted.org/packages/ed/91/228eeddb008ecbe3ffa6c77b440597fdf640307162f0c6488e72c5a2d112/aiohttp-3.12.14-cp313-cp313-win32.whl", hash = "sha256:a3c99ab19c7bf375c4ae3debd91ca5d394b98b6089a03231d4c580ef3c2ae4c5", size = 421688, upload-time = "2025-07-10T13:04:51.993Z" }, + { url = "https://files.pythonhosted.org/packages/66/5f/8427618903343402fdafe2850738f735fd1d9409d2a8f9bcaae5e630d3ba/aiohttp-3.12.14-cp313-cp313-win_amd64.whl", hash = "sha256:3f8aad695e12edc9d571f878c62bedc91adf30c760c8632f09663e5f564f4baa", size = 448098, upload-time = "2025-07-10T13:04:53.999Z" }, ] [[package]] name = "aiosignal" -version = "1.3.2" +version = "1.4.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "frozenlist" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ba/b5/6d55e80f6d8a08ce22b982eafa278d823b541c925f11ee774b0b9c43473d/aiosignal-1.3.2.tar.gz", hash = "sha256:a8c255c66fafb1e499c9351d0bf32ff2d8a0321595ebac3b93713656d2436f54", size = 19424, upload-time = "2024-12-13T17:10:40.86Z" } +sdist = { url = "https://files.pythonhosted.org/packages/61/62/06741b579156360248d1ec624842ad0edf697050bbaf7c3e46394e106ad1/aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7", size = 25007, upload-time = "2025-07-03T22:54:43.528Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/6a/bc7e17a3e87a2985d3e8f4da4cd0f481060eb78fb08596c42be62c90a4d9/aiosignal-1.3.2-py2.py3-none-any.whl", hash = "sha256:45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5", size = 7597, upload-time = "2024-12-13T17:10:38.469Z" }, + { url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490, upload-time = "2025-07-03T22:54:42.156Z" }, ] [[package]] @@ -135,30 +138,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f9/49/6abb616eb3cbab6a7cca303dc02fdf3836de2e0b834bf966a7f5271a34d8/beautifulsoup4-4.13.3-py3-none-any.whl", hash = "sha256:99045d7d3f08f91f0d656bc9b7efbae189426cd913d830294a15eefa0ea4df16", size = 186015, upload-time = "2025-02-04T20:05:03.729Z" }, ] -[[package]] -name = "black" -version = "25.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "mypy-extensions" }, - { name = "packaging" }, - { name = "pathspec" }, - { name = "platformdirs" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/94/49/26a7b0f3f35da4b5a65f081943b7bcd22d7002f5f0fb8098ec1ff21cb6ef/black-25.1.0.tar.gz", hash = "sha256:33496d5cd1222ad73391352b4ae8da15253c5de89b93a80b3e2c8d9a19ec2666", size = 649449, upload-time = "2025-01-29T04:15:40.373Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/83/71/3fe4741df7adf015ad8dfa082dd36c94ca86bb21f25608eb247b4afb15b2/black-25.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4b60580e829091e6f9238c848ea6750efed72140b91b048770b64e74fe04908b", size = 1650988, upload-time = "2025-01-29T05:37:16.707Z" }, - { url = "https://files.pythonhosted.org/packages/13/f3/89aac8a83d73937ccd39bbe8fc6ac8860c11cfa0af5b1c96d081facac844/black-25.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1e2978f6df243b155ef5fa7e558a43037c3079093ed5d10fd84c43900f2d8ecc", size = 1453985, upload-time = "2025-01-29T05:37:18.273Z" }, - { url = "https://files.pythonhosted.org/packages/6f/22/b99efca33f1f3a1d2552c714b1e1b5ae92efac6c43e790ad539a163d1754/black-25.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3b48735872ec535027d979e8dcb20bf4f70b5ac75a8ea99f127c106a7d7aba9f", size = 1783816, upload-time = "2025-01-29T04:18:33.823Z" }, - { url = "https://files.pythonhosted.org/packages/18/7e/a27c3ad3822b6f2e0e00d63d58ff6299a99a5b3aee69fa77cd4b0076b261/black-25.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:ea0213189960bda9cf99be5b8c8ce66bb054af5e9e861249cd23471bd7b0b3ba", size = 1440860, upload-time = "2025-01-29T04:19:12.944Z" }, - { url = "https://files.pythonhosted.org/packages/98/87/0edf98916640efa5d0696e1abb0a8357b52e69e82322628f25bf14d263d1/black-25.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8f0b18a02996a836cc9c9c78e5babec10930862827b1b724ddfe98ccf2f2fe4f", size = 1650673, upload-time = "2025-01-29T05:37:20.574Z" }, - { url = "https://files.pythonhosted.org/packages/52/e5/f7bf17207cf87fa6e9b676576749c6b6ed0d70f179a3d812c997870291c3/black-25.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:afebb7098bfbc70037a053b91ae8437c3857482d3a690fefc03e9ff7aa9a5fd3", size = 1453190, upload-time = "2025-01-29T05:37:22.106Z" }, - { url = "https://files.pythonhosted.org/packages/e3/ee/adda3d46d4a9120772fae6de454c8495603c37c4c3b9c60f25b1ab6401fe/black-25.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:030b9759066a4ee5e5aca28c3c77f9c64789cdd4de8ac1df642c40b708be6171", size = 1782926, upload-time = "2025-01-29T04:18:58.564Z" }, - { url = "https://files.pythonhosted.org/packages/cc/64/94eb5f45dcb997d2082f097a3944cfc7fe87e071907f677e80788a2d7b7a/black-25.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:a22f402b410566e2d1c950708c77ebf5ebd5d0d88a6a2e87c86d9fb48afa0d18", size = 1442613, upload-time = "2025-01-29T04:19:27.63Z" }, - { url = "https://files.pythonhosted.org/packages/09/71/54e999902aed72baf26bca0d50781b01838251a462612966e9fc4891eadd/black-25.1.0-py3-none-any.whl", hash = "sha256:95e8176dae143ba9097f351d174fdaf0ccd29efb414b362ae3fd72bf0f710717", size = 207646, upload-time = "2025-01-29T04:15:38.082Z" }, -] - [[package]] name = "blockbuster" version = "1.5.24" @@ -382,6 +361,7 @@ dependencies = [ { name = "langchain-experimental" }, { name = "langchain-mcp-adapters" }, { name = "langchain-openai" }, + { name = "langchain-tavily" }, { name = "langgraph" }, { name = "langgraph-checkpoint-mongodb" }, { name = "langgraph-checkpoint-postgres" }, @@ -401,7 +381,6 @@ dependencies = [ [package.optional-dependencies] dev = [ - { name = "black" }, { name = "langgraph-cli", extra = ["inmem"] }, { name = "ruff" }, ] @@ -414,7 +393,6 @@ test = [ [package.metadata] requires-dist = [ { name = "arxiv", specifier = ">=2.2.0" }, - { name = "black", marker = "extra == 'dev'", specifier = ">=24.2.0" }, { name = "duckduckgo-search", specifier = ">=8.0.0" }, { name = "fastapi", specifier = ">=0.110.0" }, { name = "httpx", specifier = ">=0.28.1" }, @@ -426,6 +404,7 @@ requires-dist = [ { name = "langchain-experimental", specifier = ">=0.3.4" }, { name = "langchain-mcp-adapters", specifier = ">=0.0.9" }, { name = "langchain-openai", specifier = ">=0.3.8" }, + { name = "langchain-tavily", specifier = "<0.3" }, { name = "langgraph", specifier = ">=0.3.5" }, { name = "langgraph-checkpoint-mongodb", specifier = ">=0.1.4" }, { name = "langgraph-checkpoint-postgres", specifier = "==2.0.21" }, @@ -990,6 +969,21 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ec/dd/effc847fd55b808d04f7e453d1e4bd3dc813708113ee283055e77be6d651/langchain_openai-0.3.22-py3-none-any.whl", hash = "sha256:945d3b18f2293504d0b81971a9017fc1294571cce4204c18aba3cfbfc43d24c6", size = 65295, upload-time = "2025-06-10T19:56:00.609Z" }, ] +[[package]] +name = "langchain-tavily" +version = "0.2.11" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohttp" }, + { name = "langchain" }, + { name = "langchain-core" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/17/bb/63ce4058684dddf525af3c8e5dcfab15c5f17515d20241ef6e726ac9e8b7/langchain_tavily-0.2.11.tar.gz", hash = "sha256:ab4f5d0f7fcb276a3905aef2e38c21a334b6cbfc86b405a3238fdc9c6eae1290", size = 22382, upload-time = "2025-07-25T17:26:33.41Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a8/5a/9326f125b4d3055a96200a5035016efe1aac46149cdafc7182e56710fcfe/langchain_tavily-0.2.11-py3-none-any.whl", hash = "sha256:358317c18fbb26500bca665301450e38945f1f4f6a6f4e06406c7674a76c8d5c", size = 26187, upload-time = "2025-07-25T17:26:32.324Z" }, +] + [[package]] name = "langchain-text-splitters" version = "0.3.6" @@ -1557,15 +1551,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ab/5f/b38085618b950b79d2d9164a711c52b10aefc0ae6833b96f626b7021b2ed/pandas-2.2.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:ad5b65698ab28ed8d7f18790a0dc58005c7629f227be9ecc1072aa74c0c1d43a", size = 13098436, upload-time = "2024-09-20T13:09:48.112Z" }, ] -[[package]] -name = "pathspec" -version = "0.12.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043, upload-time = "2023-12-10T22:30:45Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191, upload-time = "2023-12-10T22:30:43.14Z" }, -] - [[package]] name = "peewee" version = "3.17.9"