From fe96f7de24cb1968c56c977a84d735e5a59a15a1 Mon Sep 17 00:00:00 2001 From: Victor Dibia Date: Tue, 26 Nov 2024 15:39:36 -0800 Subject: [PATCH] Add Session Saving to AGS (#4369) * fix import issue related to agentchat update #4245 * update uv lock file * fix db auto_upgrade logic issue. * im prove msg rendering issue * Support termination condition combination. Closes #4325 * fix db instantiation bug * update yarn.lock, closes #4260 #4262 * remove deps for now with vulnerabilities found by dependabot #4262 * update db tests * add ability to load sessions from db .. * format updates, add format checks to ags * format check fixes * linting and ruff check fixes * make tests for ags non-parrallel to avoid db race conditions. * format updates * fix concurrency issue * minor ui tweaks, move run start to websocket * lint fixes * update uv.lock * Update python/packages/autogen-studio/autogenstudio/datamodel/types.py Co-authored-by: Eric Zhu * Update python/packages/autogen-studio/autogenstudio/teammanager.py Co-authored-by: Eric Zhu * reuse user proxy from agentchat * ui tweaks --------- Co-authored-by: Eric Zhu Co-authored-by: Hussein Mozannar --- .../autogen-studio/autogenstudio/__init__.py | 19 +- .../autogen-studio/autogenstudio/cli.py | 8 +- .../autogenstudio/components/__init__.py | 1 - .../components/agents/__init__.py | 0 .../components/agents/userproxy.py | 47 - .../autogenstudio/database/__init__.py | 4 +- .../database/component_factory.py | 224 +- .../autogenstudio/database/config_manager.py | 156 +- .../autogenstudio/database/db_manager.py | 198 +- .../autogenstudio/database/schema_manager.py | 331 +-- .../autogenstudio/datamodel/__init__.py | 13 +- .../autogenstudio/datamodel/db.py | 159 +- .../autogenstudio/datamodel/types.py | 36 +- .../autogen-studio/autogenstudio/profiler.py | 108 - .../autogenstudio/teammanager.py | 42 +- .../autogenstudio/utils/__init__.py | 1 - .../autogenstudio/utils/utils.py | 62 +- .../autogen-studio/autogenstudio/version.py | 2 +- .../autogen-studio/autogenstudio/web/app.py | 16 +- .../autogen-studio/autogenstudio/web/deps.py | 63 +- .../autogenstudio/web/initialization.py | 15 +- .../autogenstudio/web/managers/connection.py | 262 ++- .../autogenstudio/web/routes/agents.py | 168 +- .../autogenstudio/web/routes/gallery.py | 62 + .../autogenstudio/web/routes/models.py | 81 +- .../autogenstudio/web/routes/runs.py | 75 +- .../autogenstudio/web/routes/sessions.py | 155 +- .../autogenstudio/web/routes/teams.py | 133 +- .../autogenstudio/web/routes/tools.py | 90 +- .../autogenstudio/web/routes/ws.py | 55 +- .../autogen-studio/frontend/package.json | 4 +- .../src/components/types/datamodel.ts | 46 +- .../playground/chat/agentflow/agentflow.tsx | 221 +- .../playground/chat/agentflow/agentnode.tsx | 4 +- .../views/playground/chat/agentflow/edge.tsx | 94 +- .../chat/agentflow/edgemessagemodal.tsx | 103 + .../components/views/playground/chat/chat.tsx | 877 ++++--- .../chat/{threadview.tsx => inputrequest.tsx} | 112 +- .../views/playground/chat/messagelist.tsx | 289 --- .../views/playground/chat/rendermessage.tsx | 9 +- .../views/playground/chat/runview.tsx | 271 +++ .../src/components/views/shared/markdown.tsx | 12 +- .../components/views/shared/session/api.ts | 19 +- .../frontend/src/pages/index.tsx | 2 +- .../autogen-studio/frontend/yarn.lock | 2048 ++++------------- .../autogen-studio/notebooks/tutorial.ipynb | 122 +- python/packages/autogen-studio/pyproject.toml | 21 +- .../tests/test_component_factory.py | 129 +- .../autogen-studio/tests/test_db_manager.py | 89 +- python/uv.lock | 4 +- 50 files changed, 2744 insertions(+), 4318 deletions(-) delete mode 100644 python/packages/autogen-studio/autogenstudio/components/__init__.py delete mode 100644 python/packages/autogen-studio/autogenstudio/components/agents/__init__.py delete mode 100644 python/packages/autogen-studio/autogenstudio/components/agents/userproxy.py delete mode 100644 python/packages/autogen-studio/autogenstudio/profiler.py create mode 100644 python/packages/autogen-studio/autogenstudio/web/routes/gallery.py create mode 100644 python/packages/autogen-studio/frontend/src/components/views/playground/chat/agentflow/edgemessagemodal.tsx rename python/packages/autogen-studio/frontend/src/components/views/playground/chat/{threadview.tsx => inputrequest.tsx} (59%) delete mode 100644 python/packages/autogen-studio/frontend/src/components/views/playground/chat/messagelist.tsx create mode 100644 python/packages/autogen-studio/frontend/src/components/views/playground/chat/runview.tsx diff --git a/python/packages/autogen-studio/autogenstudio/__init__.py b/python/packages/autogen-studio/autogenstudio/__init__.py index 833950913331..137cbad5a834 100644 --- a/python/packages/autogen-studio/autogenstudio/__init__.py +++ b/python/packages/autogen-studio/autogenstudio/__init__.py @@ -1,3 +1,18 @@ -from .datamodel import * +from .database.db_manager import DatabaseManager +from .datamodel import Agent, AgentConfig, Model, ModelConfig, Team, TeamConfig, Tool, ToolConfig +from .teammanager import TeamManager from .version import __version__ -from .teammanager import * + +__all__ = [ + "Tool", + "Model", + "DatabaseManager", + "Team", + "Agent", + "ToolConfig", + "ModelConfig", + "TeamConfig", + "AgentConfig", + "TeamManager", + "__version__", +] diff --git a/python/packages/autogen-studio/autogenstudio/cli.py b/python/packages/autogen-studio/autogenstudio/cli.py index b8612f4ad97b..90f4331f0b75 100644 --- a/python/packages/autogen-studio/autogenstudio/cli.py +++ b/python/packages/autogen-studio/autogenstudio/cli.py @@ -15,7 +15,7 @@ def ui( host: str = "127.0.0.1", port: int = 8081, workers: int = 1, - reload: Annotated[bool, typer.Option("--reload")] = True, + reload: Annotated[bool, typer.Option("--reload")] = False, docs: bool = True, appdir: str = None, database_uri: Optional[str] = None, @@ -48,11 +48,7 @@ def ui( port=port, workers=workers, reload=reload, - reload_excludes=[ - "**/alembic/*", - "**/alembic.ini", - "**/versions/*" - ] if reload else None + reload_excludes=["**/alembic/*", "**/alembic.ini", "**/versions/*"] if reload else None, ) diff --git a/python/packages/autogen-studio/autogenstudio/components/__init__.py b/python/packages/autogen-studio/autogenstudio/components/__init__.py deleted file mode 100644 index ac3f3116bc2f..000000000000 --- a/python/packages/autogen-studio/autogenstudio/components/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .agents.userproxy import UserProxyAgent diff --git a/python/packages/autogen-studio/autogenstudio/components/agents/__init__.py b/python/packages/autogen-studio/autogenstudio/components/agents/__init__.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/python/packages/autogen-studio/autogenstudio/components/agents/userproxy.py b/python/packages/autogen-studio/autogenstudio/components/agents/userproxy.py deleted file mode 100644 index cb0fba52e07f..000000000000 --- a/python/packages/autogen-studio/autogenstudio/components/agents/userproxy.py +++ /dev/null @@ -1,47 +0,0 @@ -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 diff --git a/python/packages/autogen-studio/autogenstudio/database/__init__.py b/python/packages/autogen-studio/autogenstudio/database/__init__.py index 18e67140acce..acdf583557c3 100644 --- a/python/packages/autogen-studio/autogenstudio/database/__init__.py +++ b/python/packages/autogen-studio/autogenstudio/database/__init__.py @@ -1,3 +1,3 @@ -from .db_manager import DatabaseManager -from .component_factory import ComponentFactory, Component +from .component_factory import Component, ComponentFactory from .config_manager import ConfigurationManager +from .db_manager import DatabaseManager diff --git a/python/packages/autogen-studio/autogenstudio/database/component_factory.py b/python/packages/autogen-studio/autogenstudio/database/component_factory.py index bd8fec61a36a..a82c4660e23d 100644 --- a/python/packages/autogen-studio/autogenstudio/database/component_factory.py +++ b/python/packages/autogen-studio/autogenstudio/database/component_factory.py @@ -1,43 +1,45 @@ -import os -from pathlib import Path -from typing import Callable, List, Literal, Union, Optional, Dict, Any, Type -from datetime import datetime import json -from autogen_agentchat.task import MaxMessageTermination, TextMentionTermination, StopMessageTermination -import yaml import logging -from packaging import version +from datetime import datetime +from pathlib import Path +from typing import Callable, Dict, List, Literal, Optional, Union -from ..datamodel import ( - TeamConfig, AgentConfig, ModelConfig, ToolConfig, - TeamTypes, AgentTypes, ModelTypes, ToolTypes, - ComponentType, ComponentConfig, ComponentConfigInput, TerminationConfig, TerminationTypes, Response -) -from ..components import UserProxyAgent -from autogen_agentchat.agents import AssistantAgent +import aiofiles +import yaml +from autogen_agentchat.agents import AssistantAgent, UserProxyAgent +from autogen_agentchat.task import MaxMessageTermination, StopMessageTermination, TextMentionTermination from autogen_agentchat.teams import RoundRobinGroupChat, SelectorGroupChat -from autogen_ext.models import OpenAIChatCompletionClient from autogen_core.components.tools import FunctionTool +from autogen_ext.models import OpenAIChatCompletionClient + +from ..datamodel.types import ( + AgentConfig, + AgentTypes, + ComponentConfig, + ComponentConfigInput, + ComponentTypes, + ModelConfig, + ModelTypes, + TeamConfig, + TeamTypes, + TerminationConfig, + TerminationTypes, + ToolConfig, + ToolTypes, +) +from ..utils.utils import Version logger = logging.getLogger(__name__) -# Type definitions for supported components TeamComponent = Union[RoundRobinGroupChat, SelectorGroupChat] -AgentComponent = Union[AssistantAgent] # Will grow with more agent types -# Will grow with more model types +AgentComponent = Union[AssistantAgent] ModelComponent = Union[OpenAIChatCompletionClient] ToolComponent = Union[FunctionTool] # Will grow with more tool types -TerminationComponent = Union[MaxMessageTermination, - StopMessageTermination, TextMentionTermination] - -# Config type definitions - -Component = Union[TeamComponent, AgentComponent, ModelComponent, ToolComponent] +TerminationComponent = Union[MaxMessageTermination, StopMessageTermination, TextMentionTermination] +Component = Union[TeamComponent, AgentComponent, ModelComponent, ToolComponent, TerminationComponent] -ReturnType = Literal['object', 'dict', 'config'] -Component = Union[RoundRobinGroupChat, SelectorGroupChat, - AssistantAgent, OpenAIChatCompletionClient, FunctionTool] +ReturnType = Literal["object", "dict", "config"] DEFAULT_SELECTOR_PROMPT = """You are in a role play game. The following roles are available: {roles}. @@ -48,18 +50,18 @@ Read the above conversation. Then select the next role from {participants} to play. Only return the role. """ -CONFIG_RETURN_TYPES = Literal['object', 'dict', 'config'] +CONFIG_RETURN_TYPES = Literal["object", "dict", "config"] class ComponentFactory: """Creates and manages agent components with versioned configuration loading""" SUPPORTED_VERSIONS = { - ComponentType.TEAM: ["1.0.0"], - ComponentType.AGENT: ["1.0.0"], - ComponentType.MODEL: ["1.0.0"], - ComponentType.TOOL: ["1.0.0"], - ComponentType.TERMINATION: ["1.0.0"] + ComponentTypes.TEAM: ["1.0.0"], + ComponentTypes.AGENT: ["1.0.0"], + ComponentTypes.MODEL: ["1.0.0"], + ComponentTypes.TOOL: ["1.0.0"], + ComponentTypes.TERMINATION: ["1.0.0"], } def __init__(self): @@ -68,10 +70,7 @@ def __init__(self): self._last_cache_clear = datetime.now() async def load( - self, - component: ComponentConfigInput, - input_func: Optional[Callable] = None, - return_type: ReturnType = 'object' + self, component: ComponentConfigInput, input_func: Optional[Callable] = None, return_type: ReturnType = "object" ) -> Union[Component, dict, ComponentConfig]: """ Universal loader for any component type @@ -103,24 +102,23 @@ async def load( ) # Return early if dict or config requested - if return_type == 'dict': + if return_type == "dict": return config.model_dump() - elif return_type == 'config': + elif return_type == "config": return config # Otherwise create and return component instance handlers = { - ComponentType.TEAM: lambda c: self.load_team(c, input_func), - ComponentType.AGENT: lambda c: self.load_agent(c, input_func), - ComponentType.MODEL: self.load_model, - ComponentType.TOOL: self.load_tool, - ComponentType.TERMINATION: self.load_termination + ComponentTypes.TEAM: lambda c: self.load_team(c, input_func), + ComponentTypes.AGENT: lambda c: self.load_agent(c, input_func), + ComponentTypes.MODEL: self.load_model, + ComponentTypes.TOOL: self.load_tool, + ComponentTypes.TERMINATION: self.load_termination, } handler = handlers.get(config.component_type) if not handler: - raise ValueError( - f"Unknown component type: {config.component_type}") + raise ValueError(f"Unknown component type: {config.component_type}") return await handler(config) @@ -128,7 +126,9 @@ async def load( logger.error(f"Failed to load component: {str(e)}") raise - async def load_directory(self, directory: Union[str, Path], 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. """ @@ -137,13 +137,12 @@ async def load_directory(self, directory: Union[str, Path], return_type: ReturnT directory = Path(directory) # Using Path.iterdir() instead of os.listdir for path in list(directory.glob("*")): - if path.suffix.lower().endswith(('.json', '.yaml', '.yml')): + if path.suffix.lower().endswith((".json", ".yaml", ".yml")): try: component = await self.load(path, return_type=return_type) components.append(component) except Exception as e: - logger.info( - f"Failed to load component: {str(e)}, {path}") + logger.info(f"Failed to load component: {str(e)}, {path}") return components except Exception as e: @@ -156,14 +155,14 @@ def _dict_to_config(self, config_dict: dict) -> ComponentConfig: raise ValueError("component_type is required in configuration") config_types = { - ComponentType.TEAM: TeamConfig, - ComponentType.AGENT: AgentConfig, - ComponentType.MODEL: ModelConfig, - ComponentType.TOOL: ToolConfig, - ComponentType.TERMINATION: TerminationConfig # Add mapping for termination + ComponentTypes.TEAM: TeamConfig, + ComponentTypes.AGENT: AgentConfig, + ComponentTypes.MODEL: ModelConfig, + ComponentTypes.TOOL: ToolConfig, + ComponentTypes.TERMINATION: TerminationConfig, # Add mapping for termination } - component_type = ComponentType(config_dict["component_type"]) + component_type = ComponentTypes(config_dict["component_type"]) config_class = config_types.get(component_type) if not config_class: @@ -174,28 +173,44 @@ def _dict_to_config(self, config_dict: dict) -> ComponentConfig: async def load_termination(self, config: TerminationConfig) -> TerminationComponent: """Create termination condition instance from configuration.""" try: - if config.termination_type == TerminationTypes.MAX_MESSAGES: + if config.termination_type == TerminationTypes.COMBINATION: + if not config.conditions or len(config.conditions) < 2: + raise ValueError("Combination termination requires at least 2 conditions") + if not config.operator: + raise ValueError("Combination termination requires an operator (and/or)") + + # Load first two conditions + conditions = [await self.load_termination(cond) for cond in config.conditions[:2]] + result = conditions[0] & conditions[1] if config.operator == "and" else conditions[0] | conditions[1] + + # Process remaining conditions if any + for condition in config.conditions[2:]: + next_condition = await self.load_termination(condition) + result = result & next_condition if config.operator == "and" else result | next_condition + + return result + + elif config.termination_type == TerminationTypes.MAX_MESSAGES: + if config.max_messages is None: + raise ValueError("max_messages parameter required for MaxMessageTermination") return MaxMessageTermination(max_messages=config.max_messages) + elif config.termination_type == TerminationTypes.STOP_MESSAGE: return StopMessageTermination() + elif config.termination_type == TerminationTypes.TEXT_MENTION: if not config.text: - raise ValueError( - "text parameter required for TextMentionTermination") + raise ValueError("text parameter required for TextMentionTermination") return TextMentionTermination(text=config.text) + else: - raise ValueError( - f"Unsupported termination type: {config.termination_type}") + raise ValueError(f"Unsupported termination type: {config.termination_type}") + except Exception as e: logger.error(f"Failed to create termination condition: {str(e)}") - raise ValueError( - f"Termination condition creation failed: {str(e)}") - - async def load_team( - self, - config: TeamConfig, - input_func: Optional[Callable] = None - ) -> TeamComponent: + raise ValueError(f"Termination condition creation failed: {str(e)}") from e + + async def load_team(self, config: TeamConfig, input_func: Optional[Callable] = None) -> TeamComponent: """Create team instance from configuration.""" try: # Load participants (agents) with input_func @@ -216,33 +231,25 @@ async def load_team( # Create team based on type if config.team_type == TeamTypes.ROUND_ROBIN: - return RoundRobinGroupChat( - participants=participants, - termination_condition=termination - ) + return RoundRobinGroupChat(participants=participants, termination_condition=termination) elif config.team_type == TeamTypes.SELECTOR: if not model_client: - raise ValueError( - "SelectorGroupChat requires a model_client") + raise ValueError("SelectorGroupChat requires a model_client") selector_prompt = config.selector_prompt if config.selector_prompt else DEFAULT_SELECTOR_PROMPT return SelectorGroupChat( participants=participants, model_client=model_client, termination_condition=termination, - selector_prompt=selector_prompt + selector_prompt=selector_prompt, ) else: raise ValueError(f"Unsupported team type: {config.team_type}") except Exception as 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)}") from e - async def load_agent( - self, - config: AgentConfig, - input_func: Optional[Callable] = None - ) -> AgentComponent: + async def load_agent(self, config: AgentConfig, input_func: Optional[Callable] = None) -> AgentComponent: """Create agent instance from configuration.""" try: # Load model client if specified @@ -263,7 +270,7 @@ async def load_agent( return UserProxyAgent( name=config.name, description=config.description or "A human user", - input_func=input_func # Pass through to UserProxyAgent + input_func=input_func, # Pass through to UserProxyAgent ) elif config.agent_type == AgentTypes.ASSISTANT: return AssistantAgent( @@ -271,15 +278,14 @@ async def load_agent( description=config.description or "A helpful assistant", model_client=model_client, tools=tools, - system_message=system_message + system_message=system_message, ) else: - raise ValueError( - f"Unsupported agent type: {config.agent_type}") + raise ValueError(f"Unsupported agent type: {config.agent_type}") except Exception as e: logger.error(f"Failed to create agent {config.name}: {str(e)}") - raise ValueError(f"Agent creation failed: {str(e)}") + raise ValueError(f"Agent creation failed: {str(e)}") from e async def load_model(self, config: ModelConfig) -> ModelComponent: """Create model instance from configuration.""" @@ -291,20 +297,15 @@ async def load_model(self, config: ModelConfig) -> ModelComponent: return self._model_cache[cache_key] if config.model_type == ModelTypes.OPENAI: - model = OpenAIChatCompletionClient( - model=config.model, - api_key=config.api_key, - base_url=config.base_url - ) + model = OpenAIChatCompletionClient(model=config.model, api_key=config.api_key, base_url=config.base_url) self._model_cache[cache_key] = model return model else: - raise ValueError( - f"Unsupported model type: {config.model_type}") + raise ValueError(f"Unsupported model type: {config.model_type}") except Exception as e: logger.error(f"Failed to create model {config.model}: {str(e)}") - raise ValueError(f"Model creation failed: {str(e)}") + raise ValueError(f"Model creation failed: {str(e)}") from e async def load_tool(self, config: ToolConfig) -> ToolComponent: """Create tool instance from configuration.""" @@ -321,9 +322,7 @@ async def load_tool(self, config: ToolConfig) -> ToolComponent: if config.tool_type == ToolTypes.PYTHON_FUNCTION: tool = FunctionTool( - name=config.name, - description=config.description, - func=self._func_from_string(config.content) + name=config.name, description=config.description, func=self._func_from_string(config.content) ) self._tool_cache[cache_key] = tool return tool @@ -334,7 +333,6 @@ async def load_tool(self, config: ToolConfig) -> ToolComponent: logger.error(f"Failed to create tool '{config.name}': {str(e)}") raise - # Helper methods remain largely the same async def _load_from_file(self, path: Union[str, Path]) -> dict: """Load configuration from JSON or YAML file.""" path = Path(path) @@ -342,15 +340,16 @@ async def _load_from_file(self, path: Union[str, Path]) -> dict: raise FileNotFoundError(f"Config file not found: {path}") try: - with open(path) as f: - if path.suffix == '.json': - return json.load(f) - elif path.suffix in ('.yml', '.yaml'): - return yaml.safe_load(f) + async with aiofiles.open(path) as f: + content = await f.read() + if path.suffix == ".json": + return json.loads(content) + elif path.suffix in (".yml", ".yaml"): + return yaml.safe_load(content) else: raise ValueError(f"Unsupported file format: {path.suffix}") except Exception as e: - raise ValueError(f"Failed to load file {path}: {str(e)}") + raise ValueError(f"Failed to load file {path}: {str(e)}") from e def _func_from_string(self, content: str) -> callable: """Convert function string to callable.""" @@ -362,24 +361,25 @@ def _func_from_string(self, content: str) -> callable: return item raise ValueError("No function found in provided code") except Exception as e: - raise ValueError(f"Failed to create function: {str(e)}") + raise ValueError(f"Failed to create function: {str(e)}") from e - def _is_version_supported(self, component_type: ComponentType, ver: str) -> bool: + def _is_version_supported(self, component_type: ComponentTypes, ver: str) -> bool: """Check if version is supported for component type.""" try: - v = version.parse(ver) - return ver in self.SUPPORTED_VERSIONS[component_type] - except version.InvalidVersion: + version = Version(ver) + supported = [Version(v) for v in self.SUPPORTED_VERSIONS[component_type]] + return any(version == v for v in supported) + except ValueError: return False async def cleanup(self) -> None: """Cleanup resources and clear caches.""" for model in self._model_cache.values(): - if hasattr(model, 'cleanup'): + if hasattr(model, "cleanup"): await model.cleanup() for tool in self._tool_cache.values(): - if hasattr(tool, 'cleanup'): + if hasattr(tool, "cleanup"): await tool.cleanup() self._model_cache.clear() diff --git a/python/packages/autogen-studio/autogenstudio/database/config_manager.py b/python/packages/autogen-studio/autogenstudio/database/config_manager.py index be4fa8ad6912..3cd1b43d81ab 100644 --- a/python/packages/autogen-studio/autogenstudio/database/config_manager.py +++ b/python/packages/autogen-studio/autogenstudio/database/config_manager.py @@ -1,13 +1,11 @@ import logging -from typing import Optional, Union, Dict, Any, List from pathlib import Path +from typing import Any, Dict, List, Optional, Union + from loguru import logger -from ..datamodel import ( - Model, Team, Agent, Tool, - Response, ComponentTypes, LinkTypes, - ComponentConfigInput -) +from ..datamodel.db import Agent, LinkTypes, Model, Team, Tool +from ..datamodel.types import ComponentConfigInput, ComponentTypes, Response from .component_factory import ComponentFactory from .db_manager import DatabaseManager @@ -16,10 +14,10 @@ class ConfigurationManager: """Manages persistence and relationships of components using ComponentFactory for validation""" DEFAULT_UNIQUENESS_FIELDS = { - ComponentTypes.MODEL: ['model_type', 'model'], - ComponentTypes.TOOL: ['name'], - ComponentTypes.AGENT: ['agent_type', 'name'], - ComponentTypes.TEAM: ['team_type', 'name'] + ComponentTypes.MODEL: ["model_type", "model"], + ComponentTypes.TOOL: ["name"], + ComponentTypes.AGENT: ["agent_type", "name"], + ComponentTypes.TEAM: ["team_type", "name"], } def __init__(self, db_manager: DatabaseManager, uniqueness_fields: Dict[ComponentTypes, List[str]] = None): @@ -27,7 +25,9 @@ def __init__(self, db_manager: DatabaseManager, uniqueness_fields: Dict[Componen self.component_factory = ComponentFactory() self.uniqueness_fields = uniqueness_fields or self.DEFAULT_UNIQUENESS_FIELDS - async def import_component(self, component_config: ComponentConfigInput, user_id: str, check_exists: bool = False) -> Response: + async def import_component( + self, component_config: ComponentConfigInput, user_id: str, check_exists: bool = False + ) -> Response: """ Import a component configuration, validate it, and store the resulting component. @@ -41,23 +41,21 @@ async def import_component(self, component_config: ComponentConfigInput, user_id """ try: # Get validated config as dict - config = await self.component_factory.load(component_config, return_type='dict') + config = await self.component_factory.load(component_config, return_type="dict") # Get component type component_type = self._determine_component_type(config) if not component_type: - raise ValueError( - f"Unable to determine component type from config") + raise ValueError("Unable to determine component type from config") # Check existence if requested if check_exists: existing = self._check_exists(component_type, config, user_id) if existing: return Response( - message=self._format_exists_message( - component_type, config), + message=self._format_exists_message(component_type, config), status=True, - data={"id": existing.id} + data={"id": existing.id}, ) # Route to appropriate storage method @@ -70,8 +68,7 @@ async def import_component(self, component_config: ComponentConfigInput, user_id elif component_type == ComponentTypes.TOOL: return await self._store_tool(config, user_id) else: - raise ValueError( - f"Unsupported component type: {component_type}") + raise ValueError(f"Unsupported component type: {component_type}") except Exception as e: logger.error(f"Failed to import component: {str(e)}") @@ -90,23 +87,21 @@ async def import_directory(self, directory: Union[str, Path], user_id: str, chec Response containing import results for all files """ try: - configs = await self.component_factory.load_directory(directory, return_type='dict') + configs = await self.component_factory.load_directory(directory, return_type="dict") results = [] for config in configs: result = await self.import_component(config, user_id, check_exists) - results.append({ - "component": self._get_component_type(config), - "status": result.status, - "message": result.message, - "id": result.data.get("id") if result.status else None - }) - - return Response( - message="Directory import complete", - status=True, - data=results - ) + results.append( + { + "component": self._get_component_type(config), + "status": result.status, + "message": result.message, + "id": result.data.get("id") if result.status else None, + } + ) + + return Response(message="Directory import complete", status=True, data=results) except Exception as e: logger.error(f"Failed to import directory: {str(e)}") @@ -116,10 +111,7 @@ async def _store_team(self, config: dict, user_id: str, check_exists: bool = Fal """Store team component and manage its relationships with agents""" try: # Store the team - team_db = Team( - user_id=user_id, - config=config - ) + team_db = Team(user_id=user_id, config=config) team_result = self.db_manager.upsert(team_db) if not team_result.status: return team_result @@ -131,27 +123,17 @@ async def _store_team(self, config: dict, user_id: str, check_exists: bool = Fal if check_exists: # Check for existing agent agent_type = self._determine_component_type(participant) - existing_agent = self._check_exists( - agent_type, participant, user_id) + existing_agent = self._check_exists(agent_type, participant, user_id) if existing_agent: # Link existing agent - self.db_manager.link( - LinkTypes.TEAM_AGENT, - team_id, - existing_agent.id - ) - logger.info( - f"Linked existing agent to team: {existing_agent}") + self.db_manager.link(LinkTypes.TEAM_AGENT, team_id, existing_agent.id) + logger.info(f"Linked existing agent to team: {existing_agent}") continue # Store and link new agent agent_result = await self._store_agent(participant, user_id, check_exists) if agent_result.status: - self.db_manager.link( - LinkTypes.TEAM_AGENT, - team_id, - agent_result.data["id"] - ) + self.db_manager.link(LinkTypes.TEAM_AGENT, team_id, agent_result.data["id"]) return team_result @@ -163,10 +145,7 @@ async def _store_agent(self, config: dict, user_id: str, check_exists: bool = Fa """Store agent component and manage its relationships with tools and model""" try: # Store the agent - agent_db = Agent( - user_id=user_id, - config=config - ) + agent_db = Agent(user_id=user_id, config=config) agent_result = self.db_manager.upsert(agent_db) if not agent_result.status: return agent_result @@ -177,64 +156,39 @@ async def _store_agent(self, config: dict, user_id: str, check_exists: bool = Fa if "model_client" in config: if check_exists: # Check for existing model - model_type = self._determine_component_type( - config["model_client"]) - existing_model = self._check_exists( - model_type, config["model_client"], user_id) + model_type = self._determine_component_type(config["model_client"]) + existing_model = self._check_exists(model_type, config["model_client"], user_id) if existing_model: # Link existing model - self.db_manager.link( - LinkTypes.AGENT_MODEL, - agent_id, - existing_model.id - ) - logger.info( - f"Linked existing model to agent: {existing_model.config.model_type}") + self.db_manager.link(LinkTypes.AGENT_MODEL, agent_id, existing_model.id) + logger.info(f"Linked existing model to agent: {existing_model.config.model_type}") else: # Store and link new model model_result = await self._store_model(config["model_client"], user_id) if model_result.status: - self.db_manager.link( - LinkTypes.AGENT_MODEL, - agent_id, - model_result.data["id"] - ) + self.db_manager.link(LinkTypes.AGENT_MODEL, agent_id, model_result.data["id"]) else: # Store and link new model without checking model_result = await self._store_model(config["model_client"], user_id) if model_result.status: - self.db_manager.link( - LinkTypes.AGENT_MODEL, - agent_id, - model_result.data["id"] - ) + self.db_manager.link(LinkTypes.AGENT_MODEL, agent_id, model_result.data["id"]) # Handle tools for tool_config in config.get("tools", []): if check_exists: # Check for existing tool tool_type = self._determine_component_type(tool_config) - existing_tool = self._check_exists( - tool_type, tool_config, user_id) + existing_tool = self._check_exists(tool_type, tool_config, user_id) if existing_tool: # Link existing tool - self.db_manager.link( - LinkTypes.AGENT_TOOL, - agent_id, - existing_tool.id - ) - logger.info( - f"Linked existing tool to agent: {existing_tool.config.name}") + self.db_manager.link(LinkTypes.AGENT_TOOL, agent_id, existing_tool.id) + logger.info(f"Linked existing tool to agent: {existing_tool.config.name}") continue # Store and link new tool tool_result = await self._store_tool(tool_config, user_id) if tool_result.status: - self.db_manager.link( - LinkTypes.AGENT_TOOL, - agent_id, - tool_result.data["id"] - ) + self.db_manager.link(LinkTypes.AGENT_TOOL, agent_id, tool_result.data["id"]) return agent_result @@ -245,10 +199,7 @@ async def _store_agent(self, config: dict, user_id: str, check_exists: bool = Fa async def _store_model(self, config: dict, user_id: str) -> Response: """Store model component (leaf node - no relationships)""" try: - model_db = Model( - user_id=user_id, - config=config - ) + model_db = Model(user_id=user_id, config=config) return self.db_manager.upsert(model_db) except Exception as e: @@ -258,17 +209,16 @@ async def _store_model(self, config: dict, user_id: str) -> Response: async def _store_tool(self, config: dict, user_id: str) -> Response: """Store tool component (leaf node - no relationships)""" try: - tool_db = Tool( - user_id=user_id, - config=config - ) + tool_db = Tool(user_id=user_id, config=config) return self.db_manager.upsert(tool_db) except Exception as e: logger.error(f"Failed to store tool: {str(e)}") return Response(message=str(e), status=False) - def _check_exists(self, component_type: ComponentTypes, config: dict, user_id: str) -> Optional[Union[Model, Tool, Agent, Team]]: + def _check_exists( + self, component_type: ComponentTypes, config: dict, user_id: str + ) -> Optional[Union[Model, Tool, Agent, Team]]: """Check if component exists based on configured uniqueness fields.""" fields = self.uniqueness_fields.get(component_type, []) if not fields: @@ -278,17 +228,13 @@ def _check_exists(self, component_type: ComponentTypes, config: dict, user_id: s ComponentTypes.MODEL: Model, ComponentTypes.TOOL: Tool, ComponentTypes.AGENT: Agent, - ComponentTypes.TEAM: Team + ComponentTypes.TEAM: Team, }.get(component_type) - components = self.db_manager.get( - component_class, {"user_id": user_id}).data + components = self.db_manager.get(component_class, {"user_id": user_id}).data for component in components: - matches = all( - component.config.get(field) == config.get(field) - for field in fields - ) + matches = all(component.config.get(field) == config.get(field) for field in fields) if matches: return component diff --git a/python/packages/autogen-studio/autogenstudio/database/db_manager.py b/python/packages/autogen-studio/autogenstudio/database/db_manager.py index d5f17492ed3c..2b9ec43e3bd5 100644 --- a/python/packages/autogen-studio/autogenstudio/database/db_manager.py +++ b/python/packages/autogen-studio/autogenstudio/database/db_manager.py @@ -1,59 +1,77 @@ -from pathlib import Path import threading from datetime import datetime +from pathlib import Path from typing import Optional from loguru import logger -from sqlalchemy import exc, text, func +from sqlalchemy import exc, func, inspect, text from sqlmodel import Session, SQLModel, and_, create_engine, select + +from ..datamodel import LinkTypes, Response from .schema_manager import SchemaManager -from ..datamodel import ( - Response, - LinkTypes -) # from .dbutils import init_db_samples class DatabaseManager: - """A class to manage database operations""" - _init_lock = threading.Lock() - def __init__( - self, - engine_uri: str, - base_dir: Optional[Path | str] = None, - auto_upgrade: bool = True - ): + def __init__(self, engine_uri: str, base_dir: Optional[Path] = None): """ - Initialize DatabaseManager with optional custom base directory. + Initialize DatabaseManager with database connection settings. + Does not perform any database operations. 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 + engine_uri: Database connection URI (e.g. sqlite:///db.sqlite3) + base_dir: Base directory for migration files. If None, uses current directory """ - # Convert string path to Path object if necessary - if isinstance(base_dir, str): - base_dir = Path(base_dir) - - connection_args = { - "check_same_thread": True - } if "sqlite" in engine_uri else {} + connection_args = {"check_same_thread": True} if "sqlite" in engine_uri else {} self.engine = create_engine(engine_uri, connect_args=connection_args) self.schema_manager = SchemaManager( engine=self.engine, base_dir=base_dir, - auto_upgrade=auto_upgrade, ) - # Check and upgrade on startup - upgraded, status = self.schema_manager.check_and_upgrade() - if upgraded: - logger.info("Database schema was upgraded automatically") - else: - logger.info(f"Schema status: {status}") + + def initialize_database(self, auto_upgrade: bool = False, force_init_alembic: bool = True) -> Response: + """ + Initialize database and migrations in the correct order. + + Args: + auto_upgrade: If True, automatically generate and apply migrations for schema changes + force_init_alembic: If True, reinitialize alembic configuration even if it exists + """ + if not self._init_lock.acquire(blocking=False): + return Response(message="Database initialization already in progress", status=False) + + try: + inspector = inspect(self.engine) + tables_exist = inspector.get_table_names() + + if not tables_exist: + # Fresh install - create tables and initialize migrations + logger.info("Creating database tables...") + SQLModel.metadata.create_all(self.engine) + + if self.schema_manager.initialize_migrations(force=force_init_alembic): + return Response(message="Database initialized successfully", status=True) + return Response(message="Failed to initialize migrations", status=False) + + # Handle existing database + if auto_upgrade: + logger.info("Checking database schema...") + if self.schema_manager.ensure_schema_up_to_date(): # <-- Use this instead + return Response(message="Database schema is up to date", status=True) + return Response(message="Database upgrade failed", status=False) + + return Response(message="Database is ready", status=True) + + except Exception as e: + error_msg = f"Database initialization failed: {str(e)}" + logger.error(error_msg) + return Response(message=error_msg, status=False) + finally: + self._init_lock.release() def reset_db(self, recreate_tables: bool = True): """ @@ -65,11 +83,7 @@ def reset_db(self, recreate_tables: bool = True): """ if not self._init_lock.acquire(blocking=False): logger.warning("Database reset already in progress") - return Response( - message="Database reset already in progress", - status=False, - data=None - ) + return Response(message="Database reset already in progress", status=False, data=None) try: # Dispose existing connections @@ -77,16 +91,16 @@ def reset_db(self, recreate_tables: bool = True): with Session(self.engine) as session: try: # Disable foreign key checks for SQLite - if 'sqlite' in str(self.engine.url): - session.exec(text('PRAGMA foreign_keys=OFF')) + if "sqlite" in str(self.engine.url): + session.exec(text("PRAGMA foreign_keys=OFF")) # Drop all tables SQLModel.metadata.drop_all(self.engine) logger.info("All tables dropped successfully") # Re-enable foreign key checks for SQLite - if 'sqlite' in str(self.engine.url): - session.exec(text('PRAGMA foreign_keys=ON')) + if "sqlite" in str(self.engine.url): + session.exec(text("PRAGMA foreign_keys=ON")) session.commit() @@ -99,48 +113,29 @@ def reset_db(self, recreate_tables: bool = True): if recreate_tables: logger.info("Recreating tables...") - self.create_db_and_tables() + self.initialize_database(auto_upgrade=False, force_init_alembic=True) return Response( message="Database reset successfully" if recreate_tables else "Database tables dropped successfully", status=True, - data=None + data=None, ) except Exception as e: error_msg = f"Error while resetting database: {str(e)}" logger.error(error_msg) - return Response( - message=error_msg, - status=False, - data=None - ) + return Response(message=error_msg, status=False, data=None) finally: if self._init_lock.locked(): self._init_lock.release() logger.info("Database reset lock released") - def create_db_and_tables(self): - """Create a new database and tables""" - with self._init_lock: - try: - SQLModel.metadata.create_all(self.engine) - logger.info("Database tables created successfully") - try: - # init_db_samples(self) - pass - except Exception as e: - logger.info( - "Error while initializing database samples: " + str(e)) - except Exception as e: - logger.info("Error while creating database tables:" + str(e)) - def upsert(self, model: SQLModel, return_json: bool = True): """Create or update an entity Args: model (SQLModel): The model instance to create or update - return_json (bool, optional): If True, returns the model as a dictionary. + return_json (bool, optional): If True, returns the model as a dictionary. If False, returns the SQLModel instance. Defaults to True. Returns: @@ -152,8 +147,7 @@ def upsert(self, model: SQLModel, return_json: bool = True): with Session(self.engine) as session: try: - existing_model = session.exec( - select(model_class).where(model_class.id == model.id)).first() + existing_model = session.exec(select(model_class).where(model_class.id == model.id)).first() if existing_model: model.updated_at = datetime.now() for key, value in model.model_dump().items(): @@ -166,8 +160,7 @@ def upsert(self, model: SQLModel, return_json: bool = True): session.refresh(model) except Exception as e: session.rollback() - logger.error("Error while updating/creating " + - str(model_class.__name__) + ": " + str(e)) + logger.error("Error while updating/creating " + str(model_class.__name__) + ": " + str(e)) status = False return Response( @@ -199,25 +192,21 @@ def get( try: statement = select(model_class) if filters: - conditions = [getattr(model_class, col) == - value for col, value in filters.items()] + conditions = [getattr(model_class, col) == value for col, value in filters.items()] statement = statement.where(and_(*conditions)) if hasattr(model_class, "created_at") and order: - order_by_clause = getattr( - model_class.created_at, order)() # Dynamically apply asc/desc + order_by_clause = getattr(model_class.created_at, order)() # Dynamically apply asc/desc statement = statement.order_by(order_by_clause) items = session.exec(statement).all() - result = [self._model_to_dict( - item) if return_json else item for item in items] + result = [self._model_to_dict(item) if return_json else item for item in items] status_message = f"{model_class.__name__} Retrieved Successfully" except Exception as e: session.rollback() status = False status_message = f"Error while fetching {model_class.__name__}" - logger.error("Error while getting items: " + - str(model_class.__name__) + " " + str(e)) + logger.error("Error while getting items: " + str(model_class.__name__) + " " + str(e)) return Response(message=status_message, status=status, data=result) @@ -230,8 +219,7 @@ def delete(self, model_class: SQLModel, filters: dict = None): try: statement = select(model_class) if filters: - conditions = [ - getattr(model_class, col) == value for col, value in filters.items()] + conditions = [getattr(model_class, col) == value for col, value in filters.items()] statement = statement.where(and_(*conditions)) rows = session.exec(statement).all() @@ -290,8 +278,7 @@ def link( select(link_table).where( and_( getattr(link_table, primary_id_field) == primary_id, - getattr( - link_table, secondary_id_field) == secondary_id + getattr(link_table, secondary_id_field) == secondary_id, ) ) ).first() @@ -302,37 +289,24 @@ def link( # Get the next sequence number if not provided if sequence is None: max_seq_result = session.exec( - select(func.max(link_table.sequence)).where( - getattr(link_table, primary_id_field) == primary_id - ) + select(func.max(link_table.sequence)).where(getattr(link_table, primary_id_field) == primary_id) ).first() sequence = 0 if max_seq_result is None else max_seq_result + 1 # Create new link - new_link = link_table(**{ - primary_id_field: primary_id, - secondary_id_field: secondary_id, - 'sequence': sequence - }) + new_link = link_table( + **{primary_id_field: primary_id, secondary_id_field: secondary_id, "sequence": sequence} + ) session.add(new_link) session.commit() - return Response( - message=f"Entities linked successfully with sequence {sequence}", - status=True - ) + return Response(message=f"Entities linked successfully with sequence {sequence}", status=True) except Exception as e: session.rollback() return Response(message=f"Error linking entities: {str(e)}", status=False) - def unlink( - self, - link_type: LinkTypes, - primary_id: int, - secondary_id: int, - sequence: Optional[int] = None - ): + def unlink(self, link_type: LinkTypes, primary_id: int, secondary_id: int, sequence: Optional[int] = None): """Unlink two entities and reorder sequences if needed.""" with Session(self.engine) as session: try: @@ -349,13 +323,12 @@ def unlink( statement = select(link_table).where( and_( getattr(link_table, primary_id_field) == primary_id, - getattr(link_table, secondary_id_field) == secondary_id + getattr(link_table, secondary_id_field) == secondary_id, ) ) if sequence is not None: - statement = statement.where( - link_table.sequence == sequence) + statement = statement.where(link_table.sequence == sequence) existing_link = session.exec(statement).first() @@ -379,10 +352,7 @@ def unlink( session.commit() - return Response( - message="Entities unlinked successfully and sequences reordered", - status=True - ) + return Response(message="Entities unlinked successfully and sequences reordered", status=True) except Exception as e: session.rollback() @@ -414,22 +384,14 @@ def get_linked_entities( .order_by(link_table.sequence) ).all() - result = [ - item.model_dump() if return_json else item for item in items] + result = [item.model_dump() if return_json else item for item in items] - return Response( - message="Linked entities retrieved successfully", - status=True, - data=result - ) + return Response(message="Linked entities retrieved successfully", status=True, data=result) except Exception as e: logger.error(f"Error getting linked entities: {str(e)}") - return Response( - message=f"Error getting linked entities: {str(e)}", - status=False, - data=[] - ) + return Response(message=f"Error getting linked entities: {str(e)}", status=False, data=[]) + # Add new close method async def close(self): diff --git a/python/packages/autogen-studio/autogenstudio/database/schema_manager.py b/python/packages/autogen-studio/autogenstudio/database/schema_manager.py index d4d7de42c8e7..42d1f5f5dec9 100644 --- a/python/packages/autogen-studio/autogenstudio/database/schema_manager.py +++ b/python/packages/autogen-studio/autogenstudio/database/schema_manager.py @@ -1,68 +1,71 @@ import os -from pathlib import Path import shutil -from typing import Optional, Tuple, List -from loguru import logger +from pathlib import Path +from typing import List, Optional, Tuple + +import sqlmodel from alembic import command +from alembic.autogenerate import compare_metadata from alembic.config import Config from alembic.runtime.migration import MigrationContext from alembic.script import ScriptDirectory -from alembic.autogenerate import compare_metadata -from sqlalchemy import Engine -from sqlmodel import SQLModel from alembic.util.exc import CommandError +from loguru import logger +from sqlalchemy import Engine, text +from sqlmodel import SQLModel class SchemaManager: """ Manages database schema validation and migrations using Alembic. - Provides automatic schema validation, migrations, and safe upgrades. - - Args: - engine: SQLAlchemy engine instance - auto_upgrade: Whether to automatically upgrade schema when differences found - init_mode: Controls initialization behavior: - - "none": No automatic initialization (raises error if not set up) - - "auto": Initialize if not present (default) - - "force": Always reinitialize, removing existing configuration + Operations are initiated explicitly by DatabaseManager. """ def __init__( self, engine: Engine, base_dir: Optional[Path] = None, - auto_upgrade: bool = True, - init_mode: str = "auto" ): - if init_mode not in ["none", "auto", "force"]: - raise ValueError("init_mode must be one of: none, auto, force") + """ + Initialize configuration only - no filesystem or DB operations. - self.engine = engine - self.auto_upgrade = auto_upgrade + Args: + engine: SQLAlchemy engine instance + base_dir: Base directory for Alembic files. If None, uses current working directory + """ + # Convert string path to Path object if necessary + if isinstance(base_dir, str): + base_dir = Path(base_dir) - # Use provided base_dir or default to class file location + self.engine = engine self.base_dir = base_dir or Path(__file__).parent - self.alembic_dir = self.base_dir / 'alembic' - self.alembic_ini_path = self.base_dir / 'alembic.ini' + self.alembic_dir = self.base_dir / "alembic" + self.alembic_ini_path = self.base_dir / "alembic.ini" - # Create base directory if it doesn't exist - self.base_dir.mkdir(parents=True, exist_ok=True) + def initialize_migrations(self, force: bool = False) -> bool: + try: + if force: + logger.info("Force reinitialization of migrations...") + self._cleanup_existing_alembic() + if not self._initialize_alembic(): + return False + else: + try: + self._validate_alembic_setup() + logger.info("Using existing Alembic configuration") + self._update_configuration() + except FileNotFoundError: + logger.info("Initializing new Alembic configuration") + if not self._initialize_alembic(): + return False + + # Only generate initial revision if alembic is properly initialized + logger.info("Creating initial migration...") + return self.generate_revision("Initial schema") is not None - # Initialize based on mode - if init_mode == "force": - self._cleanup_existing_alembic() - self._initialize_alembic() - else: - 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() + except Exception as e: + logger.error(f"Failed to initialize migrations: {e}") + return False def _update_configuration(self) -> None: """Updates existing Alembic configuration with current settings.""" @@ -70,11 +73,11 @@ def _update_configuration(self) -> None: # Update alembic.ini config_content = self._generate_alembic_ini_content() - with open(self.alembic_ini_path, 'w') as f: + with open(self.alembic_ini_path, "w") as f: f.write(config_content) # Update env.py - env_path = self.alembic_dir / 'env.py' + env_path = self.alembic_dir / "env.py" if env_path.exists(): self._update_env_py(env_path) else: @@ -82,37 +85,22 @@ def _update_configuration(self) -> None: def _cleanup_existing_alembic(self) -> None: """ - Safely removes existing Alembic configuration while preserving versions directory. + Completely remove existing Alembic configuration including versions. + For fresh initialization, we don't need to preserve anything. """ - logger.info( - "Cleaning up existing Alembic configuration while preserving versions...") - - # Create a backup of versions directory if it exists - if self.alembic_dir.exists() and (self.alembic_dir / 'versions').exists(): - logger.info("Preserving existing versions directory") + logger.info("Cleaning up existing Alembic configuration...") - # Remove alembic directory contents EXCEPT versions + # Remove entire alembic directory if it exists if self.alembic_dir.exists(): - for item in self.alembic_dir.iterdir(): - if item.name != 'versions': - try: - if item.is_dir(): - shutil.rmtree(item) - logger.info(f"Removed directory: {item}") - else: - item.unlink() - logger.info(f"Removed file: {item}") - except Exception as e: - logger.error(f"Failed to remove {item}: {e}") + import shutil + + shutil.rmtree(self.alembic_dir) + logger.info(f"Removed alembic directory: {self.alembic_dir}") # Remove alembic.ini if it exists if self.alembic_ini_path.exists(): - try: - self.alembic_ini_path.unlink() - logger.info( - f"Removed existing alembic.ini: {self.alembic_ini_path}") - except Exception as e: - logger.error(f"Failed to remove alembic.ini: {e}") + self.alembic_ini_path.unlink() + logger.info("Removed alembic.ini") def _ensure_alembic_setup(self, *, force: bool = False) -> None: """ @@ -124,51 +112,52 @@ def _ensure_alembic_setup(self, *, force: bool = False) -> None: try: self._validate_alembic_setup() if force: - logger.info( - "Force initialization requested. Cleaning up existing configuration...") + logger.info("Force initialization requested. Cleaning up existing configuration...") self._cleanup_existing_alembic() self._initialize_alembic() except FileNotFoundError: logger.info("Alembic configuration not found. Initializing...") if self.alembic_dir.exists(): - logger.warning( - "Found existing alembic directory but missing configuration") + logger.warning("Found existing alembic directory but missing configuration") self._cleanup_existing_alembic() self._initialize_alembic() logger.info("Alembic initialization complete") - def _initialize_alembic(self) -> None: - logger.info("Initializing Alembic configuration...") - - # Create directories first - self.alembic_dir.mkdir(exist_ok=True) - versions_dir = self.alembic_dir / 'versions' - versions_dir.mkdir(exist_ok=True) + def _initialize_alembic(self) -> bool: + """Initialize alembic structure and configuration""" + try: + # Ensure parent directory exists + self.alembic_dir.parent.mkdir(exist_ok=True) - # Create env.py BEFORE running command.init - env_path = self.alembic_dir / 'env.py' - if not env_path.exists(): - self._create_minimal_env_py(env_path) - logger.info("Created new env.py") + # Run alembic init to create fresh directory structure + logger.info("Initializing alembic directory structure...") - # Write alembic.ini - 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") + # Create initial config file for alembic init + config_content = self._generate_alembic_ini_content() + with open(self.alembic_ini_path, "w") as f: + f.write(config_content) - # Now run alembic init - try: - config = self.get_alembic_config() + # Use the config we just created + config = Config(str(self.alembic_ini_path)) 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 + + # Update script template after initialization + self.update_script_template() + + # Update env.py with our customizations + self._update_env_py(self.alembic_dir / "env.py") + + logger.info("Alembic initialization complete") + return True + + except Exception as e: + # Explicitly convert error to string + logger.error(f"Failed to initialize alembic: {str(e)}") + return False def _create_minimal_env_py(self, env_path: Path) -> None: """Creates a minimal env.py file for Alembic.""" - content = ''' + content = """ from logging.config import fileConfig from sqlalchemy import engine_from_config from sqlalchemy import pool @@ -201,7 +190,7 @@ def run_migrations_online() -> None: ) with connectable.connect() as connection: context.configure( - connection=connection, + connection=connection, target_metadata=target_metadata, compare_type=True ) @@ -211,9 +200,9 @@ def run_migrations_online() -> None: if context.is_offline_mode(): run_migrations_offline() else: - run_migrations_online()''' + run_migrations_online()""" - with open(env_path, 'w') as f: + with open(env_path, "w") as f: f.write(content) def _generate_alembic_ini_content(self) -> str: @@ -260,6 +249,29 @@ class = StreamHandler datefmt = %H:%M:%S """.strip() + def update_script_template(self): + """Update the Alembic script template to include SQLModel.""" + template_path = self.alembic_dir / "script.py.mako" + try: + with open(template_path, "r") as f: + content = f.read() + + # Add sqlmodel import to imports section + import_section = "from alembic import op\nimport sqlalchemy as sa" + new_imports = "from alembic import op\nimport sqlalchemy as sa\nimport sqlmodel" + + content = content.replace(import_section, new_imports) + + with open(template_path, "w") as f: + f.write(content) + + logger.info("Updated script template") + return True + + except Exception as e: + logger.error(f"Failed to update script template: {e}") + return False + def _update_env_py(self, env_path: Path) -> None: """ Updates the env.py file to use SQLModel metadata. @@ -268,27 +280,45 @@ def _update_env_py(self, env_path: Path) -> None: self._create_minimal_env_py(env_path) return try: - with open(env_path, 'r') as f: + with open(env_path, "r") as f: content = f.read() - # Add SQLModel import + # Add SQLModel import if not present if "from sqlmodel import SQLModel" not in content: content = "from sqlmodel import SQLModel\n" + content # Replace target_metadata + content = content.replace("target_metadata = None", "target_metadata = SQLModel.metadata") + + # Update both configure blocks properly content = content.replace( - "target_metadata = None", - "target_metadata = SQLModel.metadata" + """context.configure( + url=url, + target_metadata=target_metadata, + literal_binds=True, + dialect_opts={"paramstyle": "named"}, + )""", + """context.configure( + url=url, + target_metadata=target_metadata, + literal_binds=True, + dialect_opts={"paramstyle": "named"}, + compare_type=True, + )""", ) - # Add compare_type=True to context.configure - if "context.configure(" in content and "compare_type=True" not in content: - content = content.replace( - "context.configure(", - "context.configure(compare_type=True," - ) + content = content.replace( + """ context.configure( + connection=connection, target_metadata=target_metadata + )""", + """ context.configure( + connection=connection, + target_metadata=target_metadata, + compare_type=True, + )""", + ) - with open(env_path, 'w') as f: + with open(env_path, "w") as f: f.write(content) logger.info("Updated env.py with SQLModel metadata") @@ -297,6 +327,7 @@ def _update_env_py(self, env_path: Path) -> None: raise # Fixed: use keyword-only argument + def _ensure_alembic_setup(self, *, force: bool = False) -> None: """ Ensures Alembic is properly set up, initializing if necessary. @@ -307,32 +338,24 @@ def _ensure_alembic_setup(self, *, force: bool = False) -> None: try: self._validate_alembic_setup() if force: - logger.info( - "Force initialization requested. Cleaning up existing configuration...") + logger.info("Force initialization requested. Cleaning up existing configuration...") self._cleanup_existing_alembic() self._initialize_alembic() except FileNotFoundError: logger.info("Alembic configuration not found. Initializing...") if self.alembic_dir.exists(): - logger.warning( - "Found existing alembic directory but missing configuration") + logger.warning("Found existing alembic directory but missing configuration") self._cleanup_existing_alembic() self._initialize_alembic() logger.info("Alembic initialization complete") def _validate_alembic_setup(self) -> None: """Validates that Alembic is properly configured.""" - required_files = [ - self.alembic_ini_path, - self.alembic_dir / 'env.py', - self.alembic_dir / 'versions' - ] + required_files = [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)}" - ) + raise FileNotFoundError(f"Alembic configuration incomplete. Missing: {', '.join(str(f) for f in missing)}") def get_alembic_config(self) -> Config: """ @@ -430,7 +453,7 @@ def upgrade_schema(self, revision: str = "head") -> bool: def check_and_upgrade(self) -> Tuple[bool, str]: """ - Checks schema status and upgrades if necessary (and auto_upgrade is True). + Checks schema status and upgrades if necessary. Returns: Tuple[bool, str]: (action_taken, status_message) @@ -438,13 +461,11 @@ def check_and_upgrade(self) -> Tuple[bool, str]: needs_upgrade, status = self.check_schema_status() if needs_upgrade: - if self.auto_upgrade: - if self.upgrade_schema(): - return True, "Schema was automatically upgraded" - else: - return False, "Automatic schema upgrade failed" + # Remove the auto_upgrade check since we explicitly called this method + if self.upgrade_schema(): + return True, "Schema was automatically upgraded" else: - return False, f"Schema needs upgrade but auto_upgrade is disabled. Status: {status}" + return False, "Automatic schema upgrade failed" return False, status @@ -460,11 +481,7 @@ def generate_revision(self, message: str = "auto") -> Optional[str]: """ try: config = self.get_alembic_config() - command.revision( - config, - message=message, - autogenerate=True - ) + command.revision(config, message=message, autogenerate=True) return self.get_head_revision() except Exception as e: @@ -512,25 +529,39 @@ def print_status(self) -> None: def ensure_schema_up_to_date(self) -> bool: """ - Ensures the database schema is up to date, generating and applying migrations if needed. - - Returns: - bool: True if schema is up to date or was successfully updated + Reset migrations and create fresh migration for current schema state. """ try: - # Check for unmigrated changes - differences = self.get_schema_differences() - if differences: - # Generate new migration - revision = self.generate_revision("auto-generated") - if not revision: - return False - logger.info(f"Generated new migration: {revision}") + logger.info("Resetting migrations and updating to current schema...") + + # 1. Clear the entire alembic directory + if self.alembic_dir.exists(): + shutil.rmtree(self.alembic_dir) + logger.info("Cleared alembic directory") + + # 2. Clear alembic_version table + with self.engine.connect() as connection: + connection.execute(text("DROP TABLE IF EXISTS alembic_version")) + connection.commit() + logger.info("Reset alembic version") + + # 3. Reinitialize alembic from scratch + if not self._initialize_alembic(): + logger.error("Failed to reinitialize alembic") + return False + + # 4. Generate fresh migration from current schema + revision = self.generate_revision("current_schema") + if not revision: + logger.error("Failed to generate new migration") + return False + logger.info(f"Generated fresh migration: {revision}") - # Apply any pending migrations - upgraded, status = self.check_and_upgrade() - if not upgraded and "needs upgrade" in status.lower(): + # 5. Apply the migration + if not self.upgrade_schema(): + logger.error("Failed to apply migration") return False + logger.info("Successfully applied migration") return True diff --git a/python/packages/autogen-studio/autogenstudio/datamodel/__init__.py b/python/packages/autogen-studio/autogenstudio/datamodel/__init__.py index 6b7b4098df4b..0d46fb26334e 100644 --- a/python/packages/autogen-studio/autogenstudio/datamodel/__init__.py +++ b/python/packages/autogen-studio/autogenstudio/datamodel/__init__.py @@ -1,2 +1,11 @@ -from .db import * -from .types import * +from .db import Agent, LinkTypes, Message, Model, Run, RunStatus, Session, Team, Tool +from .types import ( + AgentConfig, + ComponentConfigInput, + MessageConfig, + ModelConfig, + Response, + TeamConfig, + TeamResult, + ToolConfig, +) diff --git a/python/packages/autogen-studio/autogenstudio/datamodel/db.py b/python/packages/autogen-studio/autogenstudio/datamodel/db.py index 2f8210029a9a..6395a535fd6b 100644 --- a/python/packages/autogen-studio/autogenstudio/datamodel/db.py +++ b/python/packages/autogen-studio/autogenstudio/datamodel/db.py @@ -2,24 +2,28 @@ from datetime import datetime from enum import Enum -from typing import List, Optional, Union, Tuple, Type -from sqlalchemy import ForeignKey, Integer, UniqueConstraint -from sqlmodel import JSON, Column, DateTime, Field, SQLModel, func, Relationship, SQLModel +from typing import List, Optional, Tuple, Type, Union from uuid import UUID, uuid4 -from .types import ToolConfig, ModelConfig, AgentConfig, TeamConfig, MessageConfig, MessageMeta +from loguru import logger +from pydantic import BaseModel +from sqlalchemy import ForeignKey, Integer, UniqueConstraint +from sqlmodel import JSON, Column, DateTime, Field, Relationship, SQLModel, func + +from .types import AgentConfig, MessageConfig, MessageMeta, ModelConfig, TeamConfig, TeamResult, ToolConfig # added for python3.11 and sqlmodel 0.0.22 incompatibility if hasattr(SQLModel, "model_config"): SQLModel.model_config["protected_namespaces"] = () elif hasattr(SQLModel, "Config"): + class CustomSQLModel(SQLModel): class Config: protected_namespaces = () SQLModel = CustomSQLModel else: - print("Warning: Unable to set protected_namespaces.") + logger.warning("Unable to set protected_namespaces.") # pylint: disable=protected-access @@ -36,7 +40,7 @@ def model_class(self) -> Type[SQLModel]: ComponentTypes.TEAM: Team, ComponentTypes.AGENT: Agent, ComponentTypes.MODEL: Model, - ComponentTypes.TOOL: Tool + ComponentTypes.TOOL: Tool, }[self] @@ -51,7 +55,7 @@ def link_config(self) -> Tuple[Type[SQLModel], Type[SQLModel], Type[SQLModel]]: return { LinkTypes.AGENT_MODEL: (Agent, Model, AgentModelLink), LinkTypes.AGENT_TOOL: (Agent, Tool, AgentToolLink), - LinkTypes.TEAM_AGENT: (Team, Agent, TeamAgentLink) + LinkTypes.TEAM_AGENT: (Team, Agent, TeamAgentLink), }[self] @property @@ -70,40 +74,34 @@ def link_table(self) -> Type[SQLModel]: # type: ignore # link models class AgentToolLink(SQLModel, table=True): __table_args__ = ( - UniqueConstraint('agent_id', 'sequence', - name='unique_agent_tool_sequence'), - {'sqlite_autoincrement': True} + UniqueConstraint("agent_id", "sequence", name="unique_agent_tool_sequence"), + {"sqlite_autoincrement": True}, ) - agent_id: int = Field(default=None, primary_key=True, - foreign_key="agent.id") + agent_id: int = Field(default=None, primary_key=True, foreign_key="agent.id") tool_id: int = Field(default=None, primary_key=True, foreign_key="tool.id") sequence: Optional[int] = Field(default=0, primary_key=True) class AgentModelLink(SQLModel, table=True): __table_args__ = ( - UniqueConstraint('agent_id', 'sequence', - name='unique_agent_tool_sequence'), - {'sqlite_autoincrement': True} + UniqueConstraint("agent_id", "sequence", name="unique_agent_tool_sequence"), + {"sqlite_autoincrement": True}, ) - agent_id: int = Field(default=None, primary_key=True, - foreign_key="agent.id") - model_id: int = Field(default=None, primary_key=True, - foreign_key="model.id") + agent_id: int = Field(default=None, primary_key=True, foreign_key="agent.id") + model_id: int = Field(default=None, primary_key=True, foreign_key="model.id") sequence: Optional[int] = Field(default=0, primary_key=True) class TeamAgentLink(SQLModel, table=True): __table_args__ = ( - UniqueConstraint('agent_id', 'sequence', - name='unique_agent_tool_sequence'), - {'sqlite_autoincrement': True} + UniqueConstraint("agent_id", "sequence", name="unique_agent_tool_sequence"), + {"sqlite_autoincrement": True}, ) team_id: int = Field(default=None, primary_key=True, foreign_key="team.id") - agent_id: int = Field(default=None, primary_key=True, - foreign_key="agent.id") + agent_id: int = Field(default=None, primary_key=True, foreign_key="agent.id") sequence: Optional[int] = Field(default=0, primary_key=True) + # database models @@ -120,10 +118,8 @@ class Tool(SQLModel, table=True): ) # pylint: disable=not-callable user_id: Optional[str] = None version: Optional[str] = "0.0.1" - config: Union[ToolConfig, dict] = Field( - default_factory=ToolConfig, sa_column=Column(JSON)) - agents: List["Agent"] = Relationship( - back_populates="tools", link_model=AgentToolLink) + config: Union[ToolConfig, dict] = Field(default_factory=ToolConfig, sa_column=Column(JSON)) + agents: List["Agent"] = Relationship(back_populates="tools", link_model=AgentToolLink) class Model(SQLModel, table=True): @@ -139,10 +135,8 @@ class Model(SQLModel, table=True): ) # pylint: disable=not-callable user_id: Optional[str] = None version: Optional[str] = "0.0.1" - config: Union[ModelConfig, dict] = Field( - default_factory=ModelConfig, sa_column=Column(JSON)) - agents: List["Agent"] = Relationship( - back_populates="models", link_model=AgentModelLink) + config: Union[ModelConfig, dict] = Field(default_factory=ModelConfig, sa_column=Column(JSON)) + agents: List["Agent"] = Relationship(back_populates="models", link_model=AgentModelLink) class Team(SQLModel, table=True): @@ -158,10 +152,8 @@ class Team(SQLModel, table=True): ) # pylint: disable=not-callable user_id: Optional[str] = None version: Optional[str] = "0.0.1" - config: Union[TeamConfig, dict] = Field( - default_factory=TeamConfig, sa_column=Column(JSON)) - agents: List["Agent"] = Relationship( - back_populates="teams", link_model=TeamAgentLink) + config: Union[TeamConfig, dict] = Field(default_factory=TeamConfig, sa_column=Column(JSON)) + agents: List["Agent"] = Relationship(back_populates="teams", link_model=TeamAgentLink) class Agent(SQLModel, table=True): @@ -177,14 +169,10 @@ class Agent(SQLModel, table=True): ) # pylint: disable=not-callable user_id: Optional[str] = None version: Optional[str] = "0.0.1" - config: Union[AgentConfig, dict] = Field( - default_factory=AgentConfig, sa_column=Column(JSON)) - tools: List[Tool] = Relationship( - back_populates="agents", link_model=AgentToolLink) - models: List[Model] = Relationship( - back_populates="agents", link_model=AgentModelLink) - teams: List[Team] = Relationship( - back_populates="agents", link_model=TeamAgentLink) + config: Union[AgentConfig, dict] = Field(default_factory=AgentConfig, sa_column=Column(JSON)) + tools: List[Tool] = Relationship(back_populates="agents", link_model=AgentToolLink) + models: List[Model] = Relationship(back_populates="agents", link_model=AgentModelLink) + teams: List[Team] = Relationship(back_populates="agents", link_model=TeamAgentLink) class Message(SQLModel, table=True): @@ -200,17 +188,12 @@ class Message(SQLModel, table=True): ) # pylint: disable=not-callable user_id: Optional[str] = None version: Optional[str] = "0.0.1" - config: Union[MessageConfig, dict] = Field( - default_factory=MessageConfig, sa_column=Column(JSON)) + config: Union[MessageConfig, dict] = Field(default_factory=MessageConfig, sa_column=Column(JSON)) session_id: Optional[int] = Field( default=None, sa_column=Column(Integer, ForeignKey("session.id", ondelete="CASCADE")) ) - run_id: Optional[UUID] = Field( - default=None, foreign_key="run.id" - ) - - message_meta: Optional[Union[MessageMeta, dict]] = Field( - default={}, sa_column=Column(JSON)) + run_id: Optional[UUID] = Field(default=None, foreign_key="run.id") + message_meta: Optional[Union[MessageMeta, dict]] = Field(default={}, sa_column=Column(JSON)) class Session(SQLModel, table=True): @@ -226,9 +209,7 @@ class Session(SQLModel, table=True): ) # pylint: disable=not-callable user_id: Optional[str] = None version: Optional[str] = "0.0.1" - team_id: Optional[int] = Field( - default=None, sa_column=Column(Integer, ForeignKey("team.id", ondelete="CASCADE")) - ) + team_id: Optional[int] = Field(default=None, sa_column=Column(Integer, ForeignKey("team.id", ondelete="CASCADE"))) name: Optional[str] = None @@ -242,41 +223,59 @@ class RunStatus(str, Enum): class Run(SQLModel, table=True): """Represents a single execution run within a session""" - __table_args__ = {"sqlite_autoincrement": True} - # Primary key using UUID - id: UUID = Field( - default_factory=uuid4, - primary_key=True, - index=True - ) + __table_args__ = {"sqlite_autoincrement": True} - # Timestamps using the same pattern as other models + id: UUID = Field(default_factory=uuid4, primary_key=True, index=True) created_at: datetime = Field( - default_factory=datetime.now, - sa_column=Column(DateTime(timezone=True), server_default=func.now()) + default_factory=datetime.now, sa_column=Column(DateTime(timezone=True), server_default=func.now()) ) updated_at: datetime = Field( - default_factory=datetime.now, - sa_column=Column(DateTime(timezone=True), onupdate=func.now()) + default_factory=datetime.now, sa_column=Column(DateTime(timezone=True), onupdate=func.now()) ) - - # Foreign key to Session session_id: Optional[int] = Field( - default=None, - sa_column=Column( - Integer, - ForeignKey("session.id", ondelete="CASCADE"), - nullable=False - ) + default=None, sa_column=Column(Integer, ForeignKey("session.id", ondelete="CASCADE"), nullable=False) ) - - # Run status and metadata status: RunStatus = Field(default=RunStatus.CREATED) + + # Store the original user task + task: Union[MessageConfig, dict] = Field(default_factory=MessageConfig, sa_column=Column(JSON)) + + # Store TeamResult which contains TaskResult + team_result: Union[TeamResult, dict] = Field(default=None, sa_column=Column(JSON)) + error_message: Optional[str] = None + version: Optional[str] = "0.0.1" + messages: Union[List[Message], List[dict]] = Field(default_factory=list, sa_column=Column(JSON)) + + class Config: + json_encoders = {UUID: str, datetime: lambda v: v.isoformat()} + + +class GalleryConfig(SQLModel, table=False): + id: UUID = Field(default_factory=uuid4, primary_key=True, index=True) + title: Optional[str] = None + description: Optional[str] = None + run: Run + team: TeamConfig = None + tags: Optional[List[str]] = None + visibility: str = "public" # public, private, shared - # Metadata storage following pattern from Message model - run_meta: dict = Field(default={}, sa_column=Column(JSON)) + class Config: + json_encoders = {UUID: str, datetime: lambda v: v.isoformat()} - # Version tracking like other models + +class Gallery(SQLModel, table=True): + __table_args__ = {"sqlite_autoincrement": True} + id: Optional[int] = Field(default=None, primary_key=True) + created_at: datetime = Field( + default_factory=datetime.now, + sa_column=Column(DateTime(timezone=True), server_default=func.now()), + ) + updated_at: datetime = Field( + default_factory=datetime.now, + sa_column=Column(DateTime(timezone=True), onupdate=func.now()), + ) + user_id: Optional[str] = None version: Optional[str] = "0.0.1" + config: Union[GalleryConfig, dict] = Field(default_factory=GalleryConfig, sa_column=Column(JSON)) diff --git a/python/packages/autogen-studio/autogenstudio/datamodel/types.py b/python/packages/autogen-studio/autogenstudio/datamodel/types.py index 5fec5d984bec..5974e1355626 100644 --- a/python/packages/autogen-studio/autogenstudio/datamodel/types.py +++ b/python/packages/autogen-studio/autogenstudio/datamodel/types.py @@ -1,10 +1,10 @@ from datetime import datetime from enum import Enum from pathlib import Path -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Literal, Optional, Union +from autogen_agentchat.base import TaskResult from pydantic import BaseModel -from autogen_agentchat.base._task import TaskResult class ModelTypes(str, Enum): @@ -29,9 +29,10 @@ class TerminationTypes(str, Enum): MAX_MESSAGES = "MaxMessageTermination" STOP_MESSAGE = "StopMessageTermination" TEXT_MENTION = "TextMentionTermination" + COMBINATION = "CombinationTermination" -class ComponentType(str, Enum): +class ComponentTypes(str, Enum): TEAM = "team" AGENT = "agent" MODEL = "model" @@ -40,11 +41,9 @@ class ComponentType(str, Enum): class BaseConfig(BaseModel): - model_config = { - "protected_namespaces": () - } + model_config = {"protected_namespaces": ()} version: str = "1.0.0" - component_type: ComponentType + component_type: ComponentTypes class MessageConfig(BaseModel): @@ -58,7 +57,7 @@ class ModelConfig(BaseConfig): model_type: ModelTypes api_key: Optional[str] = None base_url: Optional[str] = None - component_type: ComponentType = ComponentType.MODEL + component_type: ComponentTypes = ComponentTypes.MODEL class ToolConfig(BaseConfig): @@ -66,7 +65,7 @@ class ToolConfig(BaseConfig): description: str content: str tool_type: ToolTypes - component_type: ComponentType = ComponentType.TOOL + component_type: ComponentTypes = ComponentTypes.TOOL class AgentConfig(BaseConfig): @@ -76,14 +75,18 @@ class AgentConfig(BaseConfig): model_client: Optional[ModelConfig] = None tools: Optional[List[ToolConfig]] = None description: Optional[str] = None - component_type: ComponentType = ComponentType.AGENT + component_type: ComponentTypes = ComponentTypes.AGENT class TerminationConfig(BaseConfig): termination_type: TerminationTypes + # Fields for basic terminations max_messages: Optional[int] = None text: Optional[str] = None - component_type: ComponentType = ComponentType.TERMINATION + # Fields for combinations + operator: Optional[Literal["and", "or"]] = None + conditions: Optional[List["TerminationConfig"]] = None + component_type: ComponentTypes = ComponentTypes.TERMINATION class TeamConfig(BaseConfig): @@ -93,7 +96,7 @@ class TeamConfig(BaseConfig): model_client: Optional[ModelConfig] = None selector_prompt: Optional[str] = None termination_condition: Optional[TerminationConfig] = None - component_type: ComponentType = ComponentType.TEAM + component_type: ComponentTypes = ComponentTypes.TEAM class TeamResult(BaseModel): @@ -111,6 +114,7 @@ class MessageMeta(BaseModel): log: Optional[List[dict]] = None usage: Optional[List[dict]] = None + # web request/response data models @@ -126,12 +130,6 @@ class SocketMessage(BaseModel): type: str -ComponentConfig = Union[ - TeamConfig, - AgentConfig, - ModelConfig, - ToolConfig, - TerminationConfig -] +ComponentConfig = Union[TeamConfig, AgentConfig, ModelConfig, ToolConfig, TerminationConfig] ComponentConfigInput = Union[str, Path, dict, ComponentConfig] diff --git a/python/packages/autogen-studio/autogenstudio/profiler.py b/python/packages/autogen-studio/autogenstudio/profiler.py deleted file mode 100644 index 679a56917e20..000000000000 --- a/python/packages/autogen-studio/autogenstudio/profiler.py +++ /dev/null @@ -1,108 +0,0 @@ -# metrics - agent_frequency, execution_count, tool_count, - -from typing import Dict, List, Optional - -from .datamodel import Message, MessageMeta - - -class Profiler: - """ - Profiler class to profile agent task runs and compute metrics - for performance evaluation. - """ - - def __init__(self): - self.metrics: List[Dict] = [] - - def _is_code(self, message: Message) -> bool: - """ - Check if the message contains code. - - :param message: The message instance to check. - :return: True if the message contains code, False otherwise. - """ - content = message.get("message").get("content").lower() - return "```" in content - - def _is_tool(self, message: Message) -> bool: - """ - Check if the message uses a tool. - - :param message: The message instance to check. - :return: True if the message uses a tool, False otherwise. - """ - content = message.get("message").get("content").lower() - return "from skills import" in content - - def _is_code_execution(self, message: Message) -> bool: - """ - Check if the message indicates code execution. - - :param message: The message instance to check. - :return: dict with is_code and status keys. - """ - content = message.get("message").get("content").lower() - if "exitcode:" in content: - status = "exitcode: 0" in content - return {"is_code": True, "status": status} - else: - return {"is_code": False, "status": False} - - def _is_terminate(self, message: Message) -> bool: - """ - Check if the message indicates termination. - - :param message: The message instance to check. - :return: True if the message indicates termination, False otherwise. - """ - content = message.get("message").get("content").lower() - return "terminate" in content - - def profile(self, agent_message: Message): - """ - Profile the agent task run and compute metrics. - - :param agent: The agent instance that ran the task. - :param task: The task instance that was run. - """ - meta = MessageMeta(**agent_message.meta) - print(meta.log) - usage = meta.usage - messages = meta.messages - profile = [] - bar = [] - stats = {} - total_code_executed = 0 - success_code_executed = 0 - agents = [] - for message in messages: - agent = message.get("sender") - is_code = self._is_code(message) - is_tool = self._is_tool(message) - is_code_execution = self._is_code_execution(message) - total_code_executed += is_code_execution["is_code"] - success_code_executed += 1 if is_code_execution["status"] else 0 - - row = { - "agent": agent, - "tool_call": is_code, - "code_execution": is_code_execution, - "terminate": self._is_terminate(message), - } - bar_row = { - "agent": agent, - "tool_call": "tool call" if is_tool else "no tool call", - "code_execution": ( - "success" - if is_code_execution["status"] - else "failure" if is_code_execution["is_code"] else "no code" - ), - "message": 1, - } - profile.append(row) - bar.append(bar_row) - agents.append(agent) - code_success_rate = (success_code_executed / total_code_executed if total_code_executed > 0 else 0) * 100 - stats["code_success_rate"] = code_success_rate - stats["total_code_executed"] = total_code_executed - return {"profile": profile, "bar": bar, "stats": stats, "agents": set(agents), "usage": usage} diff --git a/python/packages/autogen-studio/autogenstudio/teammanager.py b/python/packages/autogen-studio/autogenstudio/teammanager.py index ebe4302c5f58..9dcca06c8a38 100644 --- a/python/packages/autogen-studio/autogenstudio/teammanager.py +++ b/python/packages/autogen-studio/autogenstudio/teammanager.py @@ -1,50 +1,39 @@ -from typing import AsyncGenerator, Callable, Union, Optional import time -from .database import ComponentFactory, Component -from .datamodel import TeamResult, TaskResult, ComponentConfigInput -from autogen_agentchat.messages import ChatMessage, AgentMessage +from typing import AsyncGenerator, Callable, Optional, Union + +from autogen_agentchat.base import TaskResult +from autogen_agentchat.messages import AgentMessage, ChatMessage from autogen_core.base import CancellationToken +from .database import Component, ComponentFactory +from .datamodel import ComponentConfigInput, TeamResult + class TeamManager: def __init__(self) -> None: self.component_factory = ComponentFactory() - async def _create_team( - self, - team_config: ComponentConfigInput, - input_func: Optional[Callable] = None - ) -> Component: + 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 - ) + 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 - ) + return TeamResult(task_result=task_result, usage="", duration=time.time() - start_time) async def run_stream( self, task: str, team_config: ComponentConfigInput, input_func: Optional[Callable] = None, - cancellation_token: Optional[CancellationToken] = None + cancellation_token: Optional[CancellationToken] = None, ) -> AsyncGenerator[Union[AgentMessage, ChatMessage, TaskResult], None]: """Stream the team's execution results""" start_time = time.time() try: team = await self._create_team(team_config, input_func) - stream = team.run_stream( - task=task, - cancellation_token=cancellation_token - ) + stream = team.run_stream(task=task, cancellation_token=cancellation_token) async for message in stream: if cancellation_token and cancellation_token.is_cancelled(): @@ -63,15 +52,12 @@ async def run( task: str, team_config: ComponentConfigInput, input_func: Optional[Callable] = None, - cancellation_token: Optional[CancellationToken] = None + cancellation_token: Optional[CancellationToken] = None, ) -> TeamResult: """Original non-streaming run method with optional cancellation""" start_time = time.time() team = await self._create_team(team_config, input_func) - result = await team.run( - task=task, - cancellation_token=cancellation_token - ) + result = await team.run(task=task, cancellation_token=cancellation_token) return self._create_result(result, start_time) diff --git a/python/packages/autogen-studio/autogenstudio/utils/__init__.py b/python/packages/autogen-studio/autogenstudio/utils/__init__.py index 16281fe0b66d..e69de29bb2d1 100644 --- a/python/packages/autogen-studio/autogenstudio/utils/__init__.py +++ b/python/packages/autogen-studio/autogenstudio/utils/__init__.py @@ -1 +0,0 @@ -from .utils import * diff --git a/python/packages/autogen-studio/autogenstudio/utils/utils.py b/python/packages/autogen-studio/autogenstudio/utils/utils.py index 419a6e4a66d2..38955bea5fc2 100644 --- a/python/packages/autogen-studio/autogenstudio/utils/utils.py +++ b/python/packages/autogen-studio/autogenstudio/utils/utils.py @@ -10,7 +10,6 @@ from dotenv import load_dotenv from loguru import logger - from ..datamodel import Model from ..version import APP_NAME @@ -153,8 +152,7 @@ def get_modified_files(start_timestamp: float, end_timestamp: float, source_dir: for root, dirs, files in os.walk(source_dir): # Update directories and files to exclude those to be ignored dirs[:] = [d for d in dirs if d not in ignore_files] - files[:] = [f for f in files if f not in ignore_files and os.path.splitext(f)[ - 1] not in ignore_extensions] + files[:] = [f for f in files if f not in ignore_files and os.path.splitext(f)[1] not in ignore_extensions] for file in files: file_path = os.path.join(root, file) @@ -163,9 +161,7 @@ def get_modified_files(start_timestamp: float, end_timestamp: float, source_dir: # Verify if the file was modified within the given timestamp range if start_timestamp <= file_mtime <= end_timestamp: file_relative_path = ( - "files/user" + - file_path.split( - "files/user", 1)[1] if "files/user" in file_path else "" + "files/user" + file_path.split("files/user", 1)[1] if "files/user" in file_path else "" ) file_type = get_file_type(file_path) @@ -253,41 +249,27 @@ def sanitize_model(model: Model): model = model.model_dump() valid_keys = ["model", "base_url", "api_key", "api_type", "api_version"] # only add key if value is not None - sanitized_model = {k: v for k, v in model.items() if ( - v is not None and v != "") and k in valid_keys} + sanitized_model = {k: v for k, v in model.items() if (v is not None and v != "") and k in valid_keys} return sanitized_model -def test_model(model: Model): - """ - Test the model endpoint by sending a simple message to the model and returning the response. - """ +class Version: + def __init__(self, ver_str: str): + try: + # Split into major.minor.patch + self.major, self.minor, self.patch = map(int, ver_str.split(".")) + except (ValueError, AttributeError) as err: + raise ValueError(f"Invalid version format: {ver_str}. Expected: major.minor.patch") from err + + def __str__(self): + return f"{self.major}.{self.minor}.{self.patch}" + + def __eq__(self, other): + if isinstance(other, str): + other = Version(other) + return (self.major, self.minor, self.patch) == (other.major, other.minor, other.patch) - print("Testing model", model) - - -# def summarize_chat_history(task: str, messages: List[Dict[str, str]], client: ModelClient): -# """ -# Summarize the chat history using the model endpoint and returning the response. -# """ -# summarization_system_prompt = f""" -# You are a helpful assistant that is able to review the chat history between a set of agents (userproxy agents, assistants etc) as they try to address a given TASK and provide a summary. Be SUCCINCT but also comprehensive enough to allow others (who cannot see the chat history) understand and recreate the solution. - -# The task requested by the user is: -# === -# {task} -# === -# The summary should focus on extracting the actual solution to the task from the chat history (assuming the task was addressed) such that any other agent reading the summary will understand what the actual solution is. Use a neutral tone and DO NOT directly mention the agents. Instead only focus on the actions that were carried out (e.g. do not say 'assistant agent generated some code visualization code ..' instead say say 'visualization code was generated ..'. The answer should be framed as a response to the user task. E.g. if the task is "What is the height of the Eiffel tower", the summary should be "The height of the Eiffel Tower is ..."). -# """ -# summarization_prompt = [ -# { -# "role": "system", -# "content": summarization_system_prompt, -# }, -# { -# "role": "user", -# "content": f"Summarize the following chat history. {str(messages)}", -# }, -# ] -# response = client.create(messages=summarization_prompt, cache_seed=None) -# return response.choices[0].message.content + def __gt__(self, other): + if isinstance(other, str): + other = Version(other) + return (self.major, self.minor, self.patch) > (other.major, other.minor, other.patch) diff --git a/python/packages/autogen-studio/autogenstudio/version.py b/python/packages/autogen-studio/autogenstudio/version.py index a6f047da1cb8..8534dc259905 100644 --- a/python/packages/autogen-studio/autogenstudio/version.py +++ b/python/packages/autogen-studio/autogenstudio/version.py @@ -1,3 +1,3 @@ -VERSION = "0.4.0.dev37" +VERSION = "0.4.0.dev38" __version__ = VERSION APP_NAME = "autogenstudio" diff --git a/python/packages/autogen-studio/autogenstudio/web/app.py b/python/packages/autogen-studio/autogenstudio/web/app.py index 8d62cf1adffb..2e2ad3337248 100644 --- a/python/packages/autogen-studio/autogenstudio/web/app.py +++ b/python/packages/autogen-studio/autogenstudio/web/app.py @@ -1,18 +1,19 @@ # api/app.py import os +from contextlib import asynccontextmanager +from typing import AsyncGenerator + # import logging from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from fastapi.staticfiles import StaticFiles -from contextlib import asynccontextmanager -from typing import AsyncGenerator from loguru import logger -from .routes import sessions, runs, teams, agents, models, tools, ws -from .deps import init_managers, cleanup_managers +from ..version import VERSION from .config import settings +from .deps import cleanup_managers, init_managers from .initialization import AppInitializer -from ..version import VERSION +from .routes import agents, models, runs, sessions, teams, tools, ws # Configure logging # logger = logging.getLogger(__name__) @@ -54,6 +55,7 @@ async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]: except Exception as e: logger.error(f"Error during shutdown: {str(e)}") + # Create FastAPI application app = FastAPI(lifespan=lifespan, debug=True) @@ -143,6 +145,7 @@ async def get_version(): "data": {"version": VERSION}, } + # Health check endpoint @@ -154,6 +157,7 @@ async def health_check(): "message": "Service is healthy", } + # Mount static file directories app.mount("/api", api) app.mount( @@ -172,7 +176,7 @@ async def internal_error_handler(request, exc): return { "status": False, "message": "Internal server error", - "detail": str(exc) if settings.API_DOCS else "Internal server error" + "detail": str(exc) if settings.API_DOCS else "Internal server error", } diff --git a/python/packages/autogen-studio/autogenstudio/web/deps.py b/python/packages/autogen-studio/autogenstudio/web/deps.py index 1767c004eee0..d2e5b6fabb4a 100644 --- a/python/packages/autogen-studio/autogenstudio/web/deps.py +++ b/python/packages/autogen-studio/autogenstudio/web/deps.py @@ -1,14 +1,14 @@ # api/deps.py -from typing import Optional -from fastapi import Depends, HTTPException, status import logging from contextlib import contextmanager +from typing import Optional -from ..database import DatabaseManager -from .managers.connection import WebSocketManager +from fastapi import Depends, HTTPException, status + +from ..database import ConfigurationManager, DatabaseManager from ..teammanager import TeamManager from .config import settings -from ..database import ConfigurationManager +from .managers.connection import WebSocketManager logger = logging.getLogger(__name__) @@ -25,17 +25,16 @@ def get_db_context(): """Provide a transactional scope around a series of operations.""" if not _db_manager: raise HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, - detail="Database manager not initialized" + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Database manager not initialized" ) try: yield _db_manager except Exception as e: logger.error(f"Database operation failed: {str(e)}") raise HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, - detail="Database operation failed" - ) + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Database operation failed" + ) from e + # Dependency providers @@ -44,8 +43,7 @@ async def get_db() -> DatabaseManager: """Dependency provider for database manager""" if not _db_manager: raise HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, - detail="Database manager not initialized" + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Database manager not initialized" ) return _db_manager @@ -54,8 +52,7 @@ async def get_websocket_manager() -> WebSocketManager: """Dependency provider for connection manager""" if not _websocket_manager: raise HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, - detail="Connection manager not initialized" + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Connection manager not initialized" ) return _websocket_manager @@ -63,12 +60,10 @@ async def get_websocket_manager() -> WebSocketManager: async def get_team_manager() -> TeamManager: """Dependency provider for team manager""" if not _team_manager: - raise HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, - detail="Team manager not initialized" - ) + raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Team manager not initialized") return _team_manager + # Authentication dependency @@ -83,6 +78,7 @@ async def get_current_user( # Implement your user authentication here return "user_id" # Replace with actual user identification + # Manager initialization and cleanup @@ -94,20 +90,16 @@ async def init_managers(database_uri: str, config_dir: str, app_root: str) -> No try: # Initialize database manager - _db_manager = DatabaseManager( - engine_uri=database_uri, auto_upgrade=settings.UPGRADE_DATABASE, base_dir=app_root) - _db_manager.create_db_and_tables() + _db_manager = DatabaseManager(engine_uri=database_uri, base_dir=app_root) + _db_manager.initialize_database(auto_upgrade=settings.UPGRADE_DATABASE) # init default team config _team_config_manager = ConfigurationManager(db_manager=_db_manager) - import_result = await _team_config_manager.import_directory( - config_dir, settings.DEFAULT_USER_ID, check_exists=True) + await _team_config_manager.import_directory(config_dir, settings.DEFAULT_USER_ID, check_exists=True) # Initialize connection manager - _websocket_manager = WebSocketManager( - db_manager=_db_manager - ) + _websocket_manager = WebSocketManager(db_manager=_db_manager) logger.info("Connection manager initialized") # Initialize team manager @@ -149,6 +141,7 @@ async def cleanup_managers() -> None: logger.info("All managers cleaned up") + # Utility functions for dependency management @@ -157,19 +150,17 @@ def get_manager_status() -> dict: return { "database_manager": _db_manager is not None, "websocket_manager": _websocket_manager is not None, - "team_manager": _team_manager is not None + "team_manager": _team_manager is not None, } + # Combined dependencies async def get_managers(): """Get all managers in one dependency""" - return { - "db": await get_db(), - "connection": await get_websocket_manager(), - "team": await get_team_manager() - } + return {"db": await get_db(), "connection": await get_websocket_manager(), "team": await get_team_manager()} + # Error handling for manager operations @@ -183,19 +174,21 @@ def __init__(self, manager_name: str, operation: str, detail: str): self.detail = detail super().__init__(f"{manager_name} failed during {operation}: {detail}") + # Dependency for requiring specific managers def require_managers(*manager_names: str): """Decorator to require specific managers for a route""" + async def dependency(): status = get_manager_status() - missing = [name for name in manager_names if not status.get( - f"{name}_manager")] + missing = [name for name in manager_names if not status.get(f"{name}_manager")] if missing: raise HTTPException( status_code=status.HTTP_503_SERVICE_UNAVAILABLE, - detail=f"Required managers not available: {', '.join(missing)}" + detail=f"Required managers not available: {', '.join(missing)}", ) return True + return Depends(dependency) diff --git a/python/packages/autogen-studio/autogenstudio/web/initialization.py b/python/packages/autogen-studio/autogenstudio/web/initialization.py index e938d222062d..00d8c0afa0b1 100644 --- a/python/packages/autogen-studio/autogenstudio/web/initialization.py +++ b/python/packages/autogen-studio/autogenstudio/web/initialization.py @@ -2,15 +2,17 @@ import os from pathlib import Path from typing import Dict -from pydantic import BaseModel -from loguru import logger + from dotenv import load_dotenv +from loguru import logger +from pydantic import BaseModel from .config import Settings class _AppPaths(BaseModel): """Internal model representing all application paths""" + app_root: Path static_root: Path user_files: Path @@ -47,9 +49,7 @@ def _get_database_uri(self, app_root: Path) -> str: """Generate database URI based on settings or environment""" if db_uri := os.getenv("AUTOGENSTUDIO_DATABASE_URI"): return db_uri - return self.settings.DATABASE_URI.replace( - "./", str(app_root) + "/" - ) + return self.settings.DATABASE_URI.replace("./", str(app_root) + "/") def _init_paths(self) -> _AppPaths: """Initialize and return AppPaths instance""" @@ -60,14 +60,13 @@ def _init_paths(self) -> _AppPaths: user_files=app_root / "files" / "user", ui_root=self._app_path / "ui", config_dir=app_root / self.settings.CONFIG_DIR, - database_uri=self._get_database_uri(app_root) + database_uri=self._get_database_uri(app_root), ) def _create_directories(self) -> None: """Create all required directories""" self.app_root.mkdir(parents=True, exist_ok=True) - dirs = [self.static_root, self.user_files, - self.ui_root, self.config_dir] + dirs = [self.static_root, self.user_files, self.ui_root, self.config_dir] for path in dirs: path.mkdir(parents=True, exist_ok=True) diff --git a/python/packages/autogen-studio/autogenstudio/web/managers/connection.py b/python/packages/autogen-studio/autogenstudio/web/managers/connection.py index 5ed613cbb837..831d79ac05de 100644 --- a/python/packages/autogen-studio/autogenstudio/web/managers/connection.py +++ b/python/packages/autogen-studio/autogenstudio/web/managers/connection.py @@ -1,16 +1,17 @@ import asyncio -from autogen_agentchat.base._task import TaskResult -from fastapi import WebSocket, WebSocketDisconnect -from typing import Callable, Dict, Optional, Any -from uuid import UUID import logging from datetime import datetime, timezone +from typing import Any, Callable, Dict, Optional, Union +from uuid import UUID -from ...datamodel import Run, RunStatus, TeamResult -from ...database import DatabaseManager -from ...teammanager import TeamManager +from autogen_agentchat.base._task import TaskResult from autogen_agentchat.messages import AgentMessage, ChatMessage, TextMessage from autogen_core.base import CancellationToken +from fastapi import WebSocket, WebSocketDisconnect + +from ...database import DatabaseManager +from ...datamodel import Message, MessageConfig, Run, RunStatus, TeamResult +from ...teammanager import TeamManager logger = logging.getLogger(__name__) @@ -26,12 +27,20 @@ def __init__(self, db_manager: DatabaseManager): self._closed_connections: set[UUID] = set() self._input_responses: Dict[UUID, asyncio.Queue] = {} - 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() + 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() 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() + 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: try: @@ -41,87 +50,118 @@ async def connect(self, websocket: WebSocket, run_id: UUID) -> bool: # Initialize input queue for this connection self._input_responses[run_id] = asyncio.Queue() - run = await self._get_run(run_id) - if run: - run.status = RunStatus.ACTIVE - self.db_manager.upsert(run) - - await self._send_message(run_id, { - "type": "system", - "status": "connected", - "timestamp": datetime.now(timezone.utc).isoformat() - }) + await self._send_message( + run_id, {"type": "system", "status": "connected", "timestamp": datetime.now(timezone.utc).isoformat()} + ) return True except Exception as e: logger.error(f"Connection error for run {run_id}: {e}") return False - async def start_stream( - self, - run_id: UUID, - team_manager: TeamManager, - task: str, - team_config: dict - ) -> None: + async def start_stream(self, run_id: UUID, task: str, team_config: dict) -> None: + """Start streaming task execution with proper run management""" if run_id not in self._connections or run_id in self._closed_connections: raise ValueError(f"No active connection for run {run_id}") + team_manager = TeamManager() cancellation_token = CancellationToken() self._cancellation_tokens[run_id] = cancellation_token + final_result = None try: - # Create input function for this run + # Update run with task and status + run = await self._get_run(run_id) + if run: + run.task = MessageConfig(content=task, source="user").model_dump() + run.status = RunStatus.ACTIVE + self.db_manager.upsert(run) + input_func = self.create_input_func(run_id) async for message in team_manager.run_stream( - task=task, - team_config=team_config, - input_func=input_func, # Pass the input function - cancellation_token=cancellation_token + task=task, team_config=team_config, input_func=input_func, cancellation_token=cancellation_token ): if cancellation_token.is_cancelled() or run_id in self._closed_connections: - logger.info( - f"Stream cancelled or connection closed for run {run_id}") + logger.info(f"Stream cancelled or connection closed for run {run_id}") break formatted_message = self._format_message(message) if formatted_message: await self._send_message(run_id, formatted_message) + # Save message if it's a content message + if isinstance(message, (AgentMessage, ChatMessage)): + await self._save_message(run_id, message) + # Capture final result if it's a TeamResult + elif isinstance(message, TeamResult): + final_result = message.model_dump() + if not cancellation_token.is_cancelled() and run_id not in self._closed_connections: - await self._update_run_status(run_id, RunStatus.COMPLETE) + if final_result: + await self._update_run(run_id, RunStatus.COMPLETE, team_result=final_result) + else: + logger.warning(f"No final result captured for completed run {run_id}") + await self._update_run_status(run_id, RunStatus.COMPLETE) else: - await self._send_message(run_id, { - "type": "completion", - "status": "cancelled", - "data": self._cancel_message, - "timestamp": datetime.now(timezone.utc).isoformat() - }) - await self._update_run_status(run_id, RunStatus.STOPPED) + await self._send_message( + run_id, + { + "type": "completion", + "status": "cancelled", + "data": self._cancel_message, + "timestamp": datetime.now(timezone.utc).isoformat(), + }, + ) + # Update run with cancellation result + await self._update_run(run_id, RunStatus.STOPPED, team_result=self._cancel_message) except Exception as e: logger.error(f"Stream error for run {run_id}: {e}") await self._handle_stream_error(run_id, e) - finally: self._cancellation_tokens.pop(run_id, None) + async def _save_message(self, run_id: UUID, message: Union[AgentMessage, ChatMessage]) -> None: + """Save a message to the database""" + run = await self._get_run(run_id) + if run: + db_message = Message( + session_id=run.session_id, + run_id=run_id, + config=message.model_dump(), + user_id=None, # You might want to pass this from somewhere + ) + self.db_manager.upsert(db_message) + + async def _update_run( + self, run_id: UUID, status: RunStatus, team_result: Optional[dict] = None, error: Optional[str] = None + ) -> None: + """Update run status and result""" + run = await self._get_run(run_id) + if run: + run.status = status + if team_result: + run.team_result = team_result + if error: + run.error_message = error + self.db_manager.upsert(run) + 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: + async def input_handler(prompt: str = "", cancellation_token: Optional[CancellationToken] = None) -> str: + try: # Send input request to client - await self._send_message(run_id, { - "type": "input_request", - "prompt": prompt, - "data": { - "source": "system", - "content": prompt + await self._send_message( + run_id, + { + "type": "input_request", + "prompt": prompt, + "data": {"source": "system", "content": prompt}, + "timestamp": datetime.now(timezone.utc).isoformat(), }, - "timestamp": datetime.now(timezone.utc).isoformat() - }) + ) # Wait for response if run_id in self._input_responses: @@ -141,26 +181,37 @@ async def handle_input_response(self, run_id: UUID, response: str) -> None: 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}") + 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""" if run_id in self._cancellation_tokens: logger.info(f"Stopping run {run_id}") - # self._cancellation_tokens[run_id].cancel() - # Send final message if connection still exists and not closed - if run_id in self._connections and run_id not in self._closed_connections: - try: - await self._send_message(run_id, { - "type": "completion", - "status": "cancelled", - "data": self._get_stop_message(reason), - "timestamp": datetime.now(timezone.utc).isoformat() - }) - except Exception: - pass + stop_message = self._get_stop_message(reason) + + try: + # Update run record first + await self._update_run(run_id, status=RunStatus.STOPPED, team_result=stop_message) + + # Then handle websocket communication if connection is active + if run_id in self._connections and run_id not in self._closed_connections: + await self._send_message( + run_id, + { + "type": "completion", + "status": "cancelled", + "data": stop_message, + "timestamp": datetime.now(timezone.utc).isoformat(), + }, + ) + + # Finally cancel the token + self._cancellation_tokens[run_id].cancel() + + except Exception as e: + logger.error(f"Error stopping run {run_id}: {e}") + # We might want to force disconnect here if db update failed + # await self.disconnect(run_id) # Optional async def disconnect(self, run_id: UUID) -> None: """Clean up connection and associated resources""" @@ -185,8 +236,7 @@ async def _send_message(self, run_id: UUID, message: dict) -> None: message: Message dictionary to send """ if run_id in self._closed_connections: - logger.warning( - f"Attempted to send message to closed connection for run {run_id}") + logger.warning(f"Attempted to send message to closed connection for run {run_id}") return try: @@ -194,36 +244,36 @@ async def _send_message(self, run_id: UUID, message: dict) -> None: websocket = self._connections[run_id] await websocket.send_json(message) except WebSocketDisconnect: - logger.warning( - f"WebSocket disconnected while sending message for run {run_id}") + logger.warning(f"WebSocket disconnected while sending message for run {run_id}") await self.disconnect(run_id) except Exception as e: - logger.error( - f"Error sending message for run {run_id}: {e}, {message}") + logger.error(f"Error sending message for run {run_id}: {e}, {message}") # Don't try to send error message here to avoid potential recursive loop await self._update_run_status(run_id, RunStatus.ERROR, str(e)) await self.disconnect(run_id) async def _handle_stream_error(self, run_id: UUID, error: Exception) -> None: - """Handle stream errors with connection state awareness - - Args: - run_id: UUID of the run - error: Exception that occurred - """ + """Handle stream errors with proper run updates""" if run_id not in self._closed_connections: - try: - await self._send_message(run_id, { + error_result = TeamResult( + task_result=TaskResult( + messages=[TextMessage(source="system", content=str(error))], stop_reason="error" + ), + usage="", + duration=0, + ).model_dump() + + await self._send_message( + run_id, + { "type": "completion", "status": "error", - "error": str(error), - "timestamp": datetime.now(timezone.utc).isoformat() - }) - except Exception as send_error: - logger.error( - f"Failed to send error message for run {run_id}: {send_error}") + "data": error_result, + "timestamp": datetime.now(timezone.utc).isoformat(), + }, + ) - await self._update_run_status(run_id, RunStatus.ERROR, str(error)) + await self._update_run(run_id, RunStatus.ERROR, team_result=error_result, error=str(error)) def _format_message(self, message: Any) -> Optional[dict]: """Format message for WebSocket transmission @@ -236,10 +286,7 @@ def _format_message(self, message: Any) -> Optional[dict]: """ try: if isinstance(message, (AgentMessage, ChatMessage)): - return { - "type": "message", - "data": message.model_dump() - } + return {"type": "message", "data": message.model_dump()} elif isinstance(message, TeamResult): return { "type": "result", @@ -260,16 +307,10 @@ async def _get_run(self, run_id: UUID) -> Optional[Run]: Returns: Optional[Run]: Run object if found, None otherwise """ - response = self.db_manager.get( - Run, filters={"id": run_id}, return_json=False) + response = self.db_manager.get(Run, filters={"id": run_id}, return_json=False) return response.data[0] if response.status and response.data else None - async def _update_run_status( - self, - run_id: UUID, - status: RunStatus, - error: Optional[str] = None - ) -> None: + async def _update_run_status(self, run_id: UUID, status: RunStatus, error: Optional[str] = None) -> None: """Update run status in database Args: @@ -285,14 +326,27 @@ async def _update_run_status( 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") + 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() + run = await self._get_run(run_id) + if run and run.status == RunStatus.ACTIVE: + interrupted_result = TeamResult( + task_result=TaskResult( + messages=[TextMessage(source="system", content="Run interrupted by server shutdown")], + stop_reason="server_shutdown", + ), + usage="", + duration=0, + ).model_dump() + + run.status = RunStatus.STOPPED + run.team_result = interrupted_result + self.db_manager.upsert(run) # Then disconnect all websockets with timeout # 10 second timeout for entire cleanup diff --git a/python/packages/autogen-studio/autogenstudio/web/routes/agents.py b/python/packages/autogen-studio/autogenstudio/web/routes/agents.py index 183dbf2a5bee..c0b029f67593 100644 --- a/python/packages/autogen-studio/autogenstudio/web/routes/agents.py +++ b/python/packages/autogen-studio/autogenstudio/web/routes/agents.py @@ -1,181 +1,51 @@ -# api/routes/agents.py -from fastapi import APIRouter, Depends, HTTPException from typing import Dict -from ..deps import get_db + +from fastapi import APIRouter, Depends, HTTPException + +from ...database import DatabaseManager # Add this import from ...datamodel import Agent, Model, Tool +from ..deps import get_db router = APIRouter() @router.get("/") -async def list_agents( - user_id: str, - db=Depends(get_db) -) -> Dict: +async def list_agents(user_id: str, db: DatabaseManager = Depends(get_db)) -> Dict: """List all agents for a user""" response = db.get(Agent, filters={"user_id": user_id}) - return { - "status": True, - "data": response.data - } + return {"status": True, "data": response.data} @router.get("/{agent_id}") -async def get_agent( - agent_id: int, - user_id: str, - db=Depends(get_db) -) -> Dict: +async def get_agent(agent_id: int, user_id: str, db: DatabaseManager = Depends(get_db)) -> Dict: """Get a specific agent""" - response = db.get( - Agent, - filters={"id": agent_id, "user_id": user_id} - ) + response = db.get(Agent, filters={"id": agent_id, "user_id": user_id}) if not response.status or not response.data: raise HTTPException(status_code=404, detail="Agent not found") - return { - "status": True, - "data": response.data[0] - } + return {"status": True, "data": response.data[0]} @router.post("/") -async def create_agent( - agent: Agent, - db=Depends(get_db) -) -> Dict: +async def create_agent(agent: Agent, db: DatabaseManager = Depends(get_db)) -> Dict: """Create a new agent""" response = db.upsert(agent) if not response.status: raise HTTPException(status_code=400, detail=response.message) - return { - "status": True, - "data": response.data - } + return {"status": True, "data": response.data} @router.delete("/{agent_id}") -async def delete_agent( - agent_id: int, - user_id: str, - db=Depends(get_db) -) -> Dict: +async def delete_agent(agent_id: int, user_id: str, db: DatabaseManager = Depends(get_db)) -> Dict: """Delete an agent""" - response = db.delete( - filters={"id": agent_id, "user_id": user_id}, - model_class=Agent - ) - return { - "status": True, - "message": "Agent deleted successfully" - } + db.delete(filters={"id": agent_id, "user_id": user_id}, model_class=Agent) + return {"status": True, "message": "Agent deleted successfully"} + # Agent-Model link endpoints @router.post("/{agent_id}/models/{model_id}") -async def link_agent_model( - agent_id: int, - model_id: int, - db=Depends(get_db) -) -> Dict: +async def link_agent_model(agent_id: int, model_id: int, db: DatabaseManager = Depends(get_db)) -> Dict: """Link a model to an agent""" - response = db.link( - link_type="agent_model", - primary_id=agent_id, - secondary_id=model_id - ) - return { - "status": True, - "message": "Model linked to agent successfully" - } - - -@router.delete("/{agent_id}/models/{model_id}") -async def unlink_agent_model( - agent_id: int, - model_id: int, - db=Depends(get_db) -) -> Dict: - """Unlink a model from an agent""" - response = db.unlink( - link_type="agent_model", - primary_id=agent_id, - secondary_id=model_id - ) - return { - "status": True, - "message": "Model unlinked from agent successfully" - } - - -@router.get("/{agent_id}/models") -async def get_agent_models( - agent_id: int, - db=Depends(get_db) -) -> Dict: - """Get all models linked to an agent""" - response = db.get_linked_entities( - link_type="agent_model", - primary_id=agent_id, - return_json=True - ) - return { - "status": True, - "data": response.data - } - -# Agent-Tool link endpoints - - -@router.post("/{agent_id}/tools/{tool_id}") -async def link_agent_tool( - agent_id: int, - tool_id: int, - db=Depends(get_db) -) -> Dict: - """Link a tool to an agent""" - response = db.link( - link_type="agent_tool", - primary_id=agent_id, - secondary_id=tool_id - ) - return { - "status": True, - "message": "Tool linked to agent successfully" - } - - -@router.delete("/{agent_id}/tools/{tool_id}") -async def unlink_agent_tool( - agent_id: int, - tool_id: int, - db=Depends(get_db) -) -> Dict: - """Unlink a tool from an agent""" - response = db.unlink( - link_type="agent_tool", - primary_id=agent_id, - secondary_id=tool_id - ) - return { - "status": True, - "message": "Tool unlinked from agent successfully" - } - - -@router.get("/{agent_id}/tools") -async def get_agent_tools( - agent_id: int, - db=Depends(get_db) -) -> Dict: - """Get all tools linked to an agent""" - response = db.get_linked_entities( - link_type="agent_tool", - primary_id=agent_id, - return_json=True - ) - return { - "status": True, - "data": response.data - } + db.link(link_type="agent_model", primary_id=agent_id, secondary_id=model_id) + return {"status": True, "message": "Model linked to agent successfully"} diff --git a/python/packages/autogen-studio/autogenstudio/web/routes/gallery.py b/python/packages/autogen-studio/autogenstudio/web/routes/gallery.py new file mode 100644 index 000000000000..0b0451e53efb --- /dev/null +++ b/python/packages/autogen-studio/autogenstudio/web/routes/gallery.py @@ -0,0 +1,62 @@ +# api/routes/gallery.py +from fastapi import APIRouter, Depends, HTTPException + +from ...database import DatabaseManager +from ...datamodel import Gallery, GalleryConfig, Response, Run, Session +from ..deps import get_db + +router = APIRouter() + + +@router.post("/") +async def create_gallery_entry( + gallery_data: GalleryConfig, user_id: str, db: DatabaseManager = Depends(get_db) +) -> Response: + # First validate that user owns all runs + for run in gallery_data.runs: + run_result = db.get(Run, filters={"id": run.id}) + if not run_result.status or not run_result.data: + raise HTTPException(status_code=404, detail=f"Run {run.id} not found") + + # Get associated session to check ownership + session_result = db.get(Session, filters={"id": run_result.data[0].session_id}) + if not session_result.status or not session_result.data or session_result.data[0].user_id != user_id: + raise HTTPException(status_code=403, detail=f"Not authorized to add run {run.id} to gallery") + + # Create gallery entry + gallery = Gallery(user_id=user_id, config=gallery_data) + result = db.upsert(gallery) + return result + + +@router.get("/{gallery_id}") +async def get_gallery_entry(gallery_id: int, user_id: str, db: DatabaseManager = Depends(get_db)) -> Response: + result = db.get(Gallery, filters={"id": gallery_id}) + if not result.status or not result.data: + raise HTTPException(status_code=404, detail="Gallery entry not found") + + gallery = result.data[0] + if gallery.config["visibility"] != "public" and gallery.user_id != user_id: + raise HTTPException(status_code=403, detail="Not authorized to view this gallery entry") + + return result + + +@router.get("/") +async def list_gallery_entries(user_id: str, db: DatabaseManager = Depends(get_db)) -> Response: + result = db.get(Gallery, filters={"user_id": user_id}) + return result + + +@router.delete("/{gallery_id}") +async def delete_gallery_entry(gallery_id: int, user_id: str, db: DatabaseManager = Depends(get_db)) -> Response: + # Check ownership first + result = db.get(Gallery, filters={"id": gallery_id}) + if not result.status or not result.data: + raise HTTPException(status_code=404, detail="Gallery entry not found") + + if result.data[0].user_id != user_id: + raise HTTPException(status_code=403, detail="Not authorized to delete this gallery entry") + + # Delete if authorized + return db.delete(Gallery, filters={"id": gallery_id}) diff --git a/python/packages/autogen-studio/autogenstudio/web/routes/models.py b/python/packages/autogen-studio/autogenstudio/web/routes/models.py index 9b57e6255458..f041e52cb93b 100644 --- a/python/packages/autogen-studio/autogenstudio/web/routes/models.py +++ b/python/packages/autogen-studio/autogenstudio/web/routes/models.py @@ -1,95 +1,42 @@ # api/routes/models.py -from fastapi import APIRouter, Depends, HTTPException from typing import Dict + +from fastapi import APIRouter, Depends, HTTPException from openai import OpenAIError -from ..deps import get_db + from ...datamodel import Model -from ...utils import test_model +from ..deps import get_db router = APIRouter() @router.get("/") -async def list_models( - user_id: str, - db=Depends(get_db) -) -> Dict: +async def list_models(user_id: str, db=Depends(get_db)) -> Dict: """List all models for a user""" response = db.get(Model, filters={"user_id": user_id}) - return { - "status": True, - "data": response.data - } + return {"status": True, "data": response.data} @router.get("/{model_id}") -async def get_model( - model_id: int, - user_id: str, - db=Depends(get_db) -) -> Dict: +async def get_model(model_id: int, user_id: str, db=Depends(get_db)) -> Dict: """Get a specific model""" - response = db.get( - Model, - filters={"id": model_id, "user_id": user_id} - ) + response = db.get(Model, filters={"id": model_id, "user_id": user_id}) if not response.status or not response.data: raise HTTPException(status_code=404, detail="Model not found") - return { - "status": True, - "data": response.data[0] - } + return {"status": True, "data": response.data[0]} @router.post("/") -async def create_model( - model: Model, - db=Depends(get_db) -) -> Dict: +async def create_model(model: Model, db=Depends(get_db)) -> Dict: """Create a new model""" response = db.upsert(model) if not response.status: raise HTTPException(status_code=400, detail=response.message) - return { - "status": True, - "data": response.data - } + return {"status": True, "data": response.data} @router.delete("/{model_id}") -async def delete_model( - model_id: int, - user_id: str, - db=Depends(get_db) -) -> Dict: +async def delete_model(model_id: int, user_id: str, db=Depends(get_db)) -> Dict: """Delete a model""" - response = db.delete( - filters={"id": model_id, "user_id": user_id}, - model_class=Model - ) - return { - "status": True, - "message": "Model deleted successfully" - } - - -@router.post("/test") -async def test_model_endpoint(model: Model) -> Dict: - """Test a model configuration""" - try: - response = test_model(model) - return { - "status": True, - "message": "Model tested successfully", - "data": response - } - except OpenAIError as e: - raise HTTPException( - status_code=400, - detail=f"OpenAI API error: {str(e)}" - ) - except Exception as e: - raise HTTPException( - status_code=500, - detail=f"Error testing model: {str(e)}" - ) + db.delete(filters={"id": model_id, "user_id": user_id}, model_class=Model) + return {"status": True, "message": "Model deleted successfully"} diff --git a/python/packages/autogen-studio/autogenstudio/web/routes/runs.py b/python/packages/autogen-studio/autogenstudio/web/routes/runs.py index 7fb5e7475ac0..9644099de6f0 100644 --- a/python/packages/autogen-studio/autogenstudio/web/routes/runs.py +++ b/python/packages/autogen-studio/autogenstudio/web/routes/runs.py @@ -1,14 +1,12 @@ # /api/runs routes -from fastapi import APIRouter, Body, Depends, HTTPException -from uuid import UUID from typing import Dict +from uuid import UUID +from fastapi import APIRouter, Body, Depends, HTTPException from pydantic import BaseModel -from ..deps import get_db, get_websocket_manager, get_team_manager -from ...datamodel import Run, Session, Message, Team, RunStatus, MessageConfig -from ...teammanager import TeamManager -from autogen_core.base import CancellationToken +from ...datamodel import Message, MessageConfig, Run, RunStatus, Session, Team +from ..deps import get_db, get_team_manager, get_websocket_manager router = APIRouter() @@ -23,54 +21,45 @@ async def create_run( request: CreateRunRequest, db=Depends(get_db), ) -> Dict: - """Create a new run""" + """Create a new run with initial state""" session_response = db.get( - Session, - filters={"id": request.session_id, "user_id": request.user_id}, - return_json=False + Session, filters={"id": request.session_id, "user_id": request.user_id}, return_json=False ) if not session_response.status or not session_response.data: raise HTTPException(status_code=404, detail="Session not found") try: - - run = db.upsert(Run(session_id=request.session_id), return_json=False) - return { - "status": run.status, - "data": {"run_id": str(run.data.id)} - } - - # } + # Create run with default state + run = db.upsert( + Run( + session_id=request.session_id, + status=RunStatus.CREATED, + task=None, # Will be set when run starts + team_result=None, + ), + return_json=False, + ) + return {"status": run.status, "data": {"run_id": str(run.data.id)}} except Exception as e: - raise HTTPException(status_code=500, detail=str(e)) + raise HTTPException(status_code=500, detail=str(e)) from e -@router.post("/{run_id}/start") -async def start_run( - run_id: UUID, - message: Message = Body(...), - ws_manager=Depends(get_websocket_manager), - team_manager=Depends(get_team_manager), - db=Depends(get_db), -) -> Dict: - """Start streaming task execution""" +# We might want to add these endpoints: - if isinstance(message.config, dict): - message.config = MessageConfig(**message.config) - session = db.get(Session, filters={ - "id": message.session_id}, return_json=False) +@router.get("/{run_id}") +async def get_run(run_id: UUID, db=Depends(get_db)) -> Dict: + """Get run details including task and result""" + run = db.get(Run, filters={"id": run_id}, return_json=False) + if not run.status or not run.data: + raise HTTPException(status_code=404, detail="Run not found") - team = db.get( - Team, filters={"id": session.data[0].team_id}, return_json=False) + return {"status": True, "data": run.data[0]} - try: - await ws_manager.start_stream(run_id, team_manager, message.config.content, team.data[0].config) - return { - "status": True, - "message": "Stream started successfully", - "data": {"run_id": str(run_id)} - } - except Exception as e: - raise HTTPException(status_code=500, detail=str(e)) +@router.get("/{run_id}/messages") +async def get_run_messages(run_id: UUID, db=Depends(get_db)) -> Dict: + """Get all messages for a run""" + messages = db.get(Message, filters={"run_id": run_id}, order="created_at asc", return_json=False) + + return {"status": True, "data": messages.data} diff --git a/python/packages/autogen-studio/autogenstudio/web/routes/sessions.py b/python/packages/autogen-studio/autogenstudio/web/routes/sessions.py index f74ee6288154..4ca31e4f7049 100644 --- a/python/packages/autogen-studio/autogenstudio/web/routes/sessions.py +++ b/python/packages/autogen-studio/autogenstudio/web/routes/sessions.py @@ -1,72 +1,45 @@ # api/routes/sessions.py -from fastapi import APIRouter, Depends, HTTPException from typing import Dict + +from fastapi import APIRouter, Depends, HTTPException +from loguru import logger + +from ...datamodel import Message, Run, Session from ..deps import get_db -from ...datamodel import Session, Message router = APIRouter() @router.get("/") -async def list_sessions( - user_id: str, - db=Depends(get_db) -) -> Dict: +async def list_sessions(user_id: str, db=Depends(get_db)) -> Dict: """List all sessions for a user""" response = db.get(Session, filters={"user_id": user_id}) - return { - "status": True, - "data": response.data - } + return {"status": True, "data": response.data} @router.get("/{session_id}") -async def get_session( - session_id: int, - user_id: str, - db=Depends(get_db) -) -> Dict: +async def get_session(session_id: int, user_id: str, db=Depends(get_db)) -> Dict: """Get a specific session""" - response = db.get( - Session, - filters={"id": session_id, "user_id": user_id} - ) + response = db.get(Session, filters={"id": session_id, "user_id": user_id}) if not response.status or not response.data: raise HTTPException(status_code=404, detail="Session not found") - return { - "status": True, - "data": response.data[0] - } + return {"status": True, "data": response.data[0]} @router.post("/") -async def create_session( - session: Session, - db=Depends(get_db) -) -> Dict: +async def create_session(session: Session, db=Depends(get_db)) -> Dict: """Create a new session""" response = db.upsert(session) if not response.status: raise HTTPException(status_code=400, detail=response.message) - return { - "status": True, - "data": response.data - } + return {"status": True, "data": response.data} @router.put("/{session_id}") -async def update_session( - session_id: int, - user_id: str, - session: Session, - db=Depends(get_db) -) -> Dict: +async def update_session(session_id: int, user_id: str, session: Session, db=Depends(get_db)) -> Dict: """Update an existing session""" # First verify the session belongs to user - existing = db.get( - Session, - filters={"id": session_id, "user_id": user_id} - ) + existing = db.get(Session, filters={"id": session_id, "user_id": user_id}) if not existing.status or not existing.data: raise HTTPException(status_code=404, detail="Session not found") @@ -75,40 +48,74 @@ async def update_session( if not response.status: raise HTTPException(status_code=400, detail=response.message) - return { - "status": True, - "data": response.data, - "message": "Session updated successfully" - } + return {"status": True, "data": response.data, "message": "Session updated successfully"} @router.delete("/{session_id}") -async def delete_session( - session_id: int, - user_id: str, - db=Depends(get_db) -) -> Dict: +async def delete_session(session_id: int, user_id: str, db=Depends(get_db)) -> Dict: """Delete a session""" - response = db.delete( - filters={"id": session_id, "user_id": user_id}, - model_class=Session - ) - return { - "status": True, - "message": "Session deleted successfully" - } - - -@router.get("/{session_id}/messages") -async def list_messages( - session_id: int, - user_id: str, - db=Depends(get_db) -) -> Dict: - """List all messages for a session""" - filters = {"session_id": session_id, "user_id": user_id} - response = db.get(Message, filters=filters, order="asc") - return { - "status": True, - "data": response.data - } + db.delete(filters={"id": session_id, "user_id": user_id}, model_class=Session) + return {"status": True, "message": "Session deleted successfully"} + + +@router.get("/{session_id}/runs") +async def list_session_runs(session_id: int, user_id: str, db=Depends(get_db)) -> Dict: + """Get complete session history organized by runs""" + + try: + # 1. Verify session exists and belongs to user + session = db.get(Session, filters={"id": session_id, "user_id": user_id}, return_json=False) + if not session.status: + raise HTTPException(status_code=500, detail="Database error while fetching session") + if not session.data: + raise HTTPException(status_code=404, detail="Session not found or access denied") + + # 2. Get ordered runs for session + runs = db.get(Run, filters={"session_id": session_id}, order="asc", return_json=False) + if not runs.status: + raise HTTPException(status_code=500, detail="Database error while fetching runs") + + # 3. Build response with messages per run + run_data = [] + if runs.data: # It's ok to have no runs + for run in runs.data: + try: + # Get messages for this specific run + messages = db.get(Message, filters={"run_id": run.id}, order="asc", return_json=False) + if not messages.status: + logger.error(f"Failed to fetch messages for run {run.id}") + # Continue processing other runs even if one fails + messages.data = [] + + run_data.append( + { + "id": str(run.id), + "created_at": run.created_at, + "status": run.status, + "task": run.task, + "team_result": run.team_result, + "messages": messages.data or [], + } + ) + except Exception as e: + logger.error(f"Error processing run {run.id}: {str(e)}") + # Include run with error state instead of failing entirely + run_data.append( + { + "id": str(run.id), + "created_at": run.created_at, + "status": "ERROR", + "task": run.task, + "team_result": None, + "messages": [], + "error": f"Failed to process run: {str(e)}", + } + ) + + return {"status": True, "data": {"runs": run_data}} + + except HTTPException: + raise # Re-raise HTTP exceptions + except Exception as e: + logger.error(f"Unexpected error in list_messages: {str(e)}") + raise HTTPException(status_code=500, detail="Internal server error while fetching session data") from e diff --git a/python/packages/autogen-studio/autogenstudio/web/routes/teams.py b/python/packages/autogen-studio/autogenstudio/web/routes/teams.py index 854c195d3c71..50b9273c8a29 100644 --- a/python/packages/autogen-studio/autogenstudio/web/routes/teams.py +++ b/python/packages/autogen-studio/autogenstudio/web/routes/teams.py @@ -1,146 +1,41 @@ # api/routes/teams.py -from fastapi import APIRouter, Depends, HTTPException from typing import Dict -from ..deps import get_db + +from fastapi import APIRouter, Depends, HTTPException + from ...datamodel import Team +from ..deps import get_db router = APIRouter() @router.get("/") -async def list_teams( - user_id: str, - db=Depends(get_db) -) -> Dict: +async def list_teams(user_id: str, db=Depends(get_db)) -> Dict: """List all teams for a user""" response = db.get(Team, filters={"user_id": user_id}) - return { - "status": True, - "data": response.data - } + return {"status": True, "data": response.data} @router.get("/{team_id}") -async def get_team( - team_id: int, - user_id: str, - db=Depends(get_db) -) -> Dict: +async def get_team(team_id: int, user_id: str, db=Depends(get_db)) -> Dict: """Get a specific team""" - response = db.get( - Team, - filters={"id": team_id, "user_id": user_id} - ) + response = db.get(Team, filters={"id": team_id, "user_id": user_id}) if not response.status or not response.data: raise HTTPException(status_code=404, detail="Team not found") - return { - "status": True, - "data": response.data[0] - } + return {"status": True, "data": response.data[0]} @router.post("/") -async def create_team( - team: Team, - db=Depends(get_db) -) -> Dict: +async def create_team(team: Team, db=Depends(get_db)) -> Dict: """Create a new team""" response = db.upsert(team) if not response.status: raise HTTPException(status_code=400, detail=response.message) - return { - "status": True, - "data": response.data - } + return {"status": True, "data": response.data} @router.delete("/{team_id}") -async def delete_team( - team_id: int, - user_id: str, - db=Depends(get_db) -) -> Dict: +async def delete_team(team_id: int, user_id: str, db=Depends(get_db)) -> Dict: """Delete a team""" - response = db.delete( - filters={"id": team_id, "user_id": user_id}, - model_class=Team - ) - return { - "status": True, - "message": "Team deleted successfully" - } - -# Team-Agent link endpoints - - -@router.post("/{team_id}/agents/{agent_id}") -async def link_team_agent( - team_id: int, - agent_id: int, - db=Depends(get_db) -) -> Dict: - """Link an agent to a team""" - response = db.link( - link_type="team_agent", - primary_id=team_id, - secondary_id=agent_id - ) - return { - "status": True, - "message": "Agent linked to team successfully" - } - - -@router.post("/{team_id}/agents/{agent_id}/{sequence_id}") -async def link_team_agent_sequence( - team_id: int, - agent_id: int, - sequence_id: int, - db=Depends(get_db) -) -> Dict: - """Link an agent to a team with sequence""" - response = db.link( - link_type="team_agent", - primary_id=team_id, - secondary_id=agent_id, - sequence_id=sequence_id - ) - return { - "status": True, - "message": "Agent linked to team with sequence successfully" - } - - -@router.delete("/{team_id}/agents/{agent_id}") -async def unlink_team_agent( - team_id: int, - agent_id: int, - db=Depends(get_db) -) -> Dict: - """Unlink an agent from a team""" - response = db.unlink( - link_type="team_agent", - primary_id=team_id, - secondary_id=agent_id - ) - return { - "status": True, - "message": "Agent unlinked from team successfully" - } - - -@router.get("/{team_id}/agents") -async def get_team_agents( - team_id: int, - db=Depends(get_db) -) -> Dict: - """Get all agents linked to a team""" - response = db.get_linked_entities( - link_type="team_agent", - primary_id=team_id, - return_json=True - ) - return { - "status": True, - "data": response.data - } + db.delete(filters={"id": team_id, "user_id": user_id}, model_class=Team) + return {"status": True, "message": "Team deleted successfully"} diff --git a/python/packages/autogen-studio/autogenstudio/web/routes/tools.py b/python/packages/autogen-studio/autogenstudio/web/routes/tools.py index d73b626038ad..da2ae7733b2b 100644 --- a/python/packages/autogen-studio/autogenstudio/web/routes/tools.py +++ b/python/packages/autogen-studio/autogenstudio/web/routes/tools.py @@ -1,103 +1,41 @@ # api/routes/tools.py -from fastapi import APIRouter, Depends, HTTPException from typing import Dict -from ..deps import get_db + +from fastapi import APIRouter, Depends, HTTPException + from ...datamodel import Tool +from ..deps import get_db router = APIRouter() @router.get("/") -async def list_tools( - user_id: str, - db=Depends(get_db) -) -> Dict: +async def list_tools(user_id: str, db=Depends(get_db)) -> Dict: """List all tools for a user""" response = db.get(Tool, filters={"user_id": user_id}) - return { - "status": True, - "data": response.data - } + return {"status": True, "data": response.data} @router.get("/{tool_id}") -async def get_tool( - tool_id: int, - user_id: str, - db=Depends(get_db) -) -> Dict: +async def get_tool(tool_id: int, user_id: str, db=Depends(get_db)) -> Dict: """Get a specific tool""" - response = db.get( - Tool, - filters={"id": tool_id, "user_id": user_id} - ) + response = db.get(Tool, filters={"id": tool_id, "user_id": user_id}) if not response.status or not response.data: raise HTTPException(status_code=404, detail="Tool not found") - return { - "status": True, - "data": response.data[0] - } + return {"status": True, "data": response.data[0]} @router.post("/") -async def create_tool( - tool: Tool, - db=Depends(get_db) -) -> Dict: +async def create_tool(tool: Tool, db=Depends(get_db)) -> Dict: """Create a new tool""" response = db.upsert(tool) if not response.status: raise HTTPException(status_code=400, detail=response.message) - return { - "status": True, - "data": response.data - } + return {"status": True, "data": response.data} @router.delete("/{tool_id}") -async def delete_tool( - tool_id: int, - user_id: str, - db=Depends(get_db) -) -> Dict: +async def delete_tool(tool_id: int, user_id: str, db=Depends(get_db)) -> Dict: """Delete a tool""" - response = db.delete( - filters={"id": tool_id, "user_id": user_id}, - model_class=Tool - ) - return { - "status": True, - "message": "Tool deleted successfully" - } - - -@router.post("/{tool_id}/test") -async def test_tool( - tool_id: int, - user_id: str, - db=Depends(get_db) -) -> Dict: - """Test a tool configuration""" - # Get tool - tool_response = db.get( - Tool, - filters={"id": tool_id, "user_id": user_id} - ) - if not tool_response.status or not tool_response.data: - raise HTTPException(status_code=404, detail="Tool not found") - - tool = tool_response.data[0] - - try: - # Implement tool testing logic here - # This would depend on the tool type and configuration - return { - "status": True, - "message": "Tool tested successfully", - "data": {"tool_id": tool_id} - } - except Exception as e: - raise HTTPException( - status_code=500, - detail=f"Error testing tool: {str(e)}" - ) + db.delete(filters={"id": tool_id, "user_id": user_id}, model_class=Tool) + return {"status": True, "message": "Tool deleted successfully"} diff --git a/python/packages/autogen-studio/autogenstudio/web/routes/ws.py b/python/packages/autogen-studio/autogenstudio/web/routes/ws.py index 75152036fc29..c7c45175a315 100644 --- a/python/packages/autogen-studio/autogenstudio/web/routes/ws.py +++ b/python/packages/autogen-studio/autogenstudio/web/routes/ws.py @@ -1,17 +1,17 @@ # api/ws.py -from fastapi import APIRouter, WebSocket, WebSocketDisconnect, Depends, HTTPException -from typing import Dict -from uuid import UUID -import logging +import asyncio import json from datetime import datetime +from uuid import UUID + +from fastapi import APIRouter, Depends, WebSocket, WebSocketDisconnect +from loguru import logger -from ..deps import get_websocket_manager, get_db, get_team_manager from ...datamodel import Run, RunStatus +from ..deps import get_db, get_websocket_manager from ..managers import WebSocketManager router = APIRouter() -logger = logging.getLogger(__name__) @router.websocket("/runs/{run_id}") @@ -20,12 +20,12 @@ async def run_websocket( run_id: UUID, ws_manager: WebSocketManager = Depends(get_websocket_manager), db=Depends(get_db), - team_manager=Depends(get_team_manager) ): """WebSocket endpoint for run communication""" # Verify run exists and is in valid state run_response = db.get(Run, filters={"id": run_id}, return_json=False) if not run_response.status or not run_response.data: + logger.warning(f"Run not found: {run_id}") await websocket.close(code=4004, reason="Run not found") return @@ -48,18 +48,32 @@ async def run_websocket( raw_message = await websocket.receive_text() message = json.loads(raw_message) - if message.get("type") == "stop": - print(f"Received stop request for run {run_id}") - reason = message.get( - "reason") or "User requested stop/cancellation" + if message.get("type") == "start": + # Handle start message + logger.info(f"Received start request for run {run_id}") + task = message.get("task") + team_config = message.get("team_config") + if task and team_config: + # await ws_manager.start_stream(run_id, task, team_config) + asyncio.create_task(ws_manager.start_stream(run_id, task, team_config)) + else: + logger.warning(f"Invalid start message format for run {run_id}") + await websocket.send_json( + { + "type": "error", + "error": "Invalid start message format", + "timestamp": datetime.utcnow().isoformat(), + } + ) + + elif message.get("type") == "stop": + logger.info(f"Received stop request for run {run_id}") + reason = message.get("reason") or "User requested stop/cancellation" await ws_manager.stop_run(run_id, reason=reason) break elif message.get("type") == "ping": - await websocket.send_json({ - "type": "pong", - "timestamp": datetime.utcnow().isoformat() - }) + await websocket.send_json({"type": "pong", "timestamp": datetime.utcnow().isoformat()}) elif message.get("type") == "input_response": # Handle input response from client @@ -67,16 +81,13 @@ async def run_websocket( 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}") + logger.warning(f"Invalid input response format for run {run_id}") except json.JSONDecodeError: logger.warning(f"Invalid JSON received: {raw_message}") - await websocket.send_json({ - "type": "error", - "error": "Invalid message format", - "timestamp": datetime.utcnow().isoformat() - }) + await websocket.send_json( + {"type": "error", "error": "Invalid message format", "timestamp": datetime.utcnow().isoformat()} + ) except WebSocketDisconnect: logger.info(f"WebSocket disconnected for run {run_id}") diff --git a/python/packages/autogen-studio/frontend/package.json b/python/packages/autogen-studio/frontend/package.json index f205a7a1e44d..822c0696531f 100644 --- a/python/packages/autogen-studio/frontend/package.json +++ b/python/packages/autogen-studio/frontend/package.json @@ -17,8 +17,6 @@ "typecheck": "tsc --noEmit" }, "dependencies": { - "@ant-design/charts": "^2.2.3", - "@ant-design/plots": "^2.2.2", "@dagrejs/dagre": "^1.1.4", "@headlessui/react": "^2.2.0", "@heroicons/react": "^2.0.18", @@ -38,7 +36,7 @@ "gatsby-source-filesystem": "^5.14.0", "gatsby-transformer-sharp": "^5.14.0", "install": "^0.13.0", - "lucide-react": "^0.456.0", + "lucide-react": "^0.460.0", "postcss": "^8.4.49", "react": "^18.2.0", "react-dom": "^18.2.0", diff --git a/python/packages/autogen-studio/frontend/src/components/types/datamodel.ts b/python/packages/autogen-studio/frontend/src/components/types/datamodel.ts index 4cb20e37d792..bec226028e10 100644 --- a/python/packages/autogen-studio/frontend/src/components/types/datamodel.ts +++ b/python/packages/autogen-studio/frontend/src/components/types/datamodel.ts @@ -105,22 +105,15 @@ export type ThreadStatus = | "timeout"; export interface WebSocketMessage { - type: "message" | "result" | "completion" | "input_request"; - data?: { - source?: string; - models_usage?: RequestUsage | null; - content?: string; - task_result?: TaskResult; - }; - status?: ThreadStatus; + type: "message" | "result" | "completion" | "input_request" | "error"; + data?: AgentMessageConfig | TaskResult; + status?: RunStatus; error?: string; timestamp?: string; } export interface TaskResult { messages: AgentMessageConfig[]; - usage: string; - duration: number; stop_reason?: string; } @@ -187,3 +180,36 @@ export interface TeamConfig extends BaseConfig { export interface Team extends DBModel { config: TeamConfig; } + +export interface TeamResult { + task_result: TaskResult; + usage: string; + duration: number; +} + +export interface Run { + id: string; + created_at: string; + status: RunStatus; + task: AgentMessageConfig; + team_result: TeamResult | null; + messages: Message[]; // Change to Message[] + error_message?: string; +} + +// Separate transient state +interface TransientRunState { + pendingInput?: { + prompt: string; + isPending: boolean; + }; +} + +export type RunStatus = + | "created" + | "active" // covers 'streaming' + | "awaiting_input" + | "timeout" + | "complete" + | "error" + | "stopped"; diff --git a/python/packages/autogen-studio/frontend/src/components/views/playground/chat/agentflow/agentflow.tsx b/python/packages/autogen-studio/frontend/src/components/views/playground/chat/agentflow/agentflow.tsx index 142af966f780..c076223ed473 100644 --- a/python/packages/autogen-studio/frontend/src/components/views/playground/chat/agentflow/agentflow.tsx +++ b/python/packages/autogen-studio/frontend/src/components/views/playground/chat/agentflow/agentflow.tsx @@ -10,7 +10,6 @@ import { Node, Edge, Background, - Controls, NodeTypes, useReactFlow, ReactFlowProvider, @@ -24,16 +23,16 @@ import { AgentMessageConfig, AgentConfig, TeamConfig, + Run, } from "../../../../types/datamodel"; -import { ThreadState } from "../types"; -import { CustomEdge } from "./edge"; +import { CustomEdge, CustomEdgeData } from "./edge"; import { useConfigStore } from "../../../../../hooks/store"; import { AgentFlowToolbar } from "./toolbar"; +import { EdgeMessageModal } from "./edgemessagemodal"; interface AgentFlowProps { teamConfig: TeamConfig; - messages: AgentMessageConfig[]; - threadState: ThreadState; + run: Run; } interface MessageSequence { @@ -51,40 +50,37 @@ interface BidirectionalPattern { const NODE_DIMENSIONS = { default: { width: 170, height: 100 }, - end: { width: 120, height: 80 }, + end: { width: 170, height: 80 }, + task: { width: 170, height: 100 }, }; const getLayoutedElements = ( nodes: Node[], - edges: Edge[], + edges: CustomEdge[], direction: "TB" | "LR" ) => { const g = new Dagre.graphlib.Graph().setDefaultEdgeLabel(() => ({})); - // Updated graph settings g.setGraph({ rankdir: direction, - nodesep: 80, - ranksep: 120, - ranker: "tight-tree", + nodesep: 110, + ranksep: 100, + ranker: "network-simplex", marginx: 30, marginy: 30, }); - // Add nodes (unchanged) nodes.forEach((node) => { const dimensions = node.data.type === "end" ? NODE_DIMENSIONS.end : NODE_DIMENSIONS.default; 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}`; @@ -99,33 +95,19 @@ const getLayoutedElements = ( }); }); - // 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, - }); + 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, - }); + g.setEdge(edge.source, edge.target, { weight: 1, minlen: 1 }); } }); - // Run layout Dagre.layout(g); - // Position nodes const positionedNodes = nodes.map((node) => { const { x, y } = g.node(node.id); const dimensions = @@ -139,7 +121,6 @@ const getLayoutedElements = ( }; }); - // Create a map of node positions for edge calculations const nodePositions = new Map( positionedNodes.map((node) => [ node.id, @@ -150,7 +131,6 @@ const getLayoutedElements = ( ]) ); - // Process edges with positions const positionedEdges = edges.map((edge) => { const sourcePos = nodePositions.get(edge.source)!; const targetPos = nodePositions.get(edge.target)!; @@ -164,10 +144,7 @@ const getLayoutedElements = ( }; }); - return { - nodes: positionedNodes, - edges: positionedEdges, - }; + return { nodes: positionedNodes, edges: positionedEdges }; }; const createNode = ( @@ -175,11 +152,11 @@ const createNode = ( type: "user" | "agent" | "end", agentConfig?: AgentConfig, isActive: boolean = false, - threadState?: ThreadState + run?: Run ): Node => { - const isStreamingOrWaiting = - threadState?.status === "streaming" || - threadState?.status === "awaiting_input"; + const isProcessing = + run?.status === "active" || run?.status === "awaiting_input"; + if (type === "user") { return { id, @@ -193,7 +170,7 @@ const createNode = ( isActive, status: "", reason: "", - draggable: !isStreamingOrWaiting, + draggable: !isProcessing, }, }; } @@ -206,8 +183,8 @@ const createNode = ( data: { type: "end", label: "End", - status: threadState?.status, - reason: threadState?.reason || "", + status: run?.status, + reason: run?.error_message || "", agentType: "", description: "", isActive: false, @@ -216,6 +193,23 @@ const createNode = ( }; } + // if (type === "task") { + // return { + // id, + // type: "agentNode", + // position: { x: 0, y: 0 }, + // data: { + // type: "task", + // label: "Task", + // description: run?.task.content || "", + // isActive: false, + // status: null, + // reason: null, + // draggable: false, + // }, + // }; + // } + return { id, type: "agentNode", @@ -228,7 +222,7 @@ const createNode = ( isActive, status: "", reason: "", - draggable: !isStreamingOrWaiting, + draggable: !isProcessing, }, }; }; @@ -241,23 +235,28 @@ const edgeTypes = { custom: CustomEdge, }; -const AgentFlow: React.FC = ({ - teamConfig, - messages, - threadState, -}) => { +const AgentFlow: React.FC = ({ teamConfig, run }) => { const { fitView } = useReactFlow(); const [nodes, setNodes] = useState([]); - const [edges, setEdges] = useState([]); + const [edges, setEdges] = useState([]); const [shouldRefit, setShouldRefit] = useState(false); const [isFullscreen, setIsFullscreen] = useState(false); - // Get settings from store - const { agentFlow: settings, setAgentFlowSettings } = useConfigStore(); + const { agentFlow: settings } = useConfigStore(); + const [modalOpen, setModalOpen] = useState(false); + const [selectedEdge, setSelectedEdge] = useState(null); + + const handleEdgeClick = useCallback((edge: CustomEdge) => { + if (!edge.data?.messages) return; // Early return if no data/messages + + setSelectedEdge(edge); + setModalOpen(true); + }, []); const onNodesChange = useCallback((changes: NodeChange[]) => { setNodes((nds) => applyNodeChanges(changes, nds)); }, []); + const flowWrapper = useRef(null); useEffect(() => { @@ -265,36 +264,38 @@ const AgentFlow: React.FC = ({ const timeoutId = setTimeout(() => { fitView({ padding: 0.2, duration: 200 }); setShouldRefit(false); - }, 100); // Increased delay slightly + }, 100); return () => clearTimeout(timeoutId); } }, [shouldRefit, fitView]); - // Process messages into nodes and edges const processMessages = useCallback( (messages: AgentMessageConfig[]) => { - if (messages.length === 0) return { nodes: [], edges: [] }; + if (!run.task) return { nodes: [], edges: [] }; const nodeMap = new Map(); const transitionCounts = new Map(); const bidirectionalPatterns = new Map(); - // Process first message source - const firstAgentConfig = teamConfig.participants.find( - (p) => p.name === messages[0].source - ); - nodeMap.set( - messages[0].source, - createNode( + // Add first message node if it exists + if (messages.length > 0) { + const firstAgentConfig = teamConfig.participants.find( + (p) => p.name === messages[0].source + ); + nodeMap.set( messages[0].source, - messages[0].source === "user" ? "user" : "agent", - firstAgentConfig, - false - ) - ); + createNode( + messages[0].source, + messages[0].source === "user" ? "user" : "agent", + firstAgentConfig, + false, + run + ) + ); + } - // Group messages by transitions + // Process message transitions for (let i = 0; i < messages.length - 1; i++) { const currentMsg = messages[i]; const nextMsg = messages[i + 1]; @@ -319,7 +320,6 @@ const AgentFlow: React.FC = ({ transition.messages.push(currentMsg); } - // Ensure all nodes are in the nodeMap if (!nodeMap.has(nextMsg.source)) { const agentConfig = teamConfig.participants.find( (p) => p.name === nextMsg.source @@ -330,13 +330,14 @@ const AgentFlow: React.FC = ({ nextMsg.source, nextMsg.source === "user" ? "user" : "agent", agentConfig, - false + false, + run ) ); } } - // Identify bidirectional patterns + // Process bidirectional patterns transitionCounts.forEach((transition, key) => { const [source, target] = key.split("->"); const reverseKey = `${target}->${source}`; @@ -352,10 +353,9 @@ const AgentFlow: React.FC = ({ }); // Create edges with bidirectional routing - const newEdges: Edge[] = []; + const newEdges: CustomEdge[] = []; const processedKeys = new Set(); - // Helper function to create edge label based on settings const createEdgeLabel = (transition: MessageSequence) => { if (!settings.showLabels) return ""; if (transition.totalTokens > 0) { @@ -374,7 +374,6 @@ const AgentFlow: React.FC = ({ const bidirectionalPattern = bidirectionalPatterns.get(patternKey); if (bidirectionalPattern) { - // Create paired edges for bidirectional pattern const forwardKey = `${source}->${target}`; const reverseKey = `${target}->${source}`; @@ -386,7 +385,7 @@ const AgentFlow: React.FC = ({ isSecondary: boolean, edgeId: string, pairedEdgeId: string - ) => ({ + ): CustomEdge => ({ id: edgeId, source: transition.source, target: transition.target, @@ -421,7 +420,6 @@ const AgentFlow: React.FC = ({ processedKeys.add(forwardKey); processedKeys.add(reverseKey); } else { - // Handle regular edges (including self-loops) newEdges.push({ id: `${transition.source}-${transition.target}-${key}`, source: transition.source, @@ -432,7 +430,7 @@ const AgentFlow: React.FC = ({ messages: settings.showMessages ? transition.messages : [], }, animated: - threadState?.status === "streaming" && + run.status === "active" && key === Array.from(transitionCounts.keys()).pop(), style: { stroke: "#2563eb", @@ -442,25 +440,22 @@ const AgentFlow: React.FC = ({ } }); - // Handle end node logic - if (threadState && messages.length > 0) { + // Add end node if run is complete/error/stopped + if (run && messages.length > 0) { const lastMessage = messages[messages.length - 1]; - if (["complete", "error", "cancelled"].includes(threadState.status)) { - nodeMap.set( - "end", - createNode("end", "end", undefined, false, threadState) - ); + if (["complete", "error", "stopped"].includes(run.status)) { + nodeMap.set("end", createNode("end", "end", undefined, false, run)); - const edgeColor = - { - complete: "#2563eb", - cancelled: "red", - error: "red", - streaming: "#2563eb", - awaiting_input: "#2563eb", - timeout: "red", - }[threadState.status] || "#2563eb"; + const edgeColor = { + complete: "#2563eb", + stopped: "red", + error: "red", + active: "#2563eb", + awaiting_input: "#2563eb", + timeout: "red", + created: "#2563eb", + }[run.status]; newEdges.push({ id: `${lastMessage.source}-end`, @@ -481,12 +476,9 @@ const AgentFlow: React.FC = ({ } } - return { - nodes: Array.from(nodeMap.values()), - edges: newEdges, - }; + return { nodes: Array.from(nodeMap.values()), edges: newEdges }; }, - [teamConfig.participants, threadState, settings] + [teamConfig.participants, run, settings] ); const handleToggleFullscreen = useCallback(() => { @@ -508,7 +500,9 @@ const AgentFlow: React.FC = ({ }, [isFullscreen, handleToggleFullscreen]); useEffect(() => { - const { nodes: newNodes, edges: newEdges } = processMessages(messages); + const { nodes: newNodes, edges: newEdges } = processMessages( + run.messages.map((m) => m.config) + ); const { nodes: layoutedNodes, edges: layoutedEdges } = getLayoutedElements( newNodes, newEdges, @@ -518,17 +512,22 @@ const AgentFlow: React.FC = ({ setNodes(layoutedNodes); setEdges(layoutedEdges); - if (messages.length > 0) { + if (run.messages.length > 0) { setTimeout(() => { fitView({ padding: 0.2, duration: 200 }); }, 50); } - }, [messages, processMessages, settings.direction, threadState, fitView]); + }, [run.messages, processMessages, settings.direction, run.status, fitView]); - // Define common ReactFlow props const reactFlowProps = { nodes, - edges, + edges: edges.map((edge) => ({ + ...edge, + data: { + ...edge.data, + onClick: () => handleEdgeClick(edge), + }, + })), nodeTypes, edgeTypes, defaultViewport: { x: 0, y: 0, zoom: 1 }, @@ -538,7 +537,6 @@ const AgentFlow: React.FC = ({ proOptions: { hideAttribution: true }, }; - // Define common toolbar props const toolbarProps = useMemo( () => ({ isFullscreen, @@ -547,16 +545,16 @@ const AgentFlow: React.FC = ({ }), [isFullscreen, handleToggleFullscreen, fitView] ); + return (
- {/* Backdrop when fullscreen */} {isFullscreen && (
= ({ {settings.showGrid && } - {/* */}
+ { + setModalOpen(false); + setSelectedEdge(null); + }} + edge={selectedEdge} + />
); }; diff --git a/python/packages/autogen-studio/frontend/src/components/views/playground/chat/agentflow/agentnode.tsx b/python/packages/autogen-studio/frontend/src/components/views/playground/chat/agentflow/agentnode.tsx index 5f9215a38cad..e9a66fd5b9ba 100644 --- a/python/packages/autogen-studio/frontend/src/components/views/playground/chat/agentflow/agentnode.tsx +++ b/python/packages/autogen-studio/frontend/src/components/views/playground/chat/agentflow/agentnode.tsx @@ -66,7 +66,7 @@ function AgentNode({ data, isConnectable }: AgentNodeProps) { if (data.type === "end") { return { - wrapper: `relative min-w-[120px] shadow rounded-lg overflow-hidden ${activeStyles}`, + wrapper: `relative min-w-[180px] shadow rounded-lg overflow-hidden ${activeStyles}`, border: data.status === "complete" ? "var(--accent)" @@ -77,7 +77,7 @@ function AgentNode({ data, isConnectable }: AgentNodeProps) { } return { - wrapper: `min-w-[150px] rounded-lg shadow overflow-hidden ${activeStyles}`, + wrapper: `min-w-[180px] rounded-lg shadow overflow-hidden ${activeStyles}`, border: undefined, }; }; diff --git a/python/packages/autogen-studio/frontend/src/components/views/playground/chat/agentflow/edge.tsx b/python/packages/autogen-studio/frontend/src/components/views/playground/chat/agentflow/edge.tsx index 67d82b1ca8e3..17446552b13b 100644 --- a/python/packages/autogen-studio/frontend/src/components/views/playground/chat/agentflow/edge.tsx +++ b/python/packages/autogen-studio/frontend/src/components/views/playground/chat/agentflow/edge.tsx @@ -1,38 +1,23 @@ import React from "react"; -import { Tooltip } from "antd"; import { AgentMessageConfig } from "../../../../types/datamodel"; import { + Edge, EdgeLabelRenderer, type EdgeProps, getSmoothStepPath, } from "@xyflow/react"; -import { RenderMessage } from "../rendermessage"; -interface EdgeTooltipContentProps { - messages: AgentMessageConfig[]; -} +const EDGE_OFFSET = 140; -interface CustomEdgeData { +export interface CustomEdgeData extends Record { label?: string; messages: AgentMessageConfig[]; routingType?: "primary" | "secondary"; bidirectionalPair?: string; + onClick?: () => void; } -const EdgeTooltipContent: React.FC = ({ - messages, -}) => { - return ( -
-
{messages.length} messages
-
- {messages.map((message, index) => ( - - ))} -
-
- ); -}; +export type CustomEdge = Edge; interface CustomEdgeProps extends Omit { data: CustomEdgeData; @@ -63,27 +48,24 @@ export const CustomEdge: React.FC = ({ let labelX = 0; let labelY = 0; - if (isSelfLoop) { - const rightOffset = 120; - const verticalOffset = sourceY - targetY; - const verticalPadding = 6; - const radius = 8; + if (data.routingType === "secondary" || isSelfLoop) { + // Calculate the midpoint and offset + const midY = (sourceY + targetY) / 2; + const offset = EDGE_OFFSET; + // Create path that goes out from output, right, up, left, into input edgePath = ` - M ${sourceX} ${targetY - verticalPadding} - L ${sourceX + rightOffset - radius} ${targetY - verticalPadding} - Q ${sourceX + rightOffset} ${targetY - verticalPadding} ${ - sourceX + rightOffset - } ${targetY - verticalPadding + radius} - L ${sourceX + rightOffset} ${sourceY + verticalPadding - radius} - Q ${sourceX + rightOffset} ${sourceY + verticalPadding} ${ - sourceX + rightOffset - radius - } ${sourceY + verticalPadding} - L ${sourceX} ${sourceY + verticalPadding} + M ${sourceX},${sourceY} + L ${sourceX},${sourceY + 10} + L ${sourceX + offset},${sourceY + 10} + L ${sourceX + offset},${targetY - 10} + L ${targetX},${targetY - 10} + L ${targetX},${targetY} `; - labelX = sourceX + rightOffset + 10; - labelY = targetY + verticalOffset / 2; + // Set label position + labelX = sourceX + offset; + labelY = midY; } else { [edgePath, labelX, labelY] = getSmoothStepPath({ sourceX, @@ -98,7 +80,7 @@ export const CustomEdge: React.FC = ({ 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 verticalOffset = data.routingType === "secondary" ? -35 : 35; const horizontalOffset = data.routingType === "secondary" ? -25 : 25; // Calculate edge angle to determine if it's more horizontal or vertical @@ -109,7 +91,7 @@ export const CustomEdge: React.FC = ({ // Always apply some vertical offset const basePosition = { x: isMoreHorizontal ? x : x + horizontalOffset, - y: y + (data.routingType === "secondary" ? -35 : 35), // Always apply vertical offset + y: y + (data.routingType === "secondary" ? -20 : 20), }; return basePosition; @@ -137,29 +119,23 @@ export const CustomEdge: React.FC = ({ position: "absolute", transform: `translate(-50%, -50%) translate(${labelPosition.x}px,${labelPosition.y}px)`, pointerEvents: "all", - // Add a slight transition for smooth updates - transition: "transform 0.2s ease-in-out", + transition: "all 0.2s ease-in-out", }} + onClick={data.onClick} > - 0 ? ( - - ) : ( - data?.label - ) - } - overlayStyle={{ maxWidth: "none" }} +
-
- {data.label} -
- + {messageCount > 0 && ( + ({messageCount}) + )} + {data.label} +
)} diff --git a/python/packages/autogen-studio/frontend/src/components/views/playground/chat/agentflow/edgemessagemodal.tsx b/python/packages/autogen-studio/frontend/src/components/views/playground/chat/agentflow/edgemessagemodal.tsx new file mode 100644 index 000000000000..0c5d2443f27a --- /dev/null +++ b/python/packages/autogen-studio/frontend/src/components/views/playground/chat/agentflow/edgemessagemodal.tsx @@ -0,0 +1,103 @@ +// edgemessagemodal.tsx +import React, { useState, useMemo } from "react"; +import { Modal, Input } from "antd"; +import { RenderMessage } from "../rendermessage"; +import { CustomEdge } from "./edge"; + +const { Search } = Input; + +interface EdgeMessageModalProps { + open: boolean; + onClose: () => void; + edge: CustomEdge | null; +} + +export const EdgeMessageModal: React.FC = ({ + open, + onClose, + edge, +}) => { + const [searchTerm, setSearchTerm] = useState(""); + + const totalTokens = useMemo(() => { + if (!edge?.data?.messages) return 0; + return edge.data.messages.reduce((acc, msg) => { + const promptTokens = msg.models_usage?.prompt_tokens || 0; + const completionTokens = msg.models_usage?.completion_tokens || 0; + return acc + promptTokens + completionTokens; + }, 0); + }, [edge?.data?.messages]); + + const filteredMessages = useMemo(() => { + if (!edge?.data?.messages) return []; + if (!searchTerm) return edge.data.messages; + + return edge.data.messages.filter( + (msg) => + typeof msg.content === "string" && + msg.content.toLowerCase().includes(searchTerm.toLowerCase()) + ); + }, [edge?.data?.messages, searchTerm]); + + if (!edge) return null; + + return ( + +
+ {edge.source} → {edge.target} +
+
+ {edge.data && ( + + {edge.data.messages.length} message + {`${edge.data.messages.length > 1 ? "s" : ""}`} + + )} + {totalTokens.toLocaleString()} tokens +
+ {edge.data && edge.data.messages.length > 0 && ( +
+ {" "} + The above represents the number of times the {`${edge.target}`}{" "} + node sent a message{" "} + after{" "} + the {`${edge.source}`} node.{" "} +
+ )} + + } + open={open} + onCancel={onClose} + width={800} + footer={null} + > +
+ setSearchTerm(e.target.value)} + allowClear + className="sticky top-0 z-10" + /> + +
+ {filteredMessages.map((msg, idx) => ( + + ))} + + {filteredMessages.length === 0 && ( +
+ No messages found +
+ )} +
+
+
+ ); +}; diff --git a/python/packages/autogen-studio/frontend/src/components/views/playground/chat/chat.tsx b/python/packages/autogen-studio/frontend/src/components/views/playground/chat/chat.tsx index 473c90b4f98c..b78aa50dab30 100644 --- a/python/packages/autogen-studio/frontend/src/components/views/playground/chat/chat.tsx +++ b/python/packages/autogen-studio/frontend/src/components/views/playground/chat/chat.tsx @@ -4,200 +4,119 @@ import { getServerUrl } from "../../../utils"; import { SessionManager } from "../../shared/session/manager"; import { IStatus } from "../../../types/app"; import { + Run, Message, - ThreadStatus, WebSocketMessage, + TeamConfig, + AgentMessageConfig, + RunStatus, + TeamResult, } from "../../../types/datamodel"; import { useConfigStore } from "../../../../hooks/store"; import { appContext } from "../../../../hooks/provider"; import ChatInput from "./chatinput"; -import { ModelUsage, ThreadState, TIMEOUT_CONFIG } from "./types"; -import { MessageList } from "./messagelist"; import TeamManager from "../../shared/team/manager"; import { teamAPI } from "../../shared/team/api"; +import { sessionAPI } from "../../shared/session/api"; +import RunView from "./runview"; +import { TIMEOUT_CONFIG } from "./types"; const logo = require("../../../../images/landing/welcome.svg").default; -export default function ChatView({ - initMessages, -}: { - initMessages: Message[]; -}) { +export default function ChatView() { const serverUrl = getServerUrl(); const [loading, setLoading] = React.useState(false); const [error, setError] = React.useState({ status: true, message: "All good", }); - const [messages, setMessages] = React.useState(initMessages); - const [threadMessages, setThreadMessages] = React.useState< - Record - >({}); - const chatContainerRef = React.useRef(null); - const timeoutRefs = React.useRef>({}); + // Core state + const [existingRuns, setExistingRuns] = React.useState([]); + const [currentRun, setCurrentRun] = React.useState(null); + + const chatContainerRef = React.useRef(null); + + // Context and config const { user } = React.useContext(appContext); const { session, sessions } = useConfigStore(); - const [activeSockets, setActiveSockets] = React.useState< - Record - >({}); - const activeSocketsRef = React.useRef>({}); + const [activeSocket, setActiveSocket] = React.useState( + null + ); + const [teamConfig, setTeamConfig] = React.useState(null); + + const inputTimeoutRef = React.useRef(null); + const activeSocketRef = React.useRef(null); + + // Create a Message object from AgentMessageConfig + const createMessage = ( + config: AgentMessageConfig, + runId: string, + sessionId: number + ): Message => ({ + created_at: new Date().toISOString(), + updated_at: new Date().toISOString(), + config, + session_id: sessionId, + run_id: runId, + user_id: user?.email || undefined, + }); - const [teamConfig, setTeamConfig] = React.useState(null); + // Load existing runs when session changes + const loadSessionRuns = async () => { + if (!session?.id || !user?.email) return; + + try { + const response = await sessionAPI.getSessionRuns(session.id, user.email); + setExistingRuns(response.runs); + } catch (error) { + console.error("Error loading session runs:", error); + message.error("Failed to load chat history"); + } + }; React.useEffect(() => { - if (chatContainerRef.current) { - chatContainerRef.current.scrollTo({ - top: chatContainerRef.current.scrollHeight, - behavior: "smooth", - }); + if (session?.id) { + loadSessionRuns(); + } else { + setExistingRuns([]); + setCurrentRun(null); } - }, [messages, threadMessages]); + }, [session?.id]); + // Load team config React.useEffect(() => { - if (session && session.team_id && user && user.email) { - teamAPI.getTeam(session.team_id, user?.email).then((team) => { + if (session?.team_id && user?.email) { + teamAPI.getTeam(session.team_id, user.email).then((team) => { setTeamConfig(team.config); - // console.log("Team Config", team.config); }); } }, [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(() => { - return () => { - Object.values(activeSockets).forEach((socket) => socket.close()); - }; - }, [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", - }, - })); + setTimeout(() => { + if (chatContainerRef.current && existingRuns.length > 0) { + // Scroll to bottom to show latest run + chatContainerRef.current.scrollTo({ + top: chatContainerRef.current.scrollHeight, + behavior: "auto", // Use 'auto' instead of 'smooth' for initial load + }); } - } else { - message.error("Connection lost. Please try again."); - } - }; + }, 450); + }, [existingRuns.length, currentRun?.messages]); - const getBaseUrl = (url: string): string => { - try { - // Remove protocol (http:// or https://) - let baseUrl = url.replace(/(^\w+:|^)\/\//, ""); - - // Handle both localhost and production cases - if (baseUrl.startsWith("localhost")) { - // For localhost, keep the port if it exists - baseUrl = baseUrl.replace("/api", ""); - } else if (baseUrl === "/api") { - // For production where url is just '/api' - baseUrl = window.location.host; - } else { - // For other cases, remove '/api' and trailing slash - baseUrl = baseUrl.replace("/api", "").replace(/\/$/, ""); + // Cleanup socket on unmount + React.useEffect(() => { + return () => { + if (inputTimeoutRef.current) { + clearTimeout(inputTimeoutRef.current); } - - return baseUrl; - } catch (error) { - console.error("Error processing server URL:", error); - throw new Error("Invalid server URL configuration"); - } - }; + activeSocket?.close(); + }; + }, [activeSocket]); const createRun = async (sessionId: number): Promise => { const payload = { session_id: sessionId, user_id: user?.email || "" }; - const response = await fetch(`${serverUrl}/runs/`, { method: "POST", headers: { "Content-Type": "application/json" }, @@ -212,334 +131,343 @@ export default function ChatView({ return data.data.run_id; }; - const startRun = async (runId: string, query: string) => { - const messagePayload = { - user_id: user?.email, - session_id: session?.id, - config: { - content: query, - source: "user", - }, - }; + const handleWebSocketMessage = (message: WebSocketMessage) => { + setCurrentRun((current) => { + if (!current || !session?.id) return null; - const response = await fetch(`${serverUrl}/runs/${runId}/start`, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify(messagePayload), - }); + console.log("WebSocket message:", message); - if (!response.ok) { - throw new Error("Failed to start run"); - } + switch (message.type) { + case "error": + if (inputTimeoutRef.current) { + clearTimeout(inputTimeoutRef.current); + inputTimeoutRef.current = null; + } + if (activeSocket) { + activeSocket.close(); + setActiveSocket(null); + activeSocketRef.current = null; + } + console.log("Error: ", message.error); - return await response.json(); - }; + case "message": + if (!message.data) return current; - const connectWebSocket = (runId: string, query: string) => { - const baseUrl = getBaseUrl(serverUrl); - const wsProtocol = window.location.protocol === "https:" ? "wss:" : "ws:"; - const wsUrl = `${wsProtocol}//${baseUrl}/api/ws/runs/${runId}`; + // Create new Message object from websocket data + const newMessage = createMessage( + message.data as AgentMessageConfig, + current.id, + session.id + ); - const socket = new WebSocket(wsUrl); - let isClosing = false; + return { + ...current, + messages: [...current.messages, newMessage], + }; - const clearTimeoutForRun = () => { - if (timeoutRefs.current[runId]) { - clearTimeout(timeoutRefs.current[runId]); - delete timeoutRefs.current[runId]; - } - }; + case "input_request": + if (inputTimeoutRef.current) { + clearTimeout(inputTimeoutRef.current); + } - const closeSocket = () => { - if (!isClosing && socket.readyState !== WebSocket.CLOSED) { - isClosing = true; - socket.close(); - updateSocket(runId, null); - } - }; + inputTimeoutRef.current = setTimeout(() => { + const socket = activeSocketRef.current; + console.log("Input timeout", socket); + + if (socket?.readyState === WebSocket.OPEN) { + socket.send( + JSON.stringify({ + type: "stop", + reason: TIMEOUT_CONFIG.DEFAULT_MESSAGE, + code: TIMEOUT_CONFIG.WEBSOCKET_CODE, + }) + ); + setCurrentRun((prev) => + prev + ? { + ...prev, + status: "stopped", + error_message: TIMEOUT_CONFIG.DEFAULT_MESSAGE, + } + : null + ); + } + }, TIMEOUT_CONFIG.DURATION_MS); - socket.onopen = async () => { - try { - updateSocket(runId, socket); - - setThreadMessages((prev) => ({ - ...prev, - [runId]: { - messages: [], - status: "streaming", - isExpanded: true, - }, - })); - - setMessages((prev: Message[]) => - prev.map((msg: Message) => { - if (msg.run_id === runId && msg.config.source === "bot") { - return { - ...msg, - config: { - ...msg.config, - content: "Starting...", - }, - }; + return { + ...current, + status: "awaiting_input", + }; + case "result": + case "completion": + // When run completes, move it to existingRuns + const status: RunStatus = + message.status === "complete" + ? "complete" + : message.status === "error" + ? "error" + : "stopped"; + + const isTeamResult = (data: any): data is TeamResult => { + return ( + data && + "task_result" in data && + "usage" in data && + "duration" in data + ); + }; + + const updatedRun = { + ...current, + status, + team_result: + message.data && isTeamResult(message.data) ? message.data : null, + }; + + // Add to existing runs if complete + if (status === "complete") { + if (inputTimeoutRef.current) { + clearTimeout(inputTimeoutRef.current); + inputTimeoutRef.current = null; } - return msg; - }) - ); + if (activeSocket) { + activeSocket.close(); + setActiveSocket(null); + activeSocketRef.current = null; + } + setExistingRuns((prev) => [...prev, updatedRun]); + return null; + } - await startRun(runId, query); - } catch (error) { - closeSocket(); - setThreadMessages((prev) => ({ - ...prev, - [runId]: { - ...prev[runId], - status: "error", - isExpanded: true, - }, - })); + return updatedRun; + + default: + return current; } - }; + }); + }; - socket.onmessage = (event) => { - const message: WebSocketMessage = JSON.parse(event.data); + const handleError = (error: any) => { + console.error("Error:", error); + message.error("Error during request processing"); - switch (message.type) { - case "input_request": - clearTimeoutForRun(); + setCurrentRun((current) => { + if (!current) return null; - timeoutRefs.current[runId] = setTimeout(() => { - handleTimeoutForRun(runId); - }, TIMEOUT_CONFIG.DURATION_MS); + const errorRun = { + ...current, + status: "error" as const, + error_message: + error instanceof Error ? error.message : "Unknown error occurred", + }; - setThreadMessages((prev) => ({ - ...prev, - [runId]: { - ...prev[runId], - status: "awaiting_input", - inputRequest: { - prompt: message.data?.content || "", - isPending: false, - }, - }, - })); - break; + // Add failed run to existing runs + setExistingRuns((prev) => [...prev, errorRun]); + return null; // Clear current run + }); - case "message": - clearTimeoutForRun(); - - setThreadMessages((prev) => { - const currentThread = prev[runId] || { - messages: [], - status: "streaming", - isExpanded: true, - }; - - const models_usage: ModelUsage | undefined = message.data - ?.models_usage - ? { - prompt_tokens: message.data.models_usage.prompt_tokens, - completion_tokens: - message.data.models_usage.completion_tokens, - } - : undefined; - - return { - ...prev, - [runId]: { - ...currentThread, - messages: [ - ...currentThread.messages, - { - source: message.data?.source || "", - content: message.data?.content || "", - models_usage, - }, - ], - status: "streaming", - }, - }; - }); - break; + setError({ + status: false, + message: + error instanceof Error ? error.message : "Unknown error occurred", + }); + }; - case "result": - case "completion": - clearTimeoutForRun(); - - setThreadMessages((prev) => { - const currentThread = prev[runId]; - if (!currentThread) return prev; - - const status: ThreadStatus = message.status || "complete"; - const reason = - message.data?.task_result?.stop_reason || - (message.error ? `Error: ${message.error}` : undefined); - - return { - ...prev, - [runId]: { - ...currentThread, - status, - reason, - isExpanded: true, - finalResult: message.data?.task_result?.messages - ?.filter((msg: any) => msg.content !== "TERMINATE") - .pop(), - }, - }; - }); - closeSocket(); - break; - } - }; + const handleInputResponse = async (response: string) => { + if (!activeSocketRef.current || !currentRun) return; - socket.onclose = (event) => { - clearTimeoutForRun(); - - if (!isClosing) { - updateSocket(runId, null); - - setThreadMessages((prev) => { - const thread = prev[runId]; - if (thread && thread.status === "streaming") { - return { - ...prev, - [runId]: { - ...thread, - status: - event.code === TIMEOUT_CONFIG.WEBSOCKET_CODE - ? "timeout" - : "complete", - reason: event.reason || "Connection closed", - }, - }; - } - return prev; - }); - } - }; + if (activeSocketRef.current.readyState !== WebSocket.OPEN) { + console.error( + "Socket not in OPEN state:", + activeSocketRef.current.readyState + ); + handleError(new Error("WebSocket connection not available")); + return; + } - socket.onerror = (error) => { - clearTimeoutForRun(); + // Clear timeout when response received + if (inputTimeoutRef.current) { + clearTimeout(inputTimeoutRef.current); + inputTimeoutRef.current = null; + } - setThreadMessages((prev) => { - const thread = prev[runId]; - if (!thread) return prev; + try { + console.log("Sending input response:", response); + activeSocketRef.current.send( + JSON.stringify({ + type: "input_response", + response: response, + }) + ); + setCurrentRun((current) => { + if (!current) return null; return { - ...prev, - [runId]: { - ...thread, - status: "error", - reason: "WebSocket connection error occurred", - isExpanded: true, - }, + ...current, + status: "active", }; }); - - closeSocket(); - }; - - return socket; + } catch (error) { + handleError(error); + } }; - const cancelRun = async (runId: string) => { - const socket = activeSockets[runId]; - if (socket && socket.readyState === WebSocket.OPEN) { - socket.send( - JSON.stringify({ type: "stop", reason: "Cancelled by user" }) - ); + const handleCancel = async () => { + if (!activeSocketRef.current || !currentRun) return; - setThreadMessages((prev) => ({ - ...prev, - [runId]: { - ...prev[runId], - status: "cancelled", + // Clear timeout when manually cancelled + if (inputTimeoutRef.current) { + clearTimeout(inputTimeoutRef.current); + inputTimeoutRef.current = null; + } + try { + activeSocketRef.current.send( + JSON.stringify({ + type: "stop", reason: "Cancelled by user", - isExpanded: true, - }, - })); + }) + ); + + setCurrentRun((current) => { + if (!current) return null; + return { + ...current, + status: "stopped", + }; + }); + } catch (error) { + handleError(error); } }; - // Clean up timeouts when component unmounts - React.useEffect(() => { - return () => { - Object.entries(timeoutRefs.current).forEach(([_, timeout]) => - clearTimeout(timeout) - ); - timeoutRefs.current = {}; - }; - }, []); - const runTask = async (query: string) => { setError(null); setLoading(true); - if (!session?.id) { + // Add explicit cleanup + if (activeSocket) { + activeSocket.close(); + setActiveSocket(null); + activeSocketRef.current = null; + } + if (inputTimeoutRef.current) { + clearTimeout(inputTimeoutRef.current); + inputTimeoutRef.current = null; + } + + if (!session?.id || !teamConfig) { + // Add teamConfig check setLoading(false); return; } - let runId: string | null = null; - try { - runId = (await createRun(session.id)) + ""; - - const userMessage: Message = { - config: { + const runId = await createRun(session.id); + + // Initialize run state BEFORE websocket connection + setCurrentRun({ + id: runId, + created_at: new Date().toISOString(), + status: "created", // Start with created status + messages: [], + task: { content: query, source: "user", }, - session_id: session.id, - run_id: runId, - }; - - const botMessage: Message = { - config: { - content: "Thinking...", - source: "bot", - }, - session_id: session.id, - run_id: runId, - }; - - setMessages((prev) => [...prev, userMessage, botMessage]); - connectWebSocket(runId, query); // Now passing query to connectWebSocket - } catch (err) { - console.error("Error:", err); - message.error("Error during request processing"); - - if (runId) { - if (activeSockets[runId]) { - activeSockets[runId].close(); - } - - setThreadMessages((prev) => ({ - ...prev, - [runId!]: { - ...prev[runId!], - status: "error", - isExpanded: true, - }, - })); - } - - setError({ - status: false, - message: err instanceof Error ? err.message : "Unknown error occurred", + team_result: null, + error_message: undefined, }); + + // Setup WebSocket + const socket = setupWebSocket(runId, query); + setActiveSocket(socket); + activeSocketRef.current = socket; + } catch (error) { + handleError(error); } finally { setLoading(false); } }; - React.useEffect(() => { - // session changed - if (session) { - setMessages([]); - setThreadMessages({}); + const setupWebSocket = (runId: string, query: string): WebSocket => { + if (!session || !session.id) { + throw new Error("Invalid session configuration"); } - }, [session]); + // Close existing socket if any + if (activeSocket?.readyState === WebSocket.OPEN) { + activeSocket.close(); + } + + const baseUrl = getBaseUrl(serverUrl); + const wsProtocol = window.location.protocol === "https:" ? "wss:" : "ws:"; + const wsUrl = `${wsProtocol}//${baseUrl}/api/ws/runs/${runId}`; + + const socket = new WebSocket(wsUrl); + + // Initialize current run + setCurrentRun({ + id: runId, + created_at: new Date().toISOString(), + status: "active", + task: createMessage( + { content: query, source: "user" }, + runId, + session.id || 0 + ).config, + team_result: null, + messages: [], + error_message: undefined, + }); + + socket.onopen = () => { + // Send start message with teamConfig + socket.send( + JSON.stringify({ + type: "start", + task: query, + team_config: teamConfig, + }) + ); + }; + + socket.onmessage = (event) => { + try { + const message = JSON.parse(event.data); + handleWebSocketMessage(message); + } catch (error) { + console.error("WebSocket message parsing error:", error); + } + }; + + socket.onclose = () => { + activeSocketRef.current = null; + setActiveSocket(null); + }; + + socket.onerror = (error) => { + handleError(error); + }; + + return socket; + }; + + // Helper for WebSocket URL + const getBaseUrl = (url: string): string => { + try { + let baseUrl = url.replace(/(^\w+:|^)\/\//, ""); + if (baseUrl.startsWith("localhost")) { + baseUrl = baseUrl.replace("/api", ""); + } else if (baseUrl === "/api") { + baseUrl = window.location.host; + } else { + baseUrl = baseUrl.replace("/api", "").replace(/\/$/, ""); + } + return baseUrl; + } catch (error) { + console.error("Error processing server URL:", error); + throw new Error("Invalid server URL configuration"); + } + }; return (
@@ -549,45 +477,62 @@ export default function ChatView({
+
- +
+ {" "} + {" "} +
+ {sessions !== null && sessions?.length === 0 ? ( +
+
+ Welcome + Welcome! Create a session to get started! +
+
+ ) : ( + <> + {teamConfig && ( + <> + {/* Existing Runs */} + {existingRuns.map((run, index) => ( + + ))} + + {/* Current Run */} + {currentRun && ( + + )} + + )} + + )}
- {sessions !== null && sessions?.length === 0 ? ( -
-
- Welcome - Welcome! Create a session to get started! -
+ {session && ( +
+
- ) : ( - <> - {session && ( -
- thread.status === "awaiting_input" - )} // Disable input while waiting for user input - /> -
- )} - )}
diff --git a/python/packages/autogen-studio/frontend/src/components/views/playground/chat/threadview.tsx b/python/packages/autogen-studio/frontend/src/components/views/playground/chat/inputrequest.tsx similarity index 59% rename from python/packages/autogen-studio/frontend/src/components/views/playground/chat/threadview.tsx rename to python/packages/autogen-studio/frontend/src/components/views/playground/chat/inputrequest.tsx index 355b277d4c40..d9318892500e 100644 --- a/python/packages/autogen-studio/frontend/src/components/views/playground/chat/threadview.tsx +++ b/python/packages/autogen-studio/frontend/src/components/views/playground/chat/inputrequest.tsx @@ -12,15 +12,6 @@ import { ThreadState, TIMEOUT_CONFIG } from "./types"; import { RenderMessage } from "./rendermessage"; import LoadingDots from "../../shared/atoms"; -interface ThreadViewProps { - thread: ThreadState; - isStreaming: boolean; - runId: string; - onCancel: (runId: string) => void; - onInputResponse: (runId: string, response: string) => void; - threadContainerRef: (el: HTMLDivElement | null) => void; -} - interface InputRequestProps { prompt: string; onSubmit: (response: string) => void; @@ -170,105 +161,4 @@ const InputRequestView: React.FC = ({ ); }; -const ThreadView: React.FC = ({ - thread, - isStreaming, - runId, - onCancel, - onInputResponse, - threadContainerRef, -}) => { - const isAwaitingInput = thread.status === "awaiting_input"; - const isTimedOut = thread.status === "timeout"; - - const getStatusIcon = () => { - switch (thread.status) { - case "streaming": - return ; - case "awaiting_input": - return ; - case "complete": - return ; - case "error": - return ; - case "timeout": - return ; - default: - return null; - } - }; - - const getStatusText = () => { - if (isStreaming) { - return ( - <> - Agents working - - - ); - } - if (isAwaitingInput) return "Waiting for your input"; - if (isTimedOut) return TIMEOUT_CONFIG.DEFAULT_MESSAGE; - if (thread.reason) - return ( - <> - Stop Reason: - {thread.reason} - - ); - return null; - }; - - const handleTimeout = () => { - if (thread.inputRequest) { - onInputResponse(runId, "TIMEOUT"); - } - }; - - return ( -
-
-
- {getStatusIcon()} - {getStatusText()} -
- {(isStreaming || isAwaitingInput) && ( - - )} -
- -
-
- {thread.messages.map((threadMsg, threadIndex) => ( -
- -
- ))} - - {thread.inputRequest && ( - onInputResponse(runId, response)} - disabled={!isAwaitingInput || isTimedOut} - onTimeout={handleTimeout} - /> - )} -
-
-
- ); -}; - -export default ThreadView; +export default InputRequestView; diff --git a/python/packages/autogen-studio/frontend/src/components/views/playground/chat/messagelist.tsx b/python/packages/autogen-studio/frontend/src/components/views/playground/chat/messagelist.tsx deleted file mode 100644 index d25a508e7bef..000000000000 --- a/python/packages/autogen-studio/frontend/src/components/views/playground/chat/messagelist.tsx +++ /dev/null @@ -1,289 +0,0 @@ -import React from "react"; -import { ThreadState } from "./types"; -import { - AgentMessageConfig, - Message, - TeamConfig, -} from "../../../types/datamodel"; -import { RenderMessage } from "./rendermessage"; -import { - StopCircle, - User, - Network, - MessageSquare, - Loader2, - CheckCircle, - AlertTriangle, - TriangleAlertIcon, - GroupIcon, -} from "lucide-react"; -import AgentFlow from "./agentflow/agentflow"; -import ThreadView from "./threadview"; -import LoadingDots from "../../shared/atoms"; - -interface MessageListProps { - messages: Message[]; - threadMessages: Record; - setThreadMessages: React.Dispatch< - React.SetStateAction> - >; - onRetry: (content: string) => void; - onCancel: (runId: string) => void; - onInputResponse: (runId: string, response: string) => void; - loading?: boolean; - teamConfig?: TeamConfig; -} - -interface MessagePair { - userMessage: Message; - botMessage: Message; -} - -export const MessageList: React.FC = ({ - messages, - threadMessages, - setThreadMessages, - onRetry, - onCancel, - onInputResponse, // New prop - loading = false, - teamConfig, -}) => { - const messagePairs = React.useMemo(() => { - const pairs: MessagePair[] = []; - for (let i = 0; i < messages.length; i += 2) { - if (messages[i] && messages[i + 1]) { - pairs.push({ - userMessage: messages[i], - botMessage: messages[i + 1], - }); - } - } - return pairs; - }, [messages]); - - // Create a ref map to store refs for each thread container - const threadContainerRefs = React.useRef< - Record - >({}); - - // Effect to handle scrolling when thread messages update - React.useEffect(() => { - Object.entries(threadMessages).forEach(([runId, thread]) => { - if (thread.isExpanded && threadContainerRefs.current[runId]) { - const container = threadContainerRefs.current[runId]; - if (container) { - container.scrollTo({ - top: container.scrollHeight, - behavior: "smooth", - }); - } - } - }); - }, [threadMessages]); - - const toggleThread = (runId: string) => { - setThreadMessages((prev) => ({ - ...prev, - [runId]: { - ...prev[runId], - isExpanded: !prev[runId]?.isExpanded, - }, - })); - }; - - const calculateThreadTokens = (messages: AgentMessageConfig[]) => { - return messages.reduce((total, msg) => { - if (!msg.models_usage) return total; - return ( - total + - (msg.models_usage.prompt_tokens || 0) + - (msg.models_usage.completion_tokens || 0) - ); - }, 0); - }; - - const getStatusIcon = (status: ThreadState["status"]) => { - switch (status) { - case "streaming": - return ( -
- {" "} - Processing{" "} - -
- ); - case "awaiting_input": // New status - return ( -
- {" "} - Waiting for your input -
- ); - case "complete": - return ( -
- {" "} - Task completed -
- ); - case "error": - return ( -
- {" "} - An error occurred. -
- ); - case "cancelled": - return ( -
- {" "} - Task was cancelled. -
- ); - default: - return null; - } - }; - - return ( -
- {messagePairs.map(({ userMessage, botMessage }, pairIndex) => { - const isLast = pairIndex === messagePairs.length - 1; - const thread = threadMessages[botMessage.run_id]; - const hasThread = thread && thread.messages.length > 0; - const isStreaming = thread?.status === "streaming"; - const isAwaitingInput = thread?.status === "awaiting_input"; // New check - - const isFirstMessage = pairIndex === 0; - - return ( -
- {/* User message */} - { -
- {/*
Task Run 1.
*/} -
- Run {pairIndex + 1} - {!isFirstMessage && ( - <> - {" "} - |{" "} - {" "} - Note: Each run does not share data with previous runs in - the same session yet.{" "} - - )} -
-
- } -
-
- You -
- -
-
-
- -
-
- - {/* Team response */} -
-
-
- -
- - Agent Team - -
- - {/* Main response container */} -
-
-
- {getStatusIcon(thread?.status)}{" "} - {!isAwaitingInput && thread?.finalResult?.content} -
-
- - {/* Thread section */} - {hasThread && ( -
-
-
- -
- -
- {calculateThreadTokens(thread.messages)} tokens |{" "} - {thread.messages.length} messages -
-
- -
-
- {thread.isExpanded && ( - - (threadContainerRefs.current[botMessage.run_id] = - el) - } - /> - )} -
-
- {teamConfig && thread.isExpanded && ( - - )} -
-
-
- )} -
-
-
- ); - })} - - {messages.length === 0 && !loading && ( -
-
Send a message to begin!
-
- )} -
- ); -}; diff --git a/python/packages/autogen-studio/frontend/src/components/views/playground/chat/rendermessage.tsx b/python/packages/autogen-studio/frontend/src/components/views/playground/chat/rendermessage.tsx index 54035bf7e665..66d4ed7e0403 100644 --- a/python/packages/autogen-studio/frontend/src/components/views/playground/chat/rendermessage.tsx +++ b/python/packages/autogen-studio/frontend/src/components/views/playground/chat/rendermessage.tsx @@ -58,9 +58,9 @@ const RenderToolCall: React.FC<{ content: FunctionCall[] }> = ({ content }) => ( {content.map((call) => (
Function: {call.name}
-
+        
{JSON.stringify(JSON.parse(call.arguments), null, 2)} -
+
))} @@ -90,9 +90,9 @@ const RenderToolResult: React.FC<{ content: FunctionExecutionResult[] }> = ({ }) => (
{content.map((result) => ( -
+
Result ID: {result.call_id}
-
+        
           {result.content}
         
@@ -105,6 +105,7 @@ export const RenderMessage: React.FC = ({ isLast = false, className = "", }) => { + if (!message) return null; const isUser = messageUtils.isUser(message.source); const content = message.content; diff --git a/python/packages/autogen-studio/frontend/src/components/views/playground/chat/runview.tsx b/python/packages/autogen-studio/frontend/src/components/views/playground/chat/runview.tsx new file mode 100644 index 000000000000..ab1a58c543df --- /dev/null +++ b/python/packages/autogen-studio/frontend/src/components/views/playground/chat/runview.tsx @@ -0,0 +1,271 @@ +import React, { useState, useRef, useEffect } from "react"; +import { + StopCircle, + MessageSquare, + Loader2, + CheckCircle, + AlertTriangle, + TriangleAlertIcon, + GroupIcon, +} from "lucide-react"; +import { Run, Message, TeamConfig } from "../../../types/datamodel"; +import AgentFlow from "./agentflow/agentflow"; +import { RenderMessage } from "./rendermessage"; +import LoadingDots from "../../shared/atoms"; +import InputRequestView from "./inputrequest"; +import { Tooltip } from "antd"; + +interface RunViewProps { + run: Run; + teamConfig?: TeamConfig; + onInputResponse?: (response: string) => void; + onCancel?: () => void; + isFirstRun?: boolean; +} + +const RunView: React.FC = ({ + run, + onInputResponse, + onCancel, + teamConfig, + isFirstRun = false, +}) => { + const [isExpanded, setIsExpanded] = useState(true); + const threadContainerRef = useRef(null); + const isActive = run.status === "active" || run.status === "awaiting_input"; + + // Replace existing scroll effect with this simpler one + useEffect(() => { + setTimeout(() => { + if (threadContainerRef.current) { + threadContainerRef.current.scrollTo({ + top: threadContainerRef.current.scrollHeight, + behavior: "smooth", + }); + } + }, 450); + }, [run.messages]); // Only depend on messages changing + + const calculateThreadTokens = (messages: Message[]) => { + return messages.reduce((total, msg) => { + if (!msg.config.models_usage) return total; + return ( + total + + (msg.config.models_usage.prompt_tokens || 0) + + (msg.config.models_usage.completion_tokens || 0) + ); + }, 0); + }; + + const getStatusIcon = (status: Run["status"]) => { + switch (status) { + case "active": + return ( +
+ + Processing + +
+ ); + case "awaiting_input": + return ( +
+ + Waiting for your input + +
+ ); + case "complete": + return ( +
+ + Task completed +
+ ); + case "error": + return ( +
+ + {run.error_message || "An error occurred"} +
+ ); + case "stopped": + return ( +
+ + Task was stopped +
+ ); + default: + return null; + } + }; + + return ( +
+ {/* Run Header */} +
+
+ +
ID: {run.id}
+
Created: {new Date(run.created_at).toLocaleString()}
+
Status: {run.status}
+
+ } + > + Run ...{run.id.slice(-6)} + + {!isFirstRun && ( + <> + {" "} + |{" "} + + Note: Each run does not share data with previous runs in the same + session yet. + + )} +
+
+ + {/* User Message */} +
+
+ +
+
+ + {/* Team Response */} +
+
+
+ +
+ Agent Team +
+ +
+ {/* Main Response Container */} +
+
+
{getStatusIcon(run.status)}
+ + {/* Cancel Button - More prominent placement */} + {isActive && onCancel && ( + + )} +
+ + {/* Final Response */} + {run.status !== "awaiting_input" && run.status !== "active" && ( +
+
+ Stop reason: {run.team_result?.task_result?.stop_reason} +
+ {run.messages[run.messages.length - 1]?.config?.content + ""} +
+ )} +
+ + {/* Thread Section */} +
+ {run.messages.length > 0 && ( +
+
+
+ +
+ +
+ {calculateThreadTokens(run.messages)} tokens |{" "} + {run.messages.length} messages +
+
+ + {isExpanded && ( +
+ {/* Messages Thread */} +
+
+ {" "} + {" "} +
+ {run.messages.map((msg, idx) => ( +
+ +
+ ))} + + {/* Input Request UI */} + {run.status === "awaiting_input" && onInputResponse && ( +
+ +
+ )} +
+
{" "} +
+ {getStatusIcon(run.status)} +
+
+
+ + {/* Agent Flow Visualization */} +
+ {teamConfig && ( + + )} +
+
+ )} +
+ )} +
+
+
+
+ ); +}; + +export default RunView; diff --git a/python/packages/autogen-studio/frontend/src/components/views/shared/markdown.tsx b/python/packages/autogen-studio/frontend/src/components/views/shared/markdown.tsx index c0068043b19b..c98f86ea11e2 100644 --- a/python/packages/autogen-studio/frontend/src/components/views/shared/markdown.tsx +++ b/python/packages/autogen-studio/frontend/src/components/views/shared/markdown.tsx @@ -1,20 +1,18 @@ +import React, { ReactNode } from "react"; import Markdown from "react-markdown"; -import React from "react"; interface MarkdownViewProps { - children: string; + content: string; className?: string; } export const MarkdownView: React.FC = ({ - children, + content, className = "", }) => { return ( -
- {children} +
+ {content}
); }; diff --git a/python/packages/autogen-studio/frontend/src/components/views/shared/session/api.ts b/python/packages/autogen-studio/frontend/src/components/views/shared/session/api.ts index cccd6ad61a76..f34843e239bf 100644 --- a/python/packages/autogen-studio/frontend/src/components/views/shared/session/api.ts +++ b/python/packages/autogen-studio/frontend/src/components/views/shared/session/api.ts @@ -1,4 +1,4 @@ -import { Session } from "../../../types/datamodel"; +import { Session, SessionRuns } from "../../../types/datamodel"; import { getServerUrl } from "../../../utils"; export class SessionAPI { @@ -83,6 +83,23 @@ export class SessionAPI { return data.data; } + // session runs with messages + async getSessionRuns( + sessionId: number, + userId: string + ): Promise { + const response = await fetch( + `${this.getBaseUrl()}/sessions/${sessionId}/runs?user_id=${userId}`, + { + headers: this.getHeaders(), + } + ); + const data = await response.json(); + if (!data.status) + throw new Error(data.message || "Failed to fetch session runs"); + return data.data; // Returns { runs: RunMessage[] } + } + async deleteSession(sessionId: number, userId: string): Promise { const response = await fetch( `${this.getBaseUrl()}/sessions/${sessionId}?user_id=${userId}`, diff --git a/python/packages/autogen-studio/frontend/src/pages/index.tsx b/python/packages/autogen-studio/frontend/src/pages/index.tsx index e54248574486..a1b591074098 100644 --- a/python/packages/autogen-studio/frontend/src/pages/index.tsx +++ b/python/packages/autogen-studio/frontend/src/pages/index.tsx @@ -8,7 +8,7 @@ const IndexPage = ({ data }: any) => { return (
- +
); diff --git a/python/packages/autogen-studio/frontend/yarn.lock b/python/packages/autogen-studio/frontend/yarn.lock index 03ca9a83ff87..889c3d92de89 100644 --- a/python/packages/autogen-studio/frontend/yarn.lock +++ b/python/packages/autogen-studio/frontend/yarn.lock @@ -15,27 +15,6 @@ "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.24" -"@ant-design/charts-util@0.0.1-alpha.6": - version "0.0.1-alpha.6" - resolved "https://registry.yarnpkg.com/@ant-design/charts-util/-/charts-util-0.0.1-alpha.6.tgz#09903d28a15d86cc73fafef5383a5a3f932811bb" - integrity sha512-roZobGkUJ0WqULPiQkX/2j01r6Cn0W6WTVpszq9u8dZKwyrSDr+UgfA/hDmrwOm9TWD9HAxe7aRHnvC06dux8w== - -"@ant-design/charts-util@0.0.1-alpha.7": - version "0.0.1-alpha.7" - resolved "https://registry.yarnpkg.com/@ant-design/charts-util/-/charts-util-0.0.1-alpha.7.tgz#39152b7106970faa226ba857fae64a0eb32f30b9" - integrity sha512-Yh0o6EdO6SvdSnStFZMbnUzjyymkVzV+TQ9ymVW9hlVgO/fUkUII3JYSdV+UVcFnYwUF0YiDKuSTLCZNAzg2bQ== - dependencies: - lodash "^4.17.21" - -"@ant-design/charts@^2.2.3": - version "2.2.3" - resolved "https://registry.yarnpkg.com/@ant-design/charts/-/charts-2.2.3.tgz#ca484a70877ee9c7013951f477fcba661e842525" - integrity sha512-gjyOJwAvRH3NztbR4R7bQ+wVfA/jRT+EgtSEQxQtjka4w0srMIftXgaoxoycgCEHgO1eUg20RWXx0mMFKyWIfg== - dependencies: - "@ant-design/graphs" "^2.0.0" - "@ant-design/plots" "^2.1.3" - lodash "^4.17.21" - "@ant-design/colors@^7.0.0", "@ant-design/colors@^7.1.0": version "7.1.0" resolved "https://registry.yarnpkg.com/@ant-design/colors/-/colors-7.1.0.tgz#60eadfa2e21871d8948dac5d50b9f056062f8af3" @@ -53,9 +32,9 @@ rc-util "^5.38.0" "@ant-design/cssinjs@^1.21.0", "@ant-design/cssinjs@^1.21.1": - version "1.21.1" - resolved "https://registry.yarnpkg.com/@ant-design/cssinjs/-/cssinjs-1.21.1.tgz#7320813c5f747e0cde52c388eff5198d78d57230" - integrity sha512-tyWnlK+XH7Bumd0byfbCiZNK43HEubMoCcu9VxwsAwiHdHTgWa+tMN0/yvxa+e8EzuFP1WdUNNPclRpVtD33lg== + version "1.22.0" + resolved "https://registry.yarnpkg.com/@ant-design/cssinjs/-/cssinjs-1.22.0.tgz#c2eea2490d2405e55c64f3c1af1e09524d62a228" + integrity sha512-W9XSFeRPR0mAN3OuxfuS/xhENCYKf+8s+QyNNER0FSWoK9OpISTag6CCweg6lq0hASQ/2Vcza0Z8/kGivCP0Ng== dependencies: "@babel/runtime" "^7.11.1" "@emotion/hash" "^0.8.0" @@ -63,7 +42,7 @@ classnames "^2.3.1" csstype "^3.1.3" rc-util "^5.35.0" - stylis "^4.3.3" + stylis "^4.3.4" "@ant-design/fast-color@^2.0.6": version "2.0.6" @@ -72,18 +51,6 @@ dependencies: "@babel/runtime" "^7.24.7" -"@ant-design/graphs@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@ant-design/graphs/-/graphs-2.0.0.tgz#dd0b39c05ffcb42c9368df0515fdc0a1917f26d8" - integrity sha512-giwe60AHwcQp5mXKQrsDU2/34cKOJQoc4rYPB9N1CqaGFcEWqOi6Kiz7O9s0QRwPBpzyP/boyP01a9qb03ycKw== - dependencies: - "@ant-design/charts-util" "0.0.1-alpha.7" - "@antv/g6" "^5.0.24" - "@antv/g6-extension-react" "^0.1.7" - "@antv/graphin" "^3.0.2" - lodash "^4.17.21" - styled-components "^6.1.13" - "@ant-design/icons-svg@^4.4.0": version "4.4.2" resolved "https://registry.yarnpkg.com/@ant-design/icons-svg/-/icons-svg-4.4.2.tgz#ed2be7fb4d82ac7e1d45a54a5b06d6cecf8be6f6" @@ -100,18 +67,6 @@ classnames "^2.2.6" rc-util "^5.31.1" -"@ant-design/plots@^2.1.3", "@ant-design/plots@^2.2.2": - version "2.3.2" - resolved "https://registry.yarnpkg.com/@ant-design/plots/-/plots-2.3.2.tgz#5ca93f502c9b865297e9029745e216c0962c45e9" - integrity sha512-shFV2DTQcbQDtzBwpMagG2pnKy3+I4igws6VQvM7m8UIZtWFSwkWpjCnOl7Xefqgnov/M0C9HbaVGCGc9ZfIqA== - dependencies: - "@ant-design/charts-util" "0.0.1-alpha.6" - "@antv/event-emitter" "^0.1.3" - "@antv/g" "^6.0.0" - "@antv/g2" "^5.1.18" - "@antv/g2-extension-plot" "^0.2.0" - lodash "^4.17.21" - "@ant-design/react-slick@~1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@ant-design/react-slick/-/react-slick-1.1.2.tgz#f84ce3e4d0dc941f02b16f1d1d6d7a371ffbb4f1" @@ -123,520 +78,6 @@ resize-observer-polyfill "^1.5.1" throttle-debounce "^5.0.0" -"@antv/algorithm@^0.1.26": - version "0.1.26" - resolved "https://registry.yarnpkg.com/@antv/algorithm/-/algorithm-0.1.26.tgz#e3f5e7f1d8db5b415c3f31e32b119cbcafc8f5de" - integrity sha512-DVhcFSQ8YQnMNW34Mk8BSsfc61iC1sAnmcfYoXTAshYHuU50p/6b7x3QYaGctDNKWGvi1ub7mPcSY0bK+aN0qg== - dependencies: - "@antv/util" "^2.0.13" - tslib "^2.0.0" - -"@antv/component@^2.0.0", "@antv/component@^2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@antv/component/-/component-2.1.1.tgz#c91daad673913b6efb3c6503dca7ba123346197b" - integrity sha512-V0UCq3Bekqtjw5WedexT1tHM/9x5BY0UAaU7G/5A2NhRfp9GuaQ8xGWLMSWlCQiJSRZWhPIA7RoOSw4Y/W+7UA== - dependencies: - "@antv/g" "^6.1.2" - "@antv/scale" "^0.4.3" - "@antv/util" "^3.3.5" - svg-path-parser "^1.1.0" - -"@antv/coord@^0.4.6": - version "0.4.7" - resolved "https://registry.yarnpkg.com/@antv/coord/-/coord-0.4.7.tgz#3ef6c6e3f9ca0f024b90888549946061f35df77a" - integrity sha512-UTbrMLhwJUkKzqJx5KFnSRpU3BqrdLORJbwUbHK2zHSCT3q3bjcFA//ZYLVfIlwqFDXp/hzfMyRtp0c77A9ZVA== - dependencies: - "@antv/scale" "^0.4.12" - "@antv/util" "^2.0.13" - gl-matrix "^3.4.3" - -"@antv/event-emitter@^0.1.3": - version "0.1.3" - resolved "https://registry.yarnpkg.com/@antv/event-emitter/-/event-emitter-0.1.3.tgz#3e06323b9dcd55a3241ddc7c5458cfabd2095164" - integrity sha512-4ddpsiHN9Pd4UIlWuKVK1C4IiZIdbwQvy9i7DUSI3xNJ89FPUFt8lxDYj8GzzfdllV0NkJTRxnG+FvLk0llidg== - -"@antv/g-camera-api@2.0.18": - version "2.0.18" - resolved "https://registry.yarnpkg.com/@antv/g-camera-api/-/g-camera-api-2.0.18.tgz#69c9e42e74627504a720534259cbd22b12b15cf1" - integrity sha512-N3Gd/kCSCoPZfTocAI0i1uu3VmKrVR6FAq+9QSLEHFdFpg6+Pvqjx32QeOgl3uhE5hNiG/FUZ7KWXDNSnKJS1w== - dependencies: - "@antv/g-lite" "2.1.4" - "@antv/util" "^3.3.5" - "@babel/runtime" "^7.25.6" - gl-matrix "^3.4.3" - tslib "^2.5.3" - -"@antv/g-camera-api@2.0.21": - version "2.0.21" - resolved "https://registry.yarnpkg.com/@antv/g-camera-api/-/g-camera-api-2.0.21.tgz#fb312a5db79addb978dee32fc2bb91c59ba384b5" - integrity sha512-cU903cmIBEyVX6hk7bmoltnnORnRd+KnRQsFzWv+Gg8l99bVOEqVa6/YE+Geh9Gt0JVUr+k06KVs8V40IVkz5Q== - dependencies: - "@antv/g-lite" "2.2.2" - "@antv/util" "^3.3.5" - "@babel/runtime" "^7.25.6" - gl-matrix "^3.4.3" - tslib "^2.5.3" - -"@antv/g-canvas@^2.0.0": - version "2.0.20" - resolved "https://registry.yarnpkg.com/@antv/g-canvas/-/g-canvas-2.0.20.tgz#a79a6960f408a8e3b1982468b6659303b79f5f2d" - integrity sha512-o6aB/I4g6Xi3em6cwdgPQhm/3X1uf+KaMgyQKgB/FekWAD6kxf0qwQRmn0SggUCMcfpJDOrvKmifdIfeDV1zpw== - dependencies: - "@antv/g-lite" "2.1.4" - "@antv/g-plugin-canvas-path-generator" "2.0.15" - "@antv/g-plugin-canvas-picker" "2.0.17" - "@antv/g-plugin-canvas-renderer" "2.1.4" - "@antv/g-plugin-dom-interaction" "2.1.4" - "@antv/g-plugin-html-renderer" "2.1.4" - "@antv/g-plugin-image-loader" "2.0.15" - "@antv/util" "^3.3.5" - "@babel/runtime" "^7.25.6" - tslib "^2.5.3" - -"@antv/g-canvas@^2.0.24": - version "2.0.25" - resolved "https://registry.yarnpkg.com/@antv/g-canvas/-/g-canvas-2.0.25.tgz#4558fe57b5b6ca823ab6461eb3ce302927443670" - integrity sha512-dHpEghB4f+Ts9b3vNzRf43xZ/V6xhLNYOT/0ZbK30fV495bo3Jn+sL1SSjeMnaTJkU6heBso/9yBn1ns2U7/Vw== - dependencies: - "@antv/g-lite" "2.2.2" - "@antv/g-plugin-canvas-path-generator" "2.1.2" - "@antv/g-plugin-canvas-picker" "2.1.4" - "@antv/g-plugin-canvas-renderer" "2.2.4" - "@antv/g-plugin-dom-interaction" "2.1.7" - "@antv/g-plugin-html-renderer" "2.1.7" - "@antv/g-plugin-image-loader" "2.1.4" - "@antv/util" "^3.3.5" - "@babel/runtime" "^7.25.6" - tslib "^2.5.3" - -"@antv/g-dom-mutation-observer-api@2.0.15": - version "2.0.15" - resolved "https://registry.yarnpkg.com/@antv/g-dom-mutation-observer-api/-/g-dom-mutation-observer-api-2.0.15.tgz#035199a7dca34514308edb723bfc59f0560b10ac" - integrity sha512-wHlTNJuVw899GaiWIBVtW6KG5Naf/xZXzK6GSX0z5QlcmNx5tZhUWFNreLebbADrHbr9XBNN2B5m3ndCX7500w== - dependencies: - "@antv/g-lite" "2.1.4" - "@babel/runtime" "^7.25.6" - -"@antv/g-dom-mutation-observer-api@2.0.18": - version "2.0.18" - resolved "https://registry.yarnpkg.com/@antv/g-dom-mutation-observer-api/-/g-dom-mutation-observer-api-2.0.18.tgz#4ace5f4932dc3ce594912800487d6581ab193c18" - integrity sha512-LOriTfw9iSJVQv24VpBKnwWTy2Axv1JxnOpfC6siV8M1D+5cfv+fBmWs6cIQKxM9p7RZSkpaYFQWM27+sH0AvA== - dependencies: - "@antv/g-lite" "2.2.2" - "@babel/runtime" "^7.25.6" - -"@antv/g-lite@2.1.4": - version "2.1.4" - resolved "https://registry.yarnpkg.com/@antv/g-lite/-/g-lite-2.1.4.tgz#28ec3e971ff86c031b51750bb2765525dce79cda" - integrity sha512-RPs+NdvbD1WQpdoSB8pb7Ugrauxc0a2z4QJxvNWhjVPJqnB6GUlnLDKpbd+2vqzOf4GhObAfAdPbOXjA1HkHRw== - dependencies: - "@antv/g-math" "3.0.0" - "@antv/util" "^3.3.5" - "@babel/runtime" "^7.25.6" - d3-color "^3.1.0" - eventemitter3 "^5.0.1" - gl-matrix "^3.4.3" - rbush "^3.0.1" - tslib "^2.5.3" - -"@antv/g-lite@2.2.2": - version "2.2.2" - resolved "https://registry.yarnpkg.com/@antv/g-lite/-/g-lite-2.2.2.tgz#154d60f68f842c1f3e45f91d8741ae2edd152c5a" - integrity sha512-Ffk7Jar+n6lUA+TEvoEaN30rAWe5l6Ybic7lucA90PKiyCsN0w+qVGJzbvskamuwp3RmcSZDNwQGP8vg374dCA== - dependencies: - "@antv/g-math" "3.0.0" - "@antv/util" "^3.3.5" - "@babel/runtime" "^7.25.6" - d3-color "^3.1.0" - eventemitter3 "^5.0.1" - gl-matrix "^3.4.3" - rbush "^3.0.1" - tslib "^2.5.3" - -"@antv/g-math@3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@antv/g-math/-/g-math-3.0.0.tgz#834d993391546e39ae5a30452572fdc49a7c57ec" - integrity sha512-AkmiNIEL1vgqTPeGY2wtsMdBBqKFwF7SKSgs+D1iOS/rqYMsXdhp/HvtuQ5tx/HdawE/ZzTiicIYopc520ADZw== - dependencies: - "@antv/util" "^3.3.5" - gl-matrix "^3.4.3" - tslib "^2.5.3" - -"@antv/g-plugin-canvas-path-generator@2.0.15": - version "2.0.15" - resolved "https://registry.yarnpkg.com/@antv/g-plugin-canvas-path-generator/-/g-plugin-canvas-path-generator-2.0.15.tgz#7edbf403802cf5343f8145cba4c3c3854091d1aa" - integrity sha512-QsPYUdlgSvCOu6e6KrCdfaZPH3H15hY6kFJDGRSrtydAS/IM/YqgXxsw8Xl2nByCjSg48alwNuFoajgu+7dgzA== - dependencies: - "@antv/g-lite" "2.1.4" - "@antv/g-math" "3.0.0" - "@antv/util" "^3.3.5" - "@babel/runtime" "^7.25.6" - tslib "^2.5.3" - -"@antv/g-plugin-canvas-path-generator@2.1.2": - version "2.1.2" - resolved "https://registry.yarnpkg.com/@antv/g-plugin-canvas-path-generator/-/g-plugin-canvas-path-generator-2.1.2.tgz#b96f5a572eebb66f2607414fe180f84c9fb67667" - integrity sha512-ILaKEQvbAZNkRhbE3kWxd0EszDAb3TE0HQKNfur7YuVkQMgACDj6jbVUULFPcGpcw/pQbWM8nD1RRf24hfFAlw== - dependencies: - "@antv/g-lite" "2.2.2" - "@antv/g-math" "3.0.0" - "@antv/util" "^3.3.5" - "@babel/runtime" "^7.25.6" - tslib "^2.5.3" - -"@antv/g-plugin-canvas-picker@2.0.17": - version "2.0.17" - resolved "https://registry.yarnpkg.com/@antv/g-plugin-canvas-picker/-/g-plugin-canvas-picker-2.0.17.tgz#a213d9d7a0a6613c7456f65514fa1d7efb3fc312" - integrity sha512-A36VnA25QCh38xhnuVHwK5/NKp5dAQ0Y1ZoQ6JTZHNWox+ZChjSDbfimtQOVQQaixoX4O6JFtFroUgno7vHIkg== - dependencies: - "@antv/g-lite" "2.1.4" - "@antv/g-math" "3.0.0" - "@antv/g-plugin-canvas-path-generator" "2.0.15" - "@antv/g-plugin-canvas-renderer" "2.1.4" - "@antv/util" "^3.3.5" - "@babel/runtime" "^7.25.6" - gl-matrix "^3.4.3" - tslib "^2.5.3" - -"@antv/g-plugin-canvas-picker@2.1.4": - version "2.1.4" - resolved "https://registry.yarnpkg.com/@antv/g-plugin-canvas-picker/-/g-plugin-canvas-picker-2.1.4.tgz#963dfe2a8a6771ab969910e52a7d1e1a6ef7f0ed" - integrity sha512-L/L7wiZVCnLumIsE1DU14t4kwnwOLyQlsB3ZE/Q6ZVEf6UiZp1ARrGR8zzz+yUPxeWiJqduVnBRLOkyZkdjOoQ== - dependencies: - "@antv/g-lite" "2.2.2" - "@antv/g-math" "3.0.0" - "@antv/g-plugin-canvas-path-generator" "2.1.2" - "@antv/g-plugin-canvas-renderer" "2.2.4" - "@antv/util" "^3.3.5" - "@babel/runtime" "^7.25.6" - gl-matrix "^3.4.3" - tslib "^2.5.3" - -"@antv/g-plugin-canvas-renderer@2.1.4": - version "2.1.4" - resolved "https://registry.yarnpkg.com/@antv/g-plugin-canvas-renderer/-/g-plugin-canvas-renderer-2.1.4.tgz#677449301512e30ae4ec6975689b19f3e8241f41" - integrity sha512-VtcaCZP04zsjocKNVaHTE0323GZh5J+y9ZwF316mfwD3+Ji97ueRIrXDmi0oVmnC64T3N3JKwOy+xoKOd/mw6g== - dependencies: - "@antv/g-lite" "2.1.4" - "@antv/g-math" "3.0.0" - "@antv/g-plugin-canvas-path-generator" "2.0.15" - "@antv/g-plugin-image-loader" "2.0.15" - "@antv/util" "^3.3.5" - "@babel/runtime" "^7.25.6" - gl-matrix "^3.4.3" - tslib "^2.5.3" - -"@antv/g-plugin-canvas-renderer@2.2.4": - version "2.2.4" - resolved "https://registry.yarnpkg.com/@antv/g-plugin-canvas-renderer/-/g-plugin-canvas-renderer-2.2.4.tgz#3ac4227c16dfc52f074bc8343a9eea4afc99d403" - integrity sha512-cmqVUB+aAglj/gYvc8Zcqjwe9PXOapyTE6Q9ChYVnlStP8rMdyXgdfACNa7pi7T1TWoq2etuEp29t4k+oGKLqQ== - dependencies: - "@antv/g-lite" "2.2.2" - "@antv/g-math" "3.0.0" - "@antv/g-plugin-canvas-path-generator" "2.1.2" - "@antv/g-plugin-image-loader" "2.1.4" - "@antv/util" "^3.3.5" - "@babel/runtime" "^7.25.6" - gl-matrix "^3.4.3" - tslib "^2.5.3" - -"@antv/g-plugin-dom-interaction@2.1.4": - version "2.1.4" - resolved "https://registry.yarnpkg.com/@antv/g-plugin-dom-interaction/-/g-plugin-dom-interaction-2.1.4.tgz#56c4657ffddfa0a3ab86a4c7cb91df2b87c85b2f" - integrity sha512-ewWyGj4ipYMeh9yyoZVjyOOyfGDvzIVFZ1TrY1LYh75UsOQGbCIF/IdeBCOYxM/hEi9nQAVlxgc5g6AOH6CCXw== - dependencies: - "@antv/g-lite" "2.1.4" - "@babel/runtime" "^7.25.6" - tslib "^2.5.3" - -"@antv/g-plugin-dom-interaction@2.1.7": - version "2.1.7" - resolved "https://registry.yarnpkg.com/@antv/g-plugin-dom-interaction/-/g-plugin-dom-interaction-2.1.7.tgz#93ffb590701999b742628936390a5890b81fab80" - integrity sha512-wrlcFlWsXq9Pa6ju5de8V0TzIR2GivBOkRyHQuNba6kpUC1RAT0EHpTpPCJML+Jys8nt8A0ppssSF4E0jZ1MpQ== - dependencies: - "@antv/g-lite" "2.2.2" - "@babel/runtime" "^7.25.6" - tslib "^2.5.3" - -"@antv/g-plugin-dragndrop@^2.0.0": - version "2.0.15" - resolved "https://registry.yarnpkg.com/@antv/g-plugin-dragndrop/-/g-plugin-dragndrop-2.0.15.tgz#8e710a8f66ed971c8d500cae82664de913405e05" - integrity sha512-221a2JbupxPxaLgDOTp3rXvf2824CeotlQWaQFkDbt7MPAKSOseC4di2WscH6pNqR4uaXaDzoswo3rNRgWcaBw== - dependencies: - "@antv/g-lite" "2.1.4" - "@antv/util" "^3.3.5" - "@babel/runtime" "^7.25.6" - tslib "^2.5.3" - -"@antv/g-plugin-dragndrop@^2.0.18": - version "2.0.18" - resolved "https://registry.yarnpkg.com/@antv/g-plugin-dragndrop/-/g-plugin-dragndrop-2.0.18.tgz#1e7df5d6e40a29befc4e563ceb19f2f6d6b972e0" - integrity sha512-kjRj/yoWXh5J0Db/gtB3TFNlR4x3dMWvlRz6+7M3ka/mlrdMS0SGFLZfbWq6xvN+TzyiDXZdzSwA0A0OkA5Jww== - dependencies: - "@antv/g-lite" "2.2.2" - "@antv/util" "^3.3.5" - "@babel/runtime" "^7.25.6" - tslib "^2.5.3" - -"@antv/g-plugin-html-renderer@2.1.4": - version "2.1.4" - resolved "https://registry.yarnpkg.com/@antv/g-plugin-html-renderer/-/g-plugin-html-renderer-2.1.4.tgz#e5604a9890495fa33e9f02f7648ec0d83cd8a5f5" - integrity sha512-a/1m1xOpAWusFtWsKq4ohJUWFrMbjc1g0LCPz1mu2D0r9AMl9fXhPaPmm5XapTkWBHHpOiJKEV8wsNVgkMK5Zw== - dependencies: - "@antv/g-lite" "2.1.4" - "@antv/util" "^3.3.5" - "@babel/runtime" "^7.25.6" - gl-matrix "^3.4.3" - tslib "^2.5.3" - -"@antv/g-plugin-html-renderer@2.1.7": - version "2.1.7" - resolved "https://registry.yarnpkg.com/@antv/g-plugin-html-renderer/-/g-plugin-html-renderer-2.1.7.tgz#ec4874d86a887809e9ef2b096132d6a50c1b53d4" - integrity sha512-MPquXo9MT9QHUdbvgwcBr9msNv9Qh2slOKpc1fzwWG7/aLpmOAxTAhd3+Sjj8JuVXHYw25Q3seI8lMJSGwTWvw== - dependencies: - "@antv/g-lite" "2.2.2" - "@antv/util" "^3.3.5" - "@babel/runtime" "^7.25.6" - gl-matrix "^3.4.3" - tslib "^2.5.3" - -"@antv/g-plugin-image-loader@2.0.15": - version "2.0.15" - resolved "https://registry.yarnpkg.com/@antv/g-plugin-image-loader/-/g-plugin-image-loader-2.0.15.tgz#7928c4abf7ff283deddde78bc35a34bc46a53932" - integrity sha512-iP991rOUoJHUyX8GoJ5ASRexZyhEJfMvfTZoWIpduTcH2EiYJh/luLwKedlUQ71haF3/TraEJPE+0LzGnxOeJQ== - dependencies: - "@antv/g-lite" "2.1.4" - "@antv/util" "^3.3.5" - "@babel/runtime" "^7.25.6" - gl-matrix "^3.4.3" - tslib "^2.5.3" - -"@antv/g-plugin-image-loader@2.1.4": - version "2.1.4" - resolved "https://registry.yarnpkg.com/@antv/g-plugin-image-loader/-/g-plugin-image-loader-2.1.4.tgz#0b4f5e00a0941178db4efd54afc182b47c6ce543" - integrity sha512-dRikFBY/GNvMW7ecbDerChgnKnjZQoSNONR8uL/bZ1vurTZTd9HK1FYz2QDjLIRePWNTlfcWmux1RooSKfo1OA== - dependencies: - "@antv/g-lite" "2.2.2" - "@antv/util" "^3.3.5" - "@babel/runtime" "^7.25.6" - gl-matrix "^3.4.3" - tslib "^2.5.3" - -"@antv/g-plugin-svg-picker@2.0.20": - version "2.0.20" - resolved "https://registry.yarnpkg.com/@antv/g-plugin-svg-picker/-/g-plugin-svg-picker-2.0.20.tgz#5401d37816a1bb6c8457fabfe38bc0eddeb2b383" - integrity sha512-gML0upmK24Bqr8REsuW8ZZqlKNHSEDtYlycFof36HDcKVNDWIf22ff5N3op1rCHkbny6XXjkIXoKulfQM6GHOA== - dependencies: - "@antv/g-lite" "2.2.2" - "@antv/g-plugin-svg-renderer" "2.2.2" - "@babel/runtime" "^7.25.6" - tslib "^2.5.3" - -"@antv/g-plugin-svg-renderer@2.2.2": - version "2.2.2" - resolved "https://registry.yarnpkg.com/@antv/g-plugin-svg-renderer/-/g-plugin-svg-renderer-2.2.2.tgz#c48bd91df47e73ebce22a9e8eab63cedecc221ff" - integrity sha512-fWQ5gVSxcZr+Ip95wVeHY2WtoWnsyGDqj+lkxK1aAq0uzqI2qIVyawUc86R87Bv4UVY9b0B5KCtig5F5SGGwAg== - dependencies: - "@antv/g-lite" "2.2.2" - "@antv/util" "^3.3.5" - "@babel/runtime" "^7.25.6" - gl-matrix "^3.4.3" - tslib "^2.5.3" - -"@antv/g-svg@^2.0.11": - version "2.0.20" - resolved "https://registry.yarnpkg.com/@antv/g-svg/-/g-svg-2.0.20.tgz#6f8377bd310381102b80930756a99e97f565b5aa" - integrity sha512-KMb5VzQ3nZpBBwH+sRIJGh/umfEpv4SmDWwV/Yy4nAn0X91yq++qEiIDCnq9QSXHOESV6Si7XJbo4WtX5G7TPw== - dependencies: - "@antv/g-lite" "2.2.2" - "@antv/g-plugin-dom-interaction" "2.1.7" - "@antv/g-plugin-svg-picker" "2.0.20" - "@antv/g-plugin-svg-renderer" "2.2.2" - "@antv/util" "^3.3.5" - "@babel/runtime" "^7.25.6" - tslib "^2.5.3" - -"@antv/g-web-animations-api@2.1.4": - version "2.1.4" - resolved "https://registry.yarnpkg.com/@antv/g-web-animations-api/-/g-web-animations-api-2.1.4.tgz#aaa2be6014fc58b9d8f6724b053b7893eae4cc18" - integrity sha512-KLPrP3HsnKDKdoBF3ijiXY8QJx8FrdRRPFmz1uVVIzyfJa7UVX5HOi7soK7Nh6Grg3eiy99Y9y9U1IQe41J5fQ== - dependencies: - "@antv/g-lite" "2.1.4" - "@antv/util" "^3.3.5" - "@babel/runtime" "^7.25.6" - tslib "^2.5.3" - -"@antv/g-web-animations-api@2.1.7": - version "2.1.7" - resolved "https://registry.yarnpkg.com/@antv/g-web-animations-api/-/g-web-animations-api-2.1.7.tgz#c56868ebaa8ddc7aca79c9314f6a211f91847039" - integrity sha512-yx7ZwLUgiglCe7sSisloWesO8gwgNwTGeDE0fTHhk1kZmO0BxZ8q6/VxlmLgXTyqdRso+6wfsTo2HukMURJSNw== - dependencies: - "@antv/g-lite" "2.2.2" - "@antv/util" "^3.3.5" - "@babel/runtime" "^7.25.6" - tslib "^2.5.3" - -"@antv/g2-extension-plot@^0.2.0": - version "0.2.1" - resolved "https://registry.yarnpkg.com/@antv/g2-extension-plot/-/g2-extension-plot-0.2.1.tgz#664a3cdf2d4d708ed1231ee90d984812b6226d29" - integrity sha512-WNv/LIUNJLwlfG8XXmKUbje9PbImtJqh36UDvuOk/uu+kmP/uMyHAXsBuu0yCOWdQgBVTVwoxszxJOCnY4mVfg== - dependencies: - "@antv/g2" "^5.1.8" - "@antv/util" "^3.3.5" - d3-array "^3.2.4" - d3-hierarchy "^3.1.2" - -"@antv/g2@^5.1.18", "@antv/g2@^5.1.8": - version "5.2.7" - resolved "https://registry.yarnpkg.com/@antv/g2/-/g2-5.2.7.tgz#fa131b0343a1a8a771b255d9efd57e2ded4a7503" - integrity sha512-bOU7ZJfa735KCqIsWWwlFtn3pc8TwJIckBhy7X8PFcxTuMIXzgqOt7vbMMdF4psBHMyIIOCDAo8zf9rGhgjEzA== - dependencies: - "@antv/component" "^2.0.0" - "@antv/coord" "^0.4.6" - "@antv/event-emitter" "^0.1.3" - "@antv/g" "^6.0.0" - "@antv/g-canvas" "^2.0.0" - "@antv/g-plugin-dragndrop" "^2.0.0" - "@antv/scale" "^0.4.12" - "@antv/util" "^3.3.5" - d3-array "^3.2.4" - d3-dsv "^3.0.1" - d3-force "^3.0.0" - d3-format "^3.1.0" - d3-geo "^3.1.0" - d3-hierarchy "^3.1.2" - d3-path "^3.1.0" - d3-scale-chromatic "^3.0.0" - d3-shape "^3.2.0" - flru "^1.0.2" - fmin "^0.0.2" - pdfast "^0.2.0" - -"@antv/g6-extension-react@^0.1.7": - version "0.1.7" - resolved "https://registry.yarnpkg.com/@antv/g6-extension-react/-/g6-extension-react-0.1.7.tgz#d0cf5cb2584383c47bd4d6fd3a5caeeca3943e11" - integrity sha512-fKk1weq2odHSTi5i8iSg9/keDPbufryA2TZ2X2j+qkSAwxJ7WtURagV/7/CUN9r1tMMk1eoiuzQZXdvc72a1GA== - dependencies: - "@antv/g" "^6.0.13" - "@antv/g-svg" "^2.0.11" - "@antv/react-g" "^2.0.14" - -"@antv/g6@^5.0.24", "@antv/g6@^5.0.28": - version "5.0.30" - resolved "https://registry.yarnpkg.com/@antv/g6/-/g6-5.0.30.tgz#0e241100bc0519ba0bf2c0ab11cb80a576f1796d" - integrity sha512-QEpNNAz/DcSnyHMJJ1UNSVjKgbfJ0zhwHcq8I/+f/mZl87oK1GlcRi8FCVcPGBb+W3OH8xfH5GIjPxEPma1kxg== - dependencies: - "@antv/algorithm" "^0.1.26" - "@antv/component" "^2.1.1" - "@antv/event-emitter" "^0.1.3" - "@antv/g" "^6.1.7" - "@antv/g-canvas" "^2.0.24" - "@antv/g-plugin-dragndrop" "^2.0.18" - "@antv/graphlib" "^2.0.3" - "@antv/hierarchy" "^0.6.14" - "@antv/layout" "1.2.14-beta.9" - "@antv/util" "^3.3.10" - bubblesets-js "^2.3.4" - hull.js "^1.0.6" - -"@antv/g@6.1.7", "@antv/g@^6.0.13", "@antv/g@^6.1.7": - version "6.1.7" - resolved "https://registry.yarnpkg.com/@antv/g/-/g-6.1.7.tgz#3003b2532c4287f2208537bcca87bffd0e44c30a" - integrity sha512-qv8YnBKqX3Yjs85U9OnBa6E92tNAI3cKrBhDrI5EikzjVPqfcVQLx0P5Zo8uzCYt7m9jFpJCi/iaGvWX/fA14Q== - dependencies: - "@antv/g-camera-api" "2.0.21" - "@antv/g-dom-mutation-observer-api" "2.0.18" - "@antv/g-lite" "2.2.2" - "@antv/g-web-animations-api" "2.1.7" - "@babel/runtime" "^7.25.6" - -"@antv/g@^6.0.0", "@antv/g@^6.1.2": - version "6.1.4" - resolved "https://registry.yarnpkg.com/@antv/g/-/g-6.1.4.tgz#4279fc065ab2fe4581874fddb06c46ce5c58c841" - integrity sha512-YHiYqu1nmYFdzImvfHA8E2ZhwjLHljNsQ0D1jT5ONV/CX5S7PMINpjfB/6D+HqZuDS/umLGmfPqpk1lqjvPW9A== - dependencies: - "@antv/g-camera-api" "2.0.18" - "@antv/g-dom-mutation-observer-api" "2.0.15" - "@antv/g-lite" "2.1.4" - "@antv/g-web-animations-api" "2.1.4" - "@babel/runtime" "^7.25.6" - -"@antv/graphin@^3.0.2": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@antv/graphin/-/graphin-3.0.4.tgz#33f4ead798d8f1fa1bf885247c68ca94d18e17c4" - integrity sha512-7ce6RDI5Z6ud93yiyS7b+mmFrHJhlkwwNo53kb7P7KoCsnV7ioMONDE6Gw0ROeMSR6TwHtxGZUhHw9wxnPp82Q== - dependencies: - "@antv/g6" "^5.0.28" - -"@antv/graphlib@^2.0.0", "@antv/graphlib@^2.0.3": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@antv/graphlib/-/graphlib-2.0.3.tgz#493e05872851c897e2133b0968cf5c6f4f6c022e" - integrity sha512-EtQR+DIfsYy28tumTnH560v7yIzXZq0nSgFBZh76mMiV1oHEN1L4p6JKu7IMtILH14mDqzmYYYFetYoAODoQUw== - dependencies: - "@antv/event-emitter" "^0.1.3" - -"@antv/hierarchy@^0.6.14": - version "0.6.14" - resolved "https://registry.yarnpkg.com/@antv/hierarchy/-/hierarchy-0.6.14.tgz#4e8b4966c9c2a44aaa6f9da7008c4bd44d490385" - integrity sha512-V3uknf7bhynOqQDw2sg+9r9DwZ9pc6k/EcqyTFdfXB1+ydr7urisP0MipIuimucvQKN+Qkd+d6w601r1UIroqQ== - -"@antv/layout@1.2.14-beta.9": - version "1.2.14-beta.9" - resolved "https://registry.yarnpkg.com/@antv/layout/-/layout-1.2.14-beta.9.tgz#5c66a0f22158c545aabd1654a50bfc8c3bf93f98" - integrity sha512-wPlwBFMtq2lWZFc89/7Lzb8fjHnyKVZZ9zBb2h+zZIP0YWmVmHRE8+dqCiPKOyOGUXEdDtn813f1g107dCHZlg== - dependencies: - "@antv/event-emitter" "^0.1.3" - "@antv/graphlib" "^2.0.0" - "@antv/util" "^3.3.2" - "@naoak/workerize-transferable" "^0.1.0" - comlink "^4.4.1" - d3-force "^3.0.0" - d3-force-3d "^3.0.5" - d3-octree "^1.0.2" - d3-quadtree "^3.0.1" - dagre "^0.8.5" - ml-matrix "^6.10.4" - tslib "^2.5.0" - -"@antv/react-g@^2.0.14": - version "2.0.23" - resolved "https://registry.yarnpkg.com/@antv/react-g/-/react-g-2.0.23.tgz#74df2fb27eba3144fd914baf51b9607233b4b670" - integrity sha512-Cur5/B6kRRK7kxj5USsEobKcGAGoWG9fDltVJ/3m95kMN95Ayx2rbVFxc5NavTrnmhxO4OUkRIyb0PDBFApfQA== - dependencies: - "@antv/g" "6.1.7" - "@antv/util" "^3.3.5" - "@babel/runtime" "^7.25.6" - gl-matrix "^3.4.3" - react-reconciler "^0.26.2" - scheduler "^0.20.2" - tslib "^2.5.3" - -"@antv/scale@^0.4.12", "@antv/scale@^0.4.3": - version "0.4.16" - resolved "https://registry.yarnpkg.com/@antv/scale/-/scale-0.4.16.tgz#60557470668ccfe5217e482a01f05c0cbb706b62" - integrity sha512-5wg/zB5kXHxpTV5OYwJD3ja6R8yTiqIOkjOhmpEJiowkzRlbEC/BOyMvNUq5fqFIHnMCE9woO7+c3zxEQCKPjw== - dependencies: - "@antv/util" "^3.3.7" - color-string "^1.5.5" - fecha "^4.2.1" - -"@antv/util@^2.0.13": - version "2.0.17" - resolved "https://registry.yarnpkg.com/@antv/util/-/util-2.0.17.tgz#e8ef42aca7892815b229269f3dd10c6b3c7597a9" - integrity sha512-o6I9hi5CIUvLGDhth0RxNSFDRwXeywmt6ExR4+RmVAzIi48ps6HUy+svxOCayvrPBN37uE6TAc2KDofRo0nK9Q== - dependencies: - csstype "^3.0.8" - tslib "^2.0.3" - -"@antv/util@^3.3.10", "@antv/util@^3.3.2", "@antv/util@^3.3.5", "@antv/util@^3.3.7": - version "3.3.10" - resolved "https://registry.yarnpkg.com/@antv/util/-/util-3.3.10.tgz#6fb2560c0f42df61f824e1f995a1ed1bdb00eb9a" - integrity sha512-basGML3DFA3O87INnzvDStjzS+n0JLEhRnRsDzP9keiXz8gT1z/fTdmJAZFOzMMWxy+HKbi7NbSt0+8vz/OsBQ== - dependencies: - fast-deep-equal "^3.1.3" - gl-matrix "^3.3.0" - tslib "^2.3.1" - "@ardatan/relay-compiler@12.0.0": version "12.0.0" resolved "https://registry.yarnpkg.com/@ardatan/relay-compiler/-/relay-compiler-12.0.0.tgz#2e4cca43088e807adc63450e8cab037020e91106" @@ -770,10 +211,10 @@ regexpu-core "^6.1.1" semver "^6.3.1" -"@babel/helper-define-polyfill-provider@^0.6.2": - version "0.6.2" - resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz#18594f789c3594acb24cfdb4a7f7b7d2e8bd912d" - integrity sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ== +"@babel/helper-define-polyfill-provider@^0.6.2", "@babel/helper-define-polyfill-provider@^0.6.3": + version "0.6.3" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.3.tgz#f4f2792fae2ef382074bc2d713522cf24e6ddb21" + integrity sha512-HK7Bi+Hj6H+VTHA3ZvBis7V/6hu9QuTrnMXNybfUf2iiuU/N97I8VjB+KbhFF8Rld/Lx5MzoCwPCpPjfK+n8Cg== dependencies: "@babel/helper-compilation-targets" "^7.22.6" "@babel/helper-plugin-utils" "^7.22.5" @@ -1634,7 +1075,7 @@ "@babel/plugin-transform-modules-commonjs" "^7.25.9" "@babel/plugin-transform-typescript" "^7.25.9" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.10.1", "@babel/runtime@^7.10.4", "@babel/runtime@^7.11.1", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.16.7", "@babel/runtime@^7.18.0", "@babel/runtime@^7.18.3", "@babel/runtime@^7.20.0", "@babel/runtime@^7.20.13", "@babel/runtime@^7.20.7", "@babel/runtime@^7.21.0", "@babel/runtime@^7.22.5", "@babel/runtime@^7.23.2", "@babel/runtime@^7.23.6", "@babel/runtime@^7.23.9", "@babel/runtime@^7.24.4", "@babel/runtime@^7.24.7", "@babel/runtime@^7.24.8", "@babel/runtime@^7.25.6", "@babel/runtime@^7.25.7", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": +"@babel/runtime@^7.0.0", "@babel/runtime@^7.10.1", "@babel/runtime@^7.10.4", "@babel/runtime@^7.11.1", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.16.7", "@babel/runtime@^7.18.0", "@babel/runtime@^7.18.3", "@babel/runtime@^7.20.0", "@babel/runtime@^7.20.13", "@babel/runtime@^7.20.7", "@babel/runtime@^7.21.0", "@babel/runtime@^7.22.5", "@babel/runtime@^7.23.2", "@babel/runtime@^7.23.6", "@babel/runtime@^7.23.9", "@babel/runtime@^7.24.4", "@babel/runtime@^7.24.7", "@babel/runtime@^7.24.8", "@babel/runtime@^7.25.7", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": version "7.26.0" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.26.0.tgz#8600c2f595f277c60815256418b85356a65173c1" integrity sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw== @@ -1698,23 +1139,6 @@ resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413" integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow== -"@emotion/is-prop-valid@1.2.2": - version "1.2.2" - resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.2.2.tgz#d4175076679c6a26faa92b03bb786f9e52612337" - integrity sha512-uNsoYd37AFmaCdXlg6EYD1KaPOaRWRByMCYzbKUX4+hhMfrxdVSelShywL4JVaAeM/eHUOSprYBQls+/neX3pw== - dependencies: - "@emotion/memoize" "^0.8.1" - -"@emotion/memoize@^0.8.1": - version "0.8.1" - resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.8.1.tgz#c1ddb040429c6d21d38cc945fe75c818cfb68e17" - integrity sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA== - -"@emotion/unitless@0.8.1": - version "0.8.1" - resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.8.1.tgz#182b5a4704ef8ad91bde93f7a860a88fd92c79a3" - integrity sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ== - "@emotion/unitless@^0.7.5": version "0.7.5" resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed" @@ -1770,9 +1194,9 @@ "@floating-ui/dom" "^1.0.0" "@floating-ui/react@^0.26.16": - version "0.26.27" - resolved "https://registry.yarnpkg.com/@floating-ui/react/-/react-0.26.27.tgz#402f7b4b2702650662705fe9cbe0f1d5607846a1" - integrity sha512-jLP72x0Kr2CgY6eTYi/ra3VA9LOkTo4C+DUTrbFgFOExKy3omYVmwMjNKqxAHdsnyLS96BIDLcO2SlnsNf8KUQ== + version "0.26.28" + resolved "https://registry.yarnpkg.com/@floating-ui/react/-/react-0.26.28.tgz#93f44ebaeb02409312e9df9507e83aab4a8c0dc7" + integrity sha512-yORQuuAtVpiRjpMhdc0wJj06b9JFjrYF4qp96j++v2NBpbi6SEGF7donUJ3TMieerQ6qVkAv1tgr7L4r5roTqw== dependencies: "@floating-ui/react-dom" "^2.1.2" "@floating-ui/utils" "^0.2.8" @@ -2009,9 +1433,9 @@ "@tanstack/react-virtual" "^3.8.1" "@heroicons/react@^2.0.18": - version "2.1.5" - resolved "https://registry.yarnpkg.com/@heroicons/react/-/react-2.1.5.tgz#1e13f34976cc542deae92353c01c8b3d7942e9ba" - integrity sha512-FuzFN+BsHa+7OxbvAERtgBTNeZpUjgM/MIizfVkSCL2/edriN0Hx/DWRCR//aPYwO5QX/YlgLGXk+E3PcfZwjA== + version "2.2.0" + resolved "https://registry.yarnpkg.com/@heroicons/react/-/react-2.2.0.tgz#0c05124af50434a800773abec8d3af6a297d904b" + integrity sha512-LMcepvRaS9LYHJGsF0zzmgKCUim/X3N/DQKc4jepAXJ7l8QxJ1PmxJzqplF2Z3FE4PqBAIGyJAQ/w4B5dsqbtQ== "@humanwhocodes/config-array@^0.5.0": version "0.5.0" @@ -2091,20 +1515,6 @@ dependencies: "@lezer/common" "^1.0.0" -"@ljharb/resumer@~0.0.1": - version "0.0.1" - resolved "https://registry.yarnpkg.com/@ljharb/resumer/-/resumer-0.0.1.tgz#8a940a9192dd31f6a1df17564bbd26dc6ad3e68d" - integrity sha512-skQiAOrCfO7vRTq53cxznMpks7wS1va95UCidALlOVWqvBAzwPVErwizDwoMqNVMEn1mDq0utxZd02eIrvF1lw== - dependencies: - "@ljharb/through" "^2.3.9" - -"@ljharb/through@^2.3.9", "@ljharb/through@~2.3.9": - version "2.3.13" - resolved "https://registry.yarnpkg.com/@ljharb/through/-/through-2.3.13.tgz#b7e4766e0b65aa82e529be945ab078de79874edc" - integrity sha512-/gKJun8NNiWGZJkGzI/Ragc53cOdcLNdzjLaIa+GEjguQs0ulsurx8WN0jijdK9yPqDvziX995sMRLyLt1uZMQ== - dependencies: - call-bind "^1.0.7" - "@lmdb/lmdb-darwin-arm64@2.5.2": version "2.5.2" resolved "https://registry.yarnpkg.com/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-2.5.2.tgz#bc66fa43286b5c082e8fee0eacc17995806b6fbe" @@ -2248,11 +1658,6 @@ resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.3.tgz#0aa5502d547b57abfc4ac492de68e2006e417242" integrity sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ== -"@naoak/workerize-transferable@^0.1.0": - version "0.1.0" - resolved "https://registry.yarnpkg.com/@naoak/workerize-transferable/-/workerize-transferable-0.1.0.tgz#864cc8241b977bffd8661c0be1441da9b4bfb633" - integrity sha512-fDLfuP71IPNP5+zSfxFb52OHgtjZvauRJWbVnpzQ7G7BjcbLjTny0OW1d3ZO806XKpLWNKmeeW3MhE0sy8iwYQ== - "@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1": version "5.1.1-v1" resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz#dbf733a965ca47b1973177dc0bb6c889edcfb129" @@ -2562,88 +1967,94 @@ "@parcel/source-map" "^2.1.1" chalk "^4.1.0" -"@parcel/watcher-android-arm64@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.4.1.tgz#c2c19a3c442313ff007d2d7a9c2c1dd3e1c9ca84" - integrity sha512-LOi/WTbbh3aTn2RYddrO8pnapixAziFl6SMxHM69r3tvdSm94JtCenaKgk1GRg5FJ5wpMCpHeW+7yqPlvZv7kg== +"@parcel/watcher-android-arm64@2.5.0": + version "2.5.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.0.tgz#e32d3dda6647791ee930556aee206fcd5ea0fb7a" + integrity sha512-qlX4eS28bUcQCdribHkg/herLe+0A9RyYC+mm2PXpncit8z5b3nSqGVzMNR3CmtAOgRutiZ02eIJJgP/b1iEFQ== -"@parcel/watcher-darwin-arm64@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.4.1.tgz#c817c7a3b4f3a79c1535bfe54a1c2818d9ffdc34" - integrity sha512-ln41eihm5YXIY043vBrrHfn94SIBlqOWmoROhsMVTSXGh0QahKGy77tfEywQ7v3NywyxBBkGIfrWRHm0hsKtzA== +"@parcel/watcher-darwin-arm64@2.5.0": + version "2.5.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.0.tgz#0d9e680b7e9ec1c8f54944f1b945aa8755afb12f" + integrity sha512-hyZ3TANnzGfLpRA2s/4U1kbw2ZI4qGxaRJbBH2DCSREFfubMswheh8TeiC1sGZ3z2jUf3s37P0BBlrD3sjVTUw== -"@parcel/watcher-darwin-x64@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.4.1.tgz#1a3f69d9323eae4f1c61a5f480a59c478d2cb020" - integrity sha512-yrw81BRLjjtHyDu7J61oPuSoeYWR3lDElcPGJyOvIXmor6DEo7/G2u1o7I38cwlcoBHQFULqF6nesIX3tsEXMg== +"@parcel/watcher-darwin-x64@2.5.0": + version "2.5.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.0.tgz#f9f1d5ce9d5878d344f14ef1856b7a830c59d1bb" + integrity sha512-9rhlwd78saKf18fT869/poydQK8YqlU26TMiNg7AIu7eBp9adqbJZqmdFOsbZ5cnLp5XvRo9wcFmNHgHdWaGYA== -"@parcel/watcher-freebsd-x64@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.4.1.tgz#0d67fef1609f90ba6a8a662bc76a55fc93706fc8" - integrity sha512-TJa3Pex/gX3CWIx/Co8k+ykNdDCLx+TuZj3f3h7eOjgpdKM+Mnix37RYsYU4LHhiYJz3DK5nFCCra81p6g050w== +"@parcel/watcher-freebsd-x64@2.5.0": + version "2.5.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.0.tgz#2b77f0c82d19e84ff4c21de6da7f7d096b1a7e82" + integrity sha512-syvfhZzyM8kErg3VF0xpV8dixJ+RzbUaaGaeb7uDuz0D3FK97/mZ5AJQ3XNnDsXX7KkFNtyQyFrXZzQIcN49Tw== -"@parcel/watcher-linux-arm-glibc@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.4.1.tgz#ce5b340da5829b8e546bd00f752ae5292e1c702d" - integrity sha512-4rVYDlsMEYfa537BRXxJ5UF4ddNwnr2/1O4MHM5PjI9cvV2qymvhwZSFgXqbS8YoTk5i/JR0L0JDs69BUn45YA== +"@parcel/watcher-linux-arm-glibc@2.5.0": + version "2.5.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.0.tgz#92ed322c56dbafa3d2545dcf2803334aee131e42" + integrity sha512-0VQY1K35DQET3dVYWpOaPFecqOT9dbuCfzjxoQyif1Wc574t3kOSkKevULddcR9znz1TcklCE7Ht6NIxjvTqLA== -"@parcel/watcher-linux-arm64-glibc@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.4.1.tgz#6d7c00dde6d40608f9554e73998db11b2b1ff7c7" - integrity sha512-BJ7mH985OADVLpbrzCLgrJ3TOpiZggE9FMblfO65PlOCdG++xJpKUJ0Aol74ZUIYfb8WsRlUdgrZxKkz3zXWYA== +"@parcel/watcher-linux-arm-musl@2.5.0": + version "2.5.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.0.tgz#cd48e9bfde0cdbbd2ecd9accfc52967e22f849a4" + integrity sha512-6uHywSIzz8+vi2lAzFeltnYbdHsDm3iIB57d4g5oaB9vKwjb6N6dRIgZMujw4nm5r6v9/BQH0noq6DzHrqr2pA== -"@parcel/watcher-linux-arm64-musl@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.4.1.tgz#bd39bc71015f08a4a31a47cd89c236b9d6a7f635" - integrity sha512-p4Xb7JGq3MLgAfYhslU2SjoV9G0kI0Xry0kuxeG/41UfpjHGOhv7UoUDAz/jb1u2elbhazy4rRBL8PegPJFBhA== +"@parcel/watcher-linux-arm64-glibc@2.5.0": + version "2.5.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.0.tgz#7b81f6d5a442bb89fbabaf6c13573e94a46feb03" + integrity sha512-BfNjXwZKxBy4WibDb/LDCriWSKLz+jJRL3cM/DllnHH5QUyoiUNEp3GmL80ZqxeumoADfCCP19+qiYiC8gUBjA== -"@parcel/watcher-linux-x64-glibc@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.4.1.tgz#0ce29966b082fb6cdd3de44f2f74057eef2c9e39" - integrity sha512-s9O3fByZ/2pyYDPoLM6zt92yu6P4E39a03zvO0qCHOTjxmt3GHRMLuRZEWhWLASTMSrrnVNWdVI/+pUElJBBBg== +"@parcel/watcher-linux-arm64-musl@2.5.0": + version "2.5.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.0.tgz#dcb8ff01077cdf59a18d9e0a4dff7a0cfe5fd732" + integrity sha512-S1qARKOphxfiBEkwLUbHjCY9BWPdWnW9j7f7Hb2jPplu8UZ3nes7zpPOW9bkLbHRvWM0WDTsjdOTUgW0xLBN1Q== -"@parcel/watcher-linux-x64-musl@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.4.1.tgz#d2ebbf60e407170bb647cd6e447f4f2bab19ad16" - integrity sha512-L2nZTYR1myLNST0O632g0Dx9LyMNHrn6TOt76sYxWLdff3cB22/GZX2UPtJnaqQPdCRoszoY5rcOj4oMTtp5fQ== +"@parcel/watcher-linux-x64-glibc@2.5.0": + version "2.5.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.0.tgz#2e254600fda4e32d83942384d1106e1eed84494d" + integrity sha512-d9AOkusyXARkFD66S6zlGXyzx5RvY+chTP9Jp0ypSTC9d4lzyRs9ovGf/80VCxjKddcUvnsGwCHWuF2EoPgWjw== -"@parcel/watcher-win32-arm64@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.4.1.tgz#eb4deef37e80f0b5e2f215dd6d7a6d40a85f8adc" - integrity sha512-Uq2BPp5GWhrq/lcuItCHoqxjULU1QYEcyjSO5jqqOK8RNFDBQnenMMx4gAl3v8GiWa59E9+uDM7yZ6LxwUIfRg== +"@parcel/watcher-linux-x64-musl@2.5.0": + version "2.5.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.0.tgz#01fcea60fedbb3225af808d3f0a7b11229792eef" + integrity sha512-iqOC+GoTDoFyk/VYSFHwjHhYrk8bljW6zOhPuhi5t9ulqiYq1togGJB5e3PwYVFFfeVgc6pbz3JdQyDoBszVaA== -"@parcel/watcher-win32-ia32@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.4.1.tgz#94fbd4b497be39fd5c8c71ba05436927842c9df7" - integrity sha512-maNRit5QQV2kgHFSYwftmPBxiuK5u4DXjbXx7q6eKjq5dsLXZ4FJiVvlcw35QXzk0KrUecJmuVFbj4uV9oYrcw== +"@parcel/watcher-win32-arm64@2.5.0": + version "2.5.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.0.tgz#87cdb16e0783e770197e52fb1dc027bb0c847154" + integrity sha512-twtft1d+JRNkM5YbmexfcH/N4znDtjgysFaV9zvZmmJezQsKpkfLYJ+JFV3uygugK6AtIM2oADPkB2AdhBrNig== -"@parcel/watcher-win32-x64@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.4.1.tgz#4bf920912f67cae5f2d264f58df81abfea68dadf" - integrity sha512-+DvS92F9ezicfswqrvIRM2njcYJbd5mb9CUgtrHCHmvn7pPPa+nMDRu1o1bYYz/l5IB2NVGNJWiH7h1E58IF2A== +"@parcel/watcher-win32-ia32@2.5.0": + version "2.5.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.0.tgz#778c39b56da33e045ba21c678c31a9f9d7c6b220" + integrity sha512-+rgpsNRKwo8A53elqbbHXdOMtY/tAtTzManTWShB5Kk54N8Q9mzNWV7tV+IbGueCbcj826MfWGU3mprWtuf1TA== + +"@parcel/watcher-win32-x64@2.5.0": + version "2.5.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.0.tgz#33873876d0bbc588aacce38e90d1d7480ce81cb7" + integrity sha512-lPrxve92zEHdgeff3aiu4gDOIt4u7sJYha6wbdEZDCDUhtjTsOMiaJzG5lMY4GkWH8p0fMmO2Ppq5G5XXG+DQw== "@parcel/watcher@^2.0.7": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@parcel/watcher/-/watcher-2.4.1.tgz#a50275151a1bb110879c6123589dba90c19f1bf8" - integrity sha512-HNjmfLQEVRZmHRET336f20H/8kOozUGwk7yajvsonjNxbj2wBTK1WsQuHkD5yYh9RxFGL2EyDHryOihOwUoKDA== + version "2.5.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher/-/watcher-2.5.0.tgz#5c88818b12b8de4307a9d3e6dc3e28eba0dfbd10" + integrity sha512-i0GV1yJnm2n3Yq1qw6QrUrd/LI9bE8WEBOTtOkpCXHHdyN3TAGgqAK/DAT05z4fq2x04cARXt2pDmjWjL92iTQ== dependencies: detect-libc "^1.0.3" is-glob "^4.0.3" micromatch "^4.0.5" node-addon-api "^7.0.0" optionalDependencies: - "@parcel/watcher-android-arm64" "2.4.1" - "@parcel/watcher-darwin-arm64" "2.4.1" - "@parcel/watcher-darwin-x64" "2.4.1" - "@parcel/watcher-freebsd-x64" "2.4.1" - "@parcel/watcher-linux-arm-glibc" "2.4.1" - "@parcel/watcher-linux-arm64-glibc" "2.4.1" - "@parcel/watcher-linux-arm64-musl" "2.4.1" - "@parcel/watcher-linux-x64-glibc" "2.4.1" - "@parcel/watcher-linux-x64-musl" "2.4.1" - "@parcel/watcher-win32-arm64" "2.4.1" - "@parcel/watcher-win32-ia32" "2.4.1" - "@parcel/watcher-win32-x64" "2.4.1" + "@parcel/watcher-android-arm64" "2.5.0" + "@parcel/watcher-darwin-arm64" "2.5.0" + "@parcel/watcher-darwin-x64" "2.5.0" + "@parcel/watcher-freebsd-x64" "2.5.0" + "@parcel/watcher-linux-arm-glibc" "2.5.0" + "@parcel/watcher-linux-arm-musl" "2.5.0" + "@parcel/watcher-linux-arm64-glibc" "2.5.0" + "@parcel/watcher-linux-arm64-musl" "2.5.0" + "@parcel/watcher-linux-x64-glibc" "2.5.0" + "@parcel/watcher-linux-x64-musl" "2.5.0" + "@parcel/watcher-win32-arm64" "2.5.0" + "@parcel/watcher-win32-ia32" "2.5.0" + "@parcel/watcher-win32-x64" "2.5.0" "@parcel/workers@2.8.3": version "2.8.3" @@ -2766,19 +2177,7 @@ classnames "^2.3.2" rc-util "^5.24.4" -"@rc-component/trigger@^2.0.0", "@rc-component/trigger@^2.1.1": - version "2.2.3" - resolved "https://registry.yarnpkg.com/@rc-component/trigger/-/trigger-2.2.3.tgz#b47e945115e2d0a7f7e067dbb9ed76c91c1b4385" - integrity sha512-X1oFIpKoXAMXNDYCviOmTfuNuYxE4h5laBsyCqVAVMjNHxoF3/uiyA7XdegK1XbCvBbCZ6P6byWrEoDRpKL8+A== - dependencies: - "@babel/runtime" "^7.23.2" - "@rc-component/portal" "^1.1.0" - classnames "^2.3.2" - rc-motion "^2.0.0" - rc-resize-observer "^1.3.1" - rc-util "^5.38.0" - -"@rc-component/trigger@^2.2.5": +"@rc-component/trigger@^2.0.0", "@rc-component/trigger@^2.1.1", "@rc-component/trigger@^2.2.5": version "2.2.5" resolved "https://registry.yarnpkg.com/@rc-component/trigger/-/trigger-2.2.5.tgz#5ebe383e563e667b3fa24b6b32afedbab378a92e" integrity sha512-F1EJ4KjFpGAHAjuKvOyZB/6IZDkVx0bHl0M4fQM5wXcmm7lgTgVSSnR3bXwdmS6jOJGHOqfDxIJW3WUvwMIXhQ== @@ -2791,55 +2190,55 @@ rc-util "^5.38.0" "@react-aria/focus@^3.17.1": - version "3.18.4" - resolved "https://registry.yarnpkg.com/@react-aria/focus/-/focus-3.18.4.tgz#a6e95896bc8680d1b5bcd855e983fc2c195a1a55" - integrity sha512-91J35077w9UNaMK1cpMUEFRkNNz0uZjnSwiyBCFuRdaVuivO53wNC9XtWSDNDdcO5cGy87vfJRVAiyoCn/mjqA== + version "3.19.0" + resolved "https://registry.yarnpkg.com/@react-aria/focus/-/focus-3.19.0.tgz#82b9a5b83f023b943a7970df3d059f49d61df05d" + integrity sha512-hPF9EXoUQeQl1Y21/rbV2H4FdUR2v+4/I0/vB+8U3bT1CJ+1AFj1hc/rqx2DqEwDlEwOHN+E4+mRahQmlybq0A== dependencies: - "@react-aria/interactions" "^3.22.4" - "@react-aria/utils" "^3.25.3" - "@react-types/shared" "^3.25.0" + "@react-aria/interactions" "^3.22.5" + "@react-aria/utils" "^3.26.0" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" clsx "^2.0.0" -"@react-aria/interactions@^3.21.3", "@react-aria/interactions@^3.22.4": - version "3.22.4" - resolved "https://registry.yarnpkg.com/@react-aria/interactions/-/interactions-3.22.4.tgz#88ed61ab6a485f869bc1f65ae6688d48ca96064b" - integrity sha512-E0vsgtpItmknq/MJELqYJwib+YN18Qag8nroqwjk1qOnBa9ROIkUhWJerLi1qs5diXq9LHKehZDXRlwPvdEFww== +"@react-aria/interactions@^3.21.3", "@react-aria/interactions@^3.22.5": + version "3.22.5" + resolved "https://registry.yarnpkg.com/@react-aria/interactions/-/interactions-3.22.5.tgz#9cd8c93b8b6988f1d315d3efb450119d1432bbb8" + integrity sha512-kMwiAD9E0TQp+XNnOs13yVJghiy8ET8L0cbkeuTgNI96sOAp/63EJ1FSrDf17iD8sdjt41LafwX/dKXW9nCcLQ== dependencies: - "@react-aria/ssr" "^3.9.6" - "@react-aria/utils" "^3.25.3" - "@react-types/shared" "^3.25.0" + "@react-aria/ssr" "^3.9.7" + "@react-aria/utils" "^3.26.0" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" -"@react-aria/ssr@^3.9.6": - version "3.9.6" - resolved "https://registry.yarnpkg.com/@react-aria/ssr/-/ssr-3.9.6.tgz#a9e8b351acdc8238f2b5215b0ce904636c6ea690" - integrity sha512-iLo82l82ilMiVGy342SELjshuWottlb5+VefO3jOQqQRNYnJBFpUSadswDPbRimSgJUZuFwIEYs6AabkP038fA== +"@react-aria/ssr@^3.9.7": + version "3.9.7" + resolved "https://registry.yarnpkg.com/@react-aria/ssr/-/ssr-3.9.7.tgz#d89d129f7bbc5148657e6c952ac31c9353183770" + integrity sha512-GQygZaGlmYjmYM+tiNBA5C6acmiDWF52Nqd40bBp0Znk4M4hP+LTmI0lpI1BuKMw45T8RIhrAsICIfKwZvi2Gg== dependencies: "@swc/helpers" "^0.5.0" -"@react-aria/utils@^3.25.3": - version "3.25.3" - resolved "https://registry.yarnpkg.com/@react-aria/utils/-/utils-3.25.3.tgz#cad9bffc07b045cdc283df2cb65c18747acbf76d" - integrity sha512-PR5H/2vaD8fSq0H/UB9inNbc8KDcVmW6fYAfSWkkn+OAdhTTMVKqXXrZuZBWyFfSD5Ze7VN6acr4hrOQm2bmrA== +"@react-aria/utils@^3.26.0": + version "3.26.0" + resolved "https://registry.yarnpkg.com/@react-aria/utils/-/utils-3.26.0.tgz#833cbfa33e75d15835b757791b3f754432d2f948" + integrity sha512-LkZouGSjjQ0rEqo4XJosS4L3YC/zzQkfRM3KoqK6fUOmUJ9t0jQ09WjiF+uOoG9u+p30AVg3TrZRUWmoTS+koQ== dependencies: - "@react-aria/ssr" "^3.9.6" - "@react-stately/utils" "^3.10.4" - "@react-types/shared" "^3.25.0" + "@react-aria/ssr" "^3.9.7" + "@react-stately/utils" "^3.10.5" + "@react-types/shared" "^3.26.0" "@swc/helpers" "^0.5.0" clsx "^2.0.0" -"@react-stately/utils@^3.10.4": - version "3.10.4" - resolved "https://registry.yarnpkg.com/@react-stately/utils/-/utils-3.10.4.tgz#310663a834b67048d305e1680ed258130092fe51" - integrity sha512-gBEQEIMRh5f60KCm7QKQ2WfvhB2gLUr9b72sqUdIZ2EG+xuPgaIlCBeSicvjmjBvYZwOjoOEnmIkcx2GHp/HWw== +"@react-stately/utils@^3.10.5": + version "3.10.5" + resolved "https://registry.yarnpkg.com/@react-stately/utils/-/utils-3.10.5.tgz#47bb91cd5afd1bafe39353614e5e281b818ebccc" + integrity sha512-iMQSGcpaecghDIh3mZEpZfoFH3ExBwTtuBEcvZ2XnGzCgQjeYXcMdIUwAfVQLXFTdHUHGF6Gu6/dFrYsCzySBQ== dependencies: "@swc/helpers" "^0.5.0" -"@react-types/shared@^3.25.0": - version "3.25.0" - resolved "https://registry.yarnpkg.com/@react-types/shared/-/shared-3.25.0.tgz#7223baf72256e918a3c29081bb1ecc6fad4fbf58" - integrity sha512-OZSyhzU6vTdW3eV/mz5i6hQwQUhkRs7xwY2d1aqPvTdMe0+2cY7Fwp45PAiwYLEj73i9ro2FxF9qC4DvHGSCgQ== +"@react-types/shared@^3.26.0": + version "3.26.0" + resolved "https://registry.yarnpkg.com/@react-types/shared/-/shared-3.26.0.tgz#21a8b579f0097ee78de18e3e580421ced89e4c8c" + integrity sha512-6FuPqvhmjjlpEDLTiYx29IJCbCNWPlsyO+ZUmCUXzhUv2ttShOXfw8CmeHWHftT/b2KweAWuzqSlfeXPR76jpw== "@rtsao/scc@^1.1.0": version "1.1.0" @@ -3216,10 +2615,10 @@ resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.34.tgz#10964ba0dee6ac4cd462e2795b6bebd407303433" integrity sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g== -"@types/node@*", "@types/node@>=10.0.0": - version "22.8.6" - resolved "https://registry.yarnpkg.com/@types/node/-/node-22.8.6.tgz#e8a0c0871623283d8b3ef7d7b9b1bfdfd3028e22" - integrity sha512-tosuJYKrIqjQIlVCM4PEGxOmyg3FCPa/fViuJChnGeEIhjA46oy8FMVoF9su1/v8PNs2a8Q0iFNyOx0uOF91nw== +"@types/node@*", "@types/node@>=10.0.0", "@types/node@^22.9.0": + version "22.9.2" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.9.2.tgz#51e58f2bf29cc38f529dacbb0eafca890464138e" + integrity sha512-wwuxAVEbsRvDD9x7buvAl7DyQ7Oj+va/d/Veug7higYzp9MF0CINbfWTBgDFMpcVwcdUiYuNmX2KfnvY3N70mw== dependencies: undici-types "~6.19.8" @@ -3228,13 +2627,6 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.45.tgz#2c0fafd78705e7a18b7906b5201a522719dc5190" integrity sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw== -"@types/node@^22.9.0": - version "22.9.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-22.9.0.tgz#b7f16e5c3384788542c72dc3d561a7ceae2c0365" - integrity sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ== - dependencies: - undici-types "~6.19.8" - "@types/node@^8.5.7": version "8.10.66" resolved "https://registry.yarnpkg.com/@types/node/-/node-8.10.66.tgz#dd035d409df322acc83dff62a602f12a5783bbb3" @@ -3306,11 +2698,6 @@ resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.8.tgz#8268a8c57a3e4abd25c165ecd36237db7948a55e" integrity sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ== -"@types/stylis@4.2.5": - version "4.2.5" - resolved "https://registry.yarnpkg.com/@types/stylis/-/stylis-4.2.5.tgz#1daa6456f40959d06157698a653a9ab0a70281df" - integrity sha512-1Xve+NMN7FWjY14vLoY5tL3BVEQ/n42YLwaqJIPYhotZ9uBHt87VceMwWQpzmdEt2TNXIorIFG+YeCUUW7RInw== - "@types/tmp@^0.0.33": version "0.0.33" resolved "https://registry.yarnpkg.com/@types/tmp/-/tmp-0.0.33.tgz#1073c4bc824754ae3d10cfab88ab0237ba964e4d" @@ -3432,125 +2819,125 @@ dependencies: resolve "^1.10.0" -"@webassemblyjs/ast@1.12.1", "@webassemblyjs/ast@^1.12.1": - version "1.12.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.12.1.tgz#bb16a0e8b1914f979f45864c23819cc3e3f0d4bb" - integrity sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg== +"@webassemblyjs/ast@1.14.1", "@webassemblyjs/ast@^1.12.1": + version "1.14.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.14.1.tgz#a9f6a07f2b03c95c8d38c4536a1fdfb521ff55b6" + integrity sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ== dependencies: - "@webassemblyjs/helper-numbers" "1.11.6" - "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/helper-numbers" "1.13.2" + "@webassemblyjs/helper-wasm-bytecode" "1.13.2" -"@webassemblyjs/floating-point-hex-parser@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz#dacbcb95aff135c8260f77fa3b4c5fea600a6431" - integrity sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw== +"@webassemblyjs/floating-point-hex-parser@1.13.2": + version "1.13.2" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz#fcca1eeddb1cc4e7b6eed4fc7956d6813b21b9fb" + integrity sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA== -"@webassemblyjs/helper-api-error@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz#6132f68c4acd59dcd141c44b18cbebbd9f2fa768" - integrity sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q== +"@webassemblyjs/helper-api-error@1.13.2": + version "1.13.2" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz#e0a16152248bc38daee76dd7e21f15c5ef3ab1e7" + integrity sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ== -"@webassemblyjs/helper-buffer@1.12.1": - version "1.12.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz#6df20d272ea5439bf20ab3492b7fb70e9bfcb3f6" - integrity sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw== +"@webassemblyjs/helper-buffer@1.14.1": + version "1.14.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz#822a9bc603166531f7d5df84e67b5bf99b72b96b" + integrity sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA== -"@webassemblyjs/helper-numbers@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz#cbce5e7e0c1bd32cf4905ae444ef64cea919f1b5" - integrity sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g== +"@webassemblyjs/helper-numbers@1.13.2": + version "1.13.2" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz#dbd932548e7119f4b8a7877fd5a8d20e63490b2d" + integrity sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA== dependencies: - "@webassemblyjs/floating-point-hex-parser" "1.11.6" - "@webassemblyjs/helper-api-error" "1.11.6" + "@webassemblyjs/floating-point-hex-parser" "1.13.2" + "@webassemblyjs/helper-api-error" "1.13.2" "@xtuc/long" "4.2.2" -"@webassemblyjs/helper-wasm-bytecode@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz#bb2ebdb3b83aa26d9baad4c46d4315283acd51e9" - integrity sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA== +"@webassemblyjs/helper-wasm-bytecode@1.13.2": + version "1.13.2" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz#e556108758f448aae84c850e593ce18a0eb31e0b" + integrity sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA== -"@webassemblyjs/helper-wasm-section@1.12.1": - version "1.12.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz#3da623233ae1a60409b509a52ade9bc22a37f7bf" - integrity sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g== +"@webassemblyjs/helper-wasm-section@1.14.1": + version "1.14.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz#9629dda9c4430eab54b591053d6dc6f3ba050348" + integrity sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw== dependencies: - "@webassemblyjs/ast" "1.12.1" - "@webassemblyjs/helper-buffer" "1.12.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.6" - "@webassemblyjs/wasm-gen" "1.12.1" + "@webassemblyjs/ast" "1.14.1" + "@webassemblyjs/helper-buffer" "1.14.1" + "@webassemblyjs/helper-wasm-bytecode" "1.13.2" + "@webassemblyjs/wasm-gen" "1.14.1" -"@webassemblyjs/ieee754@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz#bb665c91d0b14fffceb0e38298c329af043c6e3a" - integrity sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg== +"@webassemblyjs/ieee754@1.13.2": + version "1.13.2" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz#1c5eaace1d606ada2c7fd7045ea9356c59ee0dba" + integrity sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw== dependencies: "@xtuc/ieee754" "^1.2.0" -"@webassemblyjs/leb128@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.6.tgz#70e60e5e82f9ac81118bc25381a0b283893240d7" - integrity sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ== +"@webassemblyjs/leb128@1.13.2": + version "1.13.2" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.13.2.tgz#57c5c3deb0105d02ce25fa3fd74f4ebc9fd0bbb0" + integrity sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw== dependencies: "@xtuc/long" "4.2.2" -"@webassemblyjs/utf8@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.6.tgz#90f8bc34c561595fe156603be7253cdbcd0fab5a" - integrity sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA== +"@webassemblyjs/utf8@1.13.2": + version "1.13.2" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.13.2.tgz#917a20e93f71ad5602966c2d685ae0c6c21f60f1" + integrity sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ== "@webassemblyjs/wasm-edit@^1.12.1": - version "1.12.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz#9f9f3ff52a14c980939be0ef9d5df9ebc678ae3b" - integrity sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g== - dependencies: - "@webassemblyjs/ast" "1.12.1" - "@webassemblyjs/helper-buffer" "1.12.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.6" - "@webassemblyjs/helper-wasm-section" "1.12.1" - "@webassemblyjs/wasm-gen" "1.12.1" - "@webassemblyjs/wasm-opt" "1.12.1" - "@webassemblyjs/wasm-parser" "1.12.1" - "@webassemblyjs/wast-printer" "1.12.1" - -"@webassemblyjs/wasm-gen@1.12.1": - version "1.12.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz#a6520601da1b5700448273666a71ad0a45d78547" - integrity sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w== - dependencies: - "@webassemblyjs/ast" "1.12.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.6" - "@webassemblyjs/ieee754" "1.11.6" - "@webassemblyjs/leb128" "1.11.6" - "@webassemblyjs/utf8" "1.11.6" - -"@webassemblyjs/wasm-opt@1.12.1": - version "1.12.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz#9e6e81475dfcfb62dab574ac2dda38226c232bc5" - integrity sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg== - dependencies: - "@webassemblyjs/ast" "1.12.1" - "@webassemblyjs/helper-buffer" "1.12.1" - "@webassemblyjs/wasm-gen" "1.12.1" - "@webassemblyjs/wasm-parser" "1.12.1" - -"@webassemblyjs/wasm-parser@1.12.1", "@webassemblyjs/wasm-parser@^1.12.1": - version "1.12.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz#c47acb90e6f083391e3fa61d113650eea1e95937" - integrity sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ== - dependencies: - "@webassemblyjs/ast" "1.12.1" - "@webassemblyjs/helper-api-error" "1.11.6" - "@webassemblyjs/helper-wasm-bytecode" "1.11.6" - "@webassemblyjs/ieee754" "1.11.6" - "@webassemblyjs/leb128" "1.11.6" - "@webassemblyjs/utf8" "1.11.6" - -"@webassemblyjs/wast-printer@1.12.1": - version "1.12.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz#bcecf661d7d1abdaf989d8341a4833e33e2b31ac" - integrity sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA== - dependencies: - "@webassemblyjs/ast" "1.12.1" + version "1.14.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz#ac6689f502219b59198ddec42dcd496b1004d597" + integrity sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ== + dependencies: + "@webassemblyjs/ast" "1.14.1" + "@webassemblyjs/helper-buffer" "1.14.1" + "@webassemblyjs/helper-wasm-bytecode" "1.13.2" + "@webassemblyjs/helper-wasm-section" "1.14.1" + "@webassemblyjs/wasm-gen" "1.14.1" + "@webassemblyjs/wasm-opt" "1.14.1" + "@webassemblyjs/wasm-parser" "1.14.1" + "@webassemblyjs/wast-printer" "1.14.1" + +"@webassemblyjs/wasm-gen@1.14.1": + version "1.14.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz#991e7f0c090cb0bb62bbac882076e3d219da9570" + integrity sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg== + dependencies: + "@webassemblyjs/ast" "1.14.1" + "@webassemblyjs/helper-wasm-bytecode" "1.13.2" + "@webassemblyjs/ieee754" "1.13.2" + "@webassemblyjs/leb128" "1.13.2" + "@webassemblyjs/utf8" "1.13.2" + +"@webassemblyjs/wasm-opt@1.14.1": + version "1.14.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz#e6f71ed7ccae46781c206017d3c14c50efa8106b" + integrity sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw== + dependencies: + "@webassemblyjs/ast" "1.14.1" + "@webassemblyjs/helper-buffer" "1.14.1" + "@webassemblyjs/wasm-gen" "1.14.1" + "@webassemblyjs/wasm-parser" "1.14.1" + +"@webassemblyjs/wasm-parser@1.14.1", "@webassemblyjs/wasm-parser@^1.12.1": + version "1.14.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz#b3e13f1893605ca78b52c68e54cf6a865f90b9fb" + integrity sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ== + dependencies: + "@webassemblyjs/ast" "1.14.1" + "@webassemblyjs/helper-api-error" "1.13.2" + "@webassemblyjs/helper-wasm-bytecode" "1.13.2" + "@webassemblyjs/ieee754" "1.13.2" + "@webassemblyjs/leb128" "1.13.2" + "@webassemblyjs/utf8" "1.13.2" + +"@webassemblyjs/wast-printer@1.14.1": + version "1.14.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz#3bb3e9638a8ae5fdaf9610e7a06b4d9f9aa6fe07" + integrity sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw== + dependencies: + "@webassemblyjs/ast" "1.14.1" "@xtuc/long" "4.2.2" "@xtuc/ieee754@^1.2.0": @@ -3586,9 +2973,9 @@ d3-zoom "^3.0.0" abortcontroller-polyfill@^1.1.9: - version "1.7.5" - resolved "https://registry.yarnpkg.com/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.5.tgz#6738495f4e901fbb57b6c0611d0c75f76c485bed" - integrity sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ== + version "1.7.6" + resolved "https://registry.yarnpkg.com/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.6.tgz#7be8d35b5ed7dfa1a51b36f221720b23deb13f36" + integrity sha512-Zypm+LjYdWAzvuypZvDN0smUJrhOurcuBWhhMRBExqVLRvdjp3Z9mASxKyq19K+meZMshwjjy5S0lkm388zE4Q== accepts@~1.3.4, accepts@~1.3.8: version "1.3.8" @@ -3676,20 +3063,6 @@ ajv@^8.0.0, ajv@^8.0.1, ajv@^8.9.0: json-schema-traverse "^1.0.0" require-from-string "^2.0.2" -align-text@^0.1.1, align-text@^0.1.3: - version "0.1.4" - resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" - integrity sha512-GrTZLRpmp6wIC2ztrWW9MjjTgSKccffgFagbNDOX95/dcjEcYZibYTeaOntySQLcdw1ztBoFkviiUvTMbb9MYg== - dependencies: - kind-of "^3.0.2" - longest "^1.0.1" - repeat-string "^1.5.2" - -amdefine@>=0.0.4: - version "1.0.1" - resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" - integrity sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg== - anser@^2.1.1: version "2.3.0" resolved "https://registry.yarnpkg.com/anser/-/anser-2.3.0.tgz#9b30c8cffe864e646eebd6cd578ba67f2dfe8b2e" @@ -3744,11 +3117,6 @@ ansi-regex@^6.0.1: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.1.0.tgz#95ec409c69619d6cb1b8b34f14b660ef28ebd654" integrity sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA== -ansi-styles@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" - integrity sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA== - ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" @@ -3769,9 +3137,9 @@ ansi-styles@^6.1.0: integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== antd@^5.22.1: - version "5.22.1" - resolved "https://registry.yarnpkg.com/antd/-/antd-5.22.1.tgz#726c9d4465a1f59079ef60896418fcdbb07a796c" - integrity sha512-itq8AZwe3IfawZH6SMM5XdbTz1xXGTTqA7sNN0qpEdxcoTpD5nRsCBAMIy+PhwcWFobgFc6ZlF8d7f8eicn0SQ== + version "5.22.2" + resolved "https://registry.yarnpkg.com/antd/-/antd-5.22.2.tgz#9f5d38c09685c018c368329f1a1107d5417536d6" + integrity sha512-vihhiJbm9VG3d6boUeD1q2MXMax+qBrXhgqCEC+45v8iGUF6m4Ct+lFiCW4oWaN3EABOsbVA6Svy3Rj/QkQFKw== dependencies: "@ant-design/colors" "^7.1.0" "@ant-design/cssinjs" "^1.21.1" @@ -3794,7 +3162,7 @@ antd@^5.22.1: rc-dialog "~9.6.0" rc-drawer "~7.2.0" rc-dropdown "~4.2.0" - rc-field-form "~2.5.0" + rc-field-form "~2.5.1" rc-image "~7.11.0" rc-input "~1.6.3" rc-input-number "~9.3.0" @@ -3803,7 +3171,7 @@ antd@^5.22.1: rc-motion "^2.9.3" rc-notification "~5.6.2" rc-pagination "~4.3.0" - rc-picker "~4.8.0" + rc-picker "~4.8.1" rc-progress "~4.0.0" rc-rate "~2.13.0" rc-resize-observer "^1.4.0" @@ -4097,12 +3465,12 @@ babel-plugin-macros@^3.1.0: resolve "^1.19.0" babel-plugin-polyfill-corejs2@^0.4.10: - version "0.4.11" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz#30320dfe3ffe1a336c15afdcdafd6fd615b25e33" - integrity sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q== + version "0.4.12" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.12.tgz#ca55bbec8ab0edeeef3d7b8ffd75322e210879a9" + integrity sha512-CPWT6BwvhrTO2d8QVorhTCQw9Y43zOu7G9HigcfxvepOU6b8o3tcWad6oVgZIsZCTt42FFv97aA7ZJsbM4+8og== dependencies: "@babel/compat-data" "^7.22.6" - "@babel/helper-define-polyfill-provider" "^0.6.2" + "@babel/helper-define-polyfill-provider" "^0.6.3" semver "^6.3.1" babel-plugin-polyfill-corejs3@^0.10.6: @@ -4114,11 +3482,11 @@ babel-plugin-polyfill-corejs3@^0.10.6: core-js-compat "^3.38.0" babel-plugin-polyfill-regenerator@^0.6.1: - version "0.6.2" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.2.tgz#addc47e240edd1da1058ebda03021f382bba785e" - integrity sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg== + version "0.6.3" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.3.tgz#abeb1f3f1c762eace37587f42548b08b57789bc8" + integrity sha512-LiWSbl4CRSIa5x/JAU6jZiG9eit9w6mz+yVMFwDE83LAWvt0AfGBoZ7HS/mkhrKuh2ZlzfVZYKoLjXdqw6Yt7Q== dependencies: - "@babel/helper-define-polyfill-provider" "^0.6.2" + "@babel/helper-define-polyfill-provider" "^0.6.3" babel-plugin-remove-graphql-queries@^5.14.0: version "5.14.0" @@ -4230,9 +3598,9 @@ bare-path@^2.0.0, bare-path@^2.1.0: bare-os "^2.1.0" bare-stream@^2.0.0: - version "2.3.2" - resolved "https://registry.yarnpkg.com/bare-stream/-/bare-stream-2.3.2.tgz#3bc62b429bcf850d2f265719b7a49ee0630a3ae4" - integrity sha512-EFZHSIBkDgSHIwj2l2QZfP4U5OcD4xFAOwhSb/vlr9PIqyGJGvB/nfClJbcnh3EY4jtPE4zsb5ztae96bVF79A== + version "2.4.0" + resolved "https://registry.yarnpkg.com/bare-stream/-/bare-stream-2.4.0.tgz#2bd49033b69f69a8e2be80c0676c6e27967789d8" + integrity sha512-sd96/aZ8LjF1uJbEHzIo1LrERPKRFPEy1nZ1eOILftBxrVsFDAQkimHIIq87xrHcubzjNeETsD9PwN0wp+vLiQ== dependencies: streamx "^2.20.0" @@ -4365,11 +3733,6 @@ bser@2.1.1: dependencies: node-int64 "^0.4.0" -bubblesets-js@^2.3.4: - version "2.3.4" - resolved "https://registry.yarnpkg.com/bubblesets-js/-/bubblesets-js-2.3.4.tgz#8e1230b29c309e3327a05630fe02df3d96596ab6" - integrity sha512-DyMjHmpkS2+xcFNtyN00apJYL3ESdp9fTrkDr5+9Qg/GPqFmcWgGsK1akZnttE1XFxJ/VMy4DNNGMGYtmFp1Sg== - buffer-from@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" @@ -4440,7 +3803,7 @@ cacheable-request@^7.0.2: normalize-url "^6.0.1" responselike "^2.0.0" -call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7, call-bind@~1.0.2: +call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== @@ -4469,11 +3832,6 @@ camelcase-css@^2.0.1: resolved "https://registry.yarnpkg.com/camelcase-css/-/camelcase-css-2.0.1.tgz#ee978f6947914cc30c6b44741b6ed1df7f043fd5" integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA== -camelcase@^1.0.2: - version "1.2.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" - integrity sha512-wzLkDa4K/mzI1OSITC+DUyjgIl/ETNHE9QvYgy6J6Jvqyyz4C0Xfd+lQhb19sX2jMpZV4IssUn0VDVmglV+s4g== - camelcase@^5.0.0: version "5.3.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" @@ -4484,11 +3842,6 @@ camelcase@^6.2.0, camelcase@^6.3.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== -camelize@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/camelize/-/camelize-1.0.1.tgz#89b7e16884056331a35d6b5ad064332c91daa6c3" - integrity sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ== - caniuse-api@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0" @@ -4500,9 +3853,9 @@ caniuse-api@^3.0.0: lodash.uniq "^4.5.0" caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001646, caniuse-lite@^1.0.30001669: - version "1.0.30001676" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001676.tgz#fe133d41fe74af8f7cc93b8a714c3e86a86e6f04" - integrity sha512-Qz6zwGCiPghQXGJvgQAem79esjitvJ+CxSbSQkW9H/UX5hg8XM88d4lp2W+MEQ81j+Hip58Il+jGVdazk1z9cw== + version "1.0.30001683" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001683.tgz#7f026a2d5d319a9cf8915a1451173052caaadc81" + integrity sha512-iqmNnThZ0n70mNwvxpEC2nBJ037ZHZUoBI5Gorh1Mw6IlEAZujEoU1tXA628iZfzm7R9FvFzxbfdgml82a3k8Q== capital-case@^1.0.4: version "1.0.4" @@ -4518,25 +3871,6 @@ ccount@^2.0.0: resolved "https://registry.yarnpkg.com/ccount/-/ccount-2.0.1.tgz#17a3bf82302e0870d6da43a01311a8bc02a3ecf5" integrity sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg== -center-align@^0.1.1: - version "0.1.3" - resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" - integrity sha512-Baz3aNe2gd2LP2qk5U+sDk/m4oSuwSDcBfayTCTBoWpfIGO5XFxPmjILQII4NGiZjD6DoDI6kf7gKaxkf7s3VQ== - dependencies: - align-text "^0.1.3" - lazy-cache "^1.0.3" - -chalk@^1.1.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" - integrity sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A== - dependencies: - ansi-styles "^2.2.1" - escape-string-regexp "^1.0.2" - has-ansi "^2.0.0" - strip-ansi "^3.0.0" - supports-color "^2.0.0" - chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" @@ -4629,7 +3963,7 @@ chardet@^0.7.0: resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== -chokidar@^3.4.2, chokidar@^3.5.3: +chokidar@^3.4.2, chokidar@^3.5.3, chokidar@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== @@ -4695,15 +4029,6 @@ clipboardy@^4.0.0: is-wsl "^3.1.0" is64bit "^2.0.0" -cliui@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" - integrity sha512-GIOYRizG+TGoc7Wgc1LiOTLare95R3mzKgoln+Q/lE4ceiYH19gUpl0l0Ffq4lJDEf3FxujMe6IBfOCs7pfqNA== - dependencies: - center-align "^0.1.1" - right-align "^0.1.1" - wordwrap "0.0.2" - cliui@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" @@ -4763,7 +4088,7 @@ color-name@^1.0.0, color-name@~1.1.4: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -color-string@^1.5.5, color-string@^1.9.0: +color-string@^1.9.0: version "1.9.1" resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.9.1.tgz#4467f9146f036f855b764dfb5bf8582bf342c7a4" integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg== @@ -4796,11 +4121,6 @@ combined-stream@^1.0.8: dependencies: delayed-stream "~1.0.0" -comlink@^4.4.1: - version "4.4.2" - resolved "https://registry.yarnpkg.com/comlink/-/comlink-4.4.2.tgz#cbbcd82742fbebc06489c28a183eedc5c60a2bca" - integrity sha512-OxGdvBmJuNKSCMO4NTl1L47VRp6xn2wG4F/2hYzB6tiCb709otOxtEYCSvK80PtjODfXXZu8ds+Nw5kVCjqd2g== - comma-separated-tokens@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz#4e89c9458acb61bc8fef19f4529973b2392839ee" @@ -4811,11 +4131,6 @@ command-exists@^1.2.4: resolved "https://registry.yarnpkg.com/command-exists/-/command-exists-1.2.9.tgz#c50725af3808c8ab0260fd60b01fbfa25b954f69" integrity sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w== -commander@7, commander@^7.2.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" - integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== - commander@^2.20.0: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" @@ -4826,6 +4141,11 @@ commander@^4.0.0: resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== +commander@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" + integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== + common-tags@1.8.2, common-tags@^1.8.2: version "1.8.2" resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.2.tgz#94ebb3c076d26032745fd54face7f688ef5ac9c6" @@ -4922,11 +4242,6 @@ content-type@~1.0.4, content-type@~1.0.5: resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== -contour_plot@^0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/contour_plot/-/contour_plot-0.0.1.tgz#475870f032b8e338412aa5fc507880f0bf495c77" - integrity sha512-Nil2HI76Xux6sVGORvhSS8v66m+/h5CwFkBJDO+U5vWaMdNC0yXNCsGDPbzPhvqOEU5koebhdEvD372LI+IyLw== - convert-hrtime@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/convert-hrtime/-/convert-hrtime-3.0.0.tgz#62c7593f5809ca10be8da858a6d2f702bcda00aa" @@ -5048,9 +4363,9 @@ cross-fetch@^3.1.5: node-fetch "^2.6.12" cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: - version "7.0.5" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.5.tgz#910aac880ff5243da96b728bc6521a5f6c2f2f82" - integrity sha512-ZVJrKKYunU38/76t0RMOulHOnUcbU9GbpWKAOZ0mhjr7CX6FVrH+4FrAapSOekrgFQ3f/8gwMEuIft0aKq6Hug== + version "7.0.6" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== dependencies: path-key "^3.1.0" shebang-command "^2.0.0" @@ -5061,11 +4376,6 @@ crypto-random-string@^2.0.0: resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA== -css-color-keywords@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/css-color-keywords/-/css-color-keywords-1.0.0.tgz#fea2616dc676b2962686b3af8dbdbe180b244e05" - integrity sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg== - css-declaration-sorter@^6.3.1: version "6.4.1" resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.4.1.tgz#28beac7c20bad7f1775be3a7129d7eae409a3a71" @@ -5116,15 +4426,6 @@ css-selector-parser@^1.0.0: resolved "https://registry.yarnpkg.com/css-selector-parser/-/css-selector-parser-1.4.1.tgz#03f9cb8a81c3e5ab2c51684557d5aaf6d2569759" integrity sha512-HYPSb7y/Z7BNDCOrakL4raGO2zltZkbeXyAd6Tg9obzix6QhzxCotdBl6VT0Dv4vZfJGVz3WL/xaEI9Ly3ul0g== -css-to-react-native@3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/css-to-react-native/-/css-to-react-native-3.2.0.tgz#cdd8099f71024e149e4f6fe17a7d46ecd55f1e32" - integrity sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ== - dependencies: - camelize "^1.0.0" - css-color-keywords "^1.0.0" - postcss-value-parser "^4.0.2" - css-tree@^1.1.2, css-tree@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d" @@ -5204,24 +4505,12 @@ csso@^4.2.0: dependencies: css-tree "^1.1.2" -csstype@3.1.3, csstype@^3.0.2, csstype@^3.0.8, csstype@^3.1.3: +csstype@^3.0.2, csstype@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== -"d3-array@2.5.0 - 3", d3-array@^3.2.4: - version "3.2.4" - resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-3.2.4.tgz#15fec33b237f97ac5d7c986dc77da273a8ed0bb5" - integrity sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg== - dependencies: - internmap "1 - 2" - -d3-binarytree@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/d3-binarytree/-/d3-binarytree-1.0.2.tgz#ed43ebc13c70fbabfdd62df17480bc5a425753cc" - integrity sha512-cElUNH+sHu95L04m92pG73t2MEJXKu+GeKUN1TJkFsu93E5W8E9Sc3kHEGJKgenGvj19m6upSn2EunvMgMD2Yw== - -"d3-color@1 - 3", d3-color@^3.1.0: +"d3-color@1 - 3": version "3.1.0" resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-3.1.0.tgz#395b2833dfac71507f12ac2f7af23bf819de24e2" integrity sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA== @@ -5239,57 +4528,11 @@ d3-binarytree@1: d3-dispatch "1 - 3" d3-selection "3" -d3-dsv@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/d3-dsv/-/d3-dsv-3.0.1.tgz#c63af978f4d6a0d084a52a673922be2160789b73" - integrity sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q== - dependencies: - commander "7" - iconv-lite "0.6" - rw "1" - "d3-ease@1 - 3": version "3.0.1" resolved "https://registry.yarnpkg.com/d3-ease/-/d3-ease-3.0.1.tgz#9658ac38a2140d59d346160f1f6c30fda0bd12f4" integrity sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w== -d3-force-3d@^3.0.5: - version "3.0.5" - resolved "https://registry.yarnpkg.com/d3-force-3d/-/d3-force-3d-3.0.5.tgz#9c8931b49acc3554f9110e128bc580cd3ab830f2" - integrity sha512-tdwhAhoTYZY/a6eo9nR7HP3xSW/C6XvJTbeRpR92nlPzH6OiE+4MliN9feuSFd0tPtEUo+191qOhCTWx3NYifg== - dependencies: - d3-binarytree "1" - d3-dispatch "1 - 3" - d3-octree "1" - d3-quadtree "1 - 3" - d3-timer "1 - 3" - -d3-force@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/d3-force/-/d3-force-3.0.0.tgz#3e2ba1a61e70888fe3d9194e30d6d14eece155c4" - integrity sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg== - dependencies: - d3-dispatch "1 - 3" - d3-quadtree "1 - 3" - d3-timer "1 - 3" - -d3-format@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-3.1.0.tgz#9260e23a28ea5cb109e93b21a06e24e2ebd55641" - integrity sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA== - -d3-geo@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/d3-geo/-/d3-geo-3.1.1.tgz#6027cf51246f9b2ebd64f99e01dc7c3364033a4d" - integrity sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q== - dependencies: - d3-array "2.5.0 - 3" - -d3-hierarchy@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz#b01cd42c1eed3d46db77a5966cf726f8c09160c6" - integrity sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA== - "d3-interpolate@1 - 3": version "3.0.1" resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-3.0.1.tgz#3c47aa5b32c5b3dfb56ef3fd4342078a632b400d" @@ -5297,41 +4540,11 @@ d3-hierarchy@^3.1.2: dependencies: d3-color "1 - 3" -d3-octree@1, d3-octree@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/d3-octree/-/d3-octree-1.0.2.tgz#b39026b82701e45c7163e34ee056dc492035a017" - integrity sha512-Qxg4oirJrNXauiuC94uKMbgxwnhdda9xRLl9ihq45srlJ4Ga3CSgqGcAL8iW7N5CIv4Oz8x3E734ulxyvHPvwA== - -d3-path@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-3.1.0.tgz#22df939032fb5a71ae8b1800d61ddb7851c42526" - integrity sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ== - -"d3-quadtree@1 - 3", d3-quadtree@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/d3-quadtree/-/d3-quadtree-3.0.1.tgz#6dca3e8be2b393c9a9d514dabbd80a92deef1a4f" - integrity sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw== - -d3-scale-chromatic@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz#34c39da298b23c20e02f1a4b239bd0f22e7f1314" - integrity sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ== - dependencies: - d3-color "1 - 3" - d3-interpolate "1 - 3" - "d3-selection@2 - 3", d3-selection@3, d3-selection@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/d3-selection/-/d3-selection-3.0.0.tgz#c25338207efa72cc5b9bd1458a1a41901f1e1b31" integrity sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ== -d3-shape@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-3.2.0.tgz#a1a839cbd9ba45f28674c69d7f855bcf91dfc6a5" - integrity sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA== - dependencies: - d3-path "^3.1.0" - "d3-timer@1 - 3": version "3.0.1" resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-3.0.1.tgz#6284d2a2708285b1abb7e201eda4380af35e63b0" @@ -5367,14 +4580,6 @@ d@1, d@^1.0.1, d@^1.0.2: es5-ext "^0.10.64" type "^2.7.2" -dagre@^0.8.5: - version "0.8.5" - resolved "https://registry.yarnpkg.com/dagre/-/dagre-0.8.5.tgz#ba30b0055dac12b6c1fcc247817442777d06afee" - integrity sha512-/aTqmnRta7x7MCCpExk7HQL2O4owCT2h8NT//9I1OQ9vt29Pa0BzSAkR5lwFUcQ7491yVi/3CXU9jQ5o0Mn2Sw== - dependencies: - graphlib "^2.1.8" - lodash "^4.17.15" - damerau-levenshtein@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7" @@ -5440,7 +4645,7 @@ debug@^3.0.1, debug@^3.1.0, debug@^3.2.6, debug@^3.2.7: dependencies: ms "^2.1.1" -decamelize@^1.0.0, decamelize@^1.2.0: +decamelize@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== @@ -5464,18 +4669,6 @@ decompress-response@^6.0.0: dependencies: mimic-response "^3.1.0" -deep-equal@~1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.2.tgz#78a561b7830eef3134c7f6f3a3d6af272a678761" - integrity sha512-5tdhKF6DbU7iIzrIOa1AOUt39ZRm13cmL1cGEh//aqR8x9+tNfbywRf0n5FD/18OKMdo7DNEtrX2t22ZAkI+eg== - dependencies: - is-arguments "^1.1.1" - is-date-object "^1.0.5" - is-regex "^1.1.4" - object-is "^1.1.5" - object-keys "^1.1.1" - regexp.prototype.flags "^1.5.1" - deep-extend@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" @@ -5496,7 +4689,7 @@ defer-to-connect@^2.0.0, defer-to-connect@^2.0.1: resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587" integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg== -define-data-property@^1.0.1, define-data-property@^1.1.1, define-data-property@^1.1.4: +define-data-property@^1.0.1, define-data-property@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== @@ -5519,11 +4712,6 @@ define-properties@^1.1.3, define-properties@^1.2.0, define-properties@^1.2.1: has-property-descriptors "^1.0.0" object-keys "^1.1.1" -defined@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.1.tgz#c0b9db27bfaffd95d6f61399419b893df0f91ebf" - integrity sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q== - delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" @@ -5719,13 +4907,6 @@ dotenv@^8.6.0: resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.6.0.tgz#061af664d19f7f4d8fc6e4ff9b584ce237adcb8b" integrity sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g== -dotignore@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/dotignore/-/dotignore-0.1.2.tgz#f942f2200d28c3a76fbdd6f0ee9f3257c8a2e905" - integrity sha512-UGGGWfSauusaVJC+8fgV+NVvBXkCTmVv7sk6nojDZZvuOUNGUy0Zk4UpHQD6EDjS0jpBwcACvH4eofvyzBcRDw== - dependencies: - minimatch "^3.0.4" - duplexer@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" @@ -5742,9 +4923,9 @@ ee-first@1.1.1: integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== electron-to-chromium@^1.5.41: - version "1.5.50" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.50.tgz#d9ba818da7b2b5ef1f3dd32bce7046feb7e93234" - integrity sha512-eMVObiUQ2LdgeO1F/ySTXsvqvxb6ZH2zPGaMYsWzRDdOddUa77tdmI0ltg+L16UpbWdhPmuF3wIQYyQq65WfZw== + version "1.5.64" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.64.tgz#ac8c4c89075d35a1514b620f47dfe48a71ec3697" + integrity sha512-IXEuxU+5ClW2IGEYFC2T7szbyVgehupCWQe5GNh+H065CD6U6IFN0s4KeAMFGNmQolRU4IV7zGBWSYMmZ8uuqQ== emoji-regex@^8.0.0: version "8.0.0" @@ -5856,9 +5037,9 @@ error-stack-parser@^2.0.6, error-stack-parser@^2.1.4: stackframe "^1.3.4" es-abstract@^1.17.5, es-abstract@^1.22.1, es-abstract@^1.22.3, es-abstract@^1.23.0, es-abstract@^1.23.1, es-abstract@^1.23.2, es-abstract@^1.23.3: - version "1.23.3" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.3.tgz#8f0c5a35cd215312573c5a27c87dfd6c881a0aa0" - integrity sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A== + version "1.23.5" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.5.tgz#f4599a4946d57ed467515ed10e4f157289cd52fb" + integrity sha512-vlmniQ0WNPwXqA0BnmwV3Ng7HxiGlh6r5U6JcTMNx8OilcAGqVJBHJcPjqOMaczU9fRuRK5Px2BdVyPRnKMMVQ== dependencies: array-buffer-byte-length "^1.0.1" arraybuffer.prototype.slice "^1.0.3" @@ -5875,7 +5056,7 @@ es-abstract@^1.17.5, es-abstract@^1.22.1, es-abstract@^1.22.3, es-abstract@^1.23 function.prototype.name "^1.1.6" get-intrinsic "^1.2.4" get-symbol-description "^1.0.2" - globalthis "^1.0.3" + globalthis "^1.0.4" gopd "^1.0.1" has-property-descriptors "^1.0.2" has-proto "^1.0.3" @@ -5891,10 +5072,10 @@ es-abstract@^1.17.5, es-abstract@^1.22.1, es-abstract@^1.22.3, es-abstract@^1.23 is-string "^1.0.7" is-typed-array "^1.1.13" is-weakref "^1.0.2" - object-inspect "^1.13.1" + object-inspect "^1.13.3" object-keys "^1.1.1" object.assign "^4.1.5" - regexp.prototype.flags "^1.5.2" + regexp.prototype.flags "^1.5.3" safe-array-concat "^1.1.2" safe-regex-test "^1.0.3" string.prototype.trim "^1.2.9" @@ -5920,9 +5101,9 @@ es-errors@^1.2.1, es-errors@^1.3.0: integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== es-iterator-helpers@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.1.0.tgz#f6d745d342aea214fe09497e7152170dc333a7a6" - integrity sha512-/SurEfycdyssORP/E+bj4sEu1CWw4EmLDsHynHwSXQ7utgbrMRWW195pTrCjFgFCddf/UkYm3oqKPRq5i8bJbw== + version "1.2.0" + resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.2.0.tgz#2f1a3ab998b30cb2d10b195b587c6d9ebdebf152" + integrity sha512-tpxqxncxnpw3c93u8n3VOzACmRFoVmWJqbWXvX/JfKbkhBw1oslgPrUfeSt2psuqyEJFD6N/9lg5i7bsKpoq+Q== dependencies: call-bind "^1.0.7" define-properties "^1.2.1" @@ -5932,6 +5113,7 @@ es-iterator-helpers@^1.1.0: function-bind "^1.1.2" get-intrinsic "^1.2.4" globalthis "^1.0.4" + gopd "^1.0.1" has-property-descriptors "^1.0.2" has-proto "^1.0.3" has-symbols "^1.0.3" @@ -6358,11 +5540,6 @@ event-source-polyfill@1.0.31: resolved "https://registry.yarnpkg.com/event-source-polyfill/-/event-source-polyfill-1.0.31.tgz#45fb0a6fc1375b2ba597361ba4287ffec5bf2e0c" integrity sha512-4IJSItgS/41IxN5UVAVuAyczwZF7ZIEsM1XAoUzIHA6A+xzusEZUutdXz2Nr+MQPLxfTiCvqE79/C8HT8fKFvA== -eventemitter3@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4" - integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA== - events@^3.2.0: version "3.3.0" resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" @@ -6487,7 +5664,7 @@ fast-fifo@^1.2.0, fast-fifo@^1.3.2: resolved "https://registry.yarnpkg.com/fast-fifo/-/fast-fifo-1.3.2.tgz#286e31de96eb96d38a97899815740ba2a4f3640c" integrity sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ== -fast-glob@^3.2.9, fast-glob@^3.3.0: +fast-glob@^3.2.9, fast-glob@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== @@ -6550,11 +5727,6 @@ fbjs@^3.0.0: setimmediate "^1.0.5" ua-parser-js "^1.0.35" -fecha@^4.2.1: - version "4.2.3" - resolved "https://registry.yarnpkg.com/fecha/-/fecha-4.2.3.tgz#4d9ccdbc61e8629b259fdca67e65891448d569fd" - integrity sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw== - figures@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" @@ -6677,32 +5849,16 @@ flat@^5.0.2: integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== flatted@^3.2.9: - version "3.3.1" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" - integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== - -flru@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/flru/-/flru-1.0.2.tgz#1ae514c62b8b035ffff9ca9e4563ddcc817f4845" - integrity sha512-kWyh8ADvHBFz6ua5xYOPnUroZTT/bwWfrCeL0Wj1dzG4/YOmOcfJ99W8dOVyyynJN35rZ9aCOtHChqQovV7yog== - -fmin@^0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/fmin/-/fmin-0.0.2.tgz#59bbb40d43ffdc1c94cd00a568c41f95f1973017" - integrity sha512-sSi6DzInhl9d8yqssDfGZejChO8d2bAGIpysPsvYsxFe898z89XhCZg6CPNV3nhUhFefeC/AXZK2bAJxlBjN6A== - dependencies: - contour_plot "^0.0.1" - json2module "^0.0.3" - rollup "^0.25.8" - tape "^4.5.1" - uglify-js "^2.6.2" + version "3.3.2" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.2.tgz#adba1448a9841bec72b42c532ea23dbbedef1a27" + integrity sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA== follow-redirects@^1.15.6: version "1.15.9" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1" integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== -for-each@^0.3.3, for-each@~0.3.3: +for-each@^0.3.3: version "0.3.3" resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== @@ -7388,11 +6544,6 @@ github-slugger@^2.0.0: resolved "https://registry.yarnpkg.com/github-slugger/-/github-slugger-2.0.0.tgz#52cf2f9279a21eb6c59dd385b410f0c0adda8f1a" integrity sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw== -gl-matrix@^3.3.0, gl-matrix@^3.4.3: - version "3.4.3" - resolved "https://registry.yarnpkg.com/gl-matrix/-/gl-matrix-3.4.3.tgz#fc1191e8320009fd4d20e9339595c6041ddc22c9" - integrity sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA== - glob-parent@^5.1.2, glob-parent@~5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" @@ -7424,7 +6575,7 @@ glob@^10.3.10: package-json-from-dist "^1.0.0" path-scurry "^1.11.1" -glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.6, glob@^7.2.3, glob@~7.2.3: +glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.6, glob@^7.2.3: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== @@ -7540,13 +6691,6 @@ graphemer@^1.4.0: resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== -graphlib@^2.1.8: - version "2.1.8" - resolved "https://registry.yarnpkg.com/graphlib/-/graphlib-2.1.8.tgz#5761d414737870084c92ec7b5dbcb0592c9d35da" - integrity sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A== - dependencies: - lodash "^4.17.15" - graphql-compose@^9.0.10: version "9.0.11" resolved "https://registry.yarnpkg.com/graphql-compose/-/graphql-compose-9.0.11.tgz#c3b5a3378b62be0deb9ea43d147b756010f6d611" @@ -7555,9 +6699,9 @@ graphql-compose@^9.0.10: graphql-type-json "0.3.2" graphql-http@^1.19.0: - version "1.22.1" - resolved "https://registry.yarnpkg.com/graphql-http/-/graphql-http-1.22.1.tgz#3857ac75366e55db189cfe09ade9cc4c4f2cfd09" - integrity sha512-4Jor+LRbA7SfSaw7dfDUs2UBzvWg3cKrykfHRgKsOIvQaLuf+QOcG2t3Mx5N9GzSNJcuqMqJWz0ta5+BryEmXg== + version "1.22.3" + resolved "https://registry.yarnpkg.com/graphql-http/-/graphql-http-1.22.3.tgz#5da03ee564b847e585fa08e326a50dbd4c8fbc0a" + integrity sha512-sgUz/2DZt+QvY6WrpAsAXUvhnIkp2eX9jN78V8DAtFcpZi/nfDrzDt2byYjyoJzRcWuqhE0K63g1QMewt73U6A== graphql-tag@^2.11.0, graphql-tag@^2.12.6: version "2.12.6" @@ -7593,13 +6737,6 @@ gzip-size@^6.0.0: dependencies: duplexer "^0.1.2" -has-ansi@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" - integrity sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg== - dependencies: - ansi-regex "^2.0.0" - has-bigints@^1.0.1, has-bigints@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" @@ -7639,15 +6776,10 @@ has-tostringtag@^1.0.0, has-tostringtag@^1.0.2: dependencies: has-symbols "^1.0.3" -has@~1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.4.tgz#2eb2860e000011dae4f1406a86fe80e530fb2ec6" - integrity sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ== - hash-wasm@^4.11.0: - version "4.11.0" - resolved "https://registry.yarnpkg.com/hash-wasm/-/hash-wasm-4.11.0.tgz#7d1479b114c82e48498fdb1d2462a687d00386d5" - integrity sha512-HVusNXlVqHe0fzIzdQOGolnFN6mX/fqcrSAOcTBXdvzrXVHwTz11vXeKRmkR5gTuwVpvHZEIyKoePDvuAR+XwQ== + version "4.12.0" + resolved "https://registry.yarnpkg.com/hash-wasm/-/hash-wasm-4.12.0.tgz#f9f1a9f9121e027a9acbf6db5d59452ace1ef9bb" + integrity sha512-+/2B2rYLb48I/evdOIhP+K/DD2ca2fgBjp6O+GBEnCDk2e4rpeXIK8GvIyRPjTezgmWn9gmKwkQjjx6BtqDHVQ== hasha@^5.2.2: version "5.2.2" @@ -7857,11 +6989,6 @@ http2-wrapper@^2.1.10: quick-lru "^5.1.1" resolve-alpn "^1.2.0" -hull.js@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/hull.js/-/hull.js-1.0.6.tgz#75f013e8171eb9a871b4a94887e89eb555461d0e" - integrity sha512-TC7e9sHYOaCVms0sn2hN7buxnaGfcl9h5EPVoVX9DTPoMpqQiS9bf3tmGDgiNaMVHBD91RAvWjCxrJ5Jx8BI5A== - human-signals@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" @@ -7879,13 +7006,6 @@ iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4: dependencies: safer-buffer ">= 2.1.2 < 3" -iconv-lite@0.6: - version "0.6.3" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" - integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== - dependencies: - safer-buffer ">= 2.1.2 < 3.0.0" - icss-utils@^5.0.0, icss-utils@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae" @@ -7942,7 +7062,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3, inherits@~2.0.4: +inherits@2, inherits@2.0.4, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -7995,11 +7115,6 @@ internal-slot@^1.0.7: hasown "^2.0.0" side-channel "^1.0.4" -"internmap@1 - 2": - version "2.0.3" - resolved "https://registry.yarnpkg.com/internmap/-/internmap-2.0.3.tgz#6685f23755e43c524e251d29cbc97248e3061009" - integrity sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg== - invariant@^2.2.4: version "2.2.4" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" @@ -8038,19 +7153,6 @@ is-alphanumerical@^2.0.0: is-alphabetical "^2.0.0" is-decimal "^2.0.0" -is-any-array@^2.0.0, is-any-array@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-any-array/-/is-any-array-2.0.1.tgz#9233242a9c098220290aa2ec28f82ca7fa79899e" - integrity sha512-UtilS7hLRu++wb/WBAw9bNuP1Eg04Ivn1vERJck8zJthEvXCBEBpGR/33u/xLKWEQf95803oalHrVDptcAvFdQ== - -is-arguments@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" - integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - is-array-buffer@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.4.tgz#7a1f92b3d61edd2bc65d24f130530ea93d7fae98" @@ -8098,11 +7200,6 @@ is-boolean-object@^1.1.0: call-bind "^1.0.2" has-tostringtag "^1.0.0" -is-buffer@^1.1.5: - version "1.1.6" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" - integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== - is-buffer@^2.0.0: version "2.0.5" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" @@ -8275,13 +7372,13 @@ is-promise@^2.2.2: integrity sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ== is-reference@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-3.0.2.tgz#154747a01f45cd962404ee89d43837af2cba247c" - integrity sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg== + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-3.0.3.tgz#9ef7bf9029c70a67b2152da4adf57c23d718910f" + integrity sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw== dependencies: - "@types/estree" "*" + "@types/estree" "^1.0.6" -is-regex@^1.1.4, is-regex@~1.1.4: +is-regex@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== @@ -8493,7 +7590,7 @@ jest-worker@^27.4.5, jest-worker@^27.5.1: merge-stream "^2.0.0" supports-color "^8.0.0" -jiti@^1.20.0, jiti@^1.21.0: +jiti@^1.20.0, jiti@^1.21.6: version "1.21.6" resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.21.6.tgz#6c7f7398dd4b3142767f9a168af2f317a428d268" integrity sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w== @@ -8564,13 +7661,6 @@ json-stable-stringify-without-jsonify@^1.0.1: resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== -json2module@^0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/json2module/-/json2module-0.0.3.tgz#00fb5f4a9b7adfc3f0647c29cb17bcd1979be9b2" - integrity sha512-qYGxqrRrt4GbB8IEOy1jJGypkNsjWoIMlZt4bAsmUScCA507Hbc2p1JOhBzqn45u3PWafUgH2OnzyNU7udO/GA== - dependencies: - rw "^1.3.2" - json2mq@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/json2mq/-/json2mq-0.2.0.tgz#b637bd3ba9eabe122c83e9720483aeb10d2c904a" @@ -8616,13 +7706,6 @@ keyv@^4.0.0, keyv@^4.5.3: dependencies: json-buffer "3.0.1" -kind-of@^3.0.2: - version "3.2.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" - integrity sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ== - dependencies: - is-buffer "^1.1.5" - kind-of@^6.0.0, kind-of@^6.0.2: version "6.0.3" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" @@ -8662,11 +7745,6 @@ latest-version@^7.0.0: dependencies: package-json "^8.1.0" -lazy-cache@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" - integrity sha512-RE2g0b5VGZsOCFOCgP7omTRYFqydmZkBwl5oNnQ1lDYC57uyO9KqNnNVxT7COSHTxrRCWVcAVOcbjk+tvh/rgQ== - levn@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" @@ -8857,11 +7935,6 @@ longest-streak@^3.0.0: resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-3.1.0.tgz#62fa67cd958742a1574af9f39866364102d90cd4" integrity sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g== -longest@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" - integrity sha512-k+yt5n3l48JU4k8ftnKG6V7u32wyH2NfKzeMto9F/QRE0amxy/LayxwlvjjkZEIzqR+19IrtFO8p5kB9QaYUFg== - loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" @@ -8927,10 +8000,10 @@ lru-queue@^0.1.0: dependencies: es5-ext "~0.10.2" -lucide-react@^0.456.0: - version "0.456.0" - resolved "https://registry.yarnpkg.com/lucide-react/-/lucide-react-0.456.0.tgz#14906c3355cc65d3380b7b2294b331aeda1bb392" - integrity sha512-DIIGJqTT5X05sbAsQ+OhA8OtJYyD4NsEMCA/HQW/Y6ToPQ7gwbtujIoeAaup4HpHzV35SQOarKAWH8LYglB6eA== +lucide-react@^0.460.0: + version "0.460.0" + resolved "https://registry.yarnpkg.com/lucide-react/-/lucide-react-0.460.0.tgz#5681364b6bd94d1d475944f0385239c0b1408e35" + integrity sha512-BVtq/DykVeIvRTJvRAgCsOwaGL8Un3Bxh8MbDxMhEWlZay3T4IpEKDEpwt5KZ0KJMHzgm6jrltxlT5eXOWXDHg== make-dir@^3.0.0, make-dir@^3.0.2, make-dir@^3.1.0: version "3.1.0" @@ -9168,9 +8241,9 @@ mdast-util-to-markdown@^1.0.0, mdast-util-to-markdown@^1.3.0, mdast-util-to-mark zwitch "^2.0.0" mdast-util-to-markdown@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.1.tgz#6fdb72cd54ee4e6745e138db003609978a322e94" - integrity sha512-OrkcCoqAkEg9b1ykXBrA0ehRc8H4fGU/03cACmW2xXzau1+dIdS+qJugh1Cqex3hMumSBgSE/5pc7uqP12nLAw== + version "2.1.2" + resolved "https://registry.yarnpkg.com/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz#f910ffe60897f04bb4b7e7ee434486f76288361b" + integrity sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA== dependencies: "@types/mdast" "^4.0.0" "@types/unist" "^3.0.0" @@ -9293,9 +8366,9 @@ micromark-core-commonmark@^1.0.0, micromark-core-commonmark@^1.0.1: uvu "^0.5.0" micromark-core-commonmark@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/micromark-core-commonmark/-/micromark-core-commonmark-2.0.1.tgz#9a45510557d068605c6e9a80f282b2bb8581e43d" - integrity sha512-CUQyKr1e///ZODyD1U3xit6zXwy1a8q2a1S1HKtIlmgvurrEpaw/Y9y6KSIbF8P59cn/NjzHyO+Q2fAyYLQrAA== + version "2.0.2" + resolved "https://registry.yarnpkg.com/micromark-core-commonmark/-/micromark-core-commonmark-2.0.2.tgz#6a45bbb139e126b3f8b361a10711ccc7c6e15e93" + integrity sha512-FKjQKbxd1cibWMM1P9N+H8TwlgGgSkWZMmfuVucLCHaYqeSvJ0hFeHsIa65pA2nYbes0f8LDHPMrd9X7Ujxg9w== dependencies: decode-named-character-reference "^1.0.0" devlop "^1.0.0" @@ -9390,9 +8463,9 @@ micromark-factory-destination@^1.0.0: micromark-util-types "^1.0.0" micromark-factory-destination@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-factory-destination/-/micromark-factory-destination-2.0.0.tgz#857c94debd2c873cba34e0445ab26b74f6a6ec07" - integrity sha512-j9DGrQLm/Uhl2tCzcbLhy5kXsgkHUrjJHg4fFAeoMRwJmJerT9aw4FEhIbZStWN8A3qMwOp1uzHr4UL8AInxtA== + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz#8fef8e0f7081f0474fbdd92deb50c990a0264639" + integrity sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA== dependencies: micromark-util-character "^2.0.0" micromark-util-symbol "^2.0.0" @@ -9409,9 +8482,9 @@ micromark-factory-label@^1.0.0: uvu "^0.5.0" micromark-factory-label@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-factory-label/-/micromark-factory-label-2.0.0.tgz#17c5c2e66ce39ad6f4fc4cbf40d972f9096f726a" - integrity sha512-RR3i96ohZGde//4WSe/dJsxOX6vxIg9TimLAS3i4EhBAFx8Sm5SmqVfR8E87DPSR31nEAjZfbt91OMZWcNgdZw== + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz#5267efa97f1e5254efc7f20b459a38cb21058ba1" + integrity sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg== dependencies: devlop "^1.0.0" micromark-util-character "^2.0.0" @@ -9441,9 +8514,9 @@ micromark-factory-space@^1.0.0: micromark-util-types "^1.0.0" micromark-factory-space@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz#5e7afd5929c23b96566d0e1ae018ae4fcf81d030" - integrity sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg== + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz#36d0212e962b2b3121f8525fc7a3c7c029f334fc" + integrity sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg== dependencies: micromark-util-character "^2.0.0" micromark-util-types "^2.0.0" @@ -9459,9 +8532,9 @@ micromark-factory-title@^1.0.0: micromark-util-types "^1.0.0" micromark-factory-title@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-factory-title/-/micromark-factory-title-2.0.0.tgz#726140fc77892af524705d689e1cf06c8a83ea95" - integrity sha512-jY8CSxmpWLOxS+t8W+FG3Xigc0RDQA9bKMY/EwILvsesiRniiVMejYTE4wumNc2f4UbAa4WsHqe3J1QS1sli+A== + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz#237e4aa5d58a95863f01032d9ee9b090f1de6e94" + integrity sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw== dependencies: micromark-factory-space "^2.0.0" micromark-util-character "^2.0.0" @@ -9479,9 +8552,9 @@ micromark-factory-whitespace@^1.0.0: micromark-util-types "^1.0.0" micromark-factory-whitespace@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.0.tgz#9e92eb0f5468083381f923d9653632b3cfb5f763" - integrity sha512-28kbwaBjc5yAI1XadbdPYHX/eDnqaUFVikLwrO7FDnKG7lpgxnvk/XGRhX/PN0mOZ+dBSZ+LgunHS+6tYQAzhA== + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz#06b26b2983c4d27bfcc657b33e25134d4868b0b1" + integrity sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ== dependencies: micromark-factory-space "^2.0.0" micromark-util-character "^2.0.0" @@ -9497,9 +8570,9 @@ micromark-util-character@^1.0.0: micromark-util-types "^1.0.0" micromark-util-character@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/micromark-util-character/-/micromark-util-character-2.1.0.tgz#31320ace16b4644316f6bf057531689c71e2aee1" - integrity sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ== + version "2.1.1" + resolved "https://registry.yarnpkg.com/micromark-util-character/-/micromark-util-character-2.1.1.tgz#2f987831a40d4c510ac261e89852c4e9703ccda6" + integrity sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q== dependencies: micromark-util-symbol "^2.0.0" micromark-util-types "^2.0.0" @@ -9512,9 +8585,9 @@ micromark-util-chunked@^1.0.0: micromark-util-symbol "^1.0.0" micromark-util-chunked@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-chunked/-/micromark-util-chunked-2.0.0.tgz#e51f4db85fb203a79dbfef23fd41b2f03dc2ef89" - integrity sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg== + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz#47fbcd93471a3fccab86cff03847fc3552db1051" + integrity sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA== dependencies: micromark-util-symbol "^2.0.0" @@ -9528,9 +8601,9 @@ micromark-util-classify-character@^1.0.0: micromark-util-types "^1.0.0" micromark-util-classify-character@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-classify-character/-/micromark-util-classify-character-2.0.0.tgz#8c7537c20d0750b12df31f86e976d1d951165f34" - integrity sha512-S0ze2R9GH+fu41FA7pbSqNWObo/kzwf8rN/+IGlW/4tC6oACOs8B++bh+i9bVyNnwCcuksbFwsBme5OCKXCwIw== + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz#d399faf9c45ca14c8b4be98b1ea481bced87b629" + integrity sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q== dependencies: micromark-util-character "^2.0.0" micromark-util-symbol "^2.0.0" @@ -9545,9 +8618,9 @@ micromark-util-combine-extensions@^1.0.0: micromark-util-types "^1.0.0" micromark-util-combine-extensions@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.0.tgz#75d6ab65c58b7403616db8d6b31315013bfb7ee5" - integrity sha512-vZZio48k7ON0fVS3CUgFatWHoKbbLTK/rT7pzpJ4Bjp5JjkZeasRfrS9wsBdDJK2cJLHMckXZdzPSSr1B8a4oQ== + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz#2a0f490ab08bff5cc2fd5eec6dd0ca04f89b30a9" + integrity sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg== dependencies: micromark-util-chunked "^2.0.0" micromark-util-types "^2.0.0" @@ -9560,9 +8633,9 @@ micromark-util-decode-numeric-character-reference@^1.0.0: micromark-util-symbol "^1.0.0" micromark-util-decode-numeric-character-reference@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.1.tgz#2698bbb38f2a9ba6310e359f99fcb2b35a0d2bd5" - integrity sha512-bmkNc7z8Wn6kgjZmVHOX3SowGmVdhYS7yBpMnuMnPzDq/6xwVA604DuOXMZTO1lvq01g+Adfa0pE2UKGlxL1XQ== + version "2.0.2" + resolved "https://registry.yarnpkg.com/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz#fcf15b660979388e6f118cdb6bf7d79d73d26fe5" + integrity sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw== dependencies: micromark-util-symbol "^2.0.0" @@ -9577,9 +8650,9 @@ micromark-util-decode-string@^1.0.0: micromark-util-symbol "^1.0.0" micromark-util-decode-string@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-decode-string/-/micromark-util-decode-string-2.0.0.tgz#7dfa3a63c45aecaa17824e656bcdb01f9737154a" - integrity sha512-r4Sc6leeUTn3P6gk20aFMj2ntPwn6qpDZqWvYmAG6NgvFTIlj4WtrAudLi65qYoaGdXYViXYw2pkmn7QnIFasA== + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz#6cb99582e5d271e84efca8e61a807994d7161eb2" + integrity sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ== dependencies: decode-named-character-reference "^1.0.0" micromark-util-character "^2.0.0" @@ -9592,9 +8665,9 @@ micromark-util-encode@^1.0.0: integrity sha512-EuEzTWSTAj9PA5GOAs992GzNh2dGQO52UvAbtSOMvXTxv3Criqb6IOzJUBCmEqrrXSblJIJBbFFv6zPxpreiJw== micromark-util-encode@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-encode/-/micromark-util-encode-2.0.0.tgz#0921ac7953dc3f1fd281e3d1932decfdb9382ab1" - integrity sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA== + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz#0d51d1c095551cfaac368326963cf55f15f540b8" + integrity sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw== micromark-util-events-to-acorn@^1.0.0: version "1.2.3" @@ -9616,9 +8689,9 @@ micromark-util-html-tag-name@^1.0.0: integrity sha512-VTQzcuQgFUD7yYztuQFKXT49KghjtETQ+Wv/zUjGSGBioZnkA4P1XXZPT1FHeJA6RwRXSF47yvJ1tsJdoxwO+Q== micromark-util-html-tag-name@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.0.tgz#ae34b01cbe063363847670284c6255bb12138ec4" - integrity sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw== + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz#e40403096481986b41c106627f98f72d4d10b825" + integrity sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA== micromark-util-normalize-identifier@^1.0.0: version "1.1.0" @@ -9628,9 +8701,9 @@ micromark-util-normalize-identifier@^1.0.0: micromark-util-symbol "^1.0.0" micromark-util-normalize-identifier@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.0.tgz#91f9a4e65fe66cc80c53b35b0254ad67aa431d8b" - integrity sha512-2xhYT0sfo85FMrUPtHcPo2rrp1lwbDEEzpx7jiH2xXJLqBuy4H0GgXk5ToU8IEwoROtXuL8ND0ttVa4rNqYK3w== + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz#c30d77b2e832acf6526f8bf1aa47bc9c9438c16d" + integrity sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q== dependencies: micromark-util-symbol "^2.0.0" @@ -9642,9 +8715,9 @@ micromark-util-resolve-all@^1.0.0: micromark-util-types "^1.0.0" micromark-util-resolve-all@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.0.tgz#189656e7e1a53d0c86a38a652b284a252389f364" - integrity sha512-6KU6qO7DZ7GJkaCgwBNtplXCvGkJToU86ybBAUdavvgsCiG8lSSvYxr9MhwmQ+udpzywHsl4RpGJsYWG1pDOcA== + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz#e1a2d62cdd237230a2ae11839027b19381e31e8b" + integrity sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg== dependencies: micromark-util-types "^2.0.0" @@ -9658,9 +8731,9 @@ micromark-util-sanitize-uri@^1.0.0, micromark-util-sanitize-uri@^1.1.0: micromark-util-symbol "^1.0.0" micromark-util-sanitize-uri@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.0.tgz#ec8fbf0258e9e6d8f13d9e4770f9be64342673de" - integrity sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw== + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz#ab89789b818a58752b73d6b55238621b7faa8fd7" + integrity sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ== dependencies: micromark-util-character "^2.0.0" micromark-util-encode "^2.0.0" @@ -9677,9 +8750,9 @@ micromark-util-subtokenize@^1.0.0: uvu "^0.5.0" micromark-util-subtokenize@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.1.tgz#76129c49ac65da6e479c09d0ec4b5f29ec6eace5" - integrity sha512-jZNtiFl/1aY73yS3UGQkutD0UbhTt68qnRpw2Pifmz5wV9h8gOVsN70v+Lq/f1rKaU/W8pxRe8y8Q9FX1AOe1Q== + version "2.0.3" + resolved "https://registry.yarnpkg.com/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.3.tgz#70ffb99a454bd8c913c8b709c3dc97baefb65f96" + integrity sha512-VXJJuNxYWSoYL6AJ6OQECCFGhIU2GGHMw8tahogePBrjkG8aCCas3ibkp7RnVOSTClg2is05/R7maAhF1XyQMg== dependencies: devlop "^1.0.0" micromark-util-chunked "^2.0.0" @@ -9692,9 +8765,9 @@ micromark-util-symbol@^1.0.0: integrity sha512-uEjpEYY6KMs1g7QfJ2eX1SQEV+ZT4rUD3UcF6l57acZvLNK7PBZL+ty82Z1qhK1/yXIY4bdx04FKMgR0g4IAag== micromark-util-symbol@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz#12225c8f95edf8b17254e47080ce0862d5db8044" - integrity sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw== + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz#e5da494e8eb2b071a0d08fb34f6cefec6c0a19b8" + integrity sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q== micromark-util-types@^1.0.0, micromark-util-types@^1.0.1: version "1.1.0" @@ -9702,9 +8775,9 @@ micromark-util-types@^1.0.0, micromark-util-types@^1.0.1: integrity sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg== micromark-util-types@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-types/-/micromark-util-types-2.0.0.tgz#63b4b7ffeb35d3ecf50d1ca20e68fc7caa36d95e" - integrity sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w== + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-types/-/micromark-util-types-2.0.1.tgz#a3edfda3022c6c6b55bfb049ef5b75d70af50709" + integrity sha512-534m2WhVTddrcKVepwmVEVnUAmtrx9bfIjNoQHRqfnvdaHQiFytEhJoTgpWJvDEXCO5gLTQh3wYC1PgOJA4NSQ== micromark@^3.0.0: version "3.2.0" @@ -9730,9 +8803,9 @@ micromark@^3.0.0: uvu "^0.5.0" micromark@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/micromark/-/micromark-4.0.0.tgz#84746a249ebd904d9658cfabc1e8e5f32cbc6249" - integrity sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ== + version "4.0.1" + resolved "https://registry.yarnpkg.com/micromark/-/micromark-4.0.1.tgz#294c2f12364759e5f9e925a767ae3dfde72223ff" + integrity sha512-eBPdkcoCNvYcxQOAKAlceo5SNdzZWfF+FcSupREAzdAh9rRmE239CEQAiTwIgblwnoM8zzj35sZ5ZwvSEOF6Kw== dependencies: "@types/debug" "^4.0.0" debug "^4.0.0" @@ -9752,7 +8825,7 @@ micromark@^4.0.0: micromark-util-symbol "^2.0.0" micromark-util-types "^2.0.0" -micromatch@^4.0.4, micromatch@^4.0.5: +micromatch@^4.0.4, micromatch@^4.0.5, micromatch@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== @@ -9835,7 +8908,7 @@ minimatch@^9.0.4: dependencies: brace-expansion "^2.0.1" -minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.6, minimist@~1.2.8: +minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.6: version "1.2.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== @@ -9862,49 +8935,6 @@ mkdirp@^0.5.1, mkdirp@^0.5.4: dependencies: minimist "^1.2.6" -ml-array-max@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/ml-array-max/-/ml-array-max-1.2.4.tgz#2373e2b7e51c8807e456cc0ef364c5863713623b" - integrity sha512-BlEeg80jI0tW6WaPyGxf5Sa4sqvcyY6lbSn5Vcv44lp1I2GR6AWojfUvLnGTNsIXrZ8uqWmo8VcG1WpkI2ONMQ== - dependencies: - is-any-array "^2.0.0" - -ml-array-min@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/ml-array-min/-/ml-array-min-1.2.3.tgz#662f027c400105816b849cc3cd786915d0801495" - integrity sha512-VcZ5f3VZ1iihtrGvgfh/q0XlMobG6GQ8FsNyQXD3T+IlstDv85g8kfV0xUG1QPRO/t21aukaJowDzMTc7j5V6Q== - dependencies: - is-any-array "^2.0.0" - -ml-array-rescale@^1.3.7: - version "1.3.7" - resolved "https://registry.yarnpkg.com/ml-array-rescale/-/ml-array-rescale-1.3.7.tgz#c4d129320d113a732e62dd963dc1695bba9a5340" - integrity sha512-48NGChTouvEo9KBctDfHC3udWnQKNKEWN0ziELvY3KG25GR5cA8K8wNVzracsqSW1QEkAXjTNx+ycgAv06/1mQ== - dependencies: - is-any-array "^2.0.0" - ml-array-max "^1.2.4" - ml-array-min "^1.2.3" - -ml-matrix@^6.10.4: - version "6.12.0" - resolved "https://registry.yarnpkg.com/ml-matrix/-/ml-matrix-6.12.0.tgz#def6a0574b5fdc54a753033830e784a17399e270" - integrity sha512-AGfR+pWaC0GmzjUnB6BfwhndPEUGz0i7QUYdqNuw1zhTov/vSRJ9pP2hs6BoGpaSbtXgrKjZz2zjD1M0xuur6A== - dependencies: - is-any-array "^2.0.1" - ml-array-rescale "^1.3.7" - -mock-property@~1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/mock-property/-/mock-property-1.0.3.tgz#3e37c50a56609d548cabd56559fde3dd8767b10c" - integrity sha512-2emPTb1reeLLYwHxyVx993iYyCHEiRRO+y8NFXFPL5kl5q14sgTK76cXyEKkeKCHeRw35SfdkUJ10Q1KfHuiIQ== - dependencies: - define-data-property "^1.1.1" - functions-have-names "^1.2.3" - gopd "^1.0.1" - has-property-descriptors "^1.0.0" - hasown "^2.0.0" - isarray "^2.0.5" - moment@^2.29.4: version "2.30.1" resolved "https://registry.yarnpkg.com/moment/-/moment-2.30.1.tgz#f8c91c07b7a786e30c59926df530b4eac96974ae" @@ -10170,23 +9200,10 @@ object-hash@^3.0.0: resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-3.0.0.tgz#73f97f753e7baffc0e2cc9d6e079079744ac82e9" integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw== -object-inspect@^1.13.1: - version "1.13.2" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.2.tgz#dea0088467fb991e67af4058147a24824a3043ff" - integrity sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g== - -object-inspect@~1.12.3: - version "1.12.3" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" - integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== - -object-is@^1.1.5: - version "1.1.6" - resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.6.tgz#1a6a53aed2dd8f7e6775ff870bea58545956ab07" - integrity sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" +object-inspect@^1.13.1, object-inspect@^1.13.3: + version "1.13.3" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.3.tgz#f14c183de51130243d6d18ae149375ff50ea488a" + integrity sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA== object-keys@^1.1.1: version "1.1.1" @@ -10529,11 +9546,6 @@ path-type@^4.0.0: resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== -pdfast@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/pdfast/-/pdfast-0.2.0.tgz#8cbc556e1bf2522177787c0de2e0d4373ba885c9" - integrity sha512-cq6TTu6qKSFUHwEahi68k/kqN2mfepjkGrG9Un70cgdRRKLKY6Rf8P8uvP2NvZktaQZNF3YE7agEkLj0vGK9bA== - peek-readable@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/peek-readable/-/peek-readable-4.1.0.tgz#4ece1111bf5c2ad8867c314c81356847e8a62e72" @@ -10664,7 +9676,7 @@ postcss-js@^4.0.1: dependencies: camelcase-css "^2.0.1" -postcss-load-config@^4.0.1: +postcss-load-config@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-4.0.2.tgz#7159dcf626118d33e299f485d6afe4aff7c4a3e3" integrity sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ== @@ -10746,20 +9758,20 @@ postcss-modules-extract-imports@^3.0.0: integrity sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q== postcss-modules-local-by-default@^4.0.0: - version "4.0.5" - resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.5.tgz#f1b9bd757a8edf4d8556e8d0f4f894260e3df78f" - integrity sha512-6MieY7sIfTK0hYfafw1OMEG+2bg8Q1ocHCpoWLqOKj3JXlKu4G7btkmM/B7lFubYkYWmRSPLZi5chid63ZaZYw== + version "4.1.0" + resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.1.0.tgz#b0db6bc81ffc7bdc52eb0f84d6ca0bedf0e36d21" + integrity sha512-rm0bdSv4jC3BDma3s9H19ZddW0aHX6EoqwDYU2IfZhRN+53QrufTRo2IdkAbRqLx4R2IYbZnbjKKxg4VN5oU9Q== dependencies: icss-utils "^5.0.0" - postcss-selector-parser "^6.0.2" + postcss-selector-parser "^7.0.0" postcss-value-parser "^4.1.0" postcss-modules-scope@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-3.2.0.tgz#a43d28289a169ce2c15c00c4e64c0858e43457d5" - integrity sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ== + version "3.2.1" + resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-3.2.1.tgz#1bbccddcb398f1d7a511e0a2d1d047718af4078c" + integrity sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA== dependencies: - postcss-selector-parser "^6.0.4" + postcss-selector-parser "^7.0.0" postcss-modules-values@^4.0.0: version "4.0.0" @@ -10768,7 +9780,7 @@ postcss-modules-values@^4.0.0: dependencies: icss-utils "^5.0.0" -postcss-nested@^6.0.1: +postcss-nested@^6.2.0: version "6.2.0" resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-6.2.0.tgz#4c2d22ab5f20b9cb61e2c5c5915950784d068131" integrity sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ== @@ -10869,7 +9881,7 @@ postcss-selector-parser@6.0.10: cssesc "^3.0.0" util-deprecate "^1.0.2" -postcss-selector-parser@^6.0.11, postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.5, postcss-selector-parser@^6.0.9, postcss-selector-parser@^6.1.1: +postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.5, postcss-selector-parser@^6.0.9, postcss-selector-parser@^6.1.1, postcss-selector-parser@^6.1.2: version "6.1.2" resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz#27ecb41fb0e3b6ba7a1ec84fff347f734c7929de" integrity sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg== @@ -10877,6 +9889,14 @@ postcss-selector-parser@^6.0.11, postcss-selector-parser@^6.0.2, postcss-selecto cssesc "^3.0.0" util-deprecate "^1.0.2" +postcss-selector-parser@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz#41bd8b56f177c093ca49435f65731befe25d6b9c" + integrity sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ== + dependencies: + cssesc "^3.0.0" + util-deprecate "^1.0.2" + postcss-svgo@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-5.1.0.tgz#0a317400ced789f233a28826e77523f15857d80d" @@ -10892,30 +9912,12 @@ postcss-unique-selectors@^5.1.1: dependencies: postcss-selector-parser "^6.0.5" -postcss-value-parser@^4.0.0, postcss-value-parser@^4.0.2, postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0: +postcss-value-parser@^4.0.0, postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== -postcss@8.4.38: - version "8.4.38" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.38.tgz#b387d533baf2054288e337066d81c6bee9db9e0e" - integrity sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A== - dependencies: - nanoid "^3.3.7" - picocolors "^1.0.0" - source-map-js "^1.2.0" - -postcss@^8.2.15, postcss@^8.2.9, postcss@^8.4.23, postcss@^8.4.24: - version "8.4.47" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.47.tgz#5bf6c9a010f3e724c503bf03ef7947dcb0fea365" - integrity sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ== - dependencies: - nanoid "^3.3.7" - picocolors "^1.1.0" - source-map-js "^1.2.1" - -postcss@^8.4.49: +postcss@^8.2.15, postcss@^8.2.9, postcss@^8.4.24, postcss@^8.4.47, postcss@^8.4.49: version "8.4.49" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.49.tgz#4ea479048ab059ab3ae61d082190fabfd994fe19" integrity sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA== @@ -11085,11 +10087,6 @@ quick-lru@^5.1.1: resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== -quickselect@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/quickselect/-/quickselect-2.0.0.tgz#f19680a486a5eefb581303e023e98faaf25dd018" - integrity sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw== - randombytes@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" @@ -11120,13 +10117,6 @@ raw-loader@^4.0.2: loader-utils "^2.0.0" schema-utils "^3.0.0" -rbush@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/rbush/-/rbush-3.0.1.tgz#5fafa8a79b3b9afdfe5008403a720cc1de882ecf" - integrity sha512-XRaVO0YecOpEuIvbhbpTrZgoiI6xBlz6hnlr6EHhd+0x9ase6EmeN+hdwwUaJvLcsFFQ8iWVF1GAK1yB0BWi0w== - dependencies: - quickselect "^2.0.0" - rc-cascader@~3.30.0: version "3.30.0" resolved "https://registry.yarnpkg.com/rc-cascader/-/rc-cascader-3.30.0.tgz#da3e35cadcc00c58c62a6757eca6c7147ff94ea8" @@ -11189,7 +10179,7 @@ rc-dropdown@~4.2.0: classnames "^2.2.6" rc-util "^5.17.0" -rc-field-form@~2.5.0: +rc-field-form@~2.5.1: version "2.5.1" resolved "https://registry.yarnpkg.com/rc-field-form/-/rc-field-form-2.5.1.tgz#30f3c529f86aec6af27589052df9c66cec94ceb4" integrity sha512-33hunXwynQJyeae7LS3hMGTXNeRBjiPyPYgB0824EbmLHiXC1EBGyUwRh6xjLRy9c+en5WARYN0gJz5+JAqwig== @@ -11293,7 +10283,7 @@ rc-pagination@~4.3.0: classnames "^2.3.2" rc-util "^5.38.0" -rc-picker@~4.8.0: +rc-picker@~4.8.1: version "4.8.1" resolved "https://registry.yarnpkg.com/rc-picker/-/rc-picker-4.8.1.tgz#105cfae323bf1db5e9f9e6fdc773ff3250e837de" integrity sha512-lj9hXXMSkbjFUIhfQh8XH698ybxnoBOfq7pdM1FvfSyDwdFhdQa7dvsIYwo6Uz7Zp1wVkfw5rOJO3MpdWzoHsg== @@ -11429,9 +10419,9 @@ rc-tooltip@~6.2.1: classnames "^2.3.1" rc-tree-select@~5.24.4: - version "5.24.4" - resolved "https://registry.yarnpkg.com/rc-tree-select/-/rc-tree-select-5.24.4.tgz#6789b8761daf53a8b91b75e9e6c4f720a7e8cc92" - integrity sha512-MzljkSkk7weKOcE853UtYlXB6uyUEzcEQhhpaCwE6jQPbmBUgGiRURuKWpYUnM/dXrwTTlCK969M6Pgjj35MLA== + version "5.24.5" + resolved "https://registry.yarnpkg.com/rc-tree-select/-/rc-tree-select-5.24.5.tgz#a1bf85c7d5e4979880cfb0748bb6bab937ed3483" + integrity sha512-PnyR8LZJWaiEFw0SHRqo4MNQWyyZsyMs8eNmo68uXZWjxc7QqeWcjPPoONN0rc90c3HZqGF9z+Roz+GLzY5GXA== dependencies: "@babel/runtime" "^7.25.7" classnames "2.x" @@ -11468,9 +10458,9 @@ rc-util@^5.0.1, rc-util@^5.16.1, rc-util@^5.17.0, rc-util@^5.18.1, rc-util@^5.2. react-is "^18.2.0" rc-virtual-list@^3.14.2, rc-virtual-list@^3.5.1, rc-virtual-list@^3.5.2: - version "3.14.8" - resolved "https://registry.yarnpkg.com/rc-virtual-list/-/rc-virtual-list-3.14.8.tgz#abf6e8809b7f5c955aa7f59c2a9d57443e9942fd" - integrity sha512-8D0KfzpRYi6YZvlOWIxiOm9BGt4Wf2hQyEaM6RXlDDiY2NhLheuYI+RA+7ZaZj1lq+XQqy3KHlaeeXQfzI5fGg== + version "3.15.0" + resolved "https://registry.yarnpkg.com/rc-virtual-list/-/rc-virtual-list-3.15.0.tgz#45c5b1ef1363287214e0a3c17af29ee0c3764764" + integrity sha512-dF2YQztqrU3ijAeWOqscTshCEr7vpimzSqAVjO1AyAmaqcHulaXpnGR0ptK5PXfxTUy48VkJOiglMIxlkYGs0w== dependencies: "@babel/runtime" "^7.20.0" classnames "^2.2.6" @@ -11556,15 +10546,6 @@ react-markdown@^9.0.1: unist-util-visit "^5.0.0" vfile "^6.0.0" -react-reconciler@^0.26.2: - version "0.26.2" - resolved "https://registry.yarnpkg.com/react-reconciler/-/react-reconciler-0.26.2.tgz#bbad0e2d1309423f76cf3c3309ac6c96e05e9d91" - integrity sha512-nK6kgY28HwrMNwDnMui3dvm3rCFjZrcGiuwLc5COUipBK5hWHLOxMJhSnSomirqWwjPBJKV1QcbkI0VJr7Gl1Q== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - scheduler "^0.20.2" - react-refresh@^0.14.0: version "0.14.2" resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.2.tgz#3833da01ce32da470f1f936b9d477da5c7028bf9" @@ -11655,7 +10636,7 @@ redux@4.2.1: dependencies: "@babel/runtime" "^7.9.2" -reflect.getprototypeof@^1.0.4: +reflect.getprototypeof@^1.0.4, reflect.getprototypeof@^1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz#3ab04c32a8390b770712b7a8633972702d278859" integrity sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg== @@ -11697,7 +10678,7 @@ regenerator-transform@^0.15.2: dependencies: "@babel/runtime" "^7.8.4" -regexp.prototype.flags@^1.5.1, regexp.prototype.flags@^1.5.2: +regexp.prototype.flags@^1.5.2, regexp.prototype.flags@^1.5.3: version "1.5.3" resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.3.tgz#b3ae40b1d2499b8350ab2c3fe6ef3845d3a96f42" integrity sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ== @@ -11713,14 +10694,14 @@ regexpp@^3.1.0: integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== regexpu-core@^6.1.1: - version "6.1.1" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-6.1.1.tgz#b469b245594cb2d088ceebc6369dceb8c00becac" - integrity sha512-k67Nb9jvwJcJmVpw0jPttR1/zVfnKf8Km0IPatrU/zJ5XeG3+Slx0xLXs9HByJSzXzrlz5EDvN6yLNMDc2qdnw== + version "6.2.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-6.2.0.tgz#0e5190d79e542bf294955dccabae04d3c7d53826" + integrity sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA== dependencies: regenerate "^1.4.2" regenerate-unicode-properties "^10.2.0" regjsgen "^0.8.0" - regjsparser "^0.11.0" + regjsparser "^0.12.0" unicode-match-property-ecmascript "^2.0.0" unicode-match-property-value-ecmascript "^2.1.0" @@ -11743,10 +10724,10 @@ regjsgen@^0.8.0: resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.8.0.tgz#df23ff26e0c5b300a6470cad160a9d090c3a37ab" integrity sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q== -regjsparser@^0.11.0: - version "0.11.2" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.11.2.tgz#7404ad42be00226d72bcf1f003f1f441861913d8" - integrity sha512-3OGZZ4HoLJkkAZx/48mTXJNlmqTGOzc0o9OWQPuWpkOlXXPbyN6OafCcoXUnBqE2D3f/T5L+pWc1kdEmnfnRsA== +regjsparser@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.12.0.tgz#0e846df6c6530586429377de56e0475583b088dc" + integrity sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ== dependencies: jsesc "~3.0.2" @@ -11846,11 +10827,6 @@ renderkid@^2.0.4: lodash "^4.17.21" strip-ansi "^3.0.1" -repeat-string@^1.5.2: - version "1.6.1" - resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" - integrity sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w== - require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -11898,7 +10874,7 @@ resolve-from@^5.0.0: resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== -resolve@^1.1.7, resolve@^1.10.0, resolve@^1.14.2, resolve@^1.19.0, resolve@^1.22.2, resolve@^1.22.4, resolve@~1.22.6: +resolve@^1.1.7, resolve@^1.10.0, resolve@^1.14.2, resolve@^1.19.0, resolve@^1.22.4, resolve@^1.22.8: version "1.22.8" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== @@ -11948,13 +10924,6 @@ reusify@^1.0.4: resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== -right-align@^0.1.1: - version "0.1.3" - resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" - integrity sha512-yqINtL/G7vs2v+dFIZmFUDbnVyFUJFKd6gK22Kgo6R4jfJGFtisKyncWDDULgjfqf4ASQuIQyjJ7XZ+3aWpsAg== - dependencies: - align-text "^0.1.1" - rimraf@^2.6.2: version "2.7.1" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" @@ -11969,15 +10938,6 @@ rimraf@^3.0.2: dependencies: glob "^7.1.3" -rollup@^0.25.8: - version "0.25.8" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-0.25.8.tgz#bf6ce83b87510d163446eeaa577ed6a6fc5835e0" - integrity sha512-a2S4Bh3bgrdO4BhKr2E4nZkjTvrJ2m2bWjMTzVYtoqSCn0HnuxosXnaJUHrMEziOWr3CzL9GjilQQKcyCQpJoA== - dependencies: - chalk "^1.1.1" - minimist "^1.2.0" - source-map-support "^0.3.2" - run-async@^2.4.0: version "2.4.1" resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" @@ -11990,11 +10950,6 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -rw@1, rw@^1.3.2: - version "1.3.3" - resolved "https://registry.yarnpkg.com/rw/-/rw-1.3.3.tgz#3f862dfa91ab766b14885ef4d01124bfda074fb4" - integrity sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ== - rxjs@^6.6.0: version "6.6.7" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" @@ -12038,7 +10993,7 @@ safe-regex-test@^1.0.3: es-errors "^1.3.0" is-regex "^1.1.4" -"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": +"safer-buffer@>= 2.1.2 < 3": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== @@ -12048,14 +11003,6 @@ sax@^1.2.4: resolved "https://registry.yarnpkg.com/sax/-/sax-1.4.1.tgz#44cc8988377f126304d3b3fc1010c733b929ef0f" integrity sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg== -scheduler@^0.20.2: - version "0.20.2" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91" - integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - scheduler@^0.23.2: version "0.23.2" resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.2.tgz#414ba64a3b282892e944cf2108ecc078d115cdc3" @@ -12231,11 +11178,6 @@ shallow-compare@^1.2.2: resolved "https://registry.yarnpkg.com/shallow-compare/-/shallow-compare-1.2.2.tgz#fa4794627bf455a47c4f56881d8a6132d581ffdb" integrity sha512-LUMFi+RppPlrHzbqmFnINTrazo0lPNwhcgzuAXVVcfy/mqPDrQmHAyz5bvV0gDAuRFrk804V0HpQ6u9sZ0tBeg== -shallowequal@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8" - integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ== - sharp@^0.32.6: version "0.32.6" resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.32.6.tgz#6ad30c0b7cd910df65d5f355f774aa4fce45732a" @@ -12399,18 +11341,11 @@ source-list-map@^2.0.0: resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== -source-map-js@^1.2.0, source-map-js@^1.2.1: +source-map-js@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== -source-map-support@^0.3.2: - version "0.3.3" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.3.3.tgz#34900977d5ba3f07c7757ee72e73bb1a9b53754f" - integrity sha512-9O4+y9n64RewmFoKUZ/5Tx9IHIcXM6Q+RTSw6ehnqybUz4a7iwR3Eaw80uLtqqQ5D0C+5H03D4KKGo9PdP33Gg== - dependencies: - source-map "0.1.32" - source-map-support@~0.5.20: version "0.5.21" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" @@ -12419,13 +11354,6 @@ source-map-support@~0.5.20: buffer-from "^1.0.0" source-map "^0.6.0" -source-map@0.1.32: - version "0.1.32" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.32.tgz#c8b6c167797ba4740a8ea33252162ff08591b266" - integrity sha512-htQyLrrRLkQ87Zfrir4/yN+vAUd6DNjVayEjTSHXu29AYQJw57I4/xEL/M6p6E/woPNJwvZt6rVlzc7gFEJccQ== - dependencies: - amdefine ">=0.0.4" - source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" @@ -12436,11 +11364,6 @@ source-map@^0.7.0, source-map@^0.7.3: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656" integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA== -source-map@~0.5.1: - version "0.5.7" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== - space-separated-tokens@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz#1ecd9d2350a3844572c3f4a312bceb018348859f" @@ -12501,9 +11424,9 @@ streamsearch@^1.1.0: integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== streamx@^2.15.0, streamx@^2.20.0: - version "2.20.1" - resolved "https://registry.yarnpkg.com/streamx/-/streamx-2.20.1.tgz#471c4f8b860f7b696feb83d5b125caab2fdbb93c" - integrity sha512-uTa0mU6WUC65iUvzKH4X9hEdvSW7rbPxPtwfWiLMSj3qTdQbAiUboZTxauKfpFuGIGa1C2BYijZ7wgdUXICJhA== + version "2.20.2" + resolved "https://registry.yarnpkg.com/streamx/-/streamx-2.20.2.tgz#6a8911959d6f307c19781a1d19ecd94b5f042d78" + integrity sha512-aDGDLU+j9tJcUdPGOaHmVF1u/hhI+CsGkT02V3OKlHDV7IukOI+nTWAGkiZEKCO35rWN1wIr4tS7YFr1f4qSvA== dependencies: fast-fifo "^1.3.2" queue-tick "^1.0.1" @@ -12599,7 +11522,7 @@ string.prototype.repeat@^1.0.0: define-properties "^1.1.3" es-abstract "^1.17.5" -string.prototype.trim@^1.2.9, string.prototype.trim@~1.2.8: +string.prototype.trim@^1.2.9: version "1.2.9" resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz#b6fa326d72d2c78b6df02f7759c73f8f6274faa4" integrity sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw== @@ -12656,7 +11579,7 @@ stringify-entities@^4.0.0: dependencies: ansi-regex "^5.0.1" -strip-ansi@^3.0.0, strip-ansi@^3.0.1: +strip-ansi@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" integrity sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg== @@ -12751,21 +11674,6 @@ style-to-object@^1.0.0: dependencies: inline-style-parser "0.2.4" -styled-components@^6.1.13: - version "6.1.13" - resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-6.1.13.tgz#2d777750b773b31469bd79df754a32479e9f475e" - integrity sha512-M0+N2xSnAtwcVAQeFEsGWFFxXDftHUD7XrKla06QbpUMmbmtFBMMTcKWvFXtWxuD5qQkB8iU5gk6QASlx2ZRMw== - dependencies: - "@emotion/is-prop-valid" "1.2.2" - "@emotion/unitless" "0.8.1" - "@types/stylis" "4.2.5" - css-to-react-native "3.2.0" - csstype "3.1.3" - postcss "8.4.38" - shallowequal "1.1.0" - stylis "4.3.2" - tslib "2.6.2" - stylehacks@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-5.1.1.tgz#7934a34eb59d7152149fa69d6e9e56f2fc34bcc9" @@ -12774,17 +11682,12 @@ stylehacks@^5.1.1: browserslist "^4.21.4" postcss-selector-parser "^6.0.4" -stylis@4.3.2: - version "4.3.2" - resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.3.2.tgz#8f76b70777dd53eb669c6f58c997bf0a9972e444" - integrity sha512-bhtUjWd/z6ltJiQwg0dUfxEJ+W+jdqQd8TbWLWyeIJHlnsqmGLRFFd8e5mA0AZi/zx90smXRlN66YMTcaSFifg== - -stylis@^4.3.3: +stylis@^4.3.4: version "4.3.4" resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.3.4.tgz#ca5c6c4a35c4784e4e93a2a24dc4e9fa075250a4" integrity sha512-osIBl6BGUmSfDkyH2mB7EFvCJntXDrLhKjHTRj/rK6xLH0yuPrHULDRQzKokSOD4VoorhtKpfcfW1GAntu8now== -sucrase@^3.32.0: +sucrase@^3.35.0: version "3.35.0" resolved "https://registry.yarnpkg.com/sucrase/-/sucrase-3.35.0.tgz#57f17a3d7e19b36d8995f06679d121be914ae263" integrity sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA== @@ -12802,11 +11705,6 @@ sudo-prompt@^8.2.0: resolved "https://registry.yarnpkg.com/sudo-prompt/-/sudo-prompt-8.2.5.tgz#cc5ef3769a134bb94b24a631cc09628d4d53603e" integrity sha512-rlBo3HU/1zAJUrkY6jNxDOC9eVYliG6nS4JA8u8KAshITd07tafMc/Br7xQwCSseXwJ2iCcHCE8SNWX3q8Z+kw== -supports-color@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - integrity sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g== - supports-color@^5.3.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" @@ -12833,11 +11731,6 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== -svg-path-parser@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/svg-path-parser/-/svg-path-parser-1.1.0.tgz#e16b4b39df0d2b0d39e8347db79fdda1453a6046" - integrity sha512-jGCUqcQyXpfe38R7RFfhrMyfXcBmpMNJI/B+4CE9/Unkh98UporAc461GTthv+TVDuZXsBx7/WiwJb1Oh4tt4A== - svgo@^2.7.0: version "2.8.0" resolved "https://registry.yarnpkg.com/svgo/-/svgo-2.8.0.tgz#4ff80cce6710dc2795f0c7c74101e6764cfccd24" @@ -12880,32 +11773,32 @@ table@^6.0.9: strip-ansi "^6.0.1" tailwindcss@^3.4.14: - version "3.4.14" - resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.4.14.tgz#6dd23a7f54ec197b19159e91e3bb1e55e7aa73ac" - integrity sha512-IcSvOcTRcUtQQ7ILQL5quRDg7Xs93PdJEk1ZLbhhvJc7uj/OAhYOnruEiwnGgBvUtaUAJ8/mhSw1o8L2jCiENA== + version "3.4.15" + resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.4.15.tgz#04808bf4bf1424b105047d19e7d4bfab368044a9" + integrity sha512-r4MeXnfBmSOuKUWmXe6h2CcyfzJCEk4F0pptO5jlnYSIViUkVmsawj80N5h2lO3gwcmSb4n3PuN+e+GC1Guylw== dependencies: "@alloc/quick-lru" "^5.2.0" arg "^5.0.2" - chokidar "^3.5.3" + chokidar "^3.6.0" didyoumean "^1.2.2" dlv "^1.1.3" - fast-glob "^3.3.0" + fast-glob "^3.3.2" glob-parent "^6.0.2" is-glob "^4.0.3" - jiti "^1.21.0" + jiti "^1.21.6" lilconfig "^2.1.0" - micromatch "^4.0.5" + micromatch "^4.0.8" normalize-path "^3.0.0" object-hash "^3.0.0" - picocolors "^1.0.0" - postcss "^8.4.23" + picocolors "^1.1.1" + postcss "^8.4.47" postcss-import "^15.1.0" postcss-js "^4.0.1" - postcss-load-config "^4.0.1" - postcss-nested "^6.0.1" - postcss-selector-parser "^6.0.11" - resolve "^1.22.2" - sucrase "^3.32.0" + postcss-load-config "^4.0.2" + postcss-nested "^6.2.0" + postcss-selector-parser "^6.1.2" + resolve "^1.22.8" + sucrase "^3.35.0" tapable@^1.0.0: version "1.1.3" @@ -12917,28 +11810,6 @@ tapable@^2.1.1, tapable@^2.2.0: resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== -tape@^4.5.1: - version "4.17.0" - resolved "https://registry.yarnpkg.com/tape/-/tape-4.17.0.tgz#de89f3671ddc5dad178d04c28dc6b0183f42268e" - integrity sha512-KCuXjYxCZ3ru40dmND+oCLsXyuA8hoseu2SS404Px5ouyS0A99v8X/mdiLqsR5MTAyamMBN7PRwt2Dv3+xGIxw== - dependencies: - "@ljharb/resumer" "~0.0.1" - "@ljharb/through" "~2.3.9" - call-bind "~1.0.2" - deep-equal "~1.1.1" - defined "~1.0.1" - dotignore "~0.1.2" - for-each "~0.3.3" - glob "~7.2.3" - has "~1.0.3" - inherits "~2.0.4" - is-regex "~1.1.4" - minimist "~1.2.8" - mock-property "~1.0.0" - object-inspect "~1.12.3" - resolve "~1.22.6" - string.prototype.trim "~1.2.8" - tar-fs@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784" @@ -13129,17 +12000,12 @@ tsconfig-paths@^3.15.0: minimist "^1.2.6" strip-bom "^3.0.0" -tslib@2.6.2: - version "2.6.2" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" - integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== - tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.1, tslib@^2.4.0, tslib@^2.5.0, tslib@^2.5.3, tslib@^2.8.0: +tslib@^2.0.3, tslib@^2.1.0, tslib@^2.4.0, tslib@^2.8.0: version "2.8.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== @@ -13224,9 +12090,9 @@ typed-array-byte-length@^1.0.1: is-typed-array "^1.1.13" typed-array-byte-offset@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz#f9ec1acb9259f395093e4567eb3c28a580d02063" - integrity sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA== + version "1.0.3" + resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.3.tgz#3fa9f22567700cc86aaf86a1e7176f74b59600f2" + integrity sha512-GsvTyUHTriq6o/bHcTd0vM7OQ9JEdlvluu9YISaA7+KzDzPaIzEeDFNkTfhdE3MYcNhNi0vq/LlegYgIs5yPAw== dependencies: available-typed-arrays "^1.0.7" call-bind "^1.0.7" @@ -13234,6 +12100,7 @@ typed-array-byte-offset@^1.0.2: gopd "^1.0.1" has-proto "^1.0.3" is-typed-array "^1.1.13" + reflect.getprototypeof "^1.0.6" typed-array-length@^1.0.6: version "1.0.6" @@ -13260,30 +12127,15 @@ typedarray@^0.0.6: integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA== typescript@^5.3.3: - version "5.6.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.6.3.tgz#5f3449e31c9d94febb17de03cc081dd56d81db5b" - integrity sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw== + version "5.7.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.7.2.tgz#3169cf8c4c8a828cde53ba9ecb3d2b1d5dd67be6" + integrity sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg== ua-parser-js@^1.0.35: version "1.0.39" resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-1.0.39.tgz#bfc07f361549bf249bd8f4589a4cccec18fd2018" integrity sha512-k24RCVWlEcjkdOxYmVJgeD/0a1TiSpqLg+ZalVGV9lsnr4yqu0w7tX/x2xX6G4zpkgQnRf89lxuZ1wsbjXM8lw== -uglify-js@^2.6.2: - version "2.8.29" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd" - integrity sha512-qLq/4y2pjcU3vhlhseXGGJ7VbFO4pBANu0kwl8VCa9KEI0V8VfZIx2Fy3w01iSTA/pGwKZSmu/+I4etLNDdt5w== - dependencies: - source-map "~0.5.1" - yargs "~3.10.0" - optionalDependencies: - uglify-to-browserify "~1.0.0" - -uglify-to-browserify@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" - integrity sha512-vb2s1lYx2xBtUgy+ta+b2J/GLVUR+wmpINwHePmPRhOsIVCG2wDzKJ0n14GslH1BifsqVzSOwQhRaCAsZ/nI4Q== - unbox-primitive@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" @@ -13829,21 +12681,11 @@ wildcard@^2.0.0: resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.1.tgz#5ab10d02487198954836b6349f74fff961e10f67" integrity sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ== -window-size@0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" - integrity sha512-1pTPQDKTdd61ozlKGNCjhNRd+KPmgLSGa3mZTHoOliaGcESD8G1PXhh7c1fgiPjVbNVfgy2Faw4BI8/m0cC8Mg== - word-wrap@^1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== -wordwrap@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" - integrity sha512-xSBsCeh+g+dinoBv3GAOWM4LcVVO68wLXRanibtBSdUvkGWQRGeE9P7IwU9EmDDi4jA6L44lz15CGMwdw9N5+Q== - "wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" @@ -13960,9 +12802,9 @@ yaml@^1.10.0, yaml@^1.10.2, yaml@^1.7.2: integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== yaml@^2.0.0, yaml@^2.3.4: - version "2.6.0" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.6.0.tgz#14059ad9d0b1680d0f04d3a60fe00f3a857303c3" - integrity sha512-a6ae//JvKDEra2kdi1qzCyrJW/WZCgFi8ydDV+eXExl95t+5R+ijnqHJbz9tmMh8FUjx3iv2fCQ4dclAQlO2UQ== + version "2.6.1" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.6.1.tgz#42f2b1ba89203f374609572d5349fb8686500773" + integrity sha512-7r0XPzioN/Q9kXBro/XPnA6kznR73DHq+GXh5ON7ZozRO6aMjbmiBuKste2wslTFkC5d1dw0GooOCepZXJ2SAg== yargs-parser@^18.1.2: version "18.1.3" @@ -13989,16 +12831,6 @@ yargs@^15.3.1, yargs@^15.4.1: y18n "^4.0.0" yargs-parser "^18.1.2" -yargs@~3.10.0: - version "3.10.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" - integrity sha512-QFzUah88GAGy9lyDKGBqZdkYApt63rCXYBGYnEP4xDJPXNqXXnBDACnbrXnViV6jRSqAePwrATi2i8mfYm4L1A== - dependencies: - camelcase "^1.0.2" - cliui "^2.1.0" - decamelize "^1.0.0" - window-size "0.1.0" - yarn@^1.22.22: version "1.22.22" resolved "https://registry.yarnpkg.com/yarn/-/yarn-1.22.22.tgz#ac34549e6aa8e7ead463a7407e1c7390f61a6610" diff --git a/python/packages/autogen-studio/notebooks/tutorial.ipynb b/python/packages/autogen-studio/notebooks/tutorial.ipynb index 8e749f743839..432f94587651 100644 --- a/python/packages/autogen-studio/notebooks/tutorial.ipynb +++ b/python/packages/autogen-studio/notebooks/tutorial.ipynb @@ -16,17 +16,9 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "task_result=TaskResult(messages=[TextMessage(source='user', models_usage=None, content='What is the weather in New York?'), ToolCallMessage(source='writing_agent', models_usage=RequestUsage(prompt_tokens=65, completion_tokens=15), content=[FunctionCall(id='call_x8C5nib1PJkMZGQ6zrNUlfa0', arguments='{\"city\":\"New York\"}', name='get_weather')]), ToolCallResultMessage(source='writing_agent', models_usage=None, content=[FunctionExecutionResult(content='The weather in New York is 73 degrees and Sunny.', call_id='call_x8C5nib1PJkMZGQ6zrNUlfa0')]), TextMessage(source='writing_agent', models_usage=RequestUsage(prompt_tokens=97, completion_tokens=14), content='The weather in New York is currently 73 degrees and sunny.'), TextMessage(source='writing_agent', models_usage=RequestUsage(prompt_tokens=123, completion_tokens=13), content='Would you like to know the weather in any other city?')], stop_reason='Maximum number of messages 5 reached, current message count: 5') usage='' duration=1.9984567165374756\n" - ] - } - ], + "outputs": [], "source": [ "from autogenstudio.teammanager import TeamManager \n", " \n", @@ -37,22 +29,9 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "source='user' models_usage=None content='What is the weather in New York?'\n", - "source='writing_agent' models_usage=RequestUsage(prompt_tokens=65, completion_tokens=15) content=[FunctionCall(id='call_Gwnfsa8ndnOsXTvRECTr92hr', arguments='{\"city\":\"New York\"}', name='get_weather')]\n", - "source='writing_agent' models_usage=None content=[FunctionExecutionResult(content='The weather in New York is 73 degrees and Sunny.', call_id='call_Gwnfsa8ndnOsXTvRECTr92hr')]\n", - "source='writing_agent' models_usage=RequestUsage(prompt_tokens=97, completion_tokens=14) content='The weather in New York is currently 73 degrees and sunny.'\n", - "source='writing_agent' models_usage=RequestUsage(prompt_tokens=123, completion_tokens=14) content='The weather in New York is currently 73 degrees and sunny.'\n", - "task_result=TaskResult(messages=[TextMessage(source='user', models_usage=None, content='What is the weather in New York?'), ToolCallMessage(source='writing_agent', models_usage=RequestUsage(prompt_tokens=65, completion_tokens=15), content=[FunctionCall(id='call_Gwnfsa8ndnOsXTvRECTr92hr', arguments='{\"city\":\"New York\"}', name='get_weather')]), ToolCallResultMessage(source='writing_agent', models_usage=None, content=[FunctionExecutionResult(content='The weather in New York is 73 degrees and Sunny.', call_id='call_Gwnfsa8ndnOsXTvRECTr92hr')]), TextMessage(source='writing_agent', models_usage=RequestUsage(prompt_tokens=97, completion_tokens=14), content='The weather in New York is currently 73 degrees and sunny.'), TextMessage(source='writing_agent', models_usage=RequestUsage(prompt_tokens=123, completion_tokens=14), content='The weather in New York is currently 73 degrees and sunny.')], stop_reason='Maximum number of messages 5 reached, current message count: 5') usage='' duration=2.363379955291748\n" - ] - } - ], + "outputs": [], "source": [ "result_stream = wm.run_stream(task=\"What is the weather in New York?\", team_config=\"team.json\") \n", "async for response in result_stream:\n", @@ -74,28 +53,32 @@ "metadata": {}, "outputs": [ { - "name": "stderr", - "output_type": "stream", - "text": [ - "INFO [alembic.runtime.migration] Context impl SQLiteImpl.\n", - "INFO [alembic.runtime.migration] Will assume non-transactional DDL.\n", - "\u001b[32m2024-11-14 09:06:25.242\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mautogenstudio.database.schema_manager\u001b[0m:\u001b[36mupgrade_schema\u001b[0m:\u001b[36m390\u001b[0m - \u001b[1mSchema upgraded successfully to head\u001b[0m\n", - "\u001b[32m2024-11-14 09:06:25.243\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mautogenstudio.database.db_manager\u001b[0m:\u001b[36m__init__\u001b[0m:\u001b[36m34\u001b[0m - \u001b[1mDatabase schema was upgraded automatically\u001b[0m\n", - "\u001b[32m2024-11-14 09:06:25.244\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mautogenstudio.database.db_manager\u001b[0m:\u001b[36mcreate_db_and_tables\u001b[0m:\u001b[36m108\u001b[0m - \u001b[1mDatabase tables created successfully\u001b[0m\n" - ] + "data": { + "text/plain": [ + "Response(message='Database is ready', status=True, data=None)" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" } ], "source": [ "from autogenstudio.database import DatabaseManager \n", + "import os \n", + "# delete database\n", + "# if os.path.exists(\"test.db\"):\n", + "# os.remove(\"test.db\") \n", "\n", + "os.makedirs(\"test\", exist_ok=True)\n", "# create a database\n", - "dbmanager = DatabaseManager(engine_uri=\"sqlite:///test.db\")\n", - "dbmanager.create_db_and_tables() " + "dbmanager = DatabaseManager(engine_uri=\"sqlite:///test.db\", base_dir=\"test\")\n", + "dbmanager.initialize_database() " ] }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 6, "metadata": {}, "outputs": [], "source": [ @@ -145,14 +128,14 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "53 teams in database\n" + "2 teams in database\n" ] } ], @@ -172,7 +155,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -194,17 +177,9 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "message='Directory import complete' status=True data=[{'component': 'team', 'status': True, 'message': 'Team Created Successfully', 'id': 54}]\n" - ] - } - ], + "outputs": [], "source": [ "result = await config_manager.import_directory(\".\", user_id=\"user_id\", check_exists=False)\n", "print(result)" @@ -212,17 +187,9 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "54 teams in database\n" - ] - } - ], + "outputs": [], "source": [ "all_teams = dbmanager.get(Team)\n", "print(len(all_teams.data), \"teams in database\")" @@ -237,7 +204,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -282,22 +249,9 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "source='user' models_usage=None content='Plan a 3 day trip to Nepal.'\n", - "source='planner_agent' models_usage=RequestUsage(prompt_tokens=45, completion_tokens=54) content=\"Consider starting your 3-day trip to Nepal with a cultural tour in Kathmandu Valley, followed by an exploration of Pokhara's natural beauty on the second day, and finally, indulge in a thrilling safari at Chitwan National Park on the third day.\"\n", - "source='local_agent' models_usage=RequestUsage(prompt_tokens=116, completion_tokens=54) content=\"Consider starting your 3-day trip to Nepal with a cultural tour in Kathmandu Valley, followed by an exploration of Pokhara's natural beauty on the second day, and finally, indulge in a thrilling safari at Chitwan National Park on the third day.\"\n", - "source='language_agent' models_usage=RequestUsage(prompt_tokens=201, completion_tokens=45) content=\"Your travel plan lacks a mention of dealing with potential language barriers; it might be useful to learn some phrases in Nepali, as it's the official language of Nepal, or have a local translation app handy during your trip.\"\n", - "source='travel_summary_agent' models_usage=RequestUsage(prompt_tokens=270, completion_tokens=237) content='Day 1: Start your adventure in the capital city, Kathmandu. Take a guided tour of Kathmandu Valley to explore its UNESCO World Heritage Sites, such as the Durbar Squares, Swayambhunath Stupa, and Boudhanath Stupa. Engage with the locals and sample some traditional Nepalese cuisine.\\n\\nDay 2: Proceed to Pokhara, known for its stunning natural beauty. Visit the iconic Phewa Lake and enjoy a boat ride, then trek to the Peace Pagoda for a panoramic view of the city. Round off the day with a visit to the fascinating Pokhara Mountain Museum.\\n\\nDay 3: Travel to Chitwan National Park for a memorable safari. Explore the diverse wildlife and lush vegetation that make the park a UNESCO World Heritage site. Be on the lookout for rhinos, Bengal tigers, and a multitude of bird species.\\n\\nNote: Communication is key to enjoying your trip. The official language of Nepal is Nepali. It can be helpful to learn a few basic phrases or carry a translation app to help you interact with the local people and enrich your cultural experience.\\n\\nTERMINATE.'\n", - "TaskResult(messages=[TextMessage(source='user', models_usage=None, content='Plan a 3 day trip to Nepal.'), TextMessage(source='planner_agent', models_usage=RequestUsage(prompt_tokens=45, completion_tokens=54), content=\"Consider starting your 3-day trip to Nepal with a cultural tour in Kathmandu Valley, followed by an exploration of Pokhara's natural beauty on the second day, and finally, indulge in a thrilling safari at Chitwan National Park on the third day.\"), TextMessage(source='local_agent', models_usage=RequestUsage(prompt_tokens=116, completion_tokens=54), content=\"Consider starting your 3-day trip to Nepal with a cultural tour in Kathmandu Valley, followed by an exploration of Pokhara's natural beauty on the second day, and finally, indulge in a thrilling safari at Chitwan National Park on the third day.\"), TextMessage(source='language_agent', models_usage=RequestUsage(prompt_tokens=201, completion_tokens=45), content=\"Your travel plan lacks a mention of dealing with potential language barriers; it might be useful to learn some phrases in Nepali, as it's the official language of Nepal, or have a local translation app handy during your trip.\"), TextMessage(source='travel_summary_agent', models_usage=RequestUsage(prompt_tokens=270, completion_tokens=237), content='Day 1: Start your adventure in the capital city, Kathmandu. Take a guided tour of Kathmandu Valley to explore its UNESCO World Heritage Sites, such as the Durbar Squares, Swayambhunath Stupa, and Boudhanath Stupa. Engage with the locals and sample some traditional Nepalese cuisine.\\n\\nDay 2: Proceed to Pokhara, known for its stunning natural beauty. Visit the iconic Phewa Lake and enjoy a boat ride, then trek to the Peace Pagoda for a panoramic view of the city. Round off the day with a visit to the fascinating Pokhara Mountain Museum.\\n\\nDay 3: Travel to Chitwan National Park for a memorable safari. Explore the diverse wildlife and lush vegetation that make the park a UNESCO World Heritage site. Be on the lookout for rhinos, Bengal tigers, and a multitude of bird species.\\n\\nNote: Communication is key to enjoying your trip. The official language of Nepal is Nepali. It can be helpful to learn a few basic phrases or carry a translation app to help you interact with the local people and enrich your cultural experience.\\n\\nTERMINATE.')], stop_reason=\"Text 'TERMINATE' mentioned\")\n" - ] - } - ], + "outputs": [], "source": [ "\n", "result = group_chat.run_stream(task=\"Plan a 3 day trip to Nepal.\")\n", @@ -317,7 +271,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -330,19 +284,9 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "source='user' models_usage=None content='hello there'\n", - "source='user_agent' models_usage=None content='Hello World thereEnter your response: '\n", - "TaskResult(messages=[TextMessage(source='user', models_usage=None, content='hello there'), TextMessage(source='user_agent', models_usage=None, content='Hello World thereEnter your response: ')], stop_reason=None)\n" - ] - } - ], + "outputs": [], "source": [ "from autogen_core.base import CancellationToken \n", "cancellation_token = CancellationToken()\n", diff --git a/python/packages/autogen-studio/pyproject.toml b/python/packages/autogen-studio/pyproject.toml index fc3acee48e0f..3a067d5dfc46 100644 --- a/python/packages/autogen-studio/pyproject.toml +++ b/python/packages/autogen-studio/pyproject.toml @@ -23,7 +23,8 @@ dependencies = [ "pydantic-settings", "fastapi", "typer", - "uvicorn", + "uvicorn", + "aiofiles", "python-dotenv", "websockets", "numpy < 2.0.0", @@ -69,3 +70,21 @@ filterwarnings = [ [project.scripts] autogenstudio = "autogenstudio.cli:run" + + +[tool.ruff] +extend = "../../pyproject.toml" +exclude = ["build", "dist"] +include = [ + "autogenstudio/**" +] + +[tool.ruff.lint] +ignore = ["B008"] + + +[tool.poe.tasks] +fmt = "ruff format" +format.ref = "fmt" +lint = "ruff check" +test = "pytest -n 0" \ No newline at end of file diff --git a/python/packages/autogen-studio/tests/test_component_factory.py b/python/packages/autogen-studio/tests/test_component_factory.py index d676941feee0..4fc4aed8c66c 100644 --- a/python/packages/autogen-studio/tests/test_component_factory.py +++ b/python/packages/autogen-studio/tests/test_component_factory.py @@ -6,10 +6,10 @@ from autogen_agentchat.task import MaxMessageTermination, StopMessageTermination, TextMentionTermination from autogen_core.components.tools import FunctionTool -from autogenstudio.datamodel import ( +from autogenstudio.datamodel.types import ( AgentConfig, ModelConfig, TeamConfig, ToolConfig, TerminationConfig, ModelTypes, AgentTypes, TeamTypes, TerminationTypes, ToolTypes, - ComponentType + ComponentTypes ) from autogenstudio.database import ComponentFactory @@ -41,7 +41,7 @@ def calculator(a: int, b: int, operation: str = '+') -> int: raise ValueError("Invalid operation") """, tool_type=ToolTypes.PYTHON_FUNCTION, - component_type=ComponentType.TOOL, + component_type=ComponentTypes.TOOL, version="1.0.0" ) @@ -52,7 +52,7 @@ def sample_model_config(): model_type=ModelTypes.OPENAI, model="gpt-4", api_key="test-key", - component_type=ComponentType.MODEL, + component_type=ComponentTypes.MODEL, version="1.0.0" ) @@ -65,7 +65,7 @@ def sample_agent_config(sample_model_config: ModelConfig, sample_tool_config: To system_message="You are a helpful assistant", model_client=sample_model_config, tools=[sample_tool_config], - component_type=ComponentType.AGENT, + component_type=ComponentTypes.AGENT, version="1.0.0" ) @@ -75,7 +75,7 @@ def sample_termination_config(): return TerminationConfig( termination_type=TerminationTypes.MAX_MESSAGES, max_messages=10, - component_type=ComponentType.TERMINATION, + component_type=ComponentTypes.TERMINATION, version="1.0.0" ) @@ -88,7 +88,7 @@ def sample_team_config(sample_agent_config: AgentConfig, sample_termination_conf participants=[sample_agent_config], termination_condition=sample_termination_config, model_client=sample_model_config, - component_type=ComponentType.TEAM, + component_type=ComponentTypes.TEAM, version="1.0.0" ) @@ -115,7 +115,7 @@ async def test_load_tool_invalid_config(component_factory: ComponentFactory): description="", content="", tool_type=ToolTypes.PYTHON_FUNCTION, - component_type=ComponentType.TOOL, + component_type=ComponentTypes.TOOL, version="1.0.0" )) @@ -125,7 +125,7 @@ async def test_load_tool_invalid_config(component_factory: ComponentFactory): description="Invalid function", content="def invalid_func(): return invalid syntax", tool_type=ToolTypes.PYTHON_FUNCTION, - component_type=ComponentType.TOOL, + component_type=ComponentTypes.TOOL, version="1.0.0" ) with pytest.raises(ValueError): @@ -154,7 +154,7 @@ async def test_load_termination(component_factory: ComponentFactory): max_msg_config = TerminationConfig( termination_type=TerminationTypes.MAX_MESSAGES, max_messages=5, - component_type=ComponentType.TERMINATION, + component_type=ComponentTypes.TERMINATION, version="1.0.0" ) termination = await component_factory.load_termination(max_msg_config) @@ -164,7 +164,7 @@ async def test_load_termination(component_factory: ComponentFactory): # Test StopMessageTermination stop_msg_config = TerminationConfig( termination_type=TerminationTypes.STOP_MESSAGE, - component_type=ComponentType.TERMINATION, + component_type=ComponentTypes.TERMINATION, version="1.0.0" ) termination = await component_factory.load_termination(stop_msg_config) @@ -174,13 +174,108 @@ async def test_load_termination(component_factory: ComponentFactory): text_mention_config = TerminationConfig( termination_type=TerminationTypes.TEXT_MENTION, text="DONE", - component_type=ComponentType.TERMINATION, + component_type=ComponentTypes.TERMINATION, version="1.0.0" ) termination = await component_factory.load_termination(text_mention_config) assert isinstance(termination, TextMentionTermination) assert termination._text == "DONE" + # Test AND combination + and_combo_config = TerminationConfig( + termination_type=TerminationTypes.COMBINATION, + operator="and", + conditions=[ + TerminationConfig( + termination_type=TerminationTypes.MAX_MESSAGES, + max_messages=5, + component_type=ComponentTypes.TERMINATION, + version="1.0.0" + ), + TerminationConfig( + termination_type=TerminationTypes.TEXT_MENTION, + text="DONE", + component_type=ComponentTypes.TERMINATION, + version="1.0.0" + ) + ], + component_type=ComponentTypes.TERMINATION, + version="1.0.0" + ) + termination = await component_factory.load_termination(and_combo_config) + assert termination is not None + + # Test OR combination + or_combo_config = TerminationConfig( + termination_type=TerminationTypes.COMBINATION, + operator="or", + conditions=[ + TerminationConfig( + termination_type=TerminationTypes.MAX_MESSAGES, + max_messages=5, + component_type=ComponentTypes.TERMINATION, + version="1.0.0" + ), + TerminationConfig( + termination_type=TerminationTypes.TEXT_MENTION, + text="DONE", + component_type=ComponentTypes.TERMINATION, + version="1.0.0" + ) + ], + component_type=ComponentTypes.TERMINATION, + version="1.0.0" + ) + termination = await component_factory.load_termination(or_combo_config) + assert termination is not None + + # Test invalid combinations + with pytest.raises(ValueError): + await component_factory.load_termination(TerminationConfig( + termination_type=TerminationTypes.COMBINATION, + conditions=[], # Empty conditions + component_type=ComponentTypes.TERMINATION, + version="1.0.0" + )) + + with pytest.raises(ValueError): + await component_factory.load_termination(TerminationConfig( + termination_type=TerminationTypes.COMBINATION, + operator="invalid", # type: ignore + conditions=[ + TerminationConfig( + termination_type=TerminationTypes.MAX_MESSAGES, + max_messages=5, + component_type=ComponentTypes.TERMINATION, + version="1.0.0" + ) + ], + component_type=ComponentTypes.TERMINATION, + version="1.0.0" + )) + + # Test missing operator + with pytest.raises(ValueError): + await component_factory.load_termination(TerminationConfig( + termination_type=TerminationTypes.COMBINATION, + conditions=[ + TerminationConfig( + termination_type=TerminationTypes.MAX_MESSAGES, + max_messages=5, + component_type=ComponentTypes.TERMINATION, + version="1.0.0" + ), + TerminationConfig( + termination_type=TerminationTypes.TEXT_MENTION, + text="DONE", + component_type=ComponentTypes.TERMINATION, + version="1.0.0" + ) + ], + component_type=ComponentTypes.TERMINATION, + version="1.0.0" + )) + @pytest.mark.asyncio async def test_load_team(component_factory: ComponentFactory, sample_team_config: TeamConfig, sample_model_config: ModelConfig): @@ -201,13 +296,13 @@ async def test_load_team(component_factory: ComponentFactory, sample_team_config system_message="You are another helpful assistant", model_client=sample_model_config, tools=sample_team_config.participants[0].tools, - component_type=ComponentType.AGENT, + component_type=ComponentTypes.AGENT, version="1.0.0" ) ], termination_condition=sample_team_config.termination_condition, model_client=sample_model_config, - component_type=ComponentType.TEAM, + component_type=ComponentTypes.TEAM, version="1.0.0" ) team = await component_factory.load_team(selector_team_config) @@ -223,7 +318,7 @@ async def test_invalid_configs(component_factory: ComponentFactory): name="test", agent_type="InvalidAgent", # type: ignore system_message="test", - component_type=ComponentType.AGENT, + component_type=ComponentTypes.AGENT, version="1.0.0" )) @@ -233,7 +328,7 @@ async def test_invalid_configs(component_factory: ComponentFactory): name="test", team_type="InvalidTeam", # type: ignore participants=[], - component_type=ComponentType.TEAM, + component_type=ComponentTypes.TEAM, version="1.0.0" )) @@ -241,6 +336,6 @@ async def test_invalid_configs(component_factory: ComponentFactory): with pytest.raises(ValueError): await component_factory.load_termination(TerminationConfig( termination_type="InvalidTermination", # type: ignore - component_type=ComponentType.TERMINATION, + component_type=ComponentTypes.TERMINATION, version="1.0.0" )) diff --git a/python/packages/autogen-studio/tests/test_db_manager.py b/python/packages/autogen-studio/tests/test_db_manager.py index ccc2aa5ddcec..b77a891a7979 100644 --- a/python/packages/autogen-studio/tests/test_db_manager.py +++ b/python/packages/autogen-studio/tests/test_db_manager.py @@ -1,15 +1,16 @@ import os +import asyncio import pytest from sqlmodel import Session, text, select from typing import Generator -from datetime import datetime from autogenstudio.database import DatabaseManager -from autogenstudio.datamodel import ( - Model, ModelConfig, Agent, AgentConfig, Tool, ToolConfig, - Team, TeamConfig, ModelTypes, AgentTypes, TeamTypes, ComponentType, - TerminationConfig, TerminationTypes, LinkTypes, ToolTypes +from autogenstudio.datamodel.types import ( + ModelConfig, AgentConfig, ToolConfig, + TeamConfig, ModelTypes, AgentTypes, TeamTypes, ComponentTypes, + TerminationConfig, TerminationTypes, ToolTypes ) +from autogenstudio.datamodel.db import Model, Tool, Agent, Team, LinkTypes @pytest.fixture @@ -18,13 +19,13 @@ def test_db() -> Generator[DatabaseManager, None, None]: db_path = "test.db" db = DatabaseManager(f"sqlite:///{db_path}") db.reset_db() - db.create_db_and_tables() + # Initialize database instead of create_db_and_tables + db.initialize_database(auto_upgrade=False) yield db + # Clean up + asyncio.run(db.close()) db.reset_db() try: - # Close database connections before removing file - db.engine.dispose() - # Remove the database file if os.path.exists(db_path): os.remove(db_path) except Exception as e: @@ -44,7 +45,7 @@ def sample_model(test_user: str) -> Model: config=ModelConfig( model="gpt-4", model_type=ModelTypes.OPENAI, - component_type=ComponentType.MODEL, + component_type=ComponentTypes.MODEL, version="1.0.0" ).model_dump() ) @@ -60,7 +61,7 @@ def sample_tool(test_user: str) -> Tool: description="A test tool", content="async def test_func(x: str) -> str:\n return f'Test {x}'", tool_type=ToolTypes.PYTHON_FUNCTION, - component_type=ComponentType.TOOL, + component_type=ComponentTypes.TOOL, version="1.0.0" ).model_dump() ) @@ -76,7 +77,7 @@ def sample_agent(test_user: str, sample_model: Model, sample_tool: Tool) -> Agen agent_type=AgentTypes.ASSISTANT, model_client=ModelConfig.model_validate(sample_model.config), tools=[ToolConfig.model_validate(sample_tool.config)], - component_type=ComponentType.AGENT, + component_type=ComponentTypes.AGENT, version="1.0.0" ).model_dump() ) @@ -92,11 +93,11 @@ def sample_team(test_user: str, sample_agent: Agent) -> Team: participants=[AgentConfig.model_validate(sample_agent.config)], termination_condition=TerminationConfig( termination_type=TerminationTypes.STOP_MESSAGE, - component_type=ComponentType.TERMINATION, + component_type=ComponentTypes.TERMINATION, version="1.0.0" ).model_dump(), team_type=TeamTypes.ROUND_ROBIN, - component_type=ComponentType.TEAM, + component_type=ComponentTypes.TEAM, version="1.0.0" ).model_dump() ) @@ -144,7 +145,7 @@ def test_multiple_links(self, test_db: DatabaseManager, sample_agent: Agent): config=ModelConfig( model="gpt-4", model_type=ModelTypes.OPENAI, - component_type=ComponentType.MODEL, + component_type=ComponentTypes.MODEL, version="1.0.0" ).model_dump() ) @@ -153,7 +154,7 @@ def test_multiple_links(self, test_db: DatabaseManager, sample_agent: Agent): config=ModelConfig( model="gpt-3.5", model_type=ModelTypes.OPENAI, - component_type=ComponentType.MODEL, + component_type=ComponentTypes.MODEL, version="1.0.0" ).model_dump() ) @@ -181,3 +182,59 @@ def test_multiple_links(self, test_db: DatabaseManager, sample_agent: Agent): model_names = [model.config["model"] for model in linked_models.data] assert "gpt-4" in model_names assert "gpt-3.5" in model_names + + def test_upsert_operations(self, test_db: DatabaseManager, sample_model: Model): + """Test upsert for both create and update scenarios""" + # Test Create + response = test_db.upsert(sample_model) + assert response.status is True + assert "Created Successfully" in response.message + + # Test Update + sample_model.config["model"] = "gpt-4-turbo" + response = test_db.upsert(sample_model) + assert response.status is True + assert "Updated Successfully" in response.message + + # Verify Update + result = test_db.get(Model, {"id": sample_model.id}) + assert result.status is True + assert result.data[0].config["model"] == "gpt-4-turbo" + + def test_delete_operations(self, test_db: DatabaseManager, sample_model: Model): + """Test delete with various filters""" + # First insert the model + test_db.upsert(sample_model) + + # Test deletion by id + response = test_db.delete(Model, {"id": sample_model.id}) + assert response.status is True + assert "Deleted Successfully" in response.message + + # Verify deletion + result = test_db.get(Model, {"id": sample_model.id}) + assert len(result.data) == 0 + + # Test deletion with non-existent id + response = test_db.delete(Model, {"id": 999999}) + assert "Row not found" in response.message + + def test_initialize_database_scenarios(self): + """Test different initialize_database parameters""" + db_path = "test_init.db" + db = DatabaseManager(f"sqlite:///{db_path}") + + try: + # Test basic initialization + response = db.initialize_database() + assert response.status is True + + # Test with auto_upgrade + response = db.initialize_database(auto_upgrade=True) + assert response.status is True + + finally: + asyncio.run(db.close()) + db.reset_db() + if os.path.exists(db_path): + os.remove(db_path) diff --git a/python/uv.lock b/python/uv.lock index 4602559d0e01..d5265ff76e56 100644 --- a/python/uv.lock +++ b/python/uv.lock @@ -573,9 +573,10 @@ dev = [ [[package]] name = "autogenstudio" -version = "0.4.0.dev37" +version = "0.4.0.dev38" source = { editable = "packages/autogen-studio" } dependencies = [ + { name = "aiofiles" }, { name = "alembic" }, { name = "autogen-agentchat" }, { name = "autogen-core" }, @@ -605,6 +606,7 @@ web = [ [package.metadata] requires-dist = [ + { name = "aiofiles" }, { name = "alembic" }, { name = "autogen-agentchat", editable = "packages/autogen-agentchat" }, { name = "autogen-core", editable = "packages/autogen-core" },