mirror of https://github.com/microsoft/autogen.git
Add Human Input Mode in AGS (#4210)
* add react-flow * update tutorial, some ui improvement for agent thread layout * v1 for interactive viz for agent state * add Ui visualization of message based transitions * minor updates * fix node edges, support visualization of self loops * improve edges and layout, add support for selector group chat prompt * minor ui tweaks * ui and layout updates * ugrade dependencies to fix dependabot scan errors * persist sidebar, enable contentbar title mechanism #4191 * add support for user proxy agent, support human in put mode. #4011 * add UI support for human input mode via a userproxy agent #4011 * version update * fix db initialization bug * support for human input mode in UI, fix backend api route minor bugs * update pyproject toml and uv lock * readme update, support full screen mode for agent visualiation * update uv.lock
This commit is contained in:
parent
d55e68fc29
commit
2997c27d1b
|
@ -3,11 +3,11 @@
|
||||||
[](https://badge.fury.io/py/autogenstudio)
|
[](https://badge.fury.io/py/autogenstudio)
|
||||||
[](https://pepy.tech/project/autogenstudio)
|
[](https://pepy.tech/project/autogenstudio)
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
AutoGen Studio is an AutoGen-powered AI app (user interface) to help you rapidly prototype AI agents, enhance them with skills, compose them into workflows and interact with them to accomplish tasks. It is built on top of the [AutoGen](https://microsoft.github.io/autogen) framework, which is a toolkit for building AI agents.
|
AutoGen Studio is an AutoGen-powered AI app (user interface) to help you rapidly prototype AI agents, enhance them with skills, compose them into workflows and interact with them to accomplish tasks. It is built on top of the [AutoGen](https://microsoft.github.io/autogen) framework, which is a toolkit for building AI agents.
|
||||||
|
|
||||||
Code for AutoGen Studio is on GitHub at [microsoft/autogen](https://github.com/microsoft/autogen/tree/main/samples/apps/autogen-studio)
|
Code for AutoGen Studio is on GitHub at [microsoft/autogen](https://github.com/microsoft/autogen/tree/main/python/packages/autogen-studio)
|
||||||
|
|
||||||
> **Note**: AutoGen Studio is meant to help you rapidly prototype multi-agent workflows and demonstrate an example of end user interfaces built with AutoGen. It is not meant to be a production-ready app.
|
> **Note**: AutoGen Studio is meant to help you rapidly prototype multi-agent workflows and demonstrate an example of end user interfaces built with AutoGen. It is not meant to be a production-ready app.
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ Code for AutoGen Studio is on GitHub at [microsoft/autogen](https://github.com/m
|
||||||
|
|
||||||
**Updates**
|
**Updates**
|
||||||
|
|
||||||
|
> Nov 14: AutoGen Studio is being rewritten to use the updated AutoGen 0.4.0 api AgentChat api.
|
||||||
> April 17: AutoGen Studio database layer is now rewritten to use [SQLModel](https://sqlmodel.tiangolo.com/) (Pydantic + SQLAlchemy). This provides entity linking (skills, models, agents and workflows are linked via association tables) and supports multiple [database backend dialects](https://docs.sqlalchemy.org/en/20/dialects/) supported in SQLAlchemy (SQLite, PostgreSQL, MySQL, Oracle, Microsoft SQL Server). The backend database can be specified a `--database-uri` argument when running the application. For example, `autogenstudio ui --database-uri sqlite:///database.sqlite` for SQLite and `autogenstudio ui --database-uri postgresql+psycopg://user:password@localhost/dbname` for PostgreSQL.
|
> April 17: AutoGen Studio database layer is now rewritten to use [SQLModel](https://sqlmodel.tiangolo.com/) (Pydantic + SQLAlchemy). This provides entity linking (skills, models, agents and workflows are linked via association tables) and supports multiple [database backend dialects](https://docs.sqlalchemy.org/en/20/dialects/) supported in SQLAlchemy (SQLite, PostgreSQL, MySQL, Oracle, Microsoft SQL Server). The backend database can be specified a `--database-uri` argument when running the application. For example, `autogenstudio ui --database-uri sqlite:///database.sqlite` for SQLite and `autogenstudio ui --database-uri postgresql+psycopg://user:password@localhost/dbname` for PostgreSQL.
|
||||||
|
|
||||||
> March 12: Default directory for AutoGen Studio is now /home/<user>/.autogenstudio. You can also specify this directory using the `--appdir` argument when running the application. For example, `autogenstudio ui --appdir /path/to/folder`. This will store the database and other files in the specified directory e.g. `/path/to/folder/database.sqlite`. `.env` files in that directory will be used to set environment variables for the app.
|
> March 12: Default directory for AutoGen Studio is now /home/<user>/.autogenstudio. You can also specify this directory using the `--appdir` argument when running the application. For example, `autogenstudio ui --appdir /path/to/folder`. This will store the database and other files in the specified directory e.g. `/path/to/folder/database.sqlite`. `.env` files in that directory will be used to set environment variables for the app.
|
||||||
|
@ -49,7 +50,7 @@ There are two ways to install AutoGen Studio - from PyPi or from source. We **re
|
||||||
pip install -e .
|
pip install -e .
|
||||||
```
|
```
|
||||||
|
|
||||||
- Navigate to the `samples/apps/autogen-studio/frontend` directory, install dependencies, and build the UI:
|
- Navigate to the `python/packages/autogen-studio/frontend` directory, install dependencies, and build the UI:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm install -g gatsby-cli
|
npm install -g gatsby-cli
|
||||||
|
@ -88,16 +89,23 @@ AutoGen Studio also takes several parameters to customize the application:
|
||||||
Now that you have AutoGen Studio installed and running, you are ready to explore its capabilities, including defining and modifying agent workflows, interacting with agents and sessions, and expanding agent skills.
|
Now that you have AutoGen Studio installed and running, you are ready to explore its capabilities, including defining and modifying agent workflows, interacting with agents and sessions, and expanding agent skills.
|
||||||
|
|
||||||
#### If running from source
|
#### If running from source
|
||||||
|
|
||||||
When running from source, you need to separately bring up the frontend server.
|
When running from source, you need to separately bring up the frontend server.
|
||||||
|
|
||||||
1. Open a separate terminal and change directory to the frontend
|
1. Open a separate terminal and change directory to the frontend
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd frontend
|
cd frontend
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Create a `.env.development` file.
|
3. Create a `.env.development` file.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cp .env.default .env.development
|
cp .env.default .env.development
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Launch frontend server
|
3. Launch frontend server
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run start
|
npm run start
|
||||||
```
|
```
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
from .agents.userproxy import UserProxyAgent
|
|
@ -0,0 +1,47 @@
|
||||||
|
from typing import Callable, List, Optional, Sequence, Union, Awaitable
|
||||||
|
from inspect import iscoroutinefunction
|
||||||
|
|
||||||
|
from autogen_agentchat.agents import BaseChatAgent
|
||||||
|
from autogen_agentchat.base import Response
|
||||||
|
from autogen_agentchat.messages import ChatMessage, TextMessage
|
||||||
|
from autogen_core.base import CancellationToken
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
|
||||||
|
class UserProxyAgent(BaseChatAgent):
|
||||||
|
"""An agent that can represent a human user in a chat."""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
name: str,
|
||||||
|
description: Optional[str] = "a",
|
||||||
|
input_func: Optional[Union[Callable[..., str],
|
||||||
|
Callable[..., Awaitable[str]]]] = None
|
||||||
|
) -> None:
|
||||||
|
super().__init__(name, description=description)
|
||||||
|
self.input_func = input_func or input
|
||||||
|
self._is_async = iscoroutinefunction(
|
||||||
|
input_func) if input_func else False
|
||||||
|
|
||||||
|
@property
|
||||||
|
def produced_message_types(self) -> List[type[ChatMessage]]:
|
||||||
|
return [TextMessage]
|
||||||
|
|
||||||
|
async def _get_input(self, prompt: str) -> str:
|
||||||
|
"""Handle both sync and async input functions"""
|
||||||
|
if self._is_async:
|
||||||
|
return await self.input_func(prompt)
|
||||||
|
else:
|
||||||
|
return await asyncio.get_event_loop().run_in_executor(None, self.input_func, prompt)
|
||||||
|
|
||||||
|
async def on_messages(self, messages: Sequence[ChatMessage], cancellation_token: CancellationToken) -> Response:
|
||||||
|
|
||||||
|
try:
|
||||||
|
user_input = await self._get_input("Enter your response: ")
|
||||||
|
return Response(chat_message=TextMessage(content=user_input, source=self.name))
|
||||||
|
except Exception as e:
|
||||||
|
# Consider logging the error here
|
||||||
|
raise RuntimeError(f"Failed to get user input: {str(e)}") from e
|
||||||
|
|
||||||
|
async def on_reset(self, cancellation_token: CancellationToken) -> None:
|
||||||
|
pass
|
|
@ -1,3 +1,3 @@
|
||||||
from .db_manager import DatabaseManager
|
from .db_manager import DatabaseManager
|
||||||
from .component_factory import ComponentFactory
|
from .component_factory import ComponentFactory, Component
|
||||||
from .config_manager import ConfigurationManager
|
from .config_manager import ConfigurationManager
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import List, Literal, Union, Optional, Dict, Any, Type
|
from typing import Callable, List, Literal, Union, Optional, Dict, Any, Type
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import json
|
import json
|
||||||
from autogen_agentchat.task import MaxMessageTermination, TextMentionTermination, StopMessageTermination
|
from autogen_agentchat.task import MaxMessageTermination, TextMentionTermination, StopMessageTermination
|
||||||
|
@ -13,6 +13,7 @@ from ..datamodel import (
|
||||||
TeamTypes, AgentTypes, ModelTypes, ToolTypes,
|
TeamTypes, AgentTypes, ModelTypes, ToolTypes,
|
||||||
ComponentType, ComponentConfig, ComponentConfigInput, TerminationConfig, TerminationTypes, Response
|
ComponentType, ComponentConfig, ComponentConfigInput, TerminationConfig, TerminationTypes, Response
|
||||||
)
|
)
|
||||||
|
from ..components import UserProxyAgent
|
||||||
from autogen_agentchat.agents import AssistantAgent
|
from autogen_agentchat.agents import AssistantAgent
|
||||||
from autogen_agentchat.teams import RoundRobinGroupChat, SelectorGroupChat
|
from autogen_agentchat.teams import RoundRobinGroupChat, SelectorGroupChat
|
||||||
from autogen_ext.models import OpenAIChatCompletionClient
|
from autogen_ext.models import OpenAIChatCompletionClient
|
||||||
|
@ -38,6 +39,17 @@ ReturnType = Literal['object', 'dict', 'config']
|
||||||
Component = Union[RoundRobinGroupChat, SelectorGroupChat,
|
Component = Union[RoundRobinGroupChat, SelectorGroupChat,
|
||||||
AssistantAgent, OpenAIChatCompletionClient, FunctionTool]
|
AssistantAgent, OpenAIChatCompletionClient, FunctionTool]
|
||||||
|
|
||||||
|
DEFAULT_SELECTOR_PROMPT = """You are in a role play game. The following roles are available:
|
||||||
|
{roles}.
|
||||||
|
Read the following conversation. Then select the next role from {participants} to play. Only return the role.
|
||||||
|
|
||||||
|
{history}
|
||||||
|
|
||||||
|
Read the above conversation. Then select the next role from {participants} to play. Only return the role.
|
||||||
|
"""
|
||||||
|
|
||||||
|
CONFIG_RETURN_TYPES = Literal['object', 'dict', 'config']
|
||||||
|
|
||||||
|
|
||||||
class ComponentFactory:
|
class ComponentFactory:
|
||||||
"""Creates and manages agent components with versioned configuration loading"""
|
"""Creates and manages agent components with versioned configuration loading"""
|
||||||
|
@ -55,19 +67,22 @@ class ComponentFactory:
|
||||||
self._tool_cache: Dict[str, FunctionTool] = {}
|
self._tool_cache: Dict[str, FunctionTool] = {}
|
||||||
self._last_cache_clear = datetime.now()
|
self._last_cache_clear = datetime.now()
|
||||||
|
|
||||||
async def load(self, component: ComponentConfigInput, return_type: ReturnType = 'object') -> Union[Component, dict, ComponentConfig]:
|
async def load(
|
||||||
|
self,
|
||||||
|
component: ComponentConfigInput,
|
||||||
|
input_func: Optional[Callable] = None,
|
||||||
|
return_type: ReturnType = 'object'
|
||||||
|
) -> Union[Component, dict, ComponentConfig]:
|
||||||
"""
|
"""
|
||||||
Universal loader for any component type
|
Universal loader for any component type
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
component: Component configuration (file path, dict, or ComponentConfig)
|
component: Component configuration (file path, dict, or ComponentConfig)
|
||||||
|
input_func: Optional callable for user input handling
|
||||||
return_type: Type of return value ('object', 'dict', or 'config')
|
return_type: Type of return value ('object', 'dict', or 'config')
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Component instance, config dict, or ComponentConfig based on return_type
|
Component instance, config dict, or ComponentConfig based on return_type
|
||||||
|
|
||||||
Raises:
|
|
||||||
ValueError: If component type is unknown or version unsupported
|
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
# Load and validate config
|
# Load and validate config
|
||||||
|
@ -95,8 +110,8 @@ class ComponentFactory:
|
||||||
|
|
||||||
# Otherwise create and return component instance
|
# Otherwise create and return component instance
|
||||||
handlers = {
|
handlers = {
|
||||||
ComponentType.TEAM: self.load_team,
|
ComponentType.TEAM: lambda c: self.load_team(c, input_func),
|
||||||
ComponentType.AGENT: self.load_agent,
|
ComponentType.AGENT: lambda c: self.load_agent(c, input_func),
|
||||||
ComponentType.MODEL: self.load_model,
|
ComponentType.MODEL: self.load_model,
|
||||||
ComponentType.TOOL: self.load_tool,
|
ComponentType.TOOL: self.load_tool,
|
||||||
ComponentType.TERMINATION: self.load_termination
|
ComponentType.TERMINATION: self.load_termination
|
||||||
|
@ -113,7 +128,7 @@ class ComponentFactory:
|
||||||
logger.error(f"Failed to load component: {str(e)}")
|
logger.error(f"Failed to load component: {str(e)}")
|
||||||
raise
|
raise
|
||||||
|
|
||||||
async def load_directory(self, directory: Union[str, Path], check_exists: bool = False, return_type: ReturnType = 'object') -> List[Union[Component, dict, ComponentConfig]]:
|
async def load_directory(self, directory: Union[str, Path], return_type: ReturnType = 'object') -> List[Union[Component, dict, ComponentConfig]]:
|
||||||
"""
|
"""
|
||||||
Import all component configurations from a directory.
|
Import all component configurations from a directory.
|
||||||
"""
|
"""
|
||||||
|
@ -124,7 +139,7 @@ class ComponentFactory:
|
||||||
for path in list(directory.glob("*")):
|
for path in list(directory.glob("*")):
|
||||||
if path.suffix.lower().endswith(('.json', '.yaml', '.yml')):
|
if path.suffix.lower().endswith(('.json', '.yaml', '.yml')):
|
||||||
try:
|
try:
|
||||||
component = await self.load(path, return_type)
|
component = await self.load(path, return_type=return_type)
|
||||||
components.append(component)
|
components.append(component)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.info(
|
logger.info(
|
||||||
|
@ -176,22 +191,17 @@ class ComponentFactory:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
f"Termination condition creation failed: {str(e)}")
|
f"Termination condition creation failed: {str(e)}")
|
||||||
|
|
||||||
async def load_team(self, config: TeamConfig) -> TeamComponent:
|
async def load_team(
|
||||||
|
self,
|
||||||
|
config: TeamConfig,
|
||||||
|
input_func: Optional[Callable] = None
|
||||||
|
) -> TeamComponent:
|
||||||
"""Create team instance from configuration."""
|
"""Create team instance from configuration."""
|
||||||
|
|
||||||
default_selector_prompt = """You are in a role play game. The following roles are available:
|
|
||||||
{roles}.
|
|
||||||
Read the following conversation. Then select the next role from {participants} to play. Only return the role.
|
|
||||||
|
|
||||||
{history}
|
|
||||||
|
|
||||||
Read the above conversation. Then select the next role from {participants} to play. Only return the role.
|
|
||||||
"""
|
|
||||||
try:
|
try:
|
||||||
# Load participants (agents)
|
# Load participants (agents) with input_func
|
||||||
participants = []
|
participants = []
|
||||||
for participant in config.participants:
|
for participant in config.participants:
|
||||||
agent = await self.load(participant)
|
agent = await self.load(participant, input_func=input_func)
|
||||||
participants.append(agent)
|
participants.append(agent)
|
||||||
|
|
||||||
# Load model client if specified
|
# Load model client if specified
|
||||||
|
@ -202,7 +212,6 @@ Read the above conversation. Then select the next role from {participants} to pl
|
||||||
# Load termination condition if specified
|
# Load termination condition if specified
|
||||||
termination = None
|
termination = None
|
||||||
if config.termination_condition:
|
if config.termination_condition:
|
||||||
# Now we can use the universal load() method since termination is a proper component
|
|
||||||
termination = await self.load(config.termination_condition)
|
termination = await self.load(config.termination_condition)
|
||||||
|
|
||||||
# Create team based on type
|
# Create team based on type
|
||||||
|
@ -215,7 +224,7 @@ Read the above conversation. Then select the next role from {participants} to pl
|
||||||
if not model_client:
|
if not model_client:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"SelectorGroupChat requires a model_client")
|
"SelectorGroupChat requires a model_client")
|
||||||
selector_prompt = config.selector_prompt if config.selector_prompt else default_selector_prompt
|
selector_prompt = config.selector_prompt if config.selector_prompt else DEFAULT_SELECTOR_PROMPT
|
||||||
return SelectorGroupChat(
|
return SelectorGroupChat(
|
||||||
participants=participants,
|
participants=participants,
|
||||||
model_client=model_client,
|
model_client=model_client,
|
||||||
|
@ -229,14 +238,20 @@ Read the above conversation. Then select the next role from {participants} to pl
|
||||||
logger.error(f"Failed to create team {config.name}: {str(e)}")
|
logger.error(f"Failed to create team {config.name}: {str(e)}")
|
||||||
raise ValueError(f"Team creation failed: {str(e)}")
|
raise ValueError(f"Team creation failed: {str(e)}")
|
||||||
|
|
||||||
async def load_agent(self, config: AgentConfig) -> AgentComponent:
|
async def load_agent(
|
||||||
|
self,
|
||||||
|
config: AgentConfig,
|
||||||
|
input_func: Optional[Callable] = None
|
||||||
|
) -> AgentComponent:
|
||||||
"""Create agent instance from configuration."""
|
"""Create agent instance from configuration."""
|
||||||
try:
|
try:
|
||||||
# Load model client if specified
|
# Load model client if specified
|
||||||
model_client = None
|
model_client = None
|
||||||
if config.model_client:
|
if config.model_client:
|
||||||
model_client = await self.load(config.model_client)
|
model_client = await self.load(config.model_client)
|
||||||
|
|
||||||
system_message = config.system_message if config.system_message else "You are a helpful assistant"
|
system_message = config.system_message if config.system_message else "You are a helpful assistant"
|
||||||
|
|
||||||
# Load tools if specified
|
# Load tools if specified
|
||||||
tools = []
|
tools = []
|
||||||
if config.tools:
|
if config.tools:
|
||||||
|
@ -244,9 +259,16 @@ Read the above conversation. Then select the next role from {participants} to pl
|
||||||
tool = await self.load(tool_config)
|
tool = await self.load(tool_config)
|
||||||
tools.append(tool)
|
tools.append(tool)
|
||||||
|
|
||||||
if config.agent_type == AgentTypes.ASSISTANT:
|
if config.agent_type == AgentTypes.USERPROXY:
|
||||||
|
return UserProxyAgent(
|
||||||
|
name=config.name,
|
||||||
|
description=config.description or "A human user",
|
||||||
|
input_func=input_func # Pass through to UserProxyAgent
|
||||||
|
)
|
||||||
|
elif config.agent_type == AgentTypes.ASSISTANT:
|
||||||
return AssistantAgent(
|
return AssistantAgent(
|
||||||
name=config.name,
|
name=config.name,
|
||||||
|
description=config.description or "A helpful assistant",
|
||||||
model_client=model_client,
|
model_client=model_client,
|
||||||
tools=tools,
|
tools=tools,
|
||||||
system_message=system_message
|
system_message=system_message
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
from pathlib import Path
|
||||||
import threading
|
import threading
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
@ -19,15 +20,34 @@ class DatabaseManager:
|
||||||
|
|
||||||
_init_lock = threading.Lock()
|
_init_lock = threading.Lock()
|
||||||
|
|
||||||
def __init__(self, engine_uri: str, auto_upgrade: bool = True):
|
def __init__(
|
||||||
|
self,
|
||||||
|
engine_uri: str,
|
||||||
|
base_dir: Optional[Path | str] = None,
|
||||||
|
auto_upgrade: bool = True
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Initialize DatabaseManager with optional custom base directory.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
engine_uri: Database connection URI
|
||||||
|
base_dir: Custom base directory for Alembic files. If None, uses current working directory
|
||||||
|
auto_upgrade: Whether to automatically upgrade schema when differences found
|
||||||
|
"""
|
||||||
|
# Convert string path to Path object if necessary
|
||||||
|
if isinstance(base_dir, str):
|
||||||
|
base_dir = Path(base_dir)
|
||||||
|
|
||||||
connection_args = {
|
connection_args = {
|
||||||
"check_same_thread": True} if "sqlite" in engine_uri else {}
|
"check_same_thread": True
|
||||||
|
} if "sqlite" in engine_uri else {}
|
||||||
|
|
||||||
self.engine = create_engine(engine_uri, connect_args=connection_args)
|
self.engine = create_engine(engine_uri, connect_args=connection_args)
|
||||||
self.schema_manager = SchemaManager(
|
self.schema_manager = SchemaManager(
|
||||||
engine=self.engine,
|
engine=self.engine,
|
||||||
|
base_dir=base_dir,
|
||||||
auto_upgrade=auto_upgrade,
|
auto_upgrade=auto_upgrade,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Check and upgrade on startup
|
# Check and upgrade on startup
|
||||||
upgraded, status = self.schema_manager.check_and_upgrade()
|
upgraded, status = self.schema_manager.check_and_upgrade()
|
||||||
if upgraded:
|
if upgraded:
|
||||||
|
|
|
@ -10,6 +10,7 @@ from alembic.script import ScriptDirectory
|
||||||
from alembic.autogenerate import compare_metadata
|
from alembic.autogenerate import compare_metadata
|
||||||
from sqlalchemy import Engine
|
from sqlalchemy import Engine
|
||||||
from sqlmodel import SQLModel
|
from sqlmodel import SQLModel
|
||||||
|
from alembic.util.exc import CommandError
|
||||||
|
|
||||||
|
|
||||||
class SchemaManager:
|
class SchemaManager:
|
||||||
|
@ -29,6 +30,7 @@ class SchemaManager:
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
engine: Engine,
|
engine: Engine,
|
||||||
|
base_dir: Optional[Path] = None,
|
||||||
auto_upgrade: bool = True,
|
auto_upgrade: bool = True,
|
||||||
init_mode: str = "auto"
|
init_mode: str = "auto"
|
||||||
):
|
):
|
||||||
|
@ -38,16 +40,45 @@ class SchemaManager:
|
||||||
self.engine = engine
|
self.engine = engine
|
||||||
self.auto_upgrade = auto_upgrade
|
self.auto_upgrade = auto_upgrade
|
||||||
|
|
||||||
# Set up paths relative to this file
|
# Use provided base_dir or default to class file location
|
||||||
self.base_dir = Path(__file__).parent
|
self.base_dir = base_dir or Path(__file__).parent
|
||||||
self.alembic_dir = self.base_dir / 'alembic'
|
self.alembic_dir = self.base_dir / 'alembic'
|
||||||
self.alembic_ini_path = self.base_dir / 'alembic.ini'
|
self.alembic_ini_path = self.base_dir / 'alembic.ini'
|
||||||
|
|
||||||
# Handle initialization based on mode
|
# Create base directory if it doesn't exist
|
||||||
if init_mode == "none":
|
self.base_dir.mkdir(parents=True, exist_ok=True)
|
||||||
self._validate_alembic_setup()
|
|
||||||
|
# Initialize based on mode
|
||||||
|
if init_mode == "force":
|
||||||
|
self._cleanup_existing_alembic()
|
||||||
|
self._initialize_alembic()
|
||||||
else:
|
else:
|
||||||
self._ensure_alembic_setup(force=init_mode == "force")
|
try:
|
||||||
|
self._validate_alembic_setup()
|
||||||
|
logger.info("Using existing Alembic configuration")
|
||||||
|
# Update existing configuration
|
||||||
|
self._update_configuration()
|
||||||
|
except FileNotFoundError:
|
||||||
|
if init_mode == "none":
|
||||||
|
raise
|
||||||
|
logger.info("Initializing new Alembic configuration")
|
||||||
|
self._initialize_alembic()
|
||||||
|
|
||||||
|
def _update_configuration(self) -> None:
|
||||||
|
"""Updates existing Alembic configuration with current settings."""
|
||||||
|
logger.info("Updating existing Alembic configuration...")
|
||||||
|
|
||||||
|
# Update alembic.ini
|
||||||
|
config_content = self._generate_alembic_ini_content()
|
||||||
|
with open(self.alembic_ini_path, 'w') as f:
|
||||||
|
f.write(config_content)
|
||||||
|
|
||||||
|
# Update env.py
|
||||||
|
env_path = self.alembic_dir / 'env.py'
|
||||||
|
if env_path.exists():
|
||||||
|
self._update_env_py(env_path)
|
||||||
|
else:
|
||||||
|
self._create_minimal_env_py(env_path)
|
||||||
|
|
||||||
def _cleanup_existing_alembic(self) -> None:
|
def _cleanup_existing_alembic(self) -> None:
|
||||||
"""
|
"""
|
||||||
|
@ -106,43 +137,34 @@ class SchemaManager:
|
||||||
self._initialize_alembic()
|
self._initialize_alembic()
|
||||||
logger.info("Alembic initialization complete")
|
logger.info("Alembic initialization complete")
|
||||||
|
|
||||||
def _initialize_alembic(self) -> str:
|
def _initialize_alembic(self) -> None:
|
||||||
"""Initializes Alembic configuration in the local directory."""
|
|
||||||
logger.info("Initializing Alembic configuration...")
|
logger.info("Initializing Alembic configuration...")
|
||||||
|
|
||||||
# Check if versions exists
|
# Create directories first
|
||||||
has_versions = (self.alembic_dir / 'versions').exists()
|
|
||||||
logger.info(f"Existing versions directory found: {has_versions}")
|
|
||||||
|
|
||||||
# Create base directories
|
|
||||||
self.alembic_dir.mkdir(exist_ok=True)
|
self.alembic_dir.mkdir(exist_ok=True)
|
||||||
if not has_versions:
|
versions_dir = self.alembic_dir / 'versions'
|
||||||
(self.alembic_dir / 'versions').mkdir(exist_ok=True)
|
versions_dir.mkdir(exist_ok=True)
|
||||||
|
|
||||||
# Write alembic.ini
|
# Create env.py BEFORE running command.init
|
||||||
ini_content = self._generate_alembic_ini_content()
|
|
||||||
with open(self.alembic_ini_path, 'w') as f:
|
|
||||||
f.write(ini_content)
|
|
||||||
logger.info("Created alembic.ini")
|
|
||||||
|
|
||||||
if not has_versions:
|
|
||||||
# Only run init if no versions directory
|
|
||||||
config = self.get_alembic_config()
|
|
||||||
command.init(config, str(self.alembic_dir))
|
|
||||||
logger.info("Initialized new Alembic directory structure")
|
|
||||||
else:
|
|
||||||
# Create minimal env.py if it doesn't exist
|
|
||||||
env_path = self.alembic_dir / 'env.py'
|
env_path = self.alembic_dir / 'env.py'
|
||||||
if not env_path.exists():
|
if not env_path.exists():
|
||||||
self._create_minimal_env_py(env_path)
|
self._create_minimal_env_py(env_path)
|
||||||
logger.info("Created minimal env.py")
|
logger.info("Created new env.py")
|
||||||
else:
|
|
||||||
# Update existing env.py
|
|
||||||
self._update_env_py(env_path)
|
|
||||||
logger.info("Updated existing env.py")
|
|
||||||
|
|
||||||
logger.info(f"Alembic setup completed at {self.base_dir}")
|
# Write alembic.ini
|
||||||
return str(self.alembic_ini_path)
|
config_content = self._generate_alembic_ini_content()
|
||||||
|
with open(self.alembic_ini_path, 'w') as f:
|
||||||
|
f.write(config_content)
|
||||||
|
logger.info("Created alembic.ini")
|
||||||
|
|
||||||
|
# Now run alembic init
|
||||||
|
try:
|
||||||
|
config = self.get_alembic_config()
|
||||||
|
command.init(config, str(self.alembic_dir))
|
||||||
|
logger.info("Initialized Alembic directory structure")
|
||||||
|
except CommandError as e:
|
||||||
|
if "already exists" not in str(e):
|
||||||
|
raise
|
||||||
|
|
||||||
def _create_minimal_env_py(self, env_path: Path) -> None:
|
def _create_minimal_env_py(self, env_path: Path) -> None:
|
||||||
"""Creates a minimal env.py file for Alembic."""
|
"""Creates a minimal env.py file for Alembic."""
|
||||||
|
@ -242,6 +264,9 @@ datefmt = %H:%M:%S
|
||||||
"""
|
"""
|
||||||
Updates the env.py file to use SQLModel metadata.
|
Updates the env.py file to use SQLModel metadata.
|
||||||
"""
|
"""
|
||||||
|
if not env_path.exists():
|
||||||
|
self._create_minimal_env_py(env_path)
|
||||||
|
return
|
||||||
try:
|
try:
|
||||||
with open(env_path, 'r') as f:
|
with open(env_path, 'r') as f:
|
||||||
content = f.read()
|
content = f.read()
|
||||||
|
@ -297,8 +322,17 @@ datefmt = %H:%M:%S
|
||||||
|
|
||||||
def _validate_alembic_setup(self) -> None:
|
def _validate_alembic_setup(self) -> None:
|
||||||
"""Validates that Alembic is properly configured."""
|
"""Validates that Alembic is properly configured."""
|
||||||
if not self.alembic_ini_path.exists():
|
required_files = [
|
||||||
raise FileNotFoundError("Alembic configuration not found")
|
self.alembic_ini_path,
|
||||||
|
self.alembic_dir / 'env.py',
|
||||||
|
self.alembic_dir / 'versions'
|
||||||
|
]
|
||||||
|
|
||||||
|
missing = [f for f in required_files if not f.exists()]
|
||||||
|
if missing:
|
||||||
|
raise FileNotFoundError(
|
||||||
|
f"Alembic configuration incomplete. Missing: {', '.join(str(f) for f in missing)}"
|
||||||
|
)
|
||||||
|
|
||||||
def get_alembic_config(self) -> Config:
|
def get_alembic_config(self) -> Config:
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -17,7 +17,7 @@ class ToolTypes(str, Enum):
|
||||||
|
|
||||||
class AgentTypes(str, Enum):
|
class AgentTypes(str, Enum):
|
||||||
ASSISTANT = "AssistantAgent"
|
ASSISTANT = "AssistantAgent"
|
||||||
CODING = "CodingAssistantAgent"
|
USERPROXY = "UserProxyAgent"
|
||||||
|
|
||||||
|
|
||||||
class TeamTypes(str, Enum):
|
class TeamTypes(str, Enum):
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from typing import AsyncGenerator, Union, Optional
|
from typing import AsyncGenerator, Callable, Union, Optional
|
||||||
import time
|
import time
|
||||||
from .database import ComponentFactory
|
from .database import ComponentFactory, Component
|
||||||
from .datamodel import TeamResult, TaskResult, ComponentConfigInput
|
from .datamodel import TeamResult, TaskResult, ComponentConfigInput
|
||||||
from autogen_agentchat.messages import InnerMessage, ChatMessage
|
from autogen_agentchat.messages import InnerMessage, ChatMessage
|
||||||
from autogen_core.base import CancellationToken
|
from autogen_core.base import CancellationToken
|
||||||
|
@ -10,19 +10,37 @@ class TeamManager:
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.component_factory = ComponentFactory()
|
self.component_factory = ComponentFactory()
|
||||||
|
|
||||||
|
async def _create_team(
|
||||||
|
self,
|
||||||
|
team_config: ComponentConfigInput,
|
||||||
|
input_func: Optional[Callable] = None
|
||||||
|
) -> Component:
|
||||||
|
"""Create team instance with common setup logic"""
|
||||||
|
return await self.component_factory.load(
|
||||||
|
team_config,
|
||||||
|
input_func=input_func
|
||||||
|
)
|
||||||
|
|
||||||
|
def _create_result(self, task_result: TaskResult, start_time: float) -> TeamResult:
|
||||||
|
"""Create TeamResult with timing info"""
|
||||||
|
return TeamResult(
|
||||||
|
task_result=task_result,
|
||||||
|
usage="",
|
||||||
|
duration=time.time() - start_time
|
||||||
|
)
|
||||||
|
|
||||||
async def run_stream(
|
async def run_stream(
|
||||||
self,
|
self,
|
||||||
task: str,
|
task: str,
|
||||||
team_config: ComponentConfigInput,
|
team_config: ComponentConfigInput,
|
||||||
|
input_func: Optional[Callable] = None,
|
||||||
cancellation_token: Optional[CancellationToken] = None
|
cancellation_token: Optional[CancellationToken] = None
|
||||||
) -> AsyncGenerator[Union[InnerMessage, ChatMessage, TaskResult], None]:
|
) -> AsyncGenerator[Union[InnerMessage, ChatMessage, TaskResult], None]:
|
||||||
"""Stream the team's execution results"""
|
"""Stream the team's execution results"""
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Let factory handle all config processing
|
team = await self._create_team(team_config, input_func)
|
||||||
team = await self.component_factory.load(team_config)
|
|
||||||
|
|
||||||
stream = team.run_stream(
|
stream = team.run_stream(
|
||||||
task=task,
|
task=task,
|
||||||
cancellation_token=cancellation_token
|
cancellation_token=cancellation_token
|
||||||
|
@ -33,11 +51,7 @@ class TeamManager:
|
||||||
break
|
break
|
||||||
|
|
||||||
if isinstance(message, TaskResult):
|
if isinstance(message, TaskResult):
|
||||||
yield TeamResult(
|
yield self._create_result(message, start_time)
|
||||||
task_result=message,
|
|
||||||
usage="",
|
|
||||||
duration=time.time() - start_time
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
yield message
|
yield message
|
||||||
|
|
||||||
|
@ -48,20 +62,16 @@ class TeamManager:
|
||||||
self,
|
self,
|
||||||
task: str,
|
task: str,
|
||||||
team_config: ComponentConfigInput,
|
team_config: ComponentConfigInput,
|
||||||
|
input_func: Optional[Callable] = None,
|
||||||
cancellation_token: Optional[CancellationToken] = None
|
cancellation_token: Optional[CancellationToken] = None
|
||||||
) -> TeamResult:
|
) -> TeamResult:
|
||||||
"""Original non-streaming run method with optional cancellation"""
|
"""Original non-streaming run method with optional cancellation"""
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
|
|
||||||
# Let factory handle all config processing
|
team = await self._create_team(team_config, input_func)
|
||||||
team = await self.component_factory.load(team_config)
|
|
||||||
result = await team.run(
|
result = await team.run(
|
||||||
task=task,
|
task=task,
|
||||||
cancellation_token=cancellation_token
|
cancellation_token=cancellation_token
|
||||||
)
|
)
|
||||||
|
|
||||||
return TeamResult(
|
return self._create_result(result, start_time)
|
||||||
task_result=result,
|
|
||||||
usage="",
|
|
||||||
duration=time.time() - start_time
|
|
||||||
)
|
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
VERSION = "0.1.6"
|
VERSION = "0.4.0.dev35"
|
||||||
__version__ = VERSION
|
__version__ = VERSION
|
||||||
APP_NAME = "autogenstudio"
|
APP_NAME = "autogenstudio"
|
||||||
|
|
|
@ -34,7 +34,7 @@ async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]:
|
||||||
logger.info("Initializing application...")
|
logger.info("Initializing application...")
|
||||||
try:
|
try:
|
||||||
# Initialize managers (DB, Connection, Team)
|
# Initialize managers (DB, Connection, Team)
|
||||||
await init_managers(initializer.database_uri, initializer.config_dir)
|
await init_managers(initializer.database_uri, initializer.config_dir, initializer.app_root)
|
||||||
logger.info("Managers initialized successfully")
|
logger.info("Managers initialized successfully")
|
||||||
|
|
||||||
# Any other initialization code
|
# Any other initialization code
|
||||||
|
|
|
@ -86,7 +86,7 @@ async def get_current_user(
|
||||||
# Manager initialization and cleanup
|
# Manager initialization and cleanup
|
||||||
|
|
||||||
|
|
||||||
async def init_managers(database_uri: str, config_dir: str) -> None:
|
async def init_managers(database_uri: str, config_dir: str, app_root: str) -> None:
|
||||||
"""Initialize all manager instances"""
|
"""Initialize all manager instances"""
|
||||||
global _db_manager, _websocket_manager, _team_manager
|
global _db_manager, _websocket_manager, _team_manager
|
||||||
|
|
||||||
|
@ -95,7 +95,7 @@ async def init_managers(database_uri: str, config_dir: str) -> None:
|
||||||
try:
|
try:
|
||||||
# Initialize database manager
|
# Initialize database manager
|
||||||
_db_manager = DatabaseManager(
|
_db_manager = DatabaseManager(
|
||||||
engine_uri=database_uri, auto_upgrade=settings.UPGRADE_DATABASE)
|
engine_uri=database_uri, auto_upgrade=settings.UPGRADE_DATABASE, base_dir=app_root)
|
||||||
_db_manager.create_db_and_tables()
|
_db_manager.create_db_and_tables()
|
||||||
|
|
||||||
# init default team config
|
# init default team config
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
from .connection import WebSocketManager
|
|
@ -1,12 +1,14 @@
|
||||||
|
import asyncio
|
||||||
from autogen_agentchat.base._task import TaskResult
|
from autogen_agentchat.base._task import TaskResult
|
||||||
from fastapi import WebSocket, WebSocketDisconnect
|
from fastapi import WebSocket, WebSocketDisconnect
|
||||||
from typing import Dict, Optional, Any
|
from typing import Callable, Dict, Optional, Any
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
import logging
|
import logging
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
|
|
||||||
from ...datamodel import Run, RunStatus, TeamResult
|
from ...datamodel import Run, RunStatus, TeamResult
|
||||||
from ...database import DatabaseManager
|
from ...database import DatabaseManager
|
||||||
|
from ...teammanager import TeamManager
|
||||||
from autogen_agentchat.messages import InnerMessage, ChatMessage, TextMessage
|
from autogen_agentchat.messages import InnerMessage, ChatMessage, TextMessage
|
||||||
from autogen_core.base import CancellationToken
|
from autogen_core.base import CancellationToken
|
||||||
|
|
||||||
|
@ -22,25 +24,22 @@ class WebSocketManager:
|
||||||
self._cancellation_tokens: Dict[UUID, CancellationToken] = {}
|
self._cancellation_tokens: Dict[UUID, CancellationToken] = {}
|
||||||
# Track explicitly closed connections
|
# Track explicitly closed connections
|
||||||
self._closed_connections: set[UUID] = set()
|
self._closed_connections: set[UUID] = set()
|
||||||
|
self._input_responses: Dict[UUID, asyncio.Queue] = {}
|
||||||
|
|
||||||
self._cancel_message = TeamResult(task_result=TaskResult(messages=[TextMessage(
|
self._cancel_message = TeamResult(task_result=TaskResult(messages=[TextMessage(
|
||||||
source="user", content="Run cancelled by user")], stop_reason="cancelled by user"), usage="", duration=0).model_dump()
|
source="user", content="Run cancelled by user")], stop_reason="cancelled by user"), usage="", duration=0).model_dump()
|
||||||
|
|
||||||
|
def _get_stop_message(self, reason: str) -> dict:
|
||||||
|
return TeamResult(task_result=TaskResult(messages=[TextMessage(
|
||||||
|
source="user", content=reason)], stop_reason=reason), usage="", duration=0).model_dump()
|
||||||
|
|
||||||
async def connect(self, websocket: WebSocket, run_id: UUID) -> bool:
|
async def connect(self, websocket: WebSocket, run_id: UUID) -> bool:
|
||||||
"""Initialize WebSocket connection for a run
|
|
||||||
|
|
||||||
Args:
|
|
||||||
websocket: The WebSocket connection to initialize
|
|
||||||
run_id: UUID of the run to associate with this connection
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
bool: True if connection was successful, False otherwise
|
|
||||||
"""
|
|
||||||
try:
|
try:
|
||||||
await websocket.accept()
|
await websocket.accept()
|
||||||
self._connections[run_id] = websocket
|
self._connections[run_id] = websocket
|
||||||
# Remove from closed set if reconnecting
|
|
||||||
self._closed_connections.discard(run_id)
|
self._closed_connections.discard(run_id)
|
||||||
|
# Initialize input queue for this connection
|
||||||
|
self._input_responses[run_id] = asyncio.Queue()
|
||||||
|
|
||||||
run = await self._get_run(run_id)
|
run = await self._get_run(run_id)
|
||||||
if run:
|
if run:
|
||||||
|
@ -54,7 +53,6 @@ class WebSocketManager:
|
||||||
})
|
})
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Connection error for run {run_id}: {e}")
|
logger.error(f"Connection error for run {run_id}: {e}")
|
||||||
return False
|
return False
|
||||||
|
@ -62,18 +60,10 @@ class WebSocketManager:
|
||||||
async def start_stream(
|
async def start_stream(
|
||||||
self,
|
self,
|
||||||
run_id: UUID,
|
run_id: UUID,
|
||||||
team_manager: Any,
|
team_manager: TeamManager,
|
||||||
task: str,
|
task: str,
|
||||||
team_config: dict
|
team_config: dict
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Start streaming task execution with improved error handling
|
|
||||||
|
|
||||||
Args:
|
|
||||||
run_id: UUID of the run
|
|
||||||
team_manager: Instance of the team manager
|
|
||||||
task: Task string to execute
|
|
||||||
team_config: Team configuration dictionary
|
|
||||||
"""
|
|
||||||
if run_id not in self._connections or run_id in self._closed_connections:
|
if run_id not in self._connections or run_id in self._closed_connections:
|
||||||
raise ValueError(f"No active connection for run {run_id}")
|
raise ValueError(f"No active connection for run {run_id}")
|
||||||
|
|
||||||
|
@ -81,9 +71,13 @@ class WebSocketManager:
|
||||||
self._cancellation_tokens[run_id] = cancellation_token
|
self._cancellation_tokens[run_id] = cancellation_token
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
# Create input function for this run
|
||||||
|
input_func = self.create_input_func(run_id)
|
||||||
|
|
||||||
async for message in team_manager.run_stream(
|
async for message in team_manager.run_stream(
|
||||||
task=task,
|
task=task,
|
||||||
team_config=team_config,
|
team_config=team_config,
|
||||||
|
input_func=input_func, # Pass the input function
|
||||||
cancellation_token=cancellation_token
|
cancellation_token=cancellation_token
|
||||||
):
|
):
|
||||||
if cancellation_token.is_cancelled() or run_id in self._closed_connections:
|
if cancellation_token.is_cancelled() or run_id in self._closed_connections:
|
||||||
|
@ -113,7 +107,44 @@ class WebSocketManager:
|
||||||
finally:
|
finally:
|
||||||
self._cancellation_tokens.pop(run_id, None)
|
self._cancellation_tokens.pop(run_id, None)
|
||||||
|
|
||||||
async def stop_run(self, run_id: UUID) -> None:
|
def create_input_func(self, run_id: UUID) -> Callable:
|
||||||
|
"""Creates an input function for a specific run"""
|
||||||
|
async def input_handler(prompt: str = "") -> str:
|
||||||
|
try:
|
||||||
|
|
||||||
|
# Send input request to client
|
||||||
|
await self._send_message(run_id, {
|
||||||
|
"type": "input_request",
|
||||||
|
"prompt": prompt,
|
||||||
|
"data": {
|
||||||
|
"source": "system",
|
||||||
|
"content": prompt
|
||||||
|
},
|
||||||
|
"timestamp": datetime.now(timezone.utc).isoformat()
|
||||||
|
})
|
||||||
|
|
||||||
|
# Wait for response
|
||||||
|
if run_id in self._input_responses:
|
||||||
|
response = await self._input_responses[run_id].get()
|
||||||
|
return response
|
||||||
|
else:
|
||||||
|
raise ValueError(f"No input queue for run {run_id}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error handling input for run {run_id}: {e}")
|
||||||
|
raise
|
||||||
|
|
||||||
|
return input_handler
|
||||||
|
|
||||||
|
async def handle_input_response(self, run_id: UUID, response: str) -> None:
|
||||||
|
"""Handle input response from client"""
|
||||||
|
if run_id in self._input_responses:
|
||||||
|
await self._input_responses[run_id].put(response)
|
||||||
|
else:
|
||||||
|
logger.warning(
|
||||||
|
f"Received input response for inactive run {run_id}")
|
||||||
|
|
||||||
|
async def stop_run(self, run_id: UUID, reason: str) -> None:
|
||||||
"""Stop a running task"""
|
"""Stop a running task"""
|
||||||
if run_id in self._cancellation_tokens:
|
if run_id in self._cancellation_tokens:
|
||||||
logger.info(f"Stopping run {run_id}")
|
logger.info(f"Stopping run {run_id}")
|
||||||
|
@ -125,7 +156,7 @@ class WebSocketManager:
|
||||||
await self._send_message(run_id, {
|
await self._send_message(run_id, {
|
||||||
"type": "completion",
|
"type": "completion",
|
||||||
"status": "cancelled",
|
"status": "cancelled",
|
||||||
"data": self._cancel_message,
|
"data": self._get_stop_message(reason),
|
||||||
"timestamp": datetime.now(timezone.utc).isoformat()
|
"timestamp": datetime.now(timezone.utc).isoformat()
|
||||||
})
|
})
|
||||||
except Exception:
|
except Exception:
|
||||||
|
@ -139,11 +170,12 @@ class WebSocketManager:
|
||||||
self._closed_connections.add(run_id)
|
self._closed_connections.add(run_id)
|
||||||
|
|
||||||
# Cancel any running tasks
|
# Cancel any running tasks
|
||||||
await self.stop_run(run_id)
|
await self.stop_run(run_id, "Connection closed")
|
||||||
|
|
||||||
# Clean up resources
|
# Clean up resources
|
||||||
self._connections.pop(run_id, None)
|
self._connections.pop(run_id, None)
|
||||||
self._cancellation_tokens.pop(run_id, None)
|
self._cancellation_tokens.pop(run_id, None)
|
||||||
|
self._input_responses.pop(run_id, None)
|
||||||
|
|
||||||
async def _send_message(self, run_id: UUID, message: dict) -> None:
|
async def _send_message(self, run_id: UUID, message: dict) -> None:
|
||||||
"""Send a message through the WebSocket with connection state checking
|
"""Send a message through the WebSocket with connection state checking
|
||||||
|
@ -251,6 +283,41 @@ class WebSocketManager:
|
||||||
run.error_message = error
|
run.error_message = error
|
||||||
self.db_manager.upsert(run)
|
self.db_manager.upsert(run)
|
||||||
|
|
||||||
|
async def cleanup(self) -> None:
|
||||||
|
"""Clean up all active connections and resources when server is shutting down"""
|
||||||
|
logger.info(
|
||||||
|
f"Cleaning up {len(self.active_connections)} active connections")
|
||||||
|
|
||||||
|
try:
|
||||||
|
# First cancel all running tasks
|
||||||
|
for run_id in self.active_runs.copy():
|
||||||
|
if run_id in self._cancellation_tokens:
|
||||||
|
self._cancellation_tokens[run_id].cancel()
|
||||||
|
|
||||||
|
# Then disconnect all websockets with timeout
|
||||||
|
# 10 second timeout for entire cleanup
|
||||||
|
async with asyncio.timeout(10):
|
||||||
|
for run_id in self.active_connections.copy():
|
||||||
|
try:
|
||||||
|
# Give each disconnect operation 2 seconds
|
||||||
|
async with asyncio.timeout(2):
|
||||||
|
await self.disconnect(run_id)
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
logger.warning(f"Timeout disconnecting run {run_id}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error disconnecting run {run_id}: {e}")
|
||||||
|
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
logger.warning("WebSocketManager cleanup timed out")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error during WebSocketManager cleanup: {e}")
|
||||||
|
finally:
|
||||||
|
# Always clear internal state, even if cleanup had errors
|
||||||
|
self._connections.clear()
|
||||||
|
self._cancellation_tokens.clear()
|
||||||
|
self._closed_connections.clear()
|
||||||
|
self._input_responses.clear()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def active_connections(self) -> set[UUID]:
|
def active_connections(self) -> set[UUID]:
|
||||||
"""Get set of active run IDs"""
|
"""Get set of active run IDs"""
|
||||||
|
|
|
@ -8,6 +8,7 @@ from datetime import datetime
|
||||||
|
|
||||||
from ..deps import get_websocket_manager, get_db, get_team_manager
|
from ..deps import get_websocket_manager, get_db, get_team_manager
|
||||||
from ...datamodel import Run, RunStatus
|
from ...datamodel import Run, RunStatus
|
||||||
|
from ..managers import WebSocketManager
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
@ -17,7 +18,7 @@ logger = logging.getLogger(__name__)
|
||||||
async def run_websocket(
|
async def run_websocket(
|
||||||
websocket: WebSocket,
|
websocket: WebSocket,
|
||||||
run_id: UUID,
|
run_id: UUID,
|
||||||
ws_manager=Depends(get_websocket_manager),
|
ws_manager: WebSocketManager = Depends(get_websocket_manager),
|
||||||
db=Depends(get_db),
|
db=Depends(get_db),
|
||||||
team_manager=Depends(get_team_manager)
|
team_manager=Depends(get_team_manager)
|
||||||
):
|
):
|
||||||
|
@ -48,8 +49,10 @@ async def run_websocket(
|
||||||
message = json.loads(raw_message)
|
message = json.loads(raw_message)
|
||||||
|
|
||||||
if message.get("type") == "stop":
|
if message.get("type") == "stop":
|
||||||
logger.info(f"Received stop request for run {run_id}")
|
print(f"Received stop request for run {run_id}")
|
||||||
await ws_manager.stop_run(run_id)
|
reason = message.get(
|
||||||
|
"reason") or "User requested stop/cancellation"
|
||||||
|
await ws_manager.stop_run(run_id, reason=reason)
|
||||||
break
|
break
|
||||||
|
|
||||||
elif message.get("type") == "ping":
|
elif message.get("type") == "ping":
|
||||||
|
@ -58,6 +61,15 @@ async def run_websocket(
|
||||||
"timestamp": datetime.utcnow().isoformat()
|
"timestamp": datetime.utcnow().isoformat()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
elif message.get("type") == "input_response":
|
||||||
|
# Handle input response from client
|
||||||
|
response = message.get("response")
|
||||||
|
if response is not None:
|
||||||
|
await ws_manager.handle_input_response(run_id, response)
|
||||||
|
else:
|
||||||
|
logger.warning(
|
||||||
|
f"Invalid input response format for run {run_id}")
|
||||||
|
|
||||||
except json.JSONDecodeError:
|
except json.JSONDecodeError:
|
||||||
logger.warning(f"Invalid JSON received: {raw_message}")
|
logger.warning(f"Invalid JSON received: {raw_message}")
|
||||||
await websocket.send_json({
|
await websocket.send_json({
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:aa05d0e55262549880e3e06ca3839cffdbcd0836bd2b98690185255f03dc98ac
|
||||||
|
size 194702
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:5e3340a765da6dff6585c8b2e8a4014df0c94b537d62d341d2d0d45627bbc345
|
|
||||||
size 198222
|
|
|
@ -17,29 +17,29 @@
|
||||||
"typecheck": "tsc --noEmit"
|
"typecheck": "tsc --noEmit"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ant-design/charts": "^2.2.1",
|
"@ant-design/charts": "^2.2.3",
|
||||||
"@ant-design/plots": "^2.2.2",
|
"@ant-design/plots": "^2.2.2",
|
||||||
"@dagrejs/dagre": "^1.1.4",
|
"@dagrejs/dagre": "^1.1.4",
|
||||||
"@headlessui/react": "^1.7.16",
|
"@headlessui/react": "^2.2.0",
|
||||||
"@heroicons/react": "^2.0.18",
|
"@heroicons/react": "^2.0.18",
|
||||||
"@mdx-js/react": "^3.1.0",
|
"@mdx-js/react": "^3.1.0",
|
||||||
"@monaco-editor/react": "^4.6.0",
|
"@monaco-editor/react": "^4.6.0",
|
||||||
"@tailwindcss/typography": "^0.5.9",
|
"@tailwindcss/typography": "^0.5.9",
|
||||||
"@xyflow/react": "^12.3.5",
|
"@xyflow/react": "^12.3.5",
|
||||||
"antd": "^5.1.0",
|
"antd": "^5.22.1",
|
||||||
"autoprefixer": "^10.4.20",
|
"autoprefixer": "^10.4.20",
|
||||||
"gatsby": "^5.13.7",
|
"gatsby": "^5.14.0",
|
||||||
"gatsby-plugin-image": "^3.13.1",
|
"gatsby-plugin-image": "^3.14.0",
|
||||||
"gatsby-plugin-manifest": "^5.13.1",
|
"gatsby-plugin-manifest": "^5.14.0",
|
||||||
"gatsby-plugin-mdx": "^5.13.1",
|
"gatsby-plugin-mdx": "^5.14.0",
|
||||||
"gatsby-plugin-postcss": "^6.13.1",
|
"gatsby-plugin-postcss": "^6.14.0",
|
||||||
"gatsby-plugin-sharp": "^5.13.1",
|
"gatsby-plugin-sharp": "^5.14.0",
|
||||||
"gatsby-plugin-sitemap": "^6.13.1",
|
"gatsby-plugin-sitemap": "^6.14.0",
|
||||||
"gatsby-source-filesystem": "^5.13.1",
|
"gatsby-source-filesystem": "^5.14.0",
|
||||||
"gatsby-transformer-sharp": "^5.13.1",
|
"gatsby-transformer-sharp": "^5.14.0",
|
||||||
"install": "^0.13.0",
|
"install": "^0.13.0",
|
||||||
"lucide-react": "^0.454.0",
|
"lucide-react": "^0.456.0",
|
||||||
"postcss": "^8.4.47",
|
"postcss": "^8.4.49",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-markdown": "^9.0.1",
|
"react-markdown": "^9.0.1",
|
||||||
|
@ -49,7 +49,7 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/lodash.debounce": "^4.0.9",
|
"@types/lodash.debounce": "^4.0.9",
|
||||||
"@types/node": "^20.11.19",
|
"@types/node": "^22.9.0",
|
||||||
"@types/react": "^18.2.55",
|
"@types/react": "^18.2.55",
|
||||||
"@types/react-dom": "^18.2.19",
|
"@types/react-dom": "^18.2.19",
|
||||||
"@types/react-syntax-highlighter": "^15.5.10",
|
"@types/react-syntax-highlighter": "^15.5.10",
|
||||||
|
|
|
@ -15,9 +15,9 @@ import {
|
||||||
import { Tooltip } from "antd";
|
import { Tooltip } from "antd";
|
||||||
import { appContext } from "../hooks/provider";
|
import { appContext } from "../hooks/provider";
|
||||||
import { useConfigStore } from "../hooks/store";
|
import { useConfigStore } from "../hooks/store";
|
||||||
|
import { Link } from "gatsby";
|
||||||
|
|
||||||
type ContentHeaderProps = {
|
type ContentHeaderProps = {
|
||||||
title?: string;
|
|
||||||
onMobileMenuToggle: () => void;
|
onMobileMenuToggle: () => void;
|
||||||
isMobileMenuOpen: boolean;
|
isMobileMenuOpen: boolean;
|
||||||
};
|
};
|
||||||
|
@ -27,13 +27,13 @@ const classNames = (...classes: (string | undefined | boolean)[]) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const ContentHeader = ({
|
const ContentHeader = ({
|
||||||
title,
|
|
||||||
onMobileMenuToggle,
|
onMobileMenuToggle,
|
||||||
isMobileMenuOpen,
|
isMobileMenuOpen,
|
||||||
}: ContentHeaderProps) => {
|
}: ContentHeaderProps) => {
|
||||||
const { darkMode, setDarkMode, user, logout } = React.useContext(appContext);
|
const { darkMode, setDarkMode, user, logout } = React.useContext(appContext);
|
||||||
const { sidebar, setSidebarState } = useConfigStore();
|
const { sidebar, setSidebarState, header } = useConfigStore();
|
||||||
const { isExpanded } = sidebar;
|
const { isExpanded } = sidebar;
|
||||||
|
const { title, breadcrumbs } = header;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="sticky top-0 z-40 bg-primary border-b border-secondary">
|
<div className="sticky top-0 z-40 bg-primary border-b border-secondary">
|
||||||
|
@ -68,24 +68,63 @@ const ContentHeader = ({
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-1 gap-x-4 self-stretch lg:gap-x-6">
|
<div className="flex flex-1 gap-x-4 self-stretch lg:gap-x-6">
|
||||||
{/* Search */}
|
{/* Breadcrumbs */}
|
||||||
<div className="flex flex-1 items-center">
|
<div className="flex flex-1 items-center min-w-0">
|
||||||
<form className="hidden relative flex flex-1">
|
{breadcrumbs && breadcrumbs.length > 0 ? (
|
||||||
<label htmlFor="search-field" className="sr-only">
|
<nav aria-label="Breadcrumb" className="flex">
|
||||||
Search
|
<ol role="list" className="flex items-center space-x-4">
|
||||||
</label>
|
{breadcrumbs.map((page, index) => (
|
||||||
<MagnifyingGlassIcon className="pointer-events-none absolute inset-y-0 left-0 h-full w-5 text-secondary" />
|
<li key={page.name}>
|
||||||
<input
|
<div className="flex items-center">
|
||||||
id="search-field"
|
{index > 0 && (
|
||||||
type="search"
|
<svg
|
||||||
placeholder="Search..."
|
fill="currentColor"
|
||||||
className="block h-full w-full border-0 bg-primary py-0 pl-8 pr-0 text-primary placeholder:text-secondary focus:ring-0 sm:text-sm"
|
viewBox="0 0 20 20"
|
||||||
/>
|
aria-hidden="true"
|
||||||
</form>
|
className="size-5 shrink-0 text-secondary"
|
||||||
|
>
|
||||||
|
<path d="M5.555 17.776l8-16 .894.448-8 16-.894-.448z" />
|
||||||
|
</svg>
|
||||||
|
)}
|
||||||
|
<Link
|
||||||
|
to={page.href}
|
||||||
|
aria-current={page.current ? "page" : undefined}
|
||||||
|
className={classNames(
|
||||||
|
"text-sm font-medium",
|
||||||
|
index > 0 ? "ml-4" : "",
|
||||||
|
page.current
|
||||||
|
? "text-primary"
|
||||||
|
: "text-secondary hover:text-accent"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{page.name}
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ol>
|
||||||
|
</nav>
|
||||||
|
) : (
|
||||||
|
<h1 className="text-lg font-medium text-primary">{title}</h1>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Right side header items */}
|
{/* Right side header items */}
|
||||||
<div className="flex items-center gap-x-4 lg:gap-x-6 ml-auto">
|
<div className="flex items-center gap-x-4 lg:gap-x-6 ml-auto">
|
||||||
|
{/* Search */}
|
||||||
|
<form className="relative flex hidden h-8">
|
||||||
|
<label htmlFor="search-field" className="sr-only">
|
||||||
|
Search
|
||||||
|
</label>
|
||||||
|
<MagnifyingGlassIcon className="pointer-events-none absolute inset-y-0 left-2 h-full w-5 text-secondary" />
|
||||||
|
<input
|
||||||
|
id="search-field"
|
||||||
|
type="search"
|
||||||
|
placeholder="Search..."
|
||||||
|
className="block h-full w-full border-0 bg-primary py-0 pl-10 pr-0 text-primary placeholder:text-secondary focus:ring-0 sm:text-sm"
|
||||||
|
/>
|
||||||
|
</form>
|
||||||
|
|
||||||
{/* Dark Mode Toggle */}
|
{/* Dark Mode Toggle */}
|
||||||
<button
|
<button
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
|
|
|
@ -2,12 +2,27 @@ import React from "react";
|
||||||
import { Link } from "gatsby";
|
import { Link } from "gatsby";
|
||||||
import { useConfigStore } from "../hooks/store";
|
import { useConfigStore } from "../hooks/store";
|
||||||
import { Tooltip } from "antd";
|
import { Tooltip } from "antd";
|
||||||
import { Blocks, Settings, MessagesSquare } from "lucide-react";
|
import { Settings, MessagesSquare } from "lucide-react";
|
||||||
import Icon from "./icons";
|
import Icon from "./icons";
|
||||||
|
|
||||||
const navigation = [
|
interface INavItem {
|
||||||
// { name: "Build", href: "/build", icon: Blocks },
|
name: string;
|
||||||
{ name: "Playground", href: "/", icon: MessagesSquare },
|
href: string;
|
||||||
|
icon: React.ComponentType<{ className?: string }>;
|
||||||
|
breadcrumbs?: Array<{
|
||||||
|
name: string;
|
||||||
|
href: string;
|
||||||
|
current?: boolean;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const navigation: INavItem[] = [
|
||||||
|
{
|
||||||
|
name: "Playground",
|
||||||
|
href: "/",
|
||||||
|
icon: MessagesSquare,
|
||||||
|
breadcrumbs: [{ name: "Playground", href: "/", current: true }],
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const classNames = (...classes: (string | undefined | boolean)[]) => {
|
const classNames = (...classes: (string | undefined | boolean)[]) => {
|
||||||
|
@ -24,12 +39,42 @@ type SidebarProps = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const Sidebar = ({ link, meta, isMobile }: SidebarProps) => {
|
const Sidebar = ({ link, meta, isMobile }: SidebarProps) => {
|
||||||
const { sidebar } = useConfigStore();
|
const { sidebar, setHeader, setSidebarState } = useConfigStore();
|
||||||
const { isExpanded } = sidebar;
|
const { isExpanded } = sidebar;
|
||||||
|
|
||||||
|
// Set initial header state based on current route
|
||||||
|
React.useEffect(() => {
|
||||||
|
setNavigationHeader(link);
|
||||||
|
}, [link]);
|
||||||
|
|
||||||
// Always show full sidebar in mobile view
|
// Always show full sidebar in mobile view
|
||||||
const showFull = isMobile || isExpanded;
|
const showFull = isMobile || isExpanded;
|
||||||
|
|
||||||
|
const handleNavClick = (item: INavItem) => {
|
||||||
|
if (!isExpanded) {
|
||||||
|
setSidebarState({ isExpanded: true });
|
||||||
|
}
|
||||||
|
setHeader({
|
||||||
|
title: item.name,
|
||||||
|
breadcrumbs: item.breadcrumbs,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const setNavigationHeader = (path: string) => {
|
||||||
|
const navItem = navigation.find((item) => item.href === path);
|
||||||
|
if (navItem) {
|
||||||
|
setHeader({
|
||||||
|
title: navItem.name,
|
||||||
|
breadcrumbs: navItem.breadcrumbs,
|
||||||
|
});
|
||||||
|
} else if (path === "/settings") {
|
||||||
|
setHeader({
|
||||||
|
title: "Settings",
|
||||||
|
breadcrumbs: [{ name: "Settings", href: "/settings", current: true }],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
|
@ -42,9 +87,13 @@ const Sidebar = ({ link, meta, isMobile }: SidebarProps) => {
|
||||||
<div
|
<div
|
||||||
className={`flex h-16 items-center ${showFull ? "gap-x-3" : "ml-2"}`}
|
className={`flex h-16 items-center ${showFull ? "gap-x-3" : "ml-2"}`}
|
||||||
>
|
>
|
||||||
<div className="w-8 text-right text-accent">
|
<Link
|
||||||
|
to="/"
|
||||||
|
onClick={() => setNavigationHeader("/")}
|
||||||
|
className="w-8 text-right text-accent hover:opacity-80 transition-opacity"
|
||||||
|
>
|
||||||
<Icon icon="app" size={8} />
|
<Icon icon="app" size={8} />
|
||||||
</div>
|
</Link>
|
||||||
{showFull && (
|
{showFull && (
|
||||||
<div className="flex flex-col" style={{ minWidth: "200px" }}>
|
<div className="flex flex-col" style={{ minWidth: "200px" }}>
|
||||||
<span className="text-base font-semibold text-primary">
|
<span className="text-base font-semibold text-primary">
|
||||||
|
@ -74,20 +123,23 @@ const Sidebar = ({ link, meta, isMobile }: SidebarProps) => {
|
||||||
const navLink = (
|
const navLink = (
|
||||||
<Link
|
<Link
|
||||||
to={item.href}
|
to={item.href}
|
||||||
|
onClick={() => handleNavClick(item)}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
isActive
|
// Base styles
|
||||||
? "text-accent"
|
|
||||||
: "text-primary hover:text-accent hover:bg-secondary",
|
|
||||||
"group flex gap-x-3 rounded-md p-2 text-sm font-medium",
|
"group flex gap-x-3 rounded-md p-2 text-sm font-medium",
|
||||||
!showFull && "justify-center"
|
!showFull && "justify-center",
|
||||||
|
// Color states
|
||||||
|
isActive
|
||||||
|
? "bg-secondary/50 text-accent"
|
||||||
|
: "text-secondary hover:bg-secondary/50 hover:text-accent"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<IconComponent
|
<IconComponent
|
||||||
className={classNames(
|
className={classNames(
|
||||||
|
"h-6 w-6 shrink-0",
|
||||||
isActive
|
isActive
|
||||||
? "text-accent"
|
? "text-accent"
|
||||||
: "text-secondary group-hover:text-accent",
|
: "text-secondary group-hover:text-accent"
|
||||||
"h-6 w-6 shrink-0"
|
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
{showFull && item.name}
|
{showFull && item.name}
|
||||||
|
@ -120,6 +172,14 @@ const Sidebar = ({ link, meta, isMobile }: SidebarProps) => {
|
||||||
<Tooltip title="Settings" placement="right">
|
<Tooltip title="Settings" placement="right">
|
||||||
<Link
|
<Link
|
||||||
to="/settings"
|
to="/settings"
|
||||||
|
onClick={() =>
|
||||||
|
setHeader({
|
||||||
|
title: "Settings",
|
||||||
|
breadcrumbs: [
|
||||||
|
{ name: "Settings", href: "/settings", current: true },
|
||||||
|
],
|
||||||
|
})
|
||||||
|
}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"group flex gap-x-3 rounded-md p-2 text-sm font-medium",
|
"group flex gap-x-3 rounded-md p-2 text-sm font-medium",
|
||||||
"text-primary hover:text-accent hover:bg-secondary",
|
"text-primary hover:text-accent hover:bg-secondary",
|
||||||
|
@ -132,6 +192,14 @@ const Sidebar = ({ link, meta, isMobile }: SidebarProps) => {
|
||||||
) : (
|
) : (
|
||||||
<Link
|
<Link
|
||||||
to="/settings"
|
to="/settings"
|
||||||
|
onClick={() =>
|
||||||
|
setHeader({
|
||||||
|
title: "Settings",
|
||||||
|
breadcrumbs: [
|
||||||
|
{ name: "Settings", href: "/settings", current: true },
|
||||||
|
],
|
||||||
|
})
|
||||||
|
}
|
||||||
className="group flex gap-x-3 rounded-md p-2 text-sm font-medium text-primary hover:text-accent hover:bg-secondary"
|
className="group flex gap-x-3 rounded-md p-2 text-sm font-medium text-primary hover:text-accent hover:bg-secondary"
|
||||||
>
|
>
|
||||||
<Settings className="h-6 w-6 shrink-0 text-secondary group-hover:text-accent" />
|
<Settings className="h-6 w-6 shrink-0 text-secondary group-hover:text-accent" />
|
||||||
|
|
|
@ -76,6 +76,7 @@ export interface DBModel {
|
||||||
user_id?: string;
|
user_id?: string;
|
||||||
created_at?: string;
|
created_at?: string;
|
||||||
updated_at?: string;
|
updated_at?: string;
|
||||||
|
version?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Message extends DBModel {
|
export interface Message extends DBModel {
|
||||||
|
@ -89,19 +90,31 @@ export interface Session extends DBModel {
|
||||||
team_id?: number;
|
team_id?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface BaseConfig {
|
||||||
|
component_type: string;
|
||||||
|
version?: string;
|
||||||
|
}
|
||||||
|
|
||||||
// WebSocket message types
|
// WebSocket message types
|
||||||
export type ThreadStatus = "streaming" | "complete" | "error" | "cancelled";
|
export type ThreadStatus =
|
||||||
|
| "streaming"
|
||||||
|
| "complete"
|
||||||
|
| "error"
|
||||||
|
| "cancelled"
|
||||||
|
| "awaiting_input"
|
||||||
|
| "timeout";
|
||||||
|
|
||||||
export interface WebSocketMessage {
|
export interface WebSocketMessage {
|
||||||
type: "message" | "result" | "completion";
|
type: "message" | "result" | "completion" | "input_request";
|
||||||
data: {
|
data?: {
|
||||||
source: string;
|
source?: string;
|
||||||
models_usage?: RequestUsage;
|
models_usage?: RequestUsage | null;
|
||||||
content: unknown;
|
content?: string;
|
||||||
task_result?: TaskResult;
|
task_result?: TaskResult;
|
||||||
};
|
};
|
||||||
status?: ThreadStatus;
|
status?: ThreadStatus;
|
||||||
error?: string;
|
error?: string;
|
||||||
|
timestamp?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TaskResult {
|
export interface TaskResult {
|
||||||
|
@ -117,24 +130,38 @@ export type AgentTypes = "AssistantAgent" | "CodingAssistantAgent";
|
||||||
|
|
||||||
export type TeamTypes = "RoundRobinGroupChat" | "SelectorGroupChat";
|
export type TeamTypes = "RoundRobinGroupChat" | "SelectorGroupChat";
|
||||||
|
|
||||||
|
// class ComponentType(str, Enum):
|
||||||
|
// TEAM = "team"
|
||||||
|
// AGENT = "agent"
|
||||||
|
// MODEL = "model"
|
||||||
|
// TOOL = "tool"
|
||||||
|
// TERMINATION = "termination"
|
||||||
export type TerminationTypes =
|
export type TerminationTypes =
|
||||||
| "MaxMessageTermination"
|
| "MaxMessageTermination"
|
||||||
| "StopMessageTermination"
|
| "StopMessageTermination"
|
||||||
| "TextMentionTermination";
|
| "TextMentionTermination";
|
||||||
|
|
||||||
export interface ModelConfig {
|
export type ComponentTypes =
|
||||||
|
| "team"
|
||||||
|
| "agent"
|
||||||
|
| "model"
|
||||||
|
| "tool"
|
||||||
|
| "termination";
|
||||||
|
|
||||||
|
export interface ModelConfig extends BaseConfig {
|
||||||
model: string;
|
model: string;
|
||||||
model_type: ModelTypes;
|
model_type: ModelTypes;
|
||||||
api_key?: string;
|
api_key?: string;
|
||||||
base_url?: string;
|
base_url?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ToolConfig {
|
export interface ToolConfig extends BaseConfig {
|
||||||
name: string;
|
name: string;
|
||||||
description: string;
|
description: string;
|
||||||
content: string;
|
content: string;
|
||||||
|
tool_type: string;
|
||||||
}
|
}
|
||||||
export interface AgentConfig {
|
export interface AgentConfig extends BaseConfig {
|
||||||
name: string;
|
name: string;
|
||||||
agent_type: AgentTypes;
|
agent_type: AgentTypes;
|
||||||
system_message?: string;
|
system_message?: string;
|
||||||
|
@ -142,13 +169,13 @@ export interface AgentConfig {
|
||||||
tools?: ToolConfig[];
|
tools?: ToolConfig[];
|
||||||
description?: string;
|
description?: string;
|
||||||
}
|
}
|
||||||
export interface TerminationConfig {
|
export interface TerminationConfig extends BaseConfig {
|
||||||
termination_type: TerminationTypes;
|
termination_type: TerminationTypes;
|
||||||
max_messages?: number;
|
max_messages?: number;
|
||||||
text?: string;
|
text?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TeamConfig {
|
export interface TeamConfig extends BaseConfig {
|
||||||
name: string;
|
name: string;
|
||||||
participants: AgentConfig[];
|
participants: AgentConfig[];
|
||||||
team_type: TeamTypes;
|
team_type: TeamTypes;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { IStatus } from "./types";
|
import { IStatus } from "./types/app";
|
||||||
|
|
||||||
export const getServerUrl = () => {
|
export const getServerUrl = () => {
|
||||||
return process.env.GATSBY_API_URL || "/api";
|
return process.env.GATSBY_API_URL || "/api";
|
||||||
|
|
|
@ -1,4 +1,10 @@
|
||||||
import React, { useCallback, useState, useEffect } from "react";
|
import React, {
|
||||||
|
useCallback,
|
||||||
|
useState,
|
||||||
|
useEffect,
|
||||||
|
useRef,
|
||||||
|
useMemo,
|
||||||
|
} from "react";
|
||||||
import {
|
import {
|
||||||
ReactFlow,
|
ReactFlow,
|
||||||
Node,
|
Node,
|
||||||
|
@ -8,6 +14,8 @@ import {
|
||||||
NodeTypes,
|
NodeTypes,
|
||||||
useReactFlow,
|
useReactFlow,
|
||||||
ReactFlowProvider,
|
ReactFlowProvider,
|
||||||
|
NodeChange,
|
||||||
|
applyNodeChanges,
|
||||||
} from "@xyflow/react";
|
} from "@xyflow/react";
|
||||||
import Dagre from "@dagrejs/dagre";
|
import Dagre from "@dagrejs/dagre";
|
||||||
import "@xyflow/react/dist/style.css";
|
import "@xyflow/react/dist/style.css";
|
||||||
|
@ -17,15 +25,15 @@ import {
|
||||||
AgentConfig,
|
AgentConfig,
|
||||||
TeamConfig,
|
TeamConfig,
|
||||||
} from "../../../../types/datamodel";
|
} from "../../../../types/datamodel";
|
||||||
import { ThreadState, ThreadStatus } from "../types";
|
import { ThreadState } from "../types";
|
||||||
import { CustomEdge, EdgeTooltipContent } from "./edge";
|
import { CustomEdge } from "./edge";
|
||||||
import { Tooltip } from "antd";
|
import { useConfigStore } from "../../../../../hooks/store";
|
||||||
|
import { AgentFlowToolbar } from "./toolbar";
|
||||||
|
|
||||||
interface AgentFlowProps {
|
interface AgentFlowProps {
|
||||||
teamConfig: TeamConfig;
|
teamConfig: TeamConfig;
|
||||||
messages: AgentMessageConfig[];
|
messages: AgentMessageConfig[];
|
||||||
threadState: ThreadState;
|
threadState: ThreadState;
|
||||||
direction?: "TB" | "LR";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MessageSequence {
|
interface MessageSequence {
|
||||||
|
@ -36,8 +44,13 @@ interface MessageSequence {
|
||||||
messages: AgentMessageConfig[];
|
messages: AgentMessageConfig[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface BidirectionalPattern {
|
||||||
|
forward: MessageSequence;
|
||||||
|
reverse: MessageSequence;
|
||||||
|
}
|
||||||
|
|
||||||
const NODE_DIMENSIONS = {
|
const NODE_DIMENSIONS = {
|
||||||
default: { width: 150, height: 100 },
|
default: { width: 170, height: 100 },
|
||||||
end: { width: 120, height: 80 },
|
end: { width: 120, height: 80 },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -47,32 +60,76 @@ const getLayoutedElements = (
|
||||||
direction: "TB" | "LR"
|
direction: "TB" | "LR"
|
||||||
) => {
|
) => {
|
||||||
const g = new Dagre.graphlib.Graph().setDefaultEdgeLabel(() => ({}));
|
const g = new Dagre.graphlib.Graph().setDefaultEdgeLabel(() => ({}));
|
||||||
|
|
||||||
|
// Updated graph settings
|
||||||
g.setGraph({
|
g.setGraph({
|
||||||
rankdir: direction,
|
rankdir: direction,
|
||||||
nodesep: direction === "TB" ? 100 : 80, // Adjust for orientation
|
nodesep: 80,
|
||||||
ranksep: direction === "TB" ? 80 : 100, // Adjust for orientation
|
ranksep: 120,
|
||||||
align: direction === "TB" ? "DL" : "UL", // Adjust alignment
|
ranker: "tight-tree",
|
||||||
ranker: "network-simplex",
|
|
||||||
marginx: 30,
|
marginx: 30,
|
||||||
marginy: 30,
|
marginy: 30,
|
||||||
});
|
});
|
||||||
|
|
||||||
edges.forEach((edge) => g.setEdge(edge.source, edge.target));
|
// Add nodes (unchanged)
|
||||||
nodes.forEach((node) => {
|
nodes.forEach((node) => {
|
||||||
const dimensions =
|
const dimensions =
|
||||||
node.data.type === "end" ? NODE_DIMENSIONS.end : NODE_DIMENSIONS.default;
|
node.data.type === "end" ? NODE_DIMENSIONS.end : NODE_DIMENSIONS.default;
|
||||||
g.setNode(node.id, { ...node, ...dimensions });
|
g.setNode(node.id, { ...node, ...dimensions });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Create a map to track bidirectional edges
|
||||||
|
const bidirectionalPairs = new Map<
|
||||||
|
string,
|
||||||
|
{ source: string; target: string }[]
|
||||||
|
>();
|
||||||
|
|
||||||
|
// First pass - identify bidirectional pairs
|
||||||
|
edges.forEach((edge) => {
|
||||||
|
const forwardKey = `${edge.source}->${edge.target}`;
|
||||||
|
const reverseKey = `${edge.target}->${edge.source}`;
|
||||||
|
const pairKey = [edge.source, edge.target].sort().join("-");
|
||||||
|
|
||||||
|
if (!bidirectionalPairs.has(pairKey)) {
|
||||||
|
bidirectionalPairs.set(pairKey, []);
|
||||||
|
}
|
||||||
|
bidirectionalPairs.get(pairKey)!.push({
|
||||||
|
source: edge.source,
|
||||||
|
target: edge.target,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Second pass - add edges with weights
|
||||||
|
bidirectionalPairs.forEach((pairs, pairKey) => {
|
||||||
|
if (pairs.length === 2) {
|
||||||
|
// Bidirectional edge
|
||||||
|
const [first, second] = pairs;
|
||||||
|
g.setEdge(first.source, first.target, {
|
||||||
|
weight: 2,
|
||||||
|
minlen: 1,
|
||||||
|
});
|
||||||
|
g.setEdge(second.source, second.target, {
|
||||||
|
weight: 1,
|
||||||
|
minlen: 1,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Regular edge
|
||||||
|
const edge = pairs[0];
|
||||||
|
g.setEdge(edge.source, edge.target, {
|
||||||
|
weight: 1,
|
||||||
|
minlen: 1,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Run layout
|
||||||
Dagre.layout(g);
|
Dagre.layout(g);
|
||||||
|
|
||||||
return {
|
// Position nodes
|
||||||
nodes: nodes.map((node) => {
|
const positionedNodes = nodes.map((node) => {
|
||||||
const { x, y } = g.node(node.id);
|
const { x, y } = g.node(node.id);
|
||||||
const dimensions =
|
const dimensions =
|
||||||
node.data.type === "end"
|
node.data.type === "end" ? NODE_DIMENSIONS.end : NODE_DIMENSIONS.default;
|
||||||
? NODE_DIMENSIONS.end
|
|
||||||
: NODE_DIMENSIONS.default;
|
|
||||||
return {
|
return {
|
||||||
...node,
|
...node,
|
||||||
position: {
|
position: {
|
||||||
|
@ -80,8 +137,36 @@ const getLayoutedElements = (
|
||||||
y: y - dimensions.height / 2,
|
y: y - dimensions.height / 2,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}),
|
});
|
||||||
edges,
|
|
||||||
|
// Create a map of node positions for edge calculations
|
||||||
|
const nodePositions = new Map(
|
||||||
|
positionedNodes.map((node) => [
|
||||||
|
node.id,
|
||||||
|
{
|
||||||
|
x: node.position.x + NODE_DIMENSIONS.default.width / 2,
|
||||||
|
y: node.position.y + NODE_DIMENSIONS.default.height / 2,
|
||||||
|
},
|
||||||
|
])
|
||||||
|
);
|
||||||
|
|
||||||
|
// Process edges with positions
|
||||||
|
const positionedEdges = edges.map((edge) => {
|
||||||
|
const sourcePos = nodePositions.get(edge.source)!;
|
||||||
|
const targetPos = nodePositions.get(edge.target)!;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...edge,
|
||||||
|
sourceX: sourcePos.x,
|
||||||
|
sourceY: sourcePos.y,
|
||||||
|
targetX: targetPos.x,
|
||||||
|
targetY: targetPos.y,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
nodes: positionedNodes,
|
||||||
|
edges: positionedEdges,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -92,6 +177,9 @@ const createNode = (
|
||||||
isActive: boolean = false,
|
isActive: boolean = false,
|
||||||
threadState?: ThreadState
|
threadState?: ThreadState
|
||||||
): Node => {
|
): Node => {
|
||||||
|
const isStreamingOrWaiting =
|
||||||
|
threadState?.status === "streaming" ||
|
||||||
|
threadState?.status === "awaiting_input";
|
||||||
if (type === "user") {
|
if (type === "user") {
|
||||||
return {
|
return {
|
||||||
id,
|
id,
|
||||||
|
@ -105,6 +193,7 @@ const createNode = (
|
||||||
isActive,
|
isActive,
|
||||||
status: "",
|
status: "",
|
||||||
reason: "",
|
reason: "",
|
||||||
|
draggable: !isStreamingOrWaiting,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -122,6 +211,7 @@ const createNode = (
|
||||||
agentType: "",
|
agentType: "",
|
||||||
description: "",
|
description: "",
|
||||||
isActive: false,
|
isActive: false,
|
||||||
|
draggable: false,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -138,6 +228,7 @@ const createNode = (
|
||||||
isActive,
|
isActive,
|
||||||
status: "",
|
status: "",
|
||||||
reason: "",
|
reason: "",
|
||||||
|
draggable: !isStreamingOrWaiting,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -154,21 +245,40 @@ const AgentFlow: React.FC<AgentFlowProps> = ({
|
||||||
teamConfig,
|
teamConfig,
|
||||||
messages,
|
messages,
|
||||||
threadState,
|
threadState,
|
||||||
direction = "TB",
|
|
||||||
}) => {
|
}) => {
|
||||||
const { fitView } = useReactFlow();
|
const { fitView } = useReactFlow();
|
||||||
const [nodes, setNodes] = useState<Node[]>([]);
|
const [nodes, setNodes] = useState<Node[]>([]);
|
||||||
const [edges, setEdges] = useState<Edge[]>([]);
|
const [edges, setEdges] = useState<Edge[]>([]);
|
||||||
|
const [shouldRefit, setShouldRefit] = useState(false);
|
||||||
|
const [isFullscreen, setIsFullscreen] = useState(false);
|
||||||
|
|
||||||
// ...previous imports remain same
|
// Get settings from store
|
||||||
|
const { agentFlow: settings, setAgentFlowSettings } = useConfigStore();
|
||||||
|
|
||||||
|
const onNodesChange = useCallback((changes: NodeChange[]) => {
|
||||||
|
setNodes((nds) => applyNodeChanges(changes, nds));
|
||||||
|
}, []);
|
||||||
|
const flowWrapper = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (shouldRefit) {
|
||||||
|
const timeoutId = setTimeout(() => {
|
||||||
|
fitView({ padding: 0.2, duration: 200 });
|
||||||
|
setShouldRefit(false);
|
||||||
|
}, 100); // Increased delay slightly
|
||||||
|
|
||||||
|
return () => clearTimeout(timeoutId);
|
||||||
|
}
|
||||||
|
}, [shouldRefit, fitView]);
|
||||||
|
|
||||||
|
// Process messages into nodes and edges
|
||||||
const processMessages = useCallback(
|
const processMessages = useCallback(
|
||||||
(messages: AgentMessageConfig[]) => {
|
(messages: AgentMessageConfig[]) => {
|
||||||
if (messages.length === 0) return { nodes: [], edges: [] };
|
if (messages.length === 0) return { nodes: [], edges: [] };
|
||||||
|
|
||||||
const sequences: MessageSequence[] = [];
|
|
||||||
const nodeMap = new Map<string, Node>();
|
const nodeMap = new Map<string, Node>();
|
||||||
const transitionCounts = new Map<string, MessageSequence>();
|
const transitionCounts = new Map<string, MessageSequence>();
|
||||||
|
const bidirectionalPatterns = new Map<string, BidirectionalPattern>();
|
||||||
|
|
||||||
// Process first message source
|
// Process first message source
|
||||||
const firstAgentConfig = teamConfig.participants.find(
|
const firstAgentConfig = teamConfig.participants.find(
|
||||||
|
@ -184,7 +294,7 @@ const AgentFlow: React.FC<AgentFlowProps> = ({
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Group messages by transitions (including self-transitions)
|
// Group messages by transitions
|
||||||
for (let i = 0; i < messages.length - 1; i++) {
|
for (let i = 0; i < messages.length - 1; i++) {
|
||||||
const currentMsg = messages[i];
|
const currentMsg = messages[i];
|
||||||
const nextMsg = messages[i + 1];
|
const nextMsg = messages[i + 1];
|
||||||
|
@ -226,45 +336,113 @@ const AgentFlow: React.FC<AgentFlowProps> = ({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create edges from transitions
|
// Identify bidirectional patterns
|
||||||
const newEdges: Edge[] = Array.from(transitionCounts.entries()).map(
|
transitionCounts.forEach((transition, key) => {
|
||||||
([key, transition], index) => {
|
const [source, target] = key.split("->");
|
||||||
// const avgTokens = Math.round(
|
const reverseKey = `${target}->${source}`;
|
||||||
// transition.totalTokens / transition.count
|
const reverseTransition = transitionCounts.get(reverseKey);
|
||||||
// );
|
|
||||||
const label =
|
|
||||||
transition.totalTokens > 0
|
|
||||||
? `${transition.count > 1 ? `${transition.count}x` : ""} (${
|
|
||||||
transition.totalTokens
|
|
||||||
} tokens)`
|
|
||||||
: "";
|
|
||||||
|
|
||||||
return {
|
if (reverseTransition && !bidirectionalPatterns.has(key)) {
|
||||||
id: `${transition.source}-${transition.target}-${index}`,
|
const patternKey = [source, target].sort().join("->");
|
||||||
|
bidirectionalPatterns.set(patternKey, {
|
||||||
|
forward: transition,
|
||||||
|
reverse: reverseTransition,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create edges with bidirectional routing
|
||||||
|
const newEdges: Edge[] = [];
|
||||||
|
const processedKeys = new Set<string>();
|
||||||
|
|
||||||
|
// Helper function to create edge label based on settings
|
||||||
|
const createEdgeLabel = (transition: MessageSequence) => {
|
||||||
|
if (!settings.showLabels) return "";
|
||||||
|
if (transition.totalTokens > 0) {
|
||||||
|
return `${transition.count > 1 ? `${transition.count}x` : ""} ${
|
||||||
|
settings.showTokens ? `(${transition.totalTokens} tokens)` : ""
|
||||||
|
}`.trim();
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
};
|
||||||
|
|
||||||
|
transitionCounts.forEach((transition, key) => {
|
||||||
|
if (processedKeys.has(key)) return;
|
||||||
|
|
||||||
|
const [source, target] = key.split("->");
|
||||||
|
const patternKey = [source, target].sort().join("->");
|
||||||
|
const bidirectionalPattern = bidirectionalPatterns.get(patternKey);
|
||||||
|
|
||||||
|
if (bidirectionalPattern) {
|
||||||
|
// Create paired edges for bidirectional pattern
|
||||||
|
const forwardKey = `${source}->${target}`;
|
||||||
|
const reverseKey = `${target}->${source}`;
|
||||||
|
|
||||||
|
const forwardEdgeId = `${source}-${target}-forward`;
|
||||||
|
const reverseEdgeId = `${target}-${source}-reverse`;
|
||||||
|
|
||||||
|
const createBidirectionalEdge = (
|
||||||
|
transition: MessageSequence,
|
||||||
|
isSecondary: boolean,
|
||||||
|
edgeId: string,
|
||||||
|
pairedEdgeId: string
|
||||||
|
) => ({
|
||||||
|
id: edgeId,
|
||||||
source: transition.source,
|
source: transition.source,
|
||||||
target: transition.target,
|
target: transition.target,
|
||||||
type: "custom",
|
type: "custom",
|
||||||
data: {
|
data: {
|
||||||
label,
|
label: createEdgeLabel(transition),
|
||||||
messages: transition.messages,
|
messages: settings.showMessages ? transition.messages : [],
|
||||||
|
routingType: isSecondary ? "secondary" : "primary",
|
||||||
|
bidirectionalPair: pairedEdgeId,
|
||||||
|
},
|
||||||
|
style: {
|
||||||
|
stroke: "#2563eb",
|
||||||
|
strokeWidth: 1,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
newEdges.push(
|
||||||
|
createBidirectionalEdge(
|
||||||
|
transitionCounts.get(forwardKey)!,
|
||||||
|
false,
|
||||||
|
forwardEdgeId,
|
||||||
|
reverseEdgeId
|
||||||
|
),
|
||||||
|
createBidirectionalEdge(
|
||||||
|
transitionCounts.get(reverseKey)!,
|
||||||
|
true,
|
||||||
|
reverseEdgeId,
|
||||||
|
forwardEdgeId
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
processedKeys.add(forwardKey);
|
||||||
|
processedKeys.add(reverseKey);
|
||||||
|
} else {
|
||||||
|
// Handle regular edges (including self-loops)
|
||||||
|
newEdges.push({
|
||||||
|
id: `${transition.source}-${transition.target}-${key}`,
|
||||||
|
source: transition.source,
|
||||||
|
target: transition.target,
|
||||||
|
type: "custom",
|
||||||
|
data: {
|
||||||
|
label: createEdgeLabel(transition),
|
||||||
|
messages: settings.showMessages ? transition.messages : [],
|
||||||
},
|
},
|
||||||
animated:
|
animated:
|
||||||
threadState?.status === "streaming" &&
|
threadState?.status === "streaming" &&
|
||||||
index === transitionCounts.size - 1,
|
key === Array.from(transitionCounts.keys()).pop(),
|
||||||
style: {
|
style: {
|
||||||
stroke: "#2563eb",
|
stroke: "#2563eb",
|
||||||
strokeWidth: Math.min(Math.max(transition.count, 1), 5),
|
strokeWidth: 1,
|
||||||
// Add curved style for self-referential edges
|
|
||||||
...(transition.source === transition.target && {
|
|
||||||
borderRadius: 20,
|
|
||||||
curvature: 0.5,
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
);
|
});
|
||||||
|
|
||||||
// Handle end node logic (keeping existing end node logic)
|
// Handle end node logic
|
||||||
if (threadState && messages.length > 0) {
|
if (threadState && messages.length > 0) {
|
||||||
const lastMessage = messages[messages.length - 1];
|
const lastMessage = messages[messages.length - 1];
|
||||||
|
|
||||||
|
@ -280,6 +458,8 @@ const AgentFlow: React.FC<AgentFlowProps> = ({
|
||||||
cancelled: "red",
|
cancelled: "red",
|
||||||
error: "red",
|
error: "red",
|
||||||
streaming: "#2563eb",
|
streaming: "#2563eb",
|
||||||
|
awaiting_input: "#2563eb",
|
||||||
|
timeout: "red",
|
||||||
}[threadState.status] || "#2563eb";
|
}[threadState.status] || "#2563eb";
|
||||||
|
|
||||||
newEdges.push({
|
newEdges.push({
|
||||||
|
@ -288,12 +468,12 @@ const AgentFlow: React.FC<AgentFlowProps> = ({
|
||||||
target: "end",
|
target: "end",
|
||||||
type: "custom",
|
type: "custom",
|
||||||
data: {
|
data: {
|
||||||
label: "ended",
|
label: settings.showLabels ? "ended" : "",
|
||||||
messages: [],
|
messages: [],
|
||||||
},
|
},
|
||||||
animated: false,
|
|
||||||
style: {
|
style: {
|
||||||
stroke: edgeColor,
|
stroke: edgeColor,
|
||||||
|
strokeWidth: 1,
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
zIndex: 100,
|
zIndex: 100,
|
||||||
},
|
},
|
||||||
|
@ -301,27 +481,38 @@ const AgentFlow: React.FC<AgentFlowProps> = ({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set active state for the last message source
|
|
||||||
const lastActiveSource = messages[messages.length - 1]?.source;
|
|
||||||
nodeMap.forEach((node) => {
|
|
||||||
node.data.isActive =
|
|
||||||
node.id === lastActiveSource && threadState?.status === "streaming";
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
nodes: Array.from(nodeMap.values()),
|
nodes: Array.from(nodeMap.values()),
|
||||||
edges: newEdges,
|
edges: newEdges,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
[teamConfig.participants, threadState]
|
[teamConfig.participants, threadState, settings]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const handleToggleFullscreen = useCallback(() => {
|
||||||
|
setIsFullscreen(!isFullscreen);
|
||||||
|
setShouldRefit(true);
|
||||||
|
}, [isFullscreen]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isFullscreen) return;
|
||||||
|
|
||||||
|
const handleEscape = (event: KeyboardEvent) => {
|
||||||
|
if (event.key === "Escape") {
|
||||||
|
handleToggleFullscreen();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
document.addEventListener("keydown", handleEscape);
|
||||||
|
return () => document.removeEventListener("keydown", handleEscape);
|
||||||
|
}, [isFullscreen, handleToggleFullscreen]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const { nodes: newNodes, edges: newEdges } = processMessages(messages);
|
const { nodes: newNodes, edges: newEdges } = processMessages(messages);
|
||||||
const { nodes: layoutedNodes, edges: layoutedEdges } = getLayoutedElements(
|
const { nodes: layoutedNodes, edges: layoutedEdges } = getLayoutedElements(
|
||||||
newNodes,
|
newNodes,
|
||||||
newEdges,
|
newEdges,
|
||||||
direction
|
settings.direction
|
||||||
);
|
);
|
||||||
|
|
||||||
setNodes(layoutedNodes);
|
setNodes(layoutedNodes);
|
||||||
|
@ -332,29 +523,53 @@ const AgentFlow: React.FC<AgentFlowProps> = ({
|
||||||
fitView({ padding: 0.2, duration: 200 });
|
fitView({ padding: 0.2, duration: 200 });
|
||||||
}, 50);
|
}, 50);
|
||||||
}
|
}
|
||||||
}, [messages, processMessages, direction, threadState, fitView]);
|
}, [messages, processMessages, settings.direction, threadState, fitView]);
|
||||||
|
|
||||||
|
// Define common ReactFlow props
|
||||||
|
const reactFlowProps = {
|
||||||
|
nodes,
|
||||||
|
edges,
|
||||||
|
nodeTypes,
|
||||||
|
edgeTypes,
|
||||||
|
defaultViewport: { x: 0, y: 0, zoom: 1 },
|
||||||
|
minZoom: 0.5,
|
||||||
|
maxZoom: 2,
|
||||||
|
onNodesChange,
|
||||||
|
proOptions: { hideAttribution: true },
|
||||||
|
};
|
||||||
|
|
||||||
|
// Define common toolbar props
|
||||||
|
const toolbarProps = useMemo(
|
||||||
|
() => ({
|
||||||
|
isFullscreen,
|
||||||
|
onToggleFullscreen: handleToggleFullscreen,
|
||||||
|
onResetView: () => fitView({ padding: 0.2, duration: 200 }),
|
||||||
|
}),
|
||||||
|
[isFullscreen, handleToggleFullscreen, fitView]
|
||||||
|
);
|
||||||
return (
|
return (
|
||||||
<div className="w-full h-full bg-tertiary rounded-lg min-h-[300px]">
|
<div
|
||||||
<ReactFlow
|
ref={flowWrapper}
|
||||||
nodes={nodes}
|
className={`transition-all duration-200 ${
|
||||||
edges={edges}
|
isFullscreen
|
||||||
nodeTypes={nodeTypes}
|
? "fixed inset-4 z-[9999] shadow" // Modal-like styling
|
||||||
edgeTypes={edgeTypes}
|
: "w-full h-full min-h-[300px]"
|
||||||
defaultViewport={{ x: 0, y: 0, zoom: 1 }}
|
} bg-tertiary rounded-lg`}
|
||||||
minZoom={0.5}
|
|
||||||
maxZoom={2}
|
|
||||||
proOptions={{ hideAttribution: true }}
|
|
||||||
onInit={() => {
|
|
||||||
if (messages.length > 0) {
|
|
||||||
setTimeout(() => {
|
|
||||||
fitView({ padding: 0.2, duration: 200 });
|
|
||||||
}, 50);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<Background />
|
{/* Backdrop when fullscreen */}
|
||||||
<Controls />
|
{isFullscreen && (
|
||||||
|
<div
|
||||||
|
className="fixed inset-0 -z-10 bg-background/80 backdrop-blur-sm"
|
||||||
|
onClick={handleToggleFullscreen}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<ReactFlow {...reactFlowProps}>
|
||||||
|
{settings.showGrid && <Background />}
|
||||||
|
{/* <Controls /> */}
|
||||||
|
<div className="absolute top-0 right-0 z-50">
|
||||||
|
<AgentFlowToolbar {...toolbarProps} />
|
||||||
|
</div>
|
||||||
</ReactFlow>
|
</ReactFlow>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -20,6 +20,7 @@ export interface AgentNodeData {
|
||||||
isActive?: boolean;
|
isActive?: boolean;
|
||||||
status?: ThreadStatus | null;
|
status?: ThreadStatus | null;
|
||||||
reason?: string | null;
|
reason?: string | null;
|
||||||
|
draggable: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface AgentNodeProps {
|
interface AgentNodeProps {
|
||||||
|
@ -99,7 +100,7 @@ function AgentNode({ data, isConnectable }: AgentNodeProps) {
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Header Section */}
|
{/* Header Section */}
|
||||||
<div className="flex items-center gap-2 px-3 py-2 bg-secondary border-b border-border">
|
<div className="flex agent-draghandle items-center gap-2 px-3 py-2 bg-secondary border-b border-border">
|
||||||
{getHeaderIcon()}
|
{getHeaderIcon()}
|
||||||
<span className="text-sm font-medium text-primary truncate">
|
<span className="text-sm font-medium text-primary truncate">
|
||||||
{data.label}
|
{data.label}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { message, Tabs, Tooltip } from "antd";
|
import { Tooltip } from "antd";
|
||||||
import { AgentMessageConfig } from "../../../../types/datamodel";
|
import { AgentMessageConfig } from "../../../../types/datamodel";
|
||||||
import {
|
import {
|
||||||
EdgeLabelRenderer,
|
EdgeLabelRenderer,
|
||||||
type EdgeProps,
|
type EdgeProps,
|
||||||
getSmoothStepPath, // Add this import
|
getSmoothStepPath,
|
||||||
} from "@xyflow/react";
|
} from "@xyflow/react";
|
||||||
import { RenderMessage } from "../rendermessage";
|
import { RenderMessage } from "../rendermessage";
|
||||||
|
|
||||||
|
@ -15,15 +15,17 @@ interface EdgeTooltipContentProps {
|
||||||
interface CustomEdgeData {
|
interface CustomEdgeData {
|
||||||
label?: string;
|
label?: string;
|
||||||
messages: AgentMessageConfig[];
|
messages: AgentMessageConfig[];
|
||||||
|
routingType?: "primary" | "secondary";
|
||||||
|
bidirectionalPair?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const EdgeTooltipContent: React.FC<EdgeTooltipContentProps> = ({
|
const EdgeTooltipContent: React.FC<EdgeTooltipContentProps> = ({
|
||||||
messages,
|
messages,
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<div className="p-2 overflow-auto max-h-[200px] scroll max-w-[350px]">
|
<div className="p-2 overflow-auto max-h-[200px] scroll max-w-[350px]">
|
||||||
<div className="text-xs mb-2">{messages.length} messages</div>
|
<div className="text-xs mb-2">{messages.length} messages</div>
|
||||||
<div className="edge-tooltip ">
|
<div className="edge-tooltip">
|
||||||
{messages.map((message, index) => (
|
{messages.map((message, index) => (
|
||||||
<RenderMessage key={index} message={message} />
|
<RenderMessage key={index} message={message} />
|
||||||
))}
|
))}
|
||||||
|
@ -47,22 +49,26 @@ export const CustomEdge: React.FC<CustomEdgeProps> = ({
|
||||||
data,
|
data,
|
||||||
style = {},
|
style = {},
|
||||||
markerEnd,
|
markerEnd,
|
||||||
sourcePosition,
|
|
||||||
targetPosition,
|
|
||||||
}) => {
|
}) => {
|
||||||
const isSelfLoop = source === target;
|
const isSelfLoop = source === target;
|
||||||
|
|
||||||
|
// Keep stroke width scaling for message count but with a cleaner implementation
|
||||||
|
const baseStrokeWidth = (style.strokeWidth as number) || 1;
|
||||||
|
const messageCount = data.messages?.length || 0;
|
||||||
|
const finalStrokeWidth = isSelfLoop
|
||||||
|
? Math.max(baseStrokeWidth, 2)
|
||||||
|
: Math.min(Math.max(messageCount, 1), 5) * baseStrokeWidth;
|
||||||
|
|
||||||
let edgePath = "";
|
let edgePath = "";
|
||||||
let labelX = 0;
|
let labelX = 0;
|
||||||
let labelY = 0;
|
let labelY = 0;
|
||||||
|
|
||||||
if (isSelfLoop) {
|
if (isSelfLoop) {
|
||||||
const rightOffset = 120; // How far right the path extends
|
const rightOffset = 120;
|
||||||
const verticalOffset = sourceY - targetY; // Base vertical distance between handles
|
const verticalOffset = sourceY - targetY;
|
||||||
const verticalPadding = 6; // Extra padding above/below handles
|
const verticalPadding = 6;
|
||||||
const radius = 8; // Radius for rounded corners
|
const radius = 8;
|
||||||
|
|
||||||
// Start and end slightly beyond the handles using verticalPadding
|
|
||||||
edgePath = `
|
edgePath = `
|
||||||
M ${sourceX} ${targetY - verticalPadding}
|
M ${sourceX} ${targetY - verticalPadding}
|
||||||
L ${sourceX + rightOffset - radius} ${targetY - verticalPadding}
|
L ${sourceX + rightOffset - radius} ${targetY - verticalPadding}
|
||||||
|
@ -76,7 +82,6 @@ export const CustomEdge: React.FC<CustomEdgeProps> = ({
|
||||||
L ${sourceX} ${sourceY + verticalPadding}
|
L ${sourceX} ${sourceY + verticalPadding}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
// Adjust label position to account for padding
|
|
||||||
labelX = sourceX + rightOffset + 10;
|
labelX = sourceX + rightOffset + 10;
|
||||||
labelY = targetY + verticalOffset / 2;
|
labelY = targetY + verticalOffset / 2;
|
||||||
} else {
|
} else {
|
||||||
|
@ -88,6 +93,30 @@ export const CustomEdge: React.FC<CustomEdgeProps> = ({
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calculate label position with offset for bidirectional edges
|
||||||
|
const getLabelPosition = (x: number, y: number) => {
|
||||||
|
if (!data.routingType || isSelfLoop) return { x, y };
|
||||||
|
|
||||||
|
// Make vertical separation more pronounced
|
||||||
|
const verticalOffset = data.routingType === "secondary" ? -35 : 35; // Increased from 20 to 35
|
||||||
|
const horizontalOffset = data.routingType === "secondary" ? -25 : 25;
|
||||||
|
|
||||||
|
// Calculate edge angle to determine if it's more horizontal or vertical
|
||||||
|
const dx = targetX - sourceX;
|
||||||
|
const dy = targetY - sourceY;
|
||||||
|
const isMoreHorizontal = Math.abs(dx) > Math.abs(dy);
|
||||||
|
|
||||||
|
// Always apply some vertical offset
|
||||||
|
const basePosition = {
|
||||||
|
x: isMoreHorizontal ? x : x + horizontalOffset,
|
||||||
|
y: y + (data.routingType === "secondary" ? -35 : 35), // Always apply vertical offset
|
||||||
|
};
|
||||||
|
|
||||||
|
return basePosition;
|
||||||
|
};
|
||||||
|
|
||||||
|
const labelPosition = getLabelPosition(labelX, labelY);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<path
|
<path
|
||||||
|
@ -96,9 +125,7 @@ export const CustomEdge: React.FC<CustomEdgeProps> = ({
|
||||||
d={edgePath}
|
d={edgePath}
|
||||||
style={{
|
style={{
|
||||||
...style,
|
...style,
|
||||||
strokeWidth: isSelfLoop
|
strokeWidth: finalStrokeWidth,
|
||||||
? Math.max((style.strokeWidth as number) || 1, 2)
|
|
||||||
: style.strokeWidth,
|
|
||||||
}}
|
}}
|
||||||
markerEnd={markerEnd}
|
markerEnd={markerEnd}
|
||||||
/>
|
/>
|
||||||
|
@ -107,8 +134,10 @@ export const CustomEdge: React.FC<CustomEdgeProps> = ({
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
transform: `translate(-50%, -50%) translate(${labelX}px,${labelY}px)`,
|
transform: `translate(-50%, -50%) translate(${labelPosition.x}px,${labelPosition.y}px)`,
|
||||||
pointerEvents: "all",
|
pointerEvents: "all",
|
||||||
|
// Add a slight transition for smooth updates
|
||||||
|
transition: "transform 0.2s ease-in-out",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
|
@ -121,7 +150,12 @@ export const CustomEdge: React.FC<CustomEdgeProps> = ({
|
||||||
}
|
}
|
||||||
overlayStyle={{ maxWidth: "none" }}
|
overlayStyle={{ maxWidth: "none" }}
|
||||||
>
|
>
|
||||||
<div className="px-2 py-1 rounded bg-secondary bg-opacity-50 text-primary text-sm">
|
<div
|
||||||
|
className="px-2 py-1 rounded bg-secondary bg-opacity-50 text-primary text-sm"
|
||||||
|
style={{
|
||||||
|
whiteSpace: "nowrap", // Prevent label from wrapping
|
||||||
|
}}
|
||||||
|
>
|
||||||
{data.label}
|
{data.label}
|
||||||
</div>
|
</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|
|
@ -0,0 +1,140 @@
|
||||||
|
import React from "react";
|
||||||
|
import { Button, Tooltip, Dropdown } from "antd";
|
||||||
|
import type { MenuProps } from "antd";
|
||||||
|
import {
|
||||||
|
Maximize2,
|
||||||
|
Minimize2,
|
||||||
|
ArrowDown,
|
||||||
|
ArrowRight,
|
||||||
|
MessageSquareIcon,
|
||||||
|
MessageSquareOffIcon,
|
||||||
|
MoreHorizontal,
|
||||||
|
Grid,
|
||||||
|
Hash,
|
||||||
|
MessageSquare,
|
||||||
|
LayoutGrid,
|
||||||
|
RotateCcw,
|
||||||
|
} from "lucide-react";
|
||||||
|
import { useConfigStore } from "../../../../../hooks/store";
|
||||||
|
|
||||||
|
interface AgentFlowToolbarProps {
|
||||||
|
isFullscreen: boolean;
|
||||||
|
onToggleFullscreen: () => void;
|
||||||
|
onResetView?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const AgentFlowToolbar: React.FC<AgentFlowToolbarProps> = ({
|
||||||
|
isFullscreen,
|
||||||
|
onToggleFullscreen,
|
||||||
|
onResetView,
|
||||||
|
}) => {
|
||||||
|
const { agentFlow: settings, setAgentFlowSettings } = useConfigStore();
|
||||||
|
|
||||||
|
const toggleSetting = (setting: keyof typeof settings) => () => {
|
||||||
|
setAgentFlowSettings({
|
||||||
|
[setting]: !settings[setting],
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const menuItems: MenuProps["items"] = [
|
||||||
|
{
|
||||||
|
key: "grid",
|
||||||
|
label: "Show Grid",
|
||||||
|
icon: <Grid size={16} />,
|
||||||
|
onClick: toggleSetting("showGrid"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "tokens",
|
||||||
|
label: "Show Tokens",
|
||||||
|
icon: <Hash size={16} />,
|
||||||
|
onClick: toggleSetting("showTokens"),
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// key: "messages",
|
||||||
|
// label: "Show Messages",
|
||||||
|
// icon: <MessageSquare size={16} />,
|
||||||
|
// onClick: toggleSetting("showMessages"),
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
type: "divider",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "reset",
|
||||||
|
label: "Reset View",
|
||||||
|
icon: <RotateCcw size={16} />,
|
||||||
|
onClick: onResetView,
|
||||||
|
disabled: !onResetView,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="absolute top-2 right-2 bg-secondary bg-opacity-70 hover:bg-secondary rounded backdrop-blur-sm z-50">
|
||||||
|
<div className="p-1 flex items-center gap-1">
|
||||||
|
<Tooltip title={isFullscreen ? "Exit Fullscreen" : "Enter Fullscreen"}>
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
icon={
|
||||||
|
isFullscreen ? <Minimize2 size={18} /> : <Maximize2 size={18} />
|
||||||
|
}
|
||||||
|
className="p-1.5 hover:bg-primary/10 rounded-md text-primary/75 hover:text-primary"
|
||||||
|
onClick={onToggleFullscreen}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
|
||||||
|
<Tooltip
|
||||||
|
title={`Switch to ${
|
||||||
|
settings.direction === "TB" ? "Horizontal" : "Vertical"
|
||||||
|
} Layout`}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
icon={
|
||||||
|
settings.direction === "TB" ? (
|
||||||
|
<ArrowDown size={18} />
|
||||||
|
) : (
|
||||||
|
<ArrowRight size={18} />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
className="p-1.5 hover:bg-primary/10 rounded-md text-primary/75 hover:text-primary"
|
||||||
|
onClick={() =>
|
||||||
|
setAgentFlowSettings({
|
||||||
|
direction: settings.direction === "TB" ? "LR" : "TB",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
|
||||||
|
<Tooltip title={settings.showLabels ? "Hide Labels" : "Show Labels"}>
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
icon={
|
||||||
|
settings.showLabels ? (
|
||||||
|
<MessageSquareIcon size={18} />
|
||||||
|
) : (
|
||||||
|
<MessageSquareOffIcon size={18} />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
className="p-1.5 hover:bg-primary/10 rounded-md text-primary/75 hover:text-primary"
|
||||||
|
onClick={toggleSetting("showLabels")}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
|
||||||
|
<Dropdown
|
||||||
|
menu={{ items: menuItems }}
|
||||||
|
trigger={["click"]}
|
||||||
|
getPopupContainer={(triggerNode) =>
|
||||||
|
triggerNode.parentNode as HTMLElement
|
||||||
|
}
|
||||||
|
overlayStyle={{ zIndex: 1000 }}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
icon={<MoreHorizontal size={18} />}
|
||||||
|
className="p-1.5 hover:bg-primary/10 rounded-md text-primary/75 hover:text-primary"
|
||||||
|
title="More Options" // Use native title instead of Tooltip
|
||||||
|
/>
|
||||||
|
</Dropdown>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
|
@ -3,15 +3,18 @@ import { message } from "antd";
|
||||||
import { getServerUrl } from "../../../utils";
|
import { getServerUrl } from "../../../utils";
|
||||||
import { SessionManager } from "../../shared/session/manager";
|
import { SessionManager } from "../../shared/session/manager";
|
||||||
import { IStatus } from "../../../types/app";
|
import { IStatus } from "../../../types/app";
|
||||||
import { Message } from "../../../types/datamodel";
|
import {
|
||||||
|
Message,
|
||||||
|
ThreadStatus,
|
||||||
|
WebSocketMessage,
|
||||||
|
} from "../../../types/datamodel";
|
||||||
import { useConfigStore } from "../../../../hooks/store";
|
import { useConfigStore } from "../../../../hooks/store";
|
||||||
import { appContext } from "../../../../hooks/provider";
|
import { appContext } from "../../../../hooks/provider";
|
||||||
import ChatInput from "./chatinput";
|
import ChatInput from "./chatinput";
|
||||||
import { ModelUsage, SocketMessage, ThreadState, ThreadStatus } from "./types";
|
import { ModelUsage, ThreadState, TIMEOUT_CONFIG } from "./types";
|
||||||
import { MessageList } from "./messagelist";
|
import { MessageList } from "./messagelist";
|
||||||
import TeamManager from "../../shared/team/manager";
|
import TeamManager from "../../shared/team/manager";
|
||||||
import { teamAPI } from "../../shared/team/api";
|
import { teamAPI } from "../../shared/team/api";
|
||||||
import AgentFlow from "./agentflow/agentflow";
|
|
||||||
|
|
||||||
const logo = require("../../../../images/landing/welcome.svg").default;
|
const logo = require("../../../../images/landing/welcome.svg").default;
|
||||||
|
|
||||||
|
@ -31,12 +34,14 @@ export default function ChatView({
|
||||||
Record<string, ThreadState>
|
Record<string, ThreadState>
|
||||||
>({});
|
>({});
|
||||||
const chatContainerRef = React.useRef<HTMLDivElement>(null);
|
const chatContainerRef = React.useRef<HTMLDivElement>(null);
|
||||||
|
const timeoutRefs = React.useRef<Record<string, NodeJS.Timeout>>({});
|
||||||
|
|
||||||
const { user } = React.useContext(appContext);
|
const { user } = React.useContext(appContext);
|
||||||
const { session, sessions } = useConfigStore();
|
const { session, sessions } = useConfigStore();
|
||||||
const [activeSockets, setActiveSockets] = React.useState<
|
const [activeSockets, setActiveSockets] = React.useState<
|
||||||
Record<string, WebSocket>
|
Record<string, WebSocket>
|
||||||
>({});
|
>({});
|
||||||
|
const activeSocketsRef = React.useRef<Record<string, WebSocket>>({});
|
||||||
|
|
||||||
const [teamConfig, setTeamConfig] = React.useState<any>(null);
|
const [teamConfig, setTeamConfig] = React.useState<any>(null);
|
||||||
|
|
||||||
|
@ -58,12 +63,114 @@ export default function ChatView({
|
||||||
}
|
}
|
||||||
}, [session]);
|
}, [session]);
|
||||||
|
|
||||||
|
const updateSocket = (runId: string, socket: WebSocket | null) => {
|
||||||
|
if (socket) {
|
||||||
|
activeSocketsRef.current[runId] = socket;
|
||||||
|
setActiveSockets((prev) => ({ ...prev, [runId]: socket }));
|
||||||
|
} else {
|
||||||
|
delete activeSocketsRef.current[runId];
|
||||||
|
setActiveSockets((prev) => {
|
||||||
|
const next = { ...prev };
|
||||||
|
delete next[runId];
|
||||||
|
return next;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
return () => {
|
return () => {
|
||||||
Object.values(activeSockets).forEach((socket) => socket.close());
|
Object.values(activeSockets).forEach((socket) => socket.close());
|
||||||
};
|
};
|
||||||
}, [activeSockets]);
|
}, [activeSockets]);
|
||||||
|
|
||||||
|
const handleTimeoutForRun = (runId: string) => {
|
||||||
|
const socket = activeSocketsRef.current[runId];
|
||||||
|
if (socket && socket.readyState === WebSocket.OPEN) {
|
||||||
|
// Send stop message to backend, just like when user clicks stop
|
||||||
|
socket.send(
|
||||||
|
JSON.stringify({
|
||||||
|
type: "stop",
|
||||||
|
reason: TIMEOUT_CONFIG.DEFAULT_MESSAGE,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update thread state with timeout reason
|
||||||
|
setThreadMessages((prev) => {
|
||||||
|
const currentThread = prev[runId];
|
||||||
|
if (!currentThread) return prev;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...prev,
|
||||||
|
[runId]: {
|
||||||
|
...currentThread,
|
||||||
|
status: "cancelled", // Use existing cancelled status
|
||||||
|
reason: "Input request timed out after 3 minutes",
|
||||||
|
isExpanded: true,
|
||||||
|
inputRequest: currentThread.inputRequest
|
||||||
|
? {
|
||||||
|
prompt: currentThread.inputRequest.prompt,
|
||||||
|
isPending: true,
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
if (timeoutRefs.current[runId]) {
|
||||||
|
clearTimeout(timeoutRefs.current[runId]);
|
||||||
|
delete timeoutRefs.current[runId];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleInputResponse = async (runId: string, response: string) => {
|
||||||
|
// Clear timeout when response is received
|
||||||
|
if (timeoutRefs.current[runId]) {
|
||||||
|
clearTimeout(timeoutRefs.current[runId]);
|
||||||
|
delete timeoutRefs.current[runId];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response === "TIMEOUT") {
|
||||||
|
handleTimeoutForRun(runId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const socket = activeSockets[runId];
|
||||||
|
if (socket && socket.readyState === WebSocket.OPEN) {
|
||||||
|
try {
|
||||||
|
socket.send(
|
||||||
|
JSON.stringify({
|
||||||
|
type: "input_response",
|
||||||
|
response: response,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
setThreadMessages((prev) => ({
|
||||||
|
...prev,
|
||||||
|
[runId]: {
|
||||||
|
...prev[runId],
|
||||||
|
status: "streaming",
|
||||||
|
inputRequest: undefined,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error sending input response:", error);
|
||||||
|
message.error("Failed to send response");
|
||||||
|
|
||||||
|
setThreadMessages((prev) => ({
|
||||||
|
...prev,
|
||||||
|
[runId]: {
|
||||||
|
...prev[runId],
|
||||||
|
status: "error",
|
||||||
|
reason: "Failed to send input response",
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
message.error("Connection lost. Please try again.");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const getBaseUrl = (url: string): string => {
|
const getBaseUrl = (url: string): string => {
|
||||||
try {
|
try {
|
||||||
// Remove protocol (http:// or https://)
|
// Remove protocol (http:// or https://)
|
||||||
|
@ -91,7 +198,7 @@ export default function ChatView({
|
||||||
const createRun = async (sessionId: number): Promise<string> => {
|
const createRun = async (sessionId: number): Promise<string> => {
|
||||||
const payload = { session_id: sessionId, user_id: user?.email || "" };
|
const payload = { session_id: sessionId, user_id: user?.email || "" };
|
||||||
|
|
||||||
const response = await fetch(`${serverUrl}/runs`, {
|
const response = await fetch(`${serverUrl}/runs/`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
body: JSON.stringify(payload),
|
body: JSON.stringify(payload),
|
||||||
|
@ -128,40 +235,32 @@ export default function ChatView({
|
||||||
return await response.json();
|
return await response.json();
|
||||||
};
|
};
|
||||||
|
|
||||||
interface RequestUsage {
|
|
||||||
prompt_tokens: number;
|
|
||||||
completion_tokens: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
const connectWebSocket = (runId: string, query: string) => {
|
const connectWebSocket = (runId: string, query: string) => {
|
||||||
const baseUrl = getBaseUrl(serverUrl);
|
const baseUrl = getBaseUrl(serverUrl);
|
||||||
// Determine if we should use ws:// or wss:// based on current protocol
|
|
||||||
const wsProtocol = window.location.protocol === "https:" ? "wss:" : "ws:";
|
const wsProtocol = window.location.protocol === "https:" ? "wss:" : "ws:";
|
||||||
const wsUrl = `${wsProtocol}//${baseUrl}/api/ws/runs/${runId}`;
|
const wsUrl = `${wsProtocol}//${baseUrl}/api/ws/runs/${runId}`;
|
||||||
|
|
||||||
console.log("Connecting to WebSocket URL:", wsUrl); // For debugging
|
|
||||||
|
|
||||||
const socket = new WebSocket(wsUrl);
|
const socket = new WebSocket(wsUrl);
|
||||||
let isClosing = false;
|
let isClosing = false;
|
||||||
|
|
||||||
|
const clearTimeoutForRun = () => {
|
||||||
|
if (timeoutRefs.current[runId]) {
|
||||||
|
clearTimeout(timeoutRefs.current[runId]);
|
||||||
|
delete timeoutRefs.current[runId];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const closeSocket = () => {
|
const closeSocket = () => {
|
||||||
if (!isClosing && socket.readyState !== WebSocket.CLOSED) {
|
if (!isClosing && socket.readyState !== WebSocket.CLOSED) {
|
||||||
isClosing = true;
|
isClosing = true;
|
||||||
socket.close();
|
socket.close();
|
||||||
setActiveSockets((prev) => {
|
updateSocket(runId, null);
|
||||||
const newSockets = { ...prev };
|
|
||||||
delete newSockets[runId];
|
|
||||||
return newSockets;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
socket.onopen = async () => {
|
socket.onopen = async () => {
|
||||||
try {
|
try {
|
||||||
setActiveSockets((prev) => ({
|
updateSocket(runId, socket);
|
||||||
...prev,
|
|
||||||
[runId]: socket,
|
|
||||||
}));
|
|
||||||
|
|
||||||
setThreadMessages((prev) => ({
|
setThreadMessages((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
|
@ -187,13 +286,9 @@ export default function ChatView({
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
// Start the run only after socket is connected
|
|
||||||
await startRun(runId, query);
|
await startRun(runId, query);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error starting run:", error);
|
|
||||||
message.error("Failed to start run");
|
|
||||||
closeSocket();
|
closeSocket();
|
||||||
|
|
||||||
setThreadMessages((prev) => ({
|
setThreadMessages((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
[runId]: {
|
[runId]: {
|
||||||
|
@ -206,11 +301,32 @@ export default function ChatView({
|
||||||
};
|
};
|
||||||
|
|
||||||
socket.onmessage = (event) => {
|
socket.onmessage = (event) => {
|
||||||
const message: SocketMessage = JSON.parse(event.data);
|
const message: WebSocketMessage = JSON.parse(event.data);
|
||||||
// console.log("WebSocket message received:", message);
|
|
||||||
|
|
||||||
switch (message.type) {
|
switch (message.type) {
|
||||||
|
case "input_request":
|
||||||
|
clearTimeoutForRun();
|
||||||
|
|
||||||
|
timeoutRefs.current[runId] = setTimeout(() => {
|
||||||
|
handleTimeoutForRun(runId);
|
||||||
|
}, TIMEOUT_CONFIG.DURATION_MS);
|
||||||
|
|
||||||
|
setThreadMessages((prev) => ({
|
||||||
|
...prev,
|
||||||
|
[runId]: {
|
||||||
|
...prev[runId],
|
||||||
|
status: "awaiting_input",
|
||||||
|
inputRequest: {
|
||||||
|
prompt: message.data?.content || "",
|
||||||
|
isPending: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
break;
|
||||||
|
|
||||||
case "message":
|
case "message":
|
||||||
|
clearTimeoutForRun();
|
||||||
|
|
||||||
setThreadMessages((prev) => {
|
setThreadMessages((prev) => {
|
||||||
const currentThread = prev[runId] || {
|
const currentThread = prev[runId] || {
|
||||||
messages: [],
|
messages: [],
|
||||||
|
@ -227,17 +343,18 @@ export default function ChatView({
|
||||||
}
|
}
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
const newMessage = {
|
|
||||||
source: message.data?.source || "",
|
|
||||||
content: message.data?.content || "",
|
|
||||||
models_usage,
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...prev,
|
...prev,
|
||||||
[runId]: {
|
[runId]: {
|
||||||
...currentThread,
|
...currentThread,
|
||||||
messages: [...currentThread.messages, newMessage],
|
messages: [
|
||||||
|
...currentThread.messages,
|
||||||
|
{
|
||||||
|
source: message.data?.source || "",
|
||||||
|
content: message.data?.content || "",
|
||||||
|
models_usage,
|
||||||
|
},
|
||||||
|
],
|
||||||
status: "streaming",
|
status: "streaming",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -246,30 +363,27 @@ export default function ChatView({
|
||||||
|
|
||||||
case "result":
|
case "result":
|
||||||
case "completion":
|
case "completion":
|
||||||
|
clearTimeoutForRun();
|
||||||
|
|
||||||
setThreadMessages((prev) => {
|
setThreadMessages((prev) => {
|
||||||
const currentThread = prev[runId];
|
const currentThread = prev[runId];
|
||||||
if (!currentThread) return prev;
|
if (!currentThread) return prev;
|
||||||
|
|
||||||
const finalMessage = message.data?.task_result?.messages
|
|
||||||
?.filter((msg: any) => msg.content !== "TERMINATE")
|
|
||||||
.pop();
|
|
||||||
|
|
||||||
const status: ThreadStatus = message.status || "complete";
|
const status: ThreadStatus = message.status || "complete";
|
||||||
// Capture completion reason from task_result
|
|
||||||
const reason =
|
const reason =
|
||||||
message.data?.task_result?.stop_reason ||
|
message.data?.task_result?.stop_reason ||
|
||||||
(message.error ? `Error: ${message.error}` : undefined);
|
(message.error ? `Error: ${message.error}` : undefined);
|
||||||
console.log("All Messages", currentThread.messages);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...prev,
|
...prev,
|
||||||
[runId]: {
|
[runId]: {
|
||||||
...currentThread,
|
...currentThread,
|
||||||
status: status,
|
status,
|
||||||
reason: reason,
|
reason,
|
||||||
isExpanded: true,
|
isExpanded: true,
|
||||||
finalResult: finalMessage,
|
finalResult: message.data?.task_result?.messages
|
||||||
messages: currentThread.messages,
|
?.filter((msg: any) => msg.content !== "TERMINATE")
|
||||||
|
.pop(),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
@ -279,16 +393,10 @@ export default function ChatView({
|
||||||
};
|
};
|
||||||
|
|
||||||
socket.onclose = (event) => {
|
socket.onclose = (event) => {
|
||||||
console.log(
|
clearTimeoutForRun();
|
||||||
`WebSocket closed for run ${runId}. Code: ${event.code}, Reason: ${event.reason}`
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!isClosing) {
|
if (!isClosing) {
|
||||||
setActiveSockets((prev) => {
|
updateSocket(runId, null);
|
||||||
const newSockets = { ...prev };
|
|
||||||
delete newSockets[runId];
|
|
||||||
return newSockets;
|
|
||||||
});
|
|
||||||
|
|
||||||
setThreadMessages((prev) => {
|
setThreadMessages((prev) => {
|
||||||
const thread = prev[runId];
|
const thread = prev[runId];
|
||||||
|
@ -297,7 +405,10 @@ export default function ChatView({
|
||||||
...prev,
|
...prev,
|
||||||
[runId]: {
|
[runId]: {
|
||||||
...thread,
|
...thread,
|
||||||
status: "complete",
|
status:
|
||||||
|
event.code === TIMEOUT_CONFIG.WEBSOCKET_CODE
|
||||||
|
? "timeout"
|
||||||
|
: "complete",
|
||||||
reason: event.reason || "Connection closed",
|
reason: event.reason || "Connection closed",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -308,8 +419,7 @@ export default function ChatView({
|
||||||
};
|
};
|
||||||
|
|
||||||
socket.onerror = (error) => {
|
socket.onerror = (error) => {
|
||||||
console.error("WebSocket error:", error);
|
clearTimeoutForRun();
|
||||||
message.error("WebSocket connection error");
|
|
||||||
|
|
||||||
setThreadMessages((prev) => {
|
setThreadMessages((prev) => {
|
||||||
const thread = prev[runId];
|
const thread = prev[runId];
|
||||||
|
@ -335,7 +445,9 @@ export default function ChatView({
|
||||||
const cancelRun = async (runId: string) => {
|
const cancelRun = async (runId: string) => {
|
||||||
const socket = activeSockets[runId];
|
const socket = activeSockets[runId];
|
||||||
if (socket && socket.readyState === WebSocket.OPEN) {
|
if (socket && socket.readyState === WebSocket.OPEN) {
|
||||||
socket.send(JSON.stringify({ type: "stop" }));
|
socket.send(
|
||||||
|
JSON.stringify({ type: "stop", reason: "Cancelled by user" })
|
||||||
|
);
|
||||||
|
|
||||||
setThreadMessages((prev) => ({
|
setThreadMessages((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
|
@ -349,6 +461,16 @@ export default function ChatView({
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Clean up timeouts when component unmounts
|
||||||
|
React.useEffect(() => {
|
||||||
|
return () => {
|
||||||
|
Object.entries(timeoutRefs.current).forEach(([_, timeout]) =>
|
||||||
|
clearTimeout(timeout)
|
||||||
|
);
|
||||||
|
timeoutRefs.current = {};
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
const runTask = async (query: string) => {
|
const runTask = async (query: string) => {
|
||||||
setError(null);
|
setError(null);
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
@ -429,7 +551,7 @@ export default function ChatView({
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col h-full">
|
<div className="flex flex-col h-full">
|
||||||
<div
|
<div
|
||||||
className="flex-1 overflow-y-auto scroll relative min-h-0"
|
className="flex-1 overflow-y-auto scroll mt-2 relative min-h-0"
|
||||||
ref={chatContainerRef}
|
ref={chatContainerRef}
|
||||||
>
|
>
|
||||||
<MessageList
|
<MessageList
|
||||||
|
@ -438,12 +560,13 @@ export default function ChatView({
|
||||||
setThreadMessages={setThreadMessages}
|
setThreadMessages={setThreadMessages}
|
||||||
onRetry={runTask}
|
onRetry={runTask}
|
||||||
onCancel={cancelRun}
|
onCancel={cancelRun}
|
||||||
|
onInputResponse={handleInputResponse} // Add the new prop
|
||||||
loading={loading}
|
loading={loading}
|
||||||
teamConfig={teamConfig}
|
teamConfig={teamConfig}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{sessions && sessions?.length === 0 ? (
|
{sessions !== null && sessions?.length === 0 ? (
|
||||||
<div className="flex h-[calc(100%-100px)] flex-col items-center justify-center w-full">
|
<div className="flex h-[calc(100%-100px)] flex-col items-center justify-center w-full">
|
||||||
<div className="mt-4 text-sm text-secondary text-center">
|
<div className="mt-4 text-sm text-secondary text-center">
|
||||||
<img src={logo} alt="Welcome" className="w-72 h-72 mb-4" />
|
<img src={logo} alt="Welcome" className="w-72 h-72 mb-4" />
|
||||||
|
@ -454,7 +577,14 @@ export default function ChatView({
|
||||||
<>
|
<>
|
||||||
{session && (
|
{session && (
|
||||||
<div className="flex-shrink-0">
|
<div className="flex-shrink-0">
|
||||||
<ChatInput onSubmit={runTask} loading={loading} error={error} />
|
<ChatInput
|
||||||
|
onSubmit={runTask}
|
||||||
|
loading={loading}
|
||||||
|
error={error}
|
||||||
|
disabled={Object.values(threadMessages).some(
|
||||||
|
(thread) => thread.status === "awaiting_input"
|
||||||
|
)} // Disable input while waiting for user input
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -12,17 +12,21 @@ interface ChatInputProps {
|
||||||
onSubmit: (text: string) => void;
|
onSubmit: (text: string) => void;
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
error: IStatus | null;
|
error: IStatus | null;
|
||||||
|
disabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function ChatInput({
|
export default function ChatInput({
|
||||||
onSubmit,
|
onSubmit,
|
||||||
loading,
|
loading,
|
||||||
error,
|
error,
|
||||||
|
disabled = false,
|
||||||
}: ChatInputProps) {
|
}: ChatInputProps) {
|
||||||
const textAreaRef = React.useRef<HTMLTextAreaElement>(null);
|
const textAreaRef = React.useRef<HTMLTextAreaElement>(null);
|
||||||
const [previousLoading, setPreviousLoading] = React.useState(loading);
|
const [previousLoading, setPreviousLoading] = React.useState(loading);
|
||||||
const [text, setText] = React.useState("");
|
const [text, setText] = React.useState("");
|
||||||
|
|
||||||
const textAreaDefaultHeight = "64px";
|
const textAreaDefaultHeight = "64px";
|
||||||
|
const isInputDisabled = disabled || loading;
|
||||||
|
|
||||||
// Handle textarea auto-resize
|
// Handle textarea auto-resize
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
|
@ -54,10 +58,9 @@ export default function ChatInput({
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSubmit = () => {
|
const handleSubmit = () => {
|
||||||
if (textAreaRef.current?.value && !loading) {
|
if (textAreaRef.current?.value && !isInputDisabled) {
|
||||||
const query = textAreaRef.current.value;
|
const query = textAreaRef.current.value;
|
||||||
onSubmit(query);
|
onSubmit(query);
|
||||||
// Don't reset immediately - wait for response to complete
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -72,7 +75,7 @@ export default function ChatInput({
|
||||||
<div className="mt-2 w-full">
|
<div className="mt-2 w-full">
|
||||||
<div
|
<div
|
||||||
className={`mt-2 rounded shadow-sm flex mb-1 ${
|
className={`mt-2 rounded shadow-sm flex mb-1 ${
|
||||||
loading ? "opacity-50 pointer-events-none" : ""
|
isInputDisabled ? "opacity-50" : ""
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<form
|
<form
|
||||||
|
@ -89,31 +92,31 @@ export default function ChatInput({
|
||||||
defaultValue={"what is the height of the eiffel tower"}
|
defaultValue={"what is the height of the eiffel tower"}
|
||||||
onChange={handleTextChange}
|
onChange={handleTextChange}
|
||||||
onKeyDown={handleKeyDown}
|
onKeyDown={handleKeyDown}
|
||||||
className="flex items-center w-full resize-none text-gray-600 rounded border border-accent bg-white p-2 pl-5 pr-16"
|
className={`flex items-center w-full resize-none text-gray-600 rounded border border-accent bg-white p-2 pl-5 pr-16 ${
|
||||||
|
isInputDisabled ? "cursor-not-allowed" : ""
|
||||||
|
}`}
|
||||||
style={{
|
style={{
|
||||||
maxHeight: "120px",
|
maxHeight: "120px",
|
||||||
overflowY: "auto",
|
overflowY: "auto",
|
||||||
minHeight: "50px",
|
minHeight: "50px",
|
||||||
}}
|
}}
|
||||||
placeholder="Type your message here..."
|
placeholder="Type your message here..."
|
||||||
disabled={loading}
|
disabled={isInputDisabled}
|
||||||
/>
|
/>
|
||||||
<div
|
<button
|
||||||
role="button"
|
type="button"
|
||||||
onClick={handleSubmit}
|
onClick={handleSubmit}
|
||||||
style={{ width: "45px", height: "35px" }}
|
disabled={isInputDisabled}
|
||||||
className="absolute right-3 bottom-2 bg-accent hover:brightness-75 transition duration-300 rounded cursor-pointer flex justify-center items-center"
|
className={`absolute right-3 bottom-2 bg-accent transition duration-300 rounded flex justify-center items-center w-11 h-9 ${
|
||||||
|
isInputDisabled ? "cursor-not-allowed" : "hover:brightness-75"
|
||||||
|
}`}
|
||||||
>
|
>
|
||||||
{!loading ? (
|
{loading ? (
|
||||||
<div className="inline-block">
|
|
||||||
<PaperAirplaneIcon className="h-6 w-6 text-white" />
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div className="inline-block">
|
|
||||||
<Cog6ToothIcon className="text-white animate-spin rounded-full h-6 w-6" />
|
<Cog6ToothIcon className="text-white animate-spin rounded-full h-6 w-6" />
|
||||||
</div>
|
) : (
|
||||||
|
<PaperAirplaneIcon className="h-6 w-6 text-white" />
|
||||||
)}
|
)}
|
||||||
</div>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -14,9 +14,12 @@ import {
|
||||||
Loader2,
|
Loader2,
|
||||||
CheckCircle,
|
CheckCircle,
|
||||||
AlertTriangle,
|
AlertTriangle,
|
||||||
|
TriangleAlertIcon,
|
||||||
|
GroupIcon,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import AgentFlow from "./agentflow/agentflow";
|
import AgentFlow from "./agentflow/agentflow";
|
||||||
import ThreadView from "./threadview";
|
import ThreadView from "./threadview";
|
||||||
|
import LoadingDots from "../../shared/atoms";
|
||||||
|
|
||||||
interface MessageListProps {
|
interface MessageListProps {
|
||||||
messages: Message[];
|
messages: Message[];
|
||||||
|
@ -26,6 +29,7 @@ interface MessageListProps {
|
||||||
>;
|
>;
|
||||||
onRetry: (content: string) => void;
|
onRetry: (content: string) => void;
|
||||||
onCancel: (runId: string) => void;
|
onCancel: (runId: string) => void;
|
||||||
|
onInputResponse: (runId: string, response: string) => void;
|
||||||
loading?: boolean;
|
loading?: boolean;
|
||||||
teamConfig?: TeamConfig;
|
teamConfig?: TeamConfig;
|
||||||
}
|
}
|
||||||
|
@ -41,6 +45,7 @@ export const MessageList: React.FC<MessageListProps> = ({
|
||||||
setThreadMessages,
|
setThreadMessages,
|
||||||
onRetry,
|
onRetry,
|
||||||
onCancel,
|
onCancel,
|
||||||
|
onInputResponse, // New prop
|
||||||
loading = false,
|
loading = false,
|
||||||
teamConfig,
|
teamConfig,
|
||||||
}) => {
|
}) => {
|
||||||
|
@ -75,7 +80,7 @@ export const MessageList: React.FC<MessageListProps> = ({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, [threadMessages]); // This will trigger when any thread messages update
|
}, [threadMessages]);
|
||||||
|
|
||||||
const toggleThread = (runId: string) => {
|
const toggleThread = (runId: string) => {
|
||||||
setThreadMessages((prev) => ({
|
setThreadMessages((prev) => ({
|
||||||
|
@ -107,21 +112,43 @@ export const MessageList: React.FC<MessageListProps> = ({
|
||||||
size={20}
|
size={20}
|
||||||
className="inline-block mr-1 text-accent animate-spin"
|
className="inline-block mr-1 text-accent animate-spin"
|
||||||
/>{" "}
|
/>{" "}
|
||||||
Processing ...
|
<span className="inline-block mr-2">Processing</span>{" "}
|
||||||
|
<LoadingDots size={8} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
case "awaiting_input": // New status
|
||||||
|
return (
|
||||||
|
<div className="text-sm mb-2">
|
||||||
|
<MessageSquare
|
||||||
|
size={20}
|
||||||
|
className="inline-block mr-1 text-accent"
|
||||||
|
/>{" "}
|
||||||
|
Waiting for your input
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
case "complete":
|
case "complete":
|
||||||
return (
|
return (
|
||||||
<CheckCircle size={20} className="inline-block mr-1 text-accent" />
|
<div className="text-sm mb-2">
|
||||||
|
<CheckCircle size={20} className="inline-block mr-1 text-accent" />{" "}
|
||||||
|
Task completed
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
case "error":
|
case "error":
|
||||||
return (
|
return (
|
||||||
<AlertTriangle size={20} className="inline-block mr-1 text-red-500" />
|
<div className="text-sm mb-2">
|
||||||
|
<AlertTriangle
|
||||||
|
size={20}
|
||||||
|
className="inline-block mr-1 text-red-500"
|
||||||
|
/>{" "}
|
||||||
|
An error occurred.
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
case "cancelled":
|
case "cancelled":
|
||||||
return (
|
return (
|
||||||
<StopCircle size={20} className="inline-block mr-1 text-red-500" />
|
<div className="text-sm mb-2">
|
||||||
|
<StopCircle size={20} className="inline-block mr-1 text-red-500" />{" "}
|
||||||
|
Task was cancelled.
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
|
@ -135,26 +162,51 @@ export const MessageList: React.FC<MessageListProps> = ({
|
||||||
const thread = threadMessages[botMessage.run_id];
|
const thread = threadMessages[botMessage.run_id];
|
||||||
const hasThread = thread && thread.messages.length > 0;
|
const hasThread = thread && thread.messages.length > 0;
|
||||||
const isStreaming = thread?.status === "streaming";
|
const isStreaming = thread?.status === "streaming";
|
||||||
|
const isAwaitingInput = thread?.status === "awaiting_input"; // New check
|
||||||
|
|
||||||
|
const isFirstMessage = pairIndex === 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={`pair-${botMessage.run_id}`} className="space-y-6">
|
<div key={`pair-${botMessage.run_id}`} className="space-y-6">
|
||||||
{/* User message - first */}
|
{/* User message */}
|
||||||
|
{
|
||||||
|
<div
|
||||||
|
className={`${
|
||||||
|
isFirstMessage ? "mb-2" : "mt-8"
|
||||||
|
} mb-4 pt-2 border-t border-dashed border-secondary`}
|
||||||
|
>
|
||||||
|
{/* <div>Task Run 1. </div> */}
|
||||||
|
<div className="text-xs text-secondary">
|
||||||
|
Run {pairIndex + 1}
|
||||||
|
{!isFirstMessage && (
|
||||||
|
<>
|
||||||
|
{" "}
|
||||||
|
|{" "}
|
||||||
|
<TriangleAlertIcon className="w-4 h-4 -mt-1 inline-block mr-1 ml-1" />{" "}
|
||||||
|
Note: Each run does not share data with previous runs in
|
||||||
|
the same session yet.{" "}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
<div className="flex flex-col items-end">
|
<div className="flex flex-col items-end">
|
||||||
<div className="flex items-center gap-2 mb-1">
|
<div className="flex items-center gap-2 mb-1">
|
||||||
<span className="text-sm font-medium text-primary">User</span>
|
<span className="text-sm font-medium text-primary">You</span>
|
||||||
<div className="p-1.5 rounded bg-secondary text-accent">
|
<div className="p-1.5 rounded bg-secondary text-accent">
|
||||||
<User size={20} />
|
<User size={20} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-[95%]">
|
<div className="w-full">
|
||||||
<RenderMessage message={userMessage.config} isLast={false} />
|
<RenderMessage message={userMessage.config} isLast={false} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* Team response - second */}
|
|
||||||
|
{/* Team response */}
|
||||||
<div className="flex flex-col items-start">
|
<div className="flex flex-col items-start">
|
||||||
<div className="flex items-center gap-2 mb-1">
|
<div className="flex items-center gap-2 mb-1">
|
||||||
<div className="p-1.5 rounded bg-secondary text-primary">
|
<div className="p-1.5 rounded bg-secondary text-primary">
|
||||||
<Network size={20} />
|
<GroupIcon size={20} />
|
||||||
</div>
|
</div>
|
||||||
<span className="text-sm font-medium text-primary">
|
<span className="text-sm font-medium text-primary">
|
||||||
Agent Team
|
Agent Team
|
||||||
|
@ -162,18 +214,18 @@ export const MessageList: React.FC<MessageListProps> = ({
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Main response container */}
|
{/* Main response container */}
|
||||||
<div className="w-[95%]">
|
<div className="w-full">
|
||||||
<div className="p-4 bg-secondary border border-secondary rounded-lg">
|
<div className="p-4 bg-tertiary bordder border-secondary rounded">
|
||||||
<div className="text-primary">
|
<div className="text-primary">
|
||||||
{getStatusIcon(thread?.status)}{" "}
|
{getStatusIcon(thread?.status)}{" "}
|
||||||
{thread?.finalResult?.content}
|
{!isAwaitingInput && thread?.finalResult?.content}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Thread section with left border for hierarchy */}
|
{/* Thread section */}
|
||||||
{hasThread && (
|
{hasThread && (
|
||||||
<div className="mt-2 pl-4 border-l-2 border-secondary/30">
|
<div className="mt-2 pl-4 border-l-2 border-secondary/30">
|
||||||
<div className="flex">
|
<div className="flex pt-2">
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<button
|
<button
|
||||||
onClick={() => toggleThread(botMessage.run_id)}
|
onClick={() => toggleThread(botMessage.run_id)}
|
||||||
|
@ -195,13 +247,13 @@ export const MessageList: React.FC<MessageListProps> = ({
|
||||||
|
|
||||||
<div className="flex flex-row gap-4">
|
<div className="flex flex-row gap-4">
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
{" "}
|
|
||||||
{thread.isExpanded && (
|
{thread.isExpanded && (
|
||||||
<ThreadView
|
<ThreadView
|
||||||
thread={thread}
|
thread={thread}
|
||||||
isStreaming={isStreaming}
|
isStreaming={isStreaming}
|
||||||
runId={botMessage.run_id}
|
runId={botMessage.run_id}
|
||||||
onCancel={onCancel}
|
onCancel={onCancel}
|
||||||
|
onInputResponse={onInputResponse} // Pass through the new prop
|
||||||
threadContainerRef={(el) =>
|
threadContainerRef={(el) =>
|
||||||
(threadContainerRefs.current[botMessage.run_id] =
|
(threadContainerRefs.current[botMessage.run_id] =
|
||||||
el)
|
el)
|
||||||
|
@ -214,7 +266,7 @@ export const MessageList: React.FC<MessageListProps> = ({
|
||||||
<AgentFlow
|
<AgentFlow
|
||||||
teamConfig={teamConfig}
|
teamConfig={teamConfig}
|
||||||
messages={thread.messages}
|
messages={thread.messages}
|
||||||
threadState={thread} // Add this prop
|
threadState={thread}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -228,9 +280,8 @@ export const MessageList: React.FC<MessageListProps> = ({
|
||||||
})}
|
})}
|
||||||
|
|
||||||
{messages.length === 0 && !loading && (
|
{messages.length === 0 && !loading && (
|
||||||
<div className="text-center text-secondary h-full ">
|
<div className="text-center text-secondary h-full">
|
||||||
{/* <img src={landing} alt="No messages" /> */}
|
<div className="text-sm mt-4">Send a message to begin!</div>
|
||||||
<div className="text-sm mt-4"> Send a message to begin! </div>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,39 +1,238 @@
|
||||||
import React from "react";
|
import React, { useEffect, useRef } from "react";
|
||||||
import { StopCircle } from "lucide-react";
|
import {
|
||||||
import { ThreadState } from "./types";
|
StopCircle,
|
||||||
import { AgentMessageConfig } from "../../../types/datamodel";
|
SendHorizontal,
|
||||||
|
Loader2,
|
||||||
|
Clock,
|
||||||
|
AlertTriangle,
|
||||||
|
MessageSquare,
|
||||||
|
CheckCircle,
|
||||||
|
} from "lucide-react";
|
||||||
|
import { ThreadState, TIMEOUT_CONFIG } from "./types";
|
||||||
import { RenderMessage } from "./rendermessage";
|
import { RenderMessage } from "./rendermessage";
|
||||||
|
import LoadingDots from "../../shared/atoms";
|
||||||
|
|
||||||
interface ThreadViewProps {
|
interface ThreadViewProps {
|
||||||
thread: ThreadState;
|
thread: ThreadState;
|
||||||
isStreaming: boolean;
|
isStreaming: boolean;
|
||||||
runId: string;
|
runId: string;
|
||||||
onCancel: (runId: string) => void;
|
onCancel: (runId: string) => void;
|
||||||
|
onInputResponse: (runId: string, response: string) => void;
|
||||||
threadContainerRef: (el: HTMLDivElement | null) => void;
|
threadContainerRef: (el: HTMLDivElement | null) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface InputRequestProps {
|
||||||
|
prompt: string;
|
||||||
|
onSubmit: (response: string) => void;
|
||||||
|
disabled?: boolean;
|
||||||
|
onTimeout?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const InputRequestView: React.FC<InputRequestProps> = ({
|
||||||
|
prompt,
|
||||||
|
onSubmit,
|
||||||
|
disabled = false,
|
||||||
|
onTimeout,
|
||||||
|
}) => {
|
||||||
|
const [response, setResponse] = React.useState("");
|
||||||
|
const [isSubmitting, setIsSubmitting] = React.useState(false);
|
||||||
|
const [timeLeft, setTimeLeft] = React.useState(TIMEOUT_CONFIG.DURATION_SEC);
|
||||||
|
const [hasInteracted, setHasInteracted] = React.useState(false);
|
||||||
|
const inputRef = React.useRef<HTMLInputElement>(null);
|
||||||
|
const timerRef = useRef<NodeJS.Timeout>();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!disabled) {
|
||||||
|
timerRef.current = setInterval(() => {
|
||||||
|
setTimeLeft((prev) => {
|
||||||
|
if (prev <= 1) {
|
||||||
|
clearInterval(timerRef.current);
|
||||||
|
onTimeout?.();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return prev - 1;
|
||||||
|
});
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (timerRef.current) {
|
||||||
|
clearInterval(timerRef.current);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, [disabled, onTimeout]);
|
||||||
|
|
||||||
|
// Auto-focus effect
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (inputRef.current && !disabled) {
|
||||||
|
inputRef.current.focus();
|
||||||
|
}
|
||||||
|
}, [disabled]);
|
||||||
|
|
||||||
|
const formatTime = (seconds: number): string => {
|
||||||
|
const mins = Math.floor(seconds / 60);
|
||||||
|
const secs = seconds % 60;
|
||||||
|
return `${mins}:${secs.toString().padStart(2, "0")}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
if (!response.trim() || disabled || isSubmitting) return;
|
||||||
|
|
||||||
|
setIsSubmitting(true);
|
||||||
|
try {
|
||||||
|
await onSubmit(response.trim());
|
||||||
|
setResponse("");
|
||||||
|
setHasInteracted(false);
|
||||||
|
} finally {
|
||||||
|
setIsSubmitting(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleKeyDown = (e: React.KeyboardEvent) => {
|
||||||
|
if (e.key === "Enter" && !e.shiftKey) {
|
||||||
|
e.preventDefault();
|
||||||
|
handleSubmit();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setResponse(e.target.value);
|
||||||
|
if (!hasInteracted) {
|
||||||
|
setHasInteracted(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getTimeoutWarningClass = () => {
|
||||||
|
if (timeLeft < TIMEOUT_CONFIG.WARNING_THRESHOLD_SEC) {
|
||||||
|
return "text-red-500 font-bold animate-pulse";
|
||||||
|
}
|
||||||
|
return "text-accent";
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={`p-4 bg-accent/10 border border-accent/20 rounded-lg mt-3 ${
|
||||||
|
disabled ? "opacity-50" : ""
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<div className="flex justify-between items-center mb-2">
|
||||||
|
<div className="text-sm font-medium text-primary flex items-center gap-2">
|
||||||
|
{prompt}
|
||||||
|
{!hasInteracted && !disabled && (
|
||||||
|
<span className="relative flex h-3 w-3">
|
||||||
|
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-accent opacity-75"></span>
|
||||||
|
<span className="relative inline-flex rounded-full h-3 w-3 bg-accent"></span>
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{!disabled && (
|
||||||
|
<div className="flex items-center gap-2 text-sm">
|
||||||
|
<Clock size={14} className="text-accent" />
|
||||||
|
<span className={getTimeoutWarningClass()}>
|
||||||
|
{formatTime(timeLeft)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<input
|
||||||
|
ref={inputRef}
|
||||||
|
type="text"
|
||||||
|
value={response}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
onKeyDown={handleKeyDown}
|
||||||
|
disabled={disabled || isSubmitting}
|
||||||
|
className="flex-1 px-3 py-2 rounded bg-background border border-secondary focus:border-accent focus:ring-1 focus:ring-accent outline-none disabled:opacity-50"
|
||||||
|
placeholder={
|
||||||
|
disabled
|
||||||
|
? "Input timeout - please restart the conversation"
|
||||||
|
: "Type your response..."
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
onClick={handleSubmit}
|
||||||
|
disabled={disabled || isSubmitting || !response.trim()}
|
||||||
|
className={`px-4 py-2 rounded bg-accent text-white hover:bg-accent/90 disabled:opacity-50 disabled:hover:bg-accent flex items-center gap-2 transition-all ${
|
||||||
|
!hasInteracted && !disabled && !response.trim()
|
||||||
|
? "animate-pulse"
|
||||||
|
: ""
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{isSubmitting ? (
|
||||||
|
<Loader2 size={16} className="animate-spin" />
|
||||||
|
) : (
|
||||||
|
<SendHorizontal size={16} />
|
||||||
|
)}
|
||||||
|
<span>Submit</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const ThreadView: React.FC<ThreadViewProps> = ({
|
const ThreadView: React.FC<ThreadViewProps> = ({
|
||||||
thread,
|
thread,
|
||||||
isStreaming,
|
isStreaming,
|
||||||
runId,
|
runId,
|
||||||
onCancel,
|
onCancel,
|
||||||
|
onInputResponse,
|
||||||
threadContainerRef,
|
threadContainerRef,
|
||||||
}) => {
|
}) => {
|
||||||
|
const isAwaitingInput = thread.status === "awaiting_input";
|
||||||
|
const isTimedOut = thread.status === "timeout";
|
||||||
|
|
||||||
|
const getStatusIcon = () => {
|
||||||
|
switch (thread.status) {
|
||||||
|
case "streaming":
|
||||||
|
return <Loader2 size={16} className="animate-spin text-accent" />;
|
||||||
|
case "awaiting_input":
|
||||||
|
return <MessageSquare size={16} className="text-accent" />;
|
||||||
|
case "complete":
|
||||||
|
return <CheckCircle size={16} className="text-accent" />;
|
||||||
|
case "error":
|
||||||
|
return <AlertTriangle size={16} className="text-red-500" />;
|
||||||
|
case "timeout":
|
||||||
|
return <Clock size={16} className="text-red-500" />;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getStatusText = () => {
|
||||||
|
if (isStreaming) {
|
||||||
return (
|
return (
|
||||||
<div className="mt-2 border border-secondary rounded bg-primary">
|
|
||||||
{/* Status bar - fixed at top */}
|
|
||||||
<div className="sticky top-0 z-10 flex bg-primary rounded-t items-center justify-between p-3 border-b border-secondary bg-secondary/10">
|
|
||||||
<div className="text-sm text-primary">
|
|
||||||
{isStreaming ? (
|
|
||||||
"Agents discussing..."
|
|
||||||
) : (
|
|
||||||
<>
|
<>
|
||||||
<span className="font-semibold mr-2">Stop Reason</span>
|
<span className="inline-block mr-2">Agents working</span>
|
||||||
|
<LoadingDots size={8} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (isAwaitingInput) return "Waiting for your input";
|
||||||
|
if (isTimedOut) return TIMEOUT_CONFIG.DEFAULT_MESSAGE;
|
||||||
|
if (thread.reason)
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<span className="font-semibold mr-2">Stop Reason:</span>
|
||||||
{thread.reason}
|
{thread.reason}
|
||||||
</>
|
</>
|
||||||
)}
|
);
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTimeout = () => {
|
||||||
|
if (thread.inputRequest) {
|
||||||
|
onInputResponse(runId, "TIMEOUT");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="mt-2 border border-secondary rounded bg-primary">
|
||||||
|
<div className="sticky top-0 z-10 flex bg-primary rounded-t items-center justify-between p-3 border-b border-secondary bg-secondary/10">
|
||||||
|
<div className="text-sm text-primary flex items-center gap-2">
|
||||||
|
{getStatusIcon()}
|
||||||
|
{getStatusText()}
|
||||||
</div>
|
</div>
|
||||||
{isStreaming && (
|
{(isStreaming || isAwaitingInput) && (
|
||||||
<button
|
<button
|
||||||
onClick={() => onCancel(runId)}
|
onClick={() => onCancel(runId)}
|
||||||
className="flex items-center gap-1 px-3 py-1 rounded bg-red-500 hover:bg-red-600 text-white text-xs font-medium transition-colors"
|
className="flex items-center gap-1 px-3 py-1 rounded bg-red-500 hover:bg-red-600 text-white text-xs font-medium transition-colors"
|
||||||
|
@ -44,7 +243,6 @@ const ThreadView: React.FC<ThreadViewProps> = ({
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Thread messages and flow visualization in tabs */}
|
|
||||||
<div
|
<div
|
||||||
ref={threadContainerRef}
|
ref={threadContainerRef}
|
||||||
className="max-h-[400px] overflow-y-auto scroll"
|
className="max-h-[400px] overflow-y-auto scroll"
|
||||||
|
@ -58,6 +256,15 @@ const ThreadView: React.FC<ThreadViewProps> = ({
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
|
{thread.inputRequest && (
|
||||||
|
<InputRequestView
|
||||||
|
prompt={thread.inputRequest.prompt}
|
||||||
|
onSubmit={(response) => onInputResponse(runId, response)}
|
||||||
|
disabled={!isAwaitingInput || isTimedOut}
|
||||||
|
onTimeout={handleTimeout}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,22 +1,21 @@
|
||||||
import { Message, TaskResult } from "../../../types/datamodel";
|
import {
|
||||||
|
AgentMessageConfig,
|
||||||
export type ThreadStatus = "streaming" | "complete" | "error" | "cancelled";
|
Message,
|
||||||
|
TaskResult,
|
||||||
|
ThreadStatus,
|
||||||
|
} from "../../../types/datamodel";
|
||||||
|
|
||||||
export interface ThreadState {
|
export interface ThreadState {
|
||||||
messages: any[];
|
messages: AgentMessageConfig[];
|
||||||
finalResult?: any;
|
finalResult?: any;
|
||||||
status: ThreadStatus;
|
status: ThreadStatus;
|
||||||
isExpanded: boolean;
|
isExpanded: boolean;
|
||||||
}
|
|
||||||
|
|
||||||
export interface ThreadState {
|
|
||||||
messages: any[];
|
|
||||||
finalResult?: any;
|
|
||||||
status: "streaming" | "complete" | "error" | "cancelled";
|
|
||||||
isExpanded: boolean;
|
|
||||||
reason?: string;
|
reason?: string;
|
||||||
|
inputRequest?: {
|
||||||
|
prompt: string;
|
||||||
|
isPending: boolean;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MessageListProps {
|
export interface MessageListProps {
|
||||||
messages: Message[];
|
messages: Message[];
|
||||||
threadMessages: Record<string, ThreadState>;
|
threadMessages: Record<string, ThreadState>;
|
||||||
|
@ -33,15 +32,15 @@ export interface ModelUsage {
|
||||||
completion_tokens: number;
|
completion_tokens: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SocketMessage {
|
export const TIMEOUT_CONFIG = {
|
||||||
type: "message" | "result" | "completion";
|
DURATION_MS: 3 * 60 * 1000, // 3 minutes in milliseconds
|
||||||
data?: {
|
DURATION_SEC: 3 * 60, // 3 minutes in seconds
|
||||||
source?: string;
|
WEBSOCKET_CODE: 4000, // WebSocket close code for timeout
|
||||||
models_usage?: ModelUsage | null;
|
DEFAULT_MESSAGE: "Input timeout after 3 minutes",
|
||||||
content?: string;
|
WARNING_THRESHOLD_SEC: 30, // Show warning when 30 seconds remaining
|
||||||
task_result?: TaskResult;
|
} as const;
|
||||||
};
|
|
||||||
status?: ThreadStatus;
|
export interface TimeoutError {
|
||||||
timestamp?: string;
|
code: typeof TIMEOUT_CONFIG.WEBSOCKET_CODE;
|
||||||
error?: string;
|
message: string;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,3 +6,38 @@ export const LoadingIndicator = ({ size = 16 }: { size: number }) => (
|
||||||
<Loader2 size={size} className="animate-spin" />
|
<Loader2 size={size} className="animate-spin" />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const LoadingDots = ({ size = 8 }) => {
|
||||||
|
return (
|
||||||
|
<span className="inline-flex items-center gap-2">
|
||||||
|
<span
|
||||||
|
className="bg-accent rounded-full animate-bounce"
|
||||||
|
style={{
|
||||||
|
width: `${size}px`,
|
||||||
|
height: `${size}px`,
|
||||||
|
animationDuration: "0.6s",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
className="bg-accent rounded-full animate-bounce"
|
||||||
|
style={{
|
||||||
|
width: `${size}px`,
|
||||||
|
height: `${size}px`,
|
||||||
|
animationDuration: "0.6s",
|
||||||
|
animationDelay: "0.2s",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
className="bg-accent rounded-full animate-bounce"
|
||||||
|
style={{
|
||||||
|
width: `${size}px`,
|
||||||
|
height: `${size}px`,
|
||||||
|
animationDuration: "0.6s",
|
||||||
|
animationDelay: "0.4s",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default LoadingDots;
|
||||||
|
|
|
@ -14,7 +14,7 @@ export class SessionAPI {
|
||||||
|
|
||||||
async listSessions(userId: string): Promise<Session[]> {
|
async listSessions(userId: string): Promise<Session[]> {
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
`${this.getBaseUrl()}/sessions?user_id=${userId}`,
|
`${this.getBaseUrl()}/sessions/?user_id=${userId}`,
|
||||||
{
|
{
|
||||||
headers: this.getHeaders(),
|
headers: this.getHeaders(),
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ export class SessionAPI {
|
||||||
user_id: userId, // Ensure user_id is included
|
user_id: userId, // Ensure user_id is included
|
||||||
};
|
};
|
||||||
|
|
||||||
const response = await fetch(`${this.getBaseUrl()}/sessions`, {
|
const response = await fetch(`${this.getBaseUrl()}/sessions/`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: this.getHeaders(),
|
headers: this.getHeaders(),
|
||||||
body: JSON.stringify(session),
|
body: JSON.stringify(session),
|
||||||
|
|
|
@ -149,12 +149,12 @@ export const SessionManager: React.FC = () => {
|
||||||
icon={<Plus className="w-4 h-4" />}
|
icon={<Plus className="w-4 h-4" />}
|
||||||
>
|
>
|
||||||
New Session{" "}
|
New Session{" "}
|
||||||
{sessions.length === 0 && (
|
{/* {sessions.length === 0 && (
|
||||||
<span className="relative flex h-3 w-3">
|
<span className="relative flex h-3 w-3 -mt-2">
|
||||||
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-secondary opacity-75"></span>
|
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-secondary opacity-75"></span>
|
||||||
<span className="relative inline-flex rounded-full h-3 w-3 bg-secondary"></span>
|
<span className="relative inline-flex rounded-full h-3 w-3 bg-secondary"></span>
|
||||||
</span>
|
</span>
|
||||||
)}
|
)} */}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -14,7 +14,7 @@ export class TeamAPI {
|
||||||
|
|
||||||
async listTeams(userId: string): Promise<Team[]> {
|
async listTeams(userId: string): Promise<Team[]> {
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
`${this.getBaseUrl()}/teams?user_id=${userId}`,
|
`${this.getBaseUrl()}/teams/?user_id=${userId}`,
|
||||||
{
|
{
|
||||||
headers: this.getHeaders(),
|
headers: this.getHeaders(),
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ export class TeamAPI {
|
||||||
user_id: userId,
|
user_id: userId,
|
||||||
};
|
};
|
||||||
|
|
||||||
const response = await fetch(`${this.getBaseUrl()}/teams`, {
|
const response = await fetch(`${this.getBaseUrl()}/teams/`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: this.getHeaders(),
|
headers: this.getHeaders(),
|
||||||
body: JSON.stringify(team),
|
body: JSON.stringify(team),
|
||||||
|
|
|
@ -7,9 +7,39 @@ import type { Team, TeamConfig } from "../../../types/datamodel";
|
||||||
import { MonacoEditor } from "../monaco";
|
import { MonacoEditor } from "../monaco";
|
||||||
|
|
||||||
const defaultTeamConfig: TeamConfig = {
|
const defaultTeamConfig: TeamConfig = {
|
||||||
name: "",
|
version: "1.0.0",
|
||||||
participants: [],
|
component_type: "team",
|
||||||
|
name: "weather_team",
|
||||||
|
participants: [
|
||||||
|
{
|
||||||
|
component_type: "agent",
|
||||||
|
name: "writing_agent",
|
||||||
|
agent_type: "AssistantAgent",
|
||||||
|
system_message:
|
||||||
|
"You are a helpful assistant. Solve tasks carefully. When done respond with TERMINATE",
|
||||||
|
model_client: {
|
||||||
|
component_type: "model",
|
||||||
|
model: "gpt-4o-2024-08-06",
|
||||||
|
model_type: "OpenAIChatCompletionClient",
|
||||||
|
},
|
||||||
|
tools: [
|
||||||
|
{
|
||||||
|
component_type: "tool",
|
||||||
|
name: "get_weather",
|
||||||
|
description: "Get the weather for a city",
|
||||||
|
content:
|
||||||
|
'async def get_weather(city: str) -> str:\n return f"The weather in {city} is 73 degrees and Sunny."',
|
||||||
|
tool_type: "PythonFunction",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
team_type: "RoundRobinGroupChat",
|
team_type: "RoundRobinGroupChat",
|
||||||
|
termination_condition: {
|
||||||
|
component_type: "termination",
|
||||||
|
termination_type: "MaxMessageTermination",
|
||||||
|
max_messages: 10,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
type FieldType = {
|
type FieldType = {
|
||||||
|
@ -122,6 +152,14 @@ export const TeamEditor: React.FC<TeamEditorProps> = ({
|
||||||
width={800}
|
width={800}
|
||||||
forceRender
|
forceRender
|
||||||
>
|
>
|
||||||
|
<div>
|
||||||
|
<div className="mb-4 mt-4 border text-xs p-2 rounded">
|
||||||
|
<TriangleAlertIcon
|
||||||
|
className="w-5 h-5 inline-block mr-2"
|
||||||
|
strokeWidth={1.5}
|
||||||
|
/>
|
||||||
|
Work is still being done to create an improved team editor.
|
||||||
|
</div>
|
||||||
<Form
|
<Form
|
||||||
form={form}
|
form={form}
|
||||||
name="team-form"
|
name="team-form"
|
||||||
|
@ -164,6 +202,7 @@ export const TeamEditor: React.FC<TeamEditorProps> = ({
|
||||||
</div>
|
</div>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Form>
|
</Form>
|
||||||
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +1,29 @@
|
||||||
import { create } from "zustand";
|
import { create } from "zustand";
|
||||||
|
import { persist, createJSONStorage } from "zustand/middleware";
|
||||||
import { v4 as uuidv4 } from "uuid";
|
import { v4 as uuidv4 } from "uuid";
|
||||||
import { Message, Session } from "../components/types/datamodel";
|
import { Message, Session } from "../components/types/datamodel";
|
||||||
|
|
||||||
|
interface IBreadcrumb {
|
||||||
|
name: string;
|
||||||
|
href: string;
|
||||||
|
current?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
// New interfaces
|
||||||
|
export interface IAgentFlowSettings {
|
||||||
|
direction: "TB" | "LR";
|
||||||
|
showLabels: boolean;
|
||||||
|
showGrid: boolean;
|
||||||
|
showTokens: boolean;
|
||||||
|
showMessages: boolean;
|
||||||
|
// Add any other settings we want to persist
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IHeaderState {
|
||||||
|
title: string;
|
||||||
|
breadcrumbs?: IBreadcrumb[];
|
||||||
|
}
|
||||||
|
|
||||||
interface ISidebarState {
|
interface ISidebarState {
|
||||||
isExpanded: boolean;
|
isExpanded: boolean;
|
||||||
isPinned: boolean;
|
isPinned: boolean;
|
||||||
|
@ -17,15 +39,35 @@ export interface IConfigState {
|
||||||
version: string | null;
|
version: string | null;
|
||||||
setVersion: (version: string | null) => void;
|
setVersion: (version: string | null) => void;
|
||||||
|
|
||||||
|
// Header state
|
||||||
|
header: IHeaderState;
|
||||||
|
setHeader: (header: Partial<IHeaderState>) => void;
|
||||||
|
setBreadcrumbs: (breadcrumbs: IBreadcrumb[]) => void;
|
||||||
|
|
||||||
// Sidebar state
|
// Sidebar state
|
||||||
sidebar: ISidebarState;
|
sidebar: ISidebarState;
|
||||||
setSidebarState: (state: Partial<ISidebarState>) => void;
|
setSidebarState: (state: Partial<ISidebarState>) => void;
|
||||||
collapseSidebar: () => void;
|
collapseSidebar: () => void;
|
||||||
expandSidebar: () => void;
|
expandSidebar: () => void;
|
||||||
toggleSidebar: () => void;
|
toggleSidebar: () => void;
|
||||||
|
|
||||||
|
// Agent flow settings agentFlow: IAgentFlowSettings;
|
||||||
|
agentFlow: IAgentFlowSettings;
|
||||||
|
setAgentFlowSettings: (settings: Partial<IAgentFlowSettings>) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useConfigStore = create<IConfigState>((set) => ({
|
// Default settings
|
||||||
|
const DEFAULT_AGENT_FLOW_SETTINGS: IAgentFlowSettings = {
|
||||||
|
direction: "TB",
|
||||||
|
showLabels: true,
|
||||||
|
showGrid: true,
|
||||||
|
showTokens: true,
|
||||||
|
showMessages: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useConfigStore = create<IConfigState>()(
|
||||||
|
persist(
|
||||||
|
(set) => ({
|
||||||
// Existing state
|
// Existing state
|
||||||
messages: [],
|
messages: [],
|
||||||
setMessages: (messages) => set({ messages }),
|
setMessages: (messages) => set({ messages }),
|
||||||
|
@ -37,29 +79,55 @@ export const useConfigStore = create<IConfigState>((set) => ({
|
||||||
setVersion: (version) => set({ version }),
|
setVersion: (version) => set({ version }),
|
||||||
connectionId: uuidv4(),
|
connectionId: uuidv4(),
|
||||||
|
|
||||||
|
// Header state
|
||||||
|
header: {
|
||||||
|
title: "",
|
||||||
|
breadcrumbs: [],
|
||||||
|
},
|
||||||
|
setHeader: (newHeader) =>
|
||||||
|
set((state) => ({
|
||||||
|
header: { ...state.header, ...newHeader },
|
||||||
|
})),
|
||||||
|
setBreadcrumbs: (breadcrumbs) =>
|
||||||
|
set((state) => ({
|
||||||
|
header: { ...state.header, breadcrumbs },
|
||||||
|
})),
|
||||||
|
// Add AgentFlow settings
|
||||||
|
agentFlow: DEFAULT_AGENT_FLOW_SETTINGS,
|
||||||
|
setAgentFlowSettings: (newSettings) =>
|
||||||
|
set((state) => ({
|
||||||
|
agentFlow: { ...state.agentFlow, ...newSettings },
|
||||||
|
})),
|
||||||
|
|
||||||
// Sidebar state and actions
|
// Sidebar state and actions
|
||||||
sidebar: {
|
sidebar: {
|
||||||
isExpanded: true,
|
isExpanded: true,
|
||||||
isPinned: false,
|
isPinned: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
setSidebarState: (newState) =>
|
setSidebarState: (newState) =>
|
||||||
set((state) => ({
|
set((state) => ({
|
||||||
sidebar: { ...state.sidebar, ...newState },
|
sidebar: { ...state.sidebar, ...newState },
|
||||||
})),
|
})),
|
||||||
|
|
||||||
collapseSidebar: () =>
|
collapseSidebar: () =>
|
||||||
set((state) => ({
|
set((state) => ({
|
||||||
sidebar: { ...state.sidebar, isExpanded: false },
|
sidebar: { ...state.sidebar, isExpanded: false },
|
||||||
})),
|
})),
|
||||||
|
|
||||||
expandSidebar: () =>
|
expandSidebar: () =>
|
||||||
set((state) => ({
|
set((state) => ({
|
||||||
sidebar: { ...state.sidebar, isExpanded: true },
|
sidebar: { ...state.sidebar, isExpanded: true },
|
||||||
})),
|
})),
|
||||||
|
|
||||||
toggleSidebar: () =>
|
toggleSidebar: () =>
|
||||||
set((state) => ({
|
set((state) => ({
|
||||||
sidebar: { ...state.sidebar, isExpanded: !state.sidebar.isExpanded },
|
sidebar: { ...state.sidebar, isExpanded: !state.sidebar.isExpanded },
|
||||||
})),
|
})),
|
||||||
}));
|
}),
|
||||||
|
{
|
||||||
|
name: "app-sidebar-state",
|
||||||
|
storage: createJSONStorage(() => localStorage),
|
||||||
|
partialize: (state) => ({
|
||||||
|
sidebar: state.sidebar,
|
||||||
|
agentFlow: state.agentFlow,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
|
@ -9,7 +9,7 @@ module.exports = {
|
||||||
typography: {
|
typography: {
|
||||||
DEFAULT: {
|
DEFAULT: {
|
||||||
css: {
|
css: {
|
||||||
maxWidth: "100ch", // add required value here
|
maxWidth: "100ch",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -17,7 +17,7 @@ module.exports = {
|
||||||
height: "height",
|
height: "height",
|
||||||
spacing: "margin, padding",
|
spacing: "margin, padding",
|
||||||
},
|
},
|
||||||
backgroundColor: {
|
colors: {
|
||||||
primary: "var(--color-bg-primary)",
|
primary: "var(--color-bg-primary)",
|
||||||
secondary: "var(--color-bg-secondary)",
|
secondary: "var(--color-bg-secondary)",
|
||||||
accent: "var(--color-bg-accent)",
|
accent: "var(--color-bg-accent)",
|
||||||
|
@ -36,5 +36,16 @@ module.exports = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
plugins: [require("@tailwindcss/typography")],
|
plugins: [
|
||||||
|
require("@tailwindcss/typography"),
|
||||||
|
function ({ addBase, theme }) {
|
||||||
|
addBase({
|
||||||
|
":root": {
|
||||||
|
"--tw-bg-opacity": "1",
|
||||||
|
"--tw-text-opacity": "1",
|
||||||
|
"--tw-border-opacity": "1",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
|
@ -20,6 +20,7 @@ classifiers = [
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"pydantic",
|
"pydantic",
|
||||||
|
"pydantic-settings",
|
||||||
"fastapi",
|
"fastapi",
|
||||||
"typer",
|
"typer",
|
||||||
"uvicorn",
|
"uvicorn",
|
||||||
|
@ -30,6 +31,10 @@ dependencies = [
|
||||||
"psycopg",
|
"psycopg",
|
||||||
"alembic",
|
"alembic",
|
||||||
"loguru",
|
"loguru",
|
||||||
|
"pyyaml",
|
||||||
|
"autogen-core==0.4.0.dev6",
|
||||||
|
"autogen-agentchat==0.4.0.dev6",
|
||||||
|
"autogen-ext==0.4.0.dev6"
|
||||||
]
|
]
|
||||||
optional-dependencies = {web = ["fastapi", "uvicorn"], database = ["psycopg"]}
|
optional-dependencies = {web = ["fastapi", "uvicorn"], database = ["psycopg"]}
|
||||||
|
|
||||||
|
|
360
python/uv.lock
360
python/uv.lock
|
@ -165,6 +165,21 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/05/be/6a403b464dcab3631fe8e27b0f1d906d9e45c5e92aca97ee007e5a895560/aiohttp-3.10.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c1277cd707c465cd09572a774559a3cc7c7a28802eb3a2a9472588f062097205", size = 1306186 },
|
{ url = "https://files.pythonhosted.org/packages/05/be/6a403b464dcab3631fe8e27b0f1d906d9e45c5e92aca97ee007e5a895560/aiohttp-3.10.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c1277cd707c465cd09572a774559a3cc7c7a28802eb3a2a9472588f062097205", size = 1306186 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/8e/fd/bb50fe781068a736a02bf5c7ad5f3ab53e39f1d1e63110da6d30f7605edc/aiohttp-3.10.10-cp312-cp312-win32.whl", hash = "sha256:59bb3c54aa420521dc4ce3cc2c3fe2ad82adf7b09403fa1f48ae45c0cbde6628", size = 359289 },
|
{ url = "https://files.pythonhosted.org/packages/8e/fd/bb50fe781068a736a02bf5c7ad5f3ab53e39f1d1e63110da6d30f7605edc/aiohttp-3.10.10-cp312-cp312-win32.whl", hash = "sha256:59bb3c54aa420521dc4ce3cc2c3fe2ad82adf7b09403fa1f48ae45c0cbde6628", size = 359289 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/70/9e/5add7e240f77ef67c275c82cc1d08afbca57b77593118c1f6e920ae8ad3f/aiohttp-3.10.10-cp312-cp312-win_amd64.whl", hash = "sha256:0e1b370d8007c4ae31ee6db7f9a2fe801a42b146cec80a86766e7ad5c4a259cf", size = 379313 },
|
{ url = "https://files.pythonhosted.org/packages/70/9e/5add7e240f77ef67c275c82cc1d08afbca57b77593118c1f6e920ae8ad3f/aiohttp-3.10.10-cp312-cp312-win_amd64.whl", hash = "sha256:0e1b370d8007c4ae31ee6db7f9a2fe801a42b146cec80a86766e7ad5c4a259cf", size = 379313 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b1/eb/618b1b76c7fe8082a71c9d62e3fe84c5b9af6703078caa9ec57850a12080/aiohttp-3.10.10-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ad7593bb24b2ab09e65e8a1d385606f0f47c65b5a2ae6c551db67d6653e78c28", size = 576114 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/aa/37/3126995d7869f8b30d05381b81a2d4fb4ec6ad313db788e009bc6d39c211/aiohttp-3.10.10-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1eb89d3d29adaf533588f209768a9c02e44e4baf832b08118749c5fad191781d", size = 391901 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3e/f2/8fdfc845be1f811c31ceb797968523813f8e1263ee3e9120d61253f6848f/aiohttp-3.10.10-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3fe407bf93533a6fa82dece0e74dbcaaf5d684e5a51862887f9eaebe6372cd79", size = 387418 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/60/d5/33d2061d36bf07e80286e04b7e0a4de37ce04b5ebfed72dba67659a05250/aiohttp-3.10.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50aed5155f819873d23520919e16703fc8925e509abbb1a1491b0087d1cd969e", size = 1287073 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/00/52/affb55be16a4747740bd630b4c002dac6c5eac42f9bb64202fc3cf3f1930/aiohttp-3.10.10-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4f05e9727ce409358baa615dbeb9b969db94324a79b5a5cea45d39bdb01d82e6", size = 1323612 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/94/f2/cddb69b975387daa2182a8442566971d6410b8a0179bb4540d81c97b1611/aiohttp-3.10.10-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dffb610a30d643983aeb185ce134f97f290f8935f0abccdd32c77bed9388b42", size = 1368406 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c1/e4/afba7327da4d932da8c6e29aecaf855f9d52dace53ac15bfc8030a246f1b/aiohttp-3.10.10-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa6658732517ddabe22c9036479eabce6036655ba87a0224c612e1ae6af2087e", size = 1282761 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9f/6b/364856faa0c9031ea76e24ef0f7fef79cddd9fa8e7dba9a1771c6acc56b5/aiohttp-3.10.10-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:741a46d58677d8c733175d7e5aa618d277cd9d880301a380fd296975a9cdd7bc", size = 1236518 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/46/af/c382846f8356fe64a7b5908bb9b477457aa23b71be7ed551013b7b7d4d87/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e00e3505cd80440f6c98c6d69269dcc2a119f86ad0a9fd70bccc59504bebd68a", size = 1250344 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/87/53/294f87fc086fd0772d0ab82497beb9df67f0f27a8b3dd5742a2656db2bc6/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ffe595f10566f8276b76dc3a11ae4bb7eba1aac8ddd75811736a15b0d5311414", size = 1248956 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/86/30/7d746717fe11bdfefb88bb6c09c5fc985d85c4632da8bb6018e273899254/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:bdfcf6443637c148c4e1a20c48c566aa694fa5e288d34b20fcdc58507882fed3", size = 1293379 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/48/b9/45d670a834458db67a24258e9139ba61fa3bd7d69b98ecf3650c22806f8f/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d183cf9c797a5291e8301790ed6d053480ed94070637bfaad914dd38b0981f67", size = 1320108 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/72/8c/804bb2e837a175635d2000a0659eafc15b2e9d92d3d81c8f69e141ecd0b0/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:77abf6665ae54000b98b3c742bc6ea1d1fb31c394bcabf8b5d2c1ac3ebfe7f3b", size = 1281546 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/89/c0/862e6a9de3d6eeb126cd9d9ea388243b70df9b871ce1a42b193b7a4a77fc/aiohttp-3.10.10-cp313-cp313-win32.whl", hash = "sha256:4470c73c12cd9109db8277287d11f9dd98f77fc54155fc71a7738a83ffcc8ea8", size = 357516 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ae/63/3e1aee3e554263f3f1011cca50d78a4894ae16ce99bf78101ac3a2f0ef74/aiohttp-3.10.10-cp313-cp313-win_amd64.whl", hash = "sha256:486f7aabfa292719a2753c016cc3a8f8172965cabb3ea2e7f7436c7f5a22a151", size = 376785 },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -324,9 +339,6 @@ dependencies = [
|
||||||
[package.metadata]
|
[package.metadata]
|
||||||
requires-dist = [{ name = "autogen-core", editable = "packages/autogen-core" }]
|
requires-dist = [{ name = "autogen-core", editable = "packages/autogen-core" }]
|
||||||
|
|
||||||
[package.metadata.requires-dev]
|
|
||||||
dev = []
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autogen-core"
|
name = "autogen-core"
|
||||||
version = "0.4.0.dev6"
|
version = "0.4.0.dev6"
|
||||||
|
@ -493,9 +505,6 @@ requires-dist = [
|
||||||
{ name = "playwright", marker = "extra == 'web-surfer'", specifier = ">=1.48.0" },
|
{ name = "playwright", marker = "extra == 'web-surfer'", specifier = ">=1.48.0" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.metadata.requires-dev]
|
|
||||||
dev = []
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autogen-magentic-one"
|
name = "autogen-magentic-one"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
|
@ -567,16 +576,21 @@ dev = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autogenstudio"
|
name = "autogenstudio"
|
||||||
version = "0.1.6"
|
version = "0.4.0.dev35"
|
||||||
source = { editable = "packages/autogen-studio" }
|
source = { editable = "packages/autogen-studio" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "alembic" },
|
{ name = "alembic" },
|
||||||
|
{ name = "autogen-agentchat" },
|
||||||
|
{ name = "autogen-core" },
|
||||||
|
{ name = "autogen-ext" },
|
||||||
{ name = "fastapi" },
|
{ name = "fastapi" },
|
||||||
{ name = "loguru" },
|
{ name = "loguru" },
|
||||||
{ name = "numpy" },
|
{ name = "numpy" },
|
||||||
{ name = "psycopg" },
|
{ name = "psycopg" },
|
||||||
{ name = "pydantic" },
|
{ name = "pydantic" },
|
||||||
|
{ name = "pydantic-settings" },
|
||||||
{ name = "python-dotenv" },
|
{ name = "python-dotenv" },
|
||||||
|
{ name = "pyyaml" },
|
||||||
{ name = "sqlmodel" },
|
{ name = "sqlmodel" },
|
||||||
{ name = "typer" },
|
{ name = "typer" },
|
||||||
{ name = "uvicorn" },
|
{ name = "uvicorn" },
|
||||||
|
@ -595,6 +609,9 @@ web = [
|
||||||
[package.metadata]
|
[package.metadata]
|
||||||
requires-dist = [
|
requires-dist = [
|
||||||
{ name = "alembic" },
|
{ name = "alembic" },
|
||||||
|
{ name = "autogen-agentchat", editable = "packages/autogen-agentchat" },
|
||||||
|
{ name = "autogen-core", editable = "packages/autogen-core" },
|
||||||
|
{ name = "autogen-ext", editable = "packages/autogen-ext" },
|
||||||
{ name = "fastapi" },
|
{ name = "fastapi" },
|
||||||
{ name = "fastapi", marker = "extra == 'web'" },
|
{ name = "fastapi", marker = "extra == 'web'" },
|
||||||
{ name = "loguru" },
|
{ name = "loguru" },
|
||||||
|
@ -602,7 +619,9 @@ requires-dist = [
|
||||||
{ name = "psycopg" },
|
{ name = "psycopg" },
|
||||||
{ name = "psycopg", marker = "extra == 'database'" },
|
{ name = "psycopg", marker = "extra == 'database'" },
|
||||||
{ name = "pydantic" },
|
{ name = "pydantic" },
|
||||||
|
{ name = "pydantic-settings" },
|
||||||
{ name = "python-dotenv" },
|
{ name = "python-dotenv" },
|
||||||
|
{ name = "pyyaml" },
|
||||||
{ name = "sqlmodel" },
|
{ name = "sqlmodel" },
|
||||||
{ name = "typer" },
|
{ name = "typer" },
|
||||||
{ name = "uvicorn" },
|
{ name = "uvicorn" },
|
||||||
|
@ -739,6 +758,17 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/d4/38/ca8a4f639065f14ae0f1d9751e70447a261f1a30fa7547a828ae08142465/cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", size = 488736 },
|
{ url = "https://files.pythonhosted.org/packages/d4/38/ca8a4f639065f14ae0f1d9751e70447a261f1a30fa7547a828ae08142465/cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", size = 488736 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/86/c5/28b2d6f799ec0bdecf44dced2ec5ed43e0eb63097b0f58c293583b406582/cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", size = 172448 },
|
{ url = "https://files.pythonhosted.org/packages/86/c5/28b2d6f799ec0bdecf44dced2ec5ed43e0eb63097b0f58c293583b406582/cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", size = 172448 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/50/b9/db34c4755a7bd1cb2d1603ac3863f22bcecbd1ba29e5ee841a4bc510b294/cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", size = 181976 },
|
{ url = "https://files.pythonhosted.org/packages/50/b9/db34c4755a7bd1cb2d1603ac3863f22bcecbd1ba29e5ee841a4bc510b294/cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", size = 181976 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8d/f8/dd6c246b148639254dad4d6803eb6a54e8c85c6e11ec9df2cffa87571dbe/cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", size = 182989 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8b/f1/672d303ddf17c24fc83afd712316fda78dc6fce1cd53011b839483e1ecc8/cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", size = 178802 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0e/2d/eab2e858a91fdff70533cab61dcff4a1f55ec60425832ddfdc9cd36bc8af/cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", size = 454792 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/75/b2/fbaec7c4455c604e29388d55599b99ebcc250a60050610fadde58932b7ee/cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", size = 478893 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4f/b7/6e4a2162178bf1935c336d4da8a9352cccab4d3a5d7914065490f08c0690/cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", size = 485810 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c7/8a/1d0e4a9c26e54746dc08c2c6c037889124d4f59dffd853a659fa545f1b40/cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", size = 471200 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/26/9f/1aab65a6c0db35f43c4d1b4f580e8df53914310afc10ae0397d29d697af4/cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", size = 479447 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5f/e4/fb8b3dd8dc0e98edf1135ff067ae070bb32ef9d509d6cb0f538cd6f7483f/cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", size = 484358 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f1/47/d7145bf2dc04684935d57d67dff9d6d795b2ba2796806bb109864be3a151/cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", size = 488469 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bf/ee/f94057fa6426481d663b88637a9a10e859e492c73d0384514a17d78ee205/cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", size = 172475 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7c/fc/6a8cb64e5f0324877d503c854da15d76c1e50eb722e320b15345c4d0c6de/cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", size = 182009 },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -801,6 +831,21 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/f7/fa/d3fc622de05a86f30beea5fc4e9ac46aead4731e73fd9055496732bcc0a4/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565", size = 144800 },
|
{ url = "https://files.pythonhosted.org/packages/f7/fa/d3fc622de05a86f30beea5fc4e9ac46aead4731e73fd9055496732bcc0a4/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565", size = 144800 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/9a/65/bdb9bc496d7d190d725e96816e20e2ae3a6fa42a5cac99c3c3d6ff884118/charset_normalizer-3.4.0-cp312-cp312-win32.whl", hash = "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7", size = 94836 },
|
{ url = "https://files.pythonhosted.org/packages/9a/65/bdb9bc496d7d190d725e96816e20e2ae3a6fa42a5cac99c3c3d6ff884118/charset_normalizer-3.4.0-cp312-cp312-win32.whl", hash = "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7", size = 94836 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/3e/67/7b72b69d25b89c0b3cea583ee372c43aa24df15f0e0f8d3982c57804984b/charset_normalizer-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9", size = 102187 },
|
{ url = "https://files.pythonhosted.org/packages/3e/67/7b72b69d25b89c0b3cea583ee372c43aa24df15f0e0f8d3982c57804984b/charset_normalizer-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9", size = 102187 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f3/89/68a4c86f1a0002810a27f12e9a7b22feb198c59b2f05231349fbce5c06f4/charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114", size = 194617 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4f/cd/8947fe425e2ab0aa57aceb7807af13a0e4162cd21eee42ef5b053447edf5/charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed", size = 125310 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5b/f0/b5263e8668a4ee9becc2b451ed909e9c27058337fda5b8c49588183c267a/charset_normalizer-3.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250", size = 119126 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ff/6e/e445afe4f7fda27a533f3234b627b3e515a1b9429bc981c9a5e2aa5d97b6/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920", size = 139342 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a1/b2/4af9993b532d93270538ad4926c8e37dc29f2111c36f9c629840c57cd9b3/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64", size = 149383 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fb/6f/4e78c3b97686b871db9be6f31d64e9264e889f8c9d7ab33c771f847f79b7/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23", size = 142214 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2b/c9/1c8fe3ce05d30c87eff498592c89015b19fade13df42850aafae09e94f35/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc", size = 144104 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ee/68/efad5dcb306bf37db7db338338e7bb8ebd8cf38ee5bbd5ceaaaa46f257e6/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d", size = 146255 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0c/75/1ed813c3ffd200b1f3e71121c95da3f79e6d2a96120163443b3ad1057505/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88", size = 140251 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7d/0d/6f32255c1979653b448d3c709583557a4d24ff97ac4f3a5be156b2e6a210/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90", size = 148474 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ac/a0/c1b5298de4670d997101fef95b97ac440e8c8d8b4efa5a4d1ef44af82f0d/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b", size = 151849 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/04/4f/b3961ba0c664989ba63e30595a3ed0875d6790ff26671e2aae2fdc28a399/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d", size = 149781 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d8/90/6af4cd042066a4adad58ae25648a12c09c879efa4849c705719ba1b23d8c/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482", size = 144970 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cc/67/e5e7e0cbfefc4ca79025238b43cdf8a2037854195b37d6417f3d0895c4c2/charset_normalizer-3.4.0-cp313-cp313-win32.whl", hash = "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67", size = 94973 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/65/97/fc9bbc54ee13d33dc54a7fcf17b26368b18505500fc01e228c27b5222d80/charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b", size = 102308 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/bf/9b/08c0432272d77b04803958a4598a51e2a4b51c06640af8b8f0f908c18bf2/charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079", size = 49446 },
|
{ url = "https://files.pythonhosted.org/packages/bf/9b/08c0432272d77b04803958a4598a51e2a4b51c06640af8b8f0f908c18bf2/charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079", size = 49446 },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -956,6 +1001,10 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/80/79/8bba39190d2ea17840925d287f1c6c3a7c60b58f5090444e9ecf176c540f/debugpy-1.8.7-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:703c1fd62ae0356e194f3e7b7a92acd931f71fe81c4b3be2c17a7b8a4b546ec2", size = 4170911 },
|
{ url = "https://files.pythonhosted.org/packages/80/79/8bba39190d2ea17840925d287f1c6c3a7c60b58f5090444e9ecf176c540f/debugpy-1.8.7-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:703c1fd62ae0356e194f3e7b7a92acd931f71fe81c4b3be2c17a7b8a4b546ec2", size = 4170911 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/3b/19/5b3d312936db8eb281310fa27903459328ed722d845d594ba5feaeb2f0b3/debugpy-1.8.7-cp312-cp312-win32.whl", hash = "sha256:2f729228430ef191c1e4df72a75ac94e9bf77413ce5f3f900018712c9da0aaca", size = 5195476 },
|
{ url = "https://files.pythonhosted.org/packages/3b/19/5b3d312936db8eb281310fa27903459328ed722d845d594ba5feaeb2f0b3/debugpy-1.8.7-cp312-cp312-win32.whl", hash = "sha256:2f729228430ef191c1e4df72a75ac94e9bf77413ce5f3f900018712c9da0aaca", size = 5195476 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/9f/49/ad20b29f8c921fd5124530d3d39b8f2077efd51b71339a2eff02bba693e9/debugpy-1.8.7-cp312-cp312-win_amd64.whl", hash = "sha256:45c30aaefb3e1975e8a0258f5bbd26cd40cde9bfe71e9e5a7ac82e79bad64e39", size = 5235031 },
|
{ url = "https://files.pythonhosted.org/packages/9f/49/ad20b29f8c921fd5124530d3d39b8f2077efd51b71339a2eff02bba693e9/debugpy-1.8.7-cp312-cp312-win_amd64.whl", hash = "sha256:45c30aaefb3e1975e8a0258f5bbd26cd40cde9bfe71e9e5a7ac82e79bad64e39", size = 5235031 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/41/95/29b247518d0a6afdb5249f5d05743c9c5bfaf4bd13a85b81cb5e1dc65837/debugpy-1.8.7-cp313-cp313-macosx_14_0_universal2.whl", hash = "sha256:d050a1ec7e925f514f0f6594a1e522580317da31fbda1af71d1530d6ea1f2b40", size = 2517557 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4d/93/026e2000a0740e2f54b198f8dc317accf3a70b6524b2b15fa8e6eca74414/debugpy-1.8.7-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2f4349a28e3228a42958f8ddaa6333d6f8282d5edaea456070e48609c5983b7", size = 4162703 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c3/92/a48e653b19a171434290ecdc5935b7a292a65488139c5271d6d0eceeb0f1/debugpy-1.8.7-cp313-cp313-win32.whl", hash = "sha256:11ad72eb9ddb436afb8337891a986302e14944f0f755fd94e90d0d71e9100bba", size = 5195220 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4e/b3/dc3c5527edafcd1a6d0f8c4ecc6c5c9bc431f77340cf4193328e98f0ac38/debugpy-1.8.7-cp313-cp313-win_amd64.whl", hash = "sha256:2efb84d6789352d7950b03d7f866e6d180284bc02c7e12cb37b489b7083d81aa", size = 5235333 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/51/b1/a0866521c71a6ae3d3ca320e74835163a4671b1367ba360a55a0a51e5a91/debugpy-1.8.7-py2.py3-none-any.whl", hash = "sha256:57b00de1c8d2c84a61b90880f7e5b6deaf4c312ecbde3a0e8912f2a56c4ac9ae", size = 5210683 },
|
{ url = "https://files.pythonhosted.org/packages/51/b1/a0866521c71a6ae3d3ca320e74835163a4671b1367ba360a55a0a51e5a91/debugpy-1.8.7-py2.py3-none-any.whl", hash = "sha256:57b00de1c8d2c84a61b90880f7e5b6deaf4c312ecbde3a0e8912f2a56c4ac9ae", size = 5210683 },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1163,6 +1212,21 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/37/e0/47f87544055b3349b633a03c4d94b405956cf2437f4ab46d0928b74b7526/frozenlist-1.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:52ef692a4bc60a6dd57f507429636c2af8b6046db8b31b18dac02cbc8f507f7f", size = 280569 },
|
{ url = "https://files.pythonhosted.org/packages/37/e0/47f87544055b3349b633a03c4d94b405956cf2437f4ab46d0928b74b7526/frozenlist-1.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:52ef692a4bc60a6dd57f507429636c2af8b6046db8b31b18dac02cbc8f507f7f", size = 280569 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/f9/7c/490133c160fb6b84ed374c266f42800e33b50c3bbab1652764e6e1fc498a/frozenlist-1.5.0-cp312-cp312-win32.whl", hash = "sha256:29d94c256679247b33a3dc96cce0f93cbc69c23bf75ff715919332fdbb6a32b8", size = 44721 },
|
{ url = "https://files.pythonhosted.org/packages/f9/7c/490133c160fb6b84ed374c266f42800e33b50c3bbab1652764e6e1fc498a/frozenlist-1.5.0-cp312-cp312-win32.whl", hash = "sha256:29d94c256679247b33a3dc96cce0f93cbc69c23bf75ff715919332fdbb6a32b8", size = 44721 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/b1/56/4e45136ffc6bdbfa68c29ca56ef53783ef4c2fd395f7cbf99a2624aa9aaa/frozenlist-1.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:8969190d709e7c48ea386db202d708eb94bdb29207a1f269bab1196ce0dcca1f", size = 51329 },
|
{ url = "https://files.pythonhosted.org/packages/b1/56/4e45136ffc6bdbfa68c29ca56ef53783ef4c2fd395f7cbf99a2624aa9aaa/frozenlist-1.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:8969190d709e7c48ea386db202d708eb94bdb29207a1f269bab1196ce0dcca1f", size = 51329 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/da/3b/915f0bca8a7ea04483622e84a9bd90033bab54bdf485479556c74fd5eaf5/frozenlist-1.5.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7a1a048f9215c90973402e26c01d1cff8a209e1f1b53f72b95c13db61b00f953", size = 91538 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c7/d1/a7c98aad7e44afe5306a2b068434a5830f1470675f0e715abb86eb15f15b/frozenlist-1.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dd47a5181ce5fcb463b5d9e17ecfdb02b678cca31280639255ce9d0e5aa67af0", size = 52849 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3a/c8/76f23bf9ab15d5f760eb48701909645f686f9c64fbb8982674c241fbef14/frozenlist-1.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1431d60b36d15cda188ea222033eec8e0eab488f39a272461f2e6d9e1a8e63c2", size = 50583 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1f/22/462a3dd093d11df623179d7754a3b3269de3b42de2808cddef50ee0f4f48/frozenlist-1.5.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6482a5851f5d72767fbd0e507e80737f9c8646ae7fd303def99bfe813f76cf7f", size = 265636 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/80/cf/e075e407fc2ae7328155a1cd7e22f932773c8073c1fc78016607d19cc3e5/frozenlist-1.5.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:44c49271a937625619e862baacbd037a7ef86dd1ee215afc298a417ff3270608", size = 270214 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a1/58/0642d061d5de779f39c50cbb00df49682832923f3d2ebfb0fedf02d05f7f/frozenlist-1.5.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:12f78f98c2f1c2429d42e6a485f433722b0061d5c0b0139efa64f396efb5886b", size = 273905 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ab/66/3fe0f5f8f2add5b4ab7aa4e199f767fd3b55da26e3ca4ce2cc36698e50c4/frozenlist-1.5.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce3aa154c452d2467487765e3adc730a8c153af77ad84096bc19ce19a2400840", size = 250542 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f6/b8/260791bde9198c87a465224e0e2bb62c4e716f5d198fc3a1dacc4895dbd1/frozenlist-1.5.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b7dc0c4338e6b8b091e8faf0db3168a37101943e687f373dce00959583f7439", size = 267026 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2e/a4/3d24f88c527f08f8d44ade24eaee83b2627793fa62fa07cbb7ff7a2f7d42/frozenlist-1.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:45e0896250900b5aa25180f9aec243e84e92ac84bd4a74d9ad4138ef3f5c97de", size = 257690 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/de/9a/d311d660420b2beeff3459b6626f2ab4fb236d07afbdac034a4371fe696e/frozenlist-1.5.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:561eb1c9579d495fddb6da8959fd2a1fca2c6d060d4113f5844b433fc02f2641", size = 253893 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c6/23/e491aadc25b56eabd0f18c53bb19f3cdc6de30b2129ee0bc39cd387cd560/frozenlist-1.5.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:df6e2f325bfee1f49f81aaac97d2aa757c7646534a06f8f577ce184afe2f0a9e", size = 267006 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/08/c4/ab918ce636a35fb974d13d666dcbe03969592aeca6c3ab3835acff01f79c/frozenlist-1.5.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:140228863501b44b809fb39ec56b5d4071f4d0aa6d216c19cbb08b8c5a7eadb9", size = 276157 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c0/29/3b7a0bbbbe5a34833ba26f686aabfe982924adbdcafdc294a7a129c31688/frozenlist-1.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7707a25d6a77f5d27ea7dc7d1fc608aa0a478193823f88511ef5e6b8a48f9d03", size = 264642 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ab/42/0595b3dbffc2e82d7fe658c12d5a5bafcd7516c6bf2d1d1feb5387caa9c1/frozenlist-1.5.0-cp313-cp313-win32.whl", hash = "sha256:31a9ac2b38ab9b5a8933b693db4939764ad3f299fcaa931a3e605bc3460e693c", size = 44914 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/17/c4/b7db1206a3fea44bf3b838ca61deb6f74424a8a5db1dd53ecb21da669be6/frozenlist-1.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:11aabdd62b8b9c4b84081a3c246506d1cddd2dd93ff0ad53ede5defec7886b28", size = 51167 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/c6/c8/a5be5b7550c10858fcf9b0ea054baccab474da77d37f1e828ce043a3a5d4/frozenlist-1.5.0-py3-none-any.whl", hash = "sha256:d994863bba198a4a518b467bb971c56e1db3f180a25c6cf7bb1949c267f748c3", size = 11901 },
|
{ url = "https://files.pythonhosted.org/packages/c6/c8/a5be5b7550c10858fcf9b0ea054baccab474da77d37f1e828ce043a3a5d4/frozenlist-1.5.0-py3-none-any.whl", hash = "sha256:d994863bba198a4a518b467bb971c56e1db3f180a25c6cf7bb1949c267f748c3", size = 11901 },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1208,6 +1272,22 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/19/c5/36384a06f748044d06bdd8776e231fadf92fc896bd12cb1c9f5a1bda9578/greenlet-3.1.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b7cede291382a78f7bb5f04a529cb18e068dd29e0fb27376074b6d0317bf4dd0", size = 1135975 },
|
{ url = "https://files.pythonhosted.org/packages/19/c5/36384a06f748044d06bdd8776e231fadf92fc896bd12cb1c9f5a1bda9578/greenlet-3.1.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b7cede291382a78f7bb5f04a529cb18e068dd29e0fb27376074b6d0317bf4dd0", size = 1135975 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/38/f9/c0a0eb61bdf808d23266ecf1d63309f0e1471f284300ce6dac0ae1231881/greenlet-3.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:23f20bb60ae298d7d8656c6ec6db134bca379ecefadb0b19ce6f19d1f232a942", size = 1163955 },
|
{ url = "https://files.pythonhosted.org/packages/38/f9/c0a0eb61bdf808d23266ecf1d63309f0e1471f284300ce6dac0ae1231881/greenlet-3.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:23f20bb60ae298d7d8656c6ec6db134bca379ecefadb0b19ce6f19d1f232a942", size = 1163955 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/43/21/a5d9df1d21514883333fc86584c07c2b49ba7c602e670b174bd73cfc9c7f/greenlet-3.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:7124e16b4c55d417577c2077be379514321916d5790fa287c9ed6f23bd2ffd01", size = 299655 },
|
{ url = "https://files.pythonhosted.org/packages/43/21/a5d9df1d21514883333fc86584c07c2b49ba7c602e670b174bd73cfc9c7f/greenlet-3.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:7124e16b4c55d417577c2077be379514321916d5790fa287c9ed6f23bd2ffd01", size = 299655 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f3/57/0db4940cd7bb461365ca8d6fd53e68254c9dbbcc2b452e69d0d41f10a85e/greenlet-3.1.1-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:05175c27cb459dcfc05d026c4232f9de8913ed006d42713cb8a5137bd49375f1", size = 272990 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1c/ec/423d113c9f74e5e402e175b157203e9102feeb7088cee844d735b28ef963/greenlet-3.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:935e943ec47c4afab8965954bf49bfa639c05d4ccf9ef6e924188f762145c0ff", size = 649175 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a9/46/ddbd2db9ff209186b7b7c621d1432e2f21714adc988703dbdd0e65155c77/greenlet-3.1.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:667a9706c970cb552ede35aee17339a18e8f2a87a51fba2ed39ceeeb1004798a", size = 663425 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bc/f9/9c82d6b2b04aa37e38e74f0c429aece5eeb02bab6e3b98e7db89b23d94c6/greenlet-3.1.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b8a678974d1f3aa55f6cc34dc480169d58f2e6d8958895d68845fa4ab566509e", size = 657736 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d9/42/b87bc2a81e3a62c3de2b0d550bf91a86939442b7ff85abb94eec3fc0e6aa/greenlet-3.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efc0f674aa41b92da8c49e0346318c6075d734994c3c4e4430b1c3f853e498e4", size = 660347 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/37/fa/71599c3fd06336cdc3eac52e6871cfebab4d9d70674a9a9e7a482c318e99/greenlet-3.1.1-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0153404a4bb921f0ff1abeb5ce8a5131da56b953eda6e14b88dc6bbc04d2049e", size = 615583 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4e/96/e9ef85de031703ee7a4483489b40cf307f93c1824a02e903106f2ea315fe/greenlet-3.1.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:275f72decf9932639c1c6dd1013a1bc266438eb32710016a1c742df5da6e60a1", size = 1133039 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/87/76/b2b6362accd69f2d1889db61a18c94bc743e961e3cab344c2effaa4b4a25/greenlet-3.1.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:c4aab7f6381f38a4b42f269057aee279ab0fc7bf2e929e3d4abfae97b682a12c", size = 1160716 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1f/1b/54336d876186920e185066d8c3024ad55f21d7cc3683c856127ddb7b13ce/greenlet-3.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:b42703b1cf69f2aa1df7d1030b9d77d3e584a70755674d60e710f0af570f3761", size = 299490 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5f/17/bea55bf36990e1638a2af5ba10c1640273ef20f627962cf97107f1e5d637/greenlet-3.1.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1695e76146579f8c06c1509c7ce4dfe0706f49c6831a817ac04eebb2fd02011", size = 643731 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/78/d2/aa3d2157f9ab742a08e0fd8f77d4699f37c22adfbfeb0c610a186b5f75e0/greenlet-3.1.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7876452af029456b3f3549b696bb36a06db7c90747740c5302f74a9e9fa14b13", size = 649304 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f1/8e/d0aeffe69e53ccff5a28fa86f07ad1d2d2d6537a9506229431a2a02e2f15/greenlet-3.1.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4ead44c85f8ab905852d3de8d86f6f8baf77109f9da589cb4fa142bd3b57b475", size = 646537 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/05/79/e15408220bbb989469c8871062c97c6c9136770657ba779711b90870d867/greenlet-3.1.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8320f64b777d00dd7ccdade271eaf0cad6636343293a25074cc5566160e4de7b", size = 642506 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/18/87/470e01a940307796f1d25f8167b551a968540fbe0551c0ebb853cb527dd6/greenlet-3.1.1-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6510bf84a6b643dabba74d3049ead221257603a253d0a9873f55f6a59a65f822", size = 602753 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e2/72/576815ba674eddc3c25028238f74d7b8068902b3968cbe456771b166455e/greenlet-3.1.1-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:04b013dc07c96f83134b1e99888e7a79979f1a247e2a9f59697fa14b5862ed01", size = 1122731 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ac/38/08cc303ddddc4b3d7c628c3039a61a3aae36c241ed01393d00c2fd663473/greenlet-3.1.1-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:411f015496fec93c1c8cd4e5238da364e1da7a124bcb293f085bf2860c32c6f6", size = 1142112 },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1510,6 +1590,18 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/5f/e8/e47734280e19cd465832e610e1c69367ee72947de738785c4b6fc4031e25/jiter-0.6.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e7b75436d4fa2032b2530ad989e4cb0ca74c655975e3ff49f91a1a3d7f4e1df2", size = 496023 },
|
{ url = "https://files.pythonhosted.org/packages/5f/e8/e47734280e19cd465832e610e1c69367ee72947de738785c4b6fc4031e25/jiter-0.6.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e7b75436d4fa2032b2530ad989e4cb0ca74c655975e3ff49f91a1a3d7f4e1df2", size = 496023 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/52/01/5f65dd1387d39aa3fd4a98a5be1d8470e929a0cb0dd6cbfebaccd9a20ac5/jiter-0.6.1-cp312-none-win32.whl", hash = "sha256:883d2ced7c21bf06874fdeecab15014c1c6d82216765ca6deef08e335fa719e0", size = 197425 },
|
{ url = "https://files.pythonhosted.org/packages/52/01/5f65dd1387d39aa3fd4a98a5be1d8470e929a0cb0dd6cbfebaccd9a20ac5/jiter-0.6.1-cp312-none-win32.whl", hash = "sha256:883d2ced7c21bf06874fdeecab15014c1c6d82216765ca6deef08e335fa719e0", size = 197425 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/43/b2/bd6665030f7d7cd5d9182c62a869c3d5ceadd7bff9f1b305de9192e7dbf8/jiter-0.6.1-cp312-none-win_amd64.whl", hash = "sha256:91e63273563401aadc6c52cca64a7921c50b29372441adc104127b910e98a5b6", size = 198966 },
|
{ url = "https://files.pythonhosted.org/packages/43/b2/bd6665030f7d7cd5d9182c62a869c3d5ceadd7bff9f1b305de9192e7dbf8/jiter-0.6.1-cp312-none-win_amd64.whl", hash = "sha256:91e63273563401aadc6c52cca64a7921c50b29372441adc104127b910e98a5b6", size = 198966 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/23/38/7b48e0149778ff4b893567c9fd997ecfcc013e290375aa7823e1f681b3d3/jiter-0.6.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:852508a54fe3228432e56019da8b69208ea622a3069458252f725d634e955b31", size = 288674 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/85/3b/96d15b483d82a637279da53a1d299dd5da6e029b9905bcd1a4e1f89b8e4f/jiter-0.6.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f491cc69ff44e5a1e8bc6bf2b94c1f98d179e1aaf4a554493c171a5b2316b701", size = 301531 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cf/54/9681f112cbec4e197259e9db679bd4bc314f4bd24f74b9aa5e93073990b5/jiter-0.6.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc56c8f0b2a28ad4d8047f3ae62d25d0e9ae01b99940ec0283263a04724de1f3", size = 335954 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4a/4d/f9c0ba82b154c66278e28348086086264ccf50622ae468ec215e4bbc2873/jiter-0.6.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:51b58f7a0d9e084a43b28b23da2b09fc5e8df6aa2b6a27de43f991293cab85fd", size = 353996 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ee/be/7f26b258ef190f6d582e21c76c7dd1097753a2203bad3e1643f45392720a/jiter-0.6.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5f79ce15099154c90ef900d69c6b4c686b64dfe23b0114e0971f2fecd306ec6c", size = 369733 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5f/85/037ed5261fa622312471ef5520b2135c26b29256c83adc16c8cc55dc4108/jiter-0.6.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:03a025b52009f47e53ea619175d17e4ded7c035c6fbd44935cb3ada11e1fd592", size = 389920 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a8/f3/2e01294712faa476be9e6ceb49e424c3919e03415ded76d103378a06bb80/jiter-0.6.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c74a8d93718137c021d9295248a87c2f9fdc0dcafead12d2930bc459ad40f885", size = 324138 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/00/45/50377814f21b6412c7785be27f2dace225af52e0af20be7af899a7e3f264/jiter-0.6.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:40b03b75f903975f68199fc4ec73d546150919cb7e534f3b51e727c4d6ccca5a", size = 367610 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/af/fc/51ba30875125381bfe21a1572c176de1a7dd64a386a7498355fc100decc4/jiter-0.6.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:825651a3f04cf92a661d22cad61fc913400e33aa89b3e3ad9a6aa9dc8a1f5a71", size = 512945 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/69/60/af26168bd4916f9199ed433161e9f8a4eeda581a4e5982560d0f22dd146c/jiter-0.6.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:928bf25eb69ddb292ab8177fe69d3fbf76c7feab5fce1c09265a7dccf25d3991", size = 494963 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f3/2f/4f3cc5c9067a6fd1020d3c4365546535a69ed77da7fba2bec24368f3662c/jiter-0.6.1-cp313-none-win32.whl", hash = "sha256:352cd24121e80d3d053fab1cc9806258cad27c53cad99b7a3cac57cf934b12e4", size = 196869 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7a/fc/8709ee90837e94790d8b50db51c7b8a70e86e41b2c81e824c20b0ecfeba7/jiter-0.6.1-cp313-none-win_amd64.whl", hash = "sha256:be7503dd6f4bf02c2a9bacb5cc9335bc59132e7eee9d3e931b13d76fd80d7fda", size = 198919 },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2122,6 +2214,23 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/7d/ed/e6276c8d9668028213df01f598f385b05b55a4e1b4662ee12ef05dab35aa/lxml-5.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e63601ad5cd8f860aa99d109889b5ac34de571c7ee902d6812d5d9ddcc77fa7d", size = 5012542 },
|
{ url = "https://files.pythonhosted.org/packages/7d/ed/e6276c8d9668028213df01f598f385b05b55a4e1b4662ee12ef05dab35aa/lxml-5.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e63601ad5cd8f860aa99d109889b5ac34de571c7ee902d6812d5d9ddcc77fa7d", size = 5012542 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/36/88/684d4e800f5aa28df2a991a6a622783fb73cf0e46235cfa690f9776f032e/lxml-5.3.0-cp312-cp312-win32.whl", hash = "sha256:17e8d968d04a37c50ad9c456a286b525d78c4a1c15dd53aa46c1d8e06bf6fa30", size = 3486454 },
|
{ url = "https://files.pythonhosted.org/packages/36/88/684d4e800f5aa28df2a991a6a622783fb73cf0e46235cfa690f9776f032e/lxml-5.3.0-cp312-cp312-win32.whl", hash = "sha256:17e8d968d04a37c50ad9c456a286b525d78c4a1c15dd53aa46c1d8e06bf6fa30", size = 3486454 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/fc/82/ace5a5676051e60355bd8fb945df7b1ba4f4fb8447f2010fb816bfd57724/lxml-5.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:c1a69e58a6bb2de65902051d57fde951febad631a20a64572677a1052690482f", size = 3816857 },
|
{ url = "https://files.pythonhosted.org/packages/fc/82/ace5a5676051e60355bd8fb945df7b1ba4f4fb8447f2010fb816bfd57724/lxml-5.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:c1a69e58a6bb2de65902051d57fde951febad631a20a64572677a1052690482f", size = 3816857 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/94/6a/42141e4d373903bfea6f8e94b2f554d05506dfda522ada5343c651410dc8/lxml-5.3.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8c72e9563347c7395910de6a3100a4840a75a6f60e05af5e58566868d5eb2d6a", size = 8156284 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/91/5e/fa097f0f7d8b3d113fb7312c6308af702f2667f22644441715be961f2c7e/lxml-5.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e92ce66cd919d18d14b3856906a61d3f6b6a8500e0794142338da644260595cd", size = 4432407 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2d/a1/b901988aa6d4ff937f2e5cfc114e4ec561901ff00660c3e56713642728da/lxml-5.3.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d04f064bebdfef9240478f7a779e8c5dc32b8b7b0b2fc6a62e39b928d428e51", size = 5048331 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/30/0f/b2a54f48e52de578b71bbe2a2f8160672a8a5e103df3a78da53907e8c7ed/lxml-5.3.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c2fb570d7823c2bbaf8b419ba6e5662137f8166e364a8b2b91051a1fb40ab8b", size = 4744835 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/82/9d/b000c15538b60934589e83826ecbc437a1586488d7c13f8ee5ff1f79a9b8/lxml-5.3.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0c120f43553ec759f8de1fee2f4794452b0946773299d44c36bfe18e83caf002", size = 5316649 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e3/ee/ffbb9eaff5e541922611d2c56b175c45893d1c0b8b11e5a497708a6a3b3b/lxml-5.3.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:562e7494778a69086f0312ec9689f6b6ac1c6b65670ed7d0267e49f57ffa08c4", size = 4812046 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/15/ff/7ff89d567485c7b943cdac316087f16b2399a8b997007ed352a1248397e5/lxml-5.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:423b121f7e6fa514ba0c7918e56955a1d4470ed35faa03e3d9f0e3baa4c7e492", size = 4918597 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c6/a3/535b6ed8c048412ff51268bdf4bf1cf052a37aa7e31d2e6518038a883b29/lxml-5.3.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:c00f323cc00576df6165cc9d21a4c21285fa6b9989c5c39830c3903dc4303ef3", size = 4738071 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7a/8f/cbbfa59cb4d4fd677fe183725a76d8c956495d7a3c7f111ab8f5e13d2e83/lxml-5.3.0-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:1fdc9fae8dd4c763e8a31e7630afef517eab9f5d5d31a278df087f307bf601f4", size = 5342213 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5c/fb/db4c10dd9958d4b52e34d1d1f7c1f434422aeaf6ae2bbaaff2264351d944/lxml-5.3.0-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:658f2aa69d31e09699705949b5fc4719cbecbd4a97f9656a232e7d6c7be1a367", size = 4893749 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f2/38/bb4581c143957c47740de18a3281a0cab7722390a77cc6e610e8ebf2d736/lxml-5.3.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:1473427aff3d66a3fa2199004c3e601e6c4500ab86696edffdbc84954c72d832", size = 4945901 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fc/d5/18b7de4960c731e98037bd48fa9f8e6e8f2558e6fbca4303d9b14d21ef3b/lxml-5.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a87de7dd873bf9a792bf1e58b1c3887b9264036629a5bf2d2e6579fe8e73edff", size = 4815447 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/97/a8/cd51ceaad6eb849246559a8ef60ae55065a3df550fc5fcd27014361c1bab/lxml-5.3.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:0d7b36afa46c97875303a94e8f3ad932bf78bace9e18e603f2085b652422edcd", size = 5411186 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/89/c3/1e3dabab519481ed7b1fdcba21dcfb8832f57000733ef0e71cf6d09a5e03/lxml-5.3.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:cf120cce539453ae086eacc0130a324e7026113510efa83ab42ef3fcfccac7fb", size = 5324481 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b6/17/71e9984cf0570cd202ac0a1c9ed5c1b8889b0fc8dc736f5ef0ffb181c284/lxml-5.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:df5c7333167b9674aa8ae1d4008fa4bc17a313cc490b2cca27838bbdcc6bb15b", size = 5011053 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/69/68/9f7e6d3312a91e30829368c2b3217e750adef12a6f8eb10498249f4e8d72/lxml-5.3.0-cp313-cp313-win32.whl", hash = "sha256:c802e1c2ed9f0c06a65bc4ed0189d000ada8049312cfeab6ca635e39c9608957", size = 3485634 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7d/db/214290d58ad68c587bd5d6af3d34e56830438733d0d0856c0275fde43652/lxml-5.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:406246b96d552e0503e17a1006fd27edac678b3fcc9f1be71a2f94b4ff61528d", size = 3814417 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/99/f7/b73a431c8500565aa500e99e60b448d305eaf7c0b4c893c7c5a8a69cc595/lxml-5.3.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7b1cd427cb0d5f7393c31b7496419da594fe600e6fdc4b105a54f82405e6626c", size = 3925431 },
|
{ url = "https://files.pythonhosted.org/packages/99/f7/b73a431c8500565aa500e99e60b448d305eaf7c0b4c893c7c5a8a69cc595/lxml-5.3.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7b1cd427cb0d5f7393c31b7496419da594fe600e6fdc4b105a54f82405e6626c", size = 3925431 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/db/48/4a206623c0d093d0e3b15f415ffb4345b0bdf661a3d0b15a112948c033c7/lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:51806cfe0279e06ed8500ce19479d757db42a30fd509940b1701be9c86a5ff9a", size = 4216683 },
|
{ url = "https://files.pythonhosted.org/packages/db/48/4a206623c0d093d0e3b15f415ffb4345b0bdf661a3d0b15a112948c033c7/lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:51806cfe0279e06ed8500ce19479d757db42a30fd509940b1701be9c86a5ff9a", size = 4216683 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/54/47/577820c45dd954523ae8453b632d91e76da94ca6d9ee40d8c98dd86f916b/lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee70d08fd60c9565ba8190f41a46a54096afa0eeb8f76bd66f2c25d3b1b83005", size = 4326732 },
|
{ url = "https://files.pythonhosted.org/packages/54/47/577820c45dd954523ae8453b632d91e76da94ca6d9ee40d8c98dd86f916b/lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee70d08fd60c9565ba8190f41a46a54096afa0eeb8f76bd66f2c25d3b1b83005", size = 4326732 },
|
||||||
|
@ -2223,6 +2332,26 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352 },
|
{ url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097 },
|
{ url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601 },
|
{ url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739 },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2336,6 +2465,17 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/23/f0/d4101d4da054f04274995ddc4086c2715d9b93111eb9ed49686c0f7ccc8a/msgpack-1.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:06f5fd2f6bb2a7914922d935d3b8bb4a7fff3a9a91cfce6d06c13bc42bec975b", size = 394254 },
|
{ url = "https://files.pythonhosted.org/packages/23/f0/d4101d4da054f04274995ddc4086c2715d9b93111eb9ed49686c0f7ccc8a/msgpack-1.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:06f5fd2f6bb2a7914922d935d3b8bb4a7fff3a9a91cfce6d06c13bc42bec975b", size = 394254 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/1c/12/cf07458f35d0d775ff3a2dc5559fa2e1fcd06c46f1ef510e594ebefdca01/msgpack-1.1.0-cp312-cp312-win32.whl", hash = "sha256:ad33e8400e4ec17ba782f7b9cf868977d867ed784a1f5f2ab46e7ba53b6e1e1b", size = 69085 },
|
{ url = "https://files.pythonhosted.org/packages/1c/12/cf07458f35d0d775ff3a2dc5559fa2e1fcd06c46f1ef510e594ebefdca01/msgpack-1.1.0-cp312-cp312-win32.whl", hash = "sha256:ad33e8400e4ec17ba782f7b9cf868977d867ed784a1f5f2ab46e7ba53b6e1e1b", size = 69085 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/73/80/2708a4641f7d553a63bc934a3eb7214806b5b39d200133ca7f7afb0a53e8/msgpack-1.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:115a7af8ee9e8cddc10f87636767857e7e3717b7a2e97379dc2054712693e90f", size = 75347 },
|
{ url = "https://files.pythonhosted.org/packages/73/80/2708a4641f7d553a63bc934a3eb7214806b5b39d200133ca7f7afb0a53e8/msgpack-1.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:115a7af8ee9e8cddc10f87636767857e7e3717b7a2e97379dc2054712693e90f", size = 75347 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c8/b0/380f5f639543a4ac413e969109978feb1f3c66e931068f91ab6ab0f8be00/msgpack-1.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:071603e2f0771c45ad9bc65719291c568d4edf120b44eb36324dcb02a13bfddf", size = 151142 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c8/ee/be57e9702400a6cb2606883d55b05784fada898dfc7fd12608ab1fdb054e/msgpack-1.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0f92a83b84e7c0749e3f12821949d79485971f087604178026085f60ce109330", size = 84523 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7e/3a/2919f63acca3c119565449681ad08a2f84b2171ddfcff1dba6959db2cceb/msgpack-1.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4a1964df7b81285d00a84da4e70cb1383f2e665e0f1f2a7027e683956d04b734", size = 81556 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7c/43/a11113d9e5c1498c145a8925768ea2d5fce7cbab15c99cda655aa09947ed/msgpack-1.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59caf6a4ed0d164055ccff8fe31eddc0ebc07cf7326a2aaa0dbf7a4001cd823e", size = 392105 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2d/7b/2c1d74ca6c94f70a1add74a8393a0138172207dc5de6fc6269483519d048/msgpack-1.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0907e1a7119b337971a689153665764adc34e89175f9a34793307d9def08e6ca", size = 399979 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/82/8c/cf64ae518c7b8efc763ca1f1348a96f0e37150061e777a8ea5430b413a74/msgpack-1.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:65553c9b6da8166e819a6aa90ad15288599b340f91d18f60b2061f402b9a4915", size = 383816 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/69/86/a847ef7a0f5ef3fa94ae20f52a4cacf596a4e4a010197fbcc27744eb9a83/msgpack-1.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7a946a8992941fea80ed4beae6bff74ffd7ee129a90b4dd5cf9c476a30e9708d", size = 380973 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/aa/90/c74cf6e1126faa93185d3b830ee97246ecc4fe12cf9d2d31318ee4246994/msgpack-1.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4b51405e36e075193bc051315dbf29168d6141ae2500ba8cd80a522964e31434", size = 387435 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7a/40/631c238f1f338eb09f4acb0f34ab5862c4e9d7eda11c1b685471a4c5ea37/msgpack-1.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b4c01941fd2ff87c2a934ee6055bda4ed353a7846b8d4f341c428109e9fcde8c", size = 399082 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e9/1b/fa8a952be252a1555ed39f97c06778e3aeb9123aa4cccc0fd2acd0b4e315/msgpack-1.1.0-cp313-cp313-win32.whl", hash = "sha256:7c9a35ce2c2573bada929e0b7b3576de647b0defbd25f5139dcdaba0ae35a4cc", size = 69037 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b6/bc/8bd826dd03e022153bfa1766dcdec4976d6c818865ed54223d71f07862b3/msgpack-1.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:bce7d9e614a04d0883af0b3d4d501171fbfca038f12c77fa838d9f198147a23f", size = 75140 },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2392,6 +2532,21 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/77/00/8538f11e3356b5d95fa4b024aa566cde7a38aa7a5f08f4912b32a037c5dc/multidict-6.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3ec660d19bbc671e3a6443325f07263be452c453ac9e512f5eb935e7d4ac28b3", size = 125360 },
|
{ url = "https://files.pythonhosted.org/packages/77/00/8538f11e3356b5d95fa4b024aa566cde7a38aa7a5f08f4912b32a037c5dc/multidict-6.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3ec660d19bbc671e3a6443325f07263be452c453ac9e512f5eb935e7d4ac28b3", size = 125360 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/be/05/5d334c1f2462d43fec2363cd00b1c44c93a78c3925d952e9a71caf662e96/multidict-6.1.0-cp312-cp312-win32.whl", hash = "sha256:58130ecf8f7b8112cdb841486404f1282b9c86ccb30d3519faf301b2e5659133", size = 26382 },
|
{ url = "https://files.pythonhosted.org/packages/be/05/5d334c1f2462d43fec2363cd00b1c44c93a78c3925d952e9a71caf662e96/multidict-6.1.0-cp312-cp312-win32.whl", hash = "sha256:58130ecf8f7b8112cdb841486404f1282b9c86ccb30d3519faf301b2e5659133", size = 26382 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/a3/bf/f332a13486b1ed0496d624bcc7e8357bb8053823e8cd4b9a18edc1d97e73/multidict-6.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:188215fc0aafb8e03341995e7c4797860181562380f81ed0a87ff455b70bf1f1", size = 28529 },
|
{ url = "https://files.pythonhosted.org/packages/a3/bf/f332a13486b1ed0496d624bcc7e8357bb8053823e8cd4b9a18edc1d97e73/multidict-6.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:188215fc0aafb8e03341995e7c4797860181562380f81ed0a87ff455b70bf1f1", size = 28529 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/22/67/1c7c0f39fe069aa4e5d794f323be24bf4d33d62d2a348acdb7991f8f30db/multidict-6.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:d569388c381b24671589335a3be6e1d45546c2988c2ebe30fdcada8457a31008", size = 48771 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3c/25/c186ee7b212bdf0df2519eacfb1981a017bda34392c67542c274651daf23/multidict-6.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:052e10d2d37810b99cc170b785945421141bf7bb7d2f8799d431e7db229c385f", size = 29533 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/67/5e/04575fd837e0958e324ca035b339cea174554f6f641d3fb2b4f2e7ff44a2/multidict-6.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f90c822a402cb865e396a504f9fc8173ef34212a342d92e362ca498cad308e28", size = 29595 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d3/b2/e56388f86663810c07cfe4a3c3d87227f3811eeb2d08450b9e5d19d78876/multidict-6.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b225d95519a5bf73860323e633a664b0d85ad3d5bede6d30d95b35d4dfe8805b", size = 130094 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6c/ee/30ae9b4186a644d284543d55d491fbd4239b015d36b23fea43b4c94f7052/multidict-6.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:23bfd518810af7de1116313ebd9092cb9aa629beb12f6ed631ad53356ed6b86c", size = 134876 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/84/c7/70461c13ba8ce3c779503c70ec9d0345ae84de04521c1f45a04d5f48943d/multidict-6.1.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c09fcfdccdd0b57867577b719c69e347a436b86cd83747f179dbf0cc0d4c1f3", size = 133500 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4a/9f/002af221253f10f99959561123fae676148dd730e2daa2cd053846a58507/multidict-6.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf6bea52ec97e95560af5ae576bdac3aa3aae0b6758c6efa115236d9e07dae44", size = 131099 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/82/42/d1c7a7301d52af79d88548a97e297f9d99c961ad76bbe6f67442bb77f097/multidict-6.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57feec87371dbb3520da6192213c7d6fc892d5589a93db548331954de8248fd2", size = 120403 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/68/f3/471985c2c7ac707547553e8f37cff5158030d36bdec4414cb825fbaa5327/multidict-6.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0c3f390dc53279cbc8ba976e5f8035eab997829066756d811616b652b00a23a3", size = 125348 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/67/2c/e6df05c77e0e433c214ec1d21ddd203d9a4770a1f2866a8ca40a545869a0/multidict-6.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:59bfeae4b25ec05b34f1956eaa1cb38032282cd4dfabc5056d0a1ec4d696d3aa", size = 119673 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c5/cd/bc8608fff06239c9fb333f9db7743a1b2eafe98c2666c9a196e867a3a0a4/multidict-6.1.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b2f59caeaf7632cc633b5cf6fc449372b83bbdf0da4ae04d5be36118e46cc0aa", size = 129927 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/44/8e/281b69b7bc84fc963a44dc6e0bbcc7150e517b91df368a27834299a526ac/multidict-6.1.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:37bb93b2178e02b7b618893990941900fd25b6b9ac0fa49931a40aecdf083fe4", size = 128711 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/12/a4/63e7cd38ed29dd9f1881d5119f272c898ca92536cdb53ffe0843197f6c85/multidict-6.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4e9f48f58c2c523d5a06faea47866cd35b32655c46b443f163d08c6d0ddb17d6", size = 125519 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/38/e0/4f5855037a72cd8a7a2f60a3952d9aa45feedb37ae7831642102604e8a37/multidict-6.1.0-cp313-cp313-win32.whl", hash = "sha256:3a37ffb35399029b45c6cc33640a92bef403c9fd388acce75cdc88f58bd19a81", size = 26426 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7e/a5/17ee3a4db1e310b7405f5d25834460073a8ccd86198ce044dfaf69eac073/multidict-6.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:e9aa71e15d9d9beaad2c6b9319edcdc0a49a43ef5c0a4c8265ca9ee7d6c67774", size = 28531 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/99/b7/b9e70fde2c0f0c9af4cc5277782a89b66d35948ea3369ec9f598358c3ac5/multidict-6.1.0-py3-none-any.whl", hash = "sha256:48e171e52d1c4d33888e529b999e5900356b9ae588c2f09a52dcefb158b27506", size = 10051 },
|
{ url = "https://files.pythonhosted.org/packages/99/b7/b9e70fde2c0f0c9af4cc5277782a89b66d35948ea3369ec9f598358c3ac5/multidict-6.1.0-py3-none-any.whl", hash = "sha256:48e171e52d1c4d33888e529b999e5900356b9ae588c2f09a52dcefb158b27506", size = 10051 },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -2734,6 +2889,13 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/ad/9b/be8b3d3aec42aa47f6058482ace0d2ca3023477a46643d766e96281d5d31/orjson-3.10.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:730ed5350147db7beb23ddaf072f490329e90a1d059711d364b49fe352ec987b", size = 170424 },
|
{ url = "https://files.pythonhosted.org/packages/ad/9b/be8b3d3aec42aa47f6058482ace0d2ca3023477a46643d766e96281d5d31/orjson-3.10.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:730ed5350147db7beb23ddaf072f490329e90a1d059711d364b49fe352ec987b", size = 170424 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/1b/15/a4cc61e23c39b9dec4620cb95817c83c84078be1771d602f6d03f0e5c696/orjson-3.10.10-cp312-none-win32.whl", hash = "sha256:a8f4bf5f1c85bea2170800020d53a8877812892697f9c2de73d576c9307a8a5f", size = 145132 },
|
{ url = "https://files.pythonhosted.org/packages/1b/15/a4cc61e23c39b9dec4620cb95817c83c84078be1771d602f6d03f0e5c696/orjson-3.10.10-cp312-none-win32.whl", hash = "sha256:a8f4bf5f1c85bea2170800020d53a8877812892697f9c2de73d576c9307a8a5f", size = 145132 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/9f/8a/ce7c28e4ea337f6d95261345d7c61322f8561c52f57b263a3ad7025984f4/orjson-3.10.10-cp312-none-win_amd64.whl", hash = "sha256:384cd13579a1b4cd689d218e329f459eb9ddc504fa48c5a83ef4889db7fd7a4f", size = 139389 },
|
{ url = "https://files.pythonhosted.org/packages/9f/8a/ce7c28e4ea337f6d95261345d7c61322f8561c52f57b263a3ad7025984f4/orjson-3.10.10-cp312-none-win_amd64.whl", hash = "sha256:384cd13579a1b4cd689d218e329f459eb9ddc504fa48c5a83ef4889db7fd7a4f", size = 139389 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0c/69/f1c4382cd44bdaf10006c4e82cb85d2bcae735369f84031e203c4e5d87de/orjson-3.10.10-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:44bffae68c291f94ff5a9b4149fe9d1bdd4cd0ff0fb575bcea8351d48db629a1", size = 270695 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/61/29/aeb5153271d4953872b06ed239eb54993a5f344353727c42d3aabb2046f6/orjson-3.10.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e27b4c6437315df3024f0835887127dac2a0a3ff643500ec27088d2588fa5ae1", size = 141632 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bc/a2/c8ac38d8fb461a9b717c766fbe1f7d3acf9bde2f12488eb13194960782e4/orjson-3.10.10-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bca84df16d6b49325a4084fd8b2fe2229cb415e15c46c529f868c3387bb1339d", size = 144854 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/79/51/e7698fdb28bdec633888cc667edc29fd5376fce9ade0a5b3e22f5ebe0343/orjson-3.10.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c14ce70e8f39bd71f9f80423801b5d10bf93d1dceffdecd04df0f64d2c69bc01", size = 172023 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/02/2d/0d99c20878658c7e33b90e6a4bb75cf2924d6ff29c2365262cff3c26589a/orjson-3.10.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:24ac62336da9bda1bd93c0491eff0613003b48d3cb5d01470842e7b52a40d5b4", size = 170429 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cd/45/6a4a446f4fb29bb4703c3537d5c6a2bf7fed768cb4d7b7dce9d71b72fc93/orjson-3.10.10-cp313-none-win32.whl", hash = "sha256:eb0a42831372ec2b05acc9ee45af77bcaccbd91257345f93780a8e654efc75db", size = 145099 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/72/6e/4631fe219a4203aa111e9bb763ad2e2e0cdd1a03805029e4da124d96863f/orjson-3.10.10-cp313-none-win_amd64.whl", hash = "sha256:f0c4f37f8bf3f1075c6cc8dd8a9f843689a4b618628f8812d0a71e6968b95ffd", size = 139176 },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2790,6 +2952,19 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/20/e8/45a05d9c39d2cea61ab175dbe6a2de1d05b679e8de2011da4ee190d7e748/pandas-2.2.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6dfcb5ee8d4d50c06a51c2fffa6cff6272098ad6540aed1a76d15fb9318194d8", size = 16359235 },
|
{ url = "https://files.pythonhosted.org/packages/20/e8/45a05d9c39d2cea61ab175dbe6a2de1d05b679e8de2011da4ee190d7e748/pandas-2.2.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6dfcb5ee8d4d50c06a51c2fffa6cff6272098ad6540aed1a76d15fb9318194d8", size = 16359235 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/1d/99/617d07a6a5e429ff90c90da64d428516605a1ec7d7bea494235e1c3882de/pandas-2.2.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:062309c1b9ea12a50e8ce661145c6aab431b1e99530d3cd60640e255778bd43a", size = 14056756 },
|
{ url = "https://files.pythonhosted.org/packages/1d/99/617d07a6a5e429ff90c90da64d428516605a1ec7d7bea494235e1c3882de/pandas-2.2.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:062309c1b9ea12a50e8ce661145c6aab431b1e99530d3cd60640e255778bd43a", size = 14056756 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/29/d4/1244ab8edf173a10fd601f7e13b9566c1b525c4f365d6bee918e68381889/pandas-2.2.3-cp312-cp312-win_amd64.whl", hash = "sha256:59ef3764d0fe818125a5097d2ae867ca3fa64df032331b7e0917cf5d7bf66b13", size = 11504248 },
|
{ url = "https://files.pythonhosted.org/packages/29/d4/1244ab8edf173a10fd601f7e13b9566c1b525c4f365d6bee918e68381889/pandas-2.2.3-cp312-cp312-win_amd64.whl", hash = "sha256:59ef3764d0fe818125a5097d2ae867ca3fa64df032331b7e0917cf5d7bf66b13", size = 11504248 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/64/22/3b8f4e0ed70644e85cfdcd57454686b9057c6c38d2f74fe4b8bc2527214a/pandas-2.2.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f00d1345d84d8c86a63e476bb4955e46458b304b9575dcf71102b5c705320015", size = 12477643 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e4/93/b3f5d1838500e22c8d793625da672f3eec046b1a99257666c94446969282/pandas-2.2.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3508d914817e153ad359d7e069d752cdd736a247c322d932eb89e6bc84217f28", size = 11281573 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f5/94/6c79b07f0e5aab1dcfa35a75f4817f5c4f677931d4234afcd75f0e6a66ca/pandas-2.2.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:22a9d949bfc9a502d320aa04e5d02feab689d61da4e7764b62c30b991c42c5f0", size = 15196085 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e8/31/aa8da88ca0eadbabd0a639788a6da13bb2ff6edbbb9f29aa786450a30a91/pandas-2.2.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3a255b2c19987fbbe62a9dfd6cff7ff2aa9ccab3fc75218fd4b7530f01efa24", size = 12711809 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ee/7c/c6dbdb0cb2a4344cacfb8de1c5808ca885b2e4dcfde8008266608f9372af/pandas-2.2.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:800250ecdadb6d9c78eae4990da62743b857b470883fa27f652db8bdde7f6659", size = 16356316 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/57/b7/8b757e7d92023b832869fa8881a992696a0bfe2e26f72c9ae9f255988d42/pandas-2.2.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6374c452ff3ec675a8f46fd9ab25c4ad0ba590b71cf0656f8b6daa5202bca3fb", size = 14022055 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3b/bc/4b18e2b8c002572c5a441a64826252ce5da2aa738855747247a971988043/pandas-2.2.3-cp313-cp313-win_amd64.whl", hash = "sha256:61c5ad4043f791b61dd4752191d9f07f0ae412515d59ba8f005832a532f8736d", size = 11481175 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/76/a3/a5d88146815e972d40d19247b2c162e88213ef51c7c25993942c39dbf41d/pandas-2.2.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:3b71f27954685ee685317063bf13c7709a7ba74fc996b84fc6821c59b0f06468", size = 12615650 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9c/8c/f0fd18f6140ddafc0c24122c8a964e48294acc579d47def376fef12bcb4a/pandas-2.2.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:38cf8125c40dae9d5acc10fa66af8ea6fdf760b2714ee482ca691fc66e6fcb18", size = 11290177 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ed/f9/e995754eab9c0f14c6777401f7eece0943840b7a9fc932221c19d1abee9f/pandas-2.2.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ba96630bc17c875161df3818780af30e43be9b166ce51c9a18c1feae342906c2", size = 14651526 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/25/b0/98d6ae2e1abac4f35230aa756005e8654649d305df9a28b16b9ae4353bff/pandas-2.2.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1db71525a1538b30142094edb9adc10be3f3e176748cd7acc2240c2f2e5aa3a4", size = 11871013 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cc/57/0f72a10f9db6a4628744c8e8f0df4e6e21de01212c7c981d31e50ffc8328/pandas-2.2.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:15c0e1e02e93116177d29ff83e8b1619c93ddc9c49083f237d4312337a61165d", size = 15711620 },
|
||||||
|
{ 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 },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2892,6 +3067,25 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/af/3a/da80224a6eb15bba7a0dcb2346e2b686bb9bf98378c0b4353cd88e62b171/pillow-11.0.0-cp312-cp312-win32.whl", hash = "sha256:86510e3f5eca0ab87429dd77fafc04693195eec7fd6a137c389c3eeb4cfb77c6", size = 2249631 },
|
{ url = "https://files.pythonhosted.org/packages/af/3a/da80224a6eb15bba7a0dcb2346e2b686bb9bf98378c0b4353cd88e62b171/pillow-11.0.0-cp312-cp312-win32.whl", hash = "sha256:86510e3f5eca0ab87429dd77fafc04693195eec7fd6a137c389c3eeb4cfb77c6", size = 2249631 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/57/97/73f756c338c1d86bb802ee88c3cab015ad7ce4b838f8a24f16b676b1ac7c/pillow-11.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:8ec4a89295cd6cd4d1058a5e6aec6bf51e0eaaf9714774e1bfac7cfc9051db47", size = 2567533 },
|
{ url = "https://files.pythonhosted.org/packages/57/97/73f756c338c1d86bb802ee88c3cab015ad7ce4b838f8a24f16b676b1ac7c/pillow-11.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:8ec4a89295cd6cd4d1058a5e6aec6bf51e0eaaf9714774e1bfac7cfc9051db47", size = 2567533 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/0b/30/2b61876e2722374558b871dfbfcbe4e406626d63f4f6ed92e9c8e24cac37/pillow-11.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:27a7860107500d813fcd203b4ea19b04babe79448268403172782754870dac25", size = 2254890 },
|
{ url = "https://files.pythonhosted.org/packages/0b/30/2b61876e2722374558b871dfbfcbe4e406626d63f4f6ed92e9c8e24cac37/pillow-11.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:27a7860107500d813fcd203b4ea19b04babe79448268403172782754870dac25", size = 2254890 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/63/24/e2e15e392d00fcf4215907465d8ec2a2f23bcec1481a8ebe4ae760459995/pillow-11.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:bcd1fb5bb7b07f64c15618c89efcc2cfa3e95f0e3bcdbaf4642509de1942a699", size = 3147300 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/43/72/92ad4afaa2afc233dc44184adff289c2e77e8cd916b3ddb72ac69495bda3/pillow-11.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0e038b0745997c7dcaae350d35859c9715c71e92ffb7e0f4a8e8a16732150f38", size = 2978742 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9e/da/c8d69c5bc85d72a8523fe862f05ababdc52c0a755cfe3d362656bb86552b/pillow-11.0.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ae08bd8ffc41aebf578c2af2f9d8749d91f448b3bfd41d7d9ff573d74f2a6b2", size = 4194349 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cd/e8/686d0caeed6b998351d57796496a70185376ed9c8ec7d99e1d19ad591fc6/pillow-11.0.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d69bfd8ec3219ae71bcde1f942b728903cad25fafe3100ba2258b973bd2bc1b2", size = 4298714 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ec/da/430015cec620d622f06854be67fd2f6721f52fc17fca8ac34b32e2d60739/pillow-11.0.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:61b887f9ddba63ddf62fd02a3ba7add935d053b6dd7d58998c630e6dbade8527", size = 4208514 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/44/ae/7e4f6662a9b1cb5f92b9cc9cab8321c381ffbee309210940e57432a4063a/pillow-11.0.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:c6a660307ca9d4867caa8d9ca2c2658ab685de83792d1876274991adec7b93fa", size = 4380055 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/74/d5/1a807779ac8a0eeed57f2b92a3c32ea1b696e6140c15bd42eaf908a261cd/pillow-11.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:73e3a0200cdda995c7e43dd47436c1548f87a30bb27fb871f352a22ab8dcf45f", size = 4296751 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/38/8c/5fa3385163ee7080bc13026d59656267daaaaf3c728c233d530e2c2757c8/pillow-11.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fba162b8872d30fea8c52b258a542c5dfd7b235fb5cb352240c8d63b414013eb", size = 4430378 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ca/1d/ad9c14811133977ff87035bf426875b93097fb50af747793f013979facdb/pillow-11.0.0-cp313-cp313-win32.whl", hash = "sha256:f1b82c27e89fffc6da125d5eb0ca6e68017faf5efc078128cfaa42cf5cb38798", size = 2249588 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fb/01/3755ba287dac715e6afdb333cb1f6d69740a7475220b4637b5ce3d78cec2/pillow-11.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:8ba470552b48e5835f1d23ecb936bb7f71d206f9dfeee64245f30c3270b994de", size = 2567509 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c0/98/2c7d727079b6be1aba82d195767d35fcc2d32204c7a5820f822df5330152/pillow-11.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:846e193e103b41e984ac921b335df59195356ce3f71dcfd155aa79c603873b84", size = 2254791 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/eb/38/998b04cc6f474e78b563716b20eecf42a2fa16a84589d23c8898e64b0ffd/pillow-11.0.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4ad70c4214f67d7466bea6a08061eba35c01b1b89eaa098040a35272a8efb22b", size = 3150854 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/13/8e/be23a96292113c6cb26b2aa3c8b3681ec62b44ed5c2bd0b258bd59503d3c/pillow-11.0.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:6ec0d5af64f2e3d64a165f490d96368bb5dea8b8f9ad04487f9ab60dc4bb6003", size = 2982369 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/97/8a/3db4eaabb7a2ae8203cd3a332a005e4aba00067fc514aaaf3e9721be31f1/pillow-11.0.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c809a70e43c7977c4a42aefd62f0131823ebf7dd73556fa5d5950f5b354087e2", size = 4333703 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/28/ac/629ffc84ff67b9228fe87a97272ab125bbd4dc462745f35f192d37b822f1/pillow-11.0.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:4b60c9520f7207aaf2e1d94de026682fc227806c6e1f55bba7606d1c94dd623a", size = 4412550 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d6/07/a505921d36bb2df6868806eaf56ef58699c16c388e378b0dcdb6e5b2fb36/pillow-11.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:1e2688958a840c822279fda0086fec1fdab2f95bf2b717b66871c4ad9859d7e8", size = 4461038 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d6/b9/fb620dd47fc7cc9678af8f8bd8c772034ca4977237049287e99dda360b66/pillow-11.0.0-cp313-cp313t-win32.whl", hash = "sha256:607bbe123c74e272e381a8d1957083a9463401f7bd01287f50521ecb05a313f8", size = 2253197 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/df/86/25dde85c06c89d7fc5db17940f07aae0a56ac69aa9ccb5eb0f09798862a8/pillow-11.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5c39ed17edea3bc69c743a8dd3e9853b7509625c2462532e62baa0732163a904", size = 2572169 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/51/85/9c33f2517add612e17f3381aee7c4072779130c634921a756c97bc29fb49/pillow-11.0.0-cp313-cp313t-win_arm64.whl", hash = "sha256:75acbbeb05b86bc53cbe7b7e6fe00fbcf82ad7c684b3ad82e3d711da9ba287d3", size = 2256828 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/36/57/42a4dd825eab762ba9e690d696d894ba366e06791936056e26e099398cda/pillow-11.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:1187739620f2b365de756ce086fdb3604573337cc28a0d3ac4a01ab6b2d2a6d2", size = 3119239 },
|
{ url = "https://files.pythonhosted.org/packages/36/57/42a4dd825eab762ba9e690d696d894ba366e06791936056e26e099398cda/pillow-11.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:1187739620f2b365de756ce086fdb3604573337cc28a0d3ac4a01ab6b2d2a6d2", size = 3119239 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/98/f7/25f9f9e368226a1d6cf3507081a1a7944eddd3ca7821023377043f5a83c8/pillow-11.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:fbbcb7b57dc9c794843e3d1258c0fbf0f48656d46ffe9e09b63bbd6e8cd5d0a2", size = 2950803 },
|
{ url = "https://files.pythonhosted.org/packages/98/f7/25f9f9e368226a1d6cf3507081a1a7944eddd3ca7821023377043f5a83c8/pillow-11.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:fbbcb7b57dc9c794843e3d1258c0fbf0f48656d46ffe9e09b63bbd6e8cd5d0a2", size = 2950803 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/59/01/98ead48a6c2e31e6185d4c16c978a67fe3ccb5da5c2ff2ba8475379bb693/pillow-11.0.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d203af30149ae339ad1b4f710d9844ed8796e97fda23ffbc4cc472968a47d0b", size = 3281098 },
|
{ url = "https://files.pythonhosted.org/packages/59/01/98ead48a6c2e31e6185d4c16c978a67fe3ccb5da5c2ff2ba8475379bb693/pillow-11.0.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d203af30149ae339ad1b4f710d9844ed8796e97fda23ffbc4cc472968a47d0b", size = 3281098 },
|
||||||
|
@ -3051,6 +3245,22 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/fd/bd/8657918a35d50b18a9e4d78a5df7b6c82a637a311ab20851eef4326305c1/propcache-0.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4a9d9b4d0a9b38d1c391bb4ad24aa65f306c6f01b512e10a8a34a2dc5675d348", size = 235922 },
|
{ url = "https://files.pythonhosted.org/packages/fd/bd/8657918a35d50b18a9e4d78a5df7b6c82a637a311ab20851eef4326305c1/propcache-0.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4a9d9b4d0a9b38d1c391bb4ad24aa65f306c6f01b512e10a8a34a2dc5675d348", size = 235922 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/a8/6f/ec0095e1647b4727db945213a9f395b1103c442ef65e54c62e92a72a3f75/propcache-0.2.0-cp312-cp312-win32.whl", hash = "sha256:69d3a98eebae99a420d4b28756c8ce6ea5a29291baf2dc9ff9414b42676f61d5", size = 40177 },
|
{ url = "https://files.pythonhosted.org/packages/a8/6f/ec0095e1647b4727db945213a9f395b1103c442ef65e54c62e92a72a3f75/propcache-0.2.0-cp312-cp312-win32.whl", hash = "sha256:69d3a98eebae99a420d4b28756c8ce6ea5a29291baf2dc9ff9414b42676f61d5", size = 40177 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/20/a2/bd0896fdc4f4c1db46d9bc361c8c79a9bf08ccc08ba054a98e38e7ba1557/propcache-0.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:ad9c9b99b05f163109466638bd30ada1722abb01bbb85c739c50b6dc11f92dc3", size = 44446 },
|
{ url = "https://files.pythonhosted.org/packages/20/a2/bd0896fdc4f4c1db46d9bc361c8c79a9bf08ccc08ba054a98e38e7ba1557/propcache-0.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:ad9c9b99b05f163109466638bd30ada1722abb01bbb85c739c50b6dc11f92dc3", size = 44446 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a8/a7/5f37b69197d4f558bfef5b4bceaff7c43cc9b51adf5bd75e9081d7ea80e4/propcache-0.2.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ecddc221a077a8132cf7c747d5352a15ed763b674c0448d811f408bf803d9ad7", size = 78120 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c8/cd/48ab2b30a6b353ecb95a244915f85756d74f815862eb2ecc7a518d565b48/propcache-0.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0e53cb83fdd61cbd67202735e6a6687a7b491c8742dfc39c9e01e80354956763", size = 45127 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a5/ba/0a1ef94a3412aab057bd996ed5f0ac7458be5bf469e85c70fa9ceb43290b/propcache-0.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92fe151145a990c22cbccf9ae15cae8ae9eddabfc949a219c9f667877e40853d", size = 44419 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b4/6c/ca70bee4f22fa99eacd04f4d2f1699be9d13538ccf22b3169a61c60a27fa/propcache-0.2.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6a21ef516d36909931a2967621eecb256018aeb11fc48656e3257e73e2e247a", size = 229611 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/19/70/47b872a263e8511ca33718d96a10c17d3c853aefadeb86dc26e8421184b9/propcache-0.2.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f88a4095e913f98988f5b338c1d4d5d07dbb0b6bad19892fd447484e483ba6b", size = 234005 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4f/be/3b0ab8c84a22e4a3224719099c1229ddfdd8a6a1558cf75cb55ee1e35c25/propcache-0.2.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a5b3bb545ead161be780ee85a2b54fdf7092815995661947812dde94a40f6fb", size = 237270 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/04/d8/f071bb000d4b8f851d312c3c75701e586b3f643fe14a2e3409b1b9ab3936/propcache-0.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67aeb72e0f482709991aa91345a831d0b707d16b0257e8ef88a2ad246a7280bf", size = 231877 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/93/e7/57a035a1359e542bbb0a7df95aad6b9871ebee6dce2840cb157a415bd1f3/propcache-0.2.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c997f8c44ec9b9b0bcbf2d422cc00a1d9b9c681f56efa6ca149a941e5560da2", size = 217848 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f0/93/d1dea40f112ec183398fb6c42fde340edd7bab202411c4aa1a8289f461b6/propcache-0.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2a66df3d4992bc1d725b9aa803e8c5a66c010c65c741ad901e260ece77f58d2f", size = 216987 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/62/4c/877340871251145d3522c2b5d25c16a1690ad655fbab7bb9ece6b117e39f/propcache-0.2.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:3ebbcf2a07621f29638799828b8d8668c421bfb94c6cb04269130d8de4fb7136", size = 212451 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7c/bb/a91b72efeeb42906ef58ccf0cdb87947b54d7475fee3c93425d732f16a61/propcache-0.2.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1235c01ddaa80da8235741e80815ce381c5267f96cc49b1477fdcf8c047ef325", size = 212879 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9b/7f/ee7fea8faac57b3ec5d91ff47470c6c5d40d7f15d0b1fccac806348fa59e/propcache-0.2.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3947483a381259c06921612550867b37d22e1df6d6d7e8361264b6d037595f44", size = 222288 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ff/d7/acd67901c43d2e6b20a7a973d9d5fd543c6e277af29b1eb0e1f7bd7ca7d2/propcache-0.2.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d5bed7f9805cc29c780f3aee05de3262ee7ce1f47083cfe9f77471e9d6777e83", size = 228257 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8d/6f/6272ecc7a8daad1d0754cfc6c8846076a8cb13f810005c79b15ce0ef0cf2/propcache-0.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e4a91d44379f45f5e540971d41e4626dacd7f01004826a18cb048e7da7e96544", size = 221075 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7c/bd/c7a6a719a6b3dd8b3aeadb3675b5783983529e4a3185946aa444d3e078f6/propcache-0.2.0-cp313-cp313-win32.whl", hash = "sha256:f902804113e032e2cdf8c71015651c97af6418363bea8d78dc0911d56c335032", size = 39654 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/88/e7/0eef39eff84fa3e001b44de0bd41c7c0e3432e7648ffd3d64955910f002d/propcache-0.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:8f188cfcc64fb1266f4684206c9de0e80f54622c3f22a910cbd200478aeae61e", size = 43705 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/3d/b6/e6d98278f2d49b22b4d033c9f792eda783b9ab2094b041f013fc69bcde87/propcache-0.2.0-py3-none-any.whl", hash = "sha256:2ccc28197af5313706511fab3a8b66dcd6da067a1331372c82ea1cb74285e036", size = 11603 },
|
{ url = "https://files.pythonhosted.org/packages/3d/b6/e6d98278f2d49b22b4d033c9f792eda783b9ab2094b041f013fc69bcde87/propcache-0.2.0-py3-none-any.whl", hash = "sha256:2ccc28197af5313706511fab3a8b66dcd6da067a1331372c82ea1cb74285e036", size = 11603 },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -3074,6 +3284,8 @@ version = "6.1.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/26/10/2a30b13c61e7cf937f4adf90710776b7918ed0a9c434e2c38224732af310/psutil-6.1.0.tar.gz", hash = "sha256:353815f59a7f64cdaca1c0307ee13558a0512f6db064e92fe833784f08539c7a", size = 508565 }
|
sdist = { url = "https://files.pythonhosted.org/packages/26/10/2a30b13c61e7cf937f4adf90710776b7918ed0a9c434e2c38224732af310/psutil-6.1.0.tar.gz", hash = "sha256:353815f59a7f64cdaca1c0307ee13558a0512f6db064e92fe833784f08539c7a", size = 508565 }
|
||||||
wheels = [
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/da/2b/f4dea5d993d9cd22ad958eea828a41d5d225556123d372f02547c29c4f97/psutil-6.1.0-cp27-none-win32.whl", hash = "sha256:9118f27452b70bb1d9ab3198c1f626c2499384935aaf55388211ad982611407e", size = 246648 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9f/14/4aa97a7f2e0ac33a050d990ab31686d651ae4ef8c86661fef067f00437b9/psutil-6.1.0-cp27-none-win_amd64.whl", hash = "sha256:a8506f6119cff7015678e2bce904a4da21025cc70ad283a53b099e7620061d85", size = 249905 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/01/9e/8be43078a171381953cfee33c07c0d628594b5dbfc5157847b85022c2c1b/psutil-6.1.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6e2dcd475ce8b80522e51d923d10c7871e45f20918e027ab682f94f1c6351688", size = 247762 },
|
{ url = "https://files.pythonhosted.org/packages/01/9e/8be43078a171381953cfee33c07c0d628594b5dbfc5157847b85022c2c1b/psutil-6.1.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6e2dcd475ce8b80522e51d923d10c7871e45f20918e027ab682f94f1c6351688", size = 247762 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/1d/cb/313e80644ea407f04f6602a9e23096540d9dc1878755f3952ea8d3d104be/psutil-6.1.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:0895b8414afafc526712c498bd9de2b063deaac4021a3b3c34566283464aff8e", size = 248777 },
|
{ url = "https://files.pythonhosted.org/packages/1d/cb/313e80644ea407f04f6602a9e23096540d9dc1878755f3952ea8d3d104be/psutil-6.1.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:0895b8414afafc526712c498bd9de2b063deaac4021a3b3c34566283464aff8e", size = 248777 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/65/8e/bcbe2025c587b5d703369b6a75b65d41d1367553da6e3f788aff91eaf5bd/psutil-6.1.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9dcbfce5d89f1d1f2546a2090f4fcf87c7f669d1d90aacb7d7582addece9fb38", size = 284259 },
|
{ url = "https://files.pythonhosted.org/packages/65/8e/bcbe2025c587b5d703369b6a75b65d41d1367553da6e3f788aff91eaf5bd/psutil-6.1.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9dcbfce5d89f1d1f2546a2090f4fcf87c7f669d1d90aacb7d7582addece9fb38", size = 284259 },
|
||||||
|
@ -3200,6 +3412,18 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/e3/b9/41f7efe80f6ce2ed3ee3c2dcfe10ab7adc1172f778cc9659509a79518c43/pydantic_core-2.23.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9261d3ce84fa1d38ed649c3638feefeae23d32ba9182963e465d58d62203bd24", size = 2116872 },
|
{ url = "https://files.pythonhosted.org/packages/e3/b9/41f7efe80f6ce2ed3ee3c2dcfe10ab7adc1172f778cc9659509a79518c43/pydantic_core-2.23.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9261d3ce84fa1d38ed649c3638feefeae23d32ba9182963e465d58d62203bd24", size = 2116872 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/63/08/b59b7a92e03dd25554b0436554bf23e7c29abae7cce4b1c459cd92746811/pydantic_core-2.23.4-cp312-none-win32.whl", hash = "sha256:4ba762ed58e8d68657fc1281e9bb72e1c3e79cc5d464be146e260c541ec12d84", size = 1738535 },
|
{ url = "https://files.pythonhosted.org/packages/63/08/b59b7a92e03dd25554b0436554bf23e7c29abae7cce4b1c459cd92746811/pydantic_core-2.23.4-cp312-none-win32.whl", hash = "sha256:4ba762ed58e8d68657fc1281e9bb72e1c3e79cc5d464be146e260c541ec12d84", size = 1738535 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/88/8d/479293e4d39ab409747926eec4329de5b7129beaedc3786eca070605d07f/pydantic_core-2.23.4-cp312-none-win_amd64.whl", hash = "sha256:97df63000f4fea395b2824da80e169731088656d1818a11b95f3b173747b6cd9", size = 1917992 },
|
{ url = "https://files.pythonhosted.org/packages/88/8d/479293e4d39ab409747926eec4329de5b7129beaedc3786eca070605d07f/pydantic_core-2.23.4-cp312-none-win_amd64.whl", hash = "sha256:97df63000f4fea395b2824da80e169731088656d1818a11b95f3b173747b6cd9", size = 1917992 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ad/ef/16ee2df472bf0e419b6bc68c05bf0145c49247a1095e85cee1463c6a44a1/pydantic_core-2.23.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7530e201d10d7d14abce4fb54cfe5b94a0aefc87da539d0346a484ead376c3cc", size = 1856143 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/da/fa/bc3dbb83605669a34a93308e297ab22be82dfb9dcf88c6cf4b4f264e0a42/pydantic_core-2.23.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:df933278128ea1cd77772673c73954e53a1c95a4fdf41eef97c2b779271bd0bd", size = 1770063 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4e/48/e813f3bbd257a712303ebdf55c8dc46f9589ec74b384c9f652597df3288d/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cb3da3fd1b6a5d0279a01877713dbda118a2a4fc6f0d821a57da2e464793f05", size = 1790013 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b4/e0/56eda3a37929a1d297fcab1966db8c339023bcca0b64c5a84896db3fcc5c/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42c6dcb030aefb668a2b7009c85b27f90e51e6a3b4d5c9bc4c57631292015b0d", size = 1801077 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/04/be/5e49376769bfbf82486da6c5c1683b891809365c20d7c7e52792ce4c71f3/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:696dd8d674d6ce621ab9d45b205df149399e4bb9aa34102c970b721554828510", size = 1996782 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bc/24/e3ee6c04f1d58cc15f37bcc62f32c7478ff55142b7b3e6d42ea374ea427c/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2971bb5ffe72cc0f555c13e19b23c85b654dd2a8f7ab493c262071377bfce9f6", size = 2661375 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c1/f8/11a9006de4e89d016b8de74ebb1db727dc100608bb1e6bbe9d56a3cbbcce/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8394d940e5d400d04cad4f75c0598665cbb81aecefaca82ca85bd28264af7f9b", size = 2071635 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7c/45/bdce5779b59f468bdf262a5bc9eecbae87f271c51aef628d8c073b4b4b4c/pydantic_core-2.23.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0dff76e0602ca7d4cdaacc1ac4c005e0ce0dcfe095d5b5259163a80d3a10d327", size = 1916994 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d8/fa/c648308fe711ee1f88192cad6026ab4f925396d1293e8356de7e55be89b5/pydantic_core-2.23.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7d32706badfe136888bdea71c0def994644e09fff0bfe47441deaed8e96fdbc6", size = 1968877 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/16/16/b805c74b35607d24d37103007f899abc4880923b04929547ae68d478b7f4/pydantic_core-2.23.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ed541d70698978a20eb63d8c5d72f2cc6d7079d9d90f6b50bad07826f1320f5f", size = 2116814 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d1/58/5305e723d9fcdf1c5a655e6a4cc2a07128bf644ff4b1d98daf7a9dbf57da/pydantic_core-2.23.4-cp313-none-win32.whl", hash = "sha256:3d5639516376dce1940ea36edf408c554475369f5da2abd45d44621cb616f769", size = 1738360 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a5/ae/e14b0ff8b3f48e02394d8acd911376b7b66e164535687ef7dc24ea03072f/pydantic_core-2.23.4-cp313-none-win_amd64.whl", hash = "sha256:5a1504ad17ba4210df3a045132a7baeeba5a200e930f57512ee02909fc5c4cb5", size = 1919411 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/13/a9/5d582eb3204464284611f636b55c0a7410d748ff338756323cb1ce721b96/pydantic_core-2.23.4-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f455ee30a9d61d3e1a15abd5068827773d6e4dc513e795f380cdd59932c782d5", size = 1857135 },
|
{ url = "https://files.pythonhosted.org/packages/13/a9/5d582eb3204464284611f636b55c0a7410d748ff338756323cb1ce721b96/pydantic_core-2.23.4-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f455ee30a9d61d3e1a15abd5068827773d6e4dc513e795f380cdd59932c782d5", size = 1857135 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/2c/57/faf36290933fe16717f97829eabfb1868182ac495f99cf0eda9f59687c9d/pydantic_core-2.23.4-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1e90d2e3bd2c3863d48525d297cd143fe541be8bbf6f579504b9712cb6b643ec", size = 1740583 },
|
{ url = "https://files.pythonhosted.org/packages/2c/57/faf36290933fe16717f97829eabfb1868182ac495f99cf0eda9f59687c9d/pydantic_core-2.23.4-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1e90d2e3bd2c3863d48525d297cd143fe541be8bbf6f579504b9712cb6b643ec", size = 1740583 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/91/7c/d99e3513dc191c4fec363aef1bf4c8af9125d8fa53af7cb97e8babef4e40/pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e203fdf807ac7e12ab59ca2bfcabb38c7cf0b33c41efeb00f8e5da1d86af480", size = 1793637 },
|
{ url = "https://files.pythonhosted.org/packages/91/7c/d99e3513dc191c4fec363aef1bf4c8af9125d8fa53af7cb97e8babef4e40/pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e203fdf807ac7e12ab59ca2bfcabb38c7cf0b33c41efeb00f8e5da1d86af480", size = 1793637 },
|
||||||
|
@ -3444,6 +3668,9 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/00/7c/d00d6bdd96de4344e06c4afbf218bc86b54436a94c01c71a8701f613aa56/pywin32-308-cp312-cp312-win32.whl", hash = "sha256:587f3e19696f4bf96fde9d8a57cec74a57021ad5f204c9e627e15c33ff568897", size = 5939729 },
|
{ url = "https://files.pythonhosted.org/packages/00/7c/d00d6bdd96de4344e06c4afbf218bc86b54436a94c01c71a8701f613aa56/pywin32-308-cp312-cp312-win32.whl", hash = "sha256:587f3e19696f4bf96fde9d8a57cec74a57021ad5f204c9e627e15c33ff568897", size = 5939729 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/21/27/0c8811fbc3ca188f93b5354e7c286eb91f80a53afa4e11007ef661afa746/pywin32-308-cp312-cp312-win_amd64.whl", hash = "sha256:00b3e11ef09ede56c6a43c71f2d31857cf7c54b0ab6e78ac659497abd2834f47", size = 6543015 },
|
{ url = "https://files.pythonhosted.org/packages/21/27/0c8811fbc3ca188f93b5354e7c286eb91f80a53afa4e11007ef661afa746/pywin32-308-cp312-cp312-win_amd64.whl", hash = "sha256:00b3e11ef09ede56c6a43c71f2d31857cf7c54b0ab6e78ac659497abd2834f47", size = 6543015 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/9d/0f/d40f8373608caed2255781a3ad9a51d03a594a1248cd632d6a298daca693/pywin32-308-cp312-cp312-win_arm64.whl", hash = "sha256:9b4de86c8d909aed15b7011182c8cab38c8850de36e6afb1f0db22b8959e3091", size = 7976033 },
|
{ url = "https://files.pythonhosted.org/packages/9d/0f/d40f8373608caed2255781a3ad9a51d03a594a1248cd632d6a298daca693/pywin32-308-cp312-cp312-win_arm64.whl", hash = "sha256:9b4de86c8d909aed15b7011182c8cab38c8850de36e6afb1f0db22b8959e3091", size = 7976033 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a9/a4/aa562d8935e3df5e49c161b427a3a2efad2ed4e9cf81c3de636f1fdddfd0/pywin32-308-cp313-cp313-win32.whl", hash = "sha256:1c44539a37a5b7b21d02ab34e6a4d314e0788f1690d65b48e9b0b89f31abbbed", size = 5938579 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c7/50/b0efb8bb66210da67a53ab95fd7a98826a97ee21f1d22949863e6d588b22/pywin32-308-cp313-cp313-win_amd64.whl", hash = "sha256:fd380990e792eaf6827fcb7e187b2b4b1cede0585e3d0c9e84201ec27b9905e4", size = 6542056 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/26/df/2b63e3e4f2df0224f8aaf6d131f54fe4e8c96400eb9df563e2aae2e1a1f9/pywin32-308-cp313-cp313-win_arm64.whl", hash = "sha256:ef313c46d4c18dfb82a2431e3051ac8f112ccee1a34f29c263c583c568db63cd", size = 7974986 },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -3479,6 +3706,15 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611 },
|
{ url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591 },
|
{ url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338 },
|
{ url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446 },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -3526,6 +3762,27 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/07/18/907134c85c7152f679ed744e73e645b365f3ad571f38bdb62e36f347699a/pyzmq-26.2.0-cp312-cp312-win32.whl", hash = "sha256:989d842dc06dc59feea09e58c74ca3e1678c812a4a8a2a419046d711031f69c7", size = 575533 },
|
{ url = "https://files.pythonhosted.org/packages/07/18/907134c85c7152f679ed744e73e645b365f3ad571f38bdb62e36f347699a/pyzmq-26.2.0-cp312-cp312-win32.whl", hash = "sha256:989d842dc06dc59feea09e58c74ca3e1678c812a4a8a2a419046d711031f69c7", size = 575533 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/ce/2c/a6f4a20202a4d3c582ad93f95ee78d79bbdc26803495aec2912b17dbbb6c/pyzmq-26.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:2a50625acdc7801bc6f74698c5c583a491c61d73c6b7ea4dee3901bb99adb27a", size = 637768 },
|
{ url = "https://files.pythonhosted.org/packages/ce/2c/a6f4a20202a4d3c582ad93f95ee78d79bbdc26803495aec2912b17dbbb6c/pyzmq-26.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:2a50625acdc7801bc6f74698c5c583a491c61d73c6b7ea4dee3901bb99adb27a", size = 637768 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/5f/0e/eb16ff731632d30554bf5af4dbba3ffcd04518219d82028aea4ae1b02ca5/pyzmq-26.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:4d29ab8592b6ad12ebbf92ac2ed2bedcfd1cec192d8e559e2e099f648570e19b", size = 540675 },
|
{ url = "https://files.pythonhosted.org/packages/5f/0e/eb16ff731632d30554bf5af4dbba3ffcd04518219d82028aea4ae1b02ca5/pyzmq-26.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:4d29ab8592b6ad12ebbf92ac2ed2bedcfd1cec192d8e559e2e099f648570e19b", size = 540675 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/04/a7/0f7e2f6c126fe6e62dbae0bc93b1bd3f1099cf7fea47a5468defebe3f39d/pyzmq-26.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9dd8cd1aeb00775f527ec60022004d030ddc51d783d056e3e23e74e623e33726", size = 1006564 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/31/b6/a187165c852c5d49f826a690857684333a6a4a065af0a6015572d2284f6a/pyzmq-26.2.0-cp313-cp313-macosx_10_15_universal2.whl", hash = "sha256:28c812d9757fe8acecc910c9ac9dafd2ce968c00f9e619db09e9f8f54c3a68a3", size = 1340447 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/68/ba/f4280c58ff71f321602a6e24fd19879b7e79793fb8ab14027027c0fb58ef/pyzmq-26.2.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d80b1dd99c1942f74ed608ddb38b181b87476c6a966a88a950c7dee118fdf50", size = 665485 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/77/b5/c987a5c53c7d8704216f29fc3d810b32f156bcea488a940e330e1bcbb88d/pyzmq-26.2.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8c997098cc65e3208eca09303630e84d42718620e83b733d0fd69543a9cab9cb", size = 903484 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/29/c9/07da157d2db18c72a7eccef8e684cefc155b712a88e3d479d930aa9eceba/pyzmq-26.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ad1bc8d1b7a18497dda9600b12dc193c577beb391beae5cd2349184db40f187", size = 859981 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/43/09/e12501bd0b8394b7d02c41efd35c537a1988da67fc9c745cae9c6c776d31/pyzmq-26.2.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:bea2acdd8ea4275e1278350ced63da0b166421928276c7c8e3f9729d7402a57b", size = 860334 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/eb/ff/f5ec1d455f8f7385cc0a8b2acd8c807d7fade875c14c44b85c1bddabae21/pyzmq-26.2.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:23f4aad749d13698f3f7b64aad34f5fc02d6f20f05999eebc96b89b01262fb18", size = 1196179 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ec/8a/bb2ac43295b1950fe436a81fc5b298be0b96ac76fb029b514d3ed58f7b27/pyzmq-26.2.0-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:a4f96f0d88accc3dbe4a9025f785ba830f968e21e3e2c6321ccdfc9aef755115", size = 1507668 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a9/49/dbc284ebcfd2dca23f6349227ff1616a7ee2c4a35fe0a5d6c3deff2b4fed/pyzmq-26.2.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ced65e5a985398827cc9276b93ef6dfabe0273c23de8c7931339d7e141c2818e", size = 1406539 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/00/68/093cdce3fe31e30a341d8e52a1ad86392e13c57970d722c1f62a1d1a54b6/pyzmq-26.2.0-cp313-cp313-win32.whl", hash = "sha256:31507f7b47cc1ead1f6e86927f8ebb196a0bab043f6345ce070f412a59bf87b5", size = 575567 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/92/ae/6cc4657148143412b5819b05e362ae7dd09fb9fe76e2a539dcff3d0386bc/pyzmq-26.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:70fc7fcf0410d16ebdda9b26cbd8bf8d803d220a7f3522e060a69a9c87bf7bad", size = 637551 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6c/67/fbff102e201688f97c8092e4c3445d1c1068c2f27bbd45a578df97ed5f94/pyzmq-26.2.0-cp313-cp313-win_arm64.whl", hash = "sha256:c3789bd5768ab5618ebf09cef6ec2b35fed88709b104351748a63045f0ff9797", size = 540378 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3f/fe/2d998380b6e0122c6c4bdf9b6caf490831e5f5e2d08a203b5adff060c226/pyzmq-26.2.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:034da5fc55d9f8da09015d368f519478a52675e558c989bfcb5cf6d4e16a7d2a", size = 1007378 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4a/f4/30d6e7157f12b3a0390bde94d6a8567cdb88846ed068a6e17238a4ccf600/pyzmq-26.2.0-cp313-cp313t-macosx_10_15_universal2.whl", hash = "sha256:c92d73464b886931308ccc45b2744e5968cbaade0b1d6aeb40d8ab537765f5bc", size = 1329532 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/82/86/3fe917870e15ee1c3ad48229a2a64458e36036e64b4afa9659045d82bfa8/pyzmq-26.2.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:794a4562dcb374f7dbbfb3f51d28fb40123b5a2abadee7b4091f93054909add5", size = 653242 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/50/2d/242e7e6ef6c8c19e6cb52d095834508cd581ffb925699fd3c640cdc758f1/pyzmq-26.2.0-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aee22939bb6075e7afededabad1a56a905da0b3c4e3e0c45e75810ebe3a52672", size = 888404 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ac/11/7270566e1f31e4ea73c81ec821a4b1688fd551009a3d2bab11ec66cb1e8f/pyzmq-26.2.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ae90ff9dad33a1cfe947d2c40cb9cb5e600d759ac4f0fd22616ce6540f72797", size = 845858 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/91/d5/72b38fbc69867795c8711bdd735312f9fef1e3d9204e2f63ab57085434b9/pyzmq-26.2.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:43a47408ac52647dfabbc66a25b05b6a61700b5165807e3fbd40063fcaf46386", size = 847375 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/dd/9a/10ed3c7f72b4c24e719c59359fbadd1a27556a28b36cdf1cd9e4fb7845d5/pyzmq-26.2.0-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:25bf2374a2a8433633c65ccb9553350d5e17e60c8eb4de4d92cc6bd60f01d306", size = 1183489 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/72/2d/8660892543fabf1fe41861efa222455811adac9f3c0818d6c3170a1153e3/pyzmq-26.2.0-cp313-cp313t-musllinux_1_1_i686.whl", hash = "sha256:007137c9ac9ad5ea21e6ad97d3489af654381324d5d3ba614c323f60dab8fae6", size = 1492932 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7b/d6/32fd69744afb53995619bc5effa2a405ae0d343cd3e747d0fbc43fe894ee/pyzmq-26.2.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:470d4a4f6d48fb34e92d768b4e8a5cc3780db0d69107abf1cd7ff734b9766eb0", size = 1392485 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/53/fb/36b2b2548286e9444e52fcd198760af99fd89102b5be50f0660fcfe902df/pyzmq-26.2.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:706e794564bec25819d21a41c31d4df2d48e1cc4b061e8d345d7fb4dd3e94072", size = 906955 },
|
{ url = "https://files.pythonhosted.org/packages/53/fb/36b2b2548286e9444e52fcd198760af99fd89102b5be50f0660fcfe902df/pyzmq-26.2.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:706e794564bec25819d21a41c31d4df2d48e1cc4b061e8d345d7fb4dd3e94072", size = 906955 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/77/8f/6ce54f8979a01656e894946db6299e2273fcee21c8e5fa57c6295ef11f57/pyzmq-26.2.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b435f2753621cd36e7c1762156815e21c985c72b19135dac43a7f4f31d28dd1", size = 565701 },
|
{ url = "https://files.pythonhosted.org/packages/77/8f/6ce54f8979a01656e894946db6299e2273fcee21c8e5fa57c6295ef11f57/pyzmq-26.2.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b435f2753621cd36e7c1762156815e21c985c72b19135dac43a7f4f31d28dd1", size = 565701 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/ee/1c/bf8cd66730a866b16db8483286078892b7f6536f8c389fb46e4beba0a970/pyzmq-26.2.0-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:160c7e0a5eb178011e72892f99f918c04a131f36056d10d9c1afb223fc952c2d", size = 794312 },
|
{ url = "https://files.pythonhosted.org/packages/ee/1c/bf8cd66730a866b16db8483286078892b7f6536f8c389fb46e4beba0a970/pyzmq-26.2.0-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:160c7e0a5eb178011e72892f99f918c04a131f36056d10d9c1afb223fc952c2d", size = 794312 },
|
||||||
|
@ -3598,6 +3855,21 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/ea/75/9753e9dcebfa7c3645563ef5c8a58f3a47e799c872165f37c55737dadd3e/regex-2024.9.11-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:18406efb2f5a0e57e3a5881cd9354c1512d3bb4f5c45d96d110a66114d84d23a", size = 787333 },
|
{ url = "https://files.pythonhosted.org/packages/ea/75/9753e9dcebfa7c3645563ef5c8a58f3a47e799c872165f37c55737dadd3e/regex-2024.9.11-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:18406efb2f5a0e57e3a5881cd9354c1512d3bb4f5c45d96d110a66114d84d23a", size = 787333 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/bc/4e/ba1cbca93141f7416624b3ae63573e785d4bc1834c8be44a8f0747919eca/regex-2024.9.11-cp312-cp312-win32.whl", hash = "sha256:e464b467f1588e2c42d26814231edecbcfe77f5ac414d92cbf4e7b55b2c2a776", size = 262058 },
|
{ url = "https://files.pythonhosted.org/packages/bc/4e/ba1cbca93141f7416624b3ae63573e785d4bc1834c8be44a8f0747919eca/regex-2024.9.11-cp312-cp312-win32.whl", hash = "sha256:e464b467f1588e2c42d26814231edecbcfe77f5ac414d92cbf4e7b55b2c2a776", size = 262058 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/6e/16/efc5f194778bf43e5888209e5cec4b258005d37c613b67ae137df3b89c53/regex-2024.9.11-cp312-cp312-win_amd64.whl", hash = "sha256:9e8719792ca63c6b8340380352c24dcb8cd7ec49dae36e963742a275dfae6009", size = 273526 },
|
{ url = "https://files.pythonhosted.org/packages/6e/16/efc5f194778bf43e5888209e5cec4b258005d37c613b67ae137df3b89c53/regex-2024.9.11-cp312-cp312-win_amd64.whl", hash = "sha256:9e8719792ca63c6b8340380352c24dcb8cd7ec49dae36e963742a275dfae6009", size = 273526 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/93/0a/d1c6b9af1ff1e36832fe38d74d5c5bab913f2bdcbbd6bc0e7f3ce8b2f577/regex-2024.9.11-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c157bb447303070f256e084668b702073db99bbb61d44f85d811025fcf38f784", size = 483376 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a4/42/5910a050c105d7f750a72dcb49c30220c3ae4e2654e54aaaa0e9bc0584cb/regex-2024.9.11-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4db21ece84dfeefc5d8a3863f101995de646c6cb0536952c321a2650aa202c36", size = 288112 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8d/56/0c262aff0e9224fa7ffce47b5458d373f4d3e3ff84e99b5ff0cb15e0b5b2/regex-2024.9.11-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:220e92a30b426daf23bb67a7962900ed4613589bab80382be09b48896d211e92", size = 284608 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b9/54/9fe8f9aec5007bbbbce28ba3d2e3eaca425f95387b7d1e84f0d137d25237/regex-2024.9.11-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb1ae19e64c14c7ec1995f40bd932448713d3c73509e82d8cd7744dc00e29e86", size = 795337 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b2/e7/6b2f642c3cded271c4f16cc4daa7231be544d30fe2b168e0223724b49a61/regex-2024.9.11-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f47cd43a5bfa48f86925fe26fbdd0a488ff15b62468abb5d2a1e092a4fb10e85", size = 835848 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cd/9e/187363bdf5d8c0e4662117b92aa32bf52f8f09620ae93abc7537d96d3311/regex-2024.9.11-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9d4a76b96f398697fe01117093613166e6aa8195d63f1b4ec3f21ab637632963", size = 823503 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f8/10/601303b8ee93589f879664b0cfd3127949ff32b17f9b6c490fb201106c4d/regex-2024.9.11-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ea51dcc0835eea2ea31d66456210a4e01a076d820e9039b04ae8d17ac11dee6", size = 797049 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ef/1c/ea200f61ce9f341763f2717ab4daebe4422d83e9fd4ac5e33435fd3a148d/regex-2024.9.11-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b7aaa315101c6567a9a45d2839322c51c8d6e81f67683d529512f5bcfb99c802", size = 784144 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d8/5c/d2429be49ef3292def7688401d3deb11702c13dcaecdc71d2b407421275b/regex-2024.9.11-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c57d08ad67aba97af57a7263c2d9006d5c404d721c5f7542f077f109ec2a4a29", size = 782483 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/12/d9/cbc30f2ff7164f3b26a7760f87c54bf8b2faed286f60efd80350a51c5b99/regex-2024.9.11-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f8404bf61298bb6f8224bb9176c1424548ee1181130818fcd2cbffddc768bed8", size = 790320 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/19/1d/43ed03a236313639da5a45e61bc553c8d41e925bcf29b0f8ecff0c2c3f25/regex-2024.9.11-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:dd4490a33eb909ef5078ab20f5f000087afa2a4daa27b4c072ccb3cb3050ad84", size = 860435 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/34/4f/5d04da61c7c56e785058a46349f7285ae3ebc0726c6ea7c5c70600a52233/regex-2024.9.11-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:eee9130eaad130649fd73e5cd92f60e55708952260ede70da64de420cdcad554", size = 859571 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/12/7f/8398c8155a3c70703a8e91c29532558186558e1aea44144b382faa2a6f7a/regex-2024.9.11-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6a2644a93da36c784e546de579ec1806bfd2763ef47babc1b03d765fe560c9f8", size = 787398 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/58/3a/f5903977647a9a7e46d5535e9e96c194304aeeca7501240509bde2f9e17f/regex-2024.9.11-cp313-cp313-win32.whl", hash = "sha256:e997fd30430c57138adc06bba4c7c2968fb13d101e57dd5bb9355bf8ce3fa7e8", size = 262035 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ff/80/51ba3a4b7482f6011095b3a036e07374f64de180b7d870b704ed22509002/regex-2024.9.11-cp313-cp313-win_amd64.whl", hash = "sha256:042c55879cfeb21a8adacc84ea347721d3d83a159da6acdf1116859e2427c43f", size = 273510 },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -3698,6 +3970,19 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/70/2d/5536d28c507a4679179ab15aa0049440e4d3dd6752050fa0843ed11e9354/rpds_py-0.20.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2cf126d33a91ee6eedc7f3197b53e87a2acdac63602c0f03a02dd69e4b138174", size = 528807 },
|
{ url = "https://files.pythonhosted.org/packages/70/2d/5536d28c507a4679179ab15aa0049440e4d3dd6752050fa0843ed11e9354/rpds_py-0.20.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2cf126d33a91ee6eedc7f3197b53e87a2acdac63602c0f03a02dd69e4b138174", size = 528807 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/e3/62/7ebe6ec0d3dd6130921f8cffb7e34afb7f71b3819aa0446a24c5e81245ec/rpds_py-0.20.0-cp312-none-win32.whl", hash = "sha256:8bc7690f7caee50b04a79bf017a8d020c1f48c2a1077ffe172abec59870f1139", size = 200993 },
|
{ url = "https://files.pythonhosted.org/packages/e3/62/7ebe6ec0d3dd6130921f8cffb7e34afb7f71b3819aa0446a24c5e81245ec/rpds_py-0.20.0-cp312-none-win32.whl", hash = "sha256:8bc7690f7caee50b04a79bf017a8d020c1f48c2a1077ffe172abec59870f1139", size = 200993 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/ec/2f/b938864d66b86a6e4acadefdc56de75ef56f7cafdfd568a6464605457bd5/rpds_py-0.20.0-cp312-none-win_amd64.whl", hash = "sha256:0e13e6952ef264c40587d510ad676a988df19adea20444c2b295e536457bc585", size = 214458 },
|
{ url = "https://files.pythonhosted.org/packages/ec/2f/b938864d66b86a6e4acadefdc56de75ef56f7cafdfd568a6464605457bd5/rpds_py-0.20.0-cp312-none-win_amd64.whl", hash = "sha256:0e13e6952ef264c40587d510ad676a988df19adea20444c2b295e536457bc585", size = 214458 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/99/32/43b919a0a423c270a838ac2726b1c7168b946f2563fd99a51aaa9692d00f/rpds_py-0.20.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:aa9a0521aeca7d4941499a73ad7d4f8ffa3d1affc50b9ea11d992cd7eff18a29", size = 321465 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/58/a9/c4d899cb28e9e47b0ff12462e8f827381f243176036f17bef9c1604667f2/rpds_py-0.20.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4a1f1d51eccb7e6c32ae89243cb352389228ea62f89cd80823ea7dd1b98e0b91", size = 312900 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8f/90/9e51670575b5dfaa8c823369ef7d943087bfb73d4f124a99ad6ef19a2b26/rpds_py-0.20.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a86a9b96070674fc88b6f9f71a97d2c1d3e5165574615d1f9168ecba4cecb24", size = 370973 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fc/c1/523f2a03f853fc0d4c1acbef161747e9ab7df0a8abf6236106e333540921/rpds_py-0.20.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6c8ef2ebf76df43f5750b46851ed1cdf8f109d7787ca40035fe19fbdc1acc5a7", size = 370890 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/51/ca/2458a771f16b0931de4d384decbe43016710bc948036c8f4562d6e063437/rpds_py-0.20.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b74b25f024b421d5859d156750ea9a65651793d51b76a2e9238c05c9d5f203a9", size = 397174 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/00/7d/6e06807f6305ea2408b364efb0eef83a6e21b5e7b5267ad6b473b9a7e416/rpds_py-0.20.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:57eb94a8c16ab08fef6404301c38318e2c5a32216bf5de453e2714c964c125c8", size = 426449 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8c/d1/6c9e65260a819a1714510a7d69ac1d68aa23ee9ce8a2d9da12187263c8fc/rpds_py-0.20.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1940dae14e715e2e02dfd5b0f64a52e8374a517a1e531ad9412319dc3ac7879", size = 357698 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5d/fb/ecea8b5286d2f03eec922be7173a03ed17278944f7c124348f535116db15/rpds_py-0.20.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d20277fd62e1b992a50c43f13fbe13277a31f8c9f70d59759c88f644d66c619f", size = 378530 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e3/e3/ac72f858957f52a109c588589b73bd2fad4a0fc82387fb55fb34aeb0f9cd/rpds_py-0.20.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:06db23d43f26478303e954c34c75182356ca9aa7797d22c5345b16871ab9c45c", size = 545753 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b2/a4/a27683b519d5fc98e4390a3b130117d80fd475c67aeda8aac83c0e8e326a/rpds_py-0.20.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b2a5db5397d82fa847e4c624b0c98fe59d2d9b7cf0ce6de09e4d2e80f8f5b3f2", size = 552443 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a1/ed/c074d248409b4432b1ccb2056974175fa0af2d1bc1f9c21121f80a358fa3/rpds_py-0.20.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5a35df9f5548fd79cb2f52d27182108c3e6641a4feb0f39067911bf2adaa3e57", size = 528380 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d5/bd/04caf938895d2d78201e89c0c8a94dfd9990c34a19ff52fb01d0912343e3/rpds_py-0.20.0-cp313-none-win32.whl", hash = "sha256:fd2d84f40633bc475ef2d5490b9c19543fbf18596dcb1b291e3a12ea5d722f7a", size = 200540 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/95/cc/109eb8b9863680411ae703664abacaa035820c7755acc9686d5dd02cdd2e/rpds_py-0.20.0-cp313-none-win_amd64.whl", hash = "sha256:9bc2d153989e3216b0559251b0c260cfd168ec78b1fac33dd485750a228db5a2", size = 214111 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/06/39/bf1f664c347c946ef56cecaa896e3693d91acc741afa78ebb3fdb7aba08b/rpds_py-0.20.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:617c7357272c67696fd052811e352ac54ed1d9b49ab370261a80d3b6ce385045", size = 319444 },
|
{ url = "https://files.pythonhosted.org/packages/06/39/bf1f664c347c946ef56cecaa896e3693d91acc741afa78ebb3fdb7aba08b/rpds_py-0.20.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:617c7357272c67696fd052811e352ac54ed1d9b49ab370261a80d3b6ce385045", size = 319444 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/c1/71/876135d3cb90d62468540b84e8e83ff4dc92052ab309bfdea7ea0b9221ad/rpds_py-0.20.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9426133526f69fcaba6e42146b4e12d6bc6c839b8b555097020e2b78ce908dcc", size = 311699 },
|
{ url = "https://files.pythonhosted.org/packages/c1/71/876135d3cb90d62468540b84e8e83ff4dc92052ab309bfdea7ea0b9221ad/rpds_py-0.20.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9426133526f69fcaba6e42146b4e12d6bc6c839b8b555097020e2b78ce908dcc", size = 311699 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/f7/da/8ccaeba6a3dda7467aebaf893de9eafd56275e2c90773c83bf15fb0b8374/rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:deb62214c42a261cb3eb04d474f7155279c1a8a8c30ac89b7dcb1721d92c3c02", size = 367825 },
|
{ url = "https://files.pythonhosted.org/packages/f7/da/8ccaeba6a3dda7467aebaf893de9eafd56275e2c90773c83bf15fb0b8374/rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:deb62214c42a261cb3eb04d474f7155279c1a8a8c30ac89b7dcb1721d92c3c02", size = 367825 },
|
||||||
|
@ -3769,6 +4054,14 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/8e/ee/8a26858ca517e9c64f84b4c7734b89bda8e63bec85c3d2f432d225bb1886/scipy-1.14.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f9ea80f2e65bdaa0b7627fb00cbeb2daf163caa015e59b7516395fe3bd1e066", size = 40849331 },
|
{ url = "https://files.pythonhosted.org/packages/8e/ee/8a26858ca517e9c64f84b4c7734b89bda8e63bec85c3d2f432d225bb1886/scipy-1.14.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f9ea80f2e65bdaa0b7627fb00cbeb2daf163caa015e59b7516395fe3bd1e066", size = 40849331 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/a5/cd/06f72bc9187840f1c99e1a8750aad4216fc7dfdd7df46e6280add14b4822/scipy-1.14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:edaf02b82cd7639db00dbff629995ef185c8df4c3ffa71a5562a595765a06ce1", size = 42544049 },
|
{ url = "https://files.pythonhosted.org/packages/a5/cd/06f72bc9187840f1c99e1a8750aad4216fc7dfdd7df46e6280add14b4822/scipy-1.14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:edaf02b82cd7639db00dbff629995ef185c8df4c3ffa71a5562a595765a06ce1", size = 42544049 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/aa/7d/43ab67228ef98c6b5dd42ab386eae2d7877036970a0d7e3dd3eb47a0d530/scipy-1.14.1-cp312-cp312-win_amd64.whl", hash = "sha256:2ff38e22128e6c03ff73b6bb0f85f897d2362f8c052e3b8ad00532198fbdae3f", size = 44521212 },
|
{ url = "https://files.pythonhosted.org/packages/aa/7d/43ab67228ef98c6b5dd42ab386eae2d7877036970a0d7e3dd3eb47a0d530/scipy-1.14.1-cp312-cp312-win_amd64.whl", hash = "sha256:2ff38e22128e6c03ff73b6bb0f85f897d2362f8c052e3b8ad00532198fbdae3f", size = 44521212 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/50/ef/ac98346db016ff18a6ad7626a35808f37074d25796fd0234c2bb0ed1e054/scipy-1.14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1729560c906963fc8389f6aac023739ff3983e727b1a4d87696b7bf108316a79", size = 39091068 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b9/cc/70948fe9f393b911b4251e96b55bbdeaa8cca41f37c26fd1df0232933b9e/scipy-1.14.1-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:4079b90df244709e675cdc8b93bfd8a395d59af40b72e339c2287c91860deb8e", size = 29875417 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3b/2e/35f549b7d231c1c9f9639f9ef49b815d816bf54dd050da5da1c11517a218/scipy-1.14.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:e0cf28db0f24a38b2a0ca33a85a54852586e43cf6fd876365c86e0657cfe7d73", size = 23084508 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3f/d6/b028e3f3e59fae61fb8c0f450db732c43dd1d836223a589a8be9f6377203/scipy-1.14.1-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:0c2f95de3b04e26f5f3ad5bb05e74ba7f68b837133a4492414b3afd79dfe540e", size = 25503364 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a7/2f/6c142b352ac15967744d62b165537a965e95d557085db4beab2a11f7943b/scipy-1.14.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b99722ea48b7ea25e8e015e8341ae74624f72e5f21fc2abd45f3a93266de4c5d", size = 35292639 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/56/46/2449e6e51e0d7c3575f289f6acb7f828938eaab8874dbccfeb0cd2b71a27/scipy-1.14.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5149e3fd2d686e42144a093b206aef01932a0059c2a33ddfa67f5f035bdfe13e", size = 40798288 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/32/cd/9d86f7ed7f4497c9fd3e39f8918dd93d9f647ba80d7e34e4946c0c2d1a7c/scipy-1.14.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e4f5a7c49323533f9103d4dacf4e4f07078f360743dec7f7596949149efeec06", size = 42524647 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f5/1b/6ee032251bf4cdb0cc50059374e86a9f076308c1512b61c4e003e241efb7/scipy-1.14.1-cp313-cp313-win_amd64.whl", hash = "sha256:baff393942b550823bfce952bb62270ee17504d02a1801d7fd0719534dfb9c84", size = 44469524 },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -4049,6 +4342,14 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/ea/09/badfc9293bc3ccba6ede05e5f2b44a760aa47d84da1fc5a326e963e3d4d9/SQLAlchemy-2.0.36-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1bc330d9d29c7f06f003ab10e1eaced295e87940405afe1b110f2eb93a233588", size = 3205147 },
|
{ url = "https://files.pythonhosted.org/packages/ea/09/badfc9293bc3ccba6ede05e5f2b44a760aa47d84da1fc5a326e963e3d4d9/SQLAlchemy-2.0.36-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1bc330d9d29c7f06f003ab10e1eaced295e87940405afe1b110f2eb93a233588", size = 3205147 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/c8/60/70e681de02a13c4b27979b7b78da3058c49bacc9858c89ba672e030f03f2/SQLAlchemy-2.0.36-cp312-cp312-win32.whl", hash = "sha256:79d2e78abc26d871875b419e1fd3c0bca31a1cb0043277d0d850014599626c2e", size = 2062709 },
|
{ url = "https://files.pythonhosted.org/packages/c8/60/70e681de02a13c4b27979b7b78da3058c49bacc9858c89ba672e030f03f2/SQLAlchemy-2.0.36-cp312-cp312-win32.whl", hash = "sha256:79d2e78abc26d871875b419e1fd3c0bca31a1cb0043277d0d850014599626c2e", size = 2062709 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/b7/ed/f6cd9395e41bfe47dd253d74d2dfc3cab34980d4e20c8878cb1117306085/SQLAlchemy-2.0.36-cp312-cp312-win_amd64.whl", hash = "sha256:b544ad1935a8541d177cb402948b94e871067656b3a0b9e91dbec136b06a2ff5", size = 2088433 },
|
{ url = "https://files.pythonhosted.org/packages/b7/ed/f6cd9395e41bfe47dd253d74d2dfc3cab34980d4e20c8878cb1117306085/SQLAlchemy-2.0.36-cp312-cp312-win_amd64.whl", hash = "sha256:b544ad1935a8541d177cb402948b94e871067656b3a0b9e91dbec136b06a2ff5", size = 2088433 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/78/5c/236398ae3678b3237726819b484f15f5c038a9549da01703a771f05a00d6/SQLAlchemy-2.0.36-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b5cc79df7f4bc3d11e4b542596c03826063092611e481fcf1c9dfee3c94355ef", size = 2087651 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a8/14/55c47420c0d23fb67a35af8be4719199b81c59f3084c28d131a7767b0b0b/SQLAlchemy-2.0.36-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3c01117dd36800f2ecaa238c65365b7b16497adc1522bf84906e5710ee9ba0e8", size = 2078132 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3d/97/1e843b36abff8c4a7aa2e37f9bea364f90d021754c2de94d792c2d91405b/SQLAlchemy-2.0.36-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9bc633f4ee4b4c46e7adcb3a9b5ec083bf1d9a97c1d3854b92749d935de40b9b", size = 3164559 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7b/c5/07f18a897b997f6d6b234fab2bf31dccf66d5d16a79fe329aefc95cd7461/SQLAlchemy-2.0.36-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e46ed38affdfc95d2c958de328d037d87801cfcbea6d421000859e9789e61c2", size = 3177897 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b3/cd/e16f3cbefd82b5c40b33732da634ec67a5f33b587744c7ab41699789d492/SQLAlchemy-2.0.36-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b2985c0b06e989c043f1dc09d4fe89e1616aadd35392aea2844f0458a989eacf", size = 3111289 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/15/85/5b8a3b0bc29c9928aa62b5c91fcc8335f57c1de0a6343873b5f372e3672b/SQLAlchemy-2.0.36-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a121d62ebe7d26fec9155f83f8be5189ef1405f5973ea4874a26fab9f1e262c", size = 3139491 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a1/95/81babb6089938680dfe2cd3f88cd3fd39cccd1543b7cb603b21ad881bff1/SQLAlchemy-2.0.36-cp313-cp313-win32.whl", hash = "sha256:0572f4bd6f94752167adfd7c1bed84f4b240ee6203a95e05d1e208d488d0d436", size = 2060439 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c1/ce/5f7428df55660d6879d0522adc73a3364970b5ef33ec17fa125c5dbcac1d/SQLAlchemy-2.0.36-cp313-cp313-win_amd64.whl", hash = "sha256:8c78ac40bde930c60e0f78b3cd184c580f89456dd87fc08f9e3ee3ce8765ce88", size = 2084574 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/b8/49/21633706dd6feb14cd3f7935fc00b60870ea057686035e1a99ae6d9d9d53/SQLAlchemy-2.0.36-py3-none-any.whl", hash = "sha256:fddbe92b4760c6f5d48162aef14824add991aeda8ddadb3c31d56eb15ca69f8e", size = 1883787 },
|
{ url = "https://files.pythonhosted.org/packages/b8/49/21633706dd6feb14cd3f7935fc00b60870ea057686035e1a99ae6d9d9d53/SQLAlchemy-2.0.36-py3-none-any.whl", hash = "sha256:fddbe92b4760c6f5d48162aef14824add991aeda8ddadb3c31d56eb15ca69f8e", size = 1883787 },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -4236,6 +4537,12 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/26/32/e0e3a859136e95c85a572e4806dc58bf1ddf651108ae8b97d5f3ebe1a244/tiktoken-0.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2908c0d043a7d03ebd80347266b0e58440bdef5564f84f4d29fb235b5df3b04", size = 1175432 },
|
{ url = "https://files.pythonhosted.org/packages/26/32/e0e3a859136e95c85a572e4806dc58bf1ddf651108ae8b97d5f3ebe1a244/tiktoken-0.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2908c0d043a7d03ebd80347266b0e58440bdef5564f84f4d29fb235b5df3b04", size = 1175432 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/c7/89/926b66e9025b97e9fbabeaa59048a736fe3c3e4530a204109571104f921c/tiktoken-0.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:294440d21a2a51e12d4238e68a5972095534fe9878be57d905c476017bff99fc", size = 1236576 },
|
{ url = "https://files.pythonhosted.org/packages/c7/89/926b66e9025b97e9fbabeaa59048a736fe3c3e4530a204109571104f921c/tiktoken-0.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:294440d21a2a51e12d4238e68a5972095534fe9878be57d905c476017bff99fc", size = 1236576 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/45/e2/39d4aa02a52bba73b2cd21ba4533c84425ff8786cc63c511d68c8897376e/tiktoken-0.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:d8f3192733ac4d77977432947d563d7e1b310b96497acd3c196c9bddb36ed9db", size = 883824 },
|
{ url = "https://files.pythonhosted.org/packages/45/e2/39d4aa02a52bba73b2cd21ba4533c84425ff8786cc63c511d68c8897376e/tiktoken-0.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:d8f3192733ac4d77977432947d563d7e1b310b96497acd3c196c9bddb36ed9db", size = 883824 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e3/38/802e79ba0ee5fcbf240cd624143f57744e5d411d2e9d9ad2db70d8395986/tiktoken-0.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:02be1666096aff7da6cbd7cdaa8e7917bfed3467cd64b38b1f112e96d3b06a24", size = 1039648 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b1/da/24cdbfc302c98663fbea66f5866f7fa1048405c7564ab88483aea97c3b1a/tiktoken-0.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c94ff53c5c74b535b2cbf431d907fc13c678bbd009ee633a2aca269a04389f9a", size = 982763 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e4/f0/0ecf79a279dfa41fc97d00adccf976ecc2556d3c08ef3e25e45eb31f665b/tiktoken-0.8.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b231f5e8982c245ee3065cd84a4712d64692348bc609d84467c57b4b72dcbc5", size = 1144417 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ab/d3/155d2d4514f3471a25dc1d6d20549ef254e2aa9bb5b1060809b1d3b03d3a/tiktoken-0.8.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4177faa809bd55f699e88c96d9bb4635d22e3f59d635ba6fd9ffedf7150b9953", size = 1175108 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/19/eb/5989e16821ee8300ef8ee13c16effc20dfc26c777d05fbb6825e3c037b81/tiktoken-0.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5376b6f8dc4753cd81ead935c5f518fa0fbe7e133d9e25f648d8c4dabdd4bad7", size = 1236520 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/40/59/14b20465f1d1cb89cfbc96ec27e5617b2d41c79da12b5e04e96d689be2a7/tiktoken-0.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:18228d624807d66c87acd8f25fc135665617cab220671eb65b50f5d70fa51f69", size = 883849 },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -4548,6 +4855,18 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/44/81/1f701323a9f70805bc81c74c990137123344a80ea23ab9504a99492907f8/watchfiles-0.24.0-cp312-none-win32.whl", hash = "sha256:d9018153cf57fc302a2a34cb7564870b859ed9a732d16b41a9b5cb2ebed2d444", size = 264109 },
|
{ url = "https://files.pythonhosted.org/packages/44/81/1f701323a9f70805bc81c74c990137123344a80ea23ab9504a99492907f8/watchfiles-0.24.0-cp312-none-win32.whl", hash = "sha256:d9018153cf57fc302a2a34cb7564870b859ed9a732d16b41a9b5cb2ebed2d444", size = 264109 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/b4/0b/32cde5bc2ebd9f351be326837c61bdeb05ad652b793f25c91cac0b48a60b/watchfiles-0.24.0-cp312-none-win_amd64.whl", hash = "sha256:551ec3ee2a3ac9cbcf48a4ec76e42c2ef938a7e905a35b42a1267fa4b1645896", size = 277055 },
|
{ url = "https://files.pythonhosted.org/packages/b4/0b/32cde5bc2ebd9f351be326837c61bdeb05ad652b793f25c91cac0b48a60b/watchfiles-0.24.0-cp312-none-win_amd64.whl", hash = "sha256:551ec3ee2a3ac9cbcf48a4ec76e42c2ef938a7e905a35b42a1267fa4b1645896", size = 277055 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/4b/81/daade76ce33d21dbec7a15afd7479de8db786e5f7b7d249263b4ea174e08/watchfiles-0.24.0-cp312-none-win_arm64.whl", hash = "sha256:b52a65e4ea43c6d149c5f8ddb0bef8d4a1e779b77591a458a893eb416624a418", size = 266169 },
|
{ url = "https://files.pythonhosted.org/packages/4b/81/daade76ce33d21dbec7a15afd7479de8db786e5f7b7d249263b4ea174e08/watchfiles-0.24.0-cp312-none-win_arm64.whl", hash = "sha256:b52a65e4ea43c6d149c5f8ddb0bef8d4a1e779b77591a458a893eb416624a418", size = 266169 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/30/dc/6e9f5447ae14f645532468a84323a942996d74d5e817837a5c8ce9d16c69/watchfiles-0.24.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:3d2e3ab79a1771c530233cadfd277fcc762656d50836c77abb2e5e72b88e3a48", size = 373764 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/79/c0/c3a9929c372816c7fc87d8149bd722608ea58dc0986d3ef7564c79ad7112/watchfiles-0.24.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:327763da824817b38ad125dcd97595f942d720d32d879f6c4ddf843e3da3fe90", size = 367873 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2e/11/ff9a4445a7cfc1c98caf99042df38964af12eed47d496dd5d0d90417349f/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd82010f8ab451dabe36054a1622870166a67cf3fce894f68895db6f74bbdc94", size = 438381 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/48/a3/763ba18c98211d7bb6c0f417b2d7946d346cdc359d585cc28a17b48e964b/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d64ba08db72e5dfd5c33be1e1e687d5e4fcce09219e8aee893a4862034081d4e", size = 432809 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/30/4c/616c111b9d40eea2547489abaf4ffc84511e86888a166d3a4522c2ba44b5/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1cf1f6dd7825053f3d98f6d33f6464ebdd9ee95acd74ba2c34e183086900a827", size = 451801 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b6/be/d7da83307863a422abbfeb12903a76e43200c90ebe5d6afd6a59d158edea/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:43e3e37c15a8b6fe00c1bce2473cfa8eb3484bbeecf3aefbf259227e487a03df", size = 468886 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1d/d3/3dfe131ee59d5e90b932cf56aba5c996309d94dafe3d02d204364c23461c/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88bcd4d0fe1d8ff43675360a72def210ebad3f3f72cabfeac08d825d2639b4ab", size = 472973 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/42/6c/279288cc5653a289290d183b60a6d80e05f439d5bfdfaf2d113738d0f932/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:999928c6434372fde16c8f27143d3e97201160b48a614071261701615a2a156f", size = 425282 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d6/d7/58afe5e85217e845edf26d8780c2d2d2ae77675eeb8d1b8b8121d799ce52/watchfiles-0.24.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:30bbd525c3262fd9f4b1865cb8d88e21161366561cd7c9e1194819e0a33ea86b", size = 612540 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6d/d5/b96eeb9fe3fda137200dd2f31553670cbc731b1e13164fd69b49870b76ec/watchfiles-0.24.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:edf71b01dec9f766fb285b73930f95f730bb0943500ba0566ae234b5c1618c18", size = 593625 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c1/e5/c326fe52ee0054107267608d8cea275e80be4455b6079491dfd9da29f46f/watchfiles-0.24.0-cp313-none-win32.whl", hash = "sha256:f4c96283fca3ee09fb044f02156d9570d156698bc3734252175a38f0e8975f07", size = 263899 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a6/8b/8a7755c5e7221bb35fe4af2dc44db9174f90ebf0344fd5e9b1e8b42d381e/watchfiles-0.24.0-cp313-none-win_amd64.whl", hash = "sha256:a974231b4fdd1bb7f62064a0565a6b107d27d21d9acb50c484d2cdba515b9366", size = 276622 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/df/94/1ad200e937ec91b2a9d6b39ae1cf9c2b1a9cc88d5ceb43aa5c6962eb3c11/watchfiles-0.24.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:632676574429bee8c26be8af52af20e0c718cc7f5f67f3fb658c71928ccd4f7f", size = 376986 },
|
{ url = "https://files.pythonhosted.org/packages/df/94/1ad200e937ec91b2a9d6b39ae1cf9c2b1a9cc88d5ceb43aa5c6962eb3c11/watchfiles-0.24.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:632676574429bee8c26be8af52af20e0c718cc7f5f67f3fb658c71928ccd4f7f", size = 376986 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/ee/fd/d9e020d687ccf90fe95efc513fbb39a8049cf5a3ff51f53c59fcf4c47a5d/watchfiles-0.24.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:a2a9891723a735d3e2540651184be6fd5b96880c08ffe1a98bae5017e65b544b", size = 369445 },
|
{ url = "https://files.pythonhosted.org/packages/ee/fd/d9e020d687ccf90fe95efc513fbb39a8049cf5a3ff51f53c59fcf4c47a5d/watchfiles-0.24.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:a2a9891723a735d3e2540651184be6fd5b96880c08ffe1a98bae5017e65b544b", size = 369445 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/43/cb/c0279b35053555d10ef03559c5aebfcb0c703d9c70a7b4e532df74b9b0e8/watchfiles-0.24.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a7fa2bc0efef3e209a8199fd111b8969fe9db9c711acc46636686331eda7dd4", size = 439383 },
|
{ url = "https://files.pythonhosted.org/packages/43/cb/c0279b35053555d10ef03559c5aebfcb0c703d9c70a7b4e532df74b9b0e8/watchfiles-0.24.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a7fa2bc0efef3e209a8199fd111b8969fe9db9c711acc46636686331eda7dd4", size = 439383 },
|
||||||
|
@ -4611,6 +4930,17 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/5c/f1/a29dd6046d3a722d26f182b783a7997d25298873a14028c4760347974ea3/websockets-13.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a9dcaf8b0cc72a392760bb8755922c03e17a5a54e08cca58e8b74f6902b433cf", size = 164686 },
|
{ url = "https://files.pythonhosted.org/packages/5c/f1/a29dd6046d3a722d26f182b783a7997d25298873a14028c4760347974ea3/websockets-13.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a9dcaf8b0cc72a392760bb8755922c03e17a5a54e08cca58e8b74f6902b433cf", size = 164686 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/0f/99/ab1cdb282f7e595391226f03f9b498f52109d25a2ba03832e21614967dfa/websockets-13.1-cp312-cp312-win32.whl", hash = "sha256:2f85cf4f2a1ba8f602298a853cec8526c2ca42a9a4b947ec236eaedb8f2dc80c", size = 158712 },
|
{ url = "https://files.pythonhosted.org/packages/0f/99/ab1cdb282f7e595391226f03f9b498f52109d25a2ba03832e21614967dfa/websockets-13.1-cp312-cp312-win32.whl", hash = "sha256:2f85cf4f2a1ba8f602298a853cec8526c2ca42a9a4b947ec236eaedb8f2dc80c", size = 158712 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/46/93/e19160db48b5581feac8468330aa11b7292880a94a37d7030478596cc14e/websockets-13.1-cp312-cp312-win_amd64.whl", hash = "sha256:38377f8b0cdeee97c552d20cf1865695fcd56aba155ad1b4ca8779a5b6ef4ac3", size = 159145 },
|
{ url = "https://files.pythonhosted.org/packages/46/93/e19160db48b5581feac8468330aa11b7292880a94a37d7030478596cc14e/websockets-13.1-cp312-cp312-win_amd64.whl", hash = "sha256:38377f8b0cdeee97c552d20cf1865695fcd56aba155ad1b4ca8779a5b6ef4ac3", size = 159145 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/51/20/2b99ca918e1cbd33c53db2cace5f0c0cd8296fc77558e1908799c712e1cd/websockets-13.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a9ab1e71d3d2e54a0aa646ab6d4eebfaa5f416fe78dfe4da2839525dc5d765c6", size = 157828 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b8/47/0932a71d3d9c0e9483174f60713c84cee58d62839a143f21a2bcdbd2d205/websockets-13.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b9d7439d7fab4dce00570bb906875734df13d9faa4b48e261c440a5fec6d9708", size = 155487 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a9/60/f1711eb59ac7a6c5e98e5637fef5302f45b6f76a2c9d64fd83bbb341377a/websockets-13.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:327b74e915cf13c5931334c61e1a41040e365d380f812513a255aa804b183418", size = 155721 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6a/e6/ba9a8db7f9d9b0e5f829cf626ff32677f39824968317223605a6b419d445/websockets-13.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:325b1ccdbf5e5725fdcb1b0e9ad4d2545056479d0eee392c291c1bf76206435a", size = 165609 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c1/22/4ec80f1b9c27a0aebd84ccd857252eda8418ab9681eb571b37ca4c5e1305/websockets-13.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:346bee67a65f189e0e33f520f253d5147ab76ae42493804319b5716e46dddf0f", size = 164556 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/27/ac/35f423cb6bb15600438db80755609d27eda36d4c0b3c9d745ea12766c45e/websockets-13.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91a0fa841646320ec0d3accdff5b757b06e2e5c86ba32af2e0815c96c7a603c5", size = 164993 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/31/4e/98db4fd267f8be9e52e86b6ee4e9aa7c42b83452ea0ea0672f176224b977/websockets-13.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:18503d2c5f3943e93819238bf20df71982d193f73dcecd26c94514f417f6b135", size = 165360 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3f/15/3f0de7cda70ffc94b7e7024544072bc5b26e2c1eb36545291abb755d8cdb/websockets-13.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a9cd1af7e18e5221d2878378fbc287a14cd527fdd5939ed56a18df8a31136bb2", size = 164745 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a1/6e/66b6b756aebbd680b934c8bdbb6dcb9ce45aad72cde5f8a7208dbb00dd36/websockets-13.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:70c5be9f416aa72aab7a2a76c90ae0a4fe2755c1816c153c1a2bcc3333ce4ce6", size = 164732 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/35/c6/12e3aab52c11aeb289e3dbbc05929e7a9d90d7a9173958477d3ef4f8ce2d/websockets-13.1-cp313-cp313-win32.whl", hash = "sha256:624459daabeb310d3815b276c1adef475b3e6804abaf2d9d2c061c319f7f187d", size = 158709 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/41/d8/63d6194aae711d7263df4498200c690a9c39fb437ede10f3e157a6343e0d/websockets-13.1-cp313-cp313-win_amd64.whl", hash = "sha256:c518e84bb59c2baae725accd355c8dc517b4a3ed8db88b4bc93c78dae2974bf2", size = 159144 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/2d/75/6da22cb3ad5b8c606963f9a5f9f88656256fecc29d420b4b2bf9e0c7d56f/websockets-13.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5dd6da9bec02735931fccec99d97c29f47cc61f644264eb995ad6c0c27667238", size = 155499 },
|
{ url = "https://files.pythonhosted.org/packages/2d/75/6da22cb3ad5b8c606963f9a5f9f88656256fecc29d420b4b2bf9e0c7d56f/websockets-13.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5dd6da9bec02735931fccec99d97c29f47cc61f644264eb995ad6c0c27667238", size = 155499 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/c0/ba/22833d58629088fcb2ccccedfae725ac0bbcd713319629e97125b52ac681/websockets-13.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:2510c09d8e8df777177ee3d40cd35450dc169a81e747455cc4197e63f7e7bfe5", size = 155737 },
|
{ url = "https://files.pythonhosted.org/packages/c0/ba/22833d58629088fcb2ccccedfae725ac0bbcd713319629e97125b52ac681/websockets-13.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:2510c09d8e8df777177ee3d40cd35450dc169a81e747455cc4197e63f7e7bfe5", size = 155737 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/95/54/61684fe22bdb831e9e1843d972adadf359cf04ab8613285282baea6a24bb/websockets-13.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1c3cf67185543730888b20682fb186fc8d0fa6f07ccc3ef4390831ab4b388d9", size = 157095 },
|
{ url = "https://files.pythonhosted.org/packages/95/54/61684fe22bdb831e9e1843d972adadf359cf04ab8613285282baea6a24bb/websockets-13.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1c3cf67185543730888b20682fb186fc8d0fa6f07ccc3ef4390831ab4b388d9", size = 157095 },
|
||||||
|
@ -4758,6 +5088,22 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/ad/8d/b7b5d43cf22a020b564ddf7502d83df150d797e34f18f6bf5fe0f12cbd91/yarl-1.16.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1a5cf32539373ff39d97723e39a9283a7277cbf1224f7aef0c56c9598b6486c3", size = 355746 },
|
{ url = "https://files.pythonhosted.org/packages/ad/8d/b7b5d43cf22a020b564ddf7502d83df150d797e34f18f6bf5fe0f12cbd91/yarl-1.16.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1a5cf32539373ff39d97723e39a9283a7277cbf1224f7aef0c56c9598b6486c3", size = 355746 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/d9/a6/a2098bf3f09d38eb540b2b192e180d9d41c2ff64b692783db2188f0a55e3/yarl-1.16.0-cp312-cp312-win32.whl", hash = "sha256:a5b6c09b9b4253d6a208b0f4a2f9206e511ec68dce9198e0fbec4f160137aa67", size = 82675 },
|
{ url = "https://files.pythonhosted.org/packages/d9/a6/a2098bf3f09d38eb540b2b192e180d9d41c2ff64b692783db2188f0a55e3/yarl-1.16.0-cp312-cp312-win32.whl", hash = "sha256:a5b6c09b9b4253d6a208b0f4a2f9206e511ec68dce9198e0fbec4f160137aa67", size = 82675 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/ed/a6/0a54b382cfc336e772b72681d6816a99222dc2d21876e649474973b8d244/yarl-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:1208ca14eed2fda324042adf8d6c0adf4a31522fa95e0929027cd487875f0240", size = 88986 },
|
{ url = "https://files.pythonhosted.org/packages/ed/a6/0a54b382cfc336e772b72681d6816a99222dc2d21876e649474973b8d244/yarl-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:1208ca14eed2fda324042adf8d6c0adf4a31522fa95e0929027cd487875f0240", size = 88986 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/57/56/eef0a7050fcd11d70c536453f014d4b2dfd83fb934c9857fa1a912832405/yarl-1.16.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a5ace0177520bd4caa99295a9b6fb831d0e9a57d8e0501a22ffaa61b4c024283", size = 139373 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3f/b2/88eb9e98c5a4549606ebf673cba0d701f13ec855021b781f8e3fd7c04190/yarl-1.16.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7118bdb5e3ed81acaa2095cba7ec02a0fe74b52a16ab9f9ac8e28e53ee299732", size = 92759 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/95/1d/c3b794ef82a3b1894a9f8fc1012b073a85464b95c646ac217e8013137ea3/yarl-1.16.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:38fec8a2a94c58bd47c9a50a45d321ab2285ad133adefbbadf3012c054b7e656", size = 90573 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7f/35/39a5dcbf7ef320607bcfd1c0498ce348181b97627c3901139b429d806cf1/yarl-1.16.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8791d66d81ee45866a7bb15a517b01a2bcf583a18ebf5d72a84e6064c417e64b", size = 332461 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/36/29/2a468c8b44aa750d0f3416bc24d58464237b402388a8f03091a58537274a/yarl-1.16.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1cf936ba67bc6c734f3aa1c01391da74ab7fc046a9f8bbfa230b8393b90cf472", size = 343045 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/91/6a/002300c86ed7ef3cd5ac890a0e17101aee06c64abe2e43f9dad85bc32c70/yarl-1.16.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1aab176dd55b59f77a63b27cffaca67d29987d91a5b615cbead41331e6b7428", size = 344592 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ea/69/ca4228e0f560f0c5817e0ebd789690c78ab17e6a876b38a5d000889b2f63/yarl-1.16.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:995d0759004c08abd5d1b81300a91d18c8577c6389300bed1c7c11675105a44d", size = 338127 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/81/df/32eea6e5199f7298ec15cf708895f35a7d2899177ed556e6bdf6819462aa/yarl-1.16.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1bc22e00edeb068f71967ab99081e9406cd56dbed864fc3a8259442999d71552", size = 326127 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9a/11/1a888df53acd3d1d4b8dc803e0c8ed4a4b6cabc2abe19e4de31aa6b86857/yarl-1.16.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:35b4f7842154176523e0a63c9b871168c69b98065d05a4f637fce342a6a2693a", size = 345219 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/34/88/44fd8b372c4c50c010e66c62bfb34e67d6bd217c973599e0ee03f74e74ec/yarl-1.16.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:7ace71c4b7a0c41f317ae24be62bb61e9d80838d38acb20e70697c625e71f120", size = 339742 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ee/c8/eaa53bd40db61265cec09d3c432d8bcd8ab9fd3a9fc5b0afdd13ab27b4a8/yarl-1.16.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:8f639e3f5795a6568aa4f7d2ac6057c757dcd187593679f035adbf12b892bb00", size = 344695 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1b/8f/b00aa91bd3bc8ef41781b13ac967c9c5c2e3ca0c516cffdd15ac035a1839/yarl-1.16.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:e8be3aff14f0120ad049121322b107f8a759be76a6a62138322d4c8a337a9e2c", size = 353617 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f1/88/8e86a28a840b8dc30c880fdde127f9610c56e55796a2cc969949b4a60fe7/yarl-1.16.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:122d8e7986043d0549e9eb23c7fd23be078be4b70c9eb42a20052b3d3149c6f2", size = 359911 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ee/61/9d59f7096fd72d5f68168ed8134773982ee48a8cb4009ecb34344e064999/yarl-1.16.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0fd9c227990f609c165f56b46107d0bc34553fe0387818c42c02f77974402c36", size = 358847 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f7/25/c323097b066a2b5a554f77e27a35bc067aebfcd3a001a0a3a6bc14190460/yarl-1.16.0-cp313-cp313-win32.whl", hash = "sha256:595ca5e943baed31d56b33b34736461a371c6ea0038d3baec399949dd628560b", size = 308302 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/52/76/ca2c3de3511a127fc4124723e7ccc641aef5e0ec56c66d25dbd11f19ab84/yarl-1.16.0-cp313-cp313-win_amd64.whl", hash = "sha256:921b81b8d78f0e60242fb3db615ea3f368827a76af095d5a69f1c3366db3f596", size = 314035 },
|
||||||
{ url = "https://files.pythonhosted.org/packages/fb/f7/87a32867ddc1a9817018bfd6109ee57646a543acf0d272843d8393e575f9/yarl-1.16.0-py3-none-any.whl", hash = "sha256:e6980a558d8461230c457218bd6c92dfc1d10205548215c2c21d79dc8d0a96f3", size = 43746 },
|
{ url = "https://files.pythonhosted.org/packages/fb/f7/87a32867ddc1a9817018bfd6109ee57646a543acf0d272843d8393e575f9/yarl-1.16.0-py3-none-any.whl", hash = "sha256:e6980a558d8461230c457218bd6c92dfc1d10205548215c2c21d79dc8d0a96f3", size = 43746 },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue