diff --git a/pyproject.toml b/pyproject.toml index ad7c9cbb91559d019c57b47fecb0d48ea32dd6d4..8fa818c03dcd636eda6d1ff9fb801df355f2fb4d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,21 +38,46 @@ dependencies = [ "uvicorn>=0.27.0", "sqlmodel>=0.0.14", "aiosqlite>=0.19.0", + "greenlet>=3.0.0", # Required for SQLAlchemy async support + # Logging dependencies + "loguru>=0.7.3", "tiktoken>=0.12.0", ] [project.optional-dependencies] # Optional features research = ["beautifulsoup4>=4.12.0", "html2text>=2024.2.26"] + langgraph = [ "langgraph>=0.2.0", "langchain-core>=0.3.0", "langchain-openai>=0.2.0", ] -optimizer = ["gepa>=0.0.20"] + +smolagents = [ + "smolagents[toolkit]>=1.24.0", + "pdfminer.six>=20240706", + "cffi>=1.16.0", + "cryptography>=42.0.0", + "Pillow>=11.0.0", + "puremagic>=1.28", + "pypdf>=5.1.0", + "youtube_transcript_api>=0.6.2", + "python_pptx>=1.0.2", + "serpapi>=0.1.5", + "mammoth>=1.8.0", + "markdownify>=0.13.1", + "pandas>=2.2.3", + "openpyxl>=3.1.0", + "wikipedia-api>=0.9.0", +] + +# Bundles +optimizer = ["gepa>=0.0.27", "litellm>=1.0.0"] +hf-datasets = ["datasets>=2.0.0"] # Bundles -all = ["flow-agent[research,langgraph,optimizer]"] +all = ["flow-agent[research,langgraph,optimizer,smolagents,hf-datasets]"] dev = [ "pytest>=8.0.0", "pytest-asyncio>=0.23.0", @@ -85,7 +110,7 @@ packages = ["src/flow"] [tool.pyright] include = ["src"] -exclude = ["**/tests/**", "**/.venv/**"] +exclude = ["**/tests/**", "**/.venv/**", "**/skills/**"] typeCheckingMode = "strict" pythonVersion = "3.10" reportMissingTypeStubs = false @@ -108,6 +133,7 @@ show_error_codes = true warn_unused_ignores = false disallow_incomplete_defs = true disallow_untyped_decorators = true +exclude = ["src/flow/skills/"] # ============================================================================ # Linting - Ruff @@ -119,7 +145,7 @@ target-version = "py310" src = ["src"] fix = true include = ["*.py", "*.pyi", "**/pyproject.toml"] -exclude = ["docs/*"] +exclude = ["docs/*", "src/flow/skills/*"] [tool.ruff.lint] select = [ @@ -140,6 +166,7 @@ ignore = [ "D107", # allow missing docstring in __init__ "ANN401", # allow Any type (needed for generic tool/event handling) "S101", # allow assert statements (used in tests) + "B008", # allow Depends() in function defaults (FastAPI pattern) ] [tool.ruff.lint.per-file-ignores] diff --git a/src/flow/__init__.py b/src/flow/__init__.py index f1413cc79c538417fe430cbd394608f3d9183ece..d1701505568aefdc0f735f0cbd7c719e26c17728 100644 --- a/src/flow/__init__.py +++ b/src/flow/__init__.py @@ -21,6 +21,6 @@ __version__ = "0.1.0" __all__ = [ "MAFHarness", - "create_agent", "__version__", + "create_agent", ] diff --git a/src/flow/cli/app.py b/src/flow/cli/app.py index 98399fab6c498413fbb8b1b237bc2d0ab2fa0d03..20dbf66aa8f64f9daa08daf2fb18c6bb6580c09d 100644 --- a/src/flow/cli/app.py +++ b/src/flow/cli/app.py @@ -65,7 +65,7 @@ def run( framework: Annotated[ str, typer.Option("--framework", "-f", help="Agent framework: 'maf', 'miniagent', or 'langgraph'"), - ] = "maf", + ] = "miniagent", interactive: Annotated[ bool, typer.Option("--interactive/--no-interactive", "-i", help="Interactive mode"), @@ -110,26 +110,34 @@ async def _run_single_task( memory_path: Path, task: str, config_path: Path | None = None, - framework: str = "maf", + framework: str = "miniagent", ) -> None: """Run a single task and print the result.""" + # Import harness modules to register them (side-effect imports) + import flow.harness.maf as _maf + import flow.harness.miniagent as _miniagent from flow.cli.output import print_event from flow.harness.base import EventType - # Import harness modules to register them - import flow.harness.maf # noqa: F401 - import flow.harness.miniagent # noqa: F401 # pyright: ignore[reportUnusedImport] + _ = (_maf, _miniagent) if framework == "langgraph": try: - import flow.harness.langgraph # noqa: F401 + import flow.harness.langgraph as _lg + + _ = _lg except ImportError: console.print("[red]Error:[/] LangGraph dependencies not installed.") console.print("[dim]Install with: pip install flow-agent[langgraph][/]") raise typer.Exit(1) + from typing import cast + + from flow.experiments.models import Agent, Framework from flow.harness import create_harness - from flow.experiments.models import Agent + + # Cast the validated framework string to Framework literal type + framework_typed = cast(Framework, framework) if config_path: # Load agent config from optimization result @@ -137,19 +145,19 @@ async def _run_single_task( agent_config = load_agent(config_path) # Override framework if specified - if framework != "maf": + if framework != "miniagent": agent_config = Agent( name=agent_config.name, - framework=framework, + framework=framework_typed, tools=agent_config.tools, - model=agent_config.model, + llm_config=agent_config.llm_config, instructions=agent_config.instructions, compaction=agent_config.compaction, ) console.print(f"[dim]Using agent config: {agent_config.name} ({framework})[/]") harness = create_harness(agent_config, workspace) else: - agent = Agent(name="flow-cli", framework=framework) + agent = Agent(name="flow-cli", framework=framework_typed) harness = create_harness(agent, workspace) try: @@ -167,10 +175,12 @@ async def _run_single_task( await harness.close() -# Import and register the optimize command +# Import and register commands +from flow.cli.hf_import import hf_import as hf_import_cmd from flow.cli.optimize import optimize as optimize_cmd app.command()(optimize_cmd) +app.command(name="hf-import")(hf_import_cmd) @app.command() diff --git a/src/flow/cli/hf_import.py b/src/flow/cli/hf_import.py new file mode 100644 index 0000000000000000000000000000000000000000..49fefd55deef81a80c59e415d97f6357a48a339d --- /dev/null +++ b/src/flow/cli/hf_import.py @@ -0,0 +1,159 @@ +"""CLI command to import Hugging Face datasets.""" + +from __future__ import annotations + +from pathlib import Path +from typing import Annotated + +import typer +from rich.console import Console + +from flow.experiments.hf_datasets import ( + DATASET_CONVERTERS, + import_hf_dataset, + save_tasks_to_jsonl, +) + +console = Console() + + +def hf_import( + dataset: Annotated[ + str, + typer.Argument(help="Hugging Face dataset name (e.g., 'openai/gsm8k')"), + ], + output: Annotated[ + Path, + typer.Option( + "--output", + "-o", + help="Output JSONL file path", + ), + ] = Path("tasks/imported.jsonl"), + config: Annotated[ + str | None, + typer.Option( + "--config", + "-c", + help="Dataset configuration/subset (e.g., 'main' for gsm8k)", + ), + ] = None, + split: Annotated[ + str, + typer.Option( + "--split", + "-s", + help="Dataset split to use", + ), + ] = "train", + limit: Annotated[ + int | None, + typer.Option( + "--limit", + "-n", + help="Maximum number of examples to import", + ), + ] = None, + local_path: Annotated[ + Path | None, + typer.Option( + "--local-path", + "-l", + help="Path to download dataset snapshot to. Uses huggingface_hub.snapshot_download(). " + "For private datasets, set HF_TOKEN env variable.", + ), + ] = None, + list_supported: Annotated[ + bool, + typer.Option( + "--list", + help="List supported datasets and exit", + ), + ] = False, +) -> None: + """Import a Hugging Face dataset for use with GEPA optimization. + + Converts HF datasets into Flow's task format with evaluation criteria. + + Examples: + # Import 100 GSM8K math problems + flow hf-import openai/gsm8k --config main --output tasks/gsm8k.jsonl --limit 100 + + # Import HumanEval coding problems + flow hf-import openai_humaneval --output tasks/humaneval.jsonl + + # Download to local path first (useful for caching or private datasets) + flow hf-import openai/gsm8k --local-path /data/gsm8k --output tasks/gsm8k.jsonl + + # For private datasets, set HF_TOKEN env variable + HF_TOKEN=hf_... flow hf-import org/private-dataset --local-path /data/private + + # Use with GEPA + flow optimize \\ + --config examples/gepa_strategy.yaml \\ + --agent examples/base_agent.yaml \\ + --tasks tasks/gsm8k.jsonl \\ + --budget 10 + """ + if list_supported: + console.print("\n[bold]Supported Datasets:[/]") + console.print("\n[dim]You can add custom converters via register_converter()[/]\n") + for name in sorted(DATASET_CONVERTERS.keys()): + console.print(f" • {name}") + return + + console.print(f"\n[bold]Importing dataset:[/] {dataset}") + if config: + console.print(f"[dim]Config:[/] {config}") + console.print(f"[dim]Split:[/] {split}") + if limit: + console.print(f"[dim]Limit:[/] {limit} examples") + if local_path: + console.print(f"[dim]Local path:[/] {local_path}") + console.print() + + try: + # Import dataset + tasks = import_hf_dataset( + dataset_name=dataset, + config=config, + split=split, + limit=limit, + local_path=local_path, + ) + + if not tasks: + console.print("[red]Error:[/] No tasks were converted") + raise typer.Exit(1) + + # Save to file + save_tasks_to_jsonl(tasks, output) + + console.print(f"\n[green]Success![/] Imported {len(tasks)} tasks") + console.print(f"[dim]Output:[/] {output}") + console.print("\n[bold]Sample task:[/]") + console.print(f" Name: {tasks[0].name}") + console.print(f" Prompt: {tasks[0].prompt[:100]}...") + console.print(f" Criteria: {len(tasks[0].criteria)} evaluation criteria") + + console.print("\n[bold]Next steps:[/]") + console.print(" [dim]# Run GEPA optimization[/]") + console.print(" flow optimize \\") + console.print(" --config examples/gepa_strategy.yaml \\") + console.print(" --agent examples/base_agent.yaml \\") + console.print(f" --tasks {output} \\") + console.print(" --budget 10") + + except ImportError: + console.print("[red]Error:[/] Hugging Face datasets library not installed") + console.print("[dim]Install with:[/] pip install datasets") + raise typer.Exit(1) + except ValueError as e: + console.print(f"[red]Error:[/] {e}") + raise typer.Exit(1) + except Exception as e: + console.print(f"[red]Error:[/] {e}") + import traceback + + traceback.print_exc() + raise typer.Exit(1) diff --git a/src/flow/cli/optimize.py b/src/flow/cli/optimize.py index 75c54261c7b3b0cb191c73558d3bb5323ff3f1ee..76facc66089727decc2506c46365f44b61268099 100644 --- a/src/flow/cli/optimize.py +++ b/src/flow/cli/optimize.py @@ -18,7 +18,6 @@ from flow.experiments.models import ( Agent, Candidate, CompactionConfig, - Experiment, ExperimentResult, GridSearchStrategy, load_experiment, @@ -86,6 +85,13 @@ def optimize( help="Output directory for results", ), ] = None, + limit: Annotated[ + int | None, + typer.Option( + "--limit", "-l", + help="Max number of tasks to run (use first N tasks from suite/file)", + ), + ] = None, no_llm_eval: Annotated[ bool, typer.Option( @@ -107,7 +113,6 @@ def optimize( ranks via Pareto analysis, and exports winning agent configs. Examples: - # Use experiment YAML (recommended - defines agent, tasks, and variations) flow optimize --experiment experiment.yaml @@ -140,6 +145,7 @@ def optimize( output_dir=output, use_llm_eval=not no_llm_eval, budget=budget, + limit=limit, )) @@ -154,15 +160,16 @@ async def _run_optimize( output_dir: Path | None, use_llm_eval: bool, budget: int, + limit: int | None = None, ) -> None: """Run the optimization.""" # If experiment YAML provided, use it as the source of truth if experiment_path: - await _run_from_experiment(experiment_path, output_dir) + await _run_from_experiment(experiment_path, output_dir, limit=limit) return # Load tasks - tasks = _load_tasks(tasks_path, suite) + tasks = _load_tasks(tasks_path, suite, limit=limit) if not tasks: console.print("[red]Error:[/] No tasks specified. Use --tasks or --suite") raise typer.Exit(1) @@ -171,7 +178,7 @@ async def _run_optimize( base = _load_base_agent(agent_path) # Load candidates and check if a strategy is defined in config - candidates, strategy_instance = _load_candidates_and_strategy(config_path, vary, base, budget) + candidates, strategy_instance = await _load_candidates_and_strategy(config_path, vary, base, budget) # If a strategy was provided (like GepaStrategy), run it directly if strategy_instance is not None: @@ -221,7 +228,7 @@ async def _run_optimize( raise typer.Exit(1) -async def _run_from_experiment(experiment_path: Path, output_dir: Path | None) -> None: +async def _run_from_experiment(experiment_path: Path, output_dir: Path | None, limit: int | None = None) -> None: """Run optimization from an experiment YAML file. The experiment YAML defines: @@ -270,10 +277,13 @@ async def _run_from_experiment(experiment_path: Path, output_dir: Path | None) - console.print("[red]Error:[/] Experiment must specify 'suite' or 'tasks'") raise typer.Exit(1) + if limit is not None and limit > 0: + tasks = tasks[:limit] + # Generate candidates from variations if exp.variations: strategy = GridSearchStrategy(exp.variations) - candidates = strategy.generate(base, exp.budget) + candidates = await strategy.generate(base, exp.budget) else: candidates = [Candidate(agent=base, mutations={}, rationale="baseline")] @@ -283,7 +293,7 @@ async def _run_from_experiment(experiment_path: Path, output_dir: Path | None) - for t in tasks: console.print(f" - {t.name}") - console.print(f"\n[bold]Variations:[/]") + console.print("\n[bold]Variations:[/]") for key, values in exp.variations.items(): console.print(f" - {key}: {len(values)} variants") @@ -309,27 +319,31 @@ async def _run_from_experiment(experiment_path: Path, output_dir: Path | None) - raise typer.Exit(1) -def _load_tasks(tasks_path: Path | None, suite: str | None) -> list[Task]: +def _load_tasks(tasks_path: Path | None, suite: str | None, limit: int | None = None) -> list[Task]: """Load tasks from file or built-in suite.""" + tasks: list[Task] = [] if tasks_path: if not tasks_path.exists(): console.print(f"[red]Error:[/] Tasks file not found: {tasks_path}") raise typer.Exit(1) - return load_tasks_from_jsonl(tasks_path) - - if suite: + tasks = load_tasks_from_jsonl(tasks_path) + elif suite: try: - return get_task_suite(suite) + tasks = get_task_suite(suite) except ValueError as e: console.print(f"[red]Error:[/] {e}") raise typer.Exit(1) + else: + # Default: quick suite + try: + tasks = get_task_suite("quick") + except ValueError: + console.print("[red]Error:[/] No built-in suites available. Use --tasks to specify a JSONL file.") + raise typer.Exit(1) - # Default: quick suite - try: - return get_task_suite("quick") - except ValueError: - console.print("[red]Error:[/] No built-in suites available. Use --tasks to specify a JSONL file.") - raise typer.Exit(1) + if limit is not None and limit > 0: + tasks = tasks[:limit] + return tasks def _load_base_agent(agent_path: Path | None) -> Agent: @@ -344,18 +358,18 @@ def _load_base_agent(agent_path: Path | None) -> Agent: return Agent(name="flow_agent") -def _load_candidates_and_strategy( +async def _load_candidates_and_strategy( config_path: Path | None, vary: str | None, base: Agent, budget: int, ) -> tuple[list[Candidate], Any | None]: """Load candidates from file or generate from variations. - + Supports both YAML and Python config files: - YAML: strategy configuration (strategy_type, config) - Python: STRATEGY object, CANDIDATES list, or VARIATIONS dict - + Returns: Tuple of (candidates, strategy_instance) - If a STRATEGY is defined in config, returns ([], strategy_instance) @@ -374,17 +388,17 @@ def _load_candidates_and_strategy( # YAML files currently only support strategy definitions console.print("[red]Error:[/] YAML config must define a strategy") raise typer.Exit(1) - + # Python config file candidates, variations, strategy_obj = _load_python_config(config_path) # If a strategy object was provided (e.g., GepaStrategy), return it if strategy_obj is not None: return [], strategy_obj - + if variations: strategy = GridSearchStrategy(variations) - return strategy.generate(base, budget), None + return await strategy.generate(base, budget), None elif candidates: return candidates, None else: @@ -394,7 +408,7 @@ def _load_candidates_and_strategy( if vary: variations = _parse_vary_flag(vary) strategy = GridSearchStrategy(variations) - return strategy.generate(base, budget), None + return await strategy.generate(base, budget), None # Default: explore context engineering dimensions strategy = GridSearchStrategy(variations={ @@ -402,9 +416,8 @@ def _load_candidates_and_strategy( CompactionConfig.head_tail(10, 40), CompactionConfig.none(), ], - "tools": ["minimal", "standard"], }) - return strategy.generate(base, budget), None + return await strategy.generate(base, budget), None def _load_yaml_strategy(path: Path) -> Any | None: @@ -442,9 +455,12 @@ def _load_yaml_strategy(path: Path) -> Any | None: console.print("[red]Error:[/] GEPA optimizer not available.") console.print("[dim]Install with: pip install flow-agent[optimizer][/]") raise typer.Exit(1) + elif strategy_type == "llm_rewriter": + from flow.experiments.strategies.llm_rewriter import LLMRewriterStrategy + return LLMRewriterStrategy(config=strategy_config) else: console.print(f"[red]Error:[/] Unknown strategy type: {strategy_type}") - console.print("[dim]Supported: gepa[/]") + console.print("[dim]Supported: gepa, llm_rewriter[/]") raise typer.Exit(1) @@ -526,128 +542,193 @@ async def _run_active_strategy( use_llm_eval: bool, budget: int, ) -> None: - """Run an active optimization strategy (like GEPA).""" + """Run an active optimization strategy. + + For strategies that use the ExperimentRunner protocol (LLMRewriterStrategy), + delegates to FlowOptimizer.optimize_with_strategy() which handles setup, + evaluation, Pareto analysis, and export. + + For GEPA (which uses its own evaluator callback), uses the legacy path + with a bridging evaluator function. + """ + # Check if strategy uses GEPA's evaluator pattern (legacy path) + is_gepa = hasattr(strategy, "evaluator") + + if is_gepa: + await _run_gepa_strategy(strategy, base_agent, tasks, output_dir, parallel, use_llm_eval, budget) + else: + # Modern path: use optimize_with_strategy which passes self as runner + optimizer = FlowOptimizer( + parallel=parallel, + use_llm_evaluator=use_llm_eval, + output_dir=output_dir, + ) + result = await optimizer.optimize_with_strategy( + strategy=strategy, + base=base_agent, + tasks=tasks, + budget=budget, + ) + + console.print("\n[bold green]Optimization complete![/]") + console.print(f"\nBest agents exported to: [cyan]{result.output_dir / 'agents'}[/]") + + +async def _run_gepa_strategy( + strategy: Any, + base_agent: Agent, + tasks: list[Task], + output_dir: Path | None, + parallel: int, + use_llm_eval: bool, + budget: int, +) -> None: + """Run GEPA strategy with its custom evaluator callback bridge.""" logger = logging.getLogger(__name__) - - # Create optimizer instance to run evaluations + + import threading + from datetime import datetime + + timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") + if output_dir is None: + base_output_dir = Path.home() / ".flow" / "optimizations" + else: + base_output_dir = output_dir + run_dir = base_output_dir / f"gepa_{timestamp}" + run_dir.mkdir(parents=True, exist_ok=True) + + eval_counter = 0 + counter_lock = threading.Lock() + optimizer_runner = FlowOptimizer( parallel=parallel, use_llm_evaluator=use_llm_eval, - output_dir=None, # Don't export every intermediate run result + output_dir=run_dir, ) - main_loop = asyncio.get_running_loop() - # Define evaluator function to inject into strategy def evaluator(candidate: Candidate, minibatch: list[Task] | None = None) -> ExperimentResult: - """Evaluate a candidate on a minibatch of tasks.""" + """Evaluate a candidate on a minibatch of tasks (GEPA bridge).""" + nonlocal eval_counter + eval_tasks = minibatch if minibatch else tasks - - logger.info(f"[EVALUATOR] Evaluating candidate '{candidate.agent.name}' on {len(eval_tasks)} tasks") - logger.info(f"[EVALUATOR] Using LLM evaluator: {use_llm_eval}") - logger.debug(f"[EVALUATOR] Tasks: {[t.name for t in eval_tasks]}") - + candidate_id = candidate.mutations.get("_candidate_id", "unknown") + + with counter_lock: + rollout_num = eval_counter + eval_counter += 1 + + rollout_dir = run_dir / f"rollout_{rollout_num}_{candidate_id}" + logger.debug(f"[EVALUATOR] Evaluating {candidate_id} on {len(eval_tasks)} tasks (rollout {rollout_num})") + try: - # Run async evaluation on the main loop and wait for result - # This is safe because strategy.generate (which calls this) - # is running in an executor thread. future = asyncio.run_coroutine_threadsafe( - optimizer_runner.optimize([candidate], eval_tasks), + optimizer_runner.optimize([candidate], eval_tasks, run_dir=rollout_dir), main_loop ) optimization_result = future.result() - - # Check if we got any results + if not optimization_result.summaries: - logger.warning(f"[EVALUATOR] Optimization produced no summaries for candidate '{candidate.agent.name}'") - # Return a fallback result with zero score instead of raising return ExperimentResult( - candidate=candidate, - run_result=None, - metrics={"score": 0.0, "error": "No summaries produced"}, - eval_score=0.0, - eval_passed=False, - eval_reasoning="Evaluation failed to produce results", - traces={} + candidate=candidate, run_result=None, + metrics={"score": 0.0}, eval_score=0.0, + eval_passed=False, eval_reasoning="No results", traces={} ) - + summary = optimization_result.summaries[0] - logger.info(f"[EVALUATOR] Candidate '{candidate.agent.name}' avg_score={summary.avg_score:.3f}, pass_rate={summary.pass_rate:.2f}") - - # Log individual task results for debugging - if summary.task_results: - for tr in summary.task_results: - logger.info(f"[EVALUATOR] Task '{tr.task_name}': score={tr.eval_score:.3f}, passed={tr.eval_passed}") - logger.debug(f"[EVALUATOR] Reasoning: '{tr.eval_reasoning[:150]}'") - logger.debug(f"[EVALUATOR] Metrics: tokens={tr.metrics.total_tokens}, duration={tr.run_result.duration_seconds if tr.run_result else 0:.2f}s") - - # Convert CandidateSummary to ExperimentResult for GEPA - + if summary.task_results: - tr = summary.task_results[0] + total_tokens = sum(tr.metrics.total_tokens for tr in summary.task_results) + avg_duration = sum( + tr.run_result.duration_seconds for tr in summary.task_results if tr.run_result + ) / max(len(summary.task_results), 1) + combined_reasoning = "\n".join( + f"Task {tr.task_name}: {tr.eval_reasoning}" for tr in summary.task_results + ) return ExperimentResult( candidate=candidate, - run_result=tr.run_result, - metrics=tr.metrics, - eval_score=tr.eval_score, - eval_passed=tr.eval_passed, - eval_reasoning=tr.eval_reasoning, - traces=tr.run_result.trace if tr.run_result and isinstance(tr.run_result.trace, dict) else {} + run_result=summary.task_results[0].run_result, + metrics={"total_tokens": total_tokens, "avg_duration": avg_duration, + "pass_rate": summary.pass_rate, "num_tasks": len(summary.task_results)}, + eval_score=summary.avg_score, + eval_passed=summary.pass_rate > 0.5, + eval_reasoning=combined_reasoning, + traces=summary.task_results[0].run_result.trace if summary.task_results[0].run_result else {}, ) - - # Fallback to aggregate metrics if no individual task results + return ExperimentResult( - candidate=candidate, - run_result=None, - metrics={"score": summary.avg_score}, - eval_score=summary.avg_score, + candidate=candidate, run_result=None, + metrics={"score": summary.avg_score}, eval_score=summary.avg_score, eval_passed=summary.pass_rate > 0.5, - eval_reasoning=f"Aggregate pass rate: {summary.pass_rate}", - traces={} + eval_reasoning=f"Aggregate pass rate: {summary.pass_rate}", traces={} ) - + except Exception as e: logger.error(f"Error evaluating candidate '{candidate.agent.name}': {e}", exc_info=True) - # Return a fallback result instead of propagating the exception return ExperimentResult( - candidate=candidate, - run_result=None, - metrics={"score": 0.0, "error": str(e)}, - eval_score=0.0, - eval_passed=False, - eval_reasoning=f"Evaluation error: {str(e)}", - traces={} + candidate=candidate, run_result=None, + metrics={"score": 0.0, "error": str(e)}, eval_score=0.0, + eval_passed=False, eval_reasoning=f"Evaluation error: {e!s}", traces={} ) - - # Inject dependencies into strategy if supported - # GepaStrategy accepts them in __init__, but we might have loaded it from config - # without them. - if hasattr(strategy, "evaluator") and strategy.evaluator is None: + # Inject GEPA-specific dependencies + if strategy.evaluator is None: strategy.evaluator = evaluator if hasattr(strategy, "dataset") and strategy.dataset is None: strategy.dataset = tasks - - # Execute strategy (blocking/sync) - # We should run this in an executor to avoid blocking the main async loop - # if we were doing other async things, but here we just wait for it. - loop = asyncio.get_running_loop() - candidates = await loop.run_in_executor(None, strategy.generate, base_agent, budget) + + candidates = await strategy.generate(base_agent, budget, tasks=tasks, runner=None) + + if hasattr(strategy, "print_report"): + strategy.print_report() console.print("\n[bold green]Optimization complete![/]") console.print(f"Generated {len(candidates)} candidates.") - # Export results - if output_dir: + output_path = output_dir if output_dir else run_dir + if output_path: + import json + from flow.experiments.models import export_agent - output_dir.mkdir(parents=True, exist_ok=True) - (output_dir / "agents").mkdir(exist_ok=True) - + + output_path.mkdir(parents=True, exist_ok=True) + (output_path / "agents").mkdir(exist_ok=True) + for i, cand in enumerate(candidates): - # Basic export name = cand.agent.name or f"candidate_{i}" - export_agent(cand.agent, output_dir / "agents" / f"{name}.yaml", metrics={"rationale": cand.rationale}) - - console.print(f"\nAgents exported to: [cyan]{output_dir / 'agents'}[/]") + export_agent(cand.agent, output_path / "agents" / f"{name}.yaml", metrics={"rationale": cand.rationale}) + + if hasattr(strategy, "get_report") and strategy.get_report(): + report = strategy.get_report() + report_data = { + "baseline_prompt": report.baseline_prompt, + "baseline_score": report.baseline_score, + "final_prompt": report.final_prompt, + "final_score": report.final_score, + "best_candidate_id": report.best_candidate_id, + "improvement": report.improvement, + "improvement_percent": (report.improvement / max(report.baseline_score, 0.001)) * 100, + "total_candidates_evaluated": report.total_candidates_evaluated, + "total_generations": report.total_generations, + "candidate_history": [ + { + "generation": r.generation, + "candidate_id": r.candidate_id, + "avg_score": r.avg_score, + "best_score": r.best_score, + "best_eval_num": r.best_eval_num, + "eval_count": r.eval_count, + "pass_rate": r.pass_rate, + "is_selected": r.is_selected, + "instructions_preview": r.instructions_preview, + } + for r in report.candidate_history + ] + } + with open(output_path / "optimization_report.json", "w") as f: + json.dump(report_data, f, indent=2) + console.print(f"Optimization report saved to: [cyan]{output_path / 'optimization_report.json'}[/]") + + console.print(f"\nAgents exported to: [cyan]{output_path / 'agents'}[/]") diff --git a/src/flow/cli/repl.py b/src/flow/cli/repl.py index 5dc63cf0fff0f19603a9980267f932cfd2a6040e..ca862dc7646092e6047231f9447d7beaeac83d73 100644 --- a/src/flow/cli/repl.py +++ b/src/flow/cli/repl.py @@ -47,7 +47,9 @@ class FlowREPL: """Get or create the harness instance.""" if self._harness is None: # Import maf module to register the harness, then use registry - import flow.harness.maf # noqa: F401 + import flow.harness.maf as _maf + + _ = _maf from flow.harness import create_harness agent = Agent(name="flow-repl") diff --git a/src/flow/experiments/__init__.py b/src/flow/experiments/__init__.py index 74dc6dfd5d2fab3c4a54ad43f2893dd230f7cf18..0900e9001b7ad9f5d5262e701110a08299d68606 100644 --- a/src/flow/experiments/__init__.py +++ b/src/flow/experiments/__init__.py @@ -27,7 +27,7 @@ Example usage: strategy = GridSearchStrategy(variations={ "enable_memory": [True, False], }) - candidates = strategy.generate(base, budget=10) + candidates = await strategy.generate(base, budget=10) # Run optimization optimizer = FlowOptimizer(parallel=4) @@ -37,18 +37,6 @@ Example usage: """ # Core models -from .models import ( - Agent, - Candidate, - CandidateStrategy, - CompactionConfig, - ExperimentResult, - GridSearchStrategy, - export_agent, - export_optimization_results, - load_agent, -) - # Experiment runner + Pareto analysis from .ablation import ( compute_pareto_frontier, @@ -66,6 +54,16 @@ from .evaluators import ( TraceEvaluator, ) +# Expansion pipeline +from .expansion import expand_variations, generate_candidates + +# HF Dataset Integration +from .hf_datasets import ( + import_hf_dataset, + register_converter, + save_tasks_to_jsonl, +) + # Metrics from .metrics import ( LLMCallInfo, @@ -75,6 +73,26 @@ from .metrics import ( format_metrics_summary, metrics_to_dict, ) +from .models import ( + Agent, + Candidate, + CandidateStrategy, + CompactionConfig, + Experiment, + ExperimentResult, + ExperimentRunner, + Framework, + GridSearchStrategy, + LiteralVariation, + StrategyIteration, + StrategyVariation, + VariationItem, + compute_max_experiments, + export_agent, + export_optimization_results, + load_agent, + load_experiment, +) # Optimizer from .optimizer import ( @@ -82,6 +100,7 @@ from .optimizer import ( FlowOptimizer, OptimizationResult, TaskResult, + evaluate_agent, load_tasks_from_jsonl, ) @@ -96,11 +115,24 @@ from .reporters import ( ) # Runner -from .runner import FlowExperimentRunner, setup_tracing +from .runner import FlowExperimentRunner, get_shared_collector, setup_tracing + +# Strategy registry +from .strategies import get_registered_strategies, get_strategy, register_strategy + +# Presets +from .presets import AgentPreset, get_all_presets, get_preset + +# Results (simple API) +from .results import ( + AgentOptimizationResult, + EvaluationResult, + ImprovementMetrics, +) # Trace collection from .trace_collector import FlowTraceCollector -from .types import CriterionResult, EvalCriterion, EvalResult, RunResult, Task +from .types import CriterionResult, EvalCriterion, EvalResult, RunResult, Task, get_task_suite __all__ = [ # noqa: RUF022 # Intentionally grouped by category # Core models @@ -108,11 +140,27 @@ __all__ = [ # noqa: RUF022 # Intentionally grouped by category "Candidate", "CandidateStrategy", "CompactionConfig", + "Experiment", "ExperimentResult", + "ExperimentRunner", + "Framework", "GridSearchStrategy", + "LiteralVariation", + "StrategyIteration", + "StrategyVariation", + "VariationItem", + "compute_max_experiments", "export_agent", "load_agent", + "load_experiment", "export_optimization_results", + # Expansion pipeline + "expand_variations", + "generate_candidates", + # Strategy registry + "get_strategy", + "register_strategy", + "get_registered_strategies", # Types "Task", "EvalCriterion", @@ -130,6 +178,7 @@ __all__ = [ # noqa: RUF022 # Intentionally grouped by category "metrics_to_dict", # Runner "FlowExperimentRunner", + "get_shared_collector", "setup_tracing", # Evaluators "Evaluator", @@ -154,5 +203,20 @@ __all__ = [ # noqa: RUF022 # Intentionally grouped by category "OptimizationResult", "CandidateSummary", "TaskResult", + "evaluate_agent", "load_tasks_from_jsonl", + # Presets + "AgentPreset", + "get_preset", + "get_all_presets", + # Results (simple API) + "EvaluationResult", + "AgentOptimizationResult", + "ImprovementMetrics", + # Task suites + "get_task_suite", + # HF Datasets + "import_hf_dataset", + "register_converter", + "save_tasks_to_jsonl", ] diff --git a/src/flow/experiments/ablation.py b/src/flow/experiments/ablation.py index 99c7dcf804471a5d888afda5d8ce9515816019b1..596eebf2b7d47b79e044541da45b2b8bfdddcf21 100644 --- a/src/flow/experiments/ablation.py +++ b/src/flow/experiments/ablation.py @@ -46,9 +46,13 @@ async def run_single_experiment( ExperimentResult with metrics and evaluation """ # Import harness modules to register them, then use registry - import flow.harness.maf # noqa: F401 + import flow.harness.maf as _maf + + _ = _maf try: - import flow.harness.miniagent # noqa: F401 + import flow.harness.miniagent as _miniagent + + _ = _miniagent except ImportError: pass # miniagent harness is optional from flow.harness import create_harness diff --git a/src/flow/experiments/agent_api.py b/src/flow/experiments/agent_api.py new file mode 100644 index 0000000000000000000000000000000000000000..3e6fde3b666741c9e3e6d5b246582dcf826114ab --- /dev/null +++ b/src/flow/experiments/agent_api.py @@ -0,0 +1,305 @@ +# Copyright (c) Microsoft. All rights reserved. + +"""Implementation of Agent.evaluate() and Agent.optimize() methods. + +This module contains the implementation details, keeping the Agent class +itself clean and focused on configuration. +""" + +from __future__ import annotations + +import contextlib +import io +import sys +from pathlib import Path +from typing import TYPE_CHECKING, Any + +from .models import Candidate, CompactionConfig, GridSearchStrategy +from .optimizer import FlowOptimizer, OptimizationResult, evaluate_agent +from .results import AgentOptimizationResult, EvaluationResult, ImprovementMetrics +from .types import Task, get_task_suite, load_tasks_from_jsonl + +if TYPE_CHECKING: + from .models import Agent + from .optimizer import CandidateSummary + + +# Default variations for optimize() when none provided +DEFAULT_VARIATIONS: dict[str, list[Any]] = { + "tools": ["minimal", "standard"], + "compaction": [ + CompactionConfig.none(), + CompactionConfig.head_tail(10, 40), + CompactionConfig.sliding_window(100_000), + ], +} + +# Known active strategy names and their classes +_STRATEGY_MAP: dict[str, str] = { + "tools": "flow.experiments.strategies.tool_selector.ToolSelectorStrategy", + "instructions": "flow.experiments.strategies.llm_rewriter.LLMRewriterStrategy", +} + + +def _resolve_tasks(tasks: str | list[Task] | Path) -> list[Task]: + """Resolve tasks specification to list of Task objects. + + Args: + tasks: One of: + - str: Suite name (e.g., "quick", "coding", "gaia_level1") + - list[Task]: Already resolved tasks + - Path: Path to JSONL file + + Returns: + List of Task objects + """ + if isinstance(tasks, str): + return get_task_suite(tasks) + elif isinstance(tasks, Path): + return load_tasks_from_jsonl(tasks) + else: + return tasks + + +def _summary_to_eval_result(summary: CandidateSummary) -> EvaluationResult: + """Convert internal CandidateSummary to user-friendly EvaluationResult.""" + return EvaluationResult( + score=summary.avg_score, + tokens=summary.total_tokens, + pass_rate=summary.pass_rate, + duration=summary.avg_duration * summary.task_count, + task_count=summary.task_count, + _details=summary, + ) + + +@contextlib.contextmanager +def _suppress_output(): + """Context manager to suppress stdout/stderr.""" + old_stdout, old_stderr = sys.stdout, sys.stderr + sys.stdout = io.StringIO() + sys.stderr = io.StringIO() + try: + yield + finally: + sys.stdout, sys.stderr = old_stdout, old_stderr + + +async def _evaluate_agent_impl( + agent: Agent, + tasks: str | list[Task] | Path, + parallel: int, + use_llm_eval: bool, + quiet: bool, + agent_id: str | None = None, +) -> EvaluationResult: + """Implementation of Agent.evaluate(). + + Args: + agent_id: If set (from deploy()), results are auto-persisted to DB. + """ + resolved_tasks = _resolve_tasks(tasks) + + if quiet: + with _suppress_output(): + summary = await evaluate_agent( + agent, + resolved_tasks, + parallel=parallel, + use_llm_evaluator=use_llm_eval, + ) + else: + summary = await evaluate_agent( + agent, + resolved_tasks, + parallel=parallel, + use_llm_evaluator=use_llm_eval, + ) + + result = _summary_to_eval_result(summary) + + # Auto-persist if agent was deployed + if agent_id is not None: + try: + from flow.ui.services.persistence_adapter import PersistenceAdapter + + adapter = PersistenceAdapter() + result.job_id = await adapter.persist_evaluation(summary, agent_id) + except ImportError: + pass # DB not available, skip persistence + + return result + + +def _resolve_strategy(name: str) -> Any: + """Import and instantiate a named strategy. + + Args: + name: Strategy name ("tools", "instructions") + + Returns: + Strategy instance + + Raises: + ValueError: If name is not a known strategy + """ + if name not in _STRATEGY_MAP: + available = ["grid"] + list(_STRATEGY_MAP.keys()) + raise ValueError(f"Unknown strategy: {name!r}. Available: {available}") + + module_path, class_name = _STRATEGY_MAP[name].rsplit(".", 1) + import importlib + mod = importlib.import_module(module_path) + cls = getattr(mod, class_name) + return cls(config={ + "max_iterations": 3, + "min_improvement": 0.01, + }) + + +def _opt_result_to_agent_result( + opt_result: OptimizationResult, + baseline_agent: Agent, +) -> AgentOptimizationResult: + """Convert internal OptimizationResult to user-friendly AgentOptimizationResult.""" + # Find baseline: look for the original agent name with no mutations, else first summary + baseline_summary = next( + (s for s in opt_result.summaries if s.name == baseline_agent.name and s.candidate.mutations == {}), + None, + ) + best_summary = opt_result.get_best_candidate("score") or opt_result.summaries[0] + + if baseline_summary is not None: + baseline_result = _summary_to_eval_result(baseline_summary) + else: + # For active strategies, the baseline is the first iteration in optimization_history + history = best_summary.candidate.optimization_history + if history: + baseline_result = EvaluationResult( + score=history[0].avg_score, + tokens=0, + pass_rate=history[0].pass_rate, + duration=0.0, + task_count=best_summary.task_count or len(history[0].change_description), + ) + else: + baseline_result = _summary_to_eval_result(best_summary) + + best_result = _summary_to_eval_result(best_summary) + + score_delta = best_result.score - baseline_result.score + token_reduction_pct = 0.0 + if baseline_result.tokens > 0: + token_reduction_pct = (baseline_result.tokens - best_result.tokens) / baseline_result.tokens * 100 + + return AgentOptimizationResult( + baseline=baseline_result, + best=best_result, + improvement=ImprovementMetrics( + score_delta=score_delta, + token_reduction_pct=token_reduction_pct, + ), + best_agent=best_summary.candidate.agent, + candidates_tested=len(opt_result.summaries), + pareto_frontier=opt_result.pareto_frontier, + output_dir=opt_result.output_dir, + ) + + +async def _optimize_agent_impl( + agent: Agent, + tasks: str | list[Task] | Path, + variations: dict[str, list[Any]] | None, + parallel: int, + budget: int, + use_llm_eval: bool, + quiet: bool, + agent_id: str | None = None, + strategy: str | list[str] | None = None, +) -> AgentOptimizationResult: + """Implementation of Agent.optimize(). + + Args: + agent_id: If set (from deploy()), results are auto-persisted to DB. + strategy: Active optimization strategy name(s). None or "grid" uses + grid search. A string like "tools" or "instructions" runs that + strategy. A list runs them sequentially, each starting from the + previous best. + """ + resolved_tasks = _resolve_tasks(tasks) + + # Normalize strategy to a list (or None for grid search) + if strategy is None or strategy == "grid": + strategy_list = None + elif isinstance(strategy, str): + strategy_list = [strategy] + else: + strategy_list = list(strategy) + + # ── Grid search path (original behavior) ── + if strategy_list is None: + actual_variations = variations if variations is not None else DEFAULT_VARIATIONS + + grid_strategy = GridSearchStrategy(variations=actual_variations) + candidates = await grid_strategy.generate(agent, budget=budget) + + baseline_candidate = Candidate(agent=agent, mutations={}, rationale="baseline") + has_baseline = any(c.agent.name == agent.name and c.mutations == {} for c in candidates) + if not has_baseline: + candidates.insert(0, baseline_candidate) + + optimizer = FlowOptimizer(parallel=parallel, use_llm_evaluator=use_llm_eval) + + if quiet: + with _suppress_output(): + opt_result = await optimizer.optimize(candidates, resolved_tasks) + else: + opt_result = await optimizer.optimize(candidates, resolved_tasks) + + result = _opt_result_to_agent_result(opt_result, agent) + + # ── Active strategy path ── + else: + current_agent = agent + last_opt_result: OptimizationResult | None = None + + for strat_name in strategy_list: + strat_instance = _resolve_strategy(strat_name) + optimizer = FlowOptimizer(parallel=parallel, use_llm_evaluator=use_llm_eval) + + if quiet: + with _suppress_output(): + last_opt_result = await optimizer.optimize_with_strategy( + strategy=strat_instance, + base=current_agent, + tasks=resolved_tasks, + budget=budget, + ) + else: + last_opt_result = await optimizer.optimize_with_strategy( + strategy=strat_instance, + base=current_agent, + tasks=resolved_tasks, + budget=budget, + ) + + # Next stage starts from the best agent found + best = last_opt_result.get_best_candidate("score") + if best: + current_agent = best.candidate.agent + + assert last_opt_result is not None + result = _opt_result_to_agent_result(last_opt_result, agent) + + # Auto-persist if agent was deployed + if agent_id is not None: + try: + from flow.ui.services.persistence_adapter import PersistenceAdapter + + adapter = PersistenceAdapter() + opt_to_persist = opt_result if strategy_list is None else last_opt_result + result.job_id = await adapter.persist_optimization(opt_to_persist, agent_id) + except ImportError: + pass # DB not available, skip persistence + + return result diff --git a/src/flow/experiments/evaluators/heuristic.py b/src/flow/experiments/evaluators/heuristic.py index 6e9104e1014ed77f0e27fbe190828a5f1a69ece7..05e2bb5380d44217d3f2b8f1726fe606c3e28f10 100644 --- a/src/flow/experiments/evaluators/heuristic.py +++ b/src/flow/experiments/evaluators/heuristic.py @@ -73,7 +73,7 @@ class HeuristicEvaluator: # Check if agent reported task complete output_lower = run_result.output.lower() - if "complete" in output_lower or "complete" in output_lower or "finished" in output_lower: + if "complete" in output_lower or "finished" in output_lower: criteria_results.append( CriterionResult( name="task_completed", diff --git a/src/flow/experiments/evaluators/llm.py b/src/flow/experiments/evaluators/llm.py index 65d01ab14e926d939655f76e81d32544cb04c07d..89c735d70e0847fd43b50e715be2d67241317dd4 100644 --- a/src/flow/experiments/evaluators/llm.py +++ b/src/flow/experiments/evaluators/llm.py @@ -11,6 +11,21 @@ from ..types import CriterionResult, EvalResult, RunResult logger = logging.getLogger(__name__) +# Presets for how agent output is formatted before sending to the LLM judge. +# Agent outputs can be very large (100K-600K+ chars for multi-step tasks). +# The final answer is almost always at the end, so "head_tail" (default) +# keeps both the initial approach and the final answer visible to the judge. +# +# Each preset specifies {"head": N, "tail": M} where N chars from the start +# and M chars from the end are kept. When truncation occurs, a marker like +# "... [150,000 chars truncated] ..." is inserted. +OUTPUT_FORMAT_PRESETS: dict[str, dict[str, int]] = { + "head_tail": {"head": 2000, "tail": 10000}, # Default: sees start + final answer + "head_only": {"head": 8000, "tail": 0}, # Legacy: first 8K only + "tail_only": {"head": 0, "tail": 12000}, # Only the final output + "full": {"head": 0, "tail": 0}, # No truncation (watch context limits) +} + class LLMEvaluator: """Evaluator that uses an LLM to assess agent output against criteria. @@ -39,6 +54,7 @@ class LLMEvaluator: model_name: str = "gpt-4o", passing_threshold: float = 0.7, temperature: float | None = None, + output_format: str | dict[str, int] = "head_tail", ) -> None: """Initialize the LLM evaluator. @@ -50,13 +66,56 @@ class LLMEvaluator: temperature: Temperature for LLM calls. None means don't specify (use model default). Some models like gpt-5.2-chat only support temperature=1.0. + output_format: How to format agent output for the judge. Either a + preset name ("head_tail", "head_only", "tail_only", "full") + or a dict with "head" and "tail" char counts. + See OUTPUT_FORMAT_PRESETS for details. """ self.model_client = model_client self.model_name = model_name self.passing_threshold = passing_threshold self.temperature = temperature - def _get_evaluation_prompt(self, run_result: RunResult) -> str: + # Resolve output format + if isinstance(output_format, str): + if output_format not in OUTPUT_FORMAT_PRESETS: + raise ValueError( + f"Unknown output_format '{output_format}'. " + f"Available: {list(OUTPUT_FORMAT_PRESETS.keys())}" + ) + fmt = OUTPUT_FORMAT_PRESETS[output_format] + else: + fmt = output_format + self._output_head = fmt["head"] + self._output_tail = fmt["tail"] + + def _format_output(self, output: str) -> str: + """Format agent output for the evaluation prompt. + + Uses head+tail truncation to ensure the judge sees both the initial + approach and the final answer. When output is truncated, a marker is + inserted showing how many characters were removed. + + The strategy is configured via the output_format parameter on __init__. + """ + head = self._output_head + tail = self._output_tail + budget = head + tail + + # No truncation if budget is 0 (full mode) or output fits + if budget == 0 or len(output) <= budget: + return output + + parts: list[str] = [] + if head > 0: + parts.append(output[:head]) + truncated = len(output) - budget + parts.append(f"\n\n... [{truncated:,} chars truncated] ...\n\n") + if tail > 0: + parts.append(output[-tail:]) + return "".join(parts) + + def _get_evaluation_prompt(self, run_result: RunResult, instructions: str | None = None) -> str: """Build the evaluation prompt for the LLM.""" criteria_text = "\n".join( f"- **{c.name}** (weight: {c.weight}): {c.instruction}" @@ -66,6 +125,8 @@ class LLMEvaluator: # Extract execution trace summary for research/multi-step tasks trace_summary = self._get_trace_summary(run_result) + instructions_section = f"\n## Agent Instructions\n```\n{instructions}\n```\n" if instructions else "" + return f"""You are an expert evaluator assessing an AI agent's output. ## Task @@ -73,15 +134,18 @@ The agent was given this task: ``` {run_result.task.prompt} ``` - +{instructions_section} ## Agent Output ``` -{run_result.output[:8000]} +{self._format_output(run_result.output)} ``` ## Files Created {json.dumps(run_result.files_created, indent=2) if run_result.files_created else "None"} +## Tool Results +{self._format_tool_results(run_result.tool_results)} + ## Execution Trace {trace_summary} @@ -95,27 +159,61 @@ The agent was given this task: Evaluate the agent's output against each criterion. Consider both the final output AND the execution trace (tools used, steps taken) when assessing correctness. -For each criterion: -1. Assess how well the output meets the criterion (0.0 to 1.0) -2. Determine if it passes (score >= 0.7) -3. Provide brief reasoning - -Respond in this exact JSON format: -```json -{{ - "criteria_results": [ - {{ - "name": "criterion_name", - "score": 0.85, - "passed": true, - "reasoning": "Brief explanation" - }} - ], - "overall_reasoning": "Summary of the overall evaluation" -}} -``` +For each criterion, provide TWO scores: +1. **score** (0.0 or 1.0): Does the agent's final answer exactly match what's required? This is strict exact-match. +2. **reasoning_score** (0.0 to 1.0): Did the agent demonstrate correct reasoning/methodology? Give partial credit for: + - Correct approach but wrong format (e.g., "17000" when "17" was expected) + - Correct methodology but wrong final number + - Identifying the right sources/data but making a calculation error + - Partial completion of a multi-part task +3. **passed**: true if score >= 1.0 (exact match) +4. Provide brief reasoning explaining both scores """ + def _get_eval_schema(self) -> dict[str, Any]: + """Get JSON schema for structured evaluation output.""" + return { + "name": "evaluation_result", + "strict": True, + "schema": { + "type": "object", + "properties": { + "criteria_results": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": {"type": "string"}, + "score": {"type": "number"}, + "reasoning_score": {"type": "number"}, + "passed": {"type": "boolean"}, + "reasoning": {"type": "string"}, + }, + "required": ["name", "score", "reasoning_score", "passed", "reasoning"], + "additionalProperties": False, + }, + }, + "overall_reasoning": {"type": "string"}, + }, + "required": ["criteria_results", "overall_reasoning"], + "additionalProperties": False, + }, + } + + def _format_tool_results(self, tool_results: list[dict[str, str]]) -> str: + """Format tool results for the evaluation prompt.""" + if not tool_results: + return "None" + lines = [] + for tr in tool_results: + tool = tr.get("tool", "unknown") + output = tr.get("output", "") + # Truncate long tool outputs + if len(output) > 500: + output = output[:500] + f"... [{len(output) - 500} chars truncated]" + lines.append(f"**{tool}**:\n```\n{output}\n```") + return "\n".join(lines) + def _get_trace_summary(self, run_result: RunResult) -> str: """Extract a summary of the execution trace for evaluation.""" if not run_result.trace: @@ -137,11 +235,12 @@ Total tool calls: {metrics.tool_call_count} {tool_summary} Tokens used: {metrics.total_tokens} (input: {metrics.input_tokens}, output: {metrics.output_tokens})""" - async def evaluate(self, run_result: RunResult) -> EvalResult: + async def evaluate(self, run_result: RunResult, instructions: str | None = None) -> EvalResult: """Evaluate the agent's output using an LLM. Args: run_result: The result from running an agent on a task + instructions: Optional instructions used by the agent during the run Returns: EvalResult with LLM-generated scores and reasoning @@ -158,45 +257,44 @@ Tokens used: {metrics.total_tokens} (input: {metrics.input_tokens}, output: {met ), ) - prompt = self._get_evaluation_prompt(run_result) + prompt = self._get_evaluation_prompt(run_result, instructions=instructions) try: - # Build params - only include temperature if explicitly set + # Build params with structured output params: dict[str, Any] = { "model": self.model_name, "messages": [ { "role": "system", - "content": "You are an expert evaluator. Respond only with valid JSON.", + "content": "You are an expert evaluator.", }, {"role": "user", "content": prompt}, ], + "response_format": { + "type": "json_schema", + "json_schema": self._get_eval_schema(), + }, } if self.temperature is not None: params["temperature"] = self.temperature response = await self.model_client.chat.completions.create(**params) - # Extract the response text - response_text = response.choices[0].message.content or "" - - # Parse JSON from response - json_start = response_text.find("{") - json_end = response_text.rfind("}") + 1 - if json_start >= 0 and json_end > json_start: - eval_data = json.loads(response_text[json_start:json_end]) - else: - raise ValueError("No JSON found in response") + # Extract and parse response - structured output guarantees valid JSON + response_text = response.choices[0].message.content or "{}" + eval_data = json.loads(response_text) # Build criterion results criteria_results = [] total_weighted_score = 0.0 + total_weighted_reasoning = 0.0 total_weight = 0.0 for cr_data in eval_data.get("criteria_results", []): cr = CriterionResult( name=cr_data.get("name", "unknown"), score=float(cr_data.get("score", 0.0)), + reasoning_score=float(cr_data.get("reasoning_score", 0.0)), passed=bool(cr_data.get("passed", False)), reasoning=cr_data.get("reasoning", ""), ) @@ -210,13 +308,16 @@ Tokens used: {metrics.total_tokens} (input: {metrics.input_tokens}, output: {met break total_weighted_score += cr.score * weight + total_weighted_reasoning += cr.reasoning_score * weight total_weight += weight - # Calculate overall score + # Calculate overall scores overall_score = total_weighted_score / total_weight if total_weight > 0 else 0.0 + overall_reasoning_score = total_weighted_reasoning / total_weight if total_weight > 0 else 0.0 return EvalResult( score=overall_score, + reasoning_score=overall_reasoning_score, passed=overall_score >= self.passing_threshold, criteria_results=criteria_results, reasoning=eval_data.get("overall_reasoning", ""), diff --git a/src/flow/experiments/expansion.py b/src/flow/experiments/expansion.py new file mode 100644 index 0000000000000000000000000000000000000000..4aeb8e71e73fb9c3e0b1ad99052ee93b382aae20 --- /dev/null +++ b/src/flow/experiments/expansion.py @@ -0,0 +1,250 @@ +# Copyright (c) Microsoft. All rights reserved. + +"""Variation expansion pipeline. + +Expands experiment variations (literals + strategies) into concrete values, +then generates candidates via Cartesian product. +""" + +from __future__ import annotations + +import logging +from dataclasses import asdict +from itertools import product as itertools_product +from typing import TYPE_CHECKING, Any + +from .models import ( + Agent, + Candidate, + CompactionConfig, + ExperimentRunner, + LiteralVariation, + StrategyVariation, + VariationItem, +) +from .strategies import get_strategy + +if TYPE_CHECKING: + from .types import Task + +logger = logging.getLogger(__name__) + + +async def expand_variations( + variations: dict[str, list[VariationItem]], + base: Agent, + tasks: list[Task], + runner: ExperimentRunner | None = None, +) -> dict[str, list[Any]]: + """Expand all variations to concrete values. + + - LiteralVariation: value passes through directly + - StrategyVariation: strategy.generate() is called to produce values + + Args: + variations: Parsed variations from Experiment + base: Base agent for strategies + tasks: Tasks for active strategies + runner: Optional ExperimentRunner for active strategies + + Returns: + Dict mapping dimension names to lists of concrete values + """ + expanded: dict[str, list[Any]] = {} + + for dimension, items in variations.items(): + expanded[dimension] = [] + logger.info(f"Expanding dimension '{dimension}' ({len(items)} items)") + + for item in items: + if isinstance(item, LiteralVariation): + # Literal: add directly + expanded[dimension].append(item.value) + logger.debug(f" Literal: {_format_value(item.value)}") + + elif isinstance(item, StrategyVariation): + # Strategy: invoke and collect results + logger.info(f" Running strategy '{item.strategy}' (max_candidates={item.max_candidates})") + + try: + strategy = get_strategy(item.strategy, item.config) + + candidates = await strategy.generate( + base=base, + budget=item.max_candidates, + tasks=tasks, + runner=runner, + ) + + # Extract mutated values for this dimension + for cand in candidates: + if dimension in cand.mutations: + value = cand.mutations[dimension] + expanded[dimension].append(value) + logger.debug(f" Strategy produced: {_format_value(value)}") + else: + # Strategy didn't mutate this dimension, use base value + base_value = getattr(base, dimension, None) + if base_value is not None: + expanded[dimension].append(base_value) + logger.debug(f" Strategy kept base: {_format_value(base_value)}") + + logger.info(f" Strategy '{item.strategy}' produced {len(candidates)} candidates") + + except Exception as e: + logger.error(f" Strategy '{item.strategy}' failed: {e}") + raise + + logger.info(f"Dimension '{dimension}': {len(expanded[dimension])} total values") + + return expanded + + +def generate_candidates( + base: Agent, + expanded: dict[str, list[Any]], + budget: int = 1000, +) -> list[Candidate]: + """Generate candidates via Cartesian product of expanded variations. + + Args: + base: Base agent to mutate + expanded: Dict mapping dimension names to lists of concrete values + budget: Maximum candidates to generate (safety limit) + + Returns: + List of Candidate objects + """ + if not expanded: + return [Candidate(agent=base, mutations={}, rationale="baseline")] + + dimensions = list(expanded.keys()) + value_lists = [expanded[d] for d in dimensions] + + # Check if any dimension is empty + for dim, values in zip(dimensions, value_lists, strict=True): + if not values: + logger.warning(f"Dimension '{dim}' has no values, using baseline") + return [Candidate(agent=base, mutations={}, rationale="baseline (empty variations)")] + + candidates: list[Candidate] = [] + + for values in itertools_product(*value_lists): + if len(candidates) >= budget: + logger.warning(f"Reached budget limit ({budget}), stopping candidate generation") + break + + mutations = dict(zip(dimensions, values, strict=True)) + candidate = _create_candidate(base, mutations) + candidates.append(candidate) + + logger.info(f"Generated {len(candidates)} candidates from {len(dimensions)} dimensions") + return candidates + + +def _create_candidate(base: Agent, mutations: dict[str, Any]) -> Candidate: + """Create a candidate by applying mutations to base agent. + + Args: + base: Base agent + mutations: Dict of field name -> value + + Returns: + New Candidate with mutated agent + """ + # Build mutated agent dict + agent_dict = asdict(base) + + for key, value in mutations.items(): + if key == "compaction" and isinstance(value, CompactionConfig): + agent_dict["compaction"] = asdict(value) + elif key in agent_dict: + agent_dict[key] = value + + # Reconstruct CompactionConfig from dict + comp_data = agent_dict.pop("compaction") + if isinstance(comp_data, dict): + compaction = CompactionConfig(**comp_data) + else: + compaction = comp_data + + # Handle tools field - keep as-is (str, list, or dict) + tools = agent_dict.pop("tools", "standard") + + mutated = Agent( + **{k: v for k, v in agent_dict.items() if k not in ("compaction", "tools")}, + compaction=compaction, + tools=tools, + ) + + # Build name from mutations + name_parts = _build_name_parts(mutations) + mutated.name = f"{base.name}_{'_'.join(name_parts)}" if name_parts else base.name + + # Serialize mutations for storage + serializable_mutations = _serialize_mutations(mutations) + + return Candidate( + agent=mutated, + mutations=serializable_mutations, + rationale=f"Variations: {', '.join(name_parts)}" if name_parts else "baseline", + ) + + +def _build_name_parts(mutations: dict[str, Any]) -> list[str]: + """Build name parts from mutations for candidate naming.""" + name_parts = [] + + for k, v in mutations.items(): + if isinstance(v, CompactionConfig): + name_parts.append(f"{v.strategy}") + if v.strategy == "head_tail": + name_parts.append(f"h{v.head_size}_t{v.tail_size}") + elif k == "tools": + if isinstance(v, str): + name_parts.append(f"tools={v}") + elif isinstance(v, list): + name_parts.append(f"tools=[{len(v)}]") + else: + name_parts.append(f"tools=[{len(v)}]") + elif k == "llm_config" and isinstance(v, dict): + provider = v.get("provider", "unknown") + model = v.get("model", "") + name_parts.append(f"{provider}/{model}" if model else provider) + elif k == "instructions": + # Truncate instructions for name + preview = str(v)[:30].replace(" ", "_").replace("\n", "_") + name_parts.append(f"instr={preview}") + elif isinstance(v, bool): + name_parts.append(f"{k}={'on' if v else 'off'}") + else: + name_parts.append(f"{k}={v}") + + return name_parts + + +def _serialize_mutations(mutations: dict[str, Any]) -> dict[str, Any]: + """Serialize mutations for storage (convert non-serializable types).""" + serializable = {} + + for k, v in mutations.items(): + if isinstance(v, CompactionConfig): + serializable[k] = asdict(v) + else: + serializable[k] = v + + return serializable + + +def _format_value(value: Any) -> str: + """Format a value for logging.""" + if isinstance(value, CompactionConfig): + return f"CompactionConfig({value.strategy})" + elif isinstance(value, str) and len(value) > 50: + return f'"{value[:50]}..."' + elif isinstance(value, dict): + return f"dict({len(value)} keys)" + elif isinstance(value, list): + return f"list({len(value)} items)" + else: + return repr(value) diff --git a/src/flow/experiments/gaia_converter.py b/src/flow/experiments/gaia_converter.py new file mode 100644 index 0000000000000000000000000000000000000000..0f301d41402d1816a8474bce469123812dd0b3eb --- /dev/null +++ b/src/flow/experiments/gaia_converter.py @@ -0,0 +1,216 @@ +import os +from pathlib import Path +from typing import Any + +from loguru import logger + +from flow.experiments.types import EvalCriterion, Task +from flow.tools.text_inspector_qa import TextInspectorTool +from flow.tools.visual_inspector_qa import VisualInspectorTool + + +def _get_augmented_prompt_for_files( + local_path: str, + task: Task, + visual_inspector_tool: VisualInspectorTool | None, + text_inspector_tool: TextInspectorTool, +) -> str: + gaia_file = task.metadata.get("gaia_file") + if not gaia_file: + return "" + + file_name = str(gaia_file) + full_file_path = str(Path(local_path) / file_name) + ext = Path(file_name).suffix.lower() + + prompt_use_files = "\n\nTo answer the question above, you will have to use these attached files:" + + if ext in [".pdf", ".xlsx"]: + image_path = file_name.split(".")[0] + ".png" + full_image_path = Path(local_path) / image_path + if full_image_path.exists(): + prompt_use_files += f"\nAttached image: {full_image_path}" + else: + prompt_use_files += f"\nAttached file: {full_file_path}" + + elif ext == ".zip": + import shutil + + folder_name = full_file_path.replace(".zip", "") + os.makedirs(folder_name, exist_ok=True) + shutil.unpack_archive(full_file_path, folder_name) + + # Convert the extracted files + prompt_use_files = ( + "\n\nYou have been given a zip archive of supporting files. " + "We extracted it into a directory: find the extracted files at the following paths:\n" + ) + + for root, _, files in os.walk(folder_name): + for file in files: + file_path = os.path.join(root, file) + prompt_use_files += f"- {file_path}\n" + if Path(file).suffix.lower() in [".png", ".jpg", ".jpeg"] and visual_inspector_tool is not None: + prompt = f"""Write a caption of 5 sentences maximum for this image. Pay special attention to any details that might be useful for someone answering the following question: +{task.prompt}. But do not try to answer the question directly! +Do not add any information that is not present in the image. +""".strip() + prompt_use_files += ( + "> Description of this image: " + + visual_inspector_tool(image_path=file_path, question=prompt) + + "\n\n" + ) + else: + prompt = f"""Write a short caption (5 sentences maximum) for this file. Pay special attention to any details that might be useful for someone answering the following question: +{task.prompt}. But do not try to answer the question directly! +Do not add any information that is not present in the file. +""".strip() + prompt_use_files += ( + "> Description of this file: " + + text_inspector_tool.forward_initial_exam_mode(file_path=file_path, question=prompt) + + "\n\n" + ) + elif ext in [".png", ".jpg", ".jpeg"]: + prompt_use_files += f"\nAttached image: {full_file_path}" + elif ext in [".mp3", ".m4a", ".wav"]: + prompt_use_files += f"\nAttached audio: {full_file_path}" + else: + prompt_use_files += f"\nAttached file: {full_file_path}" + + return prompt_use_files + + +def extract_task(row: dict[str, Any]) -> dict[str, Any] | None: + """Extract task fields from a row with flexible field names. + + GAIA dataset has inconsistent field names across versions, so we try + multiple variants for each field. + + Args: + row: Raw row from parquet/jsonl + + Returns: + Normalized task dict, or None if task should be skipped + """ + # Question field variants + question = row.get("Question") or row.get("question") or row.get("query") or row.get("prompt") + + # Answer field variants + answer = row.get("Final answer") or row.get("answer") or row.get("final_answer") + + # Task ID field variants + task_id = str(row.get("task_id") or row.get("question_id") or row.get("id") or row.get("uuid")) + + # Level field + level = row.get("Level") or row.get("level") + if isinstance(level, str) and level.isdigit(): + level = int(level) + + # File attachment + file_name = row.get("file_name") or row.get("filename") + + # Skip tasks without question or valid answer (test set has "?" placeholders) + if not question or answer is None or str(answer).strip() in ["?", ""]: + return None + + return { + "task_id": task_id, + "question": question, + "answer": str(answer), + "level": level, + "file_name": file_name, + } + + +def convert_to_flow_task(gaia_task: dict[str, Any]) -> Task: + """Convert a GAIA task to Flow task format. + + Flow uses LLM-as-judge evaluation with criteria instructions. For GAIA, + we store the expected answer in both the criteria instruction and metadata + so that: + 1. LLM-as-judge can evaluate based on the instruction + 2. Custom evaluators can use metadata.gaia_answer for exact-match scoring + + Args: + gaia_task: Normalized GAIA task dict + + Returns: + Flow-compatible task dict + """ + return Task( + name=gaia_task["task_id"], + prompt=gaia_task["question"], + criteria=[ + EvalCriterion( + name="correct_answer", + instruction=f"The agent's final answer must match: {gaia_task['answer']}", + weight=1.0, + ) + ], + metadata={ + "gaia_answer": gaia_task["answer"], + "gaia_level": gaia_task.get("level"), + "gaia_file": gaia_task.get("file_name"), + "source": "gaia-benchmark", + }, + ) + + +def convert_gaia(example: dict[str, Any], index: int, dataset_metadata: dict[str, Any] | None = None) -> Task: + logger.debug(f"Processing task at index: {index}") + + if dataset_metadata is None: + raise ValueError("dataset_metadata is required and cannot be None.") + + # Validate required fields in dataset_metadata + config = dataset_metadata.get("config") + split = dataset_metadata.get("split") + local_path = dataset_metadata.get("local_path") + + if config is None: + raise ValueError("dataset_metadata 'config' is required and cannot be None.") + + if split is None: + raise ValueError("dataset_metadata 'split' is required and cannot be None.") + + if local_path is None: + raise ValueError("dataset_metadata 'local_path' is required and cannot be None.") + + # Derive GAIA year from the config when possible (e.g., "2023_level2" -> "2023"), + # falling back to "2023" to preserve existing behavior if parsing fails. + gaia_year = "2023" + if isinstance(config, str): + year_candidate = config.split("_", 1)[0] + if year_candidate.isdigit() and len(year_candidate) == 4: + gaia_year = year_candidate + + resolved_local_path = str(Path(local_path) / gaia_year / split) + + extracted_task = extract_task(example) + + converted_task = convert_to_flow_task(extracted_task) + + try: + visual_inspector_tool = VisualInspectorTool() + text_inspector_tool = TextInspectorTool() + except RuntimeError as exc: + logger.warning( + "Inspector tools could not be initialized (likely missing environment " + "variables). Skipping file-based prompt augmentation. Error: {}", + exc, + ) + prompt_for_files = "" + else: + prompt_for_files = _get_augmented_prompt_for_files( + local_path=resolved_local_path, + task=converted_task, + visual_inspector_tool=visual_inspector_tool, + text_inspector_tool=text_inspector_tool, + ) + + if len(prompt_for_files) > 0: + new_prompt = converted_task.prompt + prompt_for_files + converted_task.metadata["original_prompt"] = converted_task.prompt + converted_task.prompt = new_prompt + + return converted_task diff --git a/src/flow/experiments/hf_datasets.py b/src/flow/experiments/hf_datasets.py new file mode 100644 index 0000000000000000000000000000000000000000..46771dc4956e84ceba673a38939e9bbe329553bd --- /dev/null +++ b/src/flow/experiments/hf_datasets.py @@ -0,0 +1,354 @@ +"""Convert Hugging Face datasets to Flow task format. + +This module provides utilities to convert HF datasets (like GSM8K, MATH, HumanEval) +into Flow's task format for use with GEPA optimization. + +Usage: + # From CLI + python -m flow.cli.hf_import gsm8k --output tasks/gsm8k.jsonl --limit 100 + + # Programmatically + from flow.experiments.hf_datasets import import_hf_dataset + tasks = import_hf_dataset("openai/gsm8k", split="train", limit=50) +""" + +from __future__ import annotations + +import json +import logging +import os +from pathlib import Path +from typing import Any + +from flow.experiments.types import EvalCriterion, Task + +logger = logging.getLogger(__name__) + + +# Dataset-specific converters +# Each converter knows how to extract question/answer from a specific dataset + + +def convert_gsm8k(example: dict[str, Any], index: int, dataset_metadata: dict[str, Any] | None = None) -> Task: + """Convert GSM8K math problem to Flow task. + + GSM8K format: + { + "question": "Natalia sold clips to 48 of her friends...", + "answer": "Natalia sold 48/2 = 24 clips in May. ... #### 72" + } + """ + question = example["question"] + answer = example["answer"] + + # Extract final answer (after ####) + final_answer = None + if "####" in answer: + final_answer = answer.split("####")[-1].strip() + + # Create task with evaluation criteria + criteria = [ + EvalCriterion( + name="correctness", + instruction=f"The solution correctly answers: {question}. The correct answer is {final_answer}", + weight=1.0, + ), + EvalCriterion( + name="reasoning", + instruction="The solution shows clear mathematical reasoning and step-by-step work", + weight=0.7, + ), + ] + + task_metadata = {"dataset": "gsm8k", "index": index, "answer": answer, "final_answer": final_answer} + if dataset_metadata: + task_metadata.update(dataset_metadata) + + return Task( + name=f"gsm8k_{index}", + prompt=f"Solve this math problem step by step:\n\n{question}", + criteria=criteria, + metadata=task_metadata, + ) + + +def convert_math(example: dict[str, Any], index: int, dataset_metadata: dict[str, Any] | None = None) -> Task: + """Convert MATH dataset problem to Flow task. + + MATH format: + { + "problem": "What is 2+2?", + "solution": "The answer is 4", + "level": "Level 1", + "type": "Algebra" + } + """ + problem = example["problem"] + solution = example.get("solution", "") + level = example.get("level", "Unknown") + problem_type = example.get("type", "Unknown") + + criteria = [ + EvalCriterion(name="correctness", instruction=f"The solution correctly solves: {problem}", weight=1.0), + EvalCriterion( + name="mathematical_rigor", + instruction="The solution uses proper mathematical notation and reasoning", + weight=0.8, + ), + ] + + task_metadata = {"dataset": "math", "index": index, "level": level, "type": problem_type, "solution": solution} + if dataset_metadata: + task_metadata.update(dataset_metadata) + + return Task( + name=f"math_{problem_type.lower()}_{index}", + prompt=f"Solve this {level} {problem_type} problem:\n\n{problem}", + criteria=criteria, + metadata=task_metadata, + ) + + +def convert_humaneval(example: dict[str, Any], index: int, dataset_metadata: dict[str, Any] | None = None) -> Task: + r"""Convert HumanEval coding problem to Flow task. + + HumanEval format: + { + "task_id": "HumanEval/0", + "prompt": "def has_close_elements(numbers, threshold):\n ...", + "canonical_solution": " ...", + "test": "def check(...):\n ...", + "entry_point": "has_close_elements" + } + """ + task_id = example.get("task_id", f"task_{index}") + prompt = example["prompt"] + entry_point = example.get("entry_point", "") + test = example.get("test", "") + + criteria = [ + EvalCriterion( + name="correctness", instruction="The code implementation is correct and passes all test cases", weight=1.0 + ), + EvalCriterion( + name="code_quality", + instruction="The code is clean, well-documented, and follows best practices", + weight=0.6, + ), + ] + + task_metadata = {"dataset": "humaneval", "task_id": task_id, "entry_point": entry_point, "test": test} + if dataset_metadata: + task_metadata.update(dataset_metadata) + + return Task( + name=f"humaneval_{task_id.replace('/', '_')}", + prompt=f"Complete this Python function:\n\n{prompt}\n\nMake sure it passes the test cases.", + criteria=criteria, + metadata=task_metadata, + ) + + +def convert_mbpp(example: dict[str, Any], index: int, dataset_metadata: dict[str, Any] | None = None) -> Task: + """Convert MBPP coding problem to Flow task. + + MBPP format: + { + "task_id": 1, + "text": "Write a function to find the minimum cost path...", + "code": "def min_cost(cost, m, n): ...", + "test_list": ["assert min_cost(...) == ..."] + } + """ + task_id = example.get("task_id", index) + text = example.get("text", "") + test_list = example.get("test_list", []) + + criteria = [ + EvalCriterion(name="correctness", instruction=f"The solution correctly implements: {text}", weight=1.0), + EvalCriterion(name="efficiency", instruction="The solution uses an efficient algorithm", weight=0.7), + ] + + task_metadata = {"dataset": "mbpp", "task_id": task_id, "test_list": test_list} + if dataset_metadata: + task_metadata.update(dataset_metadata) + + return Task( + name=f"mbpp_{task_id}", + prompt=f"{text}\n\nImplement this in Python.", + criteria=criteria, + metadata=task_metadata, + ) + + +# Registry of dataset converters +def _get_gaia_converter(): + """Lazy import for GAIA converter to avoid smolagents dependency at import time.""" + from flow.experiments.gaia_converter import convert_gaia + return convert_gaia + + +DATASET_CONVERTERS = { + "openai/gsm8k": convert_gsm8k, + "gsm8k": convert_gsm8k, + "competition_math": convert_math, + "hendrycks/math": convert_math, + "humaneval": convert_humaneval, + "openai_humaneval": convert_humaneval, + "mbpp": convert_mbpp, + "google-research-datasets/mbpp": convert_mbpp, + "gaia-benchmark/GAIA": _get_gaia_converter, # Lazy loaded +} + + +def import_hf_dataset( + dataset_name: str, + config: str | None = None, + split: str = "train", + limit: int | None = None, + converter_override: Any = None, + local_path: str | Path | None = None, +) -> list[Task]: + """Import a Hugging Face dataset and convert to Flow tasks. + + Args: + dataset_name: HF dataset name (e.g., "openai/gsm8k") + config: Dataset configuration/subset (e.g., "main") + split: Dataset split to use (default: "train") + limit: Maximum number of examples to convert (default: all) + converter_override: Custom converter function (optional) + local_path: Path to download the dataset snapshot to using huggingface_hub.snapshot_download(). + When provided, downloads the dataset to this path first, then loads from local files. + If the snapshot already exists at this path, it will be reused. + For private datasets, set the HF_TOKEN environment variable with your Hugging Face token. + + Returns: + List of Flow Task objects + + Environment Variables: + HF_TOKEN: Hugging Face API token for accessing private/gated datasets. + Required when using local_path with private datasets. + + Example: + >>> # Load from Hugging Face Hub (default behavior) + >>> tasks = import_hf_dataset("openai/gsm8k", config="main", split="train", limit=50) + >>> print(f"Loaded {len(tasks)} tasks") + + >>> # Download to local path first, then load + >>> tasks = import_hf_dataset("openai/gsm8k", config="main", split="train", local_path="/data/gsm8k") + + >>> # For private datasets, set HF_TOKEN env variable first + >>> # export HF_TOKEN="hf_..." + >>> tasks = import_hf_dataset("org/private-dataset", split="train", local_path="/data/private") + """ + try: + from datasets import load_dataset + except ImportError as e: + raise ImportError("Hugging Face datasets library is required. Install with: pip install datasets") from e + + # Download to local path if specified, then load from there + if local_path is not None: + try: + from huggingface_hub import snapshot_download + except ImportError as e: + raise ImportError( + "huggingface_hub library is required for local_path support. Install with: pip install huggingface_hub" + ) from e + + local_path = Path(local_path) + hf_token = os.environ.get("HF_TOKEN") + logger.info(f"Downloading dataset {dataset_name} to local path: {local_path}") + snapshot_path = snapshot_download( + repo_id=dataset_name, + repo_type="dataset", + local_dir=str(local_path), + token=hf_token, + ) + logger.info(f"Loading dataset from local snapshot: {snapshot_path} (split: {split})") + dataset = load_dataset(snapshot_path, config, split=split) + else: + logger.info(f"Loading dataset: {dataset_name} (config: {config}, split: {split})") + dataset = load_dataset(dataset_name, config, split=split) + + # Apply limit + if limit: + dataset = dataset.select(range(min(limit, len(dataset)))) + + logger.info(f"Converting {len(dataset)} examples to Flow tasks...") + + # Find converter + converter = converter_override + if converter is None: + # Try to find matching converter + for key, conv in DATASET_CONVERTERS.items(): + if key in dataset_name: + # Handle lazy loaders (functions that return the actual converter) + if conv is _get_gaia_converter: + converter = conv() + else: + converter = conv + break + + if converter is None: + raise ValueError( + f"No converter found for dataset '{dataset_name}'. " + f"Available: {list(DATASET_CONVERTERS.keys())}\n" + f"Use converter_override parameter to provide a custom converter." + ) + + # Build dataset metadata to pass to converters + dataset_metadata: dict[str, Any] = {} + dataset_metadata["local_path"] = str(local_path) if local_path else None + dataset_metadata["config"] = config + dataset_metadata["split"] = split + + # Convert examples + tasks = [] + for i, example in enumerate(dataset): + try: + task = converter(example, i, dataset_metadata) + tasks.append(task) + except Exception as e: + logger.warning(f"Failed to convert example {i}: {e}", exc_info=True) + + logger.info(f"Successfully converted {len(tasks)} tasks") + return tasks + + +def save_tasks_to_jsonl(tasks: list[Task], output_path: Path) -> None: + """Save tasks to JSONL file. + + Args: + tasks: List of Task objects + output_path: Path to output JSONL file + """ + output_path.parent.mkdir(parents=True, exist_ok=True) + + with open(output_path, "w") as f: + for task in tasks: + # Convert to dict + task_dict = { + "name": task.name, + "prompt": task.prompt, + "criteria": [{"name": c.name, "instruction": c.instruction, "weight": c.weight} for c in task.criteria], + "metadata": task.metadata, + } + f.write(json.dumps(task_dict) + "\n") + + logger.info(f"Saved {len(tasks)} tasks to {output_path}") + + +def register_converter(dataset_name: str, converter_func: Any) -> None: + """Register a custom converter for a dataset. + + Args: + dataset_name: Dataset identifier + converter_func: Function that converts example dict to Task + + Example: + >>> def my_converter(example, index): + ... return Task(name=f"task_{index}", prompt=example["text"], ...) + >>> register_converter("my/dataset", my_converter) + """ + DATASET_CONVERTERS[dataset_name] = converter_func + logger.info(f"Registered converter for '{dataset_name}'") diff --git a/src/flow/experiments/models.py b/src/flow/experiments/models.py index 7e90de2902178e58c219b3e3c9049da563b860e0..7ddc186000faf1a56b5bcb9598cd40dcf3aaf1a4 100644 --- a/src/flow/experiments/models.py +++ b/src/flow/experiments/models.py @@ -3,6 +3,8 @@ """Core data models for the optimization framework. Defines: +- COMPACTION_STRATEGIES: Registry of compaction strategies for schema API +- DEFAULT_TOKEN_BUDGET: Default token budget (200k) for modern models - CompactionConfig: Extensible compaction strategy configuration - Agent: Framework-agnostic agent definition (what the customer brings) - Candidate: A mutated agent variant produced by optimization @@ -17,14 +19,17 @@ from __future__ import annotations from dataclasses import asdict, dataclass, field from itertools import product as itertools_product from pathlib import Path -from typing import TYPE_CHECKING, Any, Protocol, runtime_checkable +from typing import TYPE_CHECKING, Any, Literal, Protocol, runtime_checkable import yaml if TYPE_CHECKING: - from collections.abc import Awaitable, Callable + from collections.abc import AsyncIterator, Awaitable, Callable + + from flow.harness.base import Event from .evaluators.base import Evaluator + from .results import AgentOptimizationResult, EvaluationResult from .types import Task @@ -34,6 +39,89 @@ if TYPE_CHECKING: # Tool presets define common tool configurations. # Each preset maps tool names to their configuration dicts. +# ============================================================================= +# Compaction Strategy Configuration +# ============================================================================= + +# Default token budget for modern models (GPT-4o, Claude 3.5, etc.) +DEFAULT_TOKEN_BUDGET = 200_000 + +# Compaction strategies registry for schema API +# All strategies use token-based triggers (not message count) for safety +COMPACTION_STRATEGIES: dict[str, dict[str, Any]] = { + "head_tail": { + "label": "Head + Tail", + "description": "Keep head (system prompt, initial context) + tail (recent messages). Drops middle when over budget.", + "params": { + "head_ratio": { + "type": "number", + "default": 0.2, + "min": 0, + "max": 1, + "description": "Fraction of budget for head messages (0.2 = 20%)", + }, + "token_budget": { + "type": "number", + "default": DEFAULT_TOKEN_BUDGET, + "min": 1000, + "description": "Max tokens before compaction triggers", + }, + }, + }, + "sliding_window": { + "label": "Sliding Window", + "description": "Keep system message + most recent messages that fit within budget. Simple and effective.", + "params": { + "token_budget": { + "type": "number", + "default": DEFAULT_TOKEN_BUDGET, + "min": 1000, + "description": "Max tokens for context window", + }, + }, + }, + "summarization": { + "label": "Summarization", + "description": "Summarize middle messages using LLM instead of dropping them. Preserves context but adds latency.", + "params": { + "head_messages": { + "type": "number", + "default": 2, + "min": 1, + "description": "Messages to preserve at head", + }, + "tail_messages": { + "type": "number", + "default": 4, + "min": 1, + "description": "Messages to preserve at tail", + }, + "summary_max_tokens": { + "type": "number", + "default": 1000, + "min": 100, + "description": "Max tokens for the summary", + }, + "token_budget": { + "type": "number", + "default": DEFAULT_TOKEN_BUDGET, + "min": 1000, + "description": "Max tokens before compaction triggers", + }, + }, + }, + "none": { + "label": "No Compaction", + "description": "Context grows unbounded. Only use for benchmarking or very short tasks.", + "params": {}, + }, +} + + +# ============================================================================= +# Tool Configuration +# ============================================================================= + TOOL_PRESETS: dict[str, dict[str, dict[str, Any]]] = { "full": { "read_file": {}, @@ -43,9 +131,8 @@ TOOL_PRESETS: dict[str, dict[str, dict[str, Any]]] = { "glob_files": {}, "ls": {}, "grep": {}, - "bash": {"timeout": 120}, + "bash": {"timeout": 300}, "check_processes": {}, - "python_repl": {}, "think": {}, "todo_write": {}, "todo_read": {}, @@ -65,20 +152,21 @@ TOOL_PRESETS: dict[str, dict[str, dict[str, Any]]] = { "glob_files": {}, "ls": {}, "grep": {}, - "bash": {"timeout": 120}, + "bash": {"timeout": 300}, "check_processes": {}, - "python_repl": {}, "think": {}, "todo_write": {}, "todo_read": {}, "memory": {}, "skills": {}, + "web_search": {}, + "web_fetch": {}, }, "minimal": { "read_file": {}, "write_file": {}, "edit_file": {}, - "bash": {"timeout": 120}, + "bash": {"timeout": 300}, "think": {}, }, "readonly": { @@ -91,16 +179,17 @@ TOOL_PRESETS: dict[str, dict[str, dict[str, Any]]] = { } -def resolve_tools(tools: str | list[str] | dict[str, dict[str, Any]]) -> dict[str, dict[str, Any]]: +def resolve_tools(tools: str | list[str] | dict[str, dict[str, Any]] | None) -> dict[str, dict[str, Any]]: """Normalize tool specification to dict form. - Accepts three input formats: + Accepts four input formats: + - None: No tools (empty set) - str: Preset name (e.g., "standard", "minimal", "full", "readonly") - list[str]: List of tool names with default configs - dict[str, dict]: Full specification with per-tool configs Args: - tools: Tool specification in any supported format + tools: Tool specification in any supported format, or None for no tools Returns: Dict mapping tool names to their configuration dicts @@ -109,6 +198,9 @@ def resolve_tools(tools: str | list[str] | dict[str, dict[str, Any]]) -> dict[st ValueError: If preset name is unknown Example: + >>> resolve_tools(None) + {} + >>> resolve_tools("standard") {"read_file": {}, "write_file": {}, ...} @@ -118,6 +210,8 @@ def resolve_tools(tools: str | list[str] | dict[str, dict[str, Any]]) -> dict[st >>> resolve_tools({"bash": {"timeout": 60}}) {"bash": {"timeout": 60}} """ + if tools is None: + return {} if isinstance(tools, str): if tools not in TOOL_PRESETS: raise ValueError(f"Unknown tool preset: {tools}. Available: {list(TOOL_PRESETS.keys())}") @@ -148,8 +242,8 @@ class CompactionConfig: token_budget: Maximum tokens for context window (used by token-based strategies) """ - strategy: str = "head_tail" - params: dict[str, Any] = field(default_factory=lambda: {"head_size": 10, "tail_size": 40}) + strategy: str = "none" + params: dict[str, Any] = field(default_factory=dict) token_budget: int = 100_000 # ========================================================================= @@ -278,6 +372,10 @@ class CompactionConfig: return self.params.get("head_ratio", 0.2) +# Supported agent frameworks (harnesses) +Framework = Literal["maf", "miniagent", "langgraph"] + + @dataclass class Agent: """Framework-agnostic agent definition. @@ -289,10 +387,10 @@ class Agent: Attributes: name: Unique identifier for this agent - framework: Which harness to use ("maf", "langgraph", "claude") + framework: Which harness to use ("maf", "miniagent", "langgraph") description: Human-readable description instructions: System prompt / instructions (optional, uses framework default if None) - instructions_preset: Preset name for instructions ("coding", "benchmark", etc.) + instructions_preset: Preset name for instructions (default: "general") llm_config: LLM configuration with provider and model info: {"provider": "azure|openai|anthropic", "model": "gpt-4o"} If None, auto-detects from environment variables. @@ -304,13 +402,270 @@ class Agent: """ name: str - framework: str = "maf" + framework: Framework = "miniagent" description: str = "" instructions: str | None = None - instructions_preset: str | None = None # e.g., "coding", "benchmark", "research" + instructions_preset: str | None = None # e.g., "general" llm_config: dict[str, Any] | None = None # {"provider": "azure", "model": "gpt-4o"} compaction: CompactionConfig = field(default_factory=CompactionConfig) - tools: str | list[str] | dict[str, dict[str, Any]] = "standard" + tools: str | list[str] | dict[str, dict[str, Any]] | None = None + + # Set by deploy() — when set, evaluate/optimize auto-persist to DB + _id: str | None = field(default=None, repr=False, compare=False) + + @property + def id(self) -> str | None: + """Agent ID in the database, set after deploy().""" + return self._id + + @classmethod + def from_preset(cls, name: str) -> Agent: + """Create an Agent from a named preset. + + Args: + name: Preset name (e.g., "coding", "research", "document-analysis") + + Returns: + A new Agent instance with the preset's configuration + + Example: + agent = Agent.from_preset("coding") + result = await agent.evaluate(tasks="quick") + """ + from .presets import get_preset + + preset = get_preset(name) + return cls( + name=preset.agent.name, + framework=preset.agent.framework, + description=preset.agent.description, + instructions=preset.agent.instructions, + instructions_preset=preset.agent.instructions_preset, + llm_config=preset.agent.llm_config, + compaction=preset.agent.compaction, + tools=preset.agent.tools, + ) + + async def run(self, task: str, workspace: Path | None = None) -> str: + """Run the agent on a task and return the final output. + + This is the simplest way to use an agent — give it a task, get a result. + + Args: + task: The task/prompt to execute + workspace: Optional workspace directory (creates temp dir if None) + + Returns: + The agent's final text output + + Example: + agent = Agent(name="coding-agent", tools="standard") + output = await agent.run("Create hello.py that prints Hello World") + print(output) + """ + output_parts: list[str] = [] + async for event in self.run_stream(task, workspace=workspace): + if event.type.value == "text_delta": + output_parts.append(event.content) + return "".join(output_parts) + + async def run_stream( + self, task: str, *, workspace: Path | None = None + ) -> AsyncIterator[Event]: + """Run the agent on a task with streaming events. + + Yields real-time events as the agent works — text chunks, tool calls, + tool results, and completion. Use this for live output in notebooks or CLIs. + + Args: + task: The task/prompt to execute + workspace: Optional workspace directory (creates temp dir if None) + + Yields: + Event objects (text_delta, tool_call_start, tool_result, done, etc.) + + Example: + agent = Agent(name="coding-agent", tools="standard") + async for event in agent.run_stream("Create hello.py"): + if event.type.value == "text_delta": + print(event.content, end="", flush=True) + """ + import tempfile + + # Lazy imports to avoid circular deps and keep Agent lightweight + from flow.harness import create_harness + from flow.harness.registry import ensure_harnesses_registered + + ensure_harnesses_registered() + + if workspace is None: + workspace = Path(tempfile.mkdtemp(prefix="flow_run_")) + + harness = create_harness(self, workspace) + try: + async for event in harness.run_stream(task): + yield event + finally: + await harness.close() + + async def deploy(self) -> str: + """Register this agent in the Flow database. + + Creates an AgentConfig row in the local SQLite DB (~/.flow/flow_ui.db). + No running server required — this is a pure DB write. After deploying, + all evaluate() and optimize() calls auto-persist results to the DB. + + Run ``flow serve`` separately to browse results in the UI. + + Returns: + The agent ID (UUID string) + + Example: + agent = Agent(name="coding-agent", tools="standard") + agent_id = await agent.deploy() + # Results now auto-persist + result = await agent.evaluate(tasks="quick") + # Run `flow serve` to view at http://localhost:7860/agents/{agent_id} + """ + try: + from flow.ui.services.persistence_adapter import PersistenceAdapter + except ImportError as e: + raise ImportError( + "DB dependencies not available. Install flow with UI support " + "to use deploy(): pip install flow[ui] or uv sync" + ) from e + + adapter = PersistenceAdapter() + self._id = await adapter.deploy_agent(self) + return self._id + + async def evaluate( + self, + tasks: str | list[Task] | Path = "quick", + *, + parallel: int = 4, + use_llm_eval: bool = True, + quiet: bool = False, + ) -> EvaluationResult: + """Evaluate this agent on a set of tasks. + + If the agent has been deployed (via deploy()), results are + automatically persisted to the database. + + Args: + tasks: Task specification - suite name (str like "quick", "coding"), + list of Task objects, or Path to JSONL file + parallel: Number of concurrent task executions + use_llm_eval: Whether to use LLM-as-Judge for scoring + quiet: Suppress verbose output + + Returns: + EvaluationResult with score, tokens, pass_rate, etc. + + Example: + agent = Agent(name="my-agent", tools="standard") + result = await agent.evaluate(tasks="quick") + print(f"Score: {result.score:.2f}, Pass rate: {result.pass_rate:.0%}") + """ + from .agent_api import _evaluate_agent_impl + + return await _evaluate_agent_impl( + self, tasks, parallel, use_llm_eval, quiet, agent_id=self._id + ) + + async def optimize( + self, + tasks: str | list[Task] | Path = "quick", + *, + strategy: str | list[str] | None = None, + variations: dict[str, list[Any]] | None = None, + parallel: int = 4, + budget: int = 50, + use_llm_eval: bool = True, + quiet: bool = False, + ) -> AgentOptimizationResult: + """Optimize this agent's configuration. + + Supports two modes: + - **Grid search** (default): Exhaustive search over parameter combinations + - **Active strategies**: Iterative evaluate-reflect-adjust optimization + + If the agent has been deployed (via deploy()), results are + automatically persisted to the database. + + Args: + tasks: Task specification - suite name (str), list of Tasks, or Path + strategy: Optimization strategy to use: + - None or "grid": Grid search over variations (default) + - "tools": Iteratively discover optimal tool configuration + - "instructions": Iteratively rewrite instructions from failures + - list: Run multiple strategies sequentially, e.g. + ["instructions", "tools"] optimizes instructions first, + then tools starting from the improved agent + variations: Custom grid search variations (only used with grid strategy) + parallel: Number of concurrent experiments + budget: Maximum number of candidates to test + use_llm_eval: Whether to use LLM-as-Judge for scoring + quiet: Suppress verbose output + + Returns: + AgentOptimizationResult with baseline, best, and improvement metrics + + Example: + agent = Agent(name="my-agent", tools="standard") + + # Grid search (default) + result = await agent.optimize(tasks="quick") + + # Active: discover optimal tools + result = await agent.optimize(tasks="quick", strategy="tools") + + # Active: improve instructions + result = await agent.optimize(tasks="quick", strategy="instructions") + + # Pipeline: instructions first, then tools + result = await agent.optimize( + tasks="quick", strategy=["instructions", "tools"] + ) + + print(f"Best score: {result.best.score:.2f}") + optimized = result.best_agent + """ + from .agent_api import _optimize_agent_impl + + return await _optimize_agent_impl( + self, tasks, variations, parallel, budget, use_llm_eval, quiet, + agent_id=self._id, + strategy=strategy, + ) + + +@dataclass +class StrategyIteration: + """One iteration of an active strategy's optimization loop. + + Tracks what was tried, how it scored, and why the change was made. + Active strategies accumulate these to provide a full audit trail. + + Attributes: + iteration: Iteration number (0 = baseline) + instructions_preview: First 200 chars of instructions used + full_instructions: Complete instructions text for this iteration + avg_score: Average score across tasks for this iteration + pass_rate: Fraction of tasks that passed + failures_count: Number of tasks that failed + change_description: What was changed (e.g., "Added bash timeout instructions") + change_rationale: Why the change was made (e.g., "3/5 tasks failed due to hanging bash commands") + """ + + iteration: int + instructions_preview: str + avg_score: float + pass_rate: float + failures_count: int + change_description: str = "" + change_rationale: str = "" + full_instructions: str = "" @dataclass @@ -325,11 +680,15 @@ class Candidate: agent: The mutated agent configuration mutations: Dict describing what was changed from the base rationale: Human-readable explanation of why this candidate exists + optimization_history: Audit trail from active optimization strategies. + Each entry records one iteration of the optimization loop with + scores, failure counts, and descriptions of what changed and why. """ agent: Agent mutations: dict[str, Any] = field(default_factory=dict) rationale: str = "" + optimization_history: list[StrategyIteration] = field(default_factory=list) @dataclass @@ -345,47 +704,93 @@ class ExperimentResult: traces: dict[str, Any] = field(default_factory=dict) +@runtime_checkable +class ExperimentRunner(Protocol): + """Protocol for evaluating candidates against tasks. + + This is the interface that active strategies use to test candidate + configurations. The FlowOptimizer implements this protocol, providing + strategies with access to the full execution pipeline (harness creation, + agent execution, trace collection, LLM evaluation, metrics extraction) + without exposing internal details. + + Passive strategies (GridSearchStrategy, etc.) ignore this entirely. + Active strategies call evaluate() in a loop to iteratively refine + candidates based on real execution results. + + The evaluate() method returns a CandidateSummary (from optimizer.py) + which contains: + - avg_score, pass_rate: Aggregate performance metrics + - task_results: list[TaskResult] — per-task details including: + - eval_reasoning: Why the evaluator scored it this way + - eval_score, eval_passed: Score and pass/fail status + - criteria_results: Per-criterion breakdown + - run_result.output: What the agent produced + - run_result.trace: Full OTel execution trace + - metrics: Token counts, tool usage, duration + """ + + async def evaluate( + self, + candidate: Candidate, + tasks: list[Task], + ) -> Any: + """Evaluate a candidate on a set of tasks. + + Args: + candidate: The candidate to evaluate + tasks: Tasks to run the candidate on + + Returns: + CandidateSummary with aggregated scores and per-task details. + Typed as Any to avoid circular imports — the actual return type + is flow.experiments.optimizer.CandidateSummary. + """ + ... + + @runtime_checkable class CandidateStrategy(Protocol): """Protocol for generating candidate variants from a base agent. Implementations can be: - - Simple (single-shot): GridSearchStrategy ignores optional params - - Complex (iterative): Runs internal experiments, checks convergence, - distills failures, etc. using the provided callbacks + - Passive (single-shot): GridSearchStrategy ignores optional params + - Active (iterative): Uses runner to evaluate candidates, inspect failures, + and iteratively refine configurations based on real execution results - All logic is internal to the strategy - the caller just calls generate() + All logic is internal to the strategy — the caller just calls generate() and receives the final list of candidates. Examples: - GridSearchStrategy: Exhaustive grid over parameter combinations - - (Future) AdaptivePromptOptimizer: Iteratively improves prompts from failures + - (Future) InstructionOptimizer: Iteratively improves instructions from failures - (Future) BayesianStrategy: Bayesian optimization over parameters """ - def generate( + async def generate( self, base: Agent, budget: int, *, tasks: list[Task] | None = None, - evaluator: Evaluator | None = None, - run_experiment: Callable[[Candidate, Task], Awaitable[ExperimentResult]] | None = None, + runner: ExperimentRunner | None = None, ) -> list[Candidate]: """Generate candidate variants from a base agent. Args: base: The base agent to optimize budget: Maximum number of candidates to return - tasks: Optional tasks for strategies that run internal experiments - evaluator: Optional evaluator for strategies that need scoring - run_experiment: Optional async callback to execute a candidate on a task. - Signature: async (candidate, task) -> ExperimentResult + tasks: Optional tasks for active strategies that run internal experiments + runner: Optional experiment runner for active strategies. + Active strategies call runner.evaluate(candidate, tasks) + to test candidates and use results to guide optimization. + Passive strategies ignore this parameter. Returns: List of Candidate objects (at most `budget` items). For iterative strategies, returns the final/best candidates after - internal optimization loops complete. + internal optimization loops complete. Candidates may include + optimization_history with per-iteration audit trail. """ ... @@ -419,23 +824,22 @@ class GridSearchStrategy: """ self.variations = variations - def generate( + async def generate( self, base: Agent, budget: int, *, tasks: list[Task] | None = None, - evaluator: Evaluator | None = None, - run_experiment: Callable[[Candidate, Task], Awaitable[ExperimentResult]] | None = None, + runner: ExperimentRunner | None = None, ) -> list[Candidate]: """Generate all grid combinations up to budget. - Note: tasks, evaluator, and run_experiment are accepted for protocol - compatibility but ignored - GridSearchStrategy is a simple single-shot - strategy that doesn't run experiments internally. + Note: tasks and runner are accepted for protocol compatibility but + ignored — GridSearchStrategy is a passive strategy that doesn't + run experiments internally. """ # Delete unused params to satisfy linters - del tasks, evaluator, run_experiment + del tasks, runner if not self.variations: return [Candidate(agent=base, mutations={}, rationale="baseline")] @@ -690,6 +1094,38 @@ def _extract_metrics( # ============================================================================= +@dataclass +class LiteralVariation: + """A literal/static variation value. + + Used for predefined values like tool presets, compaction configs, etc. + """ + + value: Any + + +@dataclass +class StrategyVariation: + """A strategy that generates variation values dynamically. + + Used for active optimization strategies like GEPA (instructions) + or agentic tool selection. + + Attributes: + strategy: Strategy name (e.g., "gepa", "agentic") + max_candidates: Number of candidates this strategy will produce + config: Strategy-specific configuration + """ + + strategy: str + max_candidates: int = 1 + config: dict[str, Any] = field(default_factory=dict) + + +# Union type for variation items +VariationItem = LiteralVariation | StrategyVariation + + @dataclass class Experiment: """Experiment configuration for optimization. @@ -699,53 +1135,173 @@ class Experiment: - Experiment YAML: How to test it (variations, tasks, evaluation settings) Attributes: - base_agent: Path to base agent YAML file + base_agent: Path to base agent YAML file (required) suite: Built-in task suite name (e.g., "coding", "quick") tasks: Path to custom tasks JSONL file (alternative to suite) - variations: Dict of parameter variations for grid search + variations: Dict mapping dimension names to lists of VariationItems parallel: Max concurrent experiments - budget: Maximum candidates to generate + budget: Maximum candidates to generate (safety limit) use_llm_eval: Whether to use LLM-as-Judge evaluation Example YAML: ```yaml - base_agent: examples/miniagent_base.yaml + base_agent: agents/coder.yaml suite: coding variations: - compaction: - - strategy: none - - strategy: head_tail - params: { head_size: 10, tail_size: 40 } - - strategy: sliding_window - token_budget: 50000 - - strategy: summarization - token_budget: 50000 + instructions: + # Literal values + - "You are a helpful coding assistant" + - file: prompts/expert.md + # Strategy (active optimization) + - strategy: gepa + max_candidates: 3 + config: + reflection_lm: gpt-4o tools: - minimal - standard - - [read_file, write_file, bash, memory] + - strategy: agentic + max_candidates: 2 + + compaction: + - strategy: none + - strategy: sliding_window + token_budget: 50000 - parallel: 4 - budget: 20 + parallel: 8 + budget: 100 use_llm_eval: true ``` """ - base_agent: str | None = None + base_agent: str suite: str | None = None tasks: str | None = None - variations: dict[str, list[Any]] = field(default_factory=dict) + variations: dict[str, list[VariationItem]] = field(default_factory=dict) parallel: int = 4 budget: int = 100 use_llm_eval: bool = True +def compute_max_experiments(variations: dict[str, list[VariationItem]]) -> int: + """Compute maximum number of experiments from variations. + + Each dimension contributes its count (literals + strategy max_candidates), + and total is the Cartesian product. + + Args: + variations: Parsed variations dict + + Returns: + Maximum number of experiments + """ + if not variations: + return 1 + + import math + + counts = [] + for items in variations.values(): + dim_count = 0 + for item in items: + if isinstance(item, StrategyVariation): + dim_count += item.max_candidates + else: + dim_count += 1 + counts.append(max(dim_count, 1)) + + return math.prod(counts) + + +def _parse_literal_value(dimension: str, value: Any) -> Any: + """Parse a literal value for a specific dimension. + + Handles special cases like compaction configs and file references. + + Args: + dimension: The dimension name (e.g., "compaction", "tools") + value: The raw value from YAML + + Returns: + Parsed value appropriate for the dimension + """ + # Handle file references + if isinstance(value, dict) and "file" in value: + file_path = Path(value["file"]) + if file_path.exists(): + return file_path.read_text() + # If relative path, caller should resolve it + return value + + # Handle compaction dimension + if dimension == "compaction": + if isinstance(value, dict): + # Dict with strategy key is a CompactionConfig + return CompactionConfig(**value) + elif isinstance(value, str): + # Shorthand: "none", "head_tail", etc. + if value == "none": + return CompactionConfig.none() + elif value == "head_tail": + return CompactionConfig.head_tail() + elif value == "sliding_window": + return CompactionConfig.sliding_window() + elif value == "summarization": + return CompactionConfig.summarization() + else: + raise ValueError(f"Unknown compaction shorthand: {value}") + + # All other values pass through as-is + return value + + +# Known compaction strategy names (these are NOT optimization strategies) +_COMPACTION_STRATEGY_NAMES = {"none", "head_tail", "sliding_window", "summarization", "last_n", "head_tail_tokens"} + + +def _is_strategy_variation(item: Any) -> bool: + """Check if an item is a StrategyVariation (optimization strategy). + + Distinguishes between: + - StrategyVariation: {"strategy": "gepa", "max_candidates": 3, "config": {...}} + - Compaction literal: {"strategy": "sliding_window", "token_budget": 50000} + + The key difference: + - Optimization strategies have max_candidates or config keys + - Compaction configs have strategy names like "none", "sliding_window", etc. + + Args: + item: The raw item from YAML + + Returns: + True if this is a StrategyVariation, False if literal + """ + if not isinstance(item, dict): + return False + + if "strategy" not in item: + return False + + strategy_name = item["strategy"] + + # If it has max_candidates or config, it's definitely an optimization strategy + if "max_candidates" in item or "config" in item: + return True + + # If the strategy name is a known compaction strategy, it's a literal + if strategy_name in _COMPACTION_STRATEGY_NAMES: + return False + + # Otherwise assume it's an optimization strategy (will fail at runtime if invalid) + return True + + def load_experiment(path: Path) -> Experiment: """Load an Experiment from a YAML file. - Handles conversion of compaction variations from dict to CompactionConfig. + Parses variations into VariationItem objects (LiteralVariation or StrategyVariation). Args: path: Path to the experiment YAML file @@ -762,38 +1318,34 @@ def load_experiment(path: Path) -> Experiment: data = yaml.safe_load(path.read_text()) - # Parse variations - convert compaction dicts to CompactionConfig - variations: dict[str, list[Any]] = {} + # Validate required fields + if "base_agent" not in data: + raise ValueError("Experiment YAML must specify 'base_agent'") + + # Parse variations into VariationItem objects + variations: dict[str, list[VariationItem]] = {} raw_variations = data.get("variations", {}) - for key, values in raw_variations.items(): - if key == "compaction": - # Convert each compaction dict to CompactionConfig - parsed_compactions = [] - for v in values: - if isinstance(v, dict): - parsed_compactions.append(CompactionConfig(**v)) - elif isinstance(v, str): - # Handle shorthand: "none", "head_tail", etc. - if v == "none": - parsed_compactions.append(CompactionConfig.none()) - elif v == "head_tail": - parsed_compactions.append(CompactionConfig.head_tail()) - elif v == "sliding_window": - parsed_compactions.append(CompactionConfig.sliding_window()) - elif v == "summarization": - parsed_compactions.append(CompactionConfig.summarization()) - else: - raise ValueError(f"Unknown compaction shorthand: {v}") - else: - parsed_compactions.append(v) - variations["compaction"] = parsed_compactions - else: - # Other variations pass through as-is - variations[key] = values + for dimension, items in raw_variations.items(): + parsed_items: list[VariationItem] = [] + + for item in items: + if _is_strategy_variation(item): + # This is a StrategyVariation (optimization strategy like "gepa") + parsed_items.append(StrategyVariation( + strategy=item["strategy"], + max_candidates=item.get("max_candidates", 1), + config=item.get("config", {}), + )) + else: + # This is a LiteralVariation + parsed_value = _parse_literal_value(dimension, item) + parsed_items.append(LiteralVariation(value=parsed_value)) + + variations[dimension] = parsed_items return Experiment( - base_agent=data.get("base_agent"), + base_agent=data["base_agent"], suite=data.get("suite"), tasks=data.get("tasks"), variations=variations, diff --git a/src/flow/experiments/optimizer.py b/src/flow/experiments/optimizer.py index d197a66551404b20e4e09a0643dd4f3872931dad..501cbc58ab4724095d9e9c730175845ed8ec4d0c 100644 --- a/src/flow/experiments/optimizer.py +++ b/src/flow/experiments/optimizer.py @@ -24,11 +24,13 @@ from .ablation import compute_pareto_frontier from .evaluators import LLMEvaluator from .metrics import TraceMetrics, extract_metrics from .models import ( + Agent, Candidate, export_optimization_results, ) from .runner import FlowExperimentRunner, setup_tracing -from .types import RunResult, Task, load_tasks_from_jsonl as _load_tasks_impl +from .types import RunResult, Task +from .types import load_tasks_from_jsonl as _load_tasks_impl logger = logging.getLogger(__name__) @@ -45,6 +47,7 @@ class TaskResult: eval_passed: bool eval_reasoning: str criteria_results: list[dict[str, Any]] = field(default_factory=list) # Per-criterion scores + eval_reasoning_score: float = 0.0 # Partial credit for correct methodology @dataclass @@ -57,6 +60,7 @@ class CandidateSummary: # Aggregated metrics avg_score: float = 0.0 + avg_reasoning_score: float = 0.0 avg_tokens: float = 0.0 avg_duration: float = 0.0 pass_rate: float = 0.0 @@ -69,12 +73,17 @@ class CandidateSummary: def to_dict(self) -> dict[str, Any]: """Convert to dictionary for serialization.""" + # Extract candidate_id from mutations if available (set by GEPA adapter) + candidate_id = self.candidate.mutations.get("_candidate_id", None) + return { "name": self.name, + "candidate_id": candidate_id, "agent": asdict(self.candidate.agent), "mutations": self.candidate.mutations, "rationale": self.candidate.rationale, "avg_score": self.avg_score, + "avg_reasoning_score": self.avg_reasoning_score, "avg_tokens": self.avg_tokens, "avg_duration": self.avg_duration, "pass_rate": self.pass_rate, @@ -82,15 +91,22 @@ class CandidateSummary: "task_count": self.task_count, "pareto_rank": self.pareto_rank, "is_pareto_optimal": self.is_pareto_optimal, - # Include per-task results with eval reasoning + # Include per-task results with full agent output and trace "task_results": [ { "task_name": tr.task_name, + "task_prompt": tr.run_result.task.prompt, + "agent_output": tr.run_result.output, "eval_score": tr.eval_score, + "eval_reasoning_score": tr.eval_reasoning_score, "eval_passed": tr.eval_passed, "eval_reasoning": tr.eval_reasoning, + "criteria_results": tr.criteria_results, "tokens": tr.metrics.total_tokens, "duration": tr.run_result.duration_seconds, + "files_created": tr.run_result.files_created, + "tool_results": tr.run_result.tool_results, + "trace": tr.run_result.trace, } for tr in self.task_results ], @@ -149,7 +165,7 @@ class FlowOptimizer: }) optimizer = FlowOptimizer(parallel=4) base = Agent(name="my_agent") - candidates = strategy.generate(base, budget=10) + candidates = await strategy.generate(base, budget=10) result = await optimizer.optimize(candidates, tasks) print(f"Best: {result.rank_by_score[0]}") """ @@ -164,11 +180,16 @@ class FlowOptimizer: self.use_llm_evaluator = use_llm_evaluator self.output_dir = output_dir or Path.home() / ".flow" / "optimizations" + # Internal state set during optimize() for use by evaluate() + self._evaluator: LLMEvaluator | None = None + self._run_dir: Path | None = None + async def optimize( self, candidates: list[Candidate], tasks: list[Task], progress_callback: Callable[[int, int, str, str], None] | None = None, + run_dir: Path | None = None, ) -> OptimizationResult: """Run optimization across all candidates and tasks. @@ -176,13 +197,15 @@ class FlowOptimizer: candidates: Candidates to test tasks: Tasks to run each candidate on progress_callback: Optional callback(completed, total, candidate_name, task_name) + run_dir: Optional fixed directory for this run. If None, creates timestamped subdir. Returns: OptimizationResult with rankings and exported agents """ start_time = datetime.now() timestamp = start_time.strftime("%Y%m%d_%H%M%S") - run_dir = self.output_dir / timestamp + if run_dir is None: + run_dir = self.output_dir / timestamp run_dir.mkdir(parents=True, exist_ok=True) setup_tracing("flow-optimizer") @@ -202,6 +225,127 @@ class FlowOptimizer: if self.use_llm_evaluator: evaluator = self._create_evaluator() + # Store for use by evaluate() (ExperimentRunner protocol) + self._evaluator = evaluator + self._run_dir = run_dir + + task_results = await self._run_parallel( + candidates, tasks, run_dir, evaluator, progress_callback + ) + + summaries = self._aggregate_results(task_results, candidates) + pareto_names = self._compute_pareto(summaries) + + rank_by_score = sorted(summaries, key=lambda s: s.avg_score, reverse=True) + rank_by_tokens = sorted(summaries, key=lambda s: s.avg_tokens) + rank_by_efficiency = sorted( + summaries, + key=lambda s: s.avg_score / max(s.avg_tokens, 1), + reverse=True, + ) + + summary_dicts = [s.to_dict() for s in summaries] + exported = export_optimization_results( + summary_dicts, pareto_names, run_dir, timestamp + ) + + end_time = datetime.now() + + result = OptimizationResult( + timestamp=timestamp, + output_dir=run_dir, + summaries=summaries, + pareto_frontier=pareto_names, + exported_agents=exported, + rank_by_score=[s.name for s in rank_by_score], + rank_by_tokens=[s.name for s in rank_by_tokens], + rank_by_efficiency=[s.name for s in rank_by_efficiency], + total_experiments=len(task_results), + total_duration_seconds=(end_time - start_time).total_seconds(), + ) + + self._save_results(result, run_dir) + self._print_summary(result) + + return result + + async def optimize_with_strategy( + self, + strategy: Any, # CandidateStrategy + base: Agent, + tasks: list[Task], + budget: int = 50, + progress_callback: Callable[[int, int, str, str], None] | None = None, + run_dir: Path | None = None, + ) -> OptimizationResult: + """Run optimization using a CandidateStrategy. + + This is the entry point for strategy-driven optimization. It: + 1. Sets up infrastructure (evaluator, tracing, output dir) + 2. Passes self as ExperimentRunner to the strategy + 3. Runs the strategy's generate() to get candidates + 4. Does a final evaluation of returned candidates + 5. Performs Pareto analysis and exports results + + For active strategies, the strategy will call self.evaluate() + during generate() to test candidates iteratively. + + Args: + strategy: A CandidateStrategy implementation + base: Base agent to optimize + tasks: Tasks to evaluate candidates on + budget: Maximum candidates for the strategy to produce + progress_callback: Optional callback(completed, total, candidate, task) + run_dir: Optional fixed output directory + + Returns: + OptimizationResult with rankings and exported agents + """ + start_time = datetime.now() + timestamp = start_time.strftime("%Y%m%d_%H%M%S") + if run_dir is None: + run_dir = self.output_dir / timestamp + run_dir.mkdir(parents=True, exist_ok=True) + + setup_tracing("flow-optimizer") + + # Set up evaluator and store state for evaluate() + evaluator = None + if self.use_llm_evaluator: + evaluator = self._create_evaluator() + self._evaluator = evaluator + self._run_dir = run_dir + + print("=" * 70) + print(" FLOW OPTIMIZER (Strategy Mode)") + print("=" * 70) + print(f" Strategy: {type(strategy).__name__}") + print(f" Base Agent: {base.name}") + print(f" Tasks: {len(tasks)}") + print(f" Budget: {budget}") + print(f" Parallel: {self.parallel}") + print(f" Output: {run_dir}") + print("=" * 70) + + # Pass self as runner — FlowOptimizer implements the ExperimentRunner + # protocol via the evaluate() method above + candidates = await strategy.generate( + base=base, + budget=budget, + tasks=tasks, + runner=self, + ) + + if not candidates: + logger.warning("Strategy produced no candidates") + candidates = [Candidate(agent=base, mutations={}, rationale="baseline (strategy produced none)")] + + print(f"\nStrategy produced {len(candidates)} candidates. Running final evaluation...") + + # Save config + self._save_config(candidates, tasks, run_dir) + + # Final evaluation of all candidates across all tasks task_results = await self._run_parallel( candidates, tasks, run_dir, evaluator, progress_callback ) @@ -266,10 +410,11 @@ class FlowOptimizer: async with lock: completed += 1 - status = "✓" if result.eval_passed else "✗" + status = "PASS" if result.eval_passed else "FAIL" print( f" [{completed}/{total}] {candidate.agent.name}/{task.name}: " f"{status} score={result.eval_score:.2f} " + f"reasoning={result.eval_reasoning_score:.2f} " f"tokens={result.metrics.total_tokens:,}" ) if progress_callback: @@ -289,6 +434,43 @@ class FlowOptimizer: return valid_results + async def evaluate( + self, + candidate: Candidate, + tasks: list[Task], + ) -> CandidateSummary: + """Evaluate a candidate on a set of tasks. + + Implements the ExperimentRunner protocol. Active strategies call this + to test candidates during their optimization loop, reusing the full + execution pipeline (harness, tracing, LLM evaluation, metrics). + + This method requires that optimize() has been called first (or that + _evaluator and _run_dir have been set up), since it reuses the + optimizer's evaluator and output directory. + + Args: + candidate: The candidate to evaluate + tasks: Tasks to run the candidate on + + Returns: + CandidateSummary with aggregated scores and per-task details + """ + if self._run_dir is None: + raise RuntimeError( + "evaluate() requires the optimizer to be initialized. " + "Call optimize() first, or use optimize_with_strategy() which handles setup." + ) + + task_results = await self._run_parallel( + [candidate], tasks, self._run_dir, self._evaluator, None + ) + summaries = self._aggregate_results(task_results, [candidate]) + if not summaries: + # Return empty summary if all experiments failed + return CandidateSummary(name=candidate.agent.name, candidate=candidate) + return summaries[0] + async def _run_single( self, candidate: Candidate, @@ -298,9 +480,13 @@ class FlowOptimizer: ) -> TaskResult: """Run a single candidate-task experiment.""" # Import harness modules to register them, then use registry - import flow.harness.maf # noqa: F401 + import flow.harness.maf as _maf + + _ = _maf try: - import flow.harness.miniagent # noqa: F401 + import flow.harness.miniagent as _miniagent + + _ = _miniagent except ImportError: pass # miniagent harness is optional from flow.harness import create_harness @@ -313,16 +499,24 @@ class FlowOptimizer: metrics = extract_metrics(run_result.trace) criteria_results: list[dict[str, Any]] = [] + eval_reasoning_score = 0.0 if evaluator: - eval_result = await evaluator.evaluate(run_result) + if isinstance(evaluator, LLMEvaluator): + eval_result = await evaluator.evaluate( + run_result, instructions=candidate.agent.instructions + ) + else: + eval_result = await evaluator.evaluate(run_result) eval_score = eval_result.score eval_passed = eval_result.passed eval_reasoning = eval_result.reasoning + eval_reasoning_score = eval_result.reasoning_score # Convert criteria results to dicts for serialization criteria_results = [ { "name": cr.name, "score": cr.score, + "reasoning_score": cr.reasoning_score, "passed": cr.passed, "reasoning": cr.reasoning, } @@ -342,6 +536,7 @@ class FlowOptimizer: eval_passed=eval_passed, eval_reasoning=eval_reasoning, criteria_results=criteria_results, + eval_reasoning_score=eval_reasoning_score, ) finally: await harness.close() @@ -370,6 +565,7 @@ class FlowOptimizer: candidate=candidate, task_results=results, avg_score=sum(r.eval_score for r in results) / len(results), + avg_reasoning_score=sum(r.eval_reasoning_score for r in results) / len(results), avg_tokens=sum(r.metrics.total_tokens for r in results) / len(results), avg_duration=sum(r.run_result.duration_seconds for r in results) / len(results), pass_rate=sum(1 for r in results if r.eval_passed) / len(results), @@ -425,7 +621,7 @@ class FlowOptimizer: logger.info("Creating AsyncAzureOpenAI client for evaluator") client = AsyncAzureOpenAI( api_key=api_key, - api_version="2024-02-15-preview", + api_version="2024-08-01-preview", # Required for json_schema response_format azure_endpoint=endpoint, ) @@ -480,13 +676,14 @@ class FlowOptimizer: print(" OPTIMIZATION RESULTS") print("=" * 70) - print(f"\n{'Candidate':<30} | {'Score':>8} | {'Tokens':>10} | {'Pareto':>8}") - print("-" * 65) + print(f"\n{'Candidate':<30} | {'Score':>8} | {'Reason':>8} | {'Tokens':>10} | {'Pareto':>8}") + print("-" * 75) for summary in sorted(result.summaries, key=lambda s: s.avg_score, reverse=True): - pareto = "★" if summary.is_pareto_optimal else "" + pareto = "*" if summary.is_pareto_optimal else "" print( f"{summary.name:<30} | {summary.avg_score:>8.2f} | " + f"{summary.avg_reasoning_score:>8.2f} | " f"{summary.avg_tokens:>10,.0f} | {pareto:>8}" ) @@ -510,3 +707,64 @@ def load_tasks_from_jsonl(path: Path) -> list[Task]: List of Task objects """ return _load_tasks_impl(path) + + +async def evaluate_agent( + agent: Agent, + tasks: list[Task], + *, + parallel: int = 4, + use_llm_evaluator: bool = True, + output_dir: Path | None = None, +) -> CandidateSummary: + """Evaluate a single agent on a set of tasks. + + This is useful for: + - Getting baseline performance before optimization + - Testing a specific agent configuration + - Validating an exported/promoted agent + + Example: + from flow.experiments import Agent, evaluate_agent, get_task_suite + + agent = Agent(name="my-agent", instructions="You are helpful.") + tasks = get_task_suite("coding") + + result = await evaluate_agent(agent, tasks) + print(f"Score: {result.avg_score:.2f}") + print(f"Pass rate: {result.pass_rate:.0%}") + print(f"Avg tokens: {result.avg_tokens:,.0f}") + + Args: + agent: The agent to evaluate + tasks: List of tasks to run the agent on + parallel: Number of concurrent task executions (default: 4) + use_llm_evaluator: Whether to use LLM-as-Judge for scoring (default: True) + output_dir: Optional directory for results (default: ~/.flow/evaluations) + + Returns: + CandidateSummary with aggregated metrics: + - avg_score: Mean evaluation score across tasks + - pass_rate: Fraction of tasks that passed + - avg_tokens: Mean token usage per task + - avg_duration: Mean execution time per task + - task_results: Per-task breakdown with scores and reasoning + """ + # Wrap agent in a candidate for the optimizer + candidate = Candidate(agent=agent, mutations={}, rationale="baseline evaluation") + + # Use a separate output directory for evaluations + eval_output_dir = output_dir or Path.home() / ".flow" / "evaluations" + + optimizer = FlowOptimizer( + parallel=parallel, + use_llm_evaluator=use_llm_evaluator, + output_dir=eval_output_dir, + ) + + result = await optimizer.optimize([candidate], tasks) + + if not result.summaries: + raise RuntimeError("Evaluation produced no results") + + return result.summaries[0] diff --git a/src/flow/experiments/presets.py b/src/flow/experiments/presets.py new file mode 100644 index 0000000000000000000000000000000000000000..43043c65d8f3d19040dbea97271ee1848a169e5d --- /dev/null +++ b/src/flow/experiments/presets.py @@ -0,0 +1,123 @@ +# Copyright (c) Microsoft. All rights reserved. +"""Agent presets — pre-configured agent bundles for common use cases. + +Presets are the single source of truth for agent templates. They are: +- Defined here in Python +- Served to the UI via the /api/schema/agent endpoint +- Used in code via Agent.from_preset("coding") + +Each preset bundles a full Agent configuration with metadata +(label, description, suggested datasets, tags) so users can +get started quickly without configuring every field. +""" + +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import TYPE_CHECKING + +from .models import Agent, CompactionConfig + +if TYPE_CHECKING: + pass + + +@dataclass +class AgentPreset: + """A pre-configured agent bundle for a specific use case. + + Attributes: + name: Machine identifier (e.g., "coding", "research") + label: Human-readable name (e.g., "Coding Agent") + description: What this preset is optimized for + agent: Fully configured Agent instance + suggested_datasets: Task suite names to evaluate this preset + tags: Categorization tags for UI display + """ + + name: str + label: str + description: str + agent: Agent + suggested_datasets: list[str] = field(default_factory=list) + tags: list[str] = field(default_factory=list) + + +# ============================================================================= +# Preset Registry +# ============================================================================= + +AGENT_PRESETS: dict[str, AgentPreset] = { + "coding": AgentPreset( + name="coding", + label="Coding Agent", + description="Writes, debugs, and refactors code. Reads and edits files, " + "runs shell commands, and tracks progress with todos.", + agent=Agent( + name="coding-agent", + framework="miniagent", + instructions_preset="general", + compaction=CompactionConfig.none(), + tools="standard", + ), + suggested_datasets=["quick", "coding"], + tags=["code", "files", "debugging"], + ), + "research": AgentPreset( + name="research", + label="Research Agent", + description="Answers factual questions using web search, fetches and reads " + "web pages, and executes code for calculations. Verifies claims from sources.", + agent=Agent( + name="research-agent", + framework="miniagent", + instructions_preset="general", + compaction=CompactionConfig.none(), + tools="standard", + ), + suggested_datasets=["quick"], + tags=["web", "search", "facts"], + ), + "document-analysis": AgentPreset( + name="document-analysis", + label="Document Analysis Agent", + description="Processes and analyzes documents including PDFs, Word docs, " + "spreadsheets, and presentations. Uses specialized skills for document formats.", + agent=Agent( + name="document-analysis-agent", + framework="miniagent", + instructions_preset="general", + compaction=CompactionConfig.none(), + tools="full", + ), + suggested_datasets=["quick"], + tags=["documents", "analysis", "skills"], + ), +} + + +def get_preset(name: str) -> AgentPreset: + """Get an agent preset by name. + + Args: + name: Preset identifier (e.g., "coding", "research", "document-analysis") + + Returns: + The AgentPreset + + Raises: + ValueError: If preset name is not found + """ + if name not in AGENT_PRESETS: + available = ", ".join(AGENT_PRESETS.keys()) + raise ValueError(f"Unknown preset: {name!r}. Available: {available}") + return AGENT_PRESETS[name] + + +def get_all_presets() -> dict[str, AgentPreset]: + """Get all available agent presets. + + Returns: + Dict mapping preset names to AgentPreset instances + """ + return dict(AGENT_PRESETS) diff --git a/src/flow/experiments/results.py b/src/flow/experiments/results.py new file mode 100644 index 0000000000000000000000000000000000000000..22ab1661cdba24b35085a70d3cd2ac9ce8c6bc9c --- /dev/null +++ b/src/flow/experiments/results.py @@ -0,0 +1,118 @@ +# Copyright (c) Microsoft. All rights reserved. + +"""Simple result types for the Agent API. + +These types provide a clean, user-friendly interface for +evaluation and optimization results. +""" + +from __future__ import annotations + +from dataclasses import dataclass, field +from pathlib import Path +from typing import TYPE_CHECKING, Any + +if TYPE_CHECKING: + from .optimizer import CandidateSummary + + +@dataclass +class EvaluationResult: + """Result from evaluating an agent on tasks. + + Attributes: + score: Average evaluation score (0.0 to 1.0) + tokens: Total tokens used across all tasks + pass_rate: Fraction of tasks that passed (0.0 to 1.0) + duration: Total duration in seconds + task_count: Number of tasks evaluated + + Example: + result = await agent.evaluate(tasks="quick") + print(f"Score: {result.score:.2f}") + print(f"Pass rate: {result.pass_rate:.0%}") + """ + + score: float + tokens: int + pass_rate: float + duration: float + task_count: int + + # Set when agent was deployed — links to the DB job + job_id: str | None = field(default=None, repr=False) + + # Internal reference to full details (for advanced users) + _details: CandidateSummary | None = field(default=None, repr=False) + + def __str__(self) -> str: + return f"score={self.score:.2f}, tokens={self.tokens:,}, pass_rate={self.pass_rate:.0%}" + + +@dataclass +class ImprovementMetrics: + """Metrics showing improvement from optimization. + + Attributes: + score_delta: Improvement in score (best - baseline) + token_reduction_pct: Token reduction as percentage (positive = fewer tokens) + + Example: + if result.improvement.token_reduction_pct > 20: + print("Significant token savings!") + """ + + score_delta: float + token_reduction_pct: float + + def __str__(self) -> str: + score_str = f"{self.score_delta:+.2f}" if self.score_delta != 0 else "0" + # Token reduction: positive = saved tokens, so show as negative change + if self.token_reduction_pct > 0: + token_str = f"-{self.token_reduction_pct:.0f}%" + elif self.token_reduction_pct < 0: + token_str = f"+{-self.token_reduction_pct:.0f}%" + else: + token_str = "0%" + return f"score: {score_str}, tokens: {token_str}" + + +@dataclass +class AgentOptimizationResult: + """Result from optimizing an agent. + + Attributes: + baseline: Performance of the original agent + best: Performance of the best found configuration + improvement: Metrics showing improvement over baseline + best_agent: The optimized agent configuration + candidates_tested: Number of candidates evaluated + pareto_frontier: Names of Pareto-optimal candidates + output_dir: Directory where detailed results are saved + + Example: + result = await agent.optimize(tasks="quick") + print(f"Best score: {result.best.score:.2f}") + print(f"Token reduction: {result.improvement.token_reduction_pct:.0f}%") + + # Use the optimized agent + optimized_agent = result.best_agent + """ + + baseline: EvaluationResult + best: EvaluationResult + improvement: ImprovementMetrics + best_agent: Any # Agent type (Any to avoid circular import) + candidates_tested: int + pareto_frontier: list[str] + output_dir: Path + + # Set when agent was deployed — links to the DB job + job_id: str | None = field(default=None, repr=False) + + def __str__(self) -> str: + return ( + f"Optimization: {self.baseline} → {self.best}\n" + f"Improvement: {self.improvement}\n" + f"Candidates tested: {self.candidates_tested}" + ) diff --git a/src/flow/experiments/runner.py b/src/flow/experiments/runner.py index 04f1a08d64046277eb6ebc3ed3587ae607a7999e..2faeca85c40c11b9b40bfc89f9513fd3368c17fd 100644 --- a/src/flow/experiments/runner.py +++ b/src/flow/experiments/runner.py @@ -17,6 +17,8 @@ from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import SimpleSpanProcessor from opentelemetry.semconv._incubating.attributes.service_attributes import SERVICE_NAME +from flow.tools.workspace import set_workspace + from .trace_collector import FlowTraceCollector from .types import RunResult, Task @@ -25,23 +27,40 @@ if TYPE_CHECKING: logger = logging.getLogger(__name__) +# Module-level shared collector — set up once via setup_tracing() +_shared_collector: FlowTraceCollector | None = None + -def setup_tracing(service_name: str = "flow-experiments") -> TracerProvider: - """Setup OpenTelemetry tracing with in-memory collection. +def setup_tracing(service_name: str = "flow-experiments") -> FlowTraceCollector: + """Setup OpenTelemetry tracing with a single shared collector. - This creates a new TracerProvider configured for experiment tracing. - Call this once at the start of your experiment session. + Creates one TracerProvider + one SimpleSpanProcessor + one FlowTraceCollector. + Idempotent: if already set up, returns the existing collector. This avoids + the issue where ``trace.set_tracer_provider()`` silently ignores subsequent + calls (OTEL SDK only allows setting the provider once), which would cause + a new collector to be created but never receive any spans. Args: service_name: Name for the tracing service Returns: - The configured TracerProvider + The shared FlowTraceCollector (also stored module-level) """ + global _shared_collector + + # Already set up — return existing collector + if _shared_collector is not None: + return _shared_collector + resource = Resource.create({SERVICE_NAME: service_name}) provider = TracerProvider(resource=resource) trace.set_tracer_provider(provider) + # Create ONE shared collector and ONE processor + _shared_collector = FlowTraceCollector() + processor = SimpleSpanProcessor(_shared_collector) + provider.add_span_processor(processor) + # Enable agent framework instrumentation if available try: from agent_framework.observability import enable_instrumentation @@ -52,7 +71,16 @@ def setup_tracing(service_name: str = "flow-experiments") -> TracerProvider: except Exception as e: logger.debug(f"Could not enable Agent Framework instrumentation: {e}") - return provider + return _shared_collector + + +def get_shared_collector() -> FlowTraceCollector | None: + """Get the shared trace collector (if setup_tracing was called). + + Returns: + The shared FlowTraceCollector or None + """ + return _shared_collector class FlowExperimentRunner: @@ -60,7 +88,7 @@ class FlowExperimentRunner: The runner handles: - Setting up temporary workspaces - - Collecting execution traces via OpenTelemetry + - Collecting execution traces via OpenTelemetry (isolated per task) - Measuring execution time - Capturing files created - Supporting streaming execution @@ -97,18 +125,14 @@ class FlowExperimentRunner: async def run( self, - harness: "BaseHarness", + harness: BaseHarness, task: Task, workspace: Path | None = None, ) -> RunResult: """Run a harness on a task and collect results. - This method: - 1. Creates or uses a workspace directory - 2. Sets up trace collection - 3. Executes the harness with streaming - 4. Collects output and files created - 5. Returns a RunResult with all data + Uses a root span to obtain a trace_id, then retrieves only this + task's spans from the shared collector after execution. Args: harness: The harness to run (any BaseHarness implementation) @@ -134,30 +158,30 @@ class FlowExperimentRunner: # Track files before execution files_before = set(self._list_files(workspace)) - # Set up trace collection - collector = FlowTraceCollector() - processor: SimpleSpanProcessor | None = None + # Get the shared collector (set up by setup_tracing) + collector = _shared_collector - try: - provider = trace.get_tracer_provider() - if isinstance(provider, TracerProvider): - processor = SimpleSpanProcessor(collector) - provider.add_span_processor(processor) - logger.debug("Trace collection enabled") - except Exception as e: - logger.debug(f"Could not set up trace collection: {e}") + # Create a root span to get a unique trace_id for this task + tracer = trace.get_tracer("flow.experiments", "0.1.0") + task_trace_ids: set[str] = set() # Execute the harness start_time = time.time() output_chunks: list[str] = [] + tool_results: list[dict[str, str]] = [] error: str | None = None try: - # Change to workspace directory for execution - original_cwd = os.getcwd() - os.chdir(workspace) + # Set workspace via contextvar (safe for concurrent async tasks — + # each task gets its own contextvar copy, no process-global cwd mutation) + set_workspace(workspace) + + # Create root span — all child spans inherit its trace_id + with tracer.start_as_current_span(f"task_{task.name}") as root_span: + trace_id = format(root_span.get_span_context().trace_id, "032x") + task_trace_ids.add(trace_id) + logger.debug(f"Task '{task.name}' trace_id: {trace_id}") - try: # Use streaming execution to capture all output async for event in harness.run_stream(task.prompt): # Collect text output @@ -167,14 +191,13 @@ class FlowExperimentRunner: if event.type in (EventType.TEXT_DELTA, EventType.TEXT_DONE): output_chunks.append(event.content) elif event.type == EventType.TOOL_RESULT: - # Optionally capture tool results - pass + tool_results.append({ + "tool": event.tool_name or "unknown", + "output": event.content, + }) elif event.type == EventType.ERROR: - # Capture error from harness error = event.content logger.error(f"Harness error: {error}") - finally: - os.chdir(original_cwd) except Exception as e: error = str(e) @@ -183,22 +206,11 @@ class FlowExperimentRunner: end_time = time.time() duration_seconds = end_time - start_time - # Force flush and get traces - if processor: - try: - processor.force_flush() - except Exception as e: - logger.debug(f"Error flushing processor: {e}") - - # Get collected traces - trace_data = collector.get_traces() - - # Clean up trace processor - if processor: - try: - processor.shutdown() - except Exception as e: - logger.debug(f"Error shutting down processor: {e}") + # Retrieve only this task's traces from the shared collector + if collector is not None: + trace_data = collector.get_traces_for_task(task_trace_ids) + else: + trace_data = [] # Find files created files_after = set(self._list_files(workspace)) @@ -223,6 +235,7 @@ class FlowExperimentRunner: duration_seconds=duration_seconds, workspace=workspace, error=error, + tool_results=tool_results, ) def _list_files(self, directory: Path) -> list[str]: diff --git a/src/flow/experiments/strategies/__init__.py b/src/flow/experiments/strategies/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..8441ee1ecd049ce21576c420ef6b5d07c2de33d6 --- /dev/null +++ b/src/flow/experiments/strategies/__init__.py @@ -0,0 +1,103 @@ +# Copyright (c) Microsoft. All rights reserved. + +"""Strategy registry for optimization. + +Provides a registry of available strategies that can be used in experiment YAML +via the `strategy:` key in variations. + +Example YAML: + variations: + instructions: + - "You are helpful" # Literal + - strategy: gepa # Strategy + max_candidates: 3 + config: + reflection_lm: gpt-4o +""" + +from __future__ import annotations + +import logging +from typing import TYPE_CHECKING, Any + +if TYPE_CHECKING: + from ..models import CandidateStrategy + +logger = logging.getLogger(__name__) + +# Strategy registry maps strategy names to factory functions +# Factory functions take config dict and return strategy instances +_STRATEGY_REGISTRY: dict[str, type] = {} + + +def register_strategy(name: str, strategy_class: type) -> None: + """Register a strategy class. + + Args: + name: Strategy name used in YAML + strategy_class: Strategy class to instantiate + """ + _STRATEGY_REGISTRY[name] = strategy_class + logger.debug(f"Registered strategy: {name}") + + +def get_strategy(name: str, config: dict[str, Any]) -> CandidateStrategy: + """Get a strategy instance by name. + + Args: + name: Strategy name from YAML + config: Strategy configuration dict + + Returns: + Instantiated strategy + + Raises: + ValueError: If strategy name is unknown + """ + if name not in _STRATEGY_REGISTRY: + available = list(_STRATEGY_REGISTRY.keys()) + raise ValueError(f"Unknown strategy: {name}. Available: {available}") + + strategy_class = _STRATEGY_REGISTRY[name] + return strategy_class(config=config) + + +def get_registered_strategies() -> dict[str, type]: + """Get all registered strategies. + + Returns: + Dict mapping strategy names to their classes + """ + return dict(_STRATEGY_REGISTRY) + + +# ============================================================================= +# Register built-in strategies +# ============================================================================= + +def _register_builtin_strategies() -> None: + """Register built-in strategies.""" + # GEPA strategy (optional - requires gepa package) + try: + from flow.optimizers.gepa_adapter import GepaStrategy + register_strategy("gepa", GepaStrategy) + except ImportError: + logger.debug("GEPA strategy not available (gepa package not installed)") + + # LLM rewriter strategy (simple instruction variations) + try: + from .llm_rewriter import LLMRewriterStrategy + register_strategy("llm_rewriter", LLMRewriterStrategy) + except ImportError: + logger.debug("LLM rewriter strategy not available") + + # Tool selector strategy (generates tool configurations) + try: + from .tool_selector import ToolSelectorStrategy + register_strategy("tool_selector", ToolSelectorStrategy) + except ImportError: + logger.debug("Tool selector strategy not available") + + +# Register on module import +_register_builtin_strategies() diff --git a/src/flow/experiments/strategies/llm_rewriter.py b/src/flow/experiments/strategies/llm_rewriter.py new file mode 100644 index 0000000000000000000000000000000000000000..60dd1665685ee1e8934e9066ff553356b0c85a2b --- /dev/null +++ b/src/flow/experiments/strategies/llm_rewriter.py @@ -0,0 +1,357 @@ +# Copyright (c) Microsoft. All rights reserved. + +"""LLM-based instruction rewriter strategy. + +This strategy always requires a runner and tasks. It: +1. Evaluates the current instructions on all tasks +2. Reflects on failures to understand what went wrong +3. Rewrites instructions to address failures +4. Re-evaluates and repeats until convergence or budget exhausted +""" + +from __future__ import annotations + +import logging +import os +from dataclasses import dataclass, field +from typing import Any + +from ..models import Agent, Candidate, ExperimentRunner, StrategyIteration +from ..types import Task + +logger = logging.getLogger(__name__) + + +@dataclass +class LLMRewriterStrategy: + """Strategy that uses an LLM to iteratively improve agent instructions. + + Runs an evaluate-reflect-rewrite loop. Each iteration evaluates + the current instructions on tasks via the runner, analyzes failures, + and rewrites the instructions to address them. Stops when: + - All tasks pass + - Score improvement drops below min_improvement + - max_iterations reached + + Requires both a runner (to evaluate candidates) and tasks (to test on). + + Config options: + model: LLM for rewriting (default: gpt-4o-mini) + max_iterations: Max optimization iterations (default: 5) + min_improvement: Min score gain to continue (default: 0.05) + + Example YAML: + strategy: + type: llm_rewriter + config: + model: gpt-4o-mini + max_iterations: 5 + min_improvement: 0.05 + """ + + config: dict[str, Any] = field(default_factory=dict) + + async def generate( + self, + base: Agent, + budget: int, + *, + tasks: list[Task] | None = None, + runner: ExperimentRunner | None = None, + ) -> list[Candidate]: + """Generate optimized instruction variants via evaluate-reflect-rewrite loop. + + Args: + base: Base agent with instructions to rewrite + budget: Max candidates to generate + tasks: Tasks to evaluate on (required) + runner: ExperimentRunner for evaluation (required) + + Returns: + List of candidates with optimized instructions + + Raises: + ValueError: If tasks or runner not provided + """ + if runner is None: + raise ValueError( + "LLMRewriterStrategy requires a runner. " + "Use FlowOptimizer.optimize_with_strategy() to provide one." + ) + if not tasks: + raise ValueError( + "LLMRewriterStrategy requires tasks to evaluate against." + ) + + base_instructions = base.instructions or "You are a helpful assistant." + return await self._generate_active(base, base_instructions, budget, tasks, runner) + + async def _generate_active( + self, + base: Agent, + instructions: str, + budget: int, + tasks: list[Task], + runner: ExperimentRunner, + ) -> list[Candidate]: + """Run active optimization loop with real evaluation feedback.""" + model = self.config.get("model", "gpt-4o-mini") + max_iterations = self.config.get("max_iterations", 5) + min_improvement = self.config.get("min_improvement", 0.05) + + logger.info( + f"LLMRewriterStrategy: active mode (max_iterations={max_iterations}, " + f"min_improvement={min_improvement})" + ) + + current_instructions = instructions + best_instructions = instructions + best_score = 0.0 + history: list[StrategyIteration] = [] + + for iteration in range(max_iterations): + # 1. Evaluate current instructions + agent = Agent( + name=f"{base.name}_rewrite_iter{iteration}", + framework=base.framework, + instructions=current_instructions, + llm_config=base.llm_config, + compaction=base.compaction, + tools=base.tools, + ) + candidate = Candidate( + agent=agent, + mutations={"instructions": current_instructions}, + ) + + summary = await runner.evaluate(candidate, tasks) + + avg_score = getattr(summary, "avg_score", 0.0) + pass_rate = getattr(summary, "pass_rate", 0.0) + task_results = getattr(summary, "task_results", []) + failures = [tr for tr in task_results if not getattr(tr, "eval_passed", True)] + + logger.info( + f" Iteration {iteration}: avg_score={avg_score:.3f}, " + f"pass_rate={pass_rate:.1%}, failures={len(failures)}" + ) + + # Build per-task summary for rationale + task_lines: list[str] = [] + for tr in task_results: + task_name = getattr(tr, "task_name", "unknown") + passed = getattr(tr, "eval_passed", True) + reasoning = getattr(tr, "eval_reasoning", "") + status = "PASS" if passed else "FAIL" + task_lines.append(f" [{status}] {task_name}: {reasoning[:150]}") + tasks_summary = "\n".join(task_lines) + + # Record iteration + change_desc = "Baseline evaluation" if iteration == 0 else f"Rewrite iteration {iteration}" + change_rationale = f"Per-task results:\n{tasks_summary}" + if iteration > 0: + score_delta = avg_score - history[-1].avg_score + change_rationale = ( + f"Score {'improved' if score_delta > 0 else 'declined'} by {abs(score_delta):.3f}. " + f"{len(failures)} failures remaining.\n{tasks_summary}" + ) + + history.append( + StrategyIteration( + iteration=iteration, + instructions_preview=current_instructions[:200], + full_instructions=current_instructions, + avg_score=avg_score, + pass_rate=pass_rate, + failures_count=len(failures), + change_description=change_desc, + change_rationale=change_rationale, + ) + ) + + # Track best + if avg_score > best_score: + best_score = avg_score + best_instructions = current_instructions + + # 2. Check stopping conditions + if iteration > 0: + improvement = avg_score - history[-2].avg_score + if improvement < min_improvement and avg_score <= best_score: + logger.info( + f" Stopping: improvement ({improvement:.3f}) < " + f"min_improvement ({min_improvement})" + ) + break + + if not failures: + logger.info(" Stopping: all tasks passed") + break + + if iteration == max_iterations - 1: + break # Don't rewrite on last iteration + + # 3. Reflect on failures and rewrite + current_instructions = self._reflect_and_rewrite( + current_instructions, failures, avg_score, model + ) + logger.info(f" Rewrote instructions ({len(current_instructions)} chars)") + + # Build final candidate with optimization history + final_agent = Agent( + name=f"{base.name}_llm_rewriter_optimized", + framework=base.framework, + instructions=best_instructions, + llm_config=base.llm_config, + compaction=base.compaction, + tools=base.tools, + ) + + score_progression = f"{history[0].avg_score:.2f} → {best_score:.2f}" + return [ + Candidate( + agent=final_agent, + mutations={"instructions": best_instructions}, + rationale=f"LLM rewriter active optimization: {len(history)} iterations, {score_progression}", + optimization_history=history, + ) + ] + + def _reflect_and_rewrite( + self, + instructions: str, + failures: list[Any], + current_score: float, + model: str, + ) -> str: + """Analyze failures and rewrite instructions to address them.""" + # Build failure analysis + failure_descriptions = [] + for tr in failures[:5]: # Limit to 5 failures for context + task_name = getattr(tr, "task_name", "unknown") + reasoning = getattr(tr, "eval_reasoning", "No reasoning") + score = getattr(tr, "eval_score", 0.0) + failure_descriptions.append( + f"- Task '{task_name}' (score={score:.2f}): {reasoning[:200]}" + ) + + failures_text = "\n".join(failure_descriptions) + + prompt = f"""You are a prompt engineer writing guidelines for a coding assistant. + +The assistant's current guidelines scored {current_score:.2f} out of 1.0 on a benchmark. + +Here are the tasks where performance was low: +{failures_text} + +The current guidelines are: +--- +{instructions} +--- + +Write a new, improved version of the guidelines. The new guidelines should: +1. Help the assistant succeed on a wide range of coding tasks — the failures + above are examples, but the guidelines must generalize beyond them +2. Include concrete strategies (e.g., always verify output, check edge cases, + create and run files when asked) +3. Be general-purpose: do NOT reference specific task names, specific answers, + or specific test cases from the failures above +4. Focus on transferable skills and habits (e.g., "verify output matches + requirements" not "check that fibonacci returns 55") +5. Be concise + +Output ONLY the new guidelines text, nothing else.""" + + try: + return self._call_llm(prompt, model) or instructions + except Exception as e: + logger.warning(f"LLM rewrite failed: {e}") + # Primary prompt failed — the original instructions may have + # triggered a content filter (Azure, OpenAI, etc.) or caused + # another error. Try a fallback that omits them entirely. + logger.info("Retrying rewrite with fallback prompt (without original instructions)") + return self._fallback_rewrite(failures_text, current_score, model) + + def _fallback_rewrite( + self, + failures_text: str, + current_score: float, + model: str, + ) -> str: + """Generate new instructions from scratch when the primary rewrite is blocked. + + This avoids including the original instructions (which may trigger + content filters) and instead writes fresh guidelines based solely on + the task failure descriptions. + """ + prompt = f"""You are a prompt engineer. Write guidelines for a coding assistant. + +The assistant scored {current_score:.2f} out of 1.0 on these tasks: +{failures_text} + +Write concise guidelines that would help a coding assistant succeed on +a wide range of coding tasks. The failures above are examples — the +guidelines must generalize beyond them. The guidelines should: +1. Instruct the assistant to complete coding tasks by creating files and + running code +2. Include strategies for verifying output and handling edge cases +3. Be general-purpose: do NOT reference specific task names or answers + from the failures above +4. Focus on transferable habits and skills + +Output ONLY the guidelines text, nothing else.""" + + try: + result = self._call_llm(prompt, model) + if result: + logger.info("Fallback rewrite succeeded") + return result + except Exception as e2: + logger.warning(f"Fallback rewrite also failed: {e2}") + + # Last resort: return a sensible default + logger.info("Using default coding assistant guidelines") + return ( + "You are a helpful coding assistant. When given a task:\n" + "1. Create the requested files with correct, working code\n" + "2. Run the code and verify the output is correct\n" + "3. Handle edge cases and validate results before finishing" + ) + + + def _get_client(self, model: str) -> tuple[Any, str]: + """Get OpenAI client and model name.""" + try: + from openai import AzureOpenAI, OpenAI + except ImportError as e: + raise ImportError("openai package required for LLMRewriterStrategy") from e + + azure_key = os.environ.get("AZURE_OPENAI_API_KEY") + azure_endpoint = os.environ.get("AZURE_OPENAI_ENDPOINT") + + if azure_key and azure_endpoint: + client = AzureOpenAI( + api_key=azure_key, + api_version="2024-08-01-preview", + azure_endpoint=azure_endpoint, + ) + model_name = os.environ.get("AZURE_OPENAI_DEPLOYMENT", model) + else: + openai_key = os.environ.get("OPENAI_API_KEY") + if not openai_key: + raise ValueError("No OpenAI or Azure OpenAI credentials found") + client = OpenAI(api_key=openai_key) + model_name = model + + return client, model_name + + def _call_llm(self, prompt: str, model: str) -> str: + """Call LLM with a prompt.""" + client, model_name = self._get_client(model) + + response = client.chat.completions.create( + model=model_name, + messages=[{"role": "user", "content": prompt}], + ) + return response.choices[0].message.content or "" + diff --git a/src/flow/experiments/strategies/tool_selector.py b/src/flow/experiments/strategies/tool_selector.py new file mode 100644 index 0000000000000000000000000000000000000000..9801602e5db83f9a149d8896127979479cbe63bb --- /dev/null +++ b/src/flow/experiments/strategies/tool_selector.py @@ -0,0 +1,426 @@ +# Copyright (c) Microsoft. All rights reserved. + +"""Active tool selector strategy. + +Uses the runner to evaluate tool configurations and iteratively adjust +the tool set based on actual execution failures. The strategy: +1. Evaluates the current tool set on all tasks +2. Analyzes failures and trace data to identify missing/unnecessary tools +3. Uses an LLM to recommend tool changes +4. Re-evaluates and repeats until convergence or budget exhausted +""" + +from __future__ import annotations + +import logging +import os +from dataclasses import dataclass, field +from typing import Any + +from ..metrics import extract_metrics +from ..models import Agent, Candidate, ExperimentRunner, StrategyIteration, TOOL_PRESETS +from ..types import Task + +logger = logging.getLogger(__name__) + +# All tools the strategy can choose from +ALL_AVAILABLE_TOOLS: list[str] = sorted( + {tool for preset in TOOL_PRESETS.values() for tool in preset} +) + + +@dataclass +class ToolSelectorStrategy: + """Strategy that iteratively optimizes tool configurations via evaluation. + + Runs an evaluate-analyze-adjust loop. Each iteration evaluates + the current tool set on tasks via the runner, analyzes which tools + were used/missing from traces, and uses an LLM to recommend changes. + + Requires both a runner (to evaluate candidates) and tasks (to test on). + + Config options: + model: LLM for tool recommendations (default: gpt-4o-mini) + max_iterations: Max optimization iterations (default: 3) + min_improvement: Min score gain to continue (default: 0.05) + available_tools: List of tool names to choose from (default: all known tools) + + Example YAML: + strategy: + type: tool_selector + config: + model: gpt-4o-mini + max_iterations: 3 + """ + + config: dict[str, Any] = field(default_factory=dict) + + async def generate( + self, + base: Agent, + budget: int, + *, + tasks: list[Task] | None = None, + runner: ExperimentRunner | None = None, + ) -> list[Candidate]: + """Generate optimized tool configurations via evaluate-analyze-adjust loop. + + Args: + base: Base agent with initial tool configuration + budget: Max candidates to generate + tasks: Tasks to evaluate on (required) + runner: ExperimentRunner for evaluation (required) + + Returns: + List of candidates with optimized tool sets + + Raises: + ValueError: If tasks or runner not provided + """ + if runner is None: + raise ValueError( + "ToolSelectorStrategy requires a runner. " + "Use FlowOptimizer.optimize_with_strategy() to provide one." + ) + if not tasks: + raise ValueError( + "ToolSelectorStrategy requires tasks to evaluate against." + ) + + # Resolve initial tools to a list + from ..models import resolve_tools + if base.tools is None or (isinstance(base.tools, list) and len(base.tools) == 0): + current_tools = [] + else: + current_tools = sorted(resolve_tools(base.tools).keys()) + + return await self._generate_active(base, current_tools, budget, tasks, runner) + + async def _generate_active( + self, + base: Agent, + tools: list[str], + budget: int, + tasks: list[Task], + runner: ExperimentRunner, + ) -> list[Candidate]: + """Run active optimization loop with real evaluation feedback.""" + model = self.config.get("model", "gpt-4o-mini") + max_iterations = self.config.get("max_iterations", 3) + min_improvement = self.config.get("min_improvement", 0.05) + available_tools = self.config.get("available_tools", ALL_AVAILABLE_TOOLS) + + logger.info( + f"ToolSelectorStrategy: active mode (max_iterations={max_iterations}, " + f"available_tools={len(available_tools)})" + ) + + current_tools = tools + best_tools = tools + best_score = 0.0 + history: list[StrategyIteration] = [] + # Track all unique tool configs tried, for returning as candidates + iteration_candidates: list[tuple[list[str], str]] = [] # (tools, name_suffix) + + for iteration in range(max_iterations): + # 1. Evaluate current tool set + agent = Agent( + name=f"{base.name}_tools_iter{iteration}", + framework=base.framework, + instructions=base.instructions, + llm_config=base.llm_config, + compaction=base.compaction, + tools=current_tools, + ) + candidate = Candidate( + agent=agent, + mutations={"tools": current_tools}, + ) + + summary = await runner.evaluate(candidate, tasks) + + avg_score = getattr(summary, "avg_score", 0.0) + pass_rate = getattr(summary, "pass_rate", 0.0) + task_results = getattr(summary, "task_results", []) + failures = [tr for tr in task_results if not getattr(tr, "eval_passed", True)] + + # Collect tool usage from traces + tools_used: dict[str, int] = {} + for tr in task_results: + metrics = getattr(tr, "metrics", None) + if metrics and hasattr(metrics, "tool_calls_by_name"): + for name, count in metrics.tool_calls_by_name.items(): + tools_used[name] = tools_used.get(name, 0) + count + + logger.info( + f" Iteration {iteration}: avg_score={avg_score:.3f}, " + f"pass_rate={pass_rate:.1%}, failures={len(failures)}, " + f"tools={current_tools}, used={tools_used}" + ) + + # Build per-task summary for rationale + task_lines: list[str] = [] + for tr in task_results: + task_name = getattr(tr, "task_name", "unknown") + passed = getattr(tr, "eval_passed", True) + reasoning = getattr(tr, "eval_reasoning", "") + task_metrics = getattr(tr, "metrics", None) + task_tools: dict[str, int] = {} + if task_metrics and hasattr(task_metrics, "tool_calls_by_name"): + task_tools = dict(task_metrics.tool_calls_by_name) + status = "PASS" if passed else "FAIL" + tools_info = f" (tools used: {task_tools})" if task_tools else "" + task_lines.append(f" [{status}] {task_name}{tools_info}: {reasoning[:150]}") + tasks_summary = "\n".join(task_lines) + + # Record iteration + tools_desc = ", ".join(current_tools) or "(none)" + used_desc = ", ".join(f"{k}={v}" for k, v in sorted(tools_used.items())) or "(none)" + change_desc = "Baseline evaluation" if iteration == 0 else f"Tool adjustment iteration {iteration}" + change_rationale = f"Tools used: {used_desc}\n{tasks_summary}" + if iteration > 0: + score_delta = avg_score - history[-1].avg_score + added = set(current_tools) - set(best_tools if iteration == 1 else _prev_tools) + removed = set(_prev_tools) - set(current_tools) if iteration > 0 else set() + change_rationale = ( + f"Score {'improved' if score_delta > 0 else 'declined'} by {abs(score_delta):.3f}. " + f"Added: {sorted(added) or 'none'}. Removed: {sorted(removed) or 'none'}. " + f"{len(failures)} failures remaining.\n" + f"Tools used: {used_desc}\n{tasks_summary}" + ) + history.append( + StrategyIteration( + iteration=iteration, + instructions_preview=f"[{tools_desc}]"[:200], + full_instructions=f"[{tools_desc}]", + avg_score=avg_score, + pass_rate=pass_rate, + failures_count=len(failures), + change_description=change_desc, + change_rationale=change_rationale, + ) + ) + + # Track this iteration's config + label = "baseline" if iteration == 0 else f"iter{iteration}" + iteration_candidates.append((list(current_tools), label)) + + # Track best + if avg_score > best_score: + best_score = avg_score + best_tools = current_tools + + # 2. Check stopping conditions + if iteration > 0: + improvement = avg_score - history[-2].avg_score + if improvement < min_improvement and avg_score <= best_score: + logger.info( + f" Stopping: improvement ({improvement:.3f}) < " + f"min_improvement ({min_improvement})" + ) + break + + if not failures: + logger.info(" Stopping: all tasks passed") + break + + if iteration == max_iterations - 1: + break # Don't adjust on last iteration + + # 3. Analyze failures and adjust tools + _prev_tools = current_tools + current_tools = self._analyze_and_adjust( + current_tools, task_results, tools_used, available_tools, model + ) + logger.info(f" Adjusted tools: {current_tools}") + + # Build candidates for all unique tool configs tried + # This gives the Pareto chart multiple data points to compare + candidates: list[Candidate] = [] + seen_tool_sets: set[tuple[str, ...]] = set() + + for iter_tools, label in iteration_candidates: + tool_key = tuple(sorted(iter_tools)) + if tool_key in seen_tool_sets: + continue + seen_tool_sets.add(tool_key) + + is_best = sorted(iter_tools) == sorted(best_tools) + suffix = "optimized" if is_best else label + agent = Agent( + name=f"{base.name}_tools_{suffix}", + framework=base.framework, + instructions=base.instructions, + llm_config=base.llm_config, + compaction=base.compaction, + tools=iter_tools, + ) + tools_desc = ", ".join(iter_tools) or "(none)" + candidates.append( + Candidate( + agent=agent, + mutations={"tools": iter_tools}, + rationale=f"Tools: [{tools_desc}]", + optimization_history=history if is_best else [], + ) + ) + + # Ensure best is always included (may differ from any iteration if + # the best score was from an earlier iteration) + best_key = tuple(sorted(best_tools)) + if best_key not in seen_tool_sets: + final_agent = Agent( + name=f"{base.name}_tools_optimized", + framework=base.framework, + instructions=base.instructions, + llm_config=base.llm_config, + compaction=base.compaction, + tools=best_tools, + ) + tools_desc = ", ".join(best_tools) + candidates.append( + Candidate( + agent=final_agent, + mutations={"tools": best_tools}, + rationale=f"Tools: [{tools_desc}]", + optimization_history=history, + ) + ) + + return candidates + + def _analyze_and_adjust( + self, + current_tools: list[str], + task_results: list[Any], + tools_used: dict[str, int], + available_tools: list[str], + model: str, + ) -> list[str]: + """Analyze failures and traces, then recommend tool changes.""" + # Build analysis of what happened + failure_descriptions = [] + for tr in task_results: + task_name = getattr(tr, "task_name", "unknown") + passed = getattr(tr, "eval_passed", True) + reasoning = getattr(tr, "eval_reasoning", "") + score = getattr(tr, "eval_score", 0.0) + + # Get per-task tool usage + metrics = getattr(tr, "metrics", None) + task_tools = {} + if metrics and hasattr(metrics, "tool_calls_by_name"): + task_tools = dict(metrics.tool_calls_by_name) + + status = "PASS" if passed else "FAIL" + failure_descriptions.append( + f"- [{status}] Task '{task_name}' (score={score:.2f}): " + f"tools_used={task_tools}. {reasoning[:200]}" + ) + + results_text = "\n".join(failure_descriptions) + not_in_current = sorted(set(available_tools) - set(current_tools)) + + prompt = f"""You are optimizing the tool configuration for a coding assistant. + +Current tools: {current_tools} +Available tools NOT currently enabled: {not_in_current} + +Task results with this tool set: +{results_text} + +Tool usage across all tasks: {tools_used} + +Based on the failures and tool usage patterns, recommend an updated tool list. +Consider: +- Tools that were needed but missing (e.g., agent tried to search but had no grep) +- Tools that were never used (candidates for removal to reduce complexity) +- Tools that could help with the failed tasks + +Rules: +- Only select from the full available set: {available_tools} +- Always include at minimum: read_file, write_file, bash +- Do NOT add tools just because they exist — only add tools that would + address specific failure patterns seen above + +Respond with ONLY a comma-separated list of tool names, nothing else. +Example: read_file, write_file, bash, grep, edit_file""" + + try: + result = self._call_llm(prompt, model) + if result: + # Parse comma-separated tool names + parsed = [t.strip() for t in result.split(",") if t.strip()] + # Validate against available tools + valid = [t for t in parsed if t in available_tools] + if valid: + return sorted(valid) + logger.warning(f"No valid tools in LLM response: {parsed}") + except Exception as e: + logger.warning(f"LLM tool adjustment failed: {e}") + # Fallback: try adding commonly useful tools + return self._heuristic_adjust(current_tools, tools_used, available_tools) + + return current_tools + + def _heuristic_adjust( + self, + current_tools: list[str], + tools_used: dict[str, int], + available_tools: list[str], + ) -> list[str]: + """Fallback heuristic when LLM is unavailable.""" + adjusted = set(current_tools) + + # If bash was used heavily but grep/glob not available, add them + if "bash" in tools_used and tools_used["bash"] > 2: + for tool in ["grep", "glob_files", "ls"]: + if tool in available_tools: + adjusted.add(tool) + + # If write_file was used but edit_file not available, add it + if "write_file" in tools_used and "edit_file" not in adjusted: + if "edit_file" in available_tools: + adjusted.add("edit_file") + + # Add think if not present (helps with reasoning) + if "think" in available_tools: + adjusted.add("think") + + return sorted(adjusted) + + def _get_client(self, model: str) -> tuple[Any, str]: + """Get OpenAI client and model name.""" + try: + from openai import AzureOpenAI, OpenAI + except ImportError as e: + raise ImportError("openai package required for ToolSelectorStrategy") from e + + azure_key = os.environ.get("AZURE_OPENAI_API_KEY") + azure_endpoint = os.environ.get("AZURE_OPENAI_ENDPOINT") + + if azure_key and azure_endpoint: + client = AzureOpenAI( + api_key=azure_key, + api_version="2024-08-01-preview", + azure_endpoint=azure_endpoint, + ) + model_name = os.environ.get("AZURE_OPENAI_DEPLOYMENT", model) + else: + openai_key = os.environ.get("OPENAI_API_KEY") + if not openai_key: + raise ValueError("No OpenAI or Azure OpenAI credentials found") + client = OpenAI(api_key=openai_key) + model_name = model + + return client, model_name + + def _call_llm(self, prompt: str, model: str) -> str: + """Call LLM with a prompt.""" + client, model_name = self._get_client(model) + + response = client.chat.completions.create( + model=model_name, + messages=[{"role": "user", "content": prompt}], + ) + return response.choices[0].message.content or "" diff --git a/src/flow/experiments/trace_collector.py b/src/flow/experiments/trace_collector.py index 7d7bc662cbb3244bb227d56ad903546500f4da26..4bb70478acdfd6dd22f84a0b7987ad61de308015 100644 --- a/src/flow/experiments/trace_collector.py +++ b/src/flow/experiments/trace_collector.py @@ -1,8 +1,13 @@ # Copyright (c) Microsoft. All rights reserved. -"""OpenTelemetry trace collector for experiment analysis.""" +"""OpenTelemetry trace collector for experiment analysis. + +Uses trace_id-based bucketing to isolate spans per task, even when +multiple tasks run concurrently on a shared TracerProvider. +""" import logging +import threading from datetime import datetime from typing import Any @@ -12,24 +17,26 @@ logger = logging.getLogger(__name__) class FlowTraceCollector(SpanExporter): - """Collects OpenTelemetry spans for experiment analysis. + """Collects OpenTelemetry spans, bucketed by trace_id for isolation. - This exporter captures spans during agent execution and converts them - to a dictionary format suitable for metrics extraction and analysis. + All spans from the global TracerProvider flow into this single collector. + Spans are stored in per-trace_id buckets so that each task can retrieve + only its own spans without cross-contamination. Example: collector = FlowTraceCollector() - # Attach to TracerProvider via SimpleSpanProcessor - # Run agent execution - traces = collector.get_traces() + # Attach ONCE to the global TracerProvider via SimpleSpanProcessor + # Run multiple tasks concurrently — each gets a unique trace_id + task_traces = collector.get_traces_for_task({"abc123"}) """ def __init__(self) -> None: """Initialize the trace collector.""" - self.spans: list[dict[str, Any]] = [] + self._spans_by_trace: dict[str, list[dict[str, Any]]] = {} + self._lock = threading.Lock() def export(self, spans: Any) -> SpanExportResult: - """Collect spans from OpenTelemetry. + """Collect spans, bucketed by trace_id. Args: spans: Sequence of OpenTelemetry ReadableSpan objects @@ -39,41 +46,46 @@ class FlowTraceCollector(SpanExporter): """ for span in spans: try: - # Convert nanoseconds to seconds for timestamps - start_time = span.start_time / 1_000_000_000 - end_time = span.end_time / 1_000_000_000 if span.end_time else None - duration_ms = ((end_time - start_time) * 1000) if end_time else None - - self.spans.append({ - "type": "trace_span", - "timestamp": datetime.fromtimestamp(start_time).isoformat(), - "data": { - "operation_name": span.name, - "span_id": format(span.context.span_id, "016x"), - "trace_id": format(span.context.trace_id, "032x"), - "parent_span_id": ( - format(span.parent.span_id, "016x") if span.parent else None - ), - "duration_ms": duration_ms, - "attributes": dict(span.attributes) if span.attributes else {}, - "status": str(span.status.status_code.name) if hasattr(span, "status") else "OK", - "events": [ - { - "name": event.name, - "timestamp": datetime.fromtimestamp( - event.timestamp / 1_000_000_000 - ).isoformat(), - "attributes": dict(event.attributes) if event.attributes else {}, - } - for event in (span.events or []) - ], - }, - }) + trace_id = format(span.context.trace_id, "032x") + span_dict = self._convert_span(span) + + with self._lock: + if trace_id not in self._spans_by_trace: + self._spans_by_trace[trace_id] = [] + self._spans_by_trace[trace_id].append(span_dict) except Exception as e: logger.debug(f"Failed to collect span: {e}") return SpanExportResult.SUCCESS + def get_traces_for_task(self, trace_ids: set[str]) -> list[dict[str, Any]]: + """Get spans matching any of the given trace_ids, removing them. + + Args: + trace_ids: Set of trace_id hex strings to retrieve + + Returns: + List of span dicts belonging to those trace_ids + """ + result: list[dict[str, Any]] = [] + with self._lock: + for tid in trace_ids: + result.extend(self._spans_by_trace.pop(tid, [])) + return result + + def get_traces(self) -> list[dict[str, Any]]: + """Get and clear ALL collected traces (legacy API). + + Returns: + List of all collected trace spans, clearing internal state + """ + with self._lock: + all_spans: list[dict[str, Any]] = [] + for spans in self._spans_by_trace.values(): + all_spans.extend(spans) + self._spans_by_trace.clear() + return all_spans + def force_flush(self, timeout_millis: int = 30000) -> bool: """Force flush spans (no-op for simple collection). @@ -89,16 +101,47 @@ class FlowTraceCollector(SpanExporter): """Shutdown the exporter (no-op).""" pass - def get_traces(self) -> list[dict[str, Any]]: - """Get and clear collected traces. + def clear(self) -> None: + """Clear collected traces without returning them.""" + with self._lock: + self._spans_by_trace.clear() + + @staticmethod + def _convert_span(span: Any) -> dict[str, Any]: + """Convert an OTEL ReadableSpan to a dict. + + Args: + span: OpenTelemetry ReadableSpan Returns: - List of collected trace spans, clearing the internal list + Dictionary representation of the span """ - traces = self.spans.copy() - self.spans.clear() - return traces - - def clear(self) -> None: - """Clear collected traces without returning them.""" - self.spans.clear() + start_time = span.start_time / 1_000_000_000 + end_time = span.end_time / 1_000_000_000 if span.end_time else None + duration_ms = ((end_time - start_time) * 1000) if end_time else None + + return { + "type": "trace_span", + "timestamp": datetime.fromtimestamp(start_time).isoformat(), + "data": { + "operation_name": span.name, + "span_id": format(span.context.span_id, "016x"), + "trace_id": format(span.context.trace_id, "032x"), + "parent_span_id": ( + format(span.parent.span_id, "016x") if span.parent else None + ), + "duration_ms": duration_ms, + "attributes": dict(span.attributes) if span.attributes else {}, + "status": str(span.status.status_code.name) if hasattr(span, "status") else "OK", + "events": [ + { + "name": event.name, + "timestamp": datetime.fromtimestamp( + event.timestamp / 1_000_000_000 + ).isoformat(), + "attributes": dict(event.attributes) if event.attributes else {}, + } + for event in (span.events or []) + ], + }, + } diff --git a/src/flow/experiments/types.py b/src/flow/experiments/types.py index ce7f0e97f5e4a05f6a1dc34608953a3b177ddb9b..610594e8ff656566d44d826c516fd2cd9d244719 100644 --- a/src/flow/experiments/types.py +++ b/src/flow/experiments/types.py @@ -61,6 +61,7 @@ class RunResult: duration_seconds: float workspace: Path error: str | None = None + tool_results: list[dict[str, str]] = field(default_factory=list) @property def success(self) -> bool: @@ -74,7 +75,8 @@ class CriterionResult: Attributes: name: Name of the criterion evaluated - score: Numeric score (0.0 to 1.0) + score: Numeric score (0.0 to 1.0) — exact match score + reasoning_score: Partial credit for correct reasoning/methodology (0.0 to 1.0) passed: Whether the criterion was met reasoning: Explanation of the evaluation """ @@ -83,6 +85,7 @@ class CriterionResult: score: float passed: bool reasoning: str + reasoning_score: float = 0.0 @dataclass @@ -90,7 +93,8 @@ class EvalResult: """Result of evaluating an agent's output. Attributes: - score: Overall weighted score (0.0 to 1.0) + score: Overall weighted exact-match score (0.0 to 1.0) + reasoning_score: Overall weighted reasoning/methodology score (0.0 to 1.0) passed: Whether the evaluation passed overall criteria_results: Results for each individual criterion reasoning: Overall evaluation reasoning/summary @@ -100,6 +104,7 @@ class EvalResult: passed: bool criteria_results: list[CriterionResult] reasoning: str + reasoning_score: float = 0.0 # ============================================================================= diff --git a/src/flow/harness/__init__.py b/src/flow/harness/__init__.py index e0d170febe68cff329c95e9eaf06d2c4582c7f31..bb37fa695f68961c1f4a1f144b46496003b483e1 100644 --- a/src/flow/harness/__init__.py +++ b/src/flow/harness/__init__.py @@ -16,6 +16,10 @@ Usage: harness = create_harness(agent, workspace=Path("/tmp")) """ +# Auto-register harnesses by importing them +# Each harness module calls register() on import +from flow.harness import maf as _maf +from flow.harness import miniagent as _miniagent from flow.harness.base import BaseHarness, Event, EventType from flow.harness.registry import ( available_frameworks, @@ -24,10 +28,7 @@ from flow.harness.registry import ( register, ) -# Auto-register harnesses by importing them -# Each harness module calls register() on import -from flow.harness import maf as _maf # noqa: F401 -from flow.harness import miniagent as _miniagent # noqa: F401 +_ = (_maf, _miniagent) # Suppress unused import warnings __all__ = [ "BaseHarness", diff --git a/src/flow/harness/base.py b/src/flow/harness/base.py index c37361e8a8c4a8e28e56535fe96789ca9397379e..9920372a8c18681bf0708b5dc84b4101aa60f811 100644 --- a/src/flow/harness/base.py +++ b/src/flow/harness/base.py @@ -10,7 +10,7 @@ from abc import ABC, abstractmethod from collections.abc import AsyncIterator from dataclasses import dataclass, field from enum import Enum -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, ClassVar if TYPE_CHECKING: from pathlib import Path @@ -62,18 +62,30 @@ class BaseHarness(ABC): Implementations: - MAFHarness (flow.harness.maf): Microsoft Agent Framework - - (Future) LangGraphHarness: LangGraph - - (Future) ClaudeHarness: Claude SDK + - LangGraphHarness (flow.harness.langgraph): LangGraph + - MiniAgentHarness (flow.harness.miniagent): MiniAgent + + Class Attributes: + framework_name: Unique identifier for this framework (e.g., "maf", "langgraph") + framework_label: Human-readable label (e.g., "Microsoft Agent Framework") + framework_description: Short description of the framework + supported_compaction_strategies: List of compaction strategy names this framework supports """ + # Framework metadata - subclasses should override these + framework_name: ClassVar[str] = "" + framework_label: ClassVar[str] = "" + framework_description: ClassVar[str] = "" + supported_compaction_strategies: ClassVar[list[str]] = [] + @classmethod @abstractmethod def from_agent( cls, - agent: "Agent", - workspace: "Path", - llm_config: "LLMClientConfig | None" = None, - ) -> "BaseHarness": + agent: Agent, + workspace: Path, + llm_config: LLMClientConfig | None = None, + ) -> BaseHarness: """Create a harness from an Agent definition. Args: diff --git a/src/flow/harness/compaction/__init__.py b/src/flow/harness/compaction/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..8015ff695c4bec69f748ccdcbe6f9e9e00b5bff2 --- /dev/null +++ b/src/flow/harness/compaction/__init__.py @@ -0,0 +1,38 @@ +# Copyright (c) Microsoft. All rights reserved. +"""Shared token-aware compaction strategies for all frameworks. + +This module provides unified compaction strategies that work across +MAF, MiniAgent, and LangGraph frameworks. All strategies are token-based +to ensure safety against large messages. + +Strategies: +- HeadTailStrategy: Keep head (system prompt) + tail (recent), drop middle +- SlidingWindowStrategy: Keep system + most recent messages within budget +- SummarizationStrategy: Summarize middle messages using LLM +- NoCompactionStrategy: Baseline (no management) + +Usage: + from flow.harness.compaction import HeadTailStrategy, count_tokens + + strategy = HeadTailStrategy(head_ratio=0.2, token_budget=200_000) + compacted = strategy.compact(messages) +""" + +from flow.harness.compaction.strategies import ( + CompactionStrategy, + HeadTailStrategy, + NoCompactionStrategy, + SlidingWindowStrategy, + SummarizationStrategy, +) +from flow.harness.compaction.tokenizer import count_tokens, get_encoder + +__all__ = [ + "CompactionStrategy", + "HeadTailStrategy", + "NoCompactionStrategy", + "SlidingWindowStrategy", + "SummarizationStrategy", + "count_tokens", + "get_encoder", +] diff --git a/src/flow/harness/compaction/strategies.py b/src/flow/harness/compaction/strategies.py new file mode 100644 index 0000000000000000000000000000000000000000..04dfd420eeeeca76964adfc14161d1677548e159 --- /dev/null +++ b/src/flow/harness/compaction/strategies.py @@ -0,0 +1,502 @@ +# Copyright (c) Microsoft. All rights reserved. +"""Token-aware compaction strategies for context management. + +All strategies use token counting (not message counting) to ensure +safety against large messages that could blow past LLM context limits. +""" + +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import Any, Protocol + +from flow.harness.compaction.tokenizer import ( + count_message_tokens, + count_messages_tokens, + get_encoder, +) + +# Default token budget (safe for GPT-4o, Claude 3.5, etc.) +DEFAULT_TOKEN_BUDGET = 200_000 + + +class CompactionStrategy(Protocol): + """Protocol for compaction strategies. + + All strategies must implement compact() which takes messages and + returns a (possibly compacted) list of messages. + """ + + def compact( + self, + messages: list[dict[str, Any]], + token_budget: int | None = None, + ) -> list[dict[str, Any]]: + """Compact messages to fit within token budget. + + Args: + messages: List of chat message dicts + token_budget: Max tokens (uses strategy default if None) + + Returns: + Compacted message list + """ + ... + + +@dataclass +class NoCompactionStrategy: + """Baseline: no compaction, context grows unbounded. + + Use this for benchmarking to see how context grows without management. + """ + + def compact( + self, + messages: list[dict[str, Any]], + token_budget: int | None = None, + ) -> list[dict[str, Any]]: + """Return messages unchanged.""" + return messages + + +@dataclass +class HeadTailStrategy: + """Token-aware head+tail compaction. + + Preserves: + - Head: System prompt, initial user message (critical context) + - Tail: Recent tool calls and results (working memory) + + Drops middle messages when over budget, respecting atomic groups + (tool calls and their results must stay together). + + This is the recommended strategy for most use cases. + """ + + head_ratio: float = 0.2 # 20% for head by default + token_budget: int = DEFAULT_TOKEN_BUDGET + model: str = "gpt-4o" + + # Statistics + compaction_count: int = field(default=0, repr=False) + total_tokens_saved: int = field(default=0, repr=False) + + def _find_atomic_groups( + self, messages: list[dict[str, Any]] + ) -> list[tuple[int, ...]]: + """Group tool_call messages with their results. + + OpenAI requires every tool_call to have a corresponding result. + This ensures we never split a tool call from its results. + + Returns list of tuples, where each tuple contains indices that + must stay together. + """ + groups: list[tuple[int, ...]] = [] + i = 0 + + while i < len(messages): + msg = messages[i] + + if msg.get("tool_calls"): + # This message has tool calls - find all results + call_ids = {tc.get("id") for tc in msg["tool_calls"] if tc.get("id")} + group_indices = [i] + + # Look ahead for results + j = i + 1 + while j < len(messages) and call_ids: + if messages[j].get("role") == "tool": + tool_call_id = messages[j].get("tool_call_id") + if tool_call_id in call_ids: + group_indices.append(j) + call_ids.remove(tool_call_id) + j += 1 + + groups.append(tuple(group_indices)) + i = max(group_indices) + 1 if group_indices else i + 1 + else: + groups.append((i,)) + i += 1 + + return groups + + def compact( + self, + messages: list[dict[str, Any]], + token_budget: int | None = None, + ) -> list[dict[str, Any]]: + """Compact if over budget.""" + if not messages: + return messages + + budget = token_budget or self.token_budget + encoder = get_encoder(self.model) + current_tokens = count_messages_tokens(messages, self.model) + + if current_tokens <= budget: + return messages + + # COMPACTION NEEDED + self.compaction_count += 1 + + groups = self._find_atomic_groups(messages) + head_budget = int(budget * self.head_ratio) + tail_budget = budget - head_budget + + # Fill head from start + head_groups: list[tuple[int, ...]] = [] + head_tokens = 0 + + for group in groups: + group_msgs = [messages[i] for i in group] + group_tokens = sum( + count_message_tokens(m, self.model, encoder) for m in group_msgs + ) + + if head_tokens + group_tokens <= head_budget: + head_groups.append(group) + head_tokens += group_tokens + else: + break + + # Fill tail from end (skip head groups) + remaining_groups = groups[len(head_groups) :] + tail_groups: list[tuple[int, ...]] = [] + tail_tokens = 0 + + for group in reversed(remaining_groups): + group_msgs = [messages[i] for i in group] + group_tokens = sum( + count_message_tokens(m, self.model, encoder) for m in group_msgs + ) + + if tail_tokens + group_tokens <= tail_budget: + tail_groups.insert(0, group) + tail_tokens += group_tokens + else: + break + + # Build compacted list + kept_indices: set[int] = set() + for group in head_groups + tail_groups: + kept_indices.update(group) + + compacted = [messages[i] for i in sorted(kept_indices)] + + # Track savings + compacted_tokens = count_messages_tokens(compacted, self.model) + self.total_tokens_saved += current_tokens - compacted_tokens + + return compacted + + +@dataclass +class SlidingWindowStrategy: + """Keep only recent messages within budget. + + Always preserves the system message (if present) plus the most + recent messages that fit in the budget. Respects atomic groups + (tool calls and their results must stay together). + + Simpler than HeadTailStrategy but may lose important early context. + """ + + token_budget: int = DEFAULT_TOKEN_BUDGET + model: str = "gpt-4o" + + def _find_atomic_groups( + self, messages: list[dict[str, Any]] + ) -> list[tuple[int, ...]]: + """Group tool_call messages with their results.""" + groups: list[tuple[int, ...]] = [] + i = 0 + + while i < len(messages): + msg = messages[i] + + if msg.get("tool_calls"): + call_ids = {tc.get("id") for tc in msg["tool_calls"] if tc.get("id")} + group_indices = [i] + + j = i + 1 + while j < len(messages) and call_ids: + if messages[j].get("role") == "tool": + tool_call_id = messages[j].get("tool_call_id") + if tool_call_id in call_ids: + group_indices.append(j) + call_ids.remove(tool_call_id) + j += 1 + + groups.append(tuple(group_indices)) + i = max(group_indices) + 1 if group_indices else i + 1 + else: + groups.append((i,)) + i += 1 + + return groups + + def compact( + self, + messages: list[dict[str, Any]], + token_budget: int | None = None, + ) -> list[dict[str, Any]]: + """Keep system message + most recent messages within budget.""" + if not messages: + return messages + + budget = token_budget or self.token_budget + encoder = get_encoder(self.model) + + # Always keep system messages at the start + system_msgs: list[dict[str, Any]] = [] + non_system_start = 0 + + for i, msg in enumerate(messages): + if msg.get("role") == "system": + system_msgs.append(msg) + non_system_start = i + 1 + else: + break + + other_msgs = messages[non_system_start:] + + system_tokens = sum( + count_message_tokens(m, self.model, encoder) for m in system_msgs + ) + remaining_budget = budget - system_tokens + + if remaining_budget <= 0: + return system_msgs + + # Check if we need to compact + other_tokens = sum( + count_message_tokens(m, self.model, encoder) for m in other_msgs + ) + if other_tokens <= remaining_budget: + return messages # No compaction needed + + # Find atomic groups in other messages + groups = self._find_atomic_groups(other_msgs) + + # Fill from end, respecting atomic groups + kept_groups: list[tuple[int, ...]] = [] + kept_tokens = 0 + + for group in reversed(groups): + group_msgs = [other_msgs[i] for i in group] + group_tokens = sum( + count_message_tokens(m, self.model, encoder) for m in group_msgs + ) + + if kept_tokens + group_tokens <= remaining_budget: + kept_groups.insert(0, group) + kept_tokens += group_tokens + else: + break + + # Build result from kept groups + kept_indices: set[int] = set() + for group in kept_groups: + kept_indices.update(group) + + result = [other_msgs[i] for i in sorted(kept_indices)] + + return system_msgs + result + + +@dataclass +class SummarizationStrategy: + """Summarize old messages instead of dropping them. + + When over budget, this strategy: + 1. Keeps: System message + initial user message (head) + 2. Keeps: Most recent messages (tail) + 3. Summarizes: Everything in between into a single "context so far" message + + This preserves critical state (files read, findings, progress) that would + otherwise be lost with simple truncation strategies. + + Note: Requires an async summarization function to be provided. + """ + + head_messages: int = 2 # Keep first N messages + tail_messages: int = 4 # Keep last N messages + summary_max_tokens: int = 1000 + token_budget: int = DEFAULT_TOKEN_BUDGET + model: str = "gpt-4o" + + # Async function to generate summaries (must be set before use) + summarize_fn: Any = field(default=None, repr=False) + + # Statistics + compaction_count: int = field(default=0, repr=False) + total_tokens_saved: int = field(default=0, repr=False) + + def _find_safe_split_points( + self, messages: list[dict[str, Any]] + ) -> tuple[int, int]: + """Find safe points to split messages without breaking tool call/result pairs. + + Returns (head_end, tail_start) indices where it's safe to summarize between. + """ + groups: list[tuple[int, int]] = [] # (start, end) indices + i = 0 + + while i < len(messages): + msg = messages[i] + if msg.get("tool_calls"): + call_ids = {tc.get("id") for tc in msg["tool_calls"] if tc.get("id")} + end = i + j = i + 1 + while j < len(messages) and call_ids: + if messages[j].get("role") == "tool": + tool_call_id = messages[j].get("tool_call_id") + if tool_call_id in call_ids: + call_ids.discard(tool_call_id) + end = j + j += 1 + groups.append((i, end + 1)) + i = end + 1 + else: + groups.append((i, i + 1)) + i += 1 + + # Find safe head end (after self.head_messages worth of groups) + head_end = 0 + for idx, (_start, end) in enumerate(groups): + if idx < self.head_messages: + head_end = end + else: + break + + # Find safe tail start (before last self.tail_messages groups) + tail_start = len(messages) + tail_groups = min(self.tail_messages, len(groups)) + if tail_groups > 0 and len(groups) > tail_groups: + tail_start = groups[-tail_groups][0] + + # Ensure we don't overlap + if head_end >= tail_start: + return len(messages), len(messages) + + return head_end, tail_start + + def _extract_key_info(self, messages: list[dict[str, Any]]) -> str: + """Extract key info without LLM (fallback).""" + files_read: set[str] = set() + key_findings: list[str] = [] + + for msg in messages: + if msg.get("role") == "tool" and msg.get("name") == "read_file": + files_read.add(msg.get("name") or "file") + if msg.get("role") == "assistant" and msg.get("content"): + content = msg["content"] + if isinstance(content, str) and len(content) < 200: + key_findings.append(content) + + parts: list[str] = [] + if files_read: + parts.append(f"Files accessed: {', '.join(files_read)}") + if key_findings: + parts.append(f"Key points: {'; '.join(key_findings[:5])}") + + return "\n".join(parts) if parts else "Previous context was processed." + + def compact( + self, + messages: list[dict[str, Any]], + token_budget: int | None = None, + ) -> list[dict[str, Any]]: + """Summarize middle messages if over budget. + + Note: This is synchronous and uses simple extraction. + For LLM-based summarization, use compact_async(). + """ + if not messages: + return messages + + budget = token_budget or self.token_budget + current_tokens = count_messages_tokens(messages, self.model) + + if current_tokens <= budget: + return messages + + self.compaction_count += 1 + + head_end, tail_start = self._find_safe_split_points(messages) + + head = messages[:head_end] + tail = messages[tail_start:] + middle = messages[head_end:tail_start] + + if not middle: + return messages + + # Extract key info without LLM + summary_text = self._extract_key_info(middle) + + summary_message = { + "role": "user", + "content": f"[CONTEXT SUMMARY - Previous {len(middle)} messages compressed]\n\n{summary_text}\n\n[END SUMMARY - Continue from here]", + } + + compacted = head + [summary_message] + tail + + compacted_tokens = count_messages_tokens(compacted, self.model) + self.total_tokens_saved += current_tokens - compacted_tokens + + return compacted + + async def compact_async( + self, + messages: list[dict[str, Any]], + token_budget: int | None = None, + ) -> list[dict[str, Any]]: + """Async version that can use LLM for summarization.""" + if not messages: + return messages + + budget = token_budget or self.token_budget + current_tokens = count_messages_tokens(messages, self.model) + + if current_tokens <= budget: + return messages + + self.compaction_count += 1 + + head_end, tail_start = self._find_safe_split_points(messages) + + head = messages[:head_end] + tail = messages[tail_start:] + middle = messages[head_end:tail_start] + + if not middle: + return messages + + # Generate summary + if self.summarize_fn: + try: + summary_text = await self.summarize_fn(middle, self.summary_max_tokens) + except Exception: + summary_text = self._extract_key_info(middle) + else: + summary_text = self._extract_key_info(middle) + + summary_message = { + "role": "user", + "content": f"""[CONTEXT CHECKPOINT - Your previous work has been summarized below] + +{summary_text} + +--- +IMPORTANT: Continue from where you left off. Do not repeat work already done.""", + } + + compacted = head + [summary_message] + tail + + compacted_tokens = count_messages_tokens(compacted, self.model) + self.total_tokens_saved += current_tokens - compacted_tokens + + return compacted diff --git a/src/flow/harness/compaction/tokenizer.py b/src/flow/harness/compaction/tokenizer.py new file mode 100644 index 0000000000000000000000000000000000000000..999ed72b318981559706683151f920c3fce95433 --- /dev/null +++ b/src/flow/harness/compaction/tokenizer.py @@ -0,0 +1,131 @@ +# Copyright (c) Microsoft. All rights reserved. +"""Shared tiktoken wrapper for consistent token counting across frameworks.""" + +from __future__ import annotations + +from typing import Any + +import tiktoken + +# Cache encoders to avoid repeated initialization +_ENCODER_CACHE: dict[str, tiktoken.Encoding] = {} + +# Default encoding for unknown models +DEFAULT_ENCODING = "cl100k_base" + + +def get_encoder(model: str = "gpt-4o") -> tiktoken.Encoding: + """Get tiktoken encoder for a model. + + Args: + model: Model name (e.g., "gpt-4o", "gpt-4", "gpt-3.5-turbo") + + Returns: + tiktoken Encoding instance + """ + if model in _ENCODER_CACHE: + return _ENCODER_CACHE[model] + + try: + encoder = tiktoken.encoding_for_model(model) + except KeyError: + # Fallback for unknown models (Claude, etc.) + encoder = tiktoken.get_encoding(DEFAULT_ENCODING) + + _ENCODER_CACHE[model] = encoder + return encoder + + +def count_tokens( + text: str, + model: str = "gpt-4o", + encoder: tiktoken.Encoding | None = None, +) -> int: + """Count tokens in a text string. + + Args: + text: The text to count tokens for + model: Model name for encoding selection + encoder: Optional pre-fetched encoder (for performance) + + Returns: + Number of tokens + """ + if encoder is None: + encoder = get_encoder(model) + return len(encoder.encode(text)) + + +def count_message_tokens( + message: dict[str, Any], + model: str = "gpt-4o", + encoder: tiktoken.Encoding | None = None, +) -> int: + """Count tokens in a chat message dict. + + Handles: + - role overhead (~4 tokens per message) + - content text + - tool_calls (name + arguments) + - tool results + + Args: + message: Chat message dict with role, content, etc. + model: Model name for encoding selection + encoder: Optional pre-fetched encoder + + Returns: + Approximate token count for the message + """ + if encoder is None: + encoder = get_encoder(model) + + total = 4 # Role overhead (approximate) + + # Content + content = message.get("content") + if content: + if isinstance(content, str): + total += len(encoder.encode(content)) + elif isinstance(content, list): + # Handle structured content (text blocks, etc.) + for item in content: + if isinstance(item, dict) and "text" in item: + total += len(encoder.encode(item["text"])) + + # Tool calls + tool_calls = message.get("tool_calls") + if tool_calls: + for tc in tool_calls: + total += 4 # Tool call overhead + if isinstance(tc, dict): + name = tc.get("name") or tc.get("function", {}).get("name", "") + args = tc.get("arguments") or tc.get("function", {}).get("arguments", "") + else: + # Handle object-style tool calls + name = getattr(tc, "name", "") + args = getattr(tc, "arguments", "") + + if name: + total += len(encoder.encode(name)) + if args: + total += len(encoder.encode(args)) + + return total + + +def count_messages_tokens( + messages: list[dict[str, Any]], + model: str = "gpt-4o", +) -> int: + """Count total tokens across all messages. + + Args: + messages: List of chat message dicts + model: Model name for encoding selection + + Returns: + Total token count + """ + encoder = get_encoder(model) + return sum(count_message_tokens(m, model, encoder) for m in messages) diff --git a/src/flow/harness/langgraph/__init__.py b/src/flow/harness/langgraph/__init__.py index 18e1c62bdcdfb881f55388a2f7cbffb58e72bccc..596d61438299f2d7470bcc7033004fd9d9d43715 100644 --- a/src/flow/harness/langgraph/__init__.py +++ b/src/flow/harness/langgraph/__init__.py @@ -19,7 +19,11 @@ Usage: print(event.type, event.content) """ -from flow.harness.langgraph.compaction import create_compaction_hook +from flow.harness.langgraph.compaction import ( + create_compaction_hook, + create_head_tail_hook, + create_sliding_window_hook, +) from flow.harness.langgraph.harness import LangGraphHarness from flow.harness.langgraph.otel_callback import OTelCallbackHandler from flow.harness.langgraph.wrappers import build_langgraph_tools, wrap_for_langgraph @@ -33,5 +37,7 @@ __all__ = [ "OTelCallbackHandler", "build_langgraph_tools", "create_compaction_hook", + "create_head_tail_hook", + "create_sliding_window_hook", "wrap_for_langgraph", ] diff --git a/src/flow/harness/langgraph/compaction.py b/src/flow/harness/langgraph/compaction.py index 5cd6f8af14b007142be816f6a6608e400bcda04e..a549793bda85ed13a11cb00a0f2809ff1d29c9cc 100644 --- a/src/flow/harness/langgraph/compaction.py +++ b/src/flow/harness/langgraph/compaction.py @@ -1,51 +1,219 @@ -"""Message compaction for LangGraph. +# Copyright (c) Microsoft. All rights reserved. +"""Token-aware message compaction for LangGraph. -Provides a pre-model hook that implements head-tail message compaction, -similar to MAF's HeadTailCompactingChatMessageStore. +Provides pre-model hooks that implement token-based message compaction, +ensuring safety against large messages that could exceed LLM context limits. """ from __future__ import annotations from typing import Any -__all__ = ["create_compaction_hook"] +from flow.harness.compaction import ( + HeadTailStrategy, + SlidingWindowStrategy, +) +__all__ = [ + "create_compaction_hook", + "create_head_tail_hook", + "create_sliding_window_hook", +] -def create_compaction_hook(head_size: int, tail_size: int): - """Create a pre-model hook for message compaction. +# Default token budget (safe for GPT-4o, Claude 3.5, etc.) +DEFAULT_TOKEN_BUDGET = 200_000 - This hook compacts messages by keeping the first `head_size` messages - and the last `tail_size` messages, dropping the middle. + +def _langchain_msg_to_dict(msg: Any) -> dict[str, Any]: + """Convert LangChain message to dict format for compaction strategies.""" + if isinstance(msg, dict): + return msg + + # Handle LangChain message types + result: dict[str, Any] = {} + + # Get role from type + msg_type = getattr(msg, "type", None) + if msg_type == "human": + result["role"] = "user" + elif msg_type == "ai": + result["role"] = "assistant" + elif msg_type == "system": + result["role"] = "system" + elif msg_type == "tool": + result["role"] = "tool" + result["tool_call_id"] = getattr(msg, "tool_call_id", None) + else: + result["role"] = msg_type or "user" + + # Get content + content = getattr(msg, "content", "") + result["content"] = content + + # Get tool calls (for AIMessage) + tool_calls = getattr(msg, "tool_calls", None) + if tool_calls: + result["tool_calls"] = [ + { + "id": tc.get("id") if isinstance(tc, dict) else getattr(tc, "id", None), + "function": { + "name": tc.get("name") if isinstance(tc, dict) else getattr(tc, "name", ""), + "arguments": str(tc.get("args", {})) if isinstance(tc, dict) else str(getattr(tc, "args", {})), + }, + } + for tc in tool_calls + ] + + return result + + +def _dict_to_langchain_msg(msg_dict: dict[str, Any], original_msg: Any) -> Any: + """Preserve original LangChain message (we don't convert back).""" + # For compaction, we return the original message objects + # The strategy just tells us which indices to keep + return original_msg + + +def create_compaction_hook( + head_ratio: float = 0.2, + token_budget: int = DEFAULT_TOKEN_BUDGET, + model: str = "gpt-4o", +): + """Create a pre-model hook for token-aware head+tail compaction. + + This hook compacts messages by keeping head messages (system prompt, + initial context) and tail messages (recent work), dropping the middle + when token count exceeds the budget. Args: - head_size: Number of messages to keep from the start - tail_size: Number of messages to keep from the end + head_ratio: Fraction of budget for head messages (0.2 = 20%) + token_budget: Max tokens before compaction triggers + model: Model name for tokenizer selection Returns: A function that can be used as a pre_model_hook in create_react_agent Example: - hook = create_compaction_hook(10, 40) + hook = create_compaction_hook(head_ratio=0.2, token_budget=200000) graph = create_react_agent( model=model, tools=tools, pre_model_hook=hook, ) """ + strategy = HeadTailStrategy( + head_ratio=head_ratio, + token_budget=token_budget, + model=model, + ) def compact_messages(state: dict[str, Any]) -> dict[str, Any]: - """Compact messages keeping head and tail, dropping middle.""" + """Compact messages using token-aware head+tail strategy.""" messages = state.get("messages", []) - total = len(messages) - # No compaction needed if within limits - if total <= head_size + tail_size: + if not messages: return {"llm_input_messages": messages} - # Keep head and tail - head = messages[:head_size] - tail = messages[-tail_size:] + # Convert to dict format for strategy + msg_dicts = [_langchain_msg_to_dict(m) for m in messages] + + # Apply compaction + compacted_dicts = strategy.compact(msg_dicts) + + # Map back to original message objects + # We need to find which original messages correspond to kept dicts + compacted_messages = [] + # Note: dict_to_idx was used for ID-based matching but content matching is more reliable + + # Build index set of kept messages + kept_indices = set() + for cd in compacted_dicts: + for i, md in enumerate(msg_dicts): + # Compare by content since we can't rely on identity + if ( + md.get("role") == cd.get("role") + and md.get("content") == cd.get("content") + and i not in kept_indices + ): + kept_indices.add(i) + break + + compacted_messages = [messages[i] for i in sorted(kept_indices)] + + return {"llm_input_messages": compacted_messages} + + return compact_messages + + +def create_head_tail_hook( + head_ratio: float = 0.2, + token_budget: int = DEFAULT_TOKEN_BUDGET, + model: str = "gpt-4o", +): + """Alias for create_compaction_hook with head+tail strategy.""" + return create_compaction_hook( + head_ratio=head_ratio, + token_budget=token_budget, + model=model, + ) + + +def create_sliding_window_hook( + token_budget: int = DEFAULT_TOKEN_BUDGET, + model: str = "gpt-4o", +): + """Create a pre-model hook for token-aware sliding window compaction. + + This hook keeps the system message plus the most recent messages + that fit within the token budget. + + Args: + token_budget: Max tokens for context window + model: Model name for tokenizer selection + + Returns: + A function that can be used as a pre_model_hook in create_react_agent + + Example: + hook = create_sliding_window_hook(token_budget=100000) + graph = create_react_agent( + model=model, + tools=tools, + pre_model_hook=hook, + ) + """ + strategy = SlidingWindowStrategy( + token_budget=token_budget, + model=model, + ) + + def compact_messages(state: dict[str, Any]) -> dict[str, Any]: + """Compact messages using sliding window strategy.""" + messages = state.get("messages", []) + + if not messages: + return {"llm_input_messages": messages} + + # Convert to dict format for strategy + msg_dicts = [_langchain_msg_to_dict(m) for m in messages] + + # Apply compaction + compacted_dicts = strategy.compact(msg_dicts) + + # Map back to original message objects + kept_indices = set() + for cd in compacted_dicts: + for i, md in enumerate(msg_dicts): + if ( + md.get("role") == cd.get("role") + and md.get("content") == cd.get("content") + and i not in kept_indices + ): + kept_indices.add(i) + break + + compacted_messages = [messages[i] for i in sorted(kept_indices)] - return {"llm_input_messages": head + tail} + return {"llm_input_messages": compacted_messages} return compact_messages diff --git a/src/flow/harness/langgraph/harness.py b/src/flow/harness/langgraph/harness.py index 7debb6dea97d180770e44704bce8e792001fa01f..5a3fd141e0ebde720eed7166b1e1d172585d492f 100644 --- a/src/flow/harness/langgraph/harness.py +++ b/src/flow/harness/langgraph/harness.py @@ -10,7 +10,7 @@ import logging import uuid from collections.abc import AsyncIterator from pathlib import Path -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING, Any, ClassVar from opentelemetry import trace @@ -50,6 +50,12 @@ class LangGraphHarness(BaseHarness): print(event.type, event.content) """ + # Framework metadata + framework_name: ClassVar[str] = "langgraph" + framework_label: ClassVar[str] = "LangGraph" + framework_description: ClassVar[str] = "Graph-based workflows with state management" + supported_compaction_strategies: ClassVar[list[str]] = ["head_tail", "sliding_window", "none"] + @classmethod def from_agent(cls, agent: Agent, workspace: Path) -> LangGraphHarness: """Create a LangGraph harness from an Agent spec. @@ -61,11 +67,12 @@ class LangGraphHarness(BaseHarness): Returns: Configured LangGraphHarness instance """ + from langgraph.checkpoint.memory import InMemorySaver + from langgraph.prebuilt import create_react_agent + from flow.experiments.models import resolve_tools from flow.harness.langgraph.compaction import create_compaction_hook from flow.harness.langgraph.wrappers import build_langgraph_tools - from langgraph.checkpoint.memory import InMemorySaver - from langgraph.prebuilt import create_react_agent # Build tools (skip sub_agent - MAF-specific) tools_spec = resolve_tools(agent.tools) @@ -234,7 +241,7 @@ class LangGraphHarness(BaseHarness): mode, data = chunk if mode == "messages": - msg_chunk, metadata = data + msg_chunk, _metadata = data # Text content if hasattr(msg_chunk, "content") and msg_chunk.content: diff --git a/src/flow/harness/maf/__init__.py b/src/flow/harness/maf/__init__.py index 1bc5011068236ff684e696e4afb1c6d79d9a7a28..40ed4fe024ebd4b9b2e19846d92be0dddcf3e7a0 100644 --- a/src/flow/harness/maf/__init__.py +++ b/src/flow/harness/maf/__init__.py @@ -12,7 +12,7 @@ from flow.harness.registry import register register("maf", MAFHarness) __all__ = [ - "create_agent", "HeadTailCompactingChatMessageStore", "MAFHarness", + "create_agent", ] diff --git a/src/flow/harness/maf/agent.py b/src/flow/harness/maf/agent.py index df18e9e0ebad3cf0e0bb243c3d283e71f15d5642..b4ffcf20b99385ea1b7bc560a5a5e278de5946f7 100644 --- a/src/flow/harness/maf/agent.py +++ b/src/flow/harness/maf/agent.py @@ -148,15 +148,19 @@ def create_agent( # Create message store factory if compaction is enabled message_store_factory = None if enable_compaction: + # Convert head/tail message counts to head_ratio for token-based compaction + # head_ratio = head_size / (head_size + tail_size) + total_size = compaction_head_size + compaction_tail_size + head_ratio = compaction_head_size / total_size if total_size > 0 else 0.2 + def create_compacting_store() -> HeadTailCompactingChatMessageStore: return HeadTailCompactingChatMessageStore( - head_size=compaction_head_size, - tail_size=compaction_tail_size, + head_ratio=head_ratio, ) message_store_factory = create_compacting_store logger.debug( - f"Message compaction enabled: head={compaction_head_size}, tail={compaction_tail_size}" + f"Message compaction enabled: head={compaction_head_size}, tail={compaction_tail_size}, head_ratio={head_ratio:.2f}" ) # Determine if memory is enabled for instructions diff --git a/src/flow/harness/maf/harness.py b/src/flow/harness/maf/harness.py index af535abe00a2be8c7e5c35c73c874f9b1f22d8b6..4bd031a8a8ebd91decd2b02471f630e119784163 100644 --- a/src/flow/harness/maf/harness.py +++ b/src/flow/harness/maf/harness.py @@ -9,7 +9,7 @@ import logging import uuid from collections.abc import AsyncIterator from pathlib import Path -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING, Any, ClassVar from flow.harness.base import BaseHarness, Event, EventType @@ -67,13 +67,19 @@ class MAFHarness(BaseHarness): >>> harness = MAFHarness.from_agent(agent, workspace=Path("/tmp")) """ + # Framework metadata + framework_name: ClassVar[str] = "maf" + framework_label: ClassVar[str] = "Microsoft Agent Framework" + framework_description: ClassVar[str] = "Default agent implementation with ChatAgent" + supported_compaction_strategies: ClassVar[list[str]] = ["head_tail", "sliding_window", "none"] + @classmethod def from_agent( cls, - agent: "Agent", + agent: Agent, workspace: Path, - llm_config: "LLMClientConfig | None" = None, - ) -> "MAFHarness": + llm_config: LLMClientConfig | None = None, + ) -> MAFHarness: """Create a MAFHarness from an Agent definition. Args: @@ -126,7 +132,7 @@ class MAFHarness(BaseHarness): def __init__( self, - agent: "ChatAgent | None" = None, + agent: ChatAgent | None = None, **create_agent_kwargs: Any, ) -> None: """Initialize the harness. diff --git a/src/flow/harness/maf/message_store.py b/src/flow/harness/maf/message_store.py index b5ad9581f6d168e360f9ee5a9146db5fb0d97daa..a1f46df9c0ed65c4f4877169f2c2b6764c0e4093 100644 --- a/src/flow/harness/maf/message_store.py +++ b/src/flow/harness/maf/message_store.py @@ -1,21 +1,82 @@ -"""Message store implementations for Microsoft Agent Framework. +# Copyright (c) Microsoft. All rights reserved. +"""Token-aware message store for Microsoft Agent Framework. -Provides ChatMessageStoreProtocol implementations for context management. +Provides ChatMessageStoreProtocol implementations with token-based compaction +to ensure safety against large messages that could exceed LLM context limits. """ from collections.abc import MutableMapping, Sequence from typing import TYPE_CHECKING, Any +from flow.harness.compaction import HeadTailStrategy +from flow.harness.compaction.tokenizer import get_encoder + +_ = (HeadTailStrategy, get_encoder) # Used for external access via this module + if TYPE_CHECKING: from agent_framework import ChatMessage +# Default token budget (safe for GPT-4o, Claude 3.5, etc.) +DEFAULT_TOKEN_BUDGET = 200_000 + + +def _chat_message_to_dict(msg: "ChatMessage") -> dict[str, Any]: + """Convert ChatMessage to dict format for token counting.""" + return msg.to_dict() + + +def _count_chat_message_tokens(msg: "ChatMessage", model: str = "gpt-4o") -> int: + """Count tokens in a ChatMessage.""" + msg_dict = _chat_message_to_dict(msg) + encoder = get_encoder(model) + + tokens = 0 + # Count role + if "role" in msg_dict: + tokens += len(encoder.encode(str(msg_dict["role"]))) + + # Count content + content = msg_dict.get("content") + if isinstance(content, str): + tokens += len(encoder.encode(content)) + elif isinstance(content, list): + for item in content: + if isinstance(item, dict): + if "text" in item: + tokens += len(encoder.encode(str(item["text"]))) + elif "content" in item: + tokens += len(encoder.encode(str(item["content"]))) + elif isinstance(item, str): + tokens += len(encoder.encode(item)) + + # Count tool calls + tool_calls = msg_dict.get("tool_calls", []) + for tc in tool_calls: + if isinstance(tc, dict): + if "function" in tc: + func = tc["function"] + if isinstance(func, dict): + tokens += len(encoder.encode(func.get("name", ""))) + tokens += len(encoder.encode(func.get("arguments", ""))) + + # Base overhead per message + tokens += 4 + + return tokens + + +class TokenAwareChatMessageStore: + """A token-aware message store for Agent Framework ChatMessage. -class HeadTailCompactingChatMessageStore: - """A compacting message store that works directly with Agent Framework ChatMessage. + This store implements ChatMessageStoreProtocol and uses token counting + to trigger compaction, ensuring safety against large messages that could + exceed LLM context limits. - This store implements ChatMessageStoreProtocol and keeps the first N messages - (head) and last M messages (tail), dropping middle messages to prevent - context overflow in long conversations. + The compaction strategy: + - Keeps head messages (system prompt, initial context) based on head_ratio + - Keeps tail messages (recent work, current state) + - Drops middle messages when token count exceeds budget + - Respects atomic groups (tool calls + results must stay together) IMPORTANT: This store preserves full ChatMessage objects including: - FunctionCallContent (tool calls) @@ -24,44 +85,44 @@ class HeadTailCompactingChatMessageStore: This is critical because OpenAI's API requires tool results to immediately follow their corresponding tool calls. - - The compaction strategy: - - Keeps the first N messages (task context, initial instructions) - - Keeps the last M messages (recent work, current state) - - Drops middle messages to prevent context overflow """ def __init__( self, messages: Sequence["ChatMessage"] | None = None, - head_size: int = 10, - tail_size: int = 40, + head_ratio: float = 0.2, + token_budget: int = DEFAULT_TOKEN_BUDGET, + model: str = "gpt-4o", ) -> None: - """Initialize the compacting store. + """Initialize the token-aware store. Args: messages: Initial messages to store - head_size: Number of initial messages to keep - tail_size: Number of recent messages to keep + head_ratio: Fraction of budget for head messages (0.2 = 20%) + token_budget: Max tokens before compaction triggers + model: Model name for tokenizer selection """ - if head_size < 0: - raise ValueError("head_size must be non-negative") - if tail_size < 0: - raise ValueError("tail_size must be non-negative") - - self._messages: list["ChatMessage"] = list(messages) if messages else [] - self._head_size = head_size - self._tail_size = tail_size + if head_ratio < 0 or head_ratio > 1: + raise ValueError("head_ratio must be between 0 and 1") + if token_budget < 1000: + raise ValueError("token_budget must be at least 1000") + + self._messages: list[ChatMessage] = list(messages) if messages else [] + self._head_ratio = head_ratio + self._token_budget = token_budget + self._model = model + self._compaction_count = 0 + self._total_tokens_saved = 0 @property - def head_size(self) -> int: - """Number of messages kept from the beginning.""" - return self._head_size + def head_ratio(self) -> float: + """Fraction of budget for head messages.""" + return self._head_ratio @property - def tail_size(self) -> int: - """Number of messages kept from the end.""" - return self._tail_size + def token_budget(self) -> int: + """Max tokens before compaction triggers.""" + return self._token_budget @property def total_messages(self) -> int: @@ -69,16 +130,126 @@ class HeadTailCompactingChatMessageStore: return len(self._messages) @property - def compacted_count(self) -> int: - """Number of messages that would be returned by list_messages().""" - total = len(self._messages) - max_kept = self._head_size + self._tail_size - return min(total, max_kept) + def compaction_count(self) -> int: + """Number of times compaction has been triggered.""" + return self._compaction_count @property - def dropped_count(self) -> int: - """Number of messages dropped during compaction.""" - return max(0, self.total_messages - self.compacted_count) + def total_tokens_saved(self) -> int: + """Total tokens saved through compaction.""" + return self._total_tokens_saved + + def _count_tokens(self) -> int: + """Count total tokens in all messages.""" + return sum(_count_chat_message_tokens(m, self._model) for m in self._messages) + + def _find_atomic_groups( + self, messages: list["ChatMessage"] + ) -> list[tuple[int, ...]]: + """Group tool_call messages with their results. + + OpenAI requires every tool_call to have a corresponding result. + This ensures we never split a tool call from its results. + """ + groups: list[tuple[int, ...]] = [] + i = 0 + + while i < len(messages): + msg = messages[i] + msg_dict = _chat_message_to_dict(msg) + + if msg_dict.get("tool_calls"): + # This message has tool calls - find all results + call_ids = { + tc.get("id") for tc in msg_dict["tool_calls"] if tc.get("id") + } + group_indices = [i] + + # Look ahead for results + j = i + 1 + while j < len(messages) and call_ids: + next_dict = _chat_message_to_dict(messages[j]) + if next_dict.get("role") == "tool": + tool_call_id = next_dict.get("tool_call_id") + if tool_call_id in call_ids: + group_indices.append(j) + call_ids.remove(tool_call_id) + j += 1 + + groups.append(tuple(group_indices)) + i = max(group_indices) + 1 if group_indices else i + 1 + else: + groups.append((i,)) + i += 1 + + return groups + + def _compact_messages( + self, messages: list["ChatMessage"] + ) -> list["ChatMessage"]: + """Apply head+tail compaction to messages.""" + if not messages: + return messages + + current_tokens = sum( + _count_chat_message_tokens(m, self._model) for m in messages + ) + + if current_tokens <= self._token_budget: + return messages + + # COMPACTION NEEDED + self._compaction_count += 1 + + groups = self._find_atomic_groups(messages) + head_budget = int(self._token_budget * self._head_ratio) + tail_budget = self._token_budget - head_budget + + # Fill head from start + head_groups: list[tuple[int, ...]] = [] + head_tokens = 0 + + for group in groups: + group_tokens = sum( + _count_chat_message_tokens(messages[i], self._model) for i in group + ) + + if head_tokens + group_tokens <= head_budget: + head_groups.append(group) + head_tokens += group_tokens + else: + break + + # Fill tail from end (skip head groups) + remaining_groups = groups[len(head_groups):] + tail_groups: list[tuple[int, ...]] = [] + tail_tokens = 0 + + for group in reversed(remaining_groups): + group_tokens = sum( + _count_chat_message_tokens(messages[i], self._model) for i in group + ) + + if tail_tokens + group_tokens <= tail_budget: + tail_groups.insert(0, group) + tail_tokens += group_tokens + else: + break + + # Build compacted list + kept_indices: set[int] = set() + for group in head_groups + tail_groups: + kept_indices.update(group) + + compacted = [messages[i] for i in sorted(kept_indices)] + + # Track savings + compacted_tokens = sum( + _count_chat_message_tokens(m, self._model) for m in compacted + ) + self._total_tokens_saved += current_tokens - compacted_tokens + + return compacted async def add_messages(self, messages: Sequence["ChatMessage"]) -> None: """Add messages to the store. @@ -91,38 +262,32 @@ class HeadTailCompactingChatMessageStore: self._messages.extend(messages) async def list_messages(self) -> list["ChatMessage"]: - """Get messages with head+tail compaction applied. + """Get messages with token-aware compaction applied. - Returns the first head_size messages plus the last tail_size messages. - If total messages <= head_size + tail_size, returns all messages. + Applies head+tail compaction if total tokens exceed budget. + Respects atomic groups (tool calls stay with their results). Returns: List of ChatMessage objects after compaction """ - total = len(self._messages) - max_kept = self._head_size + self._tail_size - - # No compaction needed - if total <= max_kept: - return list(self._messages) - - # Return head + tail - head = self._messages[: self._head_size] - tail = self._messages[-self._tail_size :] if self._tail_size > 0 else [] - - return head + tail + return self._compact_messages(self._messages) @classmethod async def deserialize( cls, serialized_store_state: MutableMapping[str, Any], **kwargs: Any, - ) -> "HeadTailCompactingChatMessageStore": + ) -> "TokenAwareChatMessageStore": """Create store from serialized state.""" from agent_framework import ChatMessage - head_size = kwargs.get("head_size", serialized_store_state.get("head_size", 10)) - tail_size = kwargs.get("tail_size", serialized_store_state.get("tail_size", 40)) + head_ratio = kwargs.get( + "head_ratio", serialized_store_state.get("head_ratio", 0.2) + ) + token_budget = kwargs.get( + "token_budget", serialized_store_state.get("token_budget", DEFAULT_TOKEN_BUDGET) + ) + model = kwargs.get("model", serialized_store_state.get("model", "gpt-4o")) messages_data = serialized_store_state.get("messages", []) messages = [ @@ -130,7 +295,12 @@ class HeadTailCompactingChatMessageStore: for m in messages_data ] - return cls(messages=messages, head_size=head_size, tail_size=tail_size) + return cls( + messages=messages, + head_ratio=head_ratio, + token_budget=token_budget, + model=model, + ) async def update_from_state( self, @@ -149,10 +319,12 @@ class HeadTailCompactingChatMessageStore: for m in messages_data ] - if "head_size" in serialized_store_state: - self._head_size = serialized_store_state["head_size"] - if "tail_size" in serialized_store_state: - self._tail_size = serialized_store_state["tail_size"] + if "head_ratio" in serialized_store_state: + self._head_ratio = serialized_store_state["head_ratio"] + if "token_budget" in serialized_store_state: + self._token_budget = serialized_store_state["token_budget"] + if "model" in serialized_store_state: + self._model = serialized_store_state["model"] async def serialize(self, **kwargs: Any) -> dict[str, Any]: """Serialize the store state. @@ -161,17 +333,23 @@ class HeadTailCompactingChatMessageStore: """ return { "messages": [m.to_dict() for m in self._messages], - "head_size": self._head_size, - "tail_size": self._tail_size, + "head_ratio": self._head_ratio, + "token_budget": self._token_budget, + "model": self._model, } @property - def stats(self) -> dict[str, int]: + def stats(self) -> dict[str, Any]: """Get compaction statistics.""" return { "total_messages": self.total_messages, - "compacted_count": self.compacted_count, - "dropped_count": self.dropped_count, - "head_size": self._head_size, - "tail_size": self._tail_size, + "current_tokens": self._count_tokens(), + "token_budget": self._token_budget, + "head_ratio": self._head_ratio, + "compaction_count": self._compaction_count, + "total_tokens_saved": self._total_tokens_saved, } + + +# Backwards compatibility alias +HeadTailCompactingChatMessageStore = TokenAwareChatMessageStore diff --git a/src/flow/harness/maf/tools/__init__.py b/src/flow/harness/maf/tools/__init__.py index 9eb3270d2b368d1d200bed69a6f27a435e5e3229..8791dc5d421bdb5426ebdff88af0416214798735 100644 --- a/src/flow/harness/maf/tools/__init__.py +++ b/src/flow/harness/maf/tools/__init__.py @@ -6,7 +6,7 @@ the to_maf_tool adapter. Available tools: - read_file, write_file, edit_file, multi_edit, glob_files, grep, ls -- bash, check_processes, python_repl +- bash, check_processes - think, todo_write, todo_read - memory, skills, task - web_search, web_fetch @@ -19,28 +19,49 @@ from pathlib import Path from typing import Any from flow.tools import ( - # Coding - read_file, write_file, edit_file, multi_edit, glob_files, grep, ls, + # Base + Tool, + Workspace, # Execution - bash, check_processes, python_repl, - # Planning - think, todo_write, todo_read, + bash, + check_processes, + create_skills_tool, + # Browsing + create_smol_web_search_tool, + create_task_tool, + create_visit_webpage_tool, + edit_file, + glob_files, + grep, + ls, # Memory - memory, create_memory_tool, - # Web - web_search, web_fetch, + memory, + multi_edit, # Notebooks - notebook_edit, notebook_read, + notebook_edit, + notebook_read, + # Coding + read_file, + # Workspace management + set_workspace, # Skills - skills, create_skills_tool, + skills, # Sub-agent - task, create_task_tool, - # Workspace management - set_workspace, Workspace, + task, + # File inspection + text_inspector, + # Planning + think, # Adapters to_maf_tool, - # Base - Tool, + todo_read, + todo_write, + visual_inspector, + web_fetch, + # Web + web_search, + wikipedia_search, + write_file, ) __all__ = [ @@ -93,7 +114,6 @@ def build_tools( # Execution "bash": bash, "check_processes": check_processes, - "python_repl": python_repl, # Planning "think": think, "todo_write": todo_write, @@ -110,6 +130,11 @@ def build_tools( "skills": skills, # Task/sub-agent (default instance) "task": task, + # Wikipedia search + "wikipedia_search": wikipedia_search, + # File inspection tools + "text_inspector": text_inspector, + "visual_inspector": visual_inspector, } tools: list[Callable[..., Coroutine[Any, Any, str]]] = [] @@ -128,10 +153,20 @@ def build_tools( tools.append(to_maf_tool(custom_task)) elif name == "skills" and config.get("additional_paths"): # Skills with custom paths - custom_skills = create_skills_tool( - project_path=Path(config["additional_paths"][0]) - ) + custom_skills = create_skills_tool(project_path=Path(config["additional_paths"][0])) tools.append(to_maf_tool(custom_skills)) + # Web search tool + elif name == "smol_web_search": + wst_max_results = config.get("wst_max_results", 10) + wst_engine = config.get("wst_engine", "duckduckgo") + custom_smol_web_search = create_smol_web_search_tool(max_results=wst_max_results, engine=wst_engine) + tools.append(to_maf_tool(custom_smol_web_search)) + + elif name == "visit_webpage": + vwp_max_output_length = config.get("vwp_max_output_length", 40000) + custom_visit_webpage = create_visit_webpage_tool(max_output_length=vwp_max_output_length) + tools.append(to_maf_tool(custom_visit_webpage)) + else: logger.warning(f"Unknown tool name: {name}. Skipping.") diff --git a/src/flow/harness/maf/wrappers.py b/src/flow/harness/maf/wrappers.py index cdc07a4679572c1e073b287d9656de1c8ef93926..1cef230866f65ea9dc60121ad2ab4d334f29037a 100644 --- a/src/flow/harness/maf/wrappers.py +++ b/src/flow/harness/maf/wrappers.py @@ -14,8 +14,8 @@ from collections.abc import Callable, Coroutine from pathlib import Path from typing import Any -from flow.tools import Tool, to_maf_tool from flow.harness.maf.tools import build_tools as build_maf_tools_impl +from flow.tools import Tool, to_maf_tool logger = logging.getLogger(__name__) diff --git a/src/flow/harness/miniagent/__init__.py b/src/flow/harness/miniagent/__init__.py index e13099601b126084f04f15277db41ada8e3af35d..01b274b219f36fa4fa3135c125739c72aa5ee34c 100644 --- a/src/flow/harness/miniagent/__init__.py +++ b/src/flow/harness/miniagent/__init__.py @@ -51,38 +51,38 @@ MiniAgent's tool loop: messages.extend(results) # Next iteration will compact again """ -from .agent import ChatAgent, AgentThread, AgentResponse, UsageStats, StreamEvent, StreamEventType -from .tool import Tool, tool -from .messages import ChatMessage, ToolCall, ToolResult +# Register with Flow's harness system +from flow.harness.registry import register + +from . import tools +from .agent import AgentResponse, AgentThread, ChatAgent, StreamEvent, StreamEventType, UsageStats +from .client import ChatClient, ChatCompletionResult, ClientConfig from .context import ( ContextStrategy, - NoCompactionStrategy, HeadTailStrategy, + NoCompactionStrategy, SlidingWindowStrategy, SummarizationStrategy, ) -from .client import ChatClient, ClientConfig, ChatCompletionResult +from .harness import MiniAgentHarness from .hooks import ( - Hooks, + AgentEndEvent, + AgentStartEvent, HookEvent, - PreToolUseEvent, - PreToolUseResult, + Hooks, + PostCompactEvent, + PostModelCallEvent, PostToolUseEvent, PostToolUseResult, - PreModelCallEvent, - PostModelCallEvent, PreCompactEvent, - PostCompactEvent, - AgentStartEvent, - AgentEndEvent, + PreModelCallEvent, + PreToolUseEvent, + PreToolUseResult, ) -from .instructions import get_instructions, INSTRUCTIONS +from .instructions import INSTRUCTIONS, get_instructions +from .messages import ChatMessage, ToolCall, ToolResult +from .tool import Tool, tool from .workspace import Workspace, get_workspace, set_workspace -from . import tools - -# Register with Flow's harness system -from flow.harness.registry import register -from .harness import MiniAgentHarness register("miniagent", MiniAgentHarness) diff --git a/src/flow/harness/miniagent/agent.py b/src/flow/harness/miniagent/agent.py index da23ee237aae02e0e42ad179d0433d168d54e423..21b43a84a75785de26647638976fbd1434cd5c6a 100644 --- a/src/flow/harness/miniagent/agent.py +++ b/src/flow/harness/miniagent/agent.py @@ -5,28 +5,29 @@ The key difference: context strategy is called BEFORE each LLM call in the tool loop, and the compacted list continues to the next iteration. """ +import json +from collections.abc import AsyncGenerator from dataclasses import dataclass, field -from typing import Any, AsyncGenerator from enum import Enum -import json +from typing import Any -from .messages import ChatMessage, ToolCall -from .tool import Tool from .client import ChatClient, ChatCompletionResult from .context import ContextStrategy, NoCompactionStrategy from .hooks import ( + AgentEndEvent, + AgentStartEvent, Hooks, - PreToolUseEvent, - PreToolUseResult, + PostCompactEvent, + PostModelCallEvent, PostToolUseEvent, PostToolUseResult, - PreModelCallEvent, - PostModelCallEvent, PreCompactEvent, - PostCompactEvent, - AgentStartEvent, - AgentEndEvent, + PreModelCallEvent, + PreToolUseEvent, + PreToolUseResult, ) +from .messages import ChatMessage, ToolCall +from .tool import Tool class StreamEventType(str, Enum): @@ -452,7 +453,7 @@ class ChatAgent: try: return await tool.invoke(**arguments) except Exception as e: - return f"Error executing {name}: {str(e)}" + return f"Error executing {name}: {e!s}" # === Hook emission methods === diff --git a/src/flow/harness/miniagent/client.py b/src/flow/harness/miniagent/client.py index c80b23040aac74cf070222fd7398164674edf8d4..3641719487b58434456c3f85beb572a9b1eb5b4c 100644 --- a/src/flow/harness/miniagent/client.py +++ b/src/flow/harness/miniagent/client.py @@ -4,9 +4,9 @@ Provides a unified interface for both OpenAI and Azure OpenAI APIs. Auto-detects configuration from environment variables. """ +import os from dataclasses import dataclass from typing import Any -import os # Load .env file if present (override=True to prefer .env over shell env) try: @@ -88,7 +88,7 @@ class ChatClient: def _create_client(self): """Create the appropriate async client.""" try: - from openai import AsyncOpenAI, AsyncAzureOpenAI + from openai import AsyncAzureOpenAI, AsyncOpenAI except ImportError: raise ImportError( "openai package is required. Install with: pip install openai" diff --git a/src/flow/harness/miniagent/context.py b/src/flow/harness/miniagent/context.py index 13706a4be3519c844a36756f1acd359d41b9c420..0c4a98fa39cbb3b9d5cbbe03d9a93ca9461a0387 100644 --- a/src/flow/harness/miniagent/context.py +++ b/src/flow/harness/miniagent/context.py @@ -5,8 +5,10 @@ Strategies are called BEFORE each LLM call, and the returned (potentially compacted) list continues to the next iteration. """ +import json from dataclasses import dataclass, field -from typing import Protocol, Any +from typing import Any, Protocol + import tiktoken from .messages import ChatMessage @@ -471,13 +473,12 @@ SUMMARY:""" if tc.name in ("read_file", "Read"): # Try to extract path from arguments try: - import json args = json.loads(tc.arguments) path = args.get("path") or args.get("file_path") or args.get("filename") if path: files.append(path) - except: - pass + except (json.JSONDecodeError, KeyError, TypeError): + pass # Skip malformed tool calls return list(dict.fromkeys(files)) # Remove duplicates, preserve order def _extract_key_info(self, messages: list[ChatMessage]) -> str: diff --git a/src/flow/harness/miniagent/harness.py b/src/flow/harness/miniagent/harness.py index 1e88716081829efbda0e314e512de4076775498c..1817fdf4c39d18d40d75762081b87d2f3381415e 100644 --- a/src/flow/harness/miniagent/harness.py +++ b/src/flow/harness/miniagent/harness.py @@ -10,7 +10,7 @@ import logging import uuid from collections.abc import AsyncIterator from pathlib import Path -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING, Any, ClassVar from flow.harness.base import BaseHarness, Event, EventType @@ -18,19 +18,21 @@ if TYPE_CHECKING: from flow.experiments.models import Agent from flow.llm import LLMClientConfig -from .agent import ChatAgent, AgentThread, StreamEvent, StreamEventType + from .client import ClientConfig + +from flow.tools import Tool + +from .agent import AgentThread, ChatAgent, StreamEvent, StreamEventType +from .client import ChatClient from .context import ( ContextStrategy, - NoCompactionStrategy, HeadTailStrategy, + NoCompactionStrategy, SlidingWindowStrategy, SummarizationStrategy, ) -from .client import ChatClient -from .otel import enable_instrumentation from .instructions import get_instructions - -from flow.tools import Tool +from .otel import enable_instrumentation logger = logging.getLogger(__name__) @@ -61,13 +63,21 @@ class MiniAgentHarness(BaseHarness): ... print(event) """ + # Framework metadata + framework_name: ClassVar[str] = "miniagent" + framework_label: ClassVar[str] = "MiniAgent" + framework_description: ClassVar[str] = "Token-aware context management with advanced compaction" + supported_compaction_strategies: ClassVar[list[str]] = [ + "head_tail", "sliding_window", "summarization", "none" + ] + @classmethod def from_agent( cls, - agent: "Agent", + agent: Agent, workspace: Path, - llm_config: "LLMClientConfig | None" = None, - ) -> "MiniAgentHarness": + llm_config: LLMClientConfig | None = None, + ) -> MiniAgentHarness: """Create a MiniAgentHarness from an Agent definition. Args: @@ -105,13 +115,13 @@ class MiniAgentHarness(BaseHarness): from .otel import create_otel_hooks otel_hooks = create_otel_hooks(model=config.model) - # Resolve instructions: explicit > preset > default "coding" + # Resolve instructions: explicit > preset > default "general" if agent.instructions: instructions = agent.instructions elif agent.instructions_preset: instructions = get_instructions(agent.instructions_preset) else: - instructions = get_instructions("coding") + instructions = get_instructions("general") chat_agent = ChatAgent( client=chat_client, @@ -126,8 +136,8 @@ class MiniAgentHarness(BaseHarness): @classmethod def _create_client_config_from_llm_config( - cls, llm_config: "LLMClientConfig" - ) -> "ClientConfig": + cls, llm_config: LLMClientConfig + ) -> ClientConfig: """Create MiniAgent ClientConfig from Flow LLMClientConfig. Args: @@ -137,6 +147,7 @@ class MiniAgentHarness(BaseHarness): MiniAgent ClientConfig """ from flow.llm import LLMProvider + from .client import ClientConfig match llm_config.provider: @@ -177,7 +188,7 @@ class MiniAgentHarness(BaseHarness): @classmethod def _create_client_config_from_dict( cls, llm_config: dict[str, Any] - ) -> "ClientConfig": + ) -> ClientConfig: """Create ClientConfig from agent's llm_config dict. Supports a simple format for YAML configuration: @@ -197,6 +208,7 @@ class MiniAgentHarness(BaseHarness): ValueError: If required fields or env vars are missing """ import os + from .client import ClientConfig provider = llm_config.get("provider", "").lower() @@ -273,7 +285,7 @@ class MiniAgentHarness(BaseHarness): ) @classmethod - def _create_context_strategy(cls, agent: "Agent") -> ContextStrategy: + def _create_context_strategy(cls, agent: Agent) -> ContextStrategy: """Map Flow's CompactionConfig to MiniAgent's ContextStrategy.""" config = agent.compaction @@ -328,24 +340,37 @@ class MiniAgentHarness(BaseHarness): """ # Import shared tools from flow.tools import ( - # Coding - read_file, write_file, edit_file, multi_edit, glob_files, grep, ls, + Workspace, # Execution - bash, check_processes, python_repl, - # Planning - think, todo_write, todo_read, + bash, + check_processes, + create_task_tool, + edit_file, + glob_files, + grep, + ls, # Memory - memory, create_memory_tool, - # Web - web_search, web_fetch, + memory, + multi_edit, # Notebooks - notebook_edit, notebook_read, + notebook_edit, + notebook_read, + # Coding + read_file, + # Workspace management + set_workspace, # Skills - skills, create_skills_tool, + skills, # Sub-agent - task, create_task_tool, - # Workspace management - set_workspace, Workspace, + task, + # Planning + think, + todo_read, + todo_write, + web_fetch, + # Web + web_search, + write_file, ) # Set workspace for tools that need it (memory, todos, etc.) @@ -364,7 +389,6 @@ class MiniAgentHarness(BaseHarness): # Execution "bash": bash, "check_processes": check_processes, - "python_repl": python_repl, # Planning "think": think, "todo_write": todo_write, diff --git a/src/flow/harness/miniagent/hooks.py b/src/flow/harness/miniagent/hooks.py index d8bb30f443f7f6e8332eb5bd6fd0a002c8b96b8c..6b92541d73ab8f6ae6bacb9cab77f9e754ed0f0e 100644 --- a/src/flow/harness/miniagent/hooks.py +++ b/src/flow/harness/miniagent/hooks.py @@ -6,9 +6,10 @@ Inspired by Claude Agent SDK's hooks system. Hooks allow applications to: - Control: Block tool calls, stop execution """ +from collections.abc import Awaitable, Callable from dataclasses import dataclass, field -from typing import Any, Callable, Awaitable, Literal from enum import Enum +from typing import Any, Literal class HookEvent(str, Enum): diff --git a/src/flow/harness/miniagent/instructions.py b/src/flow/harness/miniagent/instructions.py index c30021187007f6bcfb8544acf50e5df6ec4730c1..0e1374fcb00864a09340b38a7478c7be637ecd26 100644 --- a/src/flow/harness/miniagent/instructions.py +++ b/src/flow/harness/miniagent/instructions.py @@ -89,7 +89,7 @@ Never assume libraries exist. Check package.json, requirements.txt, or equivalen # Preset-specific instructions # ============================================================================= -CODING_AGENT_INSTRUCTIONS = f"""You are an expert coding assistant. You help users with software engineering tasks including writing code, debugging, refactoring, and explaining code. +GENERAL_AGENT_INSTRUCTIONS = f"""You are a helpful general-purpose agent. You solve tasks by combining reasoning, code execution, file operations, and web research as needed. ## Response Style @@ -111,7 +111,11 @@ CODING_AGENT_INSTRUCTIONS = f"""You are an expert coding assistant. You help use - **ls**: List directory contents. ### Execution -- **bash**: Execute shell commands. Use for git, running tests, installing packages. +- **bash**: Execute shell commands. Use for git, running tests, installing packages, and running Python code (e.g., `python -c "print(2+2)"` or `python script.py`). + +### Web Research +- **web_search**: Search the web for current information, facts, or data. +- **web_fetch**: Fetch and read web page contents. ### Planning - **think**: Reason through complex problems before acting. @@ -120,68 +124,25 @@ CODING_AGENT_INSTRUCTIONS = f"""You are an expert coding assistant. You help use ### Delegation (if available) - **task**: Delegate complex sub-tasks to a specialist agent with isolated context. -{EFFICIENCY_INSTRUCTIONS} -{BEST_PRACTICES_INSTRUCTIONS} -""" - -RESEARCH_AGENT_INSTRUCTIONS = f"""You are a research assistant. You help users find information, synthesize knowledge, and answer questions. -## Response Style - -- Be thorough in research, concise in presentation. -- Cite sources with URLs when reporting findings. -- Synthesize information - don't just list results. -{TASK_COMPLETION_INSTRUCTIONS} -## Tools +## Problem-Solving Strategy -### Search & Fetch -- **web_search**: Search the web for information. -- **web_fetch**: Fetch and read web page contents. - -### Planning -- **think**: Work through complex questions step by step. -- **todo_write**: Track research progress on multi-part questions. +### For calculations and math problems +Write and execute code rather than computing in your head. Use `bash` with `python -c "..."` or write a script with `write_file` then run it with `bash` — this avoids arithmetic errors. -## Research Strategy +### For questions requiring specific facts or current information +Use `web_search` to find authoritative sources, then `web_fetch` to read them. Do NOT guess or rely on memory for factual claims like dates, numbers, names, or statistics. -1. Start with broad searches to identify relevant sources -2. Fetch multiple promising URLs in parallel (batch web_fetch calls) -3. Synthesize findings into a coherent answer -4. If initial searches don't answer the question, refine and search again +### For complex tasks (data processing, file analysis, media) +Write code to solve them. Install required libraries with `bash` (e.g., `pip install ...`). Break the problem into steps and verify each step works before moving on. -## Guidelines - -1. **Be thorough**: Search multiple queries if needed - batch them. -2. **Cite sources**: Include URLs when reporting findings. -3. **Synthesize**: Draw conclusions, don't just list results. -4. **Keep going**: If first searches don't work, try different queries. -5. **Acknowledge uncertainty**: If information is unclear, say so. -""" - -EXPLORE_AGENT_INSTRUCTIONS = f"""You are a codebase exploration specialist. Your job is to quickly find and understand code. - -## Response Style - -- Be concise. Your response goes to another agent, so be self-contained. -- Include file paths and line numbers in findings. -- Summarize what you found, don't dump raw content. -{TASK_COMPLETION_INSTRUCTIONS} -## Tools - -- **read_file**: Read file contents (read fully, don't chunk). -- **glob_files**: Find files by pattern. -- **grep**: Search file contents with regex. -- **ls**: List directory contents. -- **think**: Reason about what you're finding. -- **todo_write**: Track exploration progress for complex searches. +### Anti-hallucination +- NEVER guess factual answers. If you don't know, search or compute. +- When a task asks for a specific number or name, verify it from a source. +- If web search fails, try different queries before giving up. +- State your confidence level when reporting facts. {EFFICIENCY_INSTRUCTIONS} -## Guidelines - -1. **Start broad, then narrow**: Use glob/grep to find candidates, then batch-read. -2. **Be efficient**: Don't read files you don't need. -3. **Report clearly**: Include file paths and line numbers. -4. **Keep searching**: If first attempt doesn't find what's needed, try different patterns. -5. **Summarize**: Be self-contained for the calling agent. +{BEST_PRACTICES_INSTRUCTIONS} """ # ============================================================================= @@ -189,19 +150,17 @@ EXPLORE_AGENT_INSTRUCTIONS = f"""You are a codebase exploration specialist. Your # ============================================================================= INSTRUCTIONS = { - "coding": CODING_AGENT_INSTRUCTIONS, - "research": RESEARCH_AGENT_INSTRUCTIONS, - "explore": EXPLORE_AGENT_INSTRUCTIONS, + "general": GENERAL_AGENT_INSTRUCTIONS, } -def get_instructions(preset: str = "coding") -> str: +def get_instructions(preset: str = "general") -> str: """Get system instructions by preset name. Args: - preset: One of 'coding', 'research', 'explore' + preset: Preset name (default: 'general') Returns: System instruction string """ - return INSTRUCTIONS.get(preset, CODING_AGENT_INSTRUCTIONS) + return INSTRUCTIONS.get(preset, GENERAL_AGENT_INSTRUCTIONS) diff --git a/src/flow/harness/miniagent/otel.py b/src/flow/harness/miniagent/otel.py index bf2a3deb7cf4b66ca646eb2012a362d798ba7a6f..daaf66c2708ca9ecdfd09ba1167a4b56274e7d2d 100644 --- a/src/flow/harness/miniagent/otel.py +++ b/src/flow/harness/miniagent/otel.py @@ -16,12 +16,12 @@ from opentelemetry import trace if TYPE_CHECKING: from .hooks import ( Hooks, - PreModelCallEvent, PostModelCallEvent, - PreToolUseEvent, - PreToolUseResult, PostToolUseEvent, PostToolUseResult, + PreModelCallEvent, + PreToolUseEvent, + PreToolUseResult, ) __all__ = ["GenAIAttr", "create_otel_hooks", "enable_instrumentation"] @@ -157,7 +157,7 @@ class OTelHooks: self._llm_spans: dict[int, trace.Span] = {} # iteration -> span self._tool_spans: dict[str, trace.Span] = {} # call_id -> span - async def on_pre_model_call(self, event: "PreModelCallEvent") -> None: + async def on_pre_model_call(self, event: PreModelCallEvent) -> None: """Start an LLM span before model call. Args: @@ -166,7 +166,7 @@ class OTelHooks: span = start_llm_span(model=self.model) self._llm_spans[event.iteration] = span - async def on_post_model_call(self, event: "PostModelCallEvent") -> None: + async def on_post_model_call(self, event: PostModelCallEvent) -> None: """End the LLM span after model call. Args: @@ -178,7 +178,7 @@ class OTelHooks: output_tokens = event.usage.get("output_tokens", 0) end_llm_span(span, input_tokens, output_tokens) - async def on_pre_tool_use(self, event: "PreToolUseEvent") -> "PreToolUseResult | None": + async def on_pre_tool_use(self, event: PreToolUseEvent) -> PreToolUseResult | None: """Start a tool span before tool execution. Args: @@ -191,7 +191,7 @@ class OTelHooks: self._tool_spans[event.tool_call_id] = span return None # Don't block - async def on_post_tool_use(self, event: "PostToolUseEvent") -> "PostToolUseResult | None": + async def on_post_tool_use(self, event: PostToolUseEvent) -> PostToolUseResult | None: """End the tool span after tool execution. Args: @@ -230,7 +230,7 @@ def enable_instrumentation() -> None: _instrumentation_enabled = True -def create_otel_hooks(model: str = "gpt-4o") -> "Hooks": +def create_otel_hooks(model: str = "gpt-4o") -> Hooks: """Create a Hooks instance with OTEL instrumentation. This is the main entry point for adding OTEL tracing to a MiniAgent. diff --git a/src/flow/harness/miniagent/tool.py b/src/flow/harness/miniagent/tool.py index 88cbdbaf5b4edaf09d240b2cadcca60fa4fd3cf0..4bcea1614c08ce00b21b4c71165aa9dec35ac730 100644 --- a/src/flow/harness/miniagent/tool.py +++ b/src/flow/harness/miniagent/tool.py @@ -3,9 +3,10 @@ Provides a simple way to define tools that can be called by the LLM. """ -from dataclasses import dataclass -from typing import Any, Callable, Literal, get_type_hints, get_origin, get_args, Annotated import inspect +from collections.abc import Callable +from dataclasses import dataclass +from typing import Annotated, Any, Literal, get_args, get_origin, get_type_hints @dataclass @@ -43,7 +44,7 @@ class Tool: result = await result return str(result) if not isinstance(result, str) else result except Exception as e: - return f"Error executing {self.name}: {str(e)}" + return f"Error executing {self.name}: {e!s}" def _python_type_to_json_schema(py_type: Any) -> dict[str, Any]: @@ -53,13 +54,13 @@ def _python_type_to_json_schema(py_type: Any) -> dict[str, Any]: return {"type": "null"} # Handle basic types - if py_type == str: + if py_type is str: return {"type": "string"} - if py_type == int: + if py_type is int: return {"type": "integer"} - if py_type == float: + if py_type is float: return {"type": "number"} - if py_type == bool: + if py_type is bool: return {"type": "boolean"} # Handle dict without type args diff --git a/src/flow/harness/miniagent/tools/__init__.py b/src/flow/harness/miniagent/tools/__init__.py index 23f64b772855891094b972d9883501f635e77d38..367b5d6ac7bdcb07ec3b746c0d70d125c75e1a00 100644 --- a/src/flow/harness/miniagent/tools/__init__.py +++ b/src/flow/harness/miniagent/tools/__init__.py @@ -33,51 +33,51 @@ Example: from flow.tools import ( # Base Tool, - # File operations - read_file, - write_file, + all_tools, + # Execution + bash, + check_processes, + # Presets + coding_tools, + create_memory_tool, + create_skills_tool, + create_task_tool, edit_file, - multi_edit, glob_files, grep, ls, + # Memory + memory, + multi_edit, # Notebook operations notebook_edit, notebook_read, - # Execution - bash, - check_processes, - python_repl, + notebook_tools, + planning_tools, + # File operations + read_file, + # Skills + skills, + # Sub-agent + task, # Planning and reasoning think, - todo_write, todo_read, + todo_write, + web_fetch, # Web operations web_search, - web_fetch, - # Memory - memory, - create_memory_tool, - # Skills - skills, - create_skills_tool, - # Sub-agent - task, - create_task_tool, - # Presets - coding_tools, - planning_tools, + write_file, +) +from flow.tools import ( web_tools as research_tools, - notebook_tools, - all_tools, ) -# Compatibility: reset_todos from planning module -from flow.tools.planning import reset_todos, get_todos - # Compatibility: reset_memory from memory module from flow.tools.memory import reset_memory +# Compatibility: reset_todos from planning module +from flow.tools.planning import get_todos, reset_todos __all__ = [ # Base @@ -102,7 +102,6 @@ __all__ = [ # Execution "bash", "check_processes", - "python_repl", # Planning "think", "todo_write", diff --git a/src/flow/harness/miniagent/workspace.py b/src/flow/harness/miniagent/workspace.py index 99371438207247430227b5e3bd04ed8403a192c5..3eda9b78e1555e563a56dc5bcd3de337be937165 100644 --- a/src/flow/harness/miniagent/workspace.py +++ b/src/flow/harness/miniagent/workspace.py @@ -31,6 +31,7 @@ Usage: ws.memory_dir # /path/to/project/.miniagent/memory """ +import contextvars import json from pathlib import Path from typing import Any @@ -97,7 +98,7 @@ class Workspace: try: with open(self.todos_file) as f: return json.load(f) # type: ignore[no-any-return] - except (json.JSONDecodeError, IOError): + except (OSError, json.JSONDecodeError): return [] def save_todos(self, todos: list[dict[str, Any]]) -> None: @@ -118,7 +119,7 @@ class Workspace: try: with open(filepath) as f: memories.append(json.load(f)) - except (json.JSONDecodeError, IOError): + except (OSError, json.JSONDecodeError): continue return memories @@ -130,7 +131,7 @@ class Workspace: try: with open(filepath) as f: return json.load(f) # type: ignore[no-any-return] - except (json.JSONDecodeError, IOError): + except (OSError, json.JSONDecodeError): return None def save_memory(self, memory_id: str, data: dict[str, Any]) -> None: @@ -157,7 +158,7 @@ class Workspace: try: with open(self.config_file) as f: return json.load(f) - except (json.JSONDecodeError, IOError): + except (OSError, json.JSONDecodeError): return {} def save_config(self, config: dict[str, Any]) -> None: @@ -170,29 +171,31 @@ class Workspace: return f"Workspace({self._root})" -# Default workspace (current directory) -_default_workspace: Workspace | None = None +# Per-task workspace via contextvars (safe for concurrent async tasks). +_workspace_var: contextvars.ContextVar[Workspace | None] = contextvars.ContextVar( + "miniagent_workspace", default=None +) def get_workspace() -> Workspace: - """Get the default workspace (creates if needed).""" - global _default_workspace - if _default_workspace is None: - _default_workspace = Workspace() - return _default_workspace + """Get the current workspace (creates from cwd if not set).""" + ws = _workspace_var.get() + if ws is None: + ws = Workspace() + _workspace_var.set(ws) + return ws def set_workspace(workspace: Workspace | str | Path) -> Workspace: - """Set the default workspace.""" - global _default_workspace + """Set the workspace for the current async task.""" if isinstance(workspace, Workspace): - _default_workspace = workspace - else: - _default_workspace = Workspace(workspace) - return _default_workspace + _workspace_var.set(workspace) + return workspace + ws = Workspace(workspace) + _workspace_var.set(ws) + return ws def reset_workspace() -> None: - """Reset default workspace (for testing).""" - global _default_workspace - _default_workspace = None + """Reset workspace for the current context (for testing).""" + _workspace_var.set(None) diff --git a/src/flow/harness/registry.py b/src/flow/harness/registry.py index 09c526c6bbaa60b35e9034342c6a1b5463a34c7a..03708977d8c631fd6045c9795219b6edde55490d 100644 --- a/src/flow/harness/registry.py +++ b/src/flow/harness/registry.py @@ -14,10 +14,10 @@ if TYPE_CHECKING: from flow.harness.base import BaseHarness from flow.llm import LLMClientConfig -_HARNESSES: dict[str, type["BaseHarness"]] = {} +_HARNESSES: dict[str, type[BaseHarness]] = {} -def register(name: str, harness_class: type["BaseHarness"]) -> None: +def register(name: str, harness_class: type[BaseHarness]) -> None: """Register a harness class for a framework. Args: @@ -27,7 +27,7 @@ def register(name: str, harness_class: type["BaseHarness"]) -> None: _HARNESSES[name] = harness_class -def get_harness_class(name: str) -> type["BaseHarness"]: +def get_harness_class(name: str) -> type[BaseHarness]: """Get harness class by framework name. Args: @@ -46,10 +46,10 @@ def get_harness_class(name: str) -> type["BaseHarness"]: def create_harness( - agent: "Agent", + agent: Agent, workspace: Path, - llm_config: "LLMClientConfig | None" = None, -) -> "BaseHarness": + llm_config: LLMClientConfig | None = None, +) -> BaseHarness: """Create a harness from an Agent spec. This is the main entry point for creating harnesses. It looks up @@ -71,6 +71,29 @@ def create_harness( return harness_class.from_agent(agent, workspace, llm_config=llm_config) +def ensure_harnesses_registered() -> None: + """Ensure all built-in harnesses are registered. + + Safe to call multiple times — only imports once. + """ + if _HARNESSES: + return + + # Import harness modules to trigger their self-registration + import flow.harness.maf as _maf + import flow.harness.miniagent as _miniagent + + _ = (_maf, _miniagent) + + # LangGraph is optional + try: + import flow.harness.langgraph as _lg + + _ = _lg # type: ignore[assignment] + except ImportError: + pass + + def available_frameworks() -> list[str]: """Get list of available framework names. @@ -78,3 +101,17 @@ def available_frameworks() -> list[str]: List of registered framework names """ return list(_HARNESSES.keys()) + + +def get_registered_harnesses() -> dict[str, type[BaseHarness]]: + """Get all registered harness classes. + + Returns: + Dict mapping framework names to harness classes. + Each harness class has metadata attributes: + - framework_name: Unique identifier + - framework_label: Human-readable name + - framework_description: Short description + - supported_compaction_strategies: List of supported strategy names + """ + return dict(_HARNESSES) diff --git a/src/flow/llm/config.py b/src/flow/llm/config.py index efeda33d9e9b5ddc664e282a195c91b7f8813818..48e46fdbe9821047e7ca5db5b8512be31b4f9bf3 100644 --- a/src/flow/llm/config.py +++ b/src/flow/llm/config.py @@ -183,7 +183,7 @@ class LLMClientConfig(BaseModel): custom: CustomConfig | None = None @model_validator(mode="after") - def validate_provider_config(self) -> "LLMClientConfig": + def validate_provider_config(self) -> LLMClientConfig: """Ensure the correct provider config is set.""" provider_configs = { LLMProvider.OPENAI: self.openai, @@ -222,6 +222,6 @@ class LLMClientConfig(BaseModel): return self.model_dump(exclude_none=True) @classmethod - def from_dict(cls, data: dict[str, Any]) -> "LLMClientConfig": + def from_dict(cls, data: dict[str, Any]) -> LLMClientConfig: """Create from dictionary.""" return cls.model_validate(data) diff --git a/src/flow/llm/factory.py b/src/flow/llm/factory.py index d2378c537a824e8d6b9bb8cec078eb22a9ed58ac..b92a2ead42893b073fe9e22107d4d5255a850043 100644 --- a/src/flow/llm/factory.py +++ b/src/flow/llm/factory.py @@ -87,7 +87,7 @@ class LLMClientFactory: return OpenAIChatClient( api_key=config.openai.get_api_key(), - model=config.openai.model_id, + model_id=config.openai.model_id, ) case _: diff --git a/src/flow/optimizers/__init__.py b/src/flow/optimizers/__init__.py index 262f9ceabbc176b46b6e8450b1d40dd4ae906f33..57e6492293302a66236f918317ab7d2b0f26ca0c 100644 --- a/src/flow/optimizers/__init__.py +++ b/src/flow/optimizers/__init__.py @@ -6,6 +6,6 @@ This module contains various optimization strategies for improving agent perform including GEPA-based active optimization. """ -from .gepa_adapter import GepaStrategy +from .gepa_adapter import CandidateRecord, GEPAOptimizationReport, GepaStrategy -__all__ = ["GepaStrategy"] +__all__ = ["CandidateRecord", "GEPAOptimizationReport", "GepaStrategy"] diff --git a/src/flow/optimizers/gepa_adapter.py b/src/flow/optimizers/gepa_adapter.py index d4216101d320afeb3ed12b1e23b06ef8f972a274..dcd39137fcb0a68f1d50b2e10a9ffa671cccfafa 100644 --- a/src/flow/optimizers/gepa_adapter.py +++ b/src/flow/optimizers/gepa_adapter.py @@ -8,27 +8,191 @@ Prompt Adjustment) to optimize prompts via an active learning loop. from __future__ import annotations -import logging -from dataclasses import dataclass -from typing import Any, Callable +import os +from collections.abc import Callable +from dataclasses import dataclass, field +from datetime import datetime +from typing import Any -from ..experiments.models import Agent, Candidate, CandidateStrategy, ExperimentResult -from ..experiments.types import Task +from loguru import logger -logger = logging.getLogger(__name__) +from ..experiments.models import Agent, Candidate, ExperimentResult +from ..experiments.types import Task @dataclass -class GEPAEvaluationResult: - """Result object returned by FlowAdapter.evaluate() for GEPA.""" - outputs: list[Any] +class CandidateRecord: + """Record of a candidate evaluation during GEPA optimization.""" + + generation: int + candidate_id: str + instructions_preview: str # First 200 chars + instructions_full: str scores: list[float] - objective_scores: list[dict[str, float]] | None = None + avg_score: float + pass_rate: float + is_selected: bool = False + selection_reason: str = "" + timestamp: str = field(default_factory=lambda: datetime.now().isoformat()) + best_score: float = 0.0 # Best score achieved by this candidate + best_eval_num: int = 0 # Global evaluation number when best score was achieved + eval_count: int = 0 # Total number of evaluations for this candidate + + +@dataclass +class GEPAOptimizationReport: + """Complete report of GEPA optimization run.""" + + baseline_prompt: str + baseline_score: float + final_prompt: str + final_score: float + improvement: float + total_candidates_evaluated: int + total_generations: int + candidate_history: list[CandidateRecord] = field(default_factory=list) + best_candidate_id: str = "" # ID of the candidate that produced the best prompt + + def format_report(self, max_prompt_length: int = 500) -> str: + """Format the report as a human-readable string.""" + lines = [ + "", + "=" * 80, + " GEPA OPTIMIZATION REPORT", + "=" * 80, + "", + "┌" + "─" * 78 + "┐", + "│ SUMMARY" + " " * 70 + "│", + "├" + "─" * 78 + "┤", + f"│ Total Generations: {self.total_generations:<48}│", + f"│ Total Candidates Tested: {self.total_candidates_evaluated:<48}│", + f"│ Baseline Score: {self.baseline_score:<48.4f}│", + f"│ Final Score: {self.final_score:<48.4f}│", + f"│ Improvement: {'+' if self.improvement >= 0 else ''}{self.improvement:<47.4f}│", + f"│ Improvement %: {'+' if self.improvement >= 0 else ''}{(self.improvement / max(self.baseline_score, 0.001)) * 100:<46.1f}%│", + "└" + "─" * 78 + "┘", + "", + ] + + # Baseline prompt section (cand_1 is always the baseline) + lines.extend( + [ + "┌" + "─" * 78 + "┐", + "│ BASELINE PROMPT (ID: cand_1)" + " " * 49 + "│", + "├" + "─" * 78 + "┤", + ] + ) + baseline_display = self.baseline_prompt[:max_prompt_length] + if len(self.baseline_prompt) > max_prompt_length: + baseline_display += f"... ({len(self.baseline_prompt)} chars total)" + for line in baseline_display.split("\n"): + wrapped = self._wrap_text(line, 76) + for w in wrapped: + lines.append(f"│ {w:<76} │") + lines.append("└" + "─" * 78 + "┘") + lines.append("") + + # Final prompt section - include candidate ID + prompt_header = ( + f"│ BEST PROMPT (ID: {self.best_candidate_id})" if self.best_candidate_id else "│ FINAL OPTIMIZED PROMPT" + ) + header_padding = " " * (79 - len(prompt_header)) + lines.extend( + [ + "┌" + "─" * 78 + "┐", + prompt_header + header_padding + "│", + "├" + "─" * 78 + "┤", + ] + ) + final_display = self.final_prompt[:max_prompt_length] + if len(self.final_prompt) > max_prompt_length: + final_display += f"... ({len(self.final_prompt)} chars total)" + for line in final_display.split("\n"): + wrapped = self._wrap_text(line, 76) + for w in wrapped: + lines.append(f"│ {w:<76} │") + lines.append("└" + "─" * 78 + "┘") + lines.append("") + + # Candidate progression table + if self.candidate_history: + lines.extend( + [ + "┌" + "─" * 90 + "┐", + "│ CANDIDATE PROGRESSION" + " " * 68 + "│", + "├" + "─" * 90 + "┤", + "│ Gen │ Candidate ID │ Avg Score │ Best Score │ Best Iter │ Pass Rate │ Selected │", + "├" + "─" * 90 + "┤", + ] + ) + + for rec in self.candidate_history: + selected_mark = "✓" if rec.is_selected else " " + cand_id = rec.candidate_id[:15] if len(rec.candidate_id) > 15 else rec.candidate_id + best_score = rec.best_score + best_eval = rec.best_eval_num if rec.eval_count > 0 else 1 + lines.append( + f"│ {rec.generation:>3} │ {cand_id:<15} │ {rec.avg_score:>9.4f} │ {best_score:>10.4f} │ {best_eval:>9} │ {rec.pass_rate:>9.1%} │ {selected_mark} │" + ) + lines.append("└" + "─" * 90 + "┘") + lines.append("") + + # Show top 3 candidates with their best iterations + sorted_candidates = sorted(self.candidate_history, key=lambda x: x.best_score, reverse=True)[:3] + lines.extend( + [ + "┌" + "─" * 78 + "┐", + "│ TOP 3 CANDIDATES (by best score)" + " " * 43 + "│", + "├" + "─" * 78 + "┤", + ] + ) + for i, rec in enumerate(sorted_candidates, 1): + best_eval_str = f", Eval #{rec.best_eval_num}" if rec.eval_count > 0 else "" + header = f"│ #{i}: {rec.candidate_id} - Avg {rec.avg_score:.4f} (Gen {rec.generation}{best_eval_str})" + lines.append(header + " " * max(0, 79 - len(header)) + "│") + preview = rec.instructions_preview.replace("\n", " ")[:70] + lines.append(f"│ {preview}..." + " " * max(0, 70 - len(preview)) + "│") + lines.append("└" + "─" * 78 + "┘") + + lines.extend(["", "=" * 80, ""]) + return "\n".join(lines) + + @staticmethod + def _wrap_text(text: str, width: int) -> list[str]: + """Wrap text to specified width.""" + if not text: + return [""] + words = text.split() + lines = [] + current_line = "" + for word in words: + if len(current_line) + len(word) + 1 <= width: + current_line += (" " if current_line else "") + word + else: + if current_line: + lines.append(current_line) + current_line = word[:width] # Truncate very long words + if current_line: + lines.append(current_line) + return lines if lines else [""] + + +@dataclass +class GEPATrajectory: + """Trajectory data for GEPA reflection.""" + + task_name: str + task_prompt: str + agent_output: str + eval_reasoning: str + eval_score: float + eval_passed: bool + instructions_used: str class GepaStrategy: """Active strategy using GEPA for prompt optimization. - + This strategy injects an evaluator and dataset into the generation process to drive GEPA's evolutionary loop. """ @@ -38,6 +202,7 @@ class GepaStrategy: evaluator: Callable[[Candidate, list[Any] | None], ExperimentResult] | None = None, dataset: list[Any] | None = None, config: dict[str, Any] | None = None, + quiet: bool = True, # Reduce logging output ) -> None: """Initialize GEPA strategy with evaluation components. @@ -45,117 +210,412 @@ class GepaStrategy: evaluator: Function to evaluate a candidate. Optional if injected later. dataset: Optional list of inputs/examples to use for optimization. config: GEPA configuration hyperparameters (e.g. reflection_lm). + quiet: If True, reduce console output and use progress bars. """ self.evaluator = evaluator self.dataset = dataset self.config = config or {} + self.quiet = quiet + + # Track all candidates evaluated during optimization + self.candidate_history: list[CandidateRecord] = [] + self.current_generation = 0 + self.baseline_prompt: str = "" + self.baseline_score: float = 0.0 + self._report: GEPAOptimizationReport | None = None - def generate(self, base: Agent, budget: int) -> list[Candidate]: + async def generate( + self, + base: Agent, + budget: int, + *, + tasks: list[Any] | None = None, + runner: Any | None = None, + ) -> list[Candidate]: """Generate optimized candidates using GEPA. - + This method runs the full GEPA optimization loop and returns the best - candidates found. + candidates found. GEPA's internal loop is CPU-bound and uses its own + evaluator callback, so it runs synchronously internally. Args: base: The base agent to optimize. budget: Max metric calls (budget for optimization). + tasks: Optional tasks to use as dataset (overrides self.dataset). + runner: Optional ExperimentRunner (not used directly, GEPA has its own + internal loop via self.evaluator). Future versions may use + runner.evaluate() instead of the custom evaluator callback. Returns: List of optimized Candidate objects. """ + # Use tasks parameter if provided, otherwise use self.dataset + if tasks is not None: + self.dataset = tasks + + # GEPA uses its own internal evaluation loop via self.evaluator callback. + # The runner parameter is available but GEPA's adapter pattern requires + # a custom evaluator function that was set during __init__ or via the + # Python API. Future refactoring can migrate to use runner.evaluate(). + _ = runner # Available for future migration + if self.evaluator is None: - raise ValueError("Evaluator must be provided via init or injection before calling generate.") + raise ValueError( + "GEPA strategy requires a run_experiment function that executes and evaluates candidates. " + "This is not yet supported in the experiment YAML variation syntax. " + "Use the Python API with GepaStrategy(evaluator=...) instead, or use literal variations." + ) try: import gepa except ImportError as e: - raise ImportError( - "GEPA is not installed. Install with `pip install flow-agent[optimizer]`" - ) from e + raise ImportError("GEPA is not installed. Install with `pip install flow-agent[optimizer]`") from e + + # Import EvaluationBatch for proper return type + from gepa.core.adapter import EvaluationBatch + + # Store reference to strategy for tracking candidates + strategy_self = self + self.baseline_prompt = base.instructions or "" + self.candidate_history = [] + self.current_generation = 0 + candidate_counter = 0 + eval_counter = 0 # Global evaluation counter across all candidates + # Track unique candidates by instructions hash to avoid duplicates + seen_candidates: dict[int, CandidateRecord] = {} # Inner adapter class to bridge Flow and GEPA class FlowAdapter(gepa.GEPAAdapter): def __init__(self, evaluator_fn: Callable[[Candidate, list[Any] | None], ExperimentResult]): self.evaluator_fn = evaluator_fn - - def evaluate(self, batch: list[Any], program: dict[str, str], **kwargs: Any) -> GEPAEvaluationResult: - # 1. Apply program (prompts) to 'base' agent to create a temp Candidate - # program maps component names (e.g. "instructions") to text - + + def evaluate( + self, batch: list[Any], candidate: dict[str, str], capture_traces: bool = False + ) -> EvaluationBatch: + nonlocal candidate_counter + + logger.debug(f"[GEPA] evaluate() called: batch_size={len(batch)}, capture_traces={capture_traces}") + + # 1. Apply candidate (prompts) to 'base' agent to create a temp Candidate + # candidate maps component names (e.g. "instructions") to text + + # Determine candidate_id upfront (check if we've seen this candidate) + instructions_text = candidate.get("instructions", "") + instructions_hash = hash(instructions_text) + + if instructions_hash in seen_candidates: + existing = seen_candidates[instructions_hash] + current_candidate_id = existing.candidate_id + is_new_candidate = False + else: + # Will be a new candidate - get next ID + current_candidate_id = f"cand_{candidate_counter + 1}" + is_new_candidate = True + # Clone base agent and update fields, preserving CompactionConfig object mutated_agent = Agent( name=f"{base.name}_gepa_eval", framework=base.framework, description=base.description, - instructions=program.get("instructions", base.instructions), - model=base.model, + instructions=candidate.get("instructions", base.instructions), + llm_config=base.llm_config, compaction=base.compaction, # Preserve the CompactionConfig object - tools=base.tools + tools=base.tools, ) - - # Create temp Candidate + + # Create temp Candidate with candidate_id in mutations for tracking temp_candidate = Candidate( agent=mutated_agent, - mutations=program, - rationale="GEPA evaluation probe" + mutations={**candidate, "_candidate_id": current_candidate_id}, + rationale=f"GEPA evaluation probe ({current_candidate_id})", ) - - # If batch is empty, return neutral results + + # Log minimally unless debug mode + instructions_preview = instructions_text[:100].replace("\n", " ") + logger.debug(f"[GEPA] Testing mutation ({current_candidate_id}): {instructions_preview}...") + + # If batch is empty, return neutral results # This can happen with GEPA's initialization or when using empty datasets if not batch: - return GEPAEvaluationResult( - outputs=[], - scores=[], - objective_scores=None + logger.debug("[GEPA] Empty batch received, returning neutral results.") + return EvaluationBatch( + outputs=[], scores=[], trajectories=[] if capture_traces else None, objective_scores=None ) - - # 2. Evaluate each task individually to get per-item scores + + # 2. Evaluate each task individually to get per-item scores and trajectories # GEPA needs granular feedback for each example, not aggregate scores - outputs = [] - scores = [] - - logger.info(f"[GEPA] Evaluating {len(batch)} tasks for GEPA") - + trajectories: list[GEPATrajectory] = [] + outputs: list[GEPATrajectory] = [] + scores: list[float] = [] + passed_count = 0 + + logger.debug(f"[GEPA] Evaluating {len(batch)} tasks (capture_traces={capture_traces})") + for i, task in enumerate(batch): # Evaluate this single task logger.debug(f"[GEPA] Calling evaluator for task {i}: {getattr(task, 'name', 'unnamed')}") result = self.evaluator_fn(temp_candidate, [task]) - + # Extract score and output for this specific task - task_score = getattr(result, "eval_score", 0.0) - task_output = getattr(result, "traces", {}) - - logger.info(f"[GEPA] Task {i} ({getattr(task, 'name', 'unnamed')}): score={task_score}, passed={getattr(result, 'eval_passed', False)}") - logger.debug(f"[GEPA] Reasoning: {getattr(result, 'eval_reasoning', 'N/A')[:200]}") - + # Handle both direct attributes and nested structures + task_score = getattr(result, "eval_score", None) + if task_score is None: + # Try to get from metrics dict + metrics = getattr(result, "metrics", {}) + task_score = metrics.get("score", metrics.get("eval_score", 0.0)) + task_score = float(task_score) if task_score is not None else 0.0 + + eval_reasoning = getattr(result, "eval_reasoning", "No reasoning provided") + eval_passed = getattr(result, "eval_passed", False) + if eval_passed: + passed_count += 1 + + # Extract agent output from traces + agent_output = "No output captured" + if hasattr(result, "run_result") and result.run_result: + if hasattr(result.run_result, "output"): + agent_output = str(result.run_result.output) + elif hasattr(result.run_result, "trace"): + # Try to extract from trace + agent_output = str(result.run_result.trace)[:500] + + # Create trajectory with all context for reflection + trajectory = GEPATrajectory( + task_name=getattr(task, "name", "unnamed"), + task_prompt=getattr(task, "prompt", ""), + agent_output=agent_output, + eval_reasoning=eval_reasoning, + eval_score=task_score, + eval_passed=eval_passed, + instructions_used=candidate.get("instructions", ""), + ) + + # Debug-level logging only + logger.debug(f"[GEPA] Task {i} ({trajectory.task_name}): score={task_score}, passed={eval_passed}") + scores.append(task_score) - outputs.append(task_output) - - avg_score = sum(scores)/len(scores) if scores else 0.0 - logger.info(f"[GEPA] Evaluation complete. Scores: {scores}, Avg: {avg_score:.3f}") - - # Return proper GEPAEvaluationResult with per-item scores - return GEPAEvaluationResult( + outputs.append(trajectory) + if capture_traces: + trajectories.append(trajectory) + + avg_score = sum(scores) / len(scores) if scores else 0.0 + pass_rate = passed_count / len(batch) if batch else 0.0 + + # Track this candidate - use hash of instructions to identify unique candidates + # GEPA may evaluate the same candidate multiple times on different batches + # Note: instructions_hash and is_new_candidate were computed earlier + + if not is_new_candidate: + # Update existing record with new evaluation data (rolling average) + existing = seen_candidates[instructions_hash] + old_count = len(existing.scores) + new_count = old_count + len(scores) + # Compute weighted average + existing.avg_score = (existing.avg_score * old_count + avg_score * len(scores)) / new_count + existing.scores.extend(scores) + existing.pass_rate = (existing.pass_rate * old_count + pass_rate * len(scores)) / new_count + + # Track best score and iteration for this candidate + existing.iteration_count += 1 + if avg_score > existing.best_score: + existing.best_score = avg_score + existing.best_iteration = existing.iteration_count + + logger.debug( + f"[GEPA] Updated {existing.candidate_id}: avg={existing.avg_score:.4f}, best={existing.best_score:.4f} (iter {existing.best_iteration}/{existing.iteration_count})" + ) + else: + # New candidate + candidate_counter += 1 + cand_id = f"cand_{candidate_counter}" + record = CandidateRecord( + generation=strategy_self.current_generation, + candidate_id=cand_id, + instructions_preview=instructions_text[:200].replace("\n", " "), + instructions_full=instructions_text, + scores=scores.copy(), + avg_score=avg_score, + pass_rate=pass_rate, + best_score=avg_score, # First evaluation is the best so far + best_eval_num=current_eval_num, # Global evaluation number + eval_count=1, + ) + seen_candidates[instructions_hash] = record + strategy_self.candidate_history.append(record) + + # Track baseline score (first unique candidate evaluated) + if candidate_counter == 1: + strategy_self.baseline_score = avg_score + + # Log at INFO level so users can see score progression + logger.info( + f"[GEPA] {cand_id} (gen {strategy_self.current_generation}): avg_score={avg_score:.4f}, scores={scores}" + ) + + logger.debug(f"[GEPA] New candidate {cand_id}: avg={avg_score:.4f}, pass_rate={pass_rate:.1%}") + + # Return proper EvaluationBatch with per-item scores and trajectories + return EvaluationBatch( outputs=outputs, scores=scores, - objective_scores=None + trajectories=trajectories if capture_traces else None, + objective_scores=None, + ) + + def make_reflective_dataset( + self, candidate: dict[str, str], eval_batch: EvaluationBatch, components_to_update: list[str] + ) -> dict[str, list[dict[str, Any]]]: + """Create reflective dataset for GEPA to generate improved prompts. + + GEPA expects each example to follow this schema: + { + "Inputs": Dict[str, str], # Minimal view of inputs to the component + "Generated Outputs": Dict[str, str] | str, # Model outputs + "Feedback": str # Feedback on performance + } + + Args: + candidate: Current program (dict mapping component names to text) + eval_batch: Evaluation batch with trajectories and scores + components_to_update: List of component names to update + + Returns: + Dict mapping component name to list of reflection examples + """ + # Log reflection call - this indicates new candidate generation + print(f"[GEPA] Generating new candidate (gen {strategy_self.current_generation + 1})...") + logger.debug( + f"[GEPA] make_reflective_dataset: components={components_to_update}, " + f"scores={eval_batch.scores if eval_batch.scores else 'None'}" ) - def extract_traces(self, candidate: dict[str, str], component: str) -> str: - # GEPA calls this sometimes to get traces for reflection? - # Actually, `evaluate` returns traces in the result. - # GEPA might use this if traces are stored elsewhere. - # For now, return empty string as base implementation. - return "" + # Increment generation counter when reflection starts (indicates new generation) + strategy_self.current_generation += 1 + + # Extract trajectories from eval_batch + trajectories = eval_batch.trajectories if eval_batch.trajectories else [] + scores = eval_batch.scores if eval_batch.scores else [] + + if not trajectories: + logger.debug("[GEPA] No trajectories available for reflection - using outputs") + # Fall back to outputs if trajectories are not available + trajectories = eval_batch.outputs if eval_batch.outputs else [] + + reflection_data: dict[str, list[dict[str, Any]]] = {} + + for component in components_to_update: + examples: list[dict[str, Any]] = [] + + # Create reflection examples - prioritize failures and low scores + for traj, score in zip(trajectories, scores): + if not isinstance(traj, GEPATrajectory): + logger.debug(f"[GEPA] Skipping non-GEPATrajectory: {type(traj)}") + continue + + # GEPA expects specific keys: Inputs, Generated Outputs, Feedback + example = { + "Inputs": { + "task": traj.task_prompt, + "instructions": traj.instructions_used[:500] + if len(traj.instructions_used) > 500 + else traj.instructions_used, + }, + "Generated Outputs": { + "agent_response": traj.agent_output[:1000] + if len(traj.agent_output) > 1000 + else traj.agent_output + }, + "Feedback": f"Score: {score:.2f}/1.0. Passed: {traj.eval_passed}. {traj.eval_reasoning}", + "score": score, + } + examples.append(example) + + # Sort by score (ascending) so low-scoring examples come first + # GEPA learns more from failures + examples.sort(key=lambda x: x.get("score", 0)) + + # Remove the score key as it's not part of GEPA's expected schema + for ex in examples: + ex.pop("score", None) + + reflection_data[component] = examples + logger.debug(f"[GEPA] Created {len(examples)} reflection examples for '{component}'") + + return reflection_data # Normalize config gepa_config = self.config.copy() - + + # Filter out parameters that are not valid for gepa.optimize + # These are convenience parameters from Flow's config format that aren't real GEPA args + VALID_GEPA_PARAMS = { + "reflection_lm", + "candidate_selection_strategy", + "frontier_type", + "skip_perfect_score", + "batch_sampler", + "reflection_minibatch_size", + "perfect_score", + "reflection_prompt_template", + "module_selector", + "use_merge", + "max_merge_invocations", + "merge_val_overlap_floor", + "stop_callbacks", + "logger", + "run_dir", + "callbacks", + "use_wandb", + "wandb_api_key", + "wandb_init_kwargs", + "use_mlflow", + "mlflow_tracking_uri", + "mlflow_experiment_name", + "track_best_outputs", + "display_progress_bar", + "use_cloudpickle", + "cache_evaluation", + "seed", + "raise_on_exception", + "val_evaluation_policy", + "task_lm", + "evaluator", # These are set by Flow, but valid GEPA params + } + + filtered_config = {} + removed_params = [] + for key, value in gepa_config.items(): + if key in VALID_GEPA_PARAMS: + filtered_config[key] = value + else: + removed_params.append(key) + + if removed_params: + logger.warning(f"[GEPA] Ignoring invalid config params: {removed_params}") + print(f"[GEPA WARNING] Ignoring invalid config params: {removed_params}") + + gepa_config = filtered_config + + # Ensure Azure OpenAI environment variables are mapped for LiteLLM/GEPA + # Flow uses AZURE_OPENAI_API_KEY/ENDPOINT, LiteLLM uses AZURE_API_KEY/BASE + if os.environ.get("AZURE_OPENAI_API_KEY"): + os.environ.setdefault("AZURE_API_KEY", os.environ["AZURE_OPENAI_API_KEY"]) + if os.environ.get("AZURE_OPENAI_ENDPOINT"): + os.environ.setdefault("AZURE_API_BASE", os.environ["AZURE_OPENAI_ENDPOINT"]) + + # If reflection_lm is set and using Azure, ensure it has the azure/ prefix + if "reflection_lm" in gepa_config and not gepa_config["reflection_lm"].startswith("azure/"): + if os.environ.get("AZURE_OPENAI_ENDPOINT"): + logger.debug( + f"[GEPA] Prefixing reflection_lm '{gepa_config['reflection_lm']}' with 'azure/' for LiteLLM" + ) + gepa_config["reflection_lm"] = f"azure/{gepa_config['reflection_lm']}" + # Determine seed candidate dictionary seed_candidate = {} if base.instructions: seed_candidate["instructions"] = base.instructions - + # Prepare dataset for GEPA # GEPA needs a list of items it can pass to the evaluator # The evaluator expects Task objects, so ensure we have those @@ -166,62 +626,138 @@ class GepaStrategy: if isinstance(item, Task): dataset_for_gepa.append(item) # Dict with 'prompt' key - convert to Task - elif isinstance(item, dict) and 'prompt' in item: - dataset_for_gepa.append(Task( - name=item.get('name', f'task_{len(dataset_for_gepa)}'), - prompt=item['prompt'], - criteria=item.get('criteria', []), - metadata=item.get('metadata', {}) - )) + elif isinstance(item, dict) and "prompt" in item: + dataset_for_gepa.append( + Task( + name=item.get("name", f"task_{len(dataset_for_gepa)}"), + prompt=item["prompt"], + criteria=item.get("criteria", []), + metadata=item.get("metadata", {}), + ) + ) # Otherwise try to use it as-is and let GEPA/evaluator handle it else: dataset_for_gepa.append(item) - + # If no dataset provided, create minimal dummy tasks for GEPA # GEPA needs at least some data to build evaluation metrics if not dataset_for_gepa: logger.warning("No dataset provided for GEPA optimization. Using minimal dataset.") dataset_for_gepa = [ - Task( - name=f'dummy_{i}', - prompt=f'Placeholder task {i}', - criteria=[], - metadata={} - ) for i in range(max(1, budget // 2)) + Task(name=f"dummy_{i}", prompt=f"Placeholder task {i}", criteria=[], metadata={}) + for i in range(max(1, budget // 2)) ] - - # Run GEPA - logger.info("Starting GEPA optimization (budget=%d, dataset_size=%d)", budget, len(dataset_for_gepa)) + + # Warn if budget seems too low for meaningful optimization + min_recommended_budget = len(dataset_for_gepa) * 3 # At least 3 iterations + if budget < min_recommended_budget: + logger.warning( + f"Budget ({budget}) may be too low for dataset size ({len(dataset_for_gepa)}). " + f"GEPA needs budget for: 1) initial evaluation, 2) reflection, 3) new candidate evaluation. " + f"Recommended minimum: {min_recommended_budget}" + ) + print(f"\n{'!' * 60}") + print(f"[GEPA WARNING] Budget ({budget}) may be too low!") + print(f"[GEPA WARNING] Dataset has {len(dataset_for_gepa)} tasks.") + print("[GEPA WARNING] GEPA needs budget for multiple evaluation + reflection cycles.") + print(f"[GEPA WARNING] Recommended: --budget {min_recommended_budget} or higher") + print(f"{'!' * 60}\n") + + # Run GEPA - use quiet mode for minimal logging + logger.debug("Starting GEPA optimization (budget=%d, dataset_size=%d)", budget, len(dataset_for_gepa)) + logger.debug(f"[GEPA] Seed candidate components: {list(seed_candidate.keys())}") + logger.debug(f"[GEPA] Config: {gepa_config}") + + # Log optimization start + reflection_lm = gepa_config.get("reflection_lm", "NOT SET!") + print(f"[GEPA] Starting optimization: budget={budget}, tasks={len(dataset_for_gepa)}") + print(f"[GEPA] Reflection LM: {reflection_lm}") + + if not gepa_config.get("reflection_lm"): + print("[GEPA WARNING] No reflection_lm configured - GEPA cannot generate new candidates!") + gepa_result = gepa.optimize( seed_candidate=seed_candidate, adapter=FlowAdapter(self.evaluator), trainset=dataset_for_gepa, - valset=dataset_for_gepa, # Use same for now if splits not provided + valset=dataset_for_gepa, # Use same for now if splits not provided max_metric_calls=budget, - **gepa_config + display_progress_bar=True, # Enable progress bar from GEPA + skip_perfect_score=False, # Disable skipping to force exploration + perfect_score=2.0, # Impossible score to disable skipping + **gepa_config, ) - + + # Log optimization results + print(f"[GEPA] Optimization complete: {len(gepa_result.candidates)} candidates tested") + print(f"[GEPA] Total metric calls: {gepa_result.total_metric_calls}") + print(f"[GEPA] Generations: {self.current_generation}") + + if self.current_generation == 0: + print("[GEPA WARNING] No new candidates generated (generations=0)!") + print("[GEPA WARNING] This usually means:") + print("[GEPA WARNING] 1. Budget too low (try --budget 100 or higher)") + print("[GEPA WARNING] 2. reflection_lm not working (check API keys)") + # Convert result back to Candidate best_prompts = gepa_result.best_candidate - + # Create final candidate, preserving CompactionConfig object final_agent = Agent( name=f"{base.name}_gepa_optimized", framework=base.framework, description=base.description, - instructions=best_prompts.get("instructions", base.instructions), - model=base.model, + instructions=final_instructions, + llm_config=base.llm_config, compaction=base.compaction, # Preserve the CompactionConfig object - tools=base.tools + tools=base.tools, ) - + # Get the best score from the result best_score = gepa_result.val_aggregate_scores[gepa_result.best_idx] - + + # Mark the winning candidate in history and capture its ID + final_instructions = best_prompts.get("instructions", "") + best_candidate_id = "" + for record in self.candidate_history: + if record.instructions_full == final_instructions: + record.is_selected = True + record.selection_reason = "best_score" + best_candidate_id = record.candidate_id + break + + # Build the final report + self._report = GEPAOptimizationReport( + baseline_prompt=self.baseline_prompt, + baseline_score=self.baseline_score, + final_prompt=final_instructions, + final_score=best_score, + improvement=best_score - self.baseline_score, + total_candidates_evaluated=len(self.candidate_history), + total_generations=self.current_generation, + candidate_history=self.candidate_history.copy(), + best_candidate_id=best_candidate_id, + ) + + # Log summary of unique scores for debugging + unique_scores = sorted(set(r.avg_score for r in self.candidate_history)) + logger.info( + f"[GEPA] Optimization complete. {len(self.candidate_history)} unique candidates, {len(unique_scores)} distinct scores: {unique_scores[:10]}" + ) + final_candidate = Candidate( - agent=final_agent, - mutations=best_prompts, - rationale=f"GEPA optimized (score={best_score:.4f})" + agent=final_agent, mutations=best_prompts, rationale=f"GEPA optimized (score={best_score:.4f})" ) - + return [final_candidate] + + def get_report(self) -> GEPAOptimizationReport | None: + """Get the optimization report after generate() has been called.""" + return self._report + + def print_report(self, max_prompt_length: int = 500) -> None: + """Print a formatted optimization report to console.""" + if self._report is None: + print("No report available. Run generate() first.") + return + print(self._report.format_report(max_prompt_length)) diff --git a/src/flow/prompts.py b/src/flow/prompts.py index 9229266bdf1a11e103087db71b3fd6e2b4315e04..b098e6b7e335dd1aa731a49b9e9ede7f8501e1da 100644 --- a/src/flow/prompts.py +++ b/src/flow/prompts.py @@ -42,7 +42,6 @@ _CORE_CAPABILITIES = """ **Execution Tools:** - `bash`: Run shell commands (tests, git, npm, pip, builds, etc.) -- `python_repl`: Execute Python code snippets for quick validation **Research Tools (if available):** - `web_search`: Search the web using Google (requires GOOGLE_API_KEY and GOOGLE_CSE_ID) @@ -72,7 +71,7 @@ _CORE_WORKFLOW_PLAN_EXECUTE_VERIFY = """ ### 3. EXECUTE - Create/edit files using `write_file` -- Test changes using `bash` or `python_repl` +- Test changes using `bash` - Fix issues immediately when tests fail ### 4. VERIFY (REQUIRED) @@ -316,7 +315,7 @@ async def fetch_data(url): ''') # 4. Test it -python_repl("import httpx; print(httpx.__version__)") +bash("python -c 'import httpx; print(httpx.__version__)'") ``` """ diff --git a/src/flow/skills/docx/ooxml/scripts/pack.py b/src/flow/skills/docx/ooxml/scripts/pack.py index 68bc0886f6ef74e6e1d3fe6da0d6a296858a42d8..0feae53ed3c9c15c782145fe77687bf14d09b489 100755 --- a/src/flow/skills/docx/ooxml/scripts/pack.py +++ b/src/flow/skills/docx/ooxml/scripts/pack.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -""" -Tool to pack a directory into a .docx, .pptx, or .xlsx file with XML formatting undone. +"""Tool to pack a directory into a .docx, .pptx, or .xlsx file with XML formatting undone. Example usage: python pack.py [--force] @@ -11,10 +10,11 @@ import shutil import subprocess import sys import tempfile -import defusedxml.minidom import zipfile from pathlib import Path +import defusedxml.minidom + def main(): parser = argparse.ArgumentParser(description="Pack a directory into an Office file") @@ -87,7 +87,7 @@ def pack_document(input_dir, output_file, validate=False): return True -def validate_document(doc_path): +def validate_document(doc_path: Path) -> bool: """Validate document by converting to HTML with soffice.""" # Determine the correct filter based on file extension match doc_path.suffix.lower(): @@ -97,6 +97,8 @@ def validate_document(doc_path): filter_name = "html:impress_html_Export" case ".xlsx": filter_name = "html:HTML (StarCalc)" + case _: + raise ValueError(f"Unsupported file extension: {doc_path.suffix}") with tempfile.TemporaryDirectory() as temp_dir: try: @@ -132,7 +134,7 @@ def validate_document(doc_path): def condense_xml(xml_file): """Strip unnecessary whitespace and remove comments.""" - with open(xml_file, "r", encoding="utf-8") as f: + with open(xml_file, encoding="utf-8") as f: dom = defusedxml.minidom.parse(f) # Process each element to remove whitespace and comments diff --git a/src/flow/skills/docx/ooxml/scripts/unpack.py b/src/flow/skills/docx/ooxml/scripts/unpack.py index 4938798813e52daf03ab859f3c2faeece7f3aeea..2ac3909a7ec9b1f3f8d8d206aefa526b243b513d 100755 --- a/src/flow/skills/docx/ooxml/scripts/unpack.py +++ b/src/flow/skills/docx/ooxml/scripts/unpack.py @@ -3,10 +3,11 @@ import random import sys -import defusedxml.minidom import zipfile from pathlib import Path +import defusedxml.minidom + # Get command line arguments assert len(sys.argv) == 3, "Usage: python unpack.py " input_file, output_dir = sys.argv[1], sys.argv[2] diff --git a/src/flow/skills/docx/ooxml/scripts/validate.py b/src/flow/skills/docx/ooxml/scripts/validate.py index 508c5891faba622051a8d5566c118de7892d95bf..7770d991749a273adec6048cae667ff16fd81de5 100755 --- a/src/flow/skills/docx/ooxml/scripts/validate.py +++ b/src/flow/skills/docx/ooxml/scripts/validate.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -""" -Command line tool to validate Office document XML files against XSD schemas and tracked changes. +"""Command line tool to validate Office document XML files against XSD schemas and tracked changes. Usage: python validate.py --original diff --git a/src/flow/skills/docx/ooxml/scripts/validation/__init__.py b/src/flow/skills/docx/ooxml/scripts/validation/__init__.py index db092ece7e21de98f87bd81471578259a1bc642f..8cefb3b3f00b18d7f0720152cb4c0d51a332b186 100644 --- a/src/flow/skills/docx/ooxml/scripts/validation/__init__.py +++ b/src/flow/skills/docx/ooxml/scripts/validation/__init__.py @@ -1,5 +1,4 @@ -""" -Validation modules for Word document processing. +"""Validation modules for Word document processing. """ from .base import BaseSchemaValidator diff --git a/src/flow/skills/docx/ooxml/scripts/validation/base.py b/src/flow/skills/docx/ooxml/scripts/validation/base.py index 0681b199c2f0539763eb115596acd82ca9c53bf3..7e1a708e0b38df0e7e014e6d409ef17d7a4eca2b 100644 --- a/src/flow/skills/docx/ooxml/scripts/validation/base.py +++ b/src/flow/skills/docx/ooxml/scripts/validation/base.py @@ -1,5 +1,4 @@ -""" -Base validator with common validation logic for document files. +"""Base validator with common validation logic for document files. """ import re @@ -140,7 +139,7 @@ class BaseSchemaValidator: except Exception as e: errors.append( f" {xml_file.relative_to(self.unpacked_dir)}: " - f"Unexpected error: {str(e)}" + f"Unexpected error: {e!s}" ) if errors: @@ -275,8 +274,7 @@ class BaseSchemaValidator: return True def validate_file_references(self): - """ - Validate that all .rels files properly reference files and that all files are referenced. + """Validate that all .rels files properly reference files and that all files are referenced. """ errors = [] @@ -386,8 +384,7 @@ class BaseSchemaValidator: return True def validate_all_relationship_ids(self): - """ - Validate that all r:id attributes in XML files reference existing IDs + """Validate that all r:id attributes in XML files reference existing IDs in their corresponding .rels files, and optionally validate relationship types. """ import lxml.etree @@ -484,8 +481,7 @@ class BaseSchemaValidator: return True def _get_expected_relationship_type(self, element_name): - """ - Get the expected relationship type for an element. + """Get the expected relationship type for an element. First checks the explicit mapping, then tries pattern detection. """ # Normalize element name to lowercase @@ -725,7 +721,7 @@ class BaseSchemaValidator: if original_error_count: print(f" - With original errors (ignored): {original_error_count}") print( - f" - With NEW errors: {len(new_errors) > 0 and len([e for e in new_errors if not e.startswith(' ')]) or 0}" + f" - With NEW errors: {(len(new_errors) > 0 and len([e for e in new_errors if not e.startswith(' ')])) or 0}" ) if new_errors: @@ -839,7 +835,7 @@ class BaseSchemaValidator: schema = lxml.etree.XMLSchema(xsd_doc) # Load and preprocess XML - with open(xml_file, "r") as f: + with open(xml_file) as f: xml_doc = lxml.etree.parse(f) xml_doc, _ = self._remove_template_tags_from_text_nodes(xml_doc) diff --git a/src/flow/skills/docx/ooxml/scripts/validation/docx.py b/src/flow/skills/docx/ooxml/scripts/validation/docx.py index 602c47087ada8d5a10e90abc864f1225abcb2345..7927fd4480a14164f96c91894c911e5288e08ba5 100644 --- a/src/flow/skills/docx/ooxml/scripts/validation/docx.py +++ b/src/flow/skills/docx/ooxml/scripts/validation/docx.py @@ -1,5 +1,4 @@ -""" -Validator for Word document XML files against XSD schemas. +"""Validator for Word document XML files against XSD schemas. """ import re @@ -70,8 +69,7 @@ class DOCXSchemaValidator(BaseSchemaValidator): return all_valid def validate_whitespace_preservation(self): - """ - Validate that w:t elements with whitespace have xml:space='preserve'. + """Validate that w:t elements with whitespace have xml:space='preserve'. """ errors = [] @@ -122,8 +120,7 @@ class DOCXSchemaValidator(BaseSchemaValidator): return True def validate_deletions(self): - """ - Validate that w:t elements are not within w:del elements. + """Validate that w:t elements are not within w:del elements. For some reason, XSD validation does not catch this, so we do it manually. """ errors = [] @@ -214,8 +211,7 @@ class DOCXSchemaValidator(BaseSchemaValidator): return count def validate_insertions(self): - """ - Validate that w:delText elements are not within w:ins elements. + """Validate that w:delText elements are not within w:ins elements. w:delText is only allowed in w:ins if nested within a w:del. """ errors = [] diff --git a/src/flow/skills/docx/ooxml/scripts/validation/pptx.py b/src/flow/skills/docx/ooxml/scripts/validation/pptx.py index 66d5b1e2dba6d1b3dbcb290fa6ef1699980435e6..e93c01d102ec21d7891d9d86dda45fd7d5f7f576 100644 --- a/src/flow/skills/docx/ooxml/scripts/validation/pptx.py +++ b/src/flow/skills/docx/ooxml/scripts/validation/pptx.py @@ -1,5 +1,4 @@ -""" -Validator for PowerPoint presentation XML files against XSD schemas. +"""Validator for PowerPoint presentation XML files against XSD schemas. """ import re diff --git a/src/flow/skills/docx/ooxml/scripts/validation/redlining.py b/src/flow/skills/docx/ooxml/scripts/validation/redlining.py index 7ed425edf5336306b9eec87164e034d87decebb8..8c918c965735f6fc9b8e2d5c6e3251811a743a52 100644 --- a/src/flow/skills/docx/ooxml/scripts/validation/redlining.py +++ b/src/flow/skills/docx/ooxml/scripts/validation/redlining.py @@ -1,5 +1,4 @@ -""" -Validator for tracked changes in Word documents. +"""Validator for tracked changes in Word documents. """ import subprocess diff --git a/src/flow/skills/docx/scripts/document.py b/src/flow/skills/docx/scripts/document.py index ae9328ddf3a15802bd6b669b3b28e5cfbc1186d3..6e4d4582f26f22852ddcfe057170e3be09a64074 100755 --- a/src/flow/skills/docx/scripts/document.py +++ b/src/flow/skills/docx/scripts/document.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -""" -Library for working with Word documents: comments, tracked changes, and editing. +"""Library for working with Word documents: comments, tracked changes, and editing. Usage: from skills.docx.scripts.document import Document @@ -620,8 +619,7 @@ class Document: author="Claude", initials="C", ): - """ - Initialize with path to unpacked Word document directory. + """Initialize with path to unpacked Word document directory. Automatically sets up comment infrastructure (people.xml, RSIDs). Args: @@ -678,8 +676,7 @@ class Document: self._add_author_to_people(author) def __getitem__(self, xml_path: str) -> DocxXMLEditor: - """ - Get or create a DocxXMLEditor for the specified XML file. + """Get or create a DocxXMLEditor for the specified XML file. Enables lazy-loaded editors with bracket notation: node = doc["word/document.xml"].get_node(tag="w:p", line_number=42) @@ -711,8 +708,7 @@ class Document: return self._editors[xml_path] def add_comment(self, start, end, text: str) -> int: - """ - Add a comment spanning from one element to another. + """Add a comment spanning from one element to another. Args: start: DOM element for the starting point @@ -767,8 +763,7 @@ class Document: parent_comment_id: int, text: str, ) -> int: - """ - Add a reply to an existing comment. + """Add a reply to an existing comment. Args: parent_comment_id: The w:id of the parent comment to reply to @@ -836,8 +831,7 @@ class Document: shutil.rmtree(self.temp_dir) def validate(self) -> None: - """ - Validate the document against XSD schema and redlining rules. + """Validate the document against XSD schema and redlining rules. Raises: ValueError: If validation fails. @@ -857,8 +851,7 @@ class Document: raise ValueError("Redlining validation failed") def save(self, destination=None, validate=True) -> None: - """ - Save all modified XML files to disk and copy to destination directory. + """Save all modified XML files to disk and copy to destination directory. This persists all changes made via add_comment() and reply_to_comment(). diff --git a/src/flow/skills/docx/scripts/utilities.py b/src/flow/skills/docx/scripts/utilities.py index d92dae611d442cdfd498b2271a8221f98837be0a..e14f393a628a498f870bd05fe9d4cbef865580d9 100755 --- a/src/flow/skills/docx/scripts/utilities.py +++ b/src/flow/skills/docx/scripts/utilities.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -""" -Utilities for editing OOXML documents. +"""Utilities for editing OOXML documents. This module provides XMLEditor, a tool for manipulating XML files with support for line-number-based node finding and DOM manipulation. Each element is automatically @@ -32,15 +31,13 @@ Example usage: import html from pathlib import Path -from typing import Optional, Union import defusedxml.minidom import defusedxml.sax class XMLEditor: - """ - Editor for manipulating OOXML XML files with line-number-based node finding. + """Editor for manipulating OOXML XML files with line-number-based node finding. This class parses XML files and tracks the original line and column position of each element. This enables finding nodes by their line number in the original @@ -53,8 +50,7 @@ class XMLEditor: """ def __init__(self, xml_path): - """ - Initialize with path to XML file and parse with line number tracking. + """Initialize with path to XML file and parse with line number tracking. Args: xml_path: Path to XML file to edit (str or Path) @@ -76,12 +72,11 @@ class XMLEditor: def get_node( self, tag: str, - attrs: Optional[dict[str, str]] = None, - line_number: Optional[Union[int, range]] = None, - contains: Optional[str] = None, + attrs: dict[str, str] | None = None, + line_number: int | range | None = None, + contains: str | None = None, ): - """ - Get a DOM element by tag and identifier. + """Get a DOM element by tag and identifier. Finds an element by either its line number in the original file or by matching attribute values. Exactly one match must be found. @@ -181,8 +176,7 @@ class XMLEditor: return matches[0] def _get_element_text(self, elem): - """ - Recursively extract all text content from an element. + """Recursively extract all text content from an element. Skips text nodes that contain only whitespace (spaces, tabs, newlines), which typically represent XML formatting rather than document content. @@ -204,8 +198,7 @@ class XMLEditor: return "".join(text_parts) def replace_node(self, elem, new_content): - """ - Replace a DOM element with new XML content. + """Replace a DOM element with new XML content. Args: elem: defusedxml.minidom.Element to replace @@ -225,8 +218,7 @@ class XMLEditor: return nodes def insert_after(self, elem, xml_content): - """ - Insert XML content after a DOM element. + """Insert XML content after a DOM element. Args: elem: defusedxml.minidom.Element to insert after @@ -249,8 +241,7 @@ class XMLEditor: return nodes def insert_before(self, elem, xml_content): - """ - Insert XML content before a DOM element. + """Insert XML content before a DOM element. Args: elem: defusedxml.minidom.Element to insert before @@ -269,8 +260,7 @@ class XMLEditor: return nodes def append_to(self, elem, xml_content): - """ - Append XML content as a child of a DOM element. + """Append XML content as a child of a DOM element. Args: elem: defusedxml.minidom.Element to append to @@ -300,8 +290,7 @@ class XMLEditor: return f"rId{max_id + 1}" def save(self): - """ - Save the edited XML back to the file. + """Save the edited XML back to the file. Serializes the DOM tree and writes it back to the original file path, preserving the original encoding (ascii or utf-8). @@ -310,8 +299,7 @@ class XMLEditor: self.xml_path.write_bytes(content) def _parse_fragment(self, xml_content): - """ - Parse XML fragment and return list of imported nodes. + """Parse XML fragment and return list of imported nodes. Args: xml_content: String containing XML fragment @@ -344,8 +332,7 @@ class XMLEditor: def _create_line_tracking_parser(): - """ - Create a SAX parser that tracks line and column numbers for each element. + """Create a SAX parser that tracks line and column numbers for each element. Monkey patches the SAX content handler to store the current line and column position from the underlying expat parser onto each element as a parse_position diff --git a/src/flow/skills/pdf/scripts/check_bounding_boxes.py b/src/flow/skills/pdf/scripts/check_bounding_boxes.py index 7443660c07171df1a2793d2303ebd1461772696a..d7ddab9d3e7f9cad4932170e3fae4848468baeb0 100644 --- a/src/flow/skills/pdf/scripts/check_bounding_boxes.py +++ b/src/flow/skills/pdf/scripts/check_bounding_boxes.py @@ -1,7 +1,6 @@ -from dataclasses import dataclass import json import sys - +from dataclasses import dataclass # Script to check that the `fields.json` file that Claude creates when analyzing PDFs # does not have overlapping bounding boxes. See forms.md. diff --git a/src/flow/skills/pdf/scripts/check_bounding_boxes_test.py b/src/flow/skills/pdf/scripts/check_bounding_boxes_test.py index 1dbb463c878566001448eb1fcaa058980305f2f4..32779732daf44195c167fe18edd0c349f2ce6d04 100644 --- a/src/flow/skills/pdf/scripts/check_bounding_boxes_test.py +++ b/src/flow/skills/pdf/scripts/check_bounding_boxes_test.py @@ -1,6 +1,7 @@ -import unittest -import json import io +import json +import unittest + from check_bounding_boxes import get_bounding_box_messages diff --git a/src/flow/skills/pdf/scripts/check_fillable_fields.py b/src/flow/skills/pdf/scripts/check_fillable_fields.py index dc43d18213e818844212c225eeecdd5d70e2578e..71d69d02ab8ee3a020aa37dc1dcdddfa79d5c0f3 100644 --- a/src/flow/skills/pdf/scripts/check_fillable_fields.py +++ b/src/flow/skills/pdf/scripts/check_fillable_fields.py @@ -1,6 +1,6 @@ import sys -from pypdf import PdfReader +from pypdf import PdfReader # Script for Claude to run to determine whether a PDF has fillable form fields. See forms.md. diff --git a/src/flow/skills/pdf/scripts/convert_pdf_to_images.py b/src/flow/skills/pdf/scripts/convert_pdf_to_images.py index f8a4ec524b28eb1b380a536c24ea589faa3b7a2e..8807e7a96478518160d1bf41fff6d31da2aa3aaf 100644 --- a/src/flow/skills/pdf/scripts/convert_pdf_to_images.py +++ b/src/flow/skills/pdf/scripts/convert_pdf_to_images.py @@ -3,7 +3,6 @@ import sys from pdf2image import convert_from_path - # Converts each page of a PDF to a PNG image. diff --git a/src/flow/skills/pdf/scripts/create_validation_image.py b/src/flow/skills/pdf/scripts/create_validation_image.py index 4913f8f8d60e3dcadac05e07eb36504a1afd6a0e..00e8f0144fe313618f9bb0ed03148a73df5c20d1 100644 --- a/src/flow/skills/pdf/scripts/create_validation_image.py +++ b/src/flow/skills/pdf/scripts/create_validation_image.py @@ -3,14 +3,13 @@ import sys from PIL import Image, ImageDraw - # Creates "validation" images with rectangles for the bounding box information that # Claude creates when determining where to add text annotations in PDFs. See forms.md. def create_validation_image(page_number, fields_json_path, input_path, output_path): # Input file should be in the `fields.json` format described in forms.md. - with open(fields_json_path, 'r') as f: + with open(fields_json_path) as f: data = json.load(f) img = Image.open(input_path) diff --git a/src/flow/skills/pdf/scripts/extract_form_field_info.py b/src/flow/skills/pdf/scripts/extract_form_field_info.py index f42a2df847f4af044f652f5dbd2c9200227ffde3..1c33b45b8651e09c479ad1c0e8de430fd8f7f9a2 100644 --- a/src/flow/skills/pdf/scripts/extract_form_field_info.py +++ b/src/flow/skills/pdf/scripts/extract_form_field_info.py @@ -3,7 +3,6 @@ import sys from pypdf import PdfReader - # Extracts data for the fillable form fields in a PDF and outputs JSON that # Claude uses to fill the fields. See forms.md. diff --git a/src/flow/skills/pdf/scripts/fill_fillable_fields.py b/src/flow/skills/pdf/scripts/fill_fillable_fields.py index ac35753c5c63f565ed7ec4b89d6c6fd792aa5a8c..93ce6f3fb97634b837999419581aa52be0a775b6 100644 --- a/src/flow/skills/pdf/scripts/fill_fillable_fields.py +++ b/src/flow/skills/pdf/scripts/fill_fillable_fields.py @@ -1,10 +1,8 @@ import json import sys -from pypdf import PdfReader, PdfWriter - from extract_form_field_info import get_field_info - +from pypdf import PdfReader, PdfWriter # Fills fillable form fields in a PDF. See forms.md. @@ -88,8 +86,8 @@ def validation_error_for_field_value(field_info, field_value): # We call the original method and adjust the return value only if the argument to `get_inherited` # is `FA.Opt` and if the return value is a list of two-element lists. def monkeypatch_pydpf_method(): - from pypdf.generic import DictionaryObject from pypdf.constants import FieldDictionaryAttributes + from pypdf.generic import DictionaryObject original_get_inherited = DictionaryObject.get_inherited diff --git a/src/flow/skills/pdf/scripts/fill_pdf_form_with_annotations.py b/src/flow/skills/pdf/scripts/fill_pdf_form_with_annotations.py index f98053135007739d8a017846a2fc3d299f947411..936cb3ef25cd81fc814074d2e79dc20e379774e0 100644 --- a/src/flow/skills/pdf/scripts/fill_pdf_form_with_annotations.py +++ b/src/flow/skills/pdf/scripts/fill_pdf_form_with_annotations.py @@ -4,7 +4,6 @@ import sys from pypdf import PdfReader, PdfWriter from pypdf.annotations import FreeText - # Fills a PDF by adding text annotations defined in `fields.json`. See forms.md. @@ -27,9 +26,8 @@ def transform_coordinates(bbox, image_width, image_height, pdf_width, pdf_height def fill_pdf_form(input_pdf_path, fields_json_path, output_pdf_path): """Fill the PDF form with data from fields.json""" - # `fields.json` format described in forms.md. - with open(fields_json_path, "r") as f: + with open(fields_json_path) as f: fields_data = json.load(f) # Open the PDF diff --git a/src/flow/skills/pptx/ooxml/scripts/pack.py b/src/flow/skills/pptx/ooxml/scripts/pack.py index 68bc0886f6ef74e6e1d3fe6da0d6a296858a42d8..0feae53ed3c9c15c782145fe77687bf14d09b489 100755 --- a/src/flow/skills/pptx/ooxml/scripts/pack.py +++ b/src/flow/skills/pptx/ooxml/scripts/pack.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -""" -Tool to pack a directory into a .docx, .pptx, or .xlsx file with XML formatting undone. +"""Tool to pack a directory into a .docx, .pptx, or .xlsx file with XML formatting undone. Example usage: python pack.py [--force] @@ -11,10 +10,11 @@ import shutil import subprocess import sys import tempfile -import defusedxml.minidom import zipfile from pathlib import Path +import defusedxml.minidom + def main(): parser = argparse.ArgumentParser(description="Pack a directory into an Office file") @@ -87,7 +87,7 @@ def pack_document(input_dir, output_file, validate=False): return True -def validate_document(doc_path): +def validate_document(doc_path: Path) -> bool: """Validate document by converting to HTML with soffice.""" # Determine the correct filter based on file extension match doc_path.suffix.lower(): @@ -97,6 +97,8 @@ def validate_document(doc_path): filter_name = "html:impress_html_Export" case ".xlsx": filter_name = "html:HTML (StarCalc)" + case _: + raise ValueError(f"Unsupported file extension: {doc_path.suffix}") with tempfile.TemporaryDirectory() as temp_dir: try: @@ -132,7 +134,7 @@ def validate_document(doc_path): def condense_xml(xml_file): """Strip unnecessary whitespace and remove comments.""" - with open(xml_file, "r", encoding="utf-8") as f: + with open(xml_file, encoding="utf-8") as f: dom = defusedxml.minidom.parse(f) # Process each element to remove whitespace and comments diff --git a/src/flow/skills/pptx/ooxml/scripts/unpack.py b/src/flow/skills/pptx/ooxml/scripts/unpack.py index 4938798813e52daf03ab859f3c2faeece7f3aeea..2ac3909a7ec9b1f3f8d8d206aefa526b243b513d 100755 --- a/src/flow/skills/pptx/ooxml/scripts/unpack.py +++ b/src/flow/skills/pptx/ooxml/scripts/unpack.py @@ -3,10 +3,11 @@ import random import sys -import defusedxml.minidom import zipfile from pathlib import Path +import defusedxml.minidom + # Get command line arguments assert len(sys.argv) == 3, "Usage: python unpack.py " input_file, output_dir = sys.argv[1], sys.argv[2] diff --git a/src/flow/skills/pptx/ooxml/scripts/validate.py b/src/flow/skills/pptx/ooxml/scripts/validate.py index 508c5891faba622051a8d5566c118de7892d95bf..7770d991749a273adec6048cae667ff16fd81de5 100755 --- a/src/flow/skills/pptx/ooxml/scripts/validate.py +++ b/src/flow/skills/pptx/ooxml/scripts/validate.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -""" -Command line tool to validate Office document XML files against XSD schemas and tracked changes. +"""Command line tool to validate Office document XML files against XSD schemas and tracked changes. Usage: python validate.py --original diff --git a/src/flow/skills/pptx/ooxml/scripts/validation/__init__.py b/src/flow/skills/pptx/ooxml/scripts/validation/__init__.py index db092ece7e21de98f87bd81471578259a1bc642f..8cefb3b3f00b18d7f0720152cb4c0d51a332b186 100644 --- a/src/flow/skills/pptx/ooxml/scripts/validation/__init__.py +++ b/src/flow/skills/pptx/ooxml/scripts/validation/__init__.py @@ -1,5 +1,4 @@ -""" -Validation modules for Word document processing. +"""Validation modules for Word document processing. """ from .base import BaseSchemaValidator diff --git a/src/flow/skills/pptx/ooxml/scripts/validation/base.py b/src/flow/skills/pptx/ooxml/scripts/validation/base.py index 0681b199c2f0539763eb115596acd82ca9c53bf3..7e1a708e0b38df0e7e014e6d409ef17d7a4eca2b 100644 --- a/src/flow/skills/pptx/ooxml/scripts/validation/base.py +++ b/src/flow/skills/pptx/ooxml/scripts/validation/base.py @@ -1,5 +1,4 @@ -""" -Base validator with common validation logic for document files. +"""Base validator with common validation logic for document files. """ import re @@ -140,7 +139,7 @@ class BaseSchemaValidator: except Exception as e: errors.append( f" {xml_file.relative_to(self.unpacked_dir)}: " - f"Unexpected error: {str(e)}" + f"Unexpected error: {e!s}" ) if errors: @@ -275,8 +274,7 @@ class BaseSchemaValidator: return True def validate_file_references(self): - """ - Validate that all .rels files properly reference files and that all files are referenced. + """Validate that all .rels files properly reference files and that all files are referenced. """ errors = [] @@ -386,8 +384,7 @@ class BaseSchemaValidator: return True def validate_all_relationship_ids(self): - """ - Validate that all r:id attributes in XML files reference existing IDs + """Validate that all r:id attributes in XML files reference existing IDs in their corresponding .rels files, and optionally validate relationship types. """ import lxml.etree @@ -484,8 +481,7 @@ class BaseSchemaValidator: return True def _get_expected_relationship_type(self, element_name): - """ - Get the expected relationship type for an element. + """Get the expected relationship type for an element. First checks the explicit mapping, then tries pattern detection. """ # Normalize element name to lowercase @@ -725,7 +721,7 @@ class BaseSchemaValidator: if original_error_count: print(f" - With original errors (ignored): {original_error_count}") print( - f" - With NEW errors: {len(new_errors) > 0 and len([e for e in new_errors if not e.startswith(' ')]) or 0}" + f" - With NEW errors: {(len(new_errors) > 0 and len([e for e in new_errors if not e.startswith(' ')])) or 0}" ) if new_errors: @@ -839,7 +835,7 @@ class BaseSchemaValidator: schema = lxml.etree.XMLSchema(xsd_doc) # Load and preprocess XML - with open(xml_file, "r") as f: + with open(xml_file) as f: xml_doc = lxml.etree.parse(f) xml_doc, _ = self._remove_template_tags_from_text_nodes(xml_doc) diff --git a/src/flow/skills/pptx/ooxml/scripts/validation/docx.py b/src/flow/skills/pptx/ooxml/scripts/validation/docx.py index 602c47087ada8d5a10e90abc864f1225abcb2345..7927fd4480a14164f96c91894c911e5288e08ba5 100644 --- a/src/flow/skills/pptx/ooxml/scripts/validation/docx.py +++ b/src/flow/skills/pptx/ooxml/scripts/validation/docx.py @@ -1,5 +1,4 @@ -""" -Validator for Word document XML files against XSD schemas. +"""Validator for Word document XML files against XSD schemas. """ import re @@ -70,8 +69,7 @@ class DOCXSchemaValidator(BaseSchemaValidator): return all_valid def validate_whitespace_preservation(self): - """ - Validate that w:t elements with whitespace have xml:space='preserve'. + """Validate that w:t elements with whitespace have xml:space='preserve'. """ errors = [] @@ -122,8 +120,7 @@ class DOCXSchemaValidator(BaseSchemaValidator): return True def validate_deletions(self): - """ - Validate that w:t elements are not within w:del elements. + """Validate that w:t elements are not within w:del elements. For some reason, XSD validation does not catch this, so we do it manually. """ errors = [] @@ -214,8 +211,7 @@ class DOCXSchemaValidator(BaseSchemaValidator): return count def validate_insertions(self): - """ - Validate that w:delText elements are not within w:ins elements. + """Validate that w:delText elements are not within w:ins elements. w:delText is only allowed in w:ins if nested within a w:del. """ errors = [] diff --git a/src/flow/skills/pptx/ooxml/scripts/validation/pptx.py b/src/flow/skills/pptx/ooxml/scripts/validation/pptx.py index 66d5b1e2dba6d1b3dbcb290fa6ef1699980435e6..e93c01d102ec21d7891d9d86dda45fd7d5f7f576 100644 --- a/src/flow/skills/pptx/ooxml/scripts/validation/pptx.py +++ b/src/flow/skills/pptx/ooxml/scripts/validation/pptx.py @@ -1,5 +1,4 @@ -""" -Validator for PowerPoint presentation XML files against XSD schemas. +"""Validator for PowerPoint presentation XML files against XSD schemas. """ import re diff --git a/src/flow/skills/pptx/ooxml/scripts/validation/redlining.py b/src/flow/skills/pptx/ooxml/scripts/validation/redlining.py index 7ed425edf5336306b9eec87164e034d87decebb8..8c918c965735f6fc9b8e2d5c6e3251811a743a52 100644 --- a/src/flow/skills/pptx/ooxml/scripts/validation/redlining.py +++ b/src/flow/skills/pptx/ooxml/scripts/validation/redlining.py @@ -1,5 +1,4 @@ -""" -Validator for tracked changes in Word documents. +"""Validator for tracked changes in Word documents. """ import subprocess diff --git a/src/flow/skills/pptx/scripts/inventory.py b/src/flow/skills/pptx/scripts/inventory.py index edda390e721f3e621002eb1986f50f1046d9a6ba..9c0379291ee498b69038bbe8437146913d2ccf91 100755 --- a/src/flow/skills/pptx/scripts/inventory.py +++ b/src/flow/skills/pptx/scripts/inventory.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -""" -Extract structured text content from PowerPoint presentations. +"""Extract structured text content from PowerPoint presentations. This module provides functionality to: - Extract all text content from PowerPoint shapes @@ -28,7 +27,7 @@ import platform import sys from dataclasses import dataclass from pathlib import Path -from typing import Any, Dict, List, Optional, Tuple, Union +from typing import Any, Union from PIL import Image, ImageDraw, ImageFont from pptx import Presentation @@ -37,14 +36,14 @@ from pptx.shapes.base import BaseShape # Type aliases for cleaner signatures JsonValue = Union[str, int, float, bool, None] -ParagraphDict = Dict[str, JsonValue] -ShapeDict = Dict[ - str, Union[str, float, bool, List[ParagraphDict], List[str], Dict[str, Any], None] +ParagraphDict = dict[str, JsonValue] +ShapeDict = dict[ + str, str | float | bool | list[ParagraphDict] | list[str] | dict[str, Any] | None ] -InventoryData = Dict[ - str, Dict[str, "ShapeData"] +InventoryData = dict[ + str, dict[str, "ShapeData"] ] # Dict of slide_id -> {shape_id -> ShapeData} -InventoryDict = Dict[str, Dict[str, ShapeDict]] # JSON-serializable inventory +InventoryDict = dict[str, dict[str, ShapeDict]] # JSON-serializable inventory def main(): @@ -145,18 +144,18 @@ class ParagraphData: """ self.text: str = paragraph.text.strip() self.bullet: bool = False - self.level: Optional[int] = None - self.alignment: Optional[str] = None - self.space_before: Optional[float] = None - self.space_after: Optional[float] = None - self.font_name: Optional[str] = None - self.font_size: Optional[float] = None - self.bold: Optional[bool] = None - self.italic: Optional[bool] = None - self.underline: Optional[bool] = None - self.color: Optional[str] = None - self.theme_color: Optional[str] = None - self.line_spacing: Optional[float] = None + self.level: int | None = None + self.alignment: str | None = None + self.space_before: float | None = None + self.space_after: float | None = None + self.font_name: str | None = None + self.font_size: float | None = None + self.bold: bool | None = None + self.italic: bool | None = None + self.underline: bool | None = None + self.color: str | None = None + self.theme_color: str | None = None + self.line_spacing: float | None = None # Check for bullet formatting if ( @@ -277,7 +276,7 @@ class ShapeData: return int(inches * dpi) @staticmethod - def get_font_path(font_name: str) -> Optional[str]: + def get_font_path(font_name: str) -> str | None: """Get the font file path for a given font name. Args: @@ -343,7 +342,7 @@ class ShapeData: return None @staticmethod - def get_slide_dimensions(slide: Any) -> tuple[Optional[int], Optional[int]]: + def get_slide_dimensions(slide: Any) -> tuple[int | None, int | None]: """Get slide dimensions from slide object. Args: @@ -359,7 +358,7 @@ class ShapeData: return None, None @staticmethod - def get_default_font_size(shape: BaseShape, slide_layout: Any) -> Optional[float]: + def get_default_font_size(shape: BaseShape, slide_layout: Any) -> float | None: """Extract default font size from slide layout for a placeholder shape. Args: @@ -388,9 +387,9 @@ class ShapeData: def __init__( self, shape: BaseShape, - absolute_left: Optional[int] = None, - absolute_top: Optional[int] = None, - slide: Optional[Any] = None, + absolute_left: int | None = None, + absolute_top: int | None = None, + slide: Any | None = None, ): """Initialize from a PowerPoint shape object. @@ -409,8 +408,8 @@ class ShapeData: ) # Get placeholder type if applicable - self.placeholder_type: Optional[str] = None - self.default_font_size: Optional[float] = None + self.placeholder_type: str | None = None + self.default_font_size: float | None = None if hasattr(shape, "is_placeholder") and shape.is_placeholder: # type: ignore if shape.placeholder_format and shape.placeholder_format.type: # type: ignore self.placeholder_type = ( @@ -454,19 +453,19 @@ class ShapeData: self.height_emu = shape.height if hasattr(shape, "height") else 0 # Calculate overflow status - self.frame_overflow_bottom: Optional[float] = None - self.slide_overflow_right: Optional[float] = None - self.slide_overflow_bottom: Optional[float] = None - self.overlapping_shapes: Dict[ + self.frame_overflow_bottom: float | None = None + self.slide_overflow_right: float | None = None + self.slide_overflow_bottom: float | None = None + self.overlapping_shapes: dict[ str, float ] = {} # Dict of shape_id -> overlap area in sq inches - self.warnings: List[str] = [] + self.warnings: list[str] = [] self._estimate_frame_overflow() self._calculate_slide_overflow() self._detect_bullet_issues() @property - def paragraphs(self) -> List[ParagraphData]: + def paragraphs(self) -> list[ParagraphData]: """Calculate paragraphs from the shape's text frame.""" if not self.shape or not hasattr(self.shape, "text_frame"): return [] @@ -506,7 +505,7 @@ class ShapeData: return 14 # Conservative default for body text - def _get_usable_dimensions(self, text_frame) -> Tuple[int, int]: + def _get_usable_dimensions(self, text_frame) -> tuple[int, int]: """Get usable width and height in pixels after accounting for margins.""" # Default PowerPoint margins in inches margins = {"top": 0.05, "bottom": 0.05, "left": 0.1, "right": 0.1} @@ -531,7 +530,7 @@ class ShapeData: self.inches_to_pixels(usable_height), ) - def _wrap_text_line(self, line: str, max_width_px: int, draw, font) -> List[str]: + def _wrap_text_line(self, line: str, max_width_px: int, draw, font) -> list[str]: """Wrap a single line of text to fit within max_width_px.""" if not line: return [""] @@ -765,7 +764,7 @@ def is_valid_shape(shape: BaseShape) -> bool: def collect_shapes_with_absolute_positions( shape: BaseShape, parent_left: int = 0, parent_top: int = 0 -) -> List[ShapeWithPosition]: +) -> list[ShapeWithPosition]: """Recursively collect all shapes with valid text, calculating absolute positions. For shapes within groups, their positions are relative to the group. @@ -816,7 +815,7 @@ def collect_shapes_with_absolute_positions( return [] -def sort_shapes_by_position(shapes: List[ShapeData]) -> List[ShapeData]: +def sort_shapes_by_position(shapes: list[ShapeData]) -> list[ShapeData]: """Sort shapes by visual position (top-to-bottom, left-to-right). Shapes within 0.5 inches vertically are considered on the same row. @@ -847,10 +846,10 @@ def sort_shapes_by_position(shapes: List[ShapeData]) -> List[ShapeData]: def calculate_overlap( - rect1: Tuple[float, float, float, float], - rect2: Tuple[float, float, float, float], + rect1: tuple[float, float, float, float], + rect2: tuple[float, float, float, float], tolerance: float = 0.05, -) -> Tuple[bool, float]: +) -> tuple[bool, float]: """Calculate if and how much two rectangles overlap. Args: @@ -879,7 +878,7 @@ def calculate_overlap( return False, 0 -def detect_overlaps(shapes: List[ShapeData]) -> None: +def detect_overlaps(shapes: list[ShapeData]) -> None: """Detect overlapping shapes and update their overlapping_shapes dictionaries. This function requires each ShapeData to have its shape_id already set. @@ -912,7 +911,7 @@ def detect_overlaps(shapes: List[ShapeData]) -> None: def extract_text_inventory( - pptx_path: Path, prs: Optional[Any] = None, issues_only: bool = False + pptx_path: Path, prs: Any | None = None, issues_only: bool = False ) -> InventoryData: """Extract text content from all slides in a PowerPoint presentation. diff --git a/src/flow/skills/pptx/scripts/rearrange.py b/src/flow/skills/pptx/scripts/rearrange.py index 2519911f152beb7c2cf300354b5c4a88a1ea3c10..acd65ee168990be371869d2f3d132d2754f98b02 100755 --- a/src/flow/skills/pptx/scripts/rearrange.py +++ b/src/flow/skills/pptx/scripts/rearrange.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -""" -Rearrange PowerPoint slides based on a sequence of indices. +"""Rearrange PowerPoint slides based on a sequence of indices. Usage: python rearrange.py template.pptx output.pptx 0,34,34,50,52 @@ -147,8 +146,7 @@ def reorder_slides(pres, slide_index, target_index): def rearrange_presentation(template_path, output_path, slide_sequence): - """ - Create a new presentation with slides from template in specified order. + """Create a new presentation with slides from template in specified order. Args: template_path: Path to template PPTX file @@ -176,7 +174,7 @@ def rearrange_presentation(template_path, output_path, slide_sequence): # Step 1: DUPLICATE repeated slides print(f"Processing {len(slide_sequence)} slides from template...") for i, template_idx in enumerate(slide_sequence): - if template_idx in duplicated and duplicated[template_idx]: + if duplicated.get(template_idx): # Already duplicated this slide, use the duplicate slide_map.append(duplicated[template_idx].pop(0)) print(f" [{i}] Using duplicate of slide {template_idx}") diff --git a/src/flow/skills/pptx/scripts/replace.py b/src/flow/skills/pptx/scripts/replace.py index 8f7a8b1ba38c62fa190c158f96182ed795b9ddc1..80f3ee9b7afc157086e94161ca5a447da0feb8cb 100755 --- a/src/flow/skills/pptx/scripts/replace.py +++ b/src/flow/skills/pptx/scripts/replace.py @@ -12,7 +12,7 @@ unless "paragraphs" is specified in the replacements for that shape. import json import sys from pathlib import Path -from typing import Any, Dict, List +from typing import Any from inventory import InventoryData, extract_text_inventory from pptx import Presentation @@ -40,7 +40,7 @@ def clear_paragraph_bullets(paragraph): return pPr -def apply_paragraph_properties(paragraph, para_data: Dict[str, Any]): +def apply_paragraph_properties(paragraph, para_data: dict[str, Any]): """Apply formatting properties to a paragraph.""" # Get the text but don't set it on paragraph directly yet text = para_data.get("text", "") @@ -110,7 +110,7 @@ def apply_paragraph_properties(paragraph, para_data: Dict[str, Any]): apply_font_properties(run, para_data) -def apply_font_properties(run, para_data: Dict[str, Any]): +def apply_font_properties(run, para_data: dict[str, Any]): """Apply font properties to a text run.""" if "bold" in para_data: run.font.bold = para_data["bold"] @@ -140,7 +140,7 @@ def apply_font_properties(run, para_data: Dict[str, Any]): print(f" WARNING: Unknown theme color name '{theme_name}'") -def detect_frame_overflow(inventory: InventoryData) -> Dict[str, Dict[str, float]]: +def detect_frame_overflow(inventory: InventoryData) -> dict[str, dict[str, float]]: """Detect text overflow in shapes (text exceeding shape bounds). Returns dict of slide_key -> shape_key -> overflow_inches. @@ -159,7 +159,7 @@ def detect_frame_overflow(inventory: InventoryData) -> Dict[str, Dict[str, float return overflow_map -def validate_replacements(inventory: InventoryData, replacements: Dict) -> List[str]: +def validate_replacements(inventory: InventoryData, replacements: dict) -> list[str]: """Validate that all shapes in replacements exist in inventory. Returns list of error messages. @@ -213,7 +213,6 @@ def check_duplicate_keys(pairs): def apply_replacements(pptx_file: str, json_file: str, output_file: str): """Apply text replacements from JSON to PowerPoint presentation.""" - # Load presentation prs = Presentation(pptx_file) @@ -225,7 +224,7 @@ def apply_replacements(pptx_file: str, json_file: str, output_file: str): original_overflow = detect_frame_overflow(inventory) # Load replacement data with duplicate key detection - with open(json_file, "r") as f: + with open(json_file) as f: replacements = json.load(f, object_pairs_hook=check_duplicate_keys) # Validate replacements diff --git a/src/flow/skills/pptx/scripts/thumbnail.py b/src/flow/skills/pptx/scripts/thumbnail.py index 5c7fdf1977e6496cbb9ea83729e7b1df1a36c310..fe93fd4f43f9151d9a571ab544df989b50a3dd84 100755 --- a/src/flow/skills/pptx/scripts/thumbnail.py +++ b/src/flow/skills/pptx/scripts/thumbnail.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -""" -Create thumbnail grids from PowerPoint presentation slides. +"""Create thumbnail grids from PowerPoint presentation slides. Creates a grid layout of slide thumbnails with configurable columns (max 6). Each grid contains up to cols×(cols+1) images. For presentations with more diff --git a/src/flow/skills/skill-creator/scripts/init_skill.py b/src/flow/skills/skill-creator/scripts/init_skill.py index 329ad4e5a71546b2c455f8e08c98b32ecdd3c1e3..1bbb64d7a8bb407b9144a7ce1408f0ca0b30b5f8 100755 --- a/src/flow/skills/skill-creator/scripts/init_skill.py +++ b/src/flow/skills/skill-creator/scripts/init_skill.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -""" -Skill Initializer - Creates a new skill from template +"""Skill Initializer - Creates a new skill from template Usage: init_skill.py --path @@ -14,7 +13,6 @@ Examples: import sys from pathlib import Path - SKILL_TEMPLATE = """--- name: {skill_name} description: [TODO: Complete and informative explanation of what the skill does and when to use it. Include WHEN to use this skill - specific scenarios, file types, or tasks that trigger it.] @@ -192,8 +190,7 @@ def title_case_skill_name(skill_name): def init_skill(skill_name, path): - """ - Initialize a new skill directory with template SKILL.md. + """Initialize a new skill directory with template SKILL.md. Args: skill_name: Name of the skill diff --git a/src/flow/skills/skill-creator/scripts/package_skill.py b/src/flow/skills/skill-creator/scripts/package_skill.py index 5cd36cb16e1314f2ab87d50aaedbc9f26925dac1..6443654e03ba2ffdc7e9fa38e39a4024fd3ee5f5 100755 --- a/src/flow/skills/skill-creator/scripts/package_skill.py +++ b/src/flow/skills/skill-creator/scripts/package_skill.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -""" -Skill Packager - Creates a distributable .skill file of a skill folder +"""Skill Packager - Creates a distributable .skill file of a skill folder Usage: python utils/package_skill.py [output-directory] @@ -13,12 +12,12 @@ Example: import sys import zipfile from pathlib import Path + from quick_validate import validate_skill def package_skill(skill_path, output_dir=None): - """ - Package a skill folder into a .skill file. + """Package a skill folder into a .skill file. Args: skill_path: Path to the skill folder diff --git a/src/flow/skills/skill-creator/scripts/quick_validate.py b/src/flow/skills/skill-creator/scripts/quick_validate.py index d9fbeb75ee10bd8f89c0ee9b6716867125820c7e..3f35d369ed23bc7d845d93d80c0359fd04c06729 100755 --- a/src/flow/skills/skill-creator/scripts/quick_validate.py +++ b/src/flow/skills/skill-creator/scripts/quick_validate.py @@ -1,14 +1,14 @@ #!/usr/bin/env python3 -""" -Quick validation script for skills - minimal version +"""Quick validation script for skills - minimal version """ -import sys -import os import re -import yaml +import sys from pathlib import Path +import yaml + + def validate_skill(skill_path): """Basic validation of a skill""" skill_path = Path(skill_path) diff --git a/src/flow/skills/webapp-testing/examples/console_logging.py b/src/flow/skills/webapp-testing/examples/console_logging.py index 9329b5e232ed53d944bfe95e750070117d31b9ab..e8109219da66b8bfcb6fb1825d1f15e07cb986fe 100644 --- a/src/flow/skills/webapp-testing/examples/console_logging.py +++ b/src/flow/skills/webapp-testing/examples/console_logging.py @@ -32,4 +32,4 @@ with open('/mnt/user-data/outputs/console.log', 'w') as f: f.write('\n'.join(console_logs)) print(f"\nCaptured {len(console_logs)} console messages") -print(f"Logs saved to: /mnt/user-data/outputs/console.log") \ No newline at end of file +print("Logs saved to: /mnt/user-data/outputs/console.log") \ No newline at end of file diff --git a/src/flow/skills/webapp-testing/examples/static_html_automation.py b/src/flow/skills/webapp-testing/examples/static_html_automation.py index 90bbedcc08cdb345c74fb938ebad02c0baf56603..f43bcc71cf83bcb36f5fba6a90d42e449dc69f65 100644 --- a/src/flow/skills/webapp-testing/examples/static_html_automation.py +++ b/src/flow/skills/webapp-testing/examples/static_html_automation.py @@ -1,6 +1,7 @@ -from playwright.sync_api import sync_playwright import os +from playwright.sync_api import sync_playwright + # Example: Automating interaction with static HTML files using file:// URLs html_file_path = os.path.abspath('path/to/your/file.html') diff --git a/src/flow/skills/webapp-testing/scripts/with_server.py b/src/flow/skills/webapp-testing/scripts/with_server.py index 431f2eba16b268b7f3e2ae4daae9db41c0289b6d..e76852f65db4d4bec1b0c6a103dfecda162e4a44 100755 --- a/src/flow/skills/webapp-testing/scripts/with_server.py +++ b/src/flow/skills/webapp-testing/scripts/with_server.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -""" -Start one or more servers, wait for them to be ready, run a command, then clean up. +"""Start one or more servers, wait for them to be ready, run a command, then clean up. Usage: # Single server @@ -14,11 +13,12 @@ Usage: -- python test.py """ -import subprocess +import argparse import socket -import time +import subprocess import sys -import argparse +import time + def is_server_ready(port, timeout=30): """Wait for server to be ready by polling the port.""" @@ -27,7 +27,7 @@ def is_server_ready(port, timeout=30): try: with socket.create_connection(('localhost', port), timeout=1): return True - except (socket.error, ConnectionRefusedError): + except (OSError, ConnectionRefusedError): time.sleep(0.5) return False diff --git a/src/flow/skills/xlsx/recalc.py b/src/flow/skills/xlsx/recalc.py index 102e157b0b6392090b2ec3e602ee8fe37fe6c7a3..763b678910cd9b5d639e55b750577bade3b86cfc 100644 --- a/src/flow/skills/xlsx/recalc.py +++ b/src/flow/skills/xlsx/recalc.py @@ -1,15 +1,15 @@ #!/usr/bin/env python3 -""" -Excel Formula Recalculation Script +"""Excel Formula Recalculation Script Recalculates all formulas in an Excel file using LibreOffice """ import json -import sys -import subprocess import os import platform +import subprocess +import sys from pathlib import Path + from openpyxl import load_workbook @@ -23,7 +23,7 @@ def setup_libreoffice_macro(): macro_file = os.path.join(macro_dir, 'Module1.xba') if os.path.exists(macro_file): - with open(macro_file, 'r') as f: + with open(macro_file) as f: if 'RecalculateAndSave' in f.read(): return True @@ -51,8 +51,7 @@ def setup_libreoffice_macro(): def recalc(filename, timeout=30): - """ - Recalculate formulas in Excel file and report any errors + """Recalculate formulas in Excel file and report any errors Args: filename: Path to Excel file diff --git a/src/flow/tools/__init__.py b/src/flow/tools/__init__.py index 3ef9f574b7ddbd75079bdd4d4c82fc6c99a3a421..ab11122b04658894cd1411b989ffdba6029bdcaf 100644 --- a/src/flow/tools/__init__.py +++ b/src/flow/tools/__init__.py @@ -24,7 +24,6 @@ Coding/Filesystem: Execution: - bash: Execute shell commands - check_processes: Manage background processes -- python_repl: Execute Python code Planning: - think: Explicit reasoning tool @@ -55,45 +54,68 @@ import logging from pathlib import Path from typing import Any +# Adapters for framework integration +from .adapters import to_maf_tool, to_openai_tool, tools_to_maf, tools_to_openai from .base import Tool, tool +# Browsing tools (optional - requires smolagents) +try: + from .browsing import ( + create_smol_web_search_tool, + create_visit_webpage_tool, + wikipedia_search, + ) + _HAS_SMOLAGENTS = True +except ImportError: + _HAS_SMOLAGENTS = False + create_smol_web_search_tool = None # type: ignore[assignment, misc] + create_visit_webpage_tool = None # type: ignore[assignment, misc] + wikipedia_search = None # type: ignore[assignment, misc] + # Coding tools from .coding import ( - read_file, - write_file, edit_file, - multi_edit, glob_files, grep, ls, + multi_edit, + read_file, + write_file, ) # Execution tools -from .execution import bash, check_processes, python_repl - -# Planning tools -from .planning import think, todo_write, todo_read +from .execution import bash, check_processes # Memory tools -from .memory import memory, create_memory_tool - -# Web tools -from .web import web_search, web_fetch +from .memory import create_memory_tool, memory # Notebook tools from .notebook import notebook_edit, notebook_read +# Planning tools +from .planning import think, todo_read, todo_write + # Skills tools -from .skills import skills, create_skills_tool +from .skills import create_skills_tool, skills # Sub-agent tools -from .subagent import task, create_task_tool +from .subagent import create_task_tool, task + +# File inspection QA tools (optional - requires smolagents) +try: + from .text_inspector_qa import text_inspector + from .visual_inspector_qa import visual_inspector + _HAS_INSPECTORS = True +except ImportError: + _HAS_INSPECTORS = False + text_inspector = None # type: ignore[assignment, misc] + visual_inspector = None # type: ignore[assignment, misc] -# Workspace management -from .workspace import Workspace, get_workspace, set_workspace, reset_workspace +# Web tools +from .web import web_fetch, web_search -# Adapters for framework integration -from .adapters import to_maf_tool, to_openai_tool, tools_to_maf, tools_to_openai +# Workspace management +from .workspace import Workspace, get_workspace, reset_workspace, set_workspace __all__ = [ # Base @@ -110,7 +132,6 @@ __all__ = [ # Execution tools "bash", "check_processes", - "python_repl", # Planning tools "think", "todo_write", @@ -146,6 +167,12 @@ __all__ = [ "web_tools", "all_tools", "build_tools", + # browsing tools + "create_smol_web_search_tool", + "create_visit_webpage_tool", + "wikipedia_search", + "text_inspector", + "visual_inspector", ] logger = logging.getLogger(__name__) @@ -184,9 +211,9 @@ def execution_tools() -> list[Tool]: Returns: List of Tool instances for running code and commands. - Includes: bash, check_processes, python_repl + Includes: bash, check_processes """ - return [bash, check_processes, python_repl] + return [bash, check_processes] def web_tools() -> list[Tool]: @@ -221,12 +248,7 @@ def all_tools() -> list[Tool]: For custom configurations (e.g., specific workspace), use create_*_tool functions. """ return ( - coding_tools() - + planning_tools() - + execution_tools() - + web_tools() - + notebook_tools() - + [memory, skills, task] + coding_tools() + planning_tools() + execution_tools() + web_tools() + notebook_tools() + [memory, skills, task] ) @@ -299,7 +321,6 @@ def _get_tool_by_name(name: str, config: dict[str, Any]) -> Tool | None: # Execution tools "bash": bash, "check_processes": check_processes, - "python_repl": python_repl, # Planning tools "think": think, "todo_write": todo_write, @@ -318,13 +339,45 @@ def _get_tool_by_name(name: str, config: dict[str, Any]) -> Tool | None: "task": task, } + # Add optional inspector tools if available + if _HAS_INSPECTORS: + tool_map["text_inspector"] = text_inspector + tool_map["visual_inspector"] = visual_inspector + if name in tool_map: - return tool_map[name] + tool_instance = tool_map[name] + if tool_instance is not None: + return tool_instance + # Tool exists in map but is None (optional dep missing) + logger.warning(f"Tool {name} requires optional dependencies. Install with: uv sync --extra smolagents") + return None # Handle configurable tools that need factory functions if name == "skills" and config.get("additional_paths"): return create_skills_tool(project_path=Path(config["additional_paths"][0])) + # Smolagents-based tools (optional) + if name == "wikipedia_search": + if _HAS_SMOLAGENTS and wikipedia_search is not None: + return wikipedia_search + logger.warning("wikipedia_search requires smolagents. Install with: uv sync --extra smolagents") + return None + + if name == "smol_web_search": + if _HAS_SMOLAGENTS and create_smol_web_search_tool is not None: + wst_max_results = config.get("wst_max_results", 10) + wst_engine = config.get("wst_engine", "duckduckgo") + return create_smol_web_search_tool(max_results=wst_max_results, engine=wst_engine) + logger.warning("smol_web_search requires smolagents. Install with: uv sync --extra smolagents") + return None + + if name == "visit_webpage": + if _HAS_SMOLAGENTS and create_visit_webpage_tool is not None: + vwp_max_output_length = config.get("vwp_max_output_length", 40000) + return create_visit_webpage_tool(max_output_length=vwp_max_output_length) + logger.warning("visit_webpage requires smolagents. Install with: uv sync --extra smolagents") + return None + # Unknown tool - log warning and skip logger.warning(f"Unknown tool name: {name}. Skipping.") return None diff --git a/src/flow/tools/adapters.py b/src/flow/tools/adapters.py index 1f6228ec80f95eb2ed7e43c32be0290015f4b8fb..ed5d3720f9f669e086713871b1d80cc998d5377e 100644 --- a/src/flow/tools/adapters.py +++ b/src/flow/tools/adapters.py @@ -21,7 +21,7 @@ if TYPE_CHECKING: logger = logging.getLogger(__name__) -def to_maf_tool(tool: Tool) -> "Callable[..., Any]": +def to_maf_tool(tool: Tool) -> Callable[..., Any]: """Convert a Flow Tool to a MAF-decorated function. Applies the MAF @tool decorator to the underlying function, @@ -74,7 +74,7 @@ def to_openai_tool(tool: Tool) -> dict[str, Any]: return tool.to_openai_tool() -def tools_to_maf(tools: list[Tool]) -> "list[Callable[..., Any]]": +def tools_to_maf(tools: list[Tool]) -> list[Callable[..., Any]]: """Convert a list of Flow Tools to MAF-decorated functions. Args: diff --git a/src/flow/tools/base.py b/src/flow/tools/base.py index fa8526ed7c903edc2c332bdf45f6c50ab0f70737..2de822ebbef2b08a262aeb1a79a1366c2667bc1e 100644 --- a/src/flow/tools/base.py +++ b/src/flow/tools/base.py @@ -10,9 +10,10 @@ Example: return f"Results for: {query}" """ -from dataclasses import dataclass -from typing import Any, Callable, Literal, get_type_hints, get_origin, get_args, Annotated import inspect +from collections.abc import Callable +from dataclasses import dataclass +from typing import Annotated, Any, Literal, get_args, get_origin, get_type_hints @dataclass @@ -56,7 +57,7 @@ class Tool: result = await result return str(result) if not isinstance(result, str) else result except Exception as e: - return f"Error executing {self.name}: {str(e)}" + return f"Error executing {self.name}: {e!s}" def _python_type_to_json_schema(py_type: Any) -> dict[str, Any]: @@ -66,13 +67,13 @@ def _python_type_to_json_schema(py_type: Any) -> dict[str, Any]: return {"type": "null"} # Handle basic types - if py_type == str: + if py_type is str: return {"type": "string"} - if py_type == int: + if py_type is int: return {"type": "integer"} - if py_type == float: + if py_type is float: return {"type": "number"} - if py_type == bool: + if py_type is bool: return {"type": "boolean"} # Handle dict without type args diff --git a/src/flow/tools/browsing.py b/src/flow/tools/browsing.py new file mode 100644 index 0000000000000000000000000000000000000000..61dc78c93fb7fc69c6fedccd557c55d8e43bcead --- /dev/null +++ b/src/flow/tools/browsing.py @@ -0,0 +1,68 @@ +from typing import Annotated + +from loguru import logger +from smolagents.default_tools import VisitWebpageTool, WebSearchTool, WikipediaSearchTool + +from flow.tools.base import Tool, tool + + +def create_smol_web_search_tool(max_results: int = 10, engine: str = "duckduckgo") -> Tool: + """Create a web search tool that performs searches and returns formatted results. + + Args: + max_results: Maximum number of search results to return. Defaults to 10. + engine: The search engine to use. Defaults to "duckduckgo". + + Returns: + A callable async function that performs web searches and returns + results formatted as markdown with titles, links, and descriptions. + """ + + @tool + def smol_web_search(query: Annotated[str, "The search query to perform."]) -> str: + """Performs a web search for a query and returns a string of the top search results. + + Results are formatted as markdown with titles, links, and descriptions. + """ + logger.info("Performing web search for query: {}", query) + tool = WebSearchTool(max_results=max_results, engine=engine) + return tool.forward(query=query) + + return smol_web_search + + +@tool +def wikipedia_search( + query: Annotated[str, "The topic to search on Wikipedia."], + language: Annotated[str, "The language to perform the search on Wikipedia."] = "en", +) -> str: + """Searches Wikipedia and returns a summary or full text of the given topic, along with the page URL.""" + logger.info("Performing wikipedia search for query: {}", query) + tool = WikipediaSearchTool(language=language) + return tool.forward(query=query) + +def create_visit_webpage_tool(max_output_length: int = 40000) -> Tool: + """Create a tool for visiting webpages and reading their content as markdown. + + Args: + max_output_length: Maximum length of the output content. Defaults to 40000. + + Returns: + An async callable tool that visits a webpage at a given URL and returns + its content as a markdown string. + """ + + @tool + def visit_webpage( + url: Annotated[str, "The URL of the webpage to visit."], + ) -> str: + """Visits a webpage at the given url and reads its content as a markdown string. Use this to browse webpages.""" + logger.info("Visiting webpage at URL: {}", url) + tool = VisitWebpageTool(max_output_length=max_output_length) + return tool.forward(url=url) + + return visit_webpage + + +visit_webpage = create_visit_webpage_tool() +smol_web_search = create_smol_web_search_tool() diff --git a/src/flow/tools/coding.py b/src/flow/tools/coding.py index 37e346469bd844b5ec0fec580bac7c7c16235f02..a75d425d7a88890d36b95e7e8cce2e51ffcbd4b8 100644 --- a/src/flow/tools/coding.py +++ b/src/flow/tools/coding.py @@ -3,12 +3,26 @@ Read, write, edit files and search the filesystem. """ +import fnmatch import re from pathlib import Path from typing import Annotated -import fnmatch from .base import tool +from .workspace import get_workspace + + +def _resolve_path(path: str) -> Path: + """Resolve a path relative to the current workspace root. + + Absolute paths are returned as-is (after expanduser). + Relative paths are resolved against the workspace root, + not the process cwd — making this safe for concurrent async tasks. + """ + p = Path(path).expanduser() + if p.is_absolute(): + return p.resolve() + return (get_workspace().root / p).resolve() @tool @@ -22,7 +36,7 @@ def read_file( Returns the file content with line numbers for easy reference. """ try: - path_obj = Path(path).expanduser().resolve() + path_obj = _resolve_path(path) if not path_obj.exists(): return f"Error: File not found: {path}" @@ -30,7 +44,7 @@ def read_file( if not path_obj.is_file(): return f"Error: Not a file: {path}" - with open(path_obj, "r", encoding="utf-8", errors="replace") as f: + with open(path_obj, encoding="utf-8", errors="replace") as f: lines = f.readlines() total_lines = len(lines) @@ -55,7 +69,7 @@ def read_file( return result except Exception as e: - return f"Error reading file: {str(e)}" + return f"Error reading file: {e!s}" @tool @@ -70,7 +84,7 @@ def write_file( For partial edits, use edit_file instead. """ try: - path_obj = Path(path).expanduser().resolve() + path_obj = _resolve_path(path) if create_dirs: path_obj.parent.mkdir(parents=True, exist_ok=True) @@ -84,7 +98,7 @@ def write_file( return f"Successfully wrote {len(content)} characters ({line_count} lines) to {path}" except Exception as e: - return f"Error writing file: {str(e)}" + return f"Error writing file: {e!s}" @tool @@ -99,12 +113,12 @@ def edit_file( For multiple replacements, call this tool multiple times. """ try: - path_obj = Path(path).expanduser().resolve() + path_obj = _resolve_path(path) if not path_obj.exists(): return f"Error: File not found: {path}" - with open(path_obj, "r", encoding="utf-8") as f: + with open(path_obj, encoding="utf-8") as f: content = f.read() # Check for unique match @@ -125,7 +139,7 @@ def edit_file( return f"Successfully edited {path}" except Exception as e: - return f"Error editing file: {str(e)}" + return f"Error editing file: {e!s}" @tool @@ -139,7 +153,7 @@ def glob_files( Returns a list of matching file paths, sorted by modification time (newest first). """ try: - base_path = Path(path).expanduser().resolve() + base_path = _resolve_path(path) if not base_path.exists(): return f"Error: Directory not found: {path}" @@ -177,7 +191,7 @@ def glob_files( return result except Exception as e: - return f"Error searching files: {str(e)}" + return f"Error searching files: {e!s}" @tool @@ -193,7 +207,7 @@ def grep( Returns matching lines with file paths and line numbers. """ try: - base_path = Path(path).expanduser().resolve() + base_path = _resolve_path(path) regex = re.compile(pattern) matches: list[str] = [] @@ -209,7 +223,7 @@ def grep( for file_path in files: try: - with open(file_path, "r", encoding="utf-8", errors="replace") as f: + with open(file_path, encoding="utf-8", errors="replace") as f: lines = f.readlines() for i, line in enumerate(lines): @@ -250,9 +264,9 @@ def grep( return result except re.error as e: - return f"Error: Invalid regex pattern: {str(e)}" + return f"Error: Invalid regex pattern: {e!s}" except Exception as e: - return f"Error searching: {str(e)}" + return f"Error searching: {e!s}" @tool @@ -266,7 +280,7 @@ def ls( Returns a formatted listing of directory contents. """ try: - dir_path = Path(path).expanduser().resolve() + dir_path = _resolve_path(path) if not dir_path.exists(): return f"Error: Path not found: {path}" @@ -316,7 +330,7 @@ def ls( return "\n".join(output_lines) except Exception as e: - return f"Error listing directory: {str(e)}" + return f"Error listing directory: {e!s}" @tool @@ -333,12 +347,12 @@ def multi_edit( Edits are applied sequentially, so later edits see the result of earlier ones. """ try: - path_obj = Path(path).expanduser().resolve() + path_obj = _resolve_path(path) if not path_obj.exists(): return f"Error: File not found: {path}" - with open(path_obj, "r", encoding="utf-8") as f: + with open(path_obj, encoding="utf-8") as f: content = f.read() # Validate all edits first @@ -379,4 +393,4 @@ def multi_edit( return f"Successfully applied {len(edits)} edit(s) to {path}:\n" + "\n".join(applied) except Exception as e: - return f"Error editing file: {str(e)}" + return f"Error editing file: {e!s}" diff --git a/src/flow/tools/execution.py b/src/flow/tools/execution.py index 122c1f407962153d3fefad02b4334c3b3d3853c0..2be6724ddaa14ca76282ace91d0b81673ca0ee35 100644 --- a/src/flow/tools/execution.py +++ b/src/flow/tools/execution.py @@ -7,6 +7,7 @@ import subprocess from typing import Annotated from .base import tool +from .workspace import get_workspace @tool @@ -21,13 +22,15 @@ def bash( Be careful with destructive commands. """ try: + # Default to workspace root so concurrent tasks don't share process cwd + effective_cwd = cwd if cwd is not None else str(get_workspace().root) result = subprocess.run( command, shell=True, capture_output=True, text=True, timeout=timeout, - cwd=cwd, + cwd=effective_cwd, ) output = result.stdout @@ -44,7 +47,7 @@ def bash( except subprocess.TimeoutExpired: return f"Error: Command timed out after {timeout} seconds" except Exception as e: - return f"Error executing command: {str(e)}" + return f"Error executing command: {e!s}" @tool @@ -72,7 +75,7 @@ def check_processes( ) return result.stdout if result.stdout else "No processes found" except Exception as e: - return f"Error listing processes: {str(e)}" + return f"Error listing processes: {e!s}" elif action == "kill": if pid is None: @@ -85,46 +88,8 @@ def check_processes( except PermissionError: return f"Error: Permission denied to kill process {pid}" except Exception as e: - return f"Error killing process: {str(e)}" + return f"Error killing process: {e!s}" else: return f"Unknown action: {action}. Use 'list' or 'kill'." - -@tool -def python_repl( - code: Annotated[str, "Python code to execute"], -) -> str: - """Execute Python code in a REPL-like environment. - - Returns the output of the code execution. - """ - import io - from contextlib import redirect_stdout, redirect_stderr - - # Capture stdout and stderr - stdout_capture = io.StringIO() - stderr_capture = io.StringIO() - - # Create execution namespace - namespace: dict[str, object] = {} - - try: - with redirect_stdout(stdout_capture), redirect_stderr(stderr_capture): - exec(code, namespace) - - stdout_output = stdout_capture.getvalue() - stderr_output = stderr_capture.getvalue() - - result = "" - if stdout_output: - result += stdout_output - if stderr_output: - if result: - result += "\n--- STDERR ---\n" - result += stderr_output - - return result.strip() if result else "(No output)" - - except Exception as e: - return f"Error: {type(e).__name__}: {str(e)}" diff --git a/src/flow/tools/mdconvert.py b/src/flow/tools/mdconvert.py new file mode 100644 index 0000000000000000000000000000000000000000..74833fac9580ec3c3215161ec251f424af7f6420 --- /dev/null +++ b/src/flow/tools/mdconvert.py @@ -0,0 +1,696 @@ + +## Original source: https://github.com/aymeric-roucher/GAIA/blob/main/scripts/tools/mdconvert.py + +import copy +import html +import json +import mimetypes +import os +import re +import tempfile +import traceback +import xml.etree.ElementTree as ET +from urllib.parse import parse_qs, urlparse + +import mammoth +import markdownify +import pandas as pd +import pdfminer +import pdfminer.high_level +import pptx +import puremagic +import requests +from bs4 import BeautifulSoup +from loguru import logger +from youtube_transcript_api import YouTubeTranscriptApi + + +class DocumentConverterResult: + """The result of converting a document to text.""" + + def __init__(self, title: str | None = None, text_content: str = ""): + self.title = title + self.text_content = text_content + + +class DocumentConverter: + def convert(self, local_path, **kwargs) -> None | DocumentConverterResult: + raise NotImplementedError() + + +class PlainTextConverter(DocumentConverter): + """Anything with content type text/plain""" + + def convert(self, local_path, **kwargs) -> None | DocumentConverterResult: + extension = kwargs.get("file_extension", "") + if extension == "": + return None + + content_type, encoding = mimetypes.guess_type("__placeholder" + extension) + + # Only handle text/* content types, skip binary formats + if content_type is None or not content_type.startswith("text/"): + return None + + text_content = "" + with open(local_path) as fh: + text_content = fh.read() + + return DocumentConverterResult( + title=None, + text_content=text_content, + ) + + +class HtmlConverter(DocumentConverter): + """Anything with content type text/html""" + + def convert(self, local_path, **kwargs) -> None | DocumentConverterResult: + # Bail if not html + extension = kwargs.get("file_extension", "") + if extension.lower() not in [".html", ".htm"]: + return None + + result = None + with open(local_path) as fh: + result = self._convert(fh.read()) + + return result + + def _convert(self, html_content) -> None | DocumentConverterResult: + """Helper function that converts and HTML string.""" + # Parse the string + soup = BeautifulSoup(html_content, "html.parser") + + # Remove javascript and style blocks + for script in soup(["script", "style"]): + script.extract() + + # Print only the main content + body_elm = soup.find("body") + webpage_text = "" + if body_elm: + webpage_text = markdownify.MarkdownConverter().convert_soup(body_elm) + else: + webpage_text = markdownify.MarkdownConverter().convert_soup(soup) + + return DocumentConverterResult( + title=None if soup.title is None else soup.title.string, + text_content=webpage_text, + ) + + +class WikipediaConverter(DocumentConverter): + """Handle Wikipedia pages separately, focusing only on the main document content.""" + + def convert(self, local_path, **kwargs) -> None | DocumentConverterResult: + # Bail if not Wikipedia + extension = kwargs.get("file_extension", "") + if extension.lower() not in [".html", ".htm"]: + return None + url = kwargs.get("url", "") + if not re.search(r"^https?:\/\/[a-zA-Z]{2,3}\.wikipedia.org\/", url): + return None + + # Parse the file + soup = None + with open(local_path) as fh: + soup = BeautifulSoup(fh.read(), "html.parser") + + # Remove javascript and style blocks + for script in soup(["script", "style"]): + script.extract() + + # Print only the main content + body_elm = soup.find("div", {"id": "mw-content-text"}) + title_elm = soup.find("span", {"class": "mw-page-title-main"}) + + webpage_text = "" + if body_elm: + # What's the title + main_title = soup.title.string + if title_elm and len(title_elm) > 0: + main_title = title_elm.string + + # Convert the page + webpage_text = "# " + main_title + "\n\n" + markdownify.MarkdownConverter().convert_soup(body_elm) + else: + webpage_text = markdownify.MarkdownConverter().convert_soup(soup) + + return DocumentConverterResult( + title=soup.title.string, + text_content=webpage_text, + ) + + +class YouTubeConverter(DocumentConverter): + """Handle YouTube specially, focusing on the video title, description, and transcript.""" + + def convert(self, local_path, **kwargs) -> None | DocumentConverterResult: + # Bail if not YouTube + extension = kwargs.get("file_extension", "") + if extension.lower() not in [".html", ".htm"]: + return None + url = kwargs.get("url", "") + if not url.startswith("https://www.youtube.com/watch?"): + return None + + # Parse the file + soup = None + with open(local_path) as fh: + soup = BeautifulSoup(fh.read(), "html.parser") + + # Read the meta tags + metadata = {"title": soup.title.string} + for meta in soup(["meta"]): + for a in meta.attrs: + if a in ["itemprop", "property", "name"]: + metadata[meta[a]] = meta.get("content", "") + break + + # We can also try to read the full description. This is more prone to breaking, since it reaches into the page implementation + try: + for script in soup(["script"]): + content = script.text + if "ytInitialData" in content: + lines = re.split(r"\r?\n", content) + obj_start = lines[0].find("{") + obj_end = lines[0].rfind("}") + if obj_start >= 0 and obj_end >= 0: + data = json.loads(lines[0][obj_start : obj_end + 1]) + attrdesc = self._findKey(data, "attributedDescriptionBodyText") + if attrdesc: + metadata["description"] = attrdesc["content"] + break + except Exception as e: + logger.info(f"Following exception occurred in youtube converted: {e}") + + # Start preparing the page + webpage_text = "# YouTube\n" + + title = self._get(metadata, ["title", "og:title", "name"]) + if title: + webpage_text += f"\n## {title}\n" + + stats = "" + views = self._get(metadata, ["interactionCount"]) + if views: + stats += f"- **Views:** {views}\n" + + keywords = self._get(metadata, ["keywords"]) + if keywords: + stats += f"- **Keywords:** {keywords}\n" + + runtime = self._get(metadata, ["duration"]) + if runtime: + stats += f"- **Runtime:** {runtime}\n" + + if len(stats) > 0: + webpage_text += f"\n### Video Metadata\n{stats}\n" + + description = self._get(metadata, ["description", "og:description"]) + if description: + webpage_text += f"\n### Description\n{description}\n" + + transcript_text = "" + parsed_url = urlparse(url) + params = parse_qs(parsed_url.query) + + video_id = params["v"][0] + # Must be a single transcript. + transcript = YouTubeTranscriptApi.get_transcript(video_id) + transcript_text = " ".join([part["text"] for part in transcript]) + # Alternative formatting: + # formatter = TextFormatter() + # formatter.format_transcript(transcript) + if transcript_text: + webpage_text += f"\n### Transcript\n{transcript_text}\n" + + return DocumentConverterResult( + title=title if title else soup.title.string, + text_content=webpage_text, + ) + + def _get(self, json, keys, default=None): + for k in keys: + if k in json: + return json[k] + return default + + def _findKey(self, json, key): + if isinstance(json, list): + for elm in json: + ret = self._findKey(elm, key) + if ret is not None: + return ret + elif isinstance(json, dict): + for k in json: + if k == key: + return json[k] + else: + ret = self._findKey(json[k], key) + if ret is not None: + return ret + return None + + +class PdfConverter(DocumentConverter): + def convert(self, local_path, **kwargs) -> None | DocumentConverterResult: + # Bail if not a PDF + extension = kwargs.get("file_extension", "") + if extension.lower() != ".pdf": + return None + + return DocumentConverterResult( + title=None, + text_content=pdfminer.high_level.extract_text(local_path), + ) + + +class AudioConverter(DocumentConverter): + def __init__(self): + super().__init__() + # Initialize Azure OpenAI client for audio transcription + from openai import AzureOpenAI + + azure_endpoint = os.environ.get("AUDIO_CONVERTER_ENDPOINT") + api_key = os.environ.get("AUDIO_CONVERTER_API_KEY") + api_version = os.environ.get("AUDIO_CONVERTER_API_VERSION", "2025-03-01-preview") + + if not azure_endpoint: + logger.error("Environment variable AUDIO_CONVERTER_ENDPOINT is not set.") + raise RuntimeError( + "Missing required environment variable AUDIO_CONVERTER_ENDPOINT for AudioConverter." + ) + + if not api_key: + logger.error("Environment variable AUDIO_CONVERTER_API_KEY is not set.") + raise RuntimeError( + "Missing required environment variable AUDIO_CONVERTER_API_KEY for AudioConverter." + ) + + self.client = AzureOpenAI( + azure_endpoint=azure_endpoint, + api_key=api_key, + api_version=api_version, + ) + + model_name = os.environ.get("AUDIO_CONVERTER_MODEL_NAME") + if not model_name: + logger.warning( + "Environment variable AUDIO_CONVERTER_MODEL_NAME is not set; " + "defaulting to 'gpt-4o-mini-transcribe'." + ) + model_name = "gpt-4o-mini-transcribe" + self.model = model_name + def convert(self, local_path, **kwargs) -> None | DocumentConverterResult: + # Bail if not an audio file + extension = kwargs.get("file_extension", "") + if extension.lower() not in [".wav", ".mp3", ".flac", ".m4a"]: + return None + + try: + with open(local_path, "rb") as audio_file: + transcription = self.client.audio.transcriptions.create( + model=self.model, + file=audio_file, + ) + result = transcription.text + except Exception as e: + logger.error(f"Error transcribing audio: {e}") + raise + + return DocumentConverterResult( + title=None, + text_content=result, + ) + + +class DocxConverter(HtmlConverter): + def convert(self, local_path, **kwargs) -> None | DocumentConverterResult: + # Bail if not a DOCX + extension = kwargs.get("file_extension", "") + if extension.lower() != ".docx": + return None + + result = None + with open(local_path, "rb") as docx_file: + result = mammoth.convert_to_html(docx_file) + html_content = result.value + result = self._convert(html_content) + + return result + + +class XlsxConverter(HtmlConverter): + def convert(self, local_path, **kwargs) -> None | DocumentConverterResult: + # Bail if not a XLSX + extension = kwargs.get("file_extension", "") + + if extension.lower() not in [".xlsx", ".xls"]: + return None + + sheets = pd.read_excel(local_path, sheet_name=None) + md_content = "" + for s in sheets: + md_content += f"## {s}\n" + html_content = sheets[s].to_html(index=False) + md_content += self._convert(html_content).text_content.strip() + "\n\n" + + return DocumentConverterResult( + title=None, + text_content=md_content.strip(), + ) + + +class XmlConverter(DocumentConverter): + def convert(self, local_path, **kwargs) -> None | DocumentConverterResult: + # Parse the XML string + extension = kwargs.get("file_extension", "") + + if extension.lower() not in [".xml"]: + return None + + xml_string = "" + with open(local_path) as fh: + xml_string = fh.read() + + def extract_table_from_html_like(xml_root): + table = xml_root.find(".//table") + if table is None: + raise ValueError("No table found in the XML") + + headers = [th.text for th in table.find("thead").findall("th")] + rows = [[td.text for td in tr.findall("td")] for tr in table.find("tbody").findall("tr")] + + # Create markdown table + markdown = "| " + " | ".join(headers) + " |\n" + markdown += "| " + " | ".join(["---"] * len(headers)) + " |\n" + for row in rows: + markdown += "| " + " | ".join(row) + " |\n" + + def extract_table_from_wordml(xml_root, namespaces): + # Parse the XML content + root = xml_root + namespace = {"w": "http://schemas.microsoft.com/office/word/2003/wordml"} + + # Extract text content + body = root.find("w:body", namespace) + paragraphs = body.findall(".//w:p", namespace) + text_content = [] + for para in paragraphs: + texts = para.findall(".//w:t", namespace) + for text in texts: + text_content.append(text.text) + + return "\n".join(text_content) + + # Parse the XML string + root = ET.fromstring(xml_string) + namespaces = {"w": "http://schemas.microsoft.com/office/word/2003/wordml"} + + if root.tag.endswith("wordDocument"): + markdown = extract_table_from_wordml(root, namespaces) + else: + markdown = extract_table_from_html_like(root) + + return DocumentConverterResult( + title=None, + text_content=markdown.strip(), + ) + + +class PptxConverter(HtmlConverter): + def convert(self, local_path, **kwargs) -> None | DocumentConverterResult: + # Bail if not a PPTX + extension = kwargs.get("file_extension", "") + if extension.lower() != ".pptx": + return None + + md_content = "" + + presentation = pptx.Presentation(local_path) + slide_num = 0 + for slide in presentation.slides: + slide_num += 1 + + md_content += f"\n\n\n" + + title = slide.shapes.title + for shape in slide.shapes: + # Pictures + if self._is_picture(shape): + # https://github.com/scanny/python-pptx/pull/512#issuecomment-1713100069 + alt_text = "" + try: + alt_text = shape._element._nvXxPr.cNvPr.attrib.get("descr", "") + except Exception as e: + logger.debug(f"Could not extract alt text from shape: {e}") + + # A placeholder name + filename = re.sub(r"\W", "", shape.name) + ".jpg" + # try: + # filename = shape.image.filename + # except: + # pass + + md_content += "\n![" + (alt_text if alt_text else shape.name) + "](" + filename + ")\n" + + # Tables + if self._is_table(shape): + html_table = "" + first_row = True + for row in shape.table.rows: + html_table += "" + for cell in row.cells: + if first_row: + html_table += "" + else: + html_table += "" + html_table += "" + first_row = False + html_table += "
" + html.escape(cell.text) + "" + html.escape(cell.text) + "
" + md_content += "\n" + self._convert(html_table).text_content.strip() + "\n" + + # Text areas + elif shape.has_text_frame: + if shape == title: + md_content += "# " + shape.text.lstrip() + " " + else: + md_content += shape.text + " " + + md_content = md_content.strip() + + if slide.has_notes_slide: + md_content += "\n\n### Notes:\n" + notes_frame = slide.notes_slide.notes_text_frame + if notes_frame is not None: + md_content += notes_frame.text + md_content = md_content.strip() + + return DocumentConverterResult( + title=None, + text_content=md_content.strip(), + ) + + def _is_picture(self, shape): + if shape.shape_type == pptx.enum.shapes.MSO_SHAPE_TYPE.PICTURE: + return True + if shape.shape_type == pptx.enum.shapes.MSO_SHAPE_TYPE.PLACEHOLDER: + if hasattr(shape, "image"): + return True + return False + + def _is_table(self, shape): + if shape.shape_type == pptx.enum.shapes.MSO_SHAPE_TYPE.TABLE: + return True + return False + + +class FileConversionException(Exception): + pass + + +class UnsupportedFormatException(Exception): + pass + + +class MarkdownConverter: + """(In preview) An extremely simple text-based document reader, suitable for LLM use. + This reader will convert common file-types or webpages to Markdown. + """ + + def __init__( + self, + requests_session: requests.Session | None = None, + ): + if requests_session is None: + self._requests_session = requests.Session() + else: + self._requests_session = requests_session + + self._page_converters: list[DocumentConverter] = [] + + # Register converters for successful browsing operations + # Later registrations are tried first / take higher priority than earlier registrations + # To this end, the most specific converters should appear below the most generic converters + self.register_page_converter(WikipediaConverter()) + self.register_page_converter(XmlConverter()) + self.register_page_converter(YouTubeConverter()) + self.register_page_converter(DocxConverter()) + self.register_page_converter(XlsxConverter()) + self.register_page_converter(PptxConverter()) + # self.register_page_converter(ImageConverter()) + self.register_page_converter(PdfConverter()) + # Only register AudioConverter if required env vars are set (it's optional) + if os.environ.get("AUDIO_CONVERTER_ENDPOINT") and os.environ.get("AUDIO_CONVERTER_API_KEY"): + self.register_page_converter(AudioConverter()) + self.register_page_converter(HtmlConverter()) + self.register_page_converter(PlainTextConverter()) + + def convert(self, source, **kwargs): + """Args: + - source: can be a string representing a path or url, or a requests.response object + - extension: specifies the file extension to use when interpreting the file. If None, infer from source (path, uri, content-type, etc.) + """ + # Local path or url + if isinstance(source, str): + if source.startswith("http://") or source.startswith("https://") or source.startswith("file://"): + return self.convert_url(source, **kwargs) + else: + return self.convert_local(source, **kwargs) + # Request response + elif isinstance(source, requests.Response): + return self.convert_response(source, **kwargs) + + def convert_local(self, path, **kwargs): + # Prepare a list of extensions to try (in order of priority) + ext = kwargs.get("file_extension") + extensions = [ext] if ext is not None else [] + + # Get extension alternatives from the path and puremagic + base, ext = os.path.splitext(path) + self._append_ext(extensions, ext) + self._append_ext(extensions, self._guess_ext_magic(path)) + + # Convert + return self._convert(path, extensions, **kwargs) + + def convert_url(self, url, **kwargs): + # Send a HTTP request to the URL + user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0" + response = self._requests_session.get(url, stream=True, headers={"User-Agent": user_agent}) + response.raise_for_status() + return self.convert_response(response, **kwargs) + + def convert_response(self, response, **kwargs): + # Prepare a list of extensions to try (in order of priority) + ext = kwargs.get("file_extension") + extensions = [ext] if ext is not None else [] + + # Guess from the mimetype + content_type = response.headers.get("content-type", "").split(";")[0] + self._append_ext(extensions, mimetypes.guess_extension(content_type)) + + # Read the content disposition if there is one + content_disposition = response.headers.get("content-disposition", "") + m = re.search(r"filename=([^;]+)", content_disposition) + if m: + base, ext = os.path.splitext(m.group(1).strip("\"'")) + self._append_ext(extensions, ext) + + # Read from the extension from the path + base, ext = os.path.splitext(urlparse(response.url).path) + self._append_ext(extensions, ext) + + # Save the file locally to a temporary file. It will be deleted before this method exits + handle, temp_path = tempfile.mkstemp() + fh = os.fdopen(handle, "wb") + result = None + try: + # Download the file + for chunk in response.iter_content(chunk_size=512): + fh.write(chunk) + fh.close() + + # Use puremagic to check for more extension options + self._append_ext(extensions, self._guess_ext_magic(temp_path)) + + # Convert + result = self._convert(temp_path, extensions, url=response.url) + except Exception as e: + print(f"Error in converting: {e}") + + # Clean up + finally: + try: + fh.close() + except Exception as e: + logger.warning(f"Failed to close temporary file handle: {e}") + os.unlink(temp_path) + + return result + + def _convert(self, local_path, extensions, **kwargs): + error_trace = "" + for ext in extensions: + for converter in self._page_converters: + _kwargs = copy.deepcopy(kwargs) + _kwargs.update({"file_extension": ext}) + # If we hit an error log it and keep trying + try: + res = converter.convert(local_path, **_kwargs) + if res is not None: + # Normalize the content + res.text_content = "\n".join([line.rstrip() for line in re.split(r"\r?\n", res.text_content)]) + res.text_content = re.sub(r"\n{3,}", "\n\n", res.text_content) + + # Todo + return res + except Exception: + error_trace = ("\n\n" + traceback.format_exc()).strip() + + # If we got this far without success, report any exceptions + if len(error_trace) > 0: + raise FileConversionException( + f"Could not convert '{local_path}' to Markdown. File type was recognized as {extensions}. While converting the file, the following error was encountered:\n\n{error_trace}" + ) + + # Nothing can handle it! + # raise UnsupportedFormatException( + # f"Could not convert '{local_path}' to Markdown. The formats {extensions} are not supported." + # ) + res = PlainTextConverter().convert(local_path, **kwargs) + return res + + def _append_ext(self, extensions, ext): + """Append a unique non-None, non-empty extension to a list of extensions.""" + if ext is None: + return + ext = ext.strip() + if ext == "": + return + # if ext not in extensions: + if True: + extensions.append(ext) + + def _guess_ext_magic(self, path): + """Use puremagic (a Python implementation of libmagic) to guess a file's extension based on the first few bytes.""" + # Use puremagic to guess + try: + guesses = puremagic.magic_file(path) + if len(guesses) > 0: + ext = guesses[0].extension.strip() + if len(ext) > 0: + return ext + except FileNotFoundError: + logger.debug(f"puremagic.magic_file could not open '{path}': file not found; treating extension as unknown.") + except IsADirectoryError: + logger.debug(f"puremagic.magic_file was given a directory '{path}'; treating extension as unknown.") + except PermissionError: + logger.debug(f"puremagic.magic_file could not open '{path}': permission denied; treating extension as unknown.") + return None + + def register_page_converter(self, converter: DocumentConverter) -> None: + """Register a page text converter.""" + self._page_converters.append(converter) diff --git a/src/flow/tools/memory.py b/src/flow/tools/memory.py index f6c0abc8d3855b8e076b257526049e7ffc5cea0d..37a05c4cb0c24bd4a4925395bd7ee6fcc4acf84d 100644 --- a/src/flow/tools/memory.py +++ b/src/flow/tools/memory.py @@ -24,9 +24,8 @@ import uuid from datetime import datetime from typing import Annotated, Any, Literal -from .base import tool, Tool -from .workspace import get_workspace, Workspace - +from .base import Tool, tool +from .workspace import Workspace, get_workspace # Optional workspace override (for testing or custom setups) _workspace_override: Workspace | None = None diff --git a/src/flow/tools/notebook.py b/src/flow/tools/notebook.py index a3c2a60e49a96800d3be7417409a2a31e3cdc327..29e081aa282be174a1a8fe67c88ba4323c59b3ac 100644 --- a/src/flow/tools/notebook.py +++ b/src/flow/tools/notebook.py @@ -37,7 +37,7 @@ def notebook_edit( return f"Error: Not a Jupyter notebook (must be .ipynb): {path}" # Read notebook - with open(path_obj, "r", encoding="utf-8") as f: + with open(path_obj, encoding="utf-8") as f: notebook = json.load(f) cells = notebook.get("cells", []) @@ -110,9 +110,9 @@ def notebook_edit( return f"Successfully replaced cell at index {cell_index}" except json.JSONDecodeError as e: - return f"Error: Invalid notebook JSON: {str(e)}" + return f"Error: Invalid notebook JSON: {e!s}" except Exception as e: - return f"Error editing notebook: {str(e)}" + return f"Error editing notebook: {e!s}" @tool @@ -134,7 +134,7 @@ def notebook_read( if not path_obj.suffix == ".ipynb": return f"Error: Not a Jupyter notebook (must be .ipynb): {path}" - with open(path_obj, "r", encoding="utf-8") as f: + with open(path_obj, encoding="utf-8") as f: notebook = json.load(f) cells = notebook.get("cells", []) @@ -198,6 +198,6 @@ def notebook_read( return result except json.JSONDecodeError as e: - return f"Error: Invalid notebook JSON: {str(e)}" + return f"Error: Invalid notebook JSON: {e!s}" except Exception as e: - return f"Error reading notebook: {str(e)}" + return f"Error reading notebook: {e!s}" diff --git a/src/flow/tools/planning.py b/src/flow/tools/planning.py index fce24c917f0f6c70bcc11bbb51c650701b3c4f18..f4a0b4dce9cade9d0bc0083d15dcae8f69130a61 100644 --- a/src/flow/tools/planning.py +++ b/src/flow/tools/planning.py @@ -7,8 +7,7 @@ Todos are persisted to the workspace's .flow/todos.json file. from typing import Annotated, Any from .base import tool -from .workspace import get_workspace, Workspace - +from .workspace import Workspace, get_workspace # Optional workspace override (for testing or custom setups) _workspace_override: Workspace | None = None diff --git a/src/flow/tools/skills.py b/src/flow/tools/skills.py index 8bec26d32f3fbf5891791f09ca241c860d3f7f02..f37b6b480ab66e8ba82501cfc50dfe65eee94fed 100644 --- a/src/flow/tools/skills.py +++ b/src/flow/tools/skills.py @@ -28,7 +28,7 @@ import re from pathlib import Path from typing import Annotated, Literal -from .base import tool, Tool +from .base import Tool, tool def _parse_frontmatter(content: str) -> dict[str, str]: diff --git a/src/flow/tools/subagent.py b/src/flow/tools/subagent.py index 4755548ff213767a18d52e499eb821bc829de817..77e0def0d6210e5d1d5e603a97b873d6cc693936 100644 --- a/src/flow/tools/subagent.py +++ b/src/flow/tools/subagent.py @@ -14,10 +14,9 @@ Based on Claude Code's Task tool architecture. from __future__ import annotations -from pathlib import Path -from typing import Annotated, Literal, TYPE_CHECKING +from typing import TYPE_CHECKING, Annotated, Literal -from .base import tool, Tool +from .base import Tool, tool if TYPE_CHECKING: pass # For future type imports @@ -162,10 +161,13 @@ def create_task_tool( else: # Specific tool set - import from shared tools from . import ( - read_file, glob_files, grep, ls, + glob_files, + grep, + ls, + read_file, ) from .planning import think - from .web import web_search, web_fetch + from .web import web_fetch, web_search tool_map = { "read_file": read_file, @@ -223,7 +225,7 @@ def create_task_tool( return result + usage_info except Exception as e: - return f"Sub-agent failed: {str(e)}" + return f"Sub-agent failed: {e!s}" return task diff --git a/src/flow/tools/text_inspector_qa.py b/src/flow/tools/text_inspector_qa.py new file mode 100644 index 0000000000000000000000000000000000000000..c03e2e49d6bad717dfa6715b81e996018544875a --- /dev/null +++ b/src/flow/tools/text_inspector_qa.py @@ -0,0 +1,194 @@ +# Original source: https://github.com/aymeric-roucher/GAIA/blob/main/gaia_multiagent.py#L98C1-L176C46 + + +import os +from pathlib import Path +from typing import Annotated + +from loguru import logger +from openai import AzureOpenAI +from smolagents import MessageRole +from smolagents.tools import Tool + +from flow.tools.base import tool +from flow.tools.mdconvert import MarkdownConverter + + +def _convert_messages_for_openai(messages: list[dict]) -> list[dict]: + """Convert smolagents-style messages to OpenAI format. + + Handles MessageRole enums and merges consecutive messages with same role. + """ + result = [] + for msg in messages: + role = msg["role"] + # Convert MessageRole enum to string + if isinstance(role, MessageRole): + if role == MessageRole.TOOL_RESPONSE: + role_str = "user" + else: + role_str = role.value + else: + role_str = str(role) + + content = msg["content"] + + # Merge with previous message if same role + if result and result[-1]["role"] == role_str: + result[-1]["content"] += "\n\n" + content + else: + result.append({"role": role_str, "content": content}) + + return result + + +class OpenAIEngine: + def __init__(self): + required_env_vars = [ + "TEXT_INSPECTOR_QA_MODEL_NAME", + "TEXT_INSPECTOR_QA_API_VERSION", + "TEXT_INSPECTOR_QA_ENDPOINT", + "TEXT_INSPECTOR_QA_API_KEY", + ] + missing = [name for name in required_env_vars if not os.environ.get(name)] + if missing: + logger.error( + "Missing required environment variables for OpenAIEngine: {}", + ", ".join(missing), + ) + raise RuntimeError(f"Missing required environment variables for OpenAIEngine: {', '.join(missing)}") + + self.model_name = os.environ["TEXT_INSPECTOR_QA_MODEL_NAME"] + self.client = AzureOpenAI( + api_version=os.environ["TEXT_INSPECTOR_QA_API_VERSION"], + azure_endpoint=os.environ["TEXT_INSPECTOR_QA_ENDPOINT"], + api_key=os.environ["TEXT_INSPECTOR_QA_API_KEY"], + ) + + def __call__(self, messages, stop_sequences=[], grammar=None) -> str: + messages = _convert_messages_for_openai(messages) + + response = self.client.chat.completions.create( + model=self.model_name, messages=messages, stop=stop_sequences, temperature=0.5, response_format=grammar + ) + return str(response.choices[0].message.content) + + +class TextInspectorTool(Tool): + name = "inspect_file_as_text" + description = """ +You cannot load files yourself: instead call this tool to read a file as markdown text and ask questions about it. +This tool handles the following file extensions: [".html", ".htm", ".xlsx", ".pptx", ".wav", ".mp3", ".flac", ".pdf", +".docx"], and all other types of text files. IT DOES NOT HANDLE IMAGES.""" + + inputs = { # noqa: RUF012 + "question": { + "description": ( + "[Optional]: Your question, as a natural language sentence. Provide as much context as possible. " + "Do not pass this parameter if you just want to directly return the content of the file." + ), + "type": "string", + "nullable": True, + }, + "file_path": { + "description": ( + "The path to the file you want to read as text. Must be a '.something' file, like '.pdf'. " + "If it is an image, use the visualizer tool instead! " + "DO NOT USE THIS TOOL FOR A WEBPAGE: use the search tool instead!" + ), + "type": "string", + }, + } + output_type = "string" + md_converter = MarkdownConverter() + + def __init__(self, text_limit: int = 70000): + self.text_limit = text_limit + self.llm_engine = OpenAIEngine() + + def forward_initial_exam_mode(self, file_path: str, question: str | None = None) -> str: + result = self.md_converter.convert(file_path) + + if Path(file_path).suffix in [".png", ".jpg", ".jpeg"]: + raise Exception("Cannot use inspect_file_as_text tool with images: use visualizer instead!") + + if ".zip" in file_path: + return result.text_content + + if not question: + return result.text_content + + messages = [ + { + "role": MessageRole.SYSTEM, + "content": "Here is a file:\n### " + + str(result.title) + + "\n\n" + + result.text_content[: self.text_limit], + }, + { + "role": MessageRole.USER, + "content": question, + }, + ] + return self.llm_engine(messages) + + def forward(self, file_path: str, question: str | None = None) -> str: + result = self.md_converter.convert(file_path) + + if Path(file_path).suffix in [".png", ".jpg", ".jpeg"]: + raise Exception("Cannot use inspect_file_as_text tool with images: use visualizer instead!") + + if ".zip" in file_path: + return result.text_content + + if not question: + return result.text_content + + messages = [ + { + "role": MessageRole.SYSTEM, + "content": "You will have to write a short caption for this file, then answer this question: " + + question, + }, + { + "role": MessageRole.USER, + "content": "Here is the complete file:\n### " + + str(result.title) + + "\n\n" + + result.text_content[: self.text_limit], + }, + { + "role": MessageRole.USER, + "content": "Now answer the question below. Use these three headings: '1. Short answer', " + "'2. Extremely detailed answer', '3. Additional Context on the document and question asked'." + + question, + }, + ] + return self.llm_engine(messages) + + +@tool +def text_inspector( + file_path: Annotated[ + str, + "The path to the file you want to read as text. Must be a '.something' file, like '.pdf'. " + "If it is an image, use the visualizer tool instead! " + "DO NOT USE THIS TOOL FOR A WEBPAGE: use the search tool instead!", + ], + question: Annotated[ + str | None, + "[Optional]: Your question, as a natural language sentence. Provide as much " + "context as possible. Do not pass this parameter if you just want to directly " + "return the content of the file.", + ] = None, +) -> str: + """You cannot load files yourself: instead call this tool to read a file as markdown text and ask questions. + + This tool handles the following file extensions: + [".html", ".htm", ".xlsx", ".pptx", ".wav", ".mp3", ".flac", ".pdf", ".docx"], + and all other types of text files. IT DOES NOT HANDLE IMAGES. + """ + logger.info("Inspecting file at path: {}", file_path) + ti_tool = TextInspectorTool() + return ti_tool.forward(file_path=file_path, question=question) diff --git a/src/flow/tools/visual_inspector_qa.py b/src/flow/tools/visual_inspector_qa.py new file mode 100644 index 0000000000000000000000000000000000000000..82d0759433677b533c1dcae604b4f62f72edbb08 --- /dev/null +++ b/src/flow/tools/visual_inspector_qa.py @@ -0,0 +1,154 @@ +# Original source: https://github.com/aymeric-roucher/GAIA/blob/main/scripts/tools/visual_qa.py#L140 + +import base64 +import mimetypes +import os +import uuid +from typing import Annotated + +import requests +from loguru import logger +from openai import AzureOpenAI +from smolagents.tools import Tool + +from flow.tools.base import tool + + +# Function to encode the image +def encode_image(image_path: str): + if image_path.startswith("http"): + user_agent = ( + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 " + "(KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0" + ) + request_kwargs = { + "headers": {"User-Agent": user_agent}, + "stream": True, + } + + # Send a HTTP request to the URL + response = requests.get(image_path, **request_kwargs) + response.raise_for_status() + content_type = response.headers.get("content-type", "") + + extension = mimetypes.guess_extension(content_type) + if extension is None: + extension = ".download" + + fname = str(uuid.uuid4()) + extension + os.makedirs("downloads", exist_ok=True) # Ensure downloads directory exists + download_path = os.path.abspath(os.path.join("downloads", fname)) + + with open(download_path, "wb") as fh: + for chunk in response.iter_content(chunk_size=512): + fh.write(chunk) + + image_path = download_path + + with open(image_path, "rb") as image_file: + return base64.b64encode(image_file.read()).decode("utf-8") + + +class VisualInspectorTool(Tool): + name = "visualizer" + description = "A tool that can answer questions about attached images." + inputs = { # noqa: RUF012 + "question": {"description": "the question to answer", "type": "string", "nullable": True}, + "image_path": { + "description": "The path to the image on which to answer the question. This should be a local path " + "to downloaded image.", + "type": "string", + }, + } + output_type = "string" + + def __init__(self): + self.model_name = os.environ.get("VISUAL_INSPECTOR_QA_MODEL_NAME") + api_version = os.environ.get("VISUAL_INSPECTOR_QA_API_VERSION") + azure_endpoint = os.environ.get("VISUAL_INSPECTOR_QA_ENDPOINT") + api_key = os.environ.get("VISUAL_INSPECTOR_QA_API_KEY") + + missing_vars = [ + name + for name, value in [ + ("VISUAL_INSPECTOR_QA_MODEL_NAME", self.model_name), + ("VISUAL_INSPECTOR_QA_API_VERSION", api_version), + ("VISUAL_INSPECTOR_QA_ENDPOINT", azure_endpoint), + ("VISUAL_INSPECTOR_QA_API_KEY", api_key), + ] + if not value + ] + if missing_vars: + raise RuntimeError( + "Missing required environment variable(s) for VisualInspectorTool: " + ", ".join(missing_vars) + ) + + self.client = AzureOpenAI( + api_version=api_version, + azure_endpoint=azure_endpoint, + api_key=api_key, + ) + + def forward(self, image_path: str, question: str | None = None) -> str: + add_note = False + if not question: + add_note = True + question = "Please write a detailed caption for this image." + if not isinstance(image_path, str): + raise Exception("You should provide only one string as argument to this tool!") + + base64_image = encode_image(image_path) + + # Determine image mime type from path + mime_type = "image/jpeg" + if image_path.lower().endswith(".png"): + mime_type = "image/png" + elif image_path.lower().endswith(".gif"): + mime_type = "image/gif" + elif image_path.lower().endswith(".webp"): + mime_type = "image/webp" + + response = self.client.chat.completions.create( + model=self.model_name, + messages=[ + { + "role": "user", + "content": [ + {"type": "text", "text": question}, + {"type": "image_url", "image_url": {"url": f"data:{mime_type};base64,{base64_image}"}}, + ], + } + ], + max_tokens=500, + ) + + try: + output = response.choices[0].message.content + except Exception as err: + logger.exception("Unexpected response format from Azure OpenAI: {response}", response=response) + raise Exception(f"Response format unexpected: {response}") from err + + if add_note: + output = f"You did not provide a particular question, so here is a detailed caption for the image: {output}" + + return output + + +@tool +def visual_inspector( + image_path: Annotated[ + str, + "The path to the image on which to answer the question. This should be a local path or a URL to download " + "the image from.", + ], + question: Annotated[ + str | None, "The question to answer about the image. If not provided, a detailed caption will be generated." + ] = None, +) -> str: + """Inspects an image at the given path and answers questions about it. + + If no question is provided, a detailed caption will be generated. + """ + logger.info("Inspecting image at path: {}", image_path) + tool = VisualInspectorTool() + return tool.forward(image_path=image_path, question=question) diff --git a/src/flow/tools/web.py b/src/flow/tools/web.py index f15cae9b027c408af89996fa863917828a88a1f8..902c4f4f538660614e9e85c4bb76a93c0919572a 100644 --- a/src/flow/tools/web.py +++ b/src/flow/tools/web.py @@ -63,7 +63,7 @@ def web_search( return "\n\n".join(results) except Exception as e: - return f"Error performing search: {str(e)}" + return f"Error performing search: {e!s}" @tool @@ -109,8 +109,8 @@ def web_fetch( else: # Try to extract text/markdown try: - from bs4 import BeautifulSoup # type: ignore[import-untyped] import html2text # type: ignore[import-untyped] + from bs4 import BeautifulSoup # type: ignore[import-untyped] soup = BeautifulSoup(html, "html.parser") @@ -142,4 +142,4 @@ def web_fetch( return content except Exception as e: - return f"Error fetching URL: {str(e)}" + return f"Error fetching URL: {e!s}" diff --git a/src/flow/tools/workspace.py b/src/flow/tools/workspace.py index fa6d537e64f007d135253dad5812b054b4443456..c88f3b21a10c4ae5eb2097ebe415eb90b6fd955f 100644 --- a/src/flow/tools/workspace.py +++ b/src/flow/tools/workspace.py @@ -31,6 +31,7 @@ Usage: ws.memory_dir # /path/to/project/.flow/memory """ +import contextvars import json from pathlib import Path from typing import Any @@ -97,7 +98,7 @@ class Workspace: try: with open(self.todos_file) as f: return json.load(f) # type: ignore[no-any-return] - except (json.JSONDecodeError, IOError): + except (OSError, json.JSONDecodeError): return [] def save_todos(self, todos: list[dict[str, Any]]) -> None: @@ -118,7 +119,7 @@ class Workspace: try: with open(filepath) as f: memories.append(json.load(f)) - except (json.JSONDecodeError, IOError): + except (OSError, json.JSONDecodeError): continue return memories @@ -130,7 +131,7 @@ class Workspace: try: with open(filepath) as f: return json.load(f) # type: ignore[no-any-return] - except (json.JSONDecodeError, IOError): + except (OSError, json.JSONDecodeError): return None def save_memory(self, memory_id: str, data: dict[str, Any]) -> None: @@ -157,7 +158,7 @@ class Workspace: try: with open(self.config_file) as f: return json.load(f) - except (json.JSONDecodeError, IOError): + except (OSError, json.JSONDecodeError): return {} def save_config(self, config: dict[str, Any]) -> None: @@ -170,29 +171,39 @@ class Workspace: return f"Workspace({self._root})" -# Default workspace (current directory) -_default_workspace: Workspace | None = None +# Per-task workspace via contextvars (safe for concurrent async tasks). +# Each asyncio Task gets its own workspace without interfering with others. +_workspace_var: contextvars.ContextVar[Workspace | None] = contextvars.ContextVar( + "flow_workspace", default=None +) def get_workspace() -> Workspace: - """Get the default workspace (creates if needed).""" - global _default_workspace - if _default_workspace is None: - _default_workspace = Workspace() - return _default_workspace + """Get the current workspace. + + Returns the workspace set for the current async task (via contextvars), + or creates one from the current working directory as fallback. + """ + ws = _workspace_var.get() + if ws is None: + ws = Workspace() + _workspace_var.set(ws) + return ws def set_workspace(workspace: Workspace | str | Path) -> Workspace: - """Set the default workspace.""" - global _default_workspace + """Set the workspace for the current async task. + + Uses contextvars so concurrent tasks each have their own workspace. + """ if isinstance(workspace, Workspace): - _default_workspace = workspace - else: - _default_workspace = Workspace(workspace) - return _default_workspace + _workspace_var.set(workspace) + return workspace + ws = Workspace(workspace) + _workspace_var.set(ws) + return ws def reset_workspace() -> None: - """Reset default workspace (for testing).""" - global _default_workspace - _default_workspace = None + """Reset workspace for the current context (for testing).""" + _workspace_var.set(None) diff --git a/src/flow/ui/api/__init__.py b/src/flow/ui/api/__init__.py index 16bb55c0510bf1d40be97520ac9c95d0c2019d39..fc2665a3121468f958846bf147a54fc6de51e7e8 100644 --- a/src/flow/ui/api/__init__.py +++ b/src/flow/ui/api/__init__.py @@ -2,19 +2,25 @@ """API routes package.""" from .configs import router as configs_router -from .tasks import router as tasks_router +from .evaluate import router as evaluate_router +from .experiment import router as experiment_router from .jobs import router as jobs_router +from .llm_configs import router as llm_configs_router from .runs import router as runs_router +from .schema import router as schema_router +from .tasks import router as tasks_router from .tests import router as tests_router -from .llm_configs import router as llm_configs_router from .tools import router as tools_router __all__ = [ "configs_router", - "tasks_router", + "evaluate_router", + "experiment_router", "jobs_router", + "llm_configs_router", "runs_router", + "schema_router", + "tasks_router", "tests_router", - "llm_configs_router", "tools_router", ] diff --git a/src/flow/ui/api/configs.py b/src/flow/ui/api/configs.py index 496cafcc73345129d24d4b59731a019ff7a5c4a3..ec17cf50ecb2b638adb624b6e17a3324006263f0 100644 --- a/src/flow/ui/api/configs.py +++ b/src/flow/ui/api/configs.py @@ -5,12 +5,9 @@ from typing import Annotated from uuid import UUID from fastapi import APIRouter, Depends, HTTPException -from pydantic import BaseModel from sqlalchemy.ext.asyncio import AsyncSession from sqlmodel import desc, or_, select -from flow.experiments.models import Agent, CompactionConfig, GridSearchStrategy - from ..auth import TokenData, get_current_user, get_effective_user_id, should_filter_by_user from ..database import get_session from ..models.config import AgentConfig @@ -19,31 +16,6 @@ from ..schemas import AgentCreate, AgentResponse, AgentUpdate router = APIRouter(prefix="/configs", tags=["configs"]) -class CandidateRequest(BaseModel): - """Request schema for generating candidate agents.""" - - base_name: str = "experiment" - - # Which dimensions to vary - vary_compaction: bool = False - vary_tools: bool = False - vary_compaction_head: bool = False - vary_compaction_tail: bool = False - - # Values for tool variations (preset names) - tool_presets: list[str] = ["standard", "minimal", "full"] - - # Values for numeric variations - compaction_head_values: list[int] = [5, 10, 20] - compaction_tail_values: list[int] = [20, 40, 60] - - # Budget limit - budget: int = 100 - - # Optional job ID to associate candidates with - job_id: str | None = None - - def parse_uuid(id_str: str) -> UUID: """Parse a string to UUID, raising 400 if invalid.""" try: @@ -212,108 +184,3 @@ async def delete_config( await session.delete(config) await session.commit() - - -@router.post("/generate-candidates", response_model=list[AgentResponse], status_code=201) -async def generate_candidates( - data: CandidateRequest, - session: AsyncSession = Depends(get_session), - user: Annotated[TokenData | None, Depends(get_current_user)] = None, -) -> list[AgentConfig]: - """Generate candidate agents for optimization. - - Uses GridSearchStrategy to generate candidate variants from a base agent. - Each candidate is stored as an AgentConfig in the database. - """ - effective_user_id = get_effective_user_id(user) - variations: dict[str, list] = {} - - if data.vary_compaction: - variations["compaction"] = [ - CompactionConfig.head_tail(10, 40), - CompactionConfig.none(), - ] - - if data.vary_tools: - variations["tools"] = data.tool_presets - - if data.vary_compaction_head: - variations["compaction"] = [ - CompactionConfig.head_tail(h, 40) for h in data.compaction_head_values - ] - - if data.vary_compaction_tail: - if data.vary_compaction_head: - variations["compaction"] = [ - CompactionConfig.head_tail(h, t) - for h in data.compaction_head_values - for t in data.compaction_tail_values - ] - else: - variations["compaction"] = [ - CompactionConfig.head_tail(10, t) for t in data.compaction_tail_values - ] - - job_uuid = None - if data.job_id: - try: - job_uuid = UUID(data.job_id) - except ValueError: - pass - - base = Agent(name=data.base_name) - - if not variations: - config = AgentConfig( - name=f"{data.base_name}_baseline", - description=f"Baseline agent from {data.base_name}", - config_json={ - "name": f"{data.base_name}_baseline", - "compaction": {"strategy": "head_tail", "params": {"head_size": 10, "tail_size": 40}}, - "tools": "standard", - }, - is_auto_generated=True, - job_id=job_uuid, - user_id=effective_user_id, - ) - session.add(config) - await session.commit() - await session.refresh(config) - return [config] - - strategy = GridSearchStrategy(variations) - candidates = strategy.generate(base, data.budget) - - configs = [] - for candidate in candidates: - candidate_name = candidate.agent.name - - existing = await session.execute( - select(AgentConfig).where(AgentConfig.name == candidate_name).limit(1) - ) - existing_config = existing.scalar_one_or_none() - - if existing_config: - configs.append(existing_config) - else: - from dataclasses import asdict - config = AgentConfig( - name=candidate_name, - description=candidate.rationale, - config_json={ - "name": candidate_name, - "compaction": asdict(candidate.agent.compaction), - "tools": candidate.agent.tools, - }, - is_auto_generated=True, - job_id=job_uuid, - user_id=effective_user_id, - ) - session.add(config) - configs.append(config) - - await session.commit() - for config in configs: - await session.refresh(config) - - return configs diff --git a/src/flow/ui/api/evaluate.py b/src/flow/ui/api/evaluate.py new file mode 100644 index 0000000000000000000000000000000000000000..f7817ab3de7fbf2e9db16623e84e167f68c3e32f --- /dev/null +++ b/src/flow/ui/api/evaluate.py @@ -0,0 +1,107 @@ +# Copyright (c) Microsoft. All rights reserved. +"""Evaluate API routes — single-agent evaluation from the UI.""" + +import asyncio +import logging +from typing import Annotated, Any +from uuid import UUID + +from fastapi import APIRouter, Depends, HTTPException +from fastapi.responses import StreamingResponse +from pydantic import BaseModel, Field +from sqlalchemy.ext.asyncio import AsyncSession +from sqlmodel import select + +from ..auth import TokenData, get_current_user, get_effective_user_id, should_filter_by_user +from ..database import async_session, get_session +from ..models.config import AgentConfig +from ..models.job import JobStatus, OptimizationJob +from ..models.task import TaskModel +from ..schemas import JobResponse + +router = APIRouter(prefix="/evaluate", tags=["evaluate"]) +logger = logging.getLogger(__name__) + + +class EvaluateRequest(BaseModel): + """Request to evaluate a single agent on a task suite.""" + + agent_id: str = Field(description="Agent config ID to evaluate") + suite_name: str | None = Field(default=None, description="Task suite to import and use") + task_ids: list[str] | None = Field(default=None, description="Specific task IDs (alternative to suite)") + use_llm_eval: bool = Field(default=True, description="Use LLM evaluator for scoring") + parallel: int = Field(default=4, description="Parallel task execution") + + +def _parse_uuid(id_str: str) -> UUID: + try: + return UUID(id_str) + except ValueError as e: + raise HTTPException(status_code=400, detail=f"Invalid UUID: {id_str}") from e + + +@router.post("", response_model=JobResponse, status_code=201) +async def evaluate_agent( + data: EvaluateRequest, + session: AsyncSession = Depends(get_session), + user: Annotated[TokenData | None, Depends(get_current_user)] = None, +) -> OptimizationJob: + """Evaluate a single agent on a task suite. + + Creates a job with 1 candidate, imports the suite if needed, + and starts the job in the background. Returns the job so the + frontend can navigate to the job detail page. + """ + effective_user_id = get_effective_user_id(user) + + # Validate agent exists + agent_uuid = _parse_uuid(data.agent_id) + query = select(AgentConfig).where(AgentConfig.id == agent_uuid) + if should_filter_by_user(): + query = query.where(AgentConfig.user_id == effective_user_id) + result = await session.execute(query) + agent = result.scalar_one_or_none() + if not agent: + raise HTTPException(status_code=404, detail="Agent not found") + + # Resolve task IDs + task_ids: list[str] = [] + + if data.suite_name: + # Import suite tasks + from .tasks import _import_suite_tasks + imported = await _import_suite_tasks(data.suite_name, session, effective_user_id) + task_ids = [str(t.id) for t in imported] + elif data.task_ids: + task_ids = data.task_ids + else: + raise HTTPException(status_code=400, detail="Must provide suite_name or task_ids") + + if not task_ids: + raise HTTPException(status_code=400, detail="No tasks found for evaluation") + + # Get display name + created_by_name = None + if user: + created_by_name = getattr(user, "name", None) or getattr(user, "preferred_username", None) or user.sub + + # Create job with single candidate + job = OptimizationJob( + name=f"Evaluate: {agent.name} ({len(task_ids)} tasks)", + candidate_ids=[data.agent_id], + task_ids=task_ids, + parallel=data.parallel, + use_llm_eval=data.use_llm_eval, + total_experiments=len(task_ids), + user_id=effective_user_id, + created_by_name=created_by_name, + ) + session.add(job) + await session.commit() + await session.refresh(job) + + # Start job in background + from .jobs import _run_job_background + asyncio.create_task(_run_job_background(str(job.id))) + + return job diff --git a/src/flow/ui/api/experiment.py b/src/flow/ui/api/experiment.py new file mode 100644 index 0000000000000000000000000000000000000000..409f44f750de04ac1b398012e63a963e3688f664 --- /dev/null +++ b/src/flow/ui/api/experiment.py @@ -0,0 +1,483 @@ +# Copyright (c) Microsoft. All rights reserved. +"""Experiment design API routes. + +Provides endpoints for: +- Generating experiment YAML from UI selections +- Importing experiment YAML to populate UI +- Validating experiment configurations +- Expanding variations into candidate AgentConfigs +""" + +import itertools +from typing import Annotated, Any +from uuid import UUID + +import yaml +from fastapi import APIRouter, Depends, HTTPException +from pydantic import BaseModel, Field +from sqlalchemy.ext.asyncio import AsyncSession +from sqlmodel import select + +from ..auth import TokenData, get_current_user, get_effective_user_id +from ..database import get_session +from ..models.config import AgentConfig +from ..schemas import ( + CompactionVariation, + ExperimentDesignRequest, + ExperimentDesignResponse, + ExperimentVariations, + ExperimentYAMLImportRequest, + ExperimentYAMLImportResponse, + LLMConfigVariation, +) + +router = APIRouter(prefix="/experiment", tags=["experiment"]) + + +def _compaction_to_dict(c: CompactionVariation) -> dict: + """Convert CompactionVariation to dict for YAML.""" + result = {"strategy": c.strategy} + if c.token_budget is not None: + result["token_budget"] = c.token_budget + if c.head_ratio is not None: + result["head_ratio"] = c.head_ratio + if c.head_messages is not None or c.tail_messages is not None or c.summary_max_tokens is not None: + params = {} + if c.head_messages is not None: + params["head_messages"] = c.head_messages + if c.tail_messages is not None: + params["tail_messages"] = c.tail_messages + if c.summary_max_tokens is not None: + params["summary_max_tokens"] = c.summary_max_tokens + if params: + result["params"] = params + return result + + +def _count_dimension(variations: ExperimentVariations) -> dict[str, int]: + """Count values per dimension.""" + counts = {} + if variations.compaction: + counts["compaction"] = len(variations.compaction) + if variations.tools: + counts["tools"] = len(variations.tools) + if variations.llm_config: + counts["llm_config"] = len(variations.llm_config) + if variations.instructions or variations.instruction_strategies: + literal_count = len(variations.instructions) + strategy_count = sum(s.max_candidates for s in variations.instruction_strategies) + counts["instructions"] = literal_count + strategy_count + return counts + + +def _compute_candidate_count(counts: dict[str, int]) -> int: + """Compute total candidates from dimension counts (Cartesian product).""" + if not counts: + return 1 + result = 1 + for count in counts.values(): + result *= max(count, 1) + return result + + +@router.post("/design", response_model=ExperimentDesignResponse) +async def design_experiment( + data: ExperimentDesignRequest, + session: AsyncSession = Depends(get_session), + user: Annotated[TokenData | None, Depends(get_current_user)] = None, +) -> ExperimentDesignResponse: + """Generate experiment YAML from UI selections. + + Takes the UI's experiment design and generates a valid experiment.yaml + that can be used with `flow optimize`. + + Returns the YAML content and candidate count for preview. + """ + # Look up base agent to get its path/name + from uuid import UUID + try: + agent_uuid = UUID(data.base_agent_id) + except ValueError as e: + raise HTTPException(status_code=400, detail=f"Invalid agent ID: {data.base_agent_id}") from e + + result = await session.execute( + select(AgentConfig).where(AgentConfig.id == agent_uuid) + ) + agent = result.scalar_one_or_none() + if not agent: + raise HTTPException(status_code=404, detail="Base agent not found") + + # Build variations dict for YAML + yaml_variations: dict[str, list] = {} + + if data.variations.compaction: + yaml_variations["compaction"] = [ + _compaction_to_dict(c) for c in data.variations.compaction + ] + + if data.variations.tools: + yaml_variations["tools"] = data.variations.tools + + if data.variations.llm_config: + yaml_variations["llm_config"] = [ + {"provider": c.provider, "model": c.model} + for c in data.variations.llm_config + ] + + if data.variations.instructions or data.variations.instruction_strategies: + instructions_list: list = [] + # Add literal instructions + instructions_list.extend(data.variations.instructions) + # Add strategy entries + for s in data.variations.instruction_strategies: + strategy_entry = { + "strategy": s.strategy, + "max_candidates": s.max_candidates, + } + if s.config: + strategy_entry["config"] = s.config + instructions_list.append(strategy_entry) + if instructions_list: + yaml_variations["instructions"] = instructions_list + + # Build the experiment YAML structure + experiment_dict = { + "base_agent": f"agents/{agent.name}.yaml", # Convention: agents/.yaml + } + + if data.task_suite: + experiment_dict["suite"] = data.task_suite + + if yaml_variations: + experiment_dict["variations"] = yaml_variations + + experiment_dict["parallel"] = data.parallel + experiment_dict["budget"] = data.budget + experiment_dict["use_llm_eval"] = data.use_llm_eval + + # Generate YAML with nice formatting + yaml_content = yaml.dump( + experiment_dict, + default_flow_style=False, + sort_keys=False, + allow_unicode=True, + ) + + # Add header comment + header = ( + "# Experiment Configuration\n" + "# Generated from UI\n" + "#\n" + "# Usage:\n" + "# flow optimize experiment.yaml\n\n" + ) + yaml_content = header + yaml_content + + # Compute counts + dimension_counts = _count_dimension(data.variations) + candidate_count = _compute_candidate_count(dimension_counts) + + return ExperimentDesignResponse( + yaml_content=yaml_content, + candidate_count=min(candidate_count, data.budget), + dimension_counts=dimension_counts, + ) + + +@router.post("/import-yaml", response_model=ExperimentYAMLImportResponse) +async def import_yaml( + data: ExperimentYAMLImportRequest, + user: Annotated[TokenData | None, Depends(get_current_user)] = None, +) -> ExperimentYAMLImportResponse: + """Parse experiment YAML and return structured data for UI. + + Enables round-trip: UI -> YAML -> UI + """ + try: + raw = yaml.safe_load(data.yaml_content) + except yaml.YAMLError as e: + raise HTTPException(status_code=400, detail=f"Invalid YAML: {e}") from e + + if not isinstance(raw, dict): + raise HTTPException(status_code=400, detail="YAML must be a mapping") + + # Parse variations + raw_variations = raw.get("variations", {}) + variations = ExperimentVariations() + + # Parse compaction + if "compaction" in raw_variations: + for item in raw_variations["compaction"]: + if isinstance(item, dict): + # Extract params if present + params = item.get("params", {}) + variations.compaction.append(CompactionVariation( + strategy=item.get("strategy", "none"), + token_budget=item.get("token_budget"), + head_ratio=item.get("head_ratio"), + head_messages=params.get("head_messages"), + tail_messages=params.get("tail_messages"), + summary_max_tokens=params.get("summary_max_tokens"), + )) + elif isinstance(item, str): + # Shorthand: "none", "head_tail", etc. + variations.compaction.append(CompactionVariation(strategy=item)) + + # Parse tools + if "tools" in raw_variations: + for item in raw_variations["tools"]: + if isinstance(item, str): + variations.tools.append(item) + + # Parse llm_config + if "llm_config" in raw_variations: + for item in raw_variations["llm_config"]: + if isinstance(item, dict): + variations.llm_config.append(LLMConfigVariation( + provider=item.get("provider", "azure_openai"), + model=item.get("model", "gpt-4o"), + )) + + # Parse instructions (literals and strategies) + if "instructions" in raw_variations: + from ..schemas.experiment import StrategyVariationRequest + for item in raw_variations["instructions"]: + if isinstance(item, str): + variations.instructions.append(item) + elif isinstance(item, dict) and "strategy" in item: + variations.instruction_strategies.append(StrategyVariationRequest( + strategy=item["strategy"], + max_candidates=item.get("max_candidates", 3), + config=item.get("config", {}), + )) + + return ExperimentYAMLImportResponse( + base_agent_path=raw.get("base_agent", ""), + suite=raw.get("suite"), + tasks_path=raw.get("tasks"), + variations=variations, + parallel=raw.get("parallel", 4), + budget=raw.get("budget", 100), + use_llm_eval=raw.get("use_llm_eval", True), + ) + + +@router.post("/validate") +async def validate_experiment( + data: ExperimentDesignRequest, + user: Annotated[TokenData | None, Depends(get_current_user)] = None, +) -> dict: + """Validate experiment design configuration. + + Checks for common issues: + - Empty variations + - Invalid strategy names + - Budget constraints + """ + errors: list[str] = [] + warnings: list[str] = [] + + # Check for at least one variation + has_variations = ( + data.variations.compaction + or data.variations.tools + or data.variations.llm_config + or data.variations.instructions + or data.variations.instruction_strategies + ) + if not has_variations: + warnings.append("No variations specified - will run baseline only") + + # Check candidate count vs budget + dimension_counts = _count_dimension(data.variations) + candidate_count = _compute_candidate_count(dimension_counts) + if candidate_count > data.budget: + warnings.append( + f"Candidate count ({candidate_count}) exceeds budget ({data.budget}). " + f"Only first {data.budget} candidates will run." + ) + + # Validate compaction strategies + valid_compaction = {"none", "head_tail", "sliding_window", "summarization", "last_n", "head_tail_tokens"} + for c in data.variations.compaction: + if c.strategy not in valid_compaction: + errors.append(f"Unknown compaction strategy: {c.strategy}") + + # Validate tool presets + from flow.experiments.models import TOOL_PRESETS + for t in data.variations.tools: + if t not in TOOL_PRESETS: + errors.append(f"Unknown tool preset: {t}") + + # Validate optimization strategies + from flow.experiments.strategies import get_registered_strategies + registered = set(get_registered_strategies().keys()) + for s in data.variations.instruction_strategies: + if s.strategy not in registered: + warnings.append(f"Strategy '{s.strategy}' not registered - may fail at runtime") + + return { + "valid": len(errors) == 0, + "errors": errors, + "warnings": warnings, + "candidate_count": min(candidate_count, data.budget), + "dimension_counts": dimension_counts, + } + + +# ============================================================================= +# Candidate Generation +# ============================================================================= + + +class GenerateCandidatesRequest(BaseModel): + """Request to generate candidate AgentConfigs from variations.""" + + base_agent_id: str = Field(description="ID of the base agent configuration") + variations: ExperimentVariations = Field(description="Parameter variations to expand") + budget: int = Field(default=100, ge=1, le=1000, description="Max candidates to generate") + + +class GenerateCandidatesResponse(BaseModel): + """Response with generated candidate IDs.""" + + candidate_ids: list[str] = Field(description="IDs of generated AgentConfig records") + candidate_count: int = Field(description="Number of candidates generated") + + +def _generate_candidate_name(base_name: str, combination: dict[str, Any], index: int) -> str: + """Generate a descriptive name for a candidate configuration.""" + parts = [base_name] + + if "compaction" in combination: + comp = combination["compaction"] + strategy = comp.get("strategy", "none") + parts.append(strategy) + + if "tools" in combination: + parts.append(combination["tools"]) + + if "llm_config" in combination: + llm = combination["llm_config"] + model = llm.get("model", "unknown") + # Shorten model name + model_short = model.replace("gpt-", "").replace("-", "") + parts.append(model_short) + + # Add index to ensure uniqueness + return f"{'-'.join(parts)}-v{index}" + + +@router.post("/generate-candidates", response_model=GenerateCandidatesResponse) +async def generate_candidates( + data: GenerateCandidatesRequest, + session: AsyncSession = Depends(get_session), + user: Annotated[TokenData | None, Depends(get_current_user)] = None, +) -> GenerateCandidatesResponse: + """Expand variations into candidate AgentConfig records. + + Takes a base agent and variations, generates the Cartesian product, + and creates AgentConfig records for each candidate. Returns the IDs + to be used when creating an optimization job. + """ + # Look up base agent + try: + agent_uuid = UUID(data.base_agent_id) + except ValueError as e: + raise HTTPException(status_code=400, detail=f"Invalid agent ID: {data.base_agent_id}") from e + + result = await session.execute( + select(AgentConfig).where(AgentConfig.id == agent_uuid) + ) + base_agent = result.scalar_one_or_none() + if not base_agent: + raise HTTPException(status_code=404, detail="Base agent not found") + + effective_user_id = get_effective_user_id(user) + + # Build lists for each dimension + compaction_list: list[dict[str, Any]] = [] + if data.variations.compaction: + for c in data.variations.compaction: + compaction_list.append(_compaction_to_dict(c)) + else: + # Use base agent's compaction + compaction_list.append(base_agent.config_json.get("compaction", {"strategy": "head_tail"})) + + tools_list: list[str] = [] + if data.variations.tools: + tools_list = data.variations.tools + else: + # Use base agent's tools + tools_list.append(base_agent.config_json.get("tools", "standard")) + + llm_config_list: list[dict[str, Any]] = [] + if data.variations.llm_config: + for llm in data.variations.llm_config: + llm_config_list.append({"provider": llm.provider, "model": llm.model}) + else: + # Use base agent's llm_config + base_llm = base_agent.config_json.get("llm_config") + if base_llm: + llm_config_list.append(base_llm) + else: + llm_config_list.append({}) # Will use default + + instructions_list: list[str] = [] + if data.variations.instructions: + instructions_list = data.variations.instructions + else: + # Use base agent's instructions + base_instr = base_agent.config_json.get("instructions") + if base_instr: + instructions_list.append(base_instr) + else: + instructions_list.append("") # Will use default + + # Generate Cartesian product of all dimensions + all_combinations = list(itertools.product( + compaction_list, + tools_list, + llm_config_list, + instructions_list, + )) + + # Limit by budget + all_combinations = all_combinations[: data.budget] + + # Create AgentConfig for each combination + candidate_ids: list[str] = [] + for idx, (compaction, tools, llm_config, instructions) in enumerate(all_combinations): + # Build config by merging base with variations + config_json = dict(base_agent.config_json) # Copy base config + config_json["compaction"] = compaction + config_json["tools"] = tools + if llm_config: + config_json["llm_config"] = llm_config + if instructions: + config_json["instructions"] = instructions + + combination = { + "compaction": compaction, + "tools": tools, + "llm_config": llm_config, + } + name = _generate_candidate_name(base_agent.name, combination, idx + 1) + + candidate = AgentConfig( + name=name, + description=f"Auto-generated variant of {base_agent.name}", + config_json=config_json, + is_auto_generated=True, + user_id=effective_user_id, + ) + session.add(candidate) + await session.flush() # Get the ID + candidate_ids.append(str(candidate.id)) + + await session.commit() + + return GenerateCandidatesResponse( + candidate_ids=candidate_ids, + candidate_count=len(candidate_ids), + ) diff --git a/src/flow/ui/api/llm_configs.py b/src/flow/ui/api/llm_configs.py index 4981ed8072abcabfb30442cb4df5aa76917be7bf..4b891f1fee12fd70b232cc33c32c3823a550b088 100644 --- a/src/flow/ui/api/llm_configs.py +++ b/src/flow/ui/api/llm_configs.py @@ -3,7 +3,6 @@ import time from datetime import datetime, timezone -from typing import Annotated from uuid import UUID from fastapi import APIRouter, Depends, HTTPException @@ -280,7 +279,7 @@ async def test_llm_config( if response.content: return LLMConfigTestResult( success=True, - message=f"Connection successful. Response received.", + message="Connection successful. Response received.", latency_ms=latency_ms, ) return LLMConfigTestResult( @@ -303,5 +302,5 @@ async def test_llm_config( except Exception as e: return LLMConfigTestResult( success=False, - message=f"Connection failed: {str(e)}", + message=f"Connection failed: {e!s}", ) diff --git a/src/flow/ui/api/schema.py b/src/flow/ui/api/schema.py new file mode 100644 index 0000000000000000000000000000000000000000..b3a73348f982139991d6ba70671c0406e0e3c2f1 --- /dev/null +++ b/src/flow/ui/api/schema.py @@ -0,0 +1,301 @@ +# Copyright (c) Microsoft. All rights reserved. +"""Schema API routes - provides dynamic configuration schema to the UI. + +This endpoint allows the UI to dynamically render configuration options +based on what each framework actually supports. +""" + +from typing import Any + +from fastapi import APIRouter +from pydantic import BaseModel, Field + +from flow.experiments.models import COMPACTION_STRATEGIES, DEFAULT_TOKEN_BUDGET, TOOL_PRESETS +from flow.experiments.presets import get_all_presets +from flow.experiments.strategies import get_registered_strategies +from flow.harness.registry import get_registered_harnesses +from flow.llm.config import LLMProvider + +router = APIRouter(prefix="/schema", tags=["schema"]) + + +# ============================================================================= +# Response Models +# ============================================================================= + + +class ParamSchema(BaseModel): + """Schema for a single parameter.""" + + type: str = Field(description="Parameter type (number, string, boolean)") + default: Any = Field(description="Default value") + min: float | None = Field(default=None, description="Minimum value for numbers") + max: float | None = Field(default=None, description="Maximum value for numbers") + description: str = Field(default="", description="Human-readable description") + + +class CompactionStrategySchema(BaseModel): + """Schema for a compaction strategy.""" + + label: str = Field(description="Human-readable label") + description: str = Field(description="Description of the strategy") + params: dict[str, ParamSchema] = Field( + default_factory=dict, + description="Parameters for this strategy", + ) + + +class FrameworkSchema(BaseModel): + """Schema for a framework.""" + + label: str = Field(description="Human-readable label") + description: str = Field(description="Description of the framework") + compaction_strategies: list[str] = Field( + description="List of supported compaction strategy names" + ) + + +class ToolPresetSchema(BaseModel): + """Schema for a tool preset.""" + + name: str = Field(description="Preset name (minimal, standard, full, readonly)") + description: str = Field(description="Human-readable description") + tools: list[str] = Field(description="List of tool names in this preset") + + +class LLMProviderSchema(BaseModel): + """Schema for an LLM provider.""" + + name: str = Field(description="Provider identifier (openai, azure_openai, etc.)") + label: str = Field(description="Human-readable label") + models: list[str] = Field( + description="Suggested models for this provider (not exhaustive)" + ) + + +class OptimizationStrategySchema(BaseModel): + """Schema for an optimization strategy (GEPA, llm_rewriter, etc.).""" + + name: str = Field(description="Strategy identifier") + description: str = Field(description="What this strategy does") + applicable_dimensions: list[str] = Field( + description="Dimensions this strategy can optimize (e.g., instructions, tools)" + ) + + +class AgentPresetSchema(BaseModel): + """Schema for an agent preset.""" + + name: str = Field(description="Preset identifier (e.g., 'coding')") + label: str = Field(description="Human-readable label") + description: str = Field(description="Description of the preset") + config: dict[str, Any] = Field(description="Agent configuration dict") + suggested_datasets: list[str] = Field( + default_factory=list, + description="Suggested task datasets for this preset", + ) + tags: list[str] = Field( + default_factory=list, + description="Tags for categorization", + ) + + +class AgentSchema(BaseModel): + """Full schema for agent configuration. + + Aggregates framework capabilities and compaction strategies + to enable dynamic UI rendering. + """ + + frameworks: dict[str, FrameworkSchema] = Field( + description="Available frameworks and their capabilities" + ) + compaction_strategies: dict[str, CompactionStrategySchema] = Field( + description="All compaction strategies with their parameters" + ) + tool_presets: list[ToolPresetSchema] = Field( + description="Available tool presets" + ) + llm_providers: list[LLMProviderSchema] = Field( + description="Available LLM providers and their models" + ) + optimization_strategies: list[OptimizationStrategySchema] = Field( + description="Available optimization strategies for experiment design" + ) + instructions_presets: list[str] = Field( + description="Available instruction preset names" + ) + default_token_budget: int = Field( + default=DEFAULT_TOKEN_BUDGET, + description="Default token budget for compaction", + ) + agent_presets: list[AgentPresetSchema] = Field( + default_factory=list, + description="Pre-configured agent presets for quick start", + ) + + +# ============================================================================= +# API Routes +# ============================================================================= + + +@router.get("/agent", response_model=AgentSchema) +async def get_agent_schema() -> AgentSchema: + """Get the full agent configuration schema. + + Returns framework capabilities aggregated from harness registrations + and compaction strategy definitions. + + This allows the UI to: + - Show only frameworks that are registered + - Filter compaction strategies by what each framework supports + - Dynamically render parameter inputs based on strategy schema + - Display available tool presets and LLM providers + - Show available optimization strategies for experiment design + """ + # Build frameworks from registered harnesses + frameworks: dict[str, FrameworkSchema] = {} + for name, harness_class in get_registered_harnesses().items(): + frameworks[name] = FrameworkSchema( + label=getattr(harness_class, "framework_label", name), + description=getattr(harness_class, "framework_description", ""), + compaction_strategies=getattr( + harness_class, "supported_compaction_strategies", [] + ), + ) + + # Build compaction strategies from registry + compaction_strategies: dict[str, CompactionStrategySchema] = {} + for name, strategy_info in COMPACTION_STRATEGIES.items(): + params = {} + for param_name, param_info in strategy_info.get("params", {}).items(): + params[param_name] = ParamSchema( + type=param_info.get("type", "string"), + default=param_info.get("default"), + min=param_info.get("min"), + max=param_info.get("max"), + description=param_info.get("description", ""), + ) + + compaction_strategies[name] = CompactionStrategySchema( + label=strategy_info.get("label", name), + description=strategy_info.get("description", ""), + params=params, + ) + + # Build tool presets from TOOL_PRESETS + tool_preset_descriptions = { + "minimal": "Basic tools: read, write, edit, bash, think", + "standard": "Standard tools + grep, glob, todos, memory, web search, skills", + "full": "All tools including task, notebooks, and sub-agent delegation", + "readonly": "Read-only tools: read, glob, ls, grep, think", + } + tool_presets = [ + ToolPresetSchema( + name=name, + description=tool_preset_descriptions.get(name, f"{name} preset"), + tools=list(tools.keys()), + ) + for name, tools in TOOL_PRESETS.items() + ] + + # Build LLM providers with suggested models + llm_provider_info = { + LLMProvider.OPENAI: { + "label": "OpenAI", + "models": ["gpt-4o", "gpt-4o-mini", "gpt-4-turbo", "gpt-3.5-turbo"], + }, + LLMProvider.AZURE_OPENAI: { + "label": "Azure OpenAI", + "models": ["gpt-4o", "gpt-4o-mini", "gpt-4"], + }, + LLMProvider.ANTHROPIC: { + "label": "Anthropic", + "models": ["claude-3-5-sonnet-20241022", "claude-3-opus-20240229", "claude-3-haiku-20240307"], + }, + LLMProvider.OLLAMA: { + "label": "Ollama (Local)", + "models": ["llama3", "codellama", "mistral"], + }, + LLMProvider.CUSTOM: { + "label": "Custom (OpenAI-compatible)", + "models": [], + }, + } + llm_providers = [ + LLMProviderSchema( + name=provider.value, + label=info["label"], + models=info["models"], + ) + for provider, info in llm_provider_info.items() + ] + + # Build optimization strategies from registry + strategy_info = { + "gepa": { + "description": "GEPA: Reflective prompt evolution using LLM feedback", + "applicable_dimensions": ["instructions"], + }, + "llm_rewriter": { + "description": "LLM-based instruction rewriting with variations", + "applicable_dimensions": ["instructions"], + }, + "tool_selector": { + "description": "Intelligent tool set selection based on task", + "applicable_dimensions": ["tools"], + }, + } + optimization_strategies = [ + OptimizationStrategySchema( + name=name, + description=strategy_info.get(name, {}).get("description", f"{name} strategy"), + applicable_dimensions=strategy_info.get(name, {}).get("applicable_dimensions", []), + ) + for name in get_registered_strategies().keys() + ] + + # Instructions presets (could be expanded to a registry later) + instructions_presets = ["general"] + + # Build agent presets from registry + agent_presets = [] + for name, preset in get_all_presets().items(): + agent = preset.agent + config: dict[str, Any] = { + "framework": agent.framework, + "tools": agent.tools, + "compaction": { + "strategy": agent.compaction.strategy, + "params": agent.compaction.params, + }, + } + if agent.instructions is not None: + config["instructions"] = agent.instructions + if agent.instructions_preset is not None: + config["instructions_preset"] = agent.instructions_preset + if agent.llm_config is not None: + config["llm_config"] = agent.llm_config + + agent_presets.append( + AgentPresetSchema( + name=name, + label=preset.label, + description=preset.description, + config=config, + suggested_datasets=preset.suggested_datasets, + tags=preset.tags, + ) + ) + + return AgentSchema( + frameworks=frameworks, + compaction_strategies=compaction_strategies, + tool_presets=tool_presets, + llm_providers=llm_providers, + optimization_strategies=optimization_strategies, + instructions_presets=instructions_presets, + default_token_budget=DEFAULT_TOKEN_BUDGET, + agent_presets=agent_presets, + ) diff --git a/src/flow/ui/api/tasks.py b/src/flow/ui/api/tasks.py index 20e167d95697035ab3ae77eb16b6c6f399ae667f..7be5d7f77441b79f045335a658715182b760911d 100644 --- a/src/flow/ui/api/tasks.py +++ b/src/flow/ui/api/tasks.py @@ -187,14 +187,25 @@ async def delete_task( await session.commit() -@router.post("/import-suite", response_model=list[TaskResponse], status_code=201) -async def import_suite( +async def _import_suite_tasks( suite_name: str, - session: AsyncSession = Depends(get_session), + session: AsyncSession, + user_id: str | None = None, ) -> list[TaskModel]: - """Import tasks from a built-in suite. + """Import tasks from a built-in suite (shared helper). - This is idempotent - tasks that already exist (by name+suite) are returned as-is. + Idempotent - tasks that already exist (by name+suite) are returned as-is. + + Args: + suite_name: Name of the suite to import + session: Active async DB session + user_id: Optional user ID (unused for suite imports, shared tasks have no owner) + + Returns: + List of TaskModel instances (existing or newly created) + + Raises: + HTTPException: If suite_name is invalid """ from flow.experiments.types import get_task_suite @@ -215,10 +226,8 @@ async def import_suite( existing_task = existing.scalar_one_or_none() if existing_task: - # Task already exists, use existing result_tasks.append(existing_task) else: - # Create new task task = TaskModel( name=t.name, prompt=t.prompt, @@ -230,8 +239,19 @@ async def import_suite( result_tasks.append(task) await session.commit() - # Refresh only newly created tasks for task in result_tasks: await session.refresh(task) return result_tasks + + +@router.post("/import-suite", response_model=list[TaskResponse], status_code=201) +async def import_suite( + suite_name: str, + session: AsyncSession = Depends(get_session), +) -> list[TaskModel]: + """Import tasks from a built-in suite. + + This is idempotent - tasks that already exist (by name+suite) are returned as-is. + """ + return await _import_suite_tasks(suite_name, session) diff --git a/src/flow/ui/api/tests.py b/src/flow/ui/api/tests.py index d2943e2b7b04a24c420d9f2cbc4c768abe287482..bc44c61f8b8feddcf07b6abd1dcba8a3d24fde99 100644 --- a/src/flow/ui/api/tests.py +++ b/src/flow/ui/api/tests.py @@ -16,7 +16,7 @@ from ..auth import TokenData, get_current_user, get_effective_user_id, should_fi from ..database import async_session, get_session from ..models.config import AgentConfig from ..models.test_run import TestRun, TestRunStatus -from ..schemas.test import TestRunCreate, TestRunResponse, TestRunDetailResponse +from ..schemas.test import TestRunCreate, TestRunDetailResponse, TestRunResponse from ..services.test_service import TestService router = APIRouter(prefix="/tests", tags=["tests"]) @@ -80,8 +80,9 @@ async def create_test( task_uuid: UUID | None = None if data.task_id: task_uuid = parse_uuid(data.task_id) - from ..models.task import TaskModel from sqlmodel import or_ + + from ..models.task import TaskModel query = select(TaskModel).where(TaskModel.id == task_uuid) if should_filter_by_user(): query = query.where( diff --git a/src/flow/ui/api/tools.py b/src/flow/ui/api/tools.py index 44face76ef4d9fda5faf7301858c497542f76d2f..f035915e6c38e8ad8137a3ab7e414a37719ef938 100644 --- a/src/flow/ui/api/tools.py +++ b/src/flow/ui/api/tools.py @@ -1,34 +1,31 @@ # Copyright (c) Microsoft. All rights reserved. """Tools API routes - serves available tools and presets to the UI.""" -from typing import Any - from fastapi import APIRouter from pydantic import BaseModel from flow.experiments.models import TOOL_PRESETS from flow.tools import ( - read_file, - write_file, + Tool, + bash, + check_processes, edit_file, - multi_edit, glob_files, grep, ls, - bash, - check_processes, - python_repl, - think, - todo_write, - todo_read, memory, - web_search, - web_fetch, + multi_edit, notebook_edit, notebook_read, + read_file, skills, task, - Tool, + think, + todo_read, + todo_write, + web_fetch, + web_search, + write_file, ) router = APIRouter(prefix="/tools", tags=["tools"]) @@ -47,7 +44,6 @@ ALL_TOOLS: list[Tool] = [ # Execution tools bash, check_processes, - python_repl, # Planning tools think, todo_write, @@ -85,7 +81,7 @@ class ToolsResponse(BaseModel): def _get_tool_category(name: str) -> str: """Determine the category of a tool by its name.""" coding_tools = {"read_file", "write_file", "edit_file", "multi_edit", "glob_files", "grep", "ls"} - execution_tools = {"bash", "check_processes", "python_repl"} + execution_tools = {"bash", "check_processes"} planning_tools = {"think", "todo_write", "todo_read"} memory_tools = {"memory"} web_tools = {"web_search", "web_fetch"} diff --git a/src/flow/ui/auth/__init__.py b/src/flow/ui/auth/__init__.py index 5e7566e09e922722aefa3916bb8547ae5c9e4cfd..c26fdd75f21d2ba3d7c7dd235b9708e20e60bfe3 100644 --- a/src/flow/ui/auth/__init__.py +++ b/src/flow/ui/auth/__init__.py @@ -1,24 +1,24 @@ # Copyright (c) Microsoft. All rights reserved. """Authentication module for Flow UI.""" -from .config import AuthSettings, AuthMode, get_auth_settings, init_auth_settings -from .tokens import create_access_token, verify_access_token, TokenData +from .config import AuthMode, AuthSettings, get_auth_settings, init_auth_settings from .middleware import get_current_user, require_auth from .router import router as auth_router -from .user_context import get_effective_user_id, should_filter_by_user, ANONYMOUS_USER_ID +from .tokens import TokenData, create_access_token, verify_access_token +from .user_context import ANONYMOUS_USER_ID, get_effective_user_id, should_filter_by_user __all__ = [ - "AuthSettings", + "ANONYMOUS_USER_ID", "AuthMode", - "get_auth_settings", - "init_auth_settings", - "create_access_token", - "verify_access_token", + "AuthSettings", "TokenData", - "get_current_user", - "require_auth", "auth_router", + "create_access_token", + "get_auth_settings", + "get_current_user", "get_effective_user_id", + "init_auth_settings", + "require_auth", "should_filter_by_user", - "ANONYMOUS_USER_ID", + "verify_access_token", ] diff --git a/src/flow/ui/auth/middleware.py b/src/flow/ui/auth/middleware.py index 3ec71275f8dcee4566edf7bb9b1d65794eb8f636..380cf36138464f30aed4784890b28361233cb131 100644 --- a/src/flow/ui/auth/middleware.py +++ b/src/flow/ui/auth/middleware.py @@ -8,8 +8,8 @@ from typing import Annotated from fastapi import Depends, HTTPException, Request, status from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer -from .config import get_auth_settings, AuthSettings -from .tokens import verify_access_token, TokenData, TokenError +from .config import AuthSettings, get_auth_settings +from .tokens import TokenData, TokenError, verify_access_token # Bearer token security scheme bearer_scheme = HTTPBearer(auto_error=False) diff --git a/src/flow/ui/auth/router.py b/src/flow/ui/auth/router.py index 1ee5558b0499d17f123d5ed6116227325882febc..a183a280515d52570069fd239860107d2b4a802e 100644 --- a/src/flow/ui/auth/router.py +++ b/src/flow/ui/auth/router.py @@ -12,7 +12,7 @@ from fastapi import APIRouter, Depends, HTTPException, Query, Request, status from fastapi.responses import RedirectResponse from pydantic import BaseModel -from .config import AuthMode, AuthSettings, get_auth_settings +from .config import AuthMode, get_auth_settings from .middleware import get_current_user from .tokens import TokenData, create_access_token diff --git a/src/flow/ui/auth/tokens.py b/src/flow/ui/auth/tokens.py index ffe1ff70cce64a9bb505b44835b68987f8af0428..e7777681f450f3a7cda6242c8bf4b30b1af43821 100644 --- a/src/flow/ui/auth/tokens.py +++ b/src/flow/ui/auth/tokens.py @@ -3,10 +3,10 @@ from __future__ import annotations +import base64 import hashlib import hmac import json -import base64 from datetime import datetime, timedelta, timezone from typing import Any diff --git a/src/flow/ui/database.py b/src/flow/ui/database.py index 229b20c367934b846e50ea071f8ef3d11c09ae9b..1c4e189b37934235c6aa0acbdf9e697df6050504 100644 --- a/src/flow/ui/database.py +++ b/src/flow/ui/database.py @@ -24,7 +24,10 @@ async_session = async_sessionmaker(engine, class_=AsyncSession, expire_on_commit async def init_db() -> None: """Initialize database tables and run migrations.""" - from flow.ui.models import AgentConfig, ExperimentRun, OptimizationJob, TaskModel, TestRun, LLMConfig # noqa: F401 + # Import models to register them with SQLModel.metadata (side-effect imports) + from flow.ui.models import AgentConfig, ExperimentRun, LLMConfig, OptimizationJob, TaskModel, TestRun + + _ = (AgentConfig, ExperimentRun, LLMConfig, OptimizationJob, TaskModel, TestRun) try: async with engine.begin() as conn: @@ -137,7 +140,9 @@ async def _seed_default_llm_configs() -> None: Detects which providers are configured via env vars and creates appropriate defaults. """ import os + from sqlmodel import select + from flow.ui.models.llm_config import LLMConfig async with async_session() as session: @@ -200,7 +205,6 @@ async def _seed_default_llm_configs() -> None: } }, )) - first_config = False logger.info(f"Created default Anthropic config (model: {model})") # Add all configs diff --git a/src/flow/ui/main.py b/src/flow/ui/main.py index 4ce873bb515624e4865d531f70d59cb8ff6467b4..a66bce900cc726f8335f41de8234c53e0339a0b6 100644 --- a/src/flow/ui/main.py +++ b/src/flow/ui/main.py @@ -1,20 +1,32 @@ # Copyright (c) Microsoft. All rights reserved. """FastAPI server for Flow UI.""" +from collections.abc import AsyncGenerator from contextlib import asynccontextmanager from pathlib import Path -from typing import Any, AsyncGenerator +from typing import Any from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware -from fastapi.staticfiles import StaticFiles from fastapi.responses import FileResponse +from fastapi.staticfiles import StaticFiles from starlette.middleware.base import BaseHTTPMiddleware -from .database import init_db -from .api import configs_router, tasks_router, jobs_router, runs_router, tests_router, llm_configs_router, tools_router -from .auth import auth_router, AuthSettings, get_auth_settings, init_auth_settings +from .api import ( + configs_router, + evaluate_router, + experiment_router, + jobs_router, + llm_configs_router, + runs_router, + schema_router, + tasks_router, + tests_router, + tools_router, +) +from .auth import auth_router, get_auth_settings, init_auth_settings from .auth.middleware import AuthMiddleware +from .database import init_db @asynccontextmanager @@ -63,12 +75,15 @@ app.add_middleware(BaseHTTPMiddleware, dispatch=AuthMiddleware()) app.include_router(auth_router, prefix="/api") # Protected routes app.include_router(configs_router, prefix="/api") +app.include_router(evaluate_router, prefix="/api") +app.include_router(experiment_router, prefix="/api") app.include_router(tasks_router, prefix="/api") app.include_router(jobs_router, prefix="/api") app.include_router(runs_router, prefix="/api") app.include_router(tests_router, prefix="/api") app.include_router(llm_configs_router, prefix="/api") app.include_router(tools_router, prefix="/api") +app.include_router(schema_router, prefix="/api") # Health check (public, not protected by auth) diff --git a/src/flow/ui/models/__init__.py b/src/flow/ui/models/__init__.py index 3897bdb70e806d74e33a08749163b7101728c897..3520a8f6c59367524e8186ca1d97bd34009c58a4 100644 --- a/src/flow/ui/models/__init__.py +++ b/src/flow/ui/models/__init__.py @@ -2,19 +2,19 @@ """Database models.""" from .config import AgentConfig -from .task import TaskModel -from .job import OptimizationJob, JobStatus +from .job import JobStatus, OptimizationJob +from .llm_config import LLMConfig from .run import ExperimentRun +from .task import TaskModel from .test_run import TestRun, TestRunStatus -from .llm_config import LLMConfig __all__ = [ "AgentConfig", - "TaskModel", - "OptimizationJob", - "JobStatus", "ExperimentRun", + "JobStatus", + "LLMConfig", + "OptimizationJob", + "TaskModel", "TestRun", "TestRunStatus", - "LLMConfig", ] diff --git a/src/flow/ui/models/config.py b/src/flow/ui/models/config.py index 92d2b1847d9c583b77d83d3dd56fb0fa21c57289..e7cc2c401cc35765ca7108d3bedfa3a09171a46f 100644 --- a/src/flow/ui/models/config.py +++ b/src/flow/ui/models/config.py @@ -5,7 +5,7 @@ from datetime import datetime, timezone from typing import Any from uuid import UUID, uuid4 -from sqlmodel import Field, SQLModel, Column, JSON +from sqlmodel import JSON, Column, Field, SQLModel class AgentConfig(SQLModel, table=True): diff --git a/src/flow/ui/models/job.py b/src/flow/ui/models/job.py index 1ac0063739dfcb29c3b3db3ed2622f3e2c33ff60..2be74f8fba813619a720918b0678bc59636b5ae0 100644 --- a/src/flow/ui/models/job.py +++ b/src/flow/ui/models/job.py @@ -5,7 +5,7 @@ from datetime import datetime, timezone from enum import Enum from uuid import UUID, uuid4 -from sqlmodel import Field, SQLModel, Column, JSON +from sqlmodel import JSON, Column, Field, SQLModel class JobStatus(str, Enum): diff --git a/src/flow/ui/models/llm_config.py b/src/flow/ui/models/llm_config.py index 1b17112539dacee24b54f434678246d6dab75ce8..08230f1fb55cbe1070ffa4e12f35ea86236c2574 100644 --- a/src/flow/ui/models/llm_config.py +++ b/src/flow/ui/models/llm_config.py @@ -5,7 +5,7 @@ from datetime import datetime, timezone from typing import Any from uuid import UUID, uuid4 -from sqlmodel import Column, Field, JSON, SQLModel +from sqlmodel import JSON, Column, Field, SQLModel from flow.llm import ( AnthropicConfig, diff --git a/src/flow/ui/models/run.py b/src/flow/ui/models/run.py index 6d432ffc28f9bc67f0f55b9ed9fa6d09d888d72b..d14335734311f9fba3782045693bb1a63f9af922 100644 --- a/src/flow/ui/models/run.py +++ b/src/flow/ui/models/run.py @@ -5,7 +5,7 @@ from datetime import datetime, timezone from typing import Any from uuid import UUID, uuid4 -from sqlmodel import Field, SQLModel, Column, JSON +from sqlmodel import JSON, Column, Field, SQLModel class ExperimentRun(SQLModel, table=True): diff --git a/src/flow/ui/models/task.py b/src/flow/ui/models/task.py index 7e643f7ba00cd60cc38693daa89509264dd828a7..857d666229fd28beccb1342d307741a74d0f6a04 100644 --- a/src/flow/ui/models/task.py +++ b/src/flow/ui/models/task.py @@ -5,7 +5,7 @@ from datetime import datetime, timezone from typing import Any from uuid import UUID, uuid4 -from sqlmodel import Field, SQLModel, Column, JSON +from sqlmodel import JSON, Column, Field, SQLModel class TaskModel(SQLModel, table=True): diff --git a/src/flow/ui/models/test_run.py b/src/flow/ui/models/test_run.py index 133c4f0f7be47127be3a30b4dcf008814aee4138..123a3a51f816575e57cbe863f52c9da7a44ab118 100644 --- a/src/flow/ui/models/test_run.py +++ b/src/flow/ui/models/test_run.py @@ -6,7 +6,7 @@ from enum import Enum from typing import Any from uuid import UUID, uuid4 -from sqlmodel import Column, Field, JSON, SQLModel +from sqlmodel import JSON, Column, Field, SQLModel class TestRunStatus(str, Enum): diff --git a/src/flow/ui/schemas/__init__.py b/src/flow/ui/schemas/__init__.py index f3f928c469c6c81c266f97eacd3975470cb48326..0d17f66f18b9f655c2cad0d20cb9e57db697e890 100644 --- a/src/flow/ui/schemas/__init__.py +++ b/src/flow/ui/schemas/__init__.py @@ -1,22 +1,32 @@ # Copyright (c) Microsoft. All rights reserved. """Pydantic schemas for API requests/responses.""" -from .config import AgentCreate, AgentUpdate, AgentResponse -from .task import TaskCreate, TaskUpdate, TaskResponse, CriterionSchema -from .job import JobCreate, JobUpdate, JobResponse, JobProgress -from .run import RunResponse, RunDetailResponse, CriterionResultSchema -from .test import TestRunCreate, TestRunResponse, TestRunDetailResponse, TestProgress +from .config import AgentCreate, AgentResponse, AgentUpdate +from .experiment import ( + CompactionVariation, + ExperimentDesignRequest, + ExperimentDesignResponse, + ExperimentVariations, + ExperimentYAMLImportRequest, + ExperimentYAMLImportResponse, + LLMConfigVariation, + StrategyVariationRequest, +) +from .job import JobCreate, JobProgress, JobResponse, JobUpdate from .llm_config import ( + AnthropicConfigSchema, + AzureOpenAIConfigSchema, + CustomConfigSchema, LLMConfigCreate, - LLMConfigUpdate, LLMConfigResponse, LLMConfigTestResult, - OpenAIConfigSchema, - AzureOpenAIConfigSchema, - AnthropicConfigSchema, + LLMConfigUpdate, OllamaConfigSchema, - CustomConfigSchema, + OpenAIConfigSchema, ) +from .run import CriterionResultSchema, RunDetailResponse, RunResponse +from .task import CriterionSchema, TaskCreate, TaskResponse, TaskUpdate +from .test import TestProgress, TestRunCreate, TestRunDetailResponse, TestRunResponse __all__ = [ "AgentCreate", @@ -47,4 +57,13 @@ __all__ = [ "AnthropicConfigSchema", "OllamaConfigSchema", "CustomConfigSchema", + # Experiment Design + "CompactionVariation", + "LLMConfigVariation", + "StrategyVariationRequest", + "ExperimentVariations", + "ExperimentDesignRequest", + "ExperimentDesignResponse", + "ExperimentYAMLImportRequest", + "ExperimentYAMLImportResponse", ] diff --git a/src/flow/ui/schemas/config.py b/src/flow/ui/schemas/config.py index de7a9b827d76c9c557cca89b66767af5f7d9a669..49ab10798251a37883eb644ea878fc444163ced0 100644 --- a/src/flow/ui/schemas/config.py +++ b/src/flow/ui/schemas/config.py @@ -31,14 +31,14 @@ class AgentCreate(BaseModel): - dict[str, dict]: Full specification with per-tool configs Framework can be: - - "maf": Microsoft Agent Framework (default) - - "miniagent": MiniAgent with correct context compaction + - "miniagent": MiniAgent with correct context compaction (default) + - "maf": Microsoft Agent Framework - "langgraph": LangGraph (requires extra dependencies) """ name: str description: str = "" - framework: str = "maf" + framework: str = "miniagent" instructions: str | None = None llm_config: LLMConfigSchema | None = None compaction: CompactionConfigSchema = CompactionConfigSchema() diff --git a/src/flow/ui/schemas/experiment.py b/src/flow/ui/schemas/experiment.py new file mode 100644 index 0000000000000000000000000000000000000000..996d0e069d8e7e3d3ea8a9f4216aa6aee15f40b5 --- /dev/null +++ b/src/flow/ui/schemas/experiment.py @@ -0,0 +1,146 @@ +# Copyright (c) Microsoft. All rights reserved. +"""Experiment design schemas for the UI API. + +These schemas define the request/response format for the experiment design +endpoint, which generates experiment configurations from UI selections. +""" + +from typing import Any + +from pydantic import BaseModel, Field + +# ============================================================================= +# Variation Item Schemas +# ============================================================================= + + +class CompactionVariation(BaseModel): + """A compaction configuration variation. + + Can be used directly in the variations list for compaction dimension. + """ + + strategy: str = Field( + description="Compaction strategy: none, head_tail, sliding_window, summarization" + ) + token_budget: int | None = Field( + default=None, description="Token budget for token-aware strategies" + ) + head_ratio: float | None = Field( + default=None, description="Head ratio for head_tail strategy (0-1)" + ) + head_messages: int | None = Field( + default=None, description="Number of head messages for summarization" + ) + tail_messages: int | None = Field( + default=None, description="Number of tail messages for summarization" + ) + summary_max_tokens: int | None = Field( + default=None, description="Max tokens for summary in summarization strategy" + ) + + +class LLMConfigVariation(BaseModel): + """An LLM configuration variation.""" + + provider: str = Field(description="LLM provider: azure_openai, openai, anthropic, etc.") + model: str = Field(description="Model name or deployment") + + +class StrategyVariationRequest(BaseModel): + """Request to use an optimization strategy for a dimension. + + Used for active optimization like GEPA (instructions) or tool selection. + """ + + strategy: str = Field( + description="Strategy name: gepa, llm_rewriter, tool_selector" + ) + max_candidates: int = Field( + default=3, ge=1, le=10, description="Number of candidates to generate" + ) + config: dict[str, Any] = Field( + default_factory=dict, description="Strategy-specific configuration" + ) + + +# ============================================================================= +# Experiment Design Request/Response +# ============================================================================= + + +class ExperimentVariations(BaseModel): + """Variations to test in an experiment. + + Each field represents a dimension that can be varied. + Literal values and strategy requests can be mixed within a dimension. + """ + + compaction: list[CompactionVariation] = Field( + default_factory=list, description="Compaction strategy variations" + ) + tools: list[str] = Field( + default_factory=list, description="Tool preset names to test" + ) + llm_config: list[LLMConfigVariation] = Field( + default_factory=list, description="LLM configurations to test" + ) + instructions: list[str] = Field( + default_factory=list, description="Instruction variations (literal strings)" + ) + instruction_strategies: list[StrategyVariationRequest] = Field( + default_factory=list, + description="Active strategies for instruction optimization (e.g., GEPA)", + ) + + +class ExperimentDesignRequest(BaseModel): + """Request to design an experiment from UI selections. + + The UI sends this when the user configures experiment variations. + """ + + base_agent_id: str = Field(description="ID of the base agent configuration") + task_suite: str | None = Field( + default=None, description="Built-in task suite name" + ) + task_ids: list[str] | None = Field( + default=None, description="Specific task IDs to run" + ) + variations: ExperimentVariations = Field( + description="Parameter variations to test" + ) + parallel: int = Field(default=4, ge=1, le=32, description="Max concurrent experiments") + budget: int = Field(default=100, ge=1, le=1000, description="Max candidates to generate") + use_llm_eval: bool = Field(default=True, description="Use LLM-as-Judge evaluation") + + +class ExperimentDesignResponse(BaseModel): + """Response from experiment design endpoint. + + Returns the generated YAML and candidate count for preview. + """ + + yaml_content: str = Field(description="Generated experiment YAML content") + candidate_count: int = Field(description="Number of candidates that will be generated") + dimension_counts: dict[str, int] = Field( + description="Number of values per dimension" + ) + + +class ExperimentYAMLImportRequest(BaseModel): + """Request to import an experiment from YAML.""" + + yaml_content: str = Field(description="YAML content to parse") + + +class ExperimentYAMLImportResponse(BaseModel): + """Response from YAML import - parsed variations for UI.""" + + base_agent_path: str = Field(description="Path to base agent from YAML") + suite: str | None = Field(default=None, description="Task suite from YAML") + tasks_path: str | None = Field(default=None, description="Tasks file path from YAML") + variations: ExperimentVariations = Field(description="Parsed variations") + parallel: int = Field(description="Parallel setting from YAML") + budget: int = Field(description="Budget setting from YAML") + use_llm_eval: bool = Field(description="LLM eval setting from YAML") diff --git a/src/flow/ui/services/optimizer_service.py b/src/flow/ui/services/optimizer_service.py index 348663e1423a5ad5b409e91515786da13c245f7d..8facc080a8f057a93b6b78bef12071692ad4aa27 100644 --- a/src/flow/ui/services/optimizer_service.py +++ b/src/flow/ui/services/optimizer_service.py @@ -2,8 +2,8 @@ """Optimizer service that wraps FlowOptimizer for the web UI.""" import asyncio +from collections.abc import AsyncGenerator from datetime import datetime, timezone -from typing import AsyncGenerator from uuid import UUID from sqlalchemy.ext.asyncio import AsyncSession @@ -15,10 +15,10 @@ from flow.experiments.types import EvalCriterion, Task from ..database import async_session from ..models.config import AgentConfig -from ..models.job import OptimizationJob, JobStatus +from ..models.job import JobStatus, OptimizationJob from ..models.task import TaskModel -from ..models.run import ExperimentRun from ..schemas import JobProgress +from .persistence_adapter import PersistenceAdapter class OptimizerService: @@ -126,39 +126,13 @@ class OptimizerService: ) return - for summary in opt_result.summaries: - for task_result in summary.task_results: - run = ExperimentRun( - job_id=job.id, - candidate_name=task_result.candidate_name, - task_name=task_result.task_name, - status="completed", - tokens_total=task_result.metrics.total_tokens, - tokens_input=task_result.metrics.input_tokens, - tokens_output=task_result.metrics.output_tokens, - duration_seconds=task_result.run_result.duration_seconds, - score=task_result.eval_score, - passed=task_result.eval_passed, - reasoning=task_result.eval_reasoning, - output=task_result.run_result.output or "", - files_created=task_result.run_result.files_created or [], - trace_json={ - "success": task_result.run_result.success, - "error": task_result.run_result.error, - "spans": task_result.run_result.trace or [], - "criteria_results": task_result.criteria_results, - }, - is_pareto=summary.is_pareto_optimal, - pareto_rank=summary.pareto_rank or 0, - ) - session.add(run) - - job.status = JobStatus.COMPLETED - job.completed_experiments = opt_result.total_experiments - job.pareto_frontier = opt_result.pareto_frontier - job.output_dir = str(opt_result.output_dir) - job.completed_at = datetime.now(timezone.utc) - await session.commit() + # Persist results using the shared adapter + adapter = PersistenceAdapter() + await adapter.persist_optimization_with_session( + result=opt_result, + job=job, + session=session, + ) yield JobProgress( event="complete", @@ -207,7 +181,7 @@ class OptimizerService: agent = Agent( name=db_config.name, - framework=cfg.get("framework", "maf"), + framework=cfg.get("framework", "miniagent"), instructions=cfg.get("instructions"), llm_config=cfg.get("llm_config"), compaction=compaction, diff --git a/src/flow/ui/services/persistence_adapter.py b/src/flow/ui/services/persistence_adapter.py new file mode 100644 index 0000000000000000000000000000000000000000..235406cb192bb534b2c32c08269ea59f354b5e50 --- /dev/null +++ b/src/flow/ui/services/persistence_adapter.py @@ -0,0 +1,285 @@ +# Copyright (c) Microsoft. All rights reserved. +"""Persistence adapter — bridges FlowOptimizer results to the database. + +This adapter provides a single, shared conversion layer used by: +1. Agent.deploy() — registers an agent in the DB +2. Agent.evaluate()/optimize() — auto-persists results when agent is deployed +3. OptimizerService — persists results from UI-initiated jobs + +By centralizing the conversion logic here, we avoid duplication between +the code-first path (agent_api.py) and the UI path (optimizer_service.py). +""" + +from __future__ import annotations + +import logging +from dataclasses import asdict +from datetime import datetime, timezone +from typing import TYPE_CHECKING +from uuid import UUID + +from flow.ui.database import async_session, init_db +from flow.ui.models.config import AgentConfig +from flow.ui.models.job import JobStatus, OptimizationJob +from flow.ui.models.run import ExperimentRun + +if TYPE_CHECKING: + from flow.experiments.models import Agent + from flow.experiments.optimizer import CandidateSummary, OptimizationResult, TaskResult + +logger = logging.getLogger(__name__) + + +class PersistenceAdapter: + """Converts FlowOptimizer results to database rows.""" + + async def _ensure_db(self) -> None: + """Ensure DB tables exist (safe to call multiple times).""" + await init_db() + + async def deploy_agent(self, agent: Agent) -> str: + """Register an agent in the database. + + Creates an AgentConfig row from the Agent dataclass. + This is a pure DB write — no server required. + + Args: + agent: The Agent to register + + Returns: + The agent ID (UUID string) + """ + await self._ensure_db() + + config_json = self._agent_to_config_json(agent) + + async with async_session() as session: + db_config = AgentConfig( + name=agent.name, + description=agent.description, + config_json=config_json, + is_auto_generated=False, + ) + session.add(db_config) + await session.commit() + await session.refresh(db_config) + agent_id = str(db_config.id) + + logger.info(f"Deployed agent {agent.name!r} with ID {agent_id}") + return agent_id + + async def persist_evaluation( + self, + summary: CandidateSummary, + agent_id: str, + job_name: str | None = None, + ) -> str: + """Persist a single-agent evaluation to the database. + + Creates an OptimizationJob with 1 candidate and ExperimentRun + rows for each task result. + + Args: + summary: The CandidateSummary from evaluate_agent() + agent_id: The deployed agent's UUID string + job_name: Optional job name (defaults to "Evaluation: {agent_name}") + + Returns: + The job ID (UUID string) + """ + await self._ensure_db() + + name = job_name or f"Evaluation: {summary.name}" + task_count = summary.task_count + + async with async_session() as session: + job = OptimizationJob( + name=name, + status=JobStatus.COMPLETED, + parallel=1, + use_llm_eval=True, + candidate_ids=[agent_id], + task_ids=[], # Tasks not in DB for code-first path + pareto_frontier=[summary.name], + total_experiments=task_count, + completed_experiments=task_count, + started_at=datetime.now(timezone.utc), + completed_at=datetime.now(timezone.utc), + ) + session.add(job) + await session.flush() # Get job.id + + for task_result in summary.task_results: + run = self._task_result_to_run( + job_id=job.id, + task_result=task_result, + is_pareto=True, + pareto_rank=0, + ) + session.add(run) + + await session.commit() + job_id = str(job.id) + + logger.info(f"Persisted evaluation job {job_id} ({task_count} tasks)") + return job_id + + async def persist_optimization( + self, + result: OptimizationResult, + agent_id: str, + job_name: str | None = None, + ) -> str: + """Persist a multi-candidate optimization to the database. + + Creates candidate AgentConfig rows, an OptimizationJob, and + ExperimentRun rows for all task results. + + Args: + result: The OptimizationResult from FlowOptimizer.optimize() + agent_id: The deployed base agent's UUID string + job_name: Optional job name + + Returns: + The job ID (UUID string) + """ + await self._ensure_db() + + name = job_name or f"Optimization ({len(result.summaries)} candidates)" + + async with async_session() as session: + # Create candidate AgentConfig rows for non-baseline candidates + candidate_ids = [agent_id] + for summary in result.summaries: + if summary.candidate and summary.candidate.mutations: + config_json = self._agent_to_config_json(summary.candidate.agent) + candidate_config = AgentConfig( + name=summary.name, + config_json=config_json, + is_auto_generated=True, + ) + session.add(candidate_config) + await session.flush() + candidate_ids.append(str(candidate_config.id)) + + job = OptimizationJob( + name=name, + status=JobStatus.COMPLETED, + parallel=1, + use_llm_eval=True, + candidate_ids=candidate_ids, + task_ids=[], + pareto_frontier=result.pareto_frontier, + output_dir=str(result.output_dir) if result.output_dir else None, + total_experiments=result.total_experiments, + completed_experiments=result.total_experiments, + started_at=datetime.now(timezone.utc), + completed_at=datetime.now(timezone.utc), + ) + session.add(job) + await session.flush() + + for summary in result.summaries: + for task_result in summary.task_results: + run = self._task_result_to_run( + job_id=job.id, + task_result=task_result, + is_pareto=summary.is_pareto_optimal, + pareto_rank=summary.pareto_rank or 0, + ) + session.add(run) + + await session.commit() + job_id = str(job.id) + + logger.info( + f"Persisted optimization job {job_id} " + f"({len(result.summaries)} candidates, {result.total_experiments} runs)" + ) + return job_id + + async def persist_optimization_with_session( + self, + result: OptimizationResult, + job: OptimizationJob, + session: object, + ) -> None: + """Persist optimization results into an existing job using an existing session. + + Used by OptimizerService which manages its own session and job lifecycle. + + Args: + result: The OptimizationResult from FlowOptimizer + job: The existing OptimizationJob row + session: The active async DB session + """ + from sqlalchemy.ext.asyncio import AsyncSession + + assert isinstance(session, AsyncSession) + + for summary in result.summaries: + for task_result in summary.task_results: + run = self._task_result_to_run( + job_id=job.id, + task_result=task_result, + is_pareto=summary.is_pareto_optimal, + pareto_rank=summary.pareto_rank or 0, + ) + session.add(run) + + job.status = JobStatus.COMPLETED + job.completed_experiments = result.total_experiments + job.pareto_frontier = result.pareto_frontier + job.output_dir = str(result.output_dir) if result.output_dir else None + job.completed_at = datetime.now(timezone.utc) + await session.commit() + + def _task_result_to_run( + self, + job_id: UUID, + task_result: TaskResult, + is_pareto: bool, + pareto_rank: int, + ) -> ExperimentRun: + """Convert a single TaskResult to an ExperimentRun row.""" + return ExperimentRun( + job_id=job_id, + candidate_name=task_result.candidate_name, + task_name=task_result.task_name, + status="completed", + tokens_total=task_result.metrics.total_tokens, + tokens_input=task_result.metrics.input_tokens, + tokens_output=task_result.metrics.output_tokens, + duration_seconds=task_result.run_result.duration_seconds, + score=task_result.eval_score, + passed=task_result.eval_passed, + reasoning=task_result.eval_reasoning, + output=task_result.run_result.output or "", + files_created=task_result.run_result.files_created or [], + trace_json={ + "success": task_result.run_result.success, + "error": task_result.run_result.error, + "spans": task_result.run_result.trace or [], + "criteria_results": task_result.criteria_results, + }, + is_pareto=is_pareto, + pareto_rank=pareto_rank, + ) + + def _agent_to_config_json(self, agent: Agent) -> dict: + """Convert an Agent dataclass to the config_json dict stored in DB.""" + compaction_dict = asdict(agent.compaction) + + config: dict = { + "framework": agent.framework, + "tools": agent.tools, + "compaction": compaction_dict, + } + if agent.instructions is not None: + config["instructions"] = agent.instructions + if agent.instructions_preset is not None: + config["instructions_preset"] = agent.instructions_preset + if agent.llm_config is not None: + config["llm_config"] = agent.llm_config + + return config diff --git a/src/flow/ui/services/test_service.py b/src/flow/ui/services/test_service.py index 659ad4214daa0572e8158c2bfe4bc1e2395feb0e..de1d27d8c6b86170e31b6ee765b28f3e88982752 100644 --- a/src/flow/ui/services/test_service.py +++ b/src/flow/ui/services/test_service.py @@ -6,9 +6,10 @@ import logging import os import tempfile import time +from collections.abc import AsyncGenerator from datetime import datetime, timezone from pathlib import Path -from typing import Any, AsyncGenerator +from typing import Any from uuid import UUID from opentelemetry import trace @@ -16,49 +17,77 @@ from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import SimpleSpanProcessor, SpanExportResult from sqlmodel import select -from flow.experiments.models import Agent, CompactionConfig from flow.experiments.metrics import extract_metrics +from flow.experiments.models import Agent, CompactionConfig from flow.experiments.trace_collector import FlowTraceCollector from flow.harness.base import BaseHarness, EventType -from flow.llm import LLMClientConfig from ..database import async_session from ..models.config import AgentConfig -from ..models.llm_config import LLMConfig from ..models.test_run import TestRun, TestRunStatus from ..schemas.test import TestProgress logger = logging.getLogger(__name__) +# Module-level shared collector for the web UI — set up once +_ui_collector: FlowTraceCollector | None = None +_ui_tracing_initialized = False + + +def _ensure_ui_tracing() -> FlowTraceCollector: + """Ensure tracing is set up for the web UI, returning the shared collector.""" + global _ui_collector, _ui_tracing_initialized + + if _ui_collector is not None: + return _ui_collector + + _ui_collector = FlowTraceCollector() + + if not _ui_tracing_initialized: + provider = trace.get_tracer_provider() + if isinstance(provider, TracerProvider): + processor = SimpleSpanProcessor(_ui_collector) + provider.add_span_processor(processor) + _ui_tracing_initialized = True + + return _ui_collector + class StreamingTraceCollector(FlowTraceCollector): - """Trace collector that pushes spans to a queue for real-time streaming.""" + """Trace collector that pushes spans to a queue for real-time streaming. + + Wraps the shared collector to also push spans into an asyncio queue + for SSE streaming. Filters by registered trace_ids so only the + current test's spans are streamed. + """ - def __init__(self, span_queue: asyncio.Queue[dict[str, Any]]) -> None: + def __init__(self, span_queue: asyncio.Queue[dict[str, Any]], task_trace_ids: set[str]) -> None: """Initialize with a queue for span streaming. Args: span_queue: Queue to push spans to for SSE streaming + task_trace_ids: Set of trace_ids to filter for this task """ super().__init__() self._queue = span_queue + self._task_trace_ids = task_trace_ids def export(self, spans: Any) -> SpanExportResult: - """Export spans and push to queue for streaming.""" - # Get count before export - count_before = len(self.spans) - - # Call parent export which populates self.spans - result = super().export(spans) - - # Push newly added spans to queue - for span in self.spans[count_before:]: + """Export spans and push matching ones to queue for streaming.""" + for span in spans: try: - self._queue.put_nowait(span) - except asyncio.QueueFull: - logger.debug("Span queue full, dropping span") + trace_id = format(span.context.trace_id, "032x") + if trace_id in self._task_trace_ids: + span_dict = self._convert_span(span) + try: + self._queue.put_nowait(span_dict) + except asyncio.QueueFull: + logger.debug("Span queue full, dropping span") + except Exception as e: + logger.debug(f"Failed to stream span: {e}") - return result + # Also store in buckets (parent handles isolation) + return super().export(spans) class TestService: @@ -67,6 +96,9 @@ class TestService: async def run_test(self, test_run_id: str | UUID) -> AsyncGenerator[TestProgress, None]: """Run an agent test and yield real-time progress with spans. + Uses a root span for trace_id isolation so that concurrent tests + don't contaminate each other's traces. + Args: test_run_id: ID of the test run to execute @@ -121,30 +153,23 @@ class TestService: workspace = Path(tempfile.mkdtemp(prefix="flow_test_")) try: - # Set up streaming trace collection - collector = StreamingTraceCollector(span_queue) - processor: SimpleSpanProcessor | None = None + # Ensure shared collector is set up + shared_collector = _ensure_ui_tracing() + + # We'll track trace_ids for this task + task_trace_ids: set[str] = set() + + # Create a streaming collector that filters by trace_id + streaming_collector = StreamingTraceCollector(span_queue, task_trace_ids) + streaming_processor: SimpleSpanProcessor | None = None provider = trace.get_tracer_provider() if isinstance(provider, TracerProvider): - processor = SimpleSpanProcessor(collector) - provider.add_span_processor(processor) - - # Load LLM config if specified - llm_client_config = None - llm_config_id = agent_config.config_json.get("llm_config_id") - if llm_config_id: - llm_config_result = await session.execute( - select(LLMConfig).where(LLMConfig.id == UUID(llm_config_id)) - ) - llm_config = llm_config_result.scalar_one_or_none() - if llm_config: - llm_client_config = llm_config.to_llm_client_config() + streaming_processor = SimpleSpanProcessor(streaming_collector) + provider.add_span_processor(streaming_processor) # Create agent from config - harness = self._create_harness_from_config( - agent_config, workspace, llm_client_config - ) + harness = self._create_harness_from_config(agent_config, workspace) # Execute agent with streaming start_time = time.time() @@ -155,42 +180,48 @@ class TestService: os.chdir(workspace) try: - async for event in harness.run_stream(test_run.prompt): - # Yield execution events - if event.type == EventType.TEXT_DELTA: - output_chunks.append(event.content) - yield TestProgress( - event="execution", - test_run_id=str(test_run_id), - execution_event="text_delta", - content=event.content, - ) - elif event.type == EventType.TOOL_CALL_START: - yield TestProgress( - event="execution", - test_run_id=str(test_run_id), - execution_event="tool_call_start", - tool_name=event.tool_name, - ) - elif event.type == EventType.TOOL_RESULT: - yield TestProgress( - event="execution", - test_run_id=str(test_run_id), - execution_event="tool_result", - content=event.content[:500] if event.content else "", # Truncate long results - ) - - # Drain span queue and yield span events - while not span_queue.empty(): - try: - span_data = span_queue.get_nowait() + # Create root span for trace_id isolation + tracer = trace.get_tracer("flow.ui.test", "0.1.0") + with tracer.start_as_current_span(f"test_{test_run_id}") as root_span: + trace_id = format(root_span.get_span_context().trace_id, "032x") + task_trace_ids.add(trace_id) + + async for event in harness.run_stream(test_run.prompt): + # Yield execution events + if event.type == EventType.TEXT_DELTA: + output_chunks.append(event.content) yield TestProgress( - event="span", + event="execution", test_run_id=str(test_run_id), - span=span_data, + execution_event="text_delta", + content=event.content, ) - except asyncio.QueueEmpty: - break + elif event.type == EventType.TOOL_CALL_START: + yield TestProgress( + event="execution", + test_run_id=str(test_run_id), + execution_event="tool_call_start", + tool_name=event.tool_name, + ) + elif event.type == EventType.TOOL_RESULT: + yield TestProgress( + event="execution", + test_run_id=str(test_run_id), + execution_event="tool_result", + content=event.content[:500] if event.content else "", + ) + + # Drain span queue and yield span events + while not span_queue.empty(): + try: + span_data = span_queue.get_nowait() + yield TestProgress( + event="span", + test_run_id=str(test_run_id), + span=span_data, + ) + except asyncio.QueueEmpty: + break except Exception as e: error = str(e) @@ -201,14 +232,14 @@ class TestService: end_time = time.time() duration_seconds = end_time - start_time - # Force flush and get all traces - if processor: + # Force flush streaming processor + if streaming_processor: try: - processor.force_flush() + streaming_processor.force_flush() except Exception as e: logger.debug(f"Error flushing processor: {e}") - # Drain remaining spans + # Drain remaining spans from queue while not span_queue.empty(): try: span_data = span_queue.get_nowait() @@ -220,13 +251,13 @@ class TestService: except asyncio.QueueEmpty: break - # Get final trace data - trace_data = collector.get_traces() + # Get this task's traces from the shared collector + trace_data = shared_collector.get_traces_for_task(task_trace_ids) - # Clean up processor - if processor: + # Shut down the streaming processor (it was per-test) + if streaming_processor: try: - processor.shutdown() + streaming_processor.shutdown() except Exception as e: logger.debug(f"Error shutting down processor: {e}") @@ -283,21 +314,21 @@ class TestService: self, agent_config: AgentConfig, workspace: Path, - llm_config: LLMClientConfig | None = None, ) -> BaseHarness: """Create a harness from an agent config using the registry. Args: agent_config: The agent configuration from database workspace: Workspace directory for agent execution - llm_config: Optional LLM configuration (falls back to env vars) Returns: Configured harness """ # Import harness modules to register them, then use registry - import flow.harness.maf # noqa: F401 - import flow.harness.miniagent # noqa: F401 + import flow.harness.maf as _maf + import flow.harness.miniagent as _miniagent + + _ = (_maf, _miniagent) from flow.harness import create_harness cfg = agent_config.config_json @@ -312,11 +343,11 @@ class TestService: # Build Agent spec from config agent = Agent( name=agent_config.name, - framework=cfg.get("framework", "maf"), + framework=cfg.get("framework", "miniagent"), instructions=cfg.get("instructions"), llm_config=cfg.get("llm_config"), compaction=compaction, tools=cfg.get("tools", "standard"), ) - return create_harness(agent, workspace, llm_config=llm_config) + return create_harness(agent, workspace) diff --git a/src/flow/ui/tests/test_e2e_user_journey.py b/src/flow/ui/tests/test_e2e_user_journey.py index 9329c351cf02f62299e6d5eee0f095891785e833..b504e77075f44af37269d9e6b447b9559c51130c 100644 --- a/src/flow/ui/tests/test_e2e_user_journey.py +++ b/src/flow/ui/tests/test_e2e_user_journey.py @@ -7,13 +7,13 @@ the complete user journey with proper cleanup. Run with: pytest src/flow/ui/tests/test_e2e_user_journey.py -xvs """ -from typing import AsyncGenerator +from collections.abc import AsyncGenerator import httpx import pytest -from flow.ui.main import app from flow.ui.database import init_db +from flow.ui.main import app @pytest.fixture @@ -162,7 +162,7 @@ class TestE2EUserJourney: job_detail = resp.json() assert job_detail["id"] == job["id"] assert job_detail["status"] == "pending" - print(f" ✓ Retrieved job details") + print(" ✓ Retrieved job details") print(f" - Name: {job_detail['name']}") print(f" - Status: {job_detail['status']}") print(f" - Created: {job_detail['created_at']}") @@ -197,12 +197,12 @@ class TestE2EUserJourney: # Get single agent resp = await client.get(f"/api/configs/{agent1['id']}") assert resp.status_code == 200 - print(f" ✓ GET /configs/{{id}} works") + print(" ✓ GET /configs/{id} works") # Get single task resp = await client.get(f"/api/tasks/{created_task_ids[0]}") assert resp.status_code == 200 - print(f" ✓ GET /tasks/{{id}} works") + print(" ✓ GET /tasks/{id} works") # List jobs resp = await client.get("/api/jobs") @@ -491,15 +491,15 @@ class TestAPIEndpoints: job_id = job["id"] print(f" ✓ Created job: {job_id[:8]}...") assert job["status"] == "pending" - print(f" ✓ Job status is 'pending'") + print(" ✓ Job status is 'pending'") # Try to start job - this is a streaming endpoint # We just verify it's accessible (200 OK) even if it errors during execution - print(f" ✓ Attempting to start job...") + print(" ✓ Attempting to start job...") start_resp = await client.post(f"/api/jobs/{job_id}/start") # The endpoint should return 200 OK for the SSE stream assert start_resp.status_code == 200, f"Start endpoint failed: {start_resp.status_code}" - print(f" ✓ Start endpoint responded with 200") + print(" ✓ Start endpoint responded with 200") # Check job status after start attempt # It should have transitioned from 'pending' (to 'running' or 'failed') @@ -516,12 +516,12 @@ class TestAPIEndpoints: # Cleanup await client.delete(f"/api/jobs/{job_id}") - print(f" ✓ Deleted job") + print(" ✓ Deleted job") finally: await client.delete(f"/api/tasks/{task['id']}") await client.delete(f"/api/configs/{config['id']}") - print(f" ✓ Cleaned up config and task") + print(" ✓ Cleaned up config and task") print("\n Job start endpoint test passed!") @@ -546,7 +546,7 @@ class TestAPIEndpoints: # Should return same tasks (same IDs) assert task_ids1 == task_ids2, "Import should be idempotent - same task IDs expected" - print(f" ✓ Same task IDs returned (idempotent)") + print(" ✓ Same task IDs returned (idempotent)") # Count tasks in DB to verify no duplicates list_resp = await client.get("/api/tasks", params={"suite": "quick"}) @@ -557,7 +557,7 @@ class TestAPIEndpoints: # Note: there may be duplicates from before this fix, so just check IDs match quick_task_ids = {t["id"] for t in all_quick_tasks if t["suite"] == "quick"} assert task_ids1.issubset(quick_task_ids), "Imported task IDs should exist in DB" - print(f" ✓ No new duplicates created") + print(" ✓ No new duplicates created") # Cleanup - delete the tasks we imported for task_id in task_ids1: @@ -605,7 +605,7 @@ class TestAPIEndpoints: # Try to reset a pending job - should fail reset_resp = await client.post(f"/api/jobs/{job_id}/reset") assert reset_resp.status_code == 400 - print(f" ✓ Cannot reset pending job (expected)") + print(" ✓ Cannot reset pending job (expected)") # Start the job (will likely fail but status changes) await client.post(f"/api/jobs/{job_id}/start") @@ -623,16 +623,16 @@ class TestAPIEndpoints: assert reset_job["status"] == "pending" assert reset_job["started_at"] is None assert reset_job["completed_experiments"] == 0 - print(f" ✓ Job reset to pending successfully") + print(" ✓ Job reset to pending successfully") # Cleanup await client.delete(f"/api/jobs/{job_id}") - print(f" ✓ Deleted job") + print(" ✓ Deleted job") finally: await client.delete(f"/api/tasks/{task['id']}") await client.delete(f"/api/configs/{config['id']}") - print(f" ✓ Cleaned up config and task") + print(" ✓ Cleaned up config and task") print("\n Job reset endpoint test passed!") diff --git a/src/flow/ui/tests/test_test_service.py b/src/flow/ui/tests/test_test_service.py index fdee5137d392f88e4150a52ed21f7427f4d653a6..4610fc028227200a7c6df78818f9a6005ddbed47 100644 --- a/src/flow/ui/tests/test_test_service.py +++ b/src/flow/ui/tests/test_test_service.py @@ -134,18 +134,20 @@ class TestTestServiceHelpers: def test_parse_uuid_valid(self): """Test parsing a valid UUID string.""" - from flow.ui.api.tests import parse_uuid from uuid import UUID + from flow.ui.api.tests import parse_uuid + result = parse_uuid("12345678-1234-1234-1234-123456789abc") assert isinstance(result, UUID) assert str(result) == "12345678-1234-1234-1234-123456789abc" def test_parse_uuid_invalid(self): """Test parsing an invalid UUID string raises HTTPException.""" - from flow.ui.api.tests import parse_uuid from fastapi import HTTPException + from flow.ui.api.tests import parse_uuid + with pytest.raises(HTTPException) as exc_info: parse_uuid("not-a-uuid") assert exc_info.value.status_code == 400 diff --git a/src/flow/ui/tests/test_tests_api.py b/src/flow/ui/tests/test_tests_api.py index d1102015803c4bdaae6b1e69956656e8d02723fc..6ce6d3bb96a08087375f05decf9c36fe0758c877 100644 --- a/src/flow/ui/tests/test_tests_api.py +++ b/src/flow/ui/tests/test_tests_api.py @@ -1,13 +1,13 @@ # Copyright (c) Microsoft. All rights reserved. """Unit tests for the tests API routes.""" -from typing import AsyncGenerator +from collections.abc import AsyncGenerator import httpx import pytest -from flow.ui.main import app from flow.ui.database import init_db +from flow.ui.main import app @pytest.fixture diff --git a/src/flow/ui/ui/assets/index-B2d0uHIr.js b/src/flow/ui/ui/assets/index-B2d0uHIr.js new file mode 100644 index 0000000000000000000000000000000000000000..83939b931d7efe06fd80c65066529fc97127d945 --- /dev/null +++ b/src/flow/ui/ui/assets/index-B2d0uHIr.js @@ -0,0 +1,270 @@ +var Vu=e=>{throw TypeError(e)};var Ua=(e,t,n)=>t.has(e)||Vu("Cannot "+n);var g=(e,t,n)=>(Ua(e,t,"read from private field"),n?n.call(e):t.get(e)),U=(e,t,n)=>t.has(e)?Vu("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(e):t.set(e,n),z=(e,t,n,r)=>(Ua(e,t,"write to private field"),r?r.call(e,n):t.set(e,n),n),W=(e,t,n)=>(Ua(e,t,"access private method"),n);var li=(e,t,n,r)=>({set _(s){z(e,t,s,n)},get _(){return g(e,t,r)}});function Vm(e,t){for(var n=0;nr[s]})}}}return Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const s of document.querySelectorAll('link[rel="modulepreload"]'))r(s);new MutationObserver(s=>{for(const i of s)if(i.type==="childList")for(const l of i.addedNodes)l.tagName==="LINK"&&l.rel==="modulepreload"&&r(l)}).observe(document,{childList:!0,subtree:!0});function n(s){const i={};return s.integrity&&(i.integrity=s.integrity),s.referrerPolicy&&(i.referrerPolicy=s.referrerPolicy),s.crossOrigin==="use-credentials"?i.credentials="include":s.crossOrigin==="anonymous"?i.credentials="omit":i.credentials="same-origin",i}function r(s){if(s.ep)return;s.ep=!0;const i=n(s);fetch(s.href,i)}})();function $d(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var Ud={exports:{}},pa={},Bd={exports:{}},J={};/** + * @license React + * react.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var ei=Symbol.for("react.element"),Km=Symbol.for("react.portal"),Hm=Symbol.for("react.fragment"),Wm=Symbol.for("react.strict_mode"),qm=Symbol.for("react.profiler"),Jm=Symbol.for("react.provider"),Gm=Symbol.for("react.context"),Ym=Symbol.for("react.forward_ref"),Xm=Symbol.for("react.suspense"),Zm=Symbol.for("react.memo"),ep=Symbol.for("react.lazy"),Ku=Symbol.iterator;function tp(e){return e===null||typeof e!="object"?null:(e=Ku&&e[Ku]||e["@@iterator"],typeof e=="function"?e:null)}var Qd={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},Vd=Object.assign,Kd={};function Wr(e,t,n){this.props=e,this.context=t,this.refs=Kd,this.updater=n||Qd}Wr.prototype.isReactComponent={};Wr.prototype.setState=function(e,t){if(typeof e!="object"&&typeof e!="function"&&e!=null)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")};Wr.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")};function Hd(){}Hd.prototype=Wr.prototype;function zo(e,t,n){this.props=e,this.context=t,this.refs=Kd,this.updater=n||Qd}var Fo=zo.prototype=new Hd;Fo.constructor=zo;Vd(Fo,Wr.prototype);Fo.isPureReactComponent=!0;var Hu=Array.isArray,Wd=Object.prototype.hasOwnProperty,Io={current:null},qd={key:!0,ref:!0,__self:!0,__source:!0};function Jd(e,t,n){var r,s={},i=null,l=null;if(t!=null)for(r in t.ref!==void 0&&(l=t.ref),t.key!==void 0&&(i=""+t.key),t)Wd.call(t,r)&&!qd.hasOwnProperty(r)&&(s[r]=t[r]);var o=arguments.length-2;if(o===1)s.children=n;else if(1>>1,M=L[H];if(0>>1;Hs(B,R))Zs(ge,B)?(L[H]=ge,L[Z]=R,H=Z):(L[H]=B,L[_]=R,H=_);else if(Zs(ge,R))L[H]=ge,L[Z]=R,H=Z;else break e}}return A}function s(L,A){var R=L.sortIndex-A.sortIndex;return R!==0?R:L.id-A.id}if(typeof performance=="object"&&typeof performance.now=="function"){var i=performance;e.unstable_now=function(){return i.now()}}else{var l=Date,o=l.now();e.unstable_now=function(){return l.now()-o}}var u=[],c=[],m=1,d=null,h=3,x=!1,w=!1,y=!1,S=typeof setTimeout=="function"?setTimeout:null,v=typeof clearTimeout=="function"?clearTimeout:null,f=typeof setImmediate<"u"?setImmediate:null;typeof navigator<"u"&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function p(L){for(var A=n(c);A!==null;){if(A.callback===null)r(c);else if(A.startTime<=L)r(c),A.sortIndex=A.expirationTime,t(u,A);else break;A=n(c)}}function j(L){if(y=!1,p(L),!w)if(n(u)!==null)w=!0,et(C);else{var A=n(c);A!==null&&be(j,A.startTime-L)}}function C(L,A){w=!1,y&&(y=!1,v(E),E=-1),x=!0;var R=h;try{for(p(A),d=n(u);d!==null&&(!(d.expirationTime>A)||L&&!Q());){var H=d.callback;if(typeof H=="function"){d.callback=null,h=d.priorityLevel;var M=H(d.expirationTime<=A);A=e.unstable_now(),typeof M=="function"?d.callback=M:d===n(u)&&r(u),p(A)}else r(u);d=n(u)}if(d!==null)var P=!0;else{var _=n(c);_!==null&&be(j,_.startTime-A),P=!1}return P}finally{d=null,h=R,x=!1}}var N=!1,b=null,E=-1,F=5,O=-1;function Q(){return!(e.unstable_now()-OL||125H?(L.sortIndex=R,t(c,L),n(u)===null&&L===n(c)&&(y?(v(E),E=-1):y=!0,be(j,R-H))):(L.sortIndex=M,t(u,L),w||x||(w=!0,et(C))),L},e.unstable_shouldYield=Q,e.unstable_wrapCallback=function(L){var A=h;return function(){var R=h;h=A;try{return L.apply(this,arguments)}finally{h=R}}}})(ef);Zd.exports=ef;var hp=Zd.exports;/** + * @license React + * react-dom.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var mp=k,Ye=hp;function T(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),yl=Object.prototype.hasOwnProperty,pp=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,qu={},Ju={};function vp(e){return yl.call(Ju,e)?!0:yl.call(qu,e)?!1:pp.test(e)?Ju[e]=!0:(qu[e]=!0,!1)}function xp(e,t,n,r){if(n!==null&&n.type===0)return!1;switch(typeof t){case"function":case"symbol":return!0;case"boolean":return r?!1:n!==null?!n.acceptsBooleans:(e=e.toLowerCase().slice(0,5),e!=="data-"&&e!=="aria-");default:return!1}}function gp(e,t,n,r){if(t===null||typeof t>"u"||xp(e,t,n,r))return!0;if(r)return!1;if(n!==null)switch(n.type){case 3:return!t;case 4:return t===!1;case 5:return isNaN(t);case 6:return isNaN(t)||1>t}return!1}function Ae(e,t,n,r,s,i,l){this.acceptsBooleans=t===2||t===3||t===4,this.attributeName=r,this.attributeNamespace=s,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=i,this.removeEmptyString=l}var Ee={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(e){Ee[e]=new Ae(e,0,!1,e,null,!1,!1)});[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(e){var t=e[0];Ee[t]=new Ae(t,1,!1,e[1],null,!1,!1)});["contentEditable","draggable","spellCheck","value"].forEach(function(e){Ee[e]=new Ae(e,2,!1,e.toLowerCase(),null,!1,!1)});["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(e){Ee[e]=new Ae(e,2,!1,e,null,!1,!1)});"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(e){Ee[e]=new Ae(e,3,!1,e.toLowerCase(),null,!1,!1)});["checked","multiple","muted","selected"].forEach(function(e){Ee[e]=new Ae(e,3,!0,e,null,!1,!1)});["capture","download"].forEach(function(e){Ee[e]=new Ae(e,4,!1,e,null,!1,!1)});["cols","rows","size","span"].forEach(function(e){Ee[e]=new Ae(e,6,!1,e,null,!1,!1)});["rowSpan","start"].forEach(function(e){Ee[e]=new Ae(e,5,!1,e.toLowerCase(),null,!1,!1)});var $o=/[\-:]([a-z])/g;function Uo(e){return e[1].toUpperCase()}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(e){var t=e.replace($o,Uo);Ee[t]=new Ae(t,1,!1,e,null,!1,!1)});"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(e){var t=e.replace($o,Uo);Ee[t]=new Ae(t,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)});["xml:base","xml:lang","xml:space"].forEach(function(e){var t=e.replace($o,Uo);Ee[t]=new Ae(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)});["tabIndex","crossOrigin"].forEach(function(e){Ee[e]=new Ae(e,1,!1,e.toLowerCase(),null,!1,!1)});Ee.xlinkHref=new Ae("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1);["src","href","action","formAction"].forEach(function(e){Ee[e]=new Ae(e,1,!1,e.toLowerCase(),null,!0,!0)});function Bo(e,t,n,r){var s=Ee.hasOwnProperty(t)?Ee[t]:null;(s!==null?s.type!==0:r||!(2o||s[l]!==i[o]){var u=` +`+s[l].replace(" at new "," at ");return e.displayName&&u.includes("")&&(u=u.replace("",e.displayName)),u}while(1<=l&&0<=o);break}}}finally{Va=!1,Error.prepareStackTrace=n}return(e=e?e.displayName||e.name:"")?us(e):""}function yp(e){switch(e.tag){case 5:return us(e.type);case 16:return us("Lazy");case 13:return us("Suspense");case 19:return us("SuspenseList");case 0:case 2:case 15:return e=Ka(e.type,!1),e;case 11:return e=Ka(e.type.render,!1),e;case 1:return e=Ka(e.type,!0),e;default:return""}}function Sl(e){if(e==null)return null;if(typeof e=="function")return e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case or:return"Fragment";case lr:return"Portal";case jl:return"Profiler";case Qo:return"StrictMode";case wl:return"Suspense";case kl:return"SuspenseList"}if(typeof e=="object")switch(e.$$typeof){case rf:return(e.displayName||"Context")+".Consumer";case nf:return(e._context.displayName||"Context")+".Provider";case Vo:var t=e.render;return e=e.displayName,e||(e=t.displayName||t.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case Ko:return t=e.displayName||null,t!==null?t:Sl(e.type)||"Memo";case Jt:t=e._payload,e=e._init;try{return Sl(e(t))}catch{}}return null}function jp(e){var t=e.type;switch(e.tag){case 24:return"Cache";case 9:return(t.displayName||"Context")+".Consumer";case 10:return(t._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return e=t.render,e=e.displayName||e.name||"",t.displayName||(e!==""?"ForwardRef("+e+")":"ForwardRef");case 7:return"Fragment";case 5:return t;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return Sl(t);case 8:return t===Qo?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if(typeof t=="function")return t.displayName||t.name||null;if(typeof t=="string")return t}return null}function Nn(e){switch(typeof e){case"boolean":case"number":case"string":case"undefined":return e;case"object":return e;default:return""}}function af(e){var t=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(t==="checkbox"||t==="radio")}function wp(e){var t=af(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),r=""+e[t];if(!e.hasOwnProperty(t)&&typeof n<"u"&&typeof n.get=="function"&&typeof n.set=="function"){var s=n.get,i=n.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return s.call(this)},set:function(l){r=""+l,i.call(this,l)}}),Object.defineProperty(e,t,{enumerable:n.enumerable}),{getValue:function(){return r},setValue:function(l){r=""+l},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}function ci(e){e._valueTracker||(e._valueTracker=wp(e))}function lf(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),r="";return e&&(r=af(e)?e.checked?"true":"false":e.value),e=r,e!==n?(t.setValue(e),!0):!1}function Ui(e){if(e=e||(typeof document<"u"?document:void 0),typeof e>"u")return null;try{return e.activeElement||e.body}catch{return e.body}}function Nl(e,t){var n=t.checked;return ce({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:n??e._wrapperState.initialChecked})}function Yu(e,t){var n=t.defaultValue==null?"":t.defaultValue,r=t.checked!=null?t.checked:t.defaultChecked;n=Nn(t.value!=null?t.value:n),e._wrapperState={initialChecked:r,initialValue:n,controlled:t.type==="checkbox"||t.type==="radio"?t.checked!=null:t.value!=null}}function of(e,t){t=t.checked,t!=null&&Bo(e,"checked",t,!1)}function bl(e,t){of(e,t);var n=Nn(t.value),r=t.type;if(n!=null)r==="number"?(n===0&&e.value===""||e.value!=n)&&(e.value=""+n):e.value!==""+n&&(e.value=""+n);else if(r==="submit"||r==="reset"){e.removeAttribute("value");return}t.hasOwnProperty("value")?Cl(e,t.type,n):t.hasOwnProperty("defaultValue")&&Cl(e,t.type,Nn(t.defaultValue)),t.checked==null&&t.defaultChecked!=null&&(e.defaultChecked=!!t.defaultChecked)}function Xu(e,t,n){if(t.hasOwnProperty("value")||t.hasOwnProperty("defaultValue")){var r=t.type;if(!(r!=="submit"&&r!=="reset"||t.value!==void 0&&t.value!==null))return;t=""+e._wrapperState.initialValue,n||t===e.value||(e.value=t),e.defaultValue=t}n=e.name,n!==""&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,n!==""&&(e.name=n)}function Cl(e,t,n){(t!=="number"||Ui(e.ownerDocument)!==e)&&(n==null?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+n&&(e.defaultValue=""+n))}var cs=Array.isArray;function yr(e,t,n,r){if(e=e.options,t){t={};for(var s=0;s"+t.valueOf().toString()+"",t=di.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}});function Cs(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&n.nodeType===3){n.nodeValue=t;return}}e.textContent=t}var ms={animationIterationCount:!0,aspectRatio:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},kp=["Webkit","ms","Moz","O"];Object.keys(ms).forEach(function(e){kp.forEach(function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),ms[t]=ms[e]})});function ff(e,t,n){return t==null||typeof t=="boolean"||t===""?"":n||typeof t!="number"||t===0||ms.hasOwnProperty(e)&&ms[e]?(""+t).trim():t+"px"}function hf(e,t){e=e.style;for(var n in t)if(t.hasOwnProperty(n)){var r=n.indexOf("--")===0,s=ff(n,t[n],r);n==="float"&&(n="cssFloat"),r?e.setProperty(n,s):e[n]=s}}var Sp=ce({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function Pl(e,t){if(t){if(Sp[e]&&(t.children!=null||t.dangerouslySetInnerHTML!=null))throw Error(T(137,e));if(t.dangerouslySetInnerHTML!=null){if(t.children!=null)throw Error(T(60));if(typeof t.dangerouslySetInnerHTML!="object"||!("__html"in t.dangerouslySetInnerHTML))throw Error(T(61))}if(t.style!=null&&typeof t.style!="object")throw Error(T(62))}}function Tl(e,t){if(e.indexOf("-")===-1)return typeof t.is=="string";switch(e){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}var Ol=null;function Ho(e){return e=e.target||e.srcElement||window,e.correspondingUseElement&&(e=e.correspondingUseElement),e.nodeType===3?e.parentNode:e}var Ll=null,jr=null,wr=null;function tc(e){if(e=ri(e)){if(typeof Ll!="function")throw Error(T(280));var t=e.stateNode;t&&(t=ja(t),Ll(e.stateNode,e.type,t))}}function mf(e){jr?wr?wr.push(e):wr=[e]:jr=e}function pf(){if(jr){var e=jr,t=wr;if(wr=jr=null,tc(e),t)for(e=0;e>>=0,e===0?32:31-(Mp(e)/zp|0)|0}var fi=64,hi=4194304;function ds(e){switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return e&4194240;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return e&130023424;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 1073741824;default:return e}}function Ki(e,t){var n=e.pendingLanes;if(n===0)return 0;var r=0,s=e.suspendedLanes,i=e.pingedLanes,l=n&268435455;if(l!==0){var o=l&~s;o!==0?r=ds(o):(i&=l,i!==0&&(r=ds(i)))}else l=n&~s,l!==0?r=ds(l):i!==0&&(r=ds(i));if(r===0)return 0;if(t!==0&&t!==r&&!(t&s)&&(s=r&-r,i=t&-t,s>=i||s===16&&(i&4194240)!==0))return t;if(r&4&&(r|=n&16),t=e.entangledLanes,t!==0)for(e=e.entanglements,t&=r;0n;n++)t.push(e);return t}function ti(e,t,n){e.pendingLanes|=t,t!==536870912&&(e.suspendedLanes=0,e.pingedLanes=0),e=e.eventTimes,t=31-pt(t),e[t]=n}function Ap(e,t){var n=e.pendingLanes&~t;e.pendingLanes=t,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=t,e.mutableReadLanes&=t,e.entangledLanes&=t,t=e.entanglements;var r=e.eventTimes;for(e=e.expirationTimes;0=vs),cc=" ",dc=!1;function zf(e,t){switch(e){case"keyup":return hv.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function Ff(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var ur=!1;function pv(e,t){switch(e){case"compositionend":return Ff(t);case"keypress":return t.which!==32?null:(dc=!0,cc);case"textInput":return e=t.data,e===cc&&dc?null:e;default:return null}}function vv(e,t){if(ur)return e==="compositionend"||!eu&&zf(e,t)?(e=Rf(),Oi=Yo=un=null,ur=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:n,offset:t-e};e=r}e:{for(;n;){if(n.nextSibling){n=n.nextSibling;break e}n=n.parentNode}n=void 0}n=pc(n)}}function $f(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?$f(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function Uf(){for(var e=window,t=Ui();t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href=="string"}catch{n=!1}if(n)e=t.contentWindow;else break;t=Ui(e.document)}return t}function tu(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}function bv(e){var t=Uf(),n=e.focusedElem,r=e.selectionRange;if(t!==n&&n&&n.ownerDocument&&$f(n.ownerDocument.documentElement,n)){if(r!==null&&tu(n)){if(t=r.start,e=r.end,e===void 0&&(e=t),"selectionStart"in n)n.selectionStart=t,n.selectionEnd=Math.min(e,n.value.length);else if(e=(t=n.ownerDocument||document)&&t.defaultView||window,e.getSelection){e=e.getSelection();var s=n.textContent.length,i=Math.min(r.start,s);r=r.end===void 0?i:Math.min(r.end,s),!e.extend&&i>r&&(s=r,r=i,i=s),s=vc(n,i);var l=vc(n,r);s&&l&&(e.rangeCount!==1||e.anchorNode!==s.node||e.anchorOffset!==s.offset||e.focusNode!==l.node||e.focusOffset!==l.offset)&&(t=t.createRange(),t.setStart(s.node,s.offset),e.removeAllRanges(),i>r?(e.addRange(t),e.extend(l.node,l.offset)):(t.setEnd(l.node,l.offset),e.addRange(t)))}}for(t=[],e=n;e=e.parentNode;)e.nodeType===1&&t.push({element:e,left:e.scrollLeft,top:e.scrollTop});for(typeof n.focus=="function"&&n.focus(),n=0;n=document.documentMode,cr=null,Dl=null,gs=null,Al=!1;function xc(e,t,n){var r=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;Al||cr==null||cr!==Ui(r)||(r=cr,"selectionStart"in r&&tu(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),gs&&Ls(gs,r)||(gs=r,r=qi(Dl,"onSelect"),0hr||(e.current=Kl[hr],Kl[hr]=null,hr--)}function se(e,t){hr++,Kl[hr]=e.current,e.current=t}var bn={},Re=_n(bn),Ve=_n(!1),Jn=bn;function Ar(e,t){var n=e.type.contextTypes;if(!n)return bn;var r=e.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===t)return r.__reactInternalMemoizedMaskedChildContext;var s={},i;for(i in n)s[i]=t[i];return r&&(e=e.stateNode,e.__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=s),s}function Ke(e){return e=e.childContextTypes,e!=null}function Gi(){ae(Ve),ae(Re)}function Nc(e,t,n){if(Re.current!==bn)throw Error(T(168));se(Re,t),se(Ve,n)}function Gf(e,t,n){var r=e.stateNode;if(t=t.childContextTypes,typeof r.getChildContext!="function")return n;r=r.getChildContext();for(var s in r)if(!(s in t))throw Error(T(108,jp(e)||"Unknown",s));return ce({},n,r)}function Yi(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||bn,Jn=Re.current,se(Re,e),se(Ve,Ve.current),!0}function bc(e,t,n){var r=e.stateNode;if(!r)throw Error(T(169));n?(e=Gf(e,t,Jn),r.__reactInternalMemoizedMergedChildContext=e,ae(Ve),ae(Re),se(Re,e)):ae(Ve),se(Ve,n)}var Ot=null,wa=!1,il=!1;function Yf(e){Ot===null?Ot=[e]:Ot.push(e)}function Iv(e){wa=!0,Yf(e)}function En(){if(!il&&Ot!==null){il=!0;var e=0,t=ne;try{var n=Ot;for(ne=1;e>=l,s-=l,Ft=1<<32-pt(t)+s|n<E?(F=b,b=null):F=b.sibling;var O=h(v,b,p[E],j);if(O===null){b===null&&(b=F);break}e&&b&&O.alternate===null&&t(v,b),f=i(O,f,E),N===null?C=O:N.sibling=O,N=O,b=F}if(E===p.length)return n(v,b),le&&On(v,E),C;if(b===null){for(;EE?(F=b,b=null):F=b.sibling;var Q=h(v,b,O.value,j);if(Q===null){b===null&&(b=F);break}e&&b&&Q.alternate===null&&t(v,b),f=i(Q,f,E),N===null?C=Q:N.sibling=Q,N=Q,b=F}if(O.done)return n(v,b),le&&On(v,E),C;if(b===null){for(;!O.done;E++,O=p.next())O=d(v,O.value,j),O!==null&&(f=i(O,f,E),N===null?C=O:N.sibling=O,N=O);return le&&On(v,E),C}for(b=r(v,b);!O.done;E++,O=p.next())O=x(b,v,E,O.value,j),O!==null&&(e&&O.alternate!==null&&b.delete(O.key===null?E:O.key),f=i(O,f,E),N===null?C=O:N.sibling=O,N=O);return e&&b.forEach(function(D){return t(v,D)}),le&&On(v,E),C}function S(v,f,p,j){if(typeof p=="object"&&p!==null&&p.type===or&&p.key===null&&(p=p.props.children),typeof p=="object"&&p!==null){switch(p.$$typeof){case ui:e:{for(var C=p.key,N=f;N!==null;){if(N.key===C){if(C=p.type,C===or){if(N.tag===7){n(v,N.sibling),f=s(N,p.props.children),f.return=v,v=f;break e}}else if(N.elementType===C||typeof C=="object"&&C!==null&&C.$$typeof===Jt&&Ec(C)===N.type){n(v,N.sibling),f=s(N,p.props),f.ref=is(v,N,p),f.return=v,v=f;break e}n(v,N);break}else t(v,N);N=N.sibling}p.type===or?(f=Wn(p.props.children,v.mode,j,p.key),f.return=v,v=f):(j=Ai(p.type,p.key,p.props,null,v.mode,j),j.ref=is(v,f,p),j.return=v,v=j)}return l(v);case lr:e:{for(N=p.key;f!==null;){if(f.key===N)if(f.tag===4&&f.stateNode.containerInfo===p.containerInfo&&f.stateNode.implementation===p.implementation){n(v,f.sibling),f=s(f,p.children||[]),f.return=v,v=f;break e}else{n(v,f);break}else t(v,f);f=f.sibling}f=hl(p,v.mode,j),f.return=v,v=f}return l(v);case Jt:return N=p._init,S(v,f,N(p._payload),j)}if(cs(p))return w(v,f,p,j);if(es(p))return y(v,f,p,j);ji(v,p)}return typeof p=="string"&&p!==""||typeof p=="number"?(p=""+p,f!==null&&f.tag===6?(n(v,f.sibling),f=s(f,p),f.return=v,v=f):(n(v,f),f=fl(p,v.mode,j),f.return=v,v=f),l(v)):n(v,f)}return S}var Ur=th(!0),nh=th(!1),ea=_n(null),ta=null,vr=null,iu=null;function au(){iu=vr=ta=null}function lu(e){var t=ea.current;ae(ea),e._currentValue=t}function ql(e,t,n){for(;e!==null;){var r=e.alternate;if((e.childLanes&t)!==t?(e.childLanes|=t,r!==null&&(r.childLanes|=t)):r!==null&&(r.childLanes&t)!==t&&(r.childLanes|=t),e===n)break;e=e.return}}function Sr(e,t){ta=e,iu=vr=null,e=e.dependencies,e!==null&&e.firstContext!==null&&(e.lanes&t&&(Qe=!0),e.firstContext=null)}function lt(e){var t=e._currentValue;if(iu!==e)if(e={context:e,memoizedValue:t,next:null},vr===null){if(ta===null)throw Error(T(308));vr=e,ta.dependencies={lanes:0,firstContext:e}}else vr=vr.next=e;return t}var Mn=null;function ou(e){Mn===null?Mn=[e]:Mn.push(e)}function rh(e,t,n,r){var s=t.interleaved;return s===null?(n.next=n,ou(t)):(n.next=s.next,s.next=n),t.interleaved=n,Qt(e,r)}function Qt(e,t){e.lanes|=t;var n=e.alternate;for(n!==null&&(n.lanes|=t),n=e,e=e.return;e!==null;)e.childLanes|=t,n=e.alternate,n!==null&&(n.childLanes|=t),n=e,e=e.return;return n.tag===3?n.stateNode:null}var Gt=!1;function uu(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,interleaved:null,lanes:0},effects:null}}function sh(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,effects:e.effects})}function At(e,t){return{eventTime:e,lane:t,tag:0,payload:null,callback:null,next:null}}function gn(e,t,n){var r=e.updateQueue;if(r===null)return null;if(r=r.shared,X&2){var s=r.pending;return s===null?t.next=t:(t.next=s.next,s.next=t),r.pending=t,Qt(e,n)}return s=r.interleaved,s===null?(t.next=t,ou(r)):(t.next=s.next,s.next=t),r.interleaved=t,Qt(e,n)}function Ri(e,t,n){if(t=t.updateQueue,t!==null&&(t=t.shared,(n&4194240)!==0)){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,qo(e,n)}}function Pc(e,t){var n=e.updateQueue,r=e.alternate;if(r!==null&&(r=r.updateQueue,n===r)){var s=null,i=null;if(n=n.firstBaseUpdate,n!==null){do{var l={eventTime:n.eventTime,lane:n.lane,tag:n.tag,payload:n.payload,callback:n.callback,next:null};i===null?s=i=l:i=i.next=l,n=n.next}while(n!==null);i===null?s=i=t:i=i.next=t}else s=i=t;n={baseState:r.baseState,firstBaseUpdate:s,lastBaseUpdate:i,shared:r.shared,effects:r.effects},e.updateQueue=n;return}e=n.lastBaseUpdate,e===null?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}function na(e,t,n,r){var s=e.updateQueue;Gt=!1;var i=s.firstBaseUpdate,l=s.lastBaseUpdate,o=s.shared.pending;if(o!==null){s.shared.pending=null;var u=o,c=u.next;u.next=null,l===null?i=c:l.next=c,l=u;var m=e.alternate;m!==null&&(m=m.updateQueue,o=m.lastBaseUpdate,o!==l&&(o===null?m.firstBaseUpdate=c:o.next=c,m.lastBaseUpdate=u))}if(i!==null){var d=s.baseState;l=0,m=c=u=null,o=i;do{var h=o.lane,x=o.eventTime;if((r&h)===h){m!==null&&(m=m.next={eventTime:x,lane:0,tag:o.tag,payload:o.payload,callback:o.callback,next:null});e:{var w=e,y=o;switch(h=t,x=n,y.tag){case 1:if(w=y.payload,typeof w=="function"){d=w.call(x,d,h);break e}d=w;break e;case 3:w.flags=w.flags&-65537|128;case 0:if(w=y.payload,h=typeof w=="function"?w.call(x,d,h):w,h==null)break e;d=ce({},d,h);break e;case 2:Gt=!0}}o.callback!==null&&o.lane!==0&&(e.flags|=64,h=s.effects,h===null?s.effects=[o]:h.push(o))}else x={eventTime:x,lane:h,tag:o.tag,payload:o.payload,callback:o.callback,next:null},m===null?(c=m=x,u=d):m=m.next=x,l|=h;if(o=o.next,o===null){if(o=s.shared.pending,o===null)break;h=o,o=h.next,h.next=null,s.lastBaseUpdate=h,s.shared.pending=null}}while(!0);if(m===null&&(u=d),s.baseState=u,s.firstBaseUpdate=c,s.lastBaseUpdate=m,t=s.shared.interleaved,t!==null){s=t;do l|=s.lane,s=s.next;while(s!==t)}else i===null&&(s.shared.lanes=0);Xn|=l,e.lanes=l,e.memoizedState=d}}function Tc(e,t,n){if(e=t.effects,t.effects=null,e!==null)for(t=0;tn?n:4,e(!0);var r=ll.transition;ll.transition={};try{e(!1),t()}finally{ne=n,ll.transition=r}}function wh(){return ot().memoizedState}function Uv(e,t,n){var r=jn(e);if(n={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null},kh(e))Sh(t,n);else if(n=rh(e,t,n,r),n!==null){var s=Ie();vt(n,e,r,s),Nh(n,t,r)}}function Bv(e,t,n){var r=jn(e),s={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null};if(kh(e))Sh(t,s);else{var i=e.alternate;if(e.lanes===0&&(i===null||i.lanes===0)&&(i=t.lastRenderedReducer,i!==null))try{var l=t.lastRenderedState,o=i(l,n);if(s.hasEagerState=!0,s.eagerState=o,xt(o,l)){var u=t.interleaved;u===null?(s.next=s,ou(t)):(s.next=u.next,u.next=s),t.interleaved=s;return}}catch{}finally{}n=rh(e,t,s,r),n!==null&&(s=Ie(),vt(n,e,r,s),Nh(n,t,r))}}function kh(e){var t=e.alternate;return e===ue||t!==null&&t===ue}function Sh(e,t){ys=sa=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function Nh(e,t,n){if(n&4194240){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,qo(e,n)}}var ia={readContext:lt,useCallback:Pe,useContext:Pe,useEffect:Pe,useImperativeHandle:Pe,useInsertionEffect:Pe,useLayoutEffect:Pe,useMemo:Pe,useReducer:Pe,useRef:Pe,useState:Pe,useDebugValue:Pe,useDeferredValue:Pe,useTransition:Pe,useMutableSource:Pe,useSyncExternalStore:Pe,useId:Pe,unstable_isNewReconciler:!1},Qv={readContext:lt,useCallback:function(e,t){return jt().memoizedState=[e,t===void 0?null:t],e},useContext:lt,useEffect:Lc,useImperativeHandle:function(e,t,n){return n=n!=null?n.concat([e]):null,zi(4194308,4,vh.bind(null,t,e),n)},useLayoutEffect:function(e,t){return zi(4194308,4,e,t)},useInsertionEffect:function(e,t){return zi(4,2,e,t)},useMemo:function(e,t){var n=jt();return t=t===void 0?null:t,e=e(),n.memoizedState=[e,t],e},useReducer:function(e,t,n){var r=jt();return t=n!==void 0?n(t):t,r.memoizedState=r.baseState=t,e={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:t},r.queue=e,e=e.dispatch=Uv.bind(null,ue,e),[r.memoizedState,e]},useRef:function(e){var t=jt();return e={current:e},t.memoizedState=e},useState:Oc,useDebugValue:xu,useDeferredValue:function(e){return jt().memoizedState=e},useTransition:function(){var e=Oc(!1),t=e[0];return e=$v.bind(null,e[1]),jt().memoizedState=e,[t,e]},useMutableSource:function(){},useSyncExternalStore:function(e,t,n){var r=ue,s=jt();if(le){if(n===void 0)throw Error(T(407));n=n()}else{if(n=t(),Ne===null)throw Error(T(349));Yn&30||oh(r,t,n)}s.memoizedState=n;var i={value:n,getSnapshot:t};return s.queue=i,Lc(ch.bind(null,r,i,e),[e]),r.flags|=2048,$s(9,uh.bind(null,r,i,n,t),void 0,null),n},useId:function(){var e=jt(),t=Ne.identifierPrefix;if(le){var n=It,r=Ft;n=(r&~(1<<32-pt(r)-1)).toString(32)+n,t=":"+t+"R"+n,n=Ds++,0<\/script>",e=e.removeChild(e.firstChild)):typeof r.is=="string"?e=l.createElement(n,{is:r.is}):(e=l.createElement(n),n==="select"&&(l=e,r.multiple?l.multiple=!0:r.size&&(l.size=r.size))):e=l.createElementNS(e,n),e[Nt]=t,e[zs]=r,Mh(e,t,!1,!1),t.stateNode=e;e:{switch(l=Tl(n,r),n){case"dialog":ie("cancel",e),ie("close",e),s=r;break;case"iframe":case"object":case"embed":ie("load",e),s=r;break;case"video":case"audio":for(s=0;sVr&&(t.flags|=128,r=!0,as(i,!1),t.lanes=4194304)}else{if(!r)if(e=ra(l),e!==null){if(t.flags|=128,r=!0,n=e.updateQueue,n!==null&&(t.updateQueue=n,t.flags|=4),as(i,!0),i.tail===null&&i.tailMode==="hidden"&&!l.alternate&&!le)return Te(t),null}else 2*pe()-i.renderingStartTime>Vr&&n!==1073741824&&(t.flags|=128,r=!0,as(i,!1),t.lanes=4194304);i.isBackwards?(l.sibling=t.child,t.child=l):(n=i.last,n!==null?n.sibling=l:t.child=l,i.last=l)}return i.tail!==null?(t=i.tail,i.rendering=t,i.tail=t.sibling,i.renderingStartTime=pe(),t.sibling=null,n=oe.current,se(oe,r?n&1|2:n&1),t):(Te(t),null);case 22:case 23:return Su(),r=t.memoizedState!==null,e!==null&&e.memoizedState!==null!==r&&(t.flags|=8192),r&&t.mode&1?We&1073741824&&(Te(t),t.subtreeFlags&6&&(t.flags|=8192)):Te(t),null;case 24:return null;case 25:return null}throw Error(T(156,t.tag))}function Yv(e,t){switch(ru(t),t.tag){case 1:return Ke(t.type)&&Gi(),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return Br(),ae(Ve),ae(Re),fu(),e=t.flags,e&65536&&!(e&128)?(t.flags=e&-65537|128,t):null;case 5:return du(t),null;case 13:if(ae(oe),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(T(340));$r()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return ae(oe),null;case 4:return Br(),null;case 10:return lu(t.type._context),null;case 22:case 23:return Su(),null;case 24:return null;default:return null}}var ki=!1,Le=!1,Xv=typeof WeakSet=="function"?WeakSet:Set,I=null;function xr(e,t){var n=e.ref;if(n!==null)if(typeof n=="function")try{n(null)}catch(r){fe(e,t,r)}else n.current=null}function ro(e,t,n){try{n()}catch(r){fe(e,t,r)}}var Qc=!1;function Zv(e,t){if($l=Hi,e=Uf(),tu(e)){if("selectionStart"in e)var n={start:e.selectionStart,end:e.selectionEnd};else e:{n=(n=e.ownerDocument)&&n.defaultView||window;var r=n.getSelection&&n.getSelection();if(r&&r.rangeCount!==0){n=r.anchorNode;var s=r.anchorOffset,i=r.focusNode;r=r.focusOffset;try{n.nodeType,i.nodeType}catch{n=null;break e}var l=0,o=-1,u=-1,c=0,m=0,d=e,h=null;t:for(;;){for(var x;d!==n||s!==0&&d.nodeType!==3||(o=l+s),d!==i||r!==0&&d.nodeType!==3||(u=l+r),d.nodeType===3&&(l+=d.nodeValue.length),(x=d.firstChild)!==null;)h=d,d=x;for(;;){if(d===e)break t;if(h===n&&++c===s&&(o=l),h===i&&++m===r&&(u=l),(x=d.nextSibling)!==null)break;d=h,h=d.parentNode}d=x}n=o===-1||u===-1?null:{start:o,end:u}}else n=null}n=n||{start:0,end:0}}else n=null;for(Ul={focusedElem:e,selectionRange:n},Hi=!1,I=t;I!==null;)if(t=I,e=t.child,(t.subtreeFlags&1028)!==0&&e!==null)e.return=t,I=e;else for(;I!==null;){t=I;try{var w=t.alternate;if(t.flags&1024)switch(t.tag){case 0:case 11:case 15:break;case 1:if(w!==null){var y=w.memoizedProps,S=w.memoizedState,v=t.stateNode,f=v.getSnapshotBeforeUpdate(t.elementType===t.type?y:ct(t.type,y),S);v.__reactInternalSnapshotBeforeUpdate=f}break;case 3:var p=t.stateNode.containerInfo;p.nodeType===1?p.textContent="":p.nodeType===9&&p.documentElement&&p.removeChild(p.documentElement);break;case 5:case 6:case 4:case 17:break;default:throw Error(T(163))}}catch(j){fe(t,t.return,j)}if(e=t.sibling,e!==null){e.return=t.return,I=e;break}I=t.return}return w=Qc,Qc=!1,w}function js(e,t,n){var r=t.updateQueue;if(r=r!==null?r.lastEffect:null,r!==null){var s=r=r.next;do{if((s.tag&e)===e){var i=s.destroy;s.destroy=void 0,i!==void 0&&ro(t,n,i)}s=s.next}while(s!==r)}}function Na(e,t){if(t=t.updateQueue,t=t!==null?t.lastEffect:null,t!==null){var n=t=t.next;do{if((n.tag&e)===e){var r=n.create;n.destroy=r()}n=n.next}while(n!==t)}}function so(e){var t=e.ref;if(t!==null){var n=e.stateNode;switch(e.tag){case 5:e=n;break;default:e=n}typeof t=="function"?t(e):t.current=e}}function Ih(e){var t=e.alternate;t!==null&&(e.alternate=null,Ih(t)),e.child=null,e.deletions=null,e.sibling=null,e.tag===5&&(t=e.stateNode,t!==null&&(delete t[Nt],delete t[zs],delete t[Vl],delete t[zv],delete t[Fv])),e.stateNode=null,e.return=null,e.dependencies=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.stateNode=null,e.updateQueue=null}function Dh(e){return e.tag===5||e.tag===3||e.tag===4}function Vc(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||Dh(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.flags&2||e.child===null||e.tag===4)continue e;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function io(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.nodeType===8?n.parentNode.insertBefore(e,t):n.insertBefore(e,t):(n.nodeType===8?(t=n.parentNode,t.insertBefore(e,n)):(t=n,t.appendChild(e)),n=n._reactRootContainer,n!=null||t.onclick!==null||(t.onclick=Ji));else if(r!==4&&(e=e.child,e!==null))for(io(e,t,n),e=e.sibling;e!==null;)io(e,t,n),e=e.sibling}function ao(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(r!==4&&(e=e.child,e!==null))for(ao(e,t,n),e=e.sibling;e!==null;)ao(e,t,n),e=e.sibling}var Ce=null,ht=!1;function Wt(e,t,n){for(n=n.child;n!==null;)Ah(e,t,n),n=n.sibling}function Ah(e,t,n){if(bt&&typeof bt.onCommitFiberUnmount=="function")try{bt.onCommitFiberUnmount(va,n)}catch{}switch(n.tag){case 5:Le||xr(n,t);case 6:var r=Ce,s=ht;Ce=null,Wt(e,t,n),Ce=r,ht=s,Ce!==null&&(ht?(e=Ce,n=n.stateNode,e.nodeType===8?e.parentNode.removeChild(n):e.removeChild(n)):Ce.removeChild(n.stateNode));break;case 18:Ce!==null&&(ht?(e=Ce,n=n.stateNode,e.nodeType===8?sl(e.parentNode,n):e.nodeType===1&&sl(e,n),Ts(e)):sl(Ce,n.stateNode));break;case 4:r=Ce,s=ht,Ce=n.stateNode.containerInfo,ht=!0,Wt(e,t,n),Ce=r,ht=s;break;case 0:case 11:case 14:case 15:if(!Le&&(r=n.updateQueue,r!==null&&(r=r.lastEffect,r!==null))){s=r=r.next;do{var i=s,l=i.destroy;i=i.tag,l!==void 0&&(i&2||i&4)&&ro(n,t,l),s=s.next}while(s!==r)}Wt(e,t,n);break;case 1:if(!Le&&(xr(n,t),r=n.stateNode,typeof r.componentWillUnmount=="function"))try{r.props=n.memoizedProps,r.state=n.memoizedState,r.componentWillUnmount()}catch(o){fe(n,t,o)}Wt(e,t,n);break;case 21:Wt(e,t,n);break;case 22:n.mode&1?(Le=(r=Le)||n.memoizedState!==null,Wt(e,t,n),Le=r):Wt(e,t,n);break;default:Wt(e,t,n)}}function Kc(e){var t=e.updateQueue;if(t!==null){e.updateQueue=null;var n=e.stateNode;n===null&&(n=e.stateNode=new Xv),t.forEach(function(r){var s=ox.bind(null,e,r);n.has(r)||(n.add(r),r.then(s,s))})}}function ut(e,t){var n=t.deletions;if(n!==null)for(var r=0;rs&&(s=l),r&=~i}if(r=s,r=pe()-r,r=(120>r?120:480>r?480:1080>r?1080:1920>r?1920:3e3>r?3e3:4320>r?4320:1960*tx(r/1960))-r,10e?16:e,cn===null)var r=!1;else{if(e=cn,cn=null,oa=0,X&6)throw Error(T(331));var s=X;for(X|=4,I=e.current;I!==null;){var i=I,l=i.child;if(I.flags&16){var o=i.deletions;if(o!==null){for(var u=0;upe()-wu?Hn(e,0):ju|=n),He(e,t)}function Wh(e,t){t===0&&(e.mode&1?(t=hi,hi<<=1,!(hi&130023424)&&(hi=4194304)):t=1);var n=Ie();e=Qt(e,t),e!==null&&(ti(e,t,n),He(e,n))}function lx(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),Wh(e,n)}function ox(e,t){var n=0;switch(e.tag){case 13:var r=e.stateNode,s=e.memoizedState;s!==null&&(n=s.retryLane);break;case 19:r=e.stateNode;break;default:throw Error(T(314))}r!==null&&r.delete(t),Wh(e,n)}var qh;qh=function(e,t,n){if(e!==null)if(e.memoizedProps!==t.pendingProps||Ve.current)Qe=!0;else{if(!(e.lanes&n)&&!(t.flags&128))return Qe=!1,Jv(e,t,n);Qe=!!(e.flags&131072)}else Qe=!1,le&&t.flags&1048576&&Xf(t,Zi,t.index);switch(t.lanes=0,t.tag){case 2:var r=t.type;Fi(e,t),e=t.pendingProps;var s=Ar(t,Re.current);Sr(t,n),s=mu(null,t,r,e,s,n);var i=pu();return t.flags|=1,typeof s=="object"&&s!==null&&typeof s.render=="function"&&s.$$typeof===void 0?(t.tag=1,t.memoizedState=null,t.updateQueue=null,Ke(r)?(i=!0,Yi(t)):i=!1,t.memoizedState=s.state!==null&&s.state!==void 0?s.state:null,uu(t),s.updater=Sa,t.stateNode=s,s._reactInternals=t,Gl(t,r,e,n),t=Zl(null,t,r,!0,i,n)):(t.tag=0,le&&i&&nu(t),ze(null,t,s,n),t=t.child),t;case 16:r=t.elementType;e:{switch(Fi(e,t),e=t.pendingProps,s=r._init,r=s(r._payload),t.type=r,s=t.tag=cx(r),e=ct(r,e),s){case 0:t=Xl(null,t,r,e,n);break e;case 1:t=$c(null,t,r,e,n);break e;case 11:t=Dc(null,t,r,e,n);break e;case 14:t=Ac(null,t,r,ct(r.type,e),n);break e}throw Error(T(306,r,""))}return t;case 0:return r=t.type,s=t.pendingProps,s=t.elementType===r?s:ct(r,s),Xl(e,t,r,s,n);case 1:return r=t.type,s=t.pendingProps,s=t.elementType===r?s:ct(r,s),$c(e,t,r,s,n);case 3:e:{if(Oh(t),e===null)throw Error(T(387));r=t.pendingProps,i=t.memoizedState,s=i.element,sh(e,t),na(t,r,null,n);var l=t.memoizedState;if(r=l.element,i.isDehydrated)if(i={element:r,isDehydrated:!1,cache:l.cache,pendingSuspenseBoundaries:l.pendingSuspenseBoundaries,transitions:l.transitions},t.updateQueue.baseState=i,t.memoizedState=i,t.flags&256){s=Qr(Error(T(423)),t),t=Uc(e,t,r,n,s);break e}else if(r!==s){s=Qr(Error(T(424)),t),t=Uc(e,t,r,n,s);break e}else for(qe=xn(t.stateNode.containerInfo.firstChild),Je=t,le=!0,mt=null,n=nh(t,null,r,n),t.child=n;n;)n.flags=n.flags&-3|4096,n=n.sibling;else{if($r(),r===s){t=Vt(e,t,n);break e}ze(e,t,r,n)}t=t.child}return t;case 5:return ih(t),e===null&&Wl(t),r=t.type,s=t.pendingProps,i=e!==null?e.memoizedProps:null,l=s.children,Bl(r,s)?l=null:i!==null&&Bl(r,i)&&(t.flags|=32),Th(e,t),ze(e,t,l,n),t.child;case 6:return e===null&&Wl(t),null;case 13:return Lh(e,t,n);case 4:return cu(t,t.stateNode.containerInfo),r=t.pendingProps,e===null?t.child=Ur(t,null,r,n):ze(e,t,r,n),t.child;case 11:return r=t.type,s=t.pendingProps,s=t.elementType===r?s:ct(r,s),Dc(e,t,r,s,n);case 7:return ze(e,t,t.pendingProps,n),t.child;case 8:return ze(e,t,t.pendingProps.children,n),t.child;case 12:return ze(e,t,t.pendingProps.children,n),t.child;case 10:e:{if(r=t.type._context,s=t.pendingProps,i=t.memoizedProps,l=s.value,se(ea,r._currentValue),r._currentValue=l,i!==null)if(xt(i.value,l)){if(i.children===s.children&&!Ve.current){t=Vt(e,t,n);break e}}else for(i=t.child,i!==null&&(i.return=t);i!==null;){var o=i.dependencies;if(o!==null){l=i.child;for(var u=o.firstContext;u!==null;){if(u.context===r){if(i.tag===1){u=At(-1,n&-n),u.tag=2;var c=i.updateQueue;if(c!==null){c=c.shared;var m=c.pending;m===null?u.next=u:(u.next=m.next,m.next=u),c.pending=u}}i.lanes|=n,u=i.alternate,u!==null&&(u.lanes|=n),ql(i.return,n,t),o.lanes|=n;break}u=u.next}}else if(i.tag===10)l=i.type===t.type?null:i.child;else if(i.tag===18){if(l=i.return,l===null)throw Error(T(341));l.lanes|=n,o=l.alternate,o!==null&&(o.lanes|=n),ql(l,n,t),l=i.sibling}else l=i.child;if(l!==null)l.return=i;else for(l=i;l!==null;){if(l===t){l=null;break}if(i=l.sibling,i!==null){i.return=l.return,l=i;break}l=l.return}i=l}ze(e,t,s.children,n),t=t.child}return t;case 9:return s=t.type,r=t.pendingProps.children,Sr(t,n),s=lt(s),r=r(s),t.flags|=1,ze(e,t,r,n),t.child;case 14:return r=t.type,s=ct(r,t.pendingProps),s=ct(r.type,s),Ac(e,t,r,s,n);case 15:return Eh(e,t,t.type,t.pendingProps,n);case 17:return r=t.type,s=t.pendingProps,s=t.elementType===r?s:ct(r,s),Fi(e,t),t.tag=1,Ke(r)?(e=!0,Yi(t)):e=!1,Sr(t,n),bh(t,r,s),Gl(t,r,s,n),Zl(null,t,r,!0,e,n);case 19:return Rh(e,t,n);case 22:return Ph(e,t,n)}throw Error(T(156,t.tag))};function Jh(e,t){return kf(e,t)}function ux(e,t,n,r){this.tag=e,this.key=n,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=t,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function it(e,t,n,r){return new ux(e,t,n,r)}function bu(e){return e=e.prototype,!(!e||!e.isReactComponent)}function cx(e){if(typeof e=="function")return bu(e)?1:0;if(e!=null){if(e=e.$$typeof,e===Vo)return 11;if(e===Ko)return 14}return 2}function wn(e,t){var n=e.alternate;return n===null?(n=it(e.tag,t,e.key,e.mode),n.elementType=e.elementType,n.type=e.type,n.stateNode=e.stateNode,n.alternate=e,e.alternate=n):(n.pendingProps=t,n.type=e.type,n.flags=0,n.subtreeFlags=0,n.deletions=null),n.flags=e.flags&14680064,n.childLanes=e.childLanes,n.lanes=e.lanes,n.child=e.child,n.memoizedProps=e.memoizedProps,n.memoizedState=e.memoizedState,n.updateQueue=e.updateQueue,t=e.dependencies,n.dependencies=t===null?null:{lanes:t.lanes,firstContext:t.firstContext},n.sibling=e.sibling,n.index=e.index,n.ref=e.ref,n}function Ai(e,t,n,r,s,i){var l=2;if(r=e,typeof e=="function")bu(e)&&(l=1);else if(typeof e=="string")l=5;else e:switch(e){case or:return Wn(n.children,s,i,t);case Qo:l=8,s|=8;break;case jl:return e=it(12,n,t,s|2),e.elementType=jl,e.lanes=i,e;case wl:return e=it(13,n,t,s),e.elementType=wl,e.lanes=i,e;case kl:return e=it(19,n,t,s),e.elementType=kl,e.lanes=i,e;case sf:return Ca(n,s,i,t);default:if(typeof e=="object"&&e!==null)switch(e.$$typeof){case nf:l=10;break e;case rf:l=9;break e;case Vo:l=11;break e;case Ko:l=14;break e;case Jt:l=16,r=null;break e}throw Error(T(130,e==null?e:typeof e,""))}return t=it(l,n,t,s),t.elementType=e,t.type=r,t.lanes=i,t}function Wn(e,t,n,r){return e=it(7,e,r,t),e.lanes=n,e}function Ca(e,t,n,r){return e=it(22,e,r,t),e.elementType=sf,e.lanes=n,e.stateNode={isHidden:!1},e}function fl(e,t,n){return e=it(6,e,null,t),e.lanes=n,e}function hl(e,t,n){return t=it(4,e.children!==null?e.children:[],e.key,t),t.lanes=n,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}function dx(e,t,n,r,s){this.tag=t,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.pendingContext=this.context=null,this.callbackPriority=0,this.eventTimes=Wa(0),this.expirationTimes=Wa(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=Wa(0),this.identifierPrefix=r,this.onRecoverableError=s,this.mutableSourceEagerHydrationData=null}function Cu(e,t,n,r,s,i,l,o,u){return e=new dx(e,t,n,o,u),t===1?(t=1,i===!0&&(t|=8)):t=0,i=it(3,null,null,t),e.current=i,i.stateNode=e,i.memoizedState={element:r,isDehydrated:n,cache:null,transitions:null,pendingSuspenseBoundaries:null},uu(i),e}function fx(e,t,n){var r=3"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(Zh)}catch(e){console.error(e)}}Zh(),Xd.exports=Xe;var xx=Xd.exports,Zc=xx;gl.createRoot=Zc.createRoot,gl.hydrateRoot=Zc.hydrateRoot;var Gr=class{constructor(){this.listeners=new Set,this.subscribe=this.subscribe.bind(this)}subscribe(e){return this.listeners.add(e),this.onSubscribe(),()=>{this.listeners.delete(e),this.onUnsubscribe()}}hasListeners(){return this.listeners.size>0}onSubscribe(){}onUnsubscribe(){}},gx={setTimeout:(e,t)=>setTimeout(e,t),clearTimeout:e=>clearTimeout(e),setInterval:(e,t)=>setInterval(e,t),clearInterval:e=>clearInterval(e)},Zt,Mo,Pd,yx=(Pd=class{constructor(){U(this,Zt,gx);U(this,Mo,!1)}setTimeoutProvider(e){z(this,Zt,e)}setTimeout(e,t){return g(this,Zt).setTimeout(e,t)}clearTimeout(e){g(this,Zt).clearTimeout(e)}setInterval(e,t){return g(this,Zt).setInterval(e,t)}clearInterval(e){g(this,Zt).clearInterval(e)}},Zt=new WeakMap,Mo=new WeakMap,Pd),Fn=new yx;function jx(e){setTimeout(e,0)}var er=typeof window>"u"||"Deno"in globalThis;function Fe(){}function wx(e,t){return typeof e=="function"?e(t):e}function fo(e){return typeof e=="number"&&e>=0&&e!==1/0}function em(e,t){return Math.max(e+(t||0)-Date.now(),0)}function kn(e,t){return typeof e=="function"?e(t):e}function nt(e,t){return typeof e=="function"?e(t):e}function ed(e,t){const{type:n="all",exact:r,fetchStatus:s,predicate:i,queryKey:l,stale:o}=e;if(l){if(r){if(t.queryHash!==Tu(l,t.options))return!1}else if(!Bs(t.queryKey,l))return!1}if(n!=="all"){const u=t.isActive();if(n==="active"&&!u||n==="inactive"&&u)return!1}return!(typeof o=="boolean"&&t.isStale()!==o||s&&s!==t.state.fetchStatus||i&&!i(t))}function td(e,t){const{exact:n,status:r,predicate:s,mutationKey:i}=e;if(i){if(!t.options.mutationKey)return!1;if(n){if(tr(t.options.mutationKey)!==tr(i))return!1}else if(!Bs(t.options.mutationKey,i))return!1}return!(r&&t.state.status!==r||s&&!s(t))}function Tu(e,t){return((t==null?void 0:t.queryKeyHashFn)||tr)(e)}function tr(e){return JSON.stringify(e,(t,n)=>ho(n)?Object.keys(n).sort().reduce((r,s)=>(r[s]=n[s],r),{}):n)}function Bs(e,t){return e===t?!0:typeof e!=typeof t?!1:e&&t&&typeof e=="object"&&typeof t=="object"?Object.keys(t).every(n=>Bs(e[n],t[n])):!1}var kx=Object.prototype.hasOwnProperty;function tm(e,t,n=0){if(e===t)return e;if(n>500)return t;const r=nd(e)&&nd(t);if(!r&&!(ho(e)&&ho(t)))return t;const i=(r?e:Object.keys(e)).length,l=r?t:Object.keys(t),o=l.length,u=r?new Array(o):{};let c=0;for(let m=0;m{Fn.setTimeout(t,e)})}function mo(e,t,n){return typeof n.structuralSharing=="function"?n.structuralSharing(e,t):n.structuralSharing!==!1?tm(e,t):t}function Nx(e,t,n=0){const r=[...e,t];return n&&r.length>n?r.slice(1):r}function bx(e,t,n=0){const r=[t,...e];return n&&r.length>n?r.slice(0,-1):r}var Ou=Symbol();function nm(e,t){return!e.queryFn&&(t!=null&&t.initialPromise)?()=>t.initialPromise:!e.queryFn||e.queryFn===Ou?()=>Promise.reject(new Error(`Missing queryFn: '${e.queryHash}'`)):e.queryFn}function Lu(e,t){return typeof e=="function"?e(...t):!!e}function Cx(e,t,n){let r=!1,s;return Object.defineProperty(e,"signal",{enumerable:!0,get:()=>(s??(s=t()),r||(r=!0,s.aborted?n():s.addEventListener("abort",n,{once:!0})),s)}),e}var In,en,Cr,Td,_x=(Td=class extends Gr{constructor(){super();U(this,In);U(this,en);U(this,Cr);z(this,Cr,t=>{if(!er&&window.addEventListener){const n=()=>t();return window.addEventListener("visibilitychange",n,!1),()=>{window.removeEventListener("visibilitychange",n)}}})}onSubscribe(){g(this,en)||this.setEventListener(g(this,Cr))}onUnsubscribe(){var t;this.hasListeners()||((t=g(this,en))==null||t.call(this),z(this,en,void 0))}setEventListener(t){var n;z(this,Cr,t),(n=g(this,en))==null||n.call(this),z(this,en,t(r=>{typeof r=="boolean"?this.setFocused(r):this.onFocus()}))}setFocused(t){g(this,In)!==t&&(z(this,In,t),this.onFocus())}onFocus(){const t=this.isFocused();this.listeners.forEach(n=>{n(t)})}isFocused(){var t;return typeof g(this,In)=="boolean"?g(this,In):((t=globalThis.document)==null?void 0:t.visibilityState)!=="hidden"}},In=new WeakMap,en=new WeakMap,Cr=new WeakMap,Td),Ru=new _x;function po(){let e,t;const n=new Promise((s,i)=>{e=s,t=i});n.status="pending",n.catch(()=>{});function r(s){Object.assign(n,s),delete n.resolve,delete n.reject}return n.resolve=s=>{r({status:"fulfilled",value:s}),e(s)},n.reject=s=>{r({status:"rejected",reason:s}),t(s)},n}var Ex=jx;function Px(){let e=[],t=0,n=o=>{o()},r=o=>{o()},s=Ex;const i=o=>{t?e.push(o):s(()=>{n(o)})},l=()=>{const o=e;e=[],o.length&&s(()=>{r(()=>{o.forEach(u=>{n(u)})})})};return{batch:o=>{let u;t++;try{u=o()}finally{t--,t||l()}return u},batchCalls:o=>(...u)=>{i(()=>{o(...u)})},schedule:i,setNotifyFunction:o=>{n=o},setBatchNotifyFunction:o=>{r=o},setScheduler:o=>{s=o}}}var je=Px(),_r,tn,Er,Od,Tx=(Od=class extends Gr{constructor(){super();U(this,_r,!0);U(this,tn);U(this,Er);z(this,Er,t=>{if(!er&&window.addEventListener){const n=()=>t(!0),r=()=>t(!1);return window.addEventListener("online",n,!1),window.addEventListener("offline",r,!1),()=>{window.removeEventListener("online",n),window.removeEventListener("offline",r)}}})}onSubscribe(){g(this,tn)||this.setEventListener(g(this,Er))}onUnsubscribe(){var t;this.hasListeners()||((t=g(this,tn))==null||t.call(this),z(this,tn,void 0))}setEventListener(t){var n;z(this,Er,t),(n=g(this,tn))==null||n.call(this),z(this,tn,t(this.setOnline.bind(this)))}setOnline(t){g(this,_r)!==t&&(z(this,_r,t),this.listeners.forEach(r=>{r(t)}))}isOnline(){return g(this,_r)}},_r=new WeakMap,tn=new WeakMap,Er=new WeakMap,Od),fa=new Tx;function Ox(e){return Math.min(1e3*2**e,3e4)}function rm(e){return(e??"online")==="online"?fa.isOnline():!0}var vo=class extends Error{constructor(e){super("CancelledError"),this.revert=e==null?void 0:e.revert,this.silent=e==null?void 0:e.silent}};function sm(e){let t=!1,n=0,r;const s=po(),i=()=>s.status!=="pending",l=y=>{var S;if(!i()){const v=new vo(y);h(v),(S=e.onCancel)==null||S.call(e,v)}},o=()=>{t=!0},u=()=>{t=!1},c=()=>Ru.isFocused()&&(e.networkMode==="always"||fa.isOnline())&&e.canRun(),m=()=>rm(e.networkMode)&&e.canRun(),d=y=>{i()||(r==null||r(),s.resolve(y))},h=y=>{i()||(r==null||r(),s.reject(y))},x=()=>new Promise(y=>{var S;r=v=>{(i()||c())&&y(v)},(S=e.onPause)==null||S.call(e)}).then(()=>{var y;r=void 0,i()||(y=e.onContinue)==null||y.call(e)}),w=()=>{if(i())return;let y;const S=n===0?e.initialPromise:void 0;try{y=S??e.fn()}catch(v){y=Promise.reject(v)}Promise.resolve(y).then(d).catch(v=>{var N;if(i())return;const f=e.retry??(er?0:3),p=e.retryDelay??Ox,j=typeof p=="function"?p(n,v):p,C=f===!0||typeof f=="number"&&nc()?void 0:x()).then(()=>{t?h(v):w()})})};return{promise:s,status:()=>s.status,cancel:l,continue:()=>(r==null||r(),s),cancelRetry:o,continueRetry:u,canStart:m,start:()=>(m()?w():x().then(w),s)}}var Dn,Ld,im=(Ld=class{constructor(){U(this,Dn)}destroy(){this.clearGcTimeout()}scheduleGc(){this.clearGcTimeout(),fo(this.gcTime)&&z(this,Dn,Fn.setTimeout(()=>{this.optionalRemove()},this.gcTime))}updateGcTime(e){this.gcTime=Math.max(this.gcTime||0,e??(er?1/0:5*60*1e3))}clearGcTimeout(){g(this,Dn)&&(Fn.clearTimeout(g(this,Dn)),z(this,Dn,void 0))}},Dn=new WeakMap,Ld),An,Pr,tt,$n,ke,Js,Un,dt,Pt,Rd,Lx=(Rd=class extends im{constructor(t){super();U(this,dt);U(this,An);U(this,Pr);U(this,tt);U(this,$n);U(this,ke);U(this,Js);U(this,Un);z(this,Un,!1),z(this,Js,t.defaultOptions),this.setOptions(t.options),this.observers=[],z(this,$n,t.client),z(this,tt,g(this,$n).getQueryCache()),this.queryKey=t.queryKey,this.queryHash=t.queryHash,z(this,An,id(this.options)),this.state=t.state??g(this,An),this.scheduleGc()}get meta(){return this.options.meta}get promise(){var t;return(t=g(this,ke))==null?void 0:t.promise}setOptions(t){if(this.options={...g(this,Js),...t},this.updateGcTime(this.options.gcTime),this.state&&this.state.data===void 0){const n=id(this.options);n.data!==void 0&&(this.setState(sd(n.data,n.dataUpdatedAt)),z(this,An,n))}}optionalRemove(){!this.observers.length&&this.state.fetchStatus==="idle"&&g(this,tt).remove(this)}setData(t,n){const r=mo(this.state.data,t,this.options);return W(this,dt,Pt).call(this,{data:r,type:"success",dataUpdatedAt:n==null?void 0:n.updatedAt,manual:n==null?void 0:n.manual}),r}setState(t,n){W(this,dt,Pt).call(this,{type:"setState",state:t,setStateOptions:n})}cancel(t){var r,s;const n=(r=g(this,ke))==null?void 0:r.promise;return(s=g(this,ke))==null||s.cancel(t),n?n.then(Fe).catch(Fe):Promise.resolve()}destroy(){super.destroy(),this.cancel({silent:!0})}reset(){this.destroy(),this.setState(g(this,An))}isActive(){return this.observers.some(t=>nt(t.options.enabled,this)!==!1)}isDisabled(){return this.getObserversCount()>0?!this.isActive():this.options.queryFn===Ou||this.state.dataUpdateCount+this.state.errorUpdateCount===0}isStatic(){return this.getObserversCount()>0?this.observers.some(t=>kn(t.options.staleTime,this)==="static"):!1}isStale(){return this.getObserversCount()>0?this.observers.some(t=>t.getCurrentResult().isStale):this.state.data===void 0||this.state.isInvalidated}isStaleByTime(t=0){return this.state.data===void 0?!0:t==="static"?!1:this.state.isInvalidated?!0:!em(this.state.dataUpdatedAt,t)}onFocus(){var n;const t=this.observers.find(r=>r.shouldFetchOnWindowFocus());t==null||t.refetch({cancelRefetch:!1}),(n=g(this,ke))==null||n.continue()}onOnline(){var n;const t=this.observers.find(r=>r.shouldFetchOnReconnect());t==null||t.refetch({cancelRefetch:!1}),(n=g(this,ke))==null||n.continue()}addObserver(t){this.observers.includes(t)||(this.observers.push(t),this.clearGcTimeout(),g(this,tt).notify({type:"observerAdded",query:this,observer:t}))}removeObserver(t){this.observers.includes(t)&&(this.observers=this.observers.filter(n=>n!==t),this.observers.length||(g(this,ke)&&(g(this,Un)?g(this,ke).cancel({revert:!0}):g(this,ke).cancelRetry()),this.scheduleGc()),g(this,tt).notify({type:"observerRemoved",query:this,observer:t}))}getObserversCount(){return this.observers.length}invalidate(){this.state.isInvalidated||W(this,dt,Pt).call(this,{type:"invalidate"})}async fetch(t,n){var u,c,m,d,h,x,w,y,S,v,f,p;if(this.state.fetchStatus!=="idle"&&((u=g(this,ke))==null?void 0:u.status())!=="rejected"){if(this.state.data!==void 0&&(n!=null&&n.cancelRefetch))this.cancel({silent:!0});else if(g(this,ke))return g(this,ke).continueRetry(),g(this,ke).promise}if(t&&this.setOptions(t),!this.options.queryFn){const j=this.observers.find(C=>C.options.queryFn);j&&this.setOptions(j.options)}const r=new AbortController,s=j=>{Object.defineProperty(j,"signal",{enumerable:!0,get:()=>(z(this,Un,!0),r.signal)})},i=()=>{const j=nm(this.options,n),N=(()=>{const b={client:g(this,$n),queryKey:this.queryKey,meta:this.meta};return s(b),b})();return z(this,Un,!1),this.options.persister?this.options.persister(j,N,this):j(N)},o=(()=>{const j={fetchOptions:n,options:this.options,queryKey:this.queryKey,client:g(this,$n),state:this.state,fetchFn:i};return s(j),j})();(c=this.options.behavior)==null||c.onFetch(o,this),z(this,Pr,this.state),(this.state.fetchStatus==="idle"||this.state.fetchMeta!==((m=o.fetchOptions)==null?void 0:m.meta))&&W(this,dt,Pt).call(this,{type:"fetch",meta:(d=o.fetchOptions)==null?void 0:d.meta}),z(this,ke,sm({initialPromise:n==null?void 0:n.initialPromise,fn:o.fetchFn,onCancel:j=>{j instanceof vo&&j.revert&&this.setState({...g(this,Pr),fetchStatus:"idle"}),r.abort()},onFail:(j,C)=>{W(this,dt,Pt).call(this,{type:"failed",failureCount:j,error:C})},onPause:()=>{W(this,dt,Pt).call(this,{type:"pause"})},onContinue:()=>{W(this,dt,Pt).call(this,{type:"continue"})},retry:o.options.retry,retryDelay:o.options.retryDelay,networkMode:o.options.networkMode,canRun:()=>!0}));try{const j=await g(this,ke).start();if(j===void 0)throw new Error(`${this.queryHash} data is undefined`);return this.setData(j),(x=(h=g(this,tt).config).onSuccess)==null||x.call(h,j,this),(y=(w=g(this,tt).config).onSettled)==null||y.call(w,j,this.state.error,this),j}catch(j){if(j instanceof vo){if(j.silent)return g(this,ke).promise;if(j.revert){if(this.state.data===void 0)throw j;return this.state.data}}throw W(this,dt,Pt).call(this,{type:"error",error:j}),(v=(S=g(this,tt).config).onError)==null||v.call(S,j,this),(p=(f=g(this,tt).config).onSettled)==null||p.call(f,this.state.data,j,this),j}finally{this.scheduleGc()}}},An=new WeakMap,Pr=new WeakMap,tt=new WeakMap,$n=new WeakMap,ke=new WeakMap,Js=new WeakMap,Un=new WeakMap,dt=new WeakSet,Pt=function(t){const n=r=>{switch(t.type){case"failed":return{...r,fetchFailureCount:t.failureCount,fetchFailureReason:t.error};case"pause":return{...r,fetchStatus:"paused"};case"continue":return{...r,fetchStatus:"fetching"};case"fetch":return{...r,...am(r.data,this.options),fetchMeta:t.meta??null};case"success":const s={...r,...sd(t.data,t.dataUpdatedAt),dataUpdateCount:r.dataUpdateCount+1,...!t.manual&&{fetchStatus:"idle",fetchFailureCount:0,fetchFailureReason:null}};return z(this,Pr,t.manual?s:void 0),s;case"error":const i=t.error;return{...r,error:i,errorUpdateCount:r.errorUpdateCount+1,errorUpdatedAt:Date.now(),fetchFailureCount:r.fetchFailureCount+1,fetchFailureReason:i,fetchStatus:"idle",status:"error",isInvalidated:!0};case"invalidate":return{...r,isInvalidated:!0};case"setState":return{...r,...t.state}}};this.state=n(this.state),je.batch(()=>{this.observers.forEach(r=>{r.onQueryUpdate()}),g(this,tt).notify({query:this,type:"updated",action:t})})},Rd);function am(e,t){return{fetchFailureCount:0,fetchFailureReason:null,fetchStatus:rm(t.networkMode)?"fetching":"paused",...e===void 0&&{error:null,status:"pending"}}}function sd(e,t){return{data:e,dataUpdatedAt:t??Date.now(),error:null,isInvalidated:!1,status:"success"}}function id(e){const t=typeof e.initialData=="function"?e.initialData():e.initialData,n=t!==void 0,r=n?typeof e.initialDataUpdatedAt=="function"?e.initialDataUpdatedAt():e.initialDataUpdatedAt:0;return{data:t,dataUpdateCount:0,dataUpdatedAt:n?r??Date.now():0,error:null,errorUpdateCount:0,errorUpdatedAt:0,fetchFailureCount:0,fetchFailureReason:null,fetchMeta:null,isInvalidated:!1,status:n?"success":"pending",fetchStatus:"idle"}}var $e,G,Gs,Me,Bn,Tr,Lt,nn,Ys,Or,Lr,Qn,Vn,rn,Rr,ee,hs,xo,go,yo,jo,wo,ko,So,lm,Md,Rx=(Md=class extends Gr{constructor(t,n){super();U(this,ee);U(this,$e);U(this,G);U(this,Gs);U(this,Me);U(this,Bn);U(this,Tr);U(this,Lt);U(this,nn);U(this,Ys);U(this,Or);U(this,Lr);U(this,Qn);U(this,Vn);U(this,rn);U(this,Rr,new Set);this.options=n,z(this,$e,t),z(this,nn,null),z(this,Lt,po()),this.bindMethods(),this.setOptions(n)}bindMethods(){this.refetch=this.refetch.bind(this)}onSubscribe(){this.listeners.size===1&&(g(this,G).addObserver(this),ad(g(this,G),this.options)?W(this,ee,hs).call(this):this.updateResult(),W(this,ee,jo).call(this))}onUnsubscribe(){this.hasListeners()||this.destroy()}shouldFetchOnReconnect(){return No(g(this,G),this.options,this.options.refetchOnReconnect)}shouldFetchOnWindowFocus(){return No(g(this,G),this.options,this.options.refetchOnWindowFocus)}destroy(){this.listeners=new Set,W(this,ee,wo).call(this),W(this,ee,ko).call(this),g(this,G).removeObserver(this)}setOptions(t){const n=this.options,r=g(this,G);if(this.options=g(this,$e).defaultQueryOptions(t),this.options.enabled!==void 0&&typeof this.options.enabled!="boolean"&&typeof this.options.enabled!="function"&&typeof nt(this.options.enabled,g(this,G))!="boolean")throw new Error("Expected enabled to be a boolean or a callback that returns a boolean");W(this,ee,So).call(this),g(this,G).setOptions(this.options),n._defaulted&&!da(this.options,n)&&g(this,$e).getQueryCache().notify({type:"observerOptionsUpdated",query:g(this,G),observer:this});const s=this.hasListeners();s&&ld(g(this,G),r,this.options,n)&&W(this,ee,hs).call(this),this.updateResult(),s&&(g(this,G)!==r||nt(this.options.enabled,g(this,G))!==nt(n.enabled,g(this,G))||kn(this.options.staleTime,g(this,G))!==kn(n.staleTime,g(this,G)))&&W(this,ee,xo).call(this);const i=W(this,ee,go).call(this);s&&(g(this,G)!==r||nt(this.options.enabled,g(this,G))!==nt(n.enabled,g(this,G))||i!==g(this,rn))&&W(this,ee,yo).call(this,i)}getOptimisticResult(t){const n=g(this,$e).getQueryCache().build(g(this,$e),t),r=this.createResult(n,t);return zx(this,r)&&(z(this,Me,r),z(this,Tr,this.options),z(this,Bn,g(this,G).state)),r}getCurrentResult(){return g(this,Me)}trackResult(t,n){return new Proxy(t,{get:(r,s)=>(this.trackProp(s),n==null||n(s),s==="promise"&&(this.trackProp("data"),!this.options.experimental_prefetchInRender&&g(this,Lt).status==="pending"&&g(this,Lt).reject(new Error("experimental_prefetchInRender feature flag is not enabled"))),Reflect.get(r,s))})}trackProp(t){g(this,Rr).add(t)}getCurrentQuery(){return g(this,G)}refetch({...t}={}){return this.fetch({...t})}fetchOptimistic(t){const n=g(this,$e).defaultQueryOptions(t),r=g(this,$e).getQueryCache().build(g(this,$e),n);return r.fetch().then(()=>this.createResult(r,n))}fetch(t){return W(this,ee,hs).call(this,{...t,cancelRefetch:t.cancelRefetch??!0}).then(()=>(this.updateResult(),g(this,Me)))}createResult(t,n){var F;const r=g(this,G),s=this.options,i=g(this,Me),l=g(this,Bn),o=g(this,Tr),c=t!==r?t.state:g(this,Gs),{state:m}=t;let d={...m},h=!1,x;if(n._optimisticResults){const O=this.hasListeners(),Q=!O&&ad(t,n),D=O&&ld(t,r,n,s);(Q||D)&&(d={...d,...am(m.data,t.options)}),n._optimisticResults==="isRestoring"&&(d.fetchStatus="idle")}let{error:w,errorUpdatedAt:y,status:S}=d;x=d.data;let v=!1;if(n.placeholderData!==void 0&&x===void 0&&S==="pending"){let O;i!=null&&i.isPlaceholderData&&n.placeholderData===(o==null?void 0:o.placeholderData)?(O=i.data,v=!0):O=typeof n.placeholderData=="function"?n.placeholderData((F=g(this,Lr))==null?void 0:F.state.data,g(this,Lr)):n.placeholderData,O!==void 0&&(S="success",x=mo(i==null?void 0:i.data,O,n),h=!0)}if(n.select&&x!==void 0&&!v)if(i&&x===(l==null?void 0:l.data)&&n.select===g(this,Ys))x=g(this,Or);else try{z(this,Ys,n.select),x=n.select(x),x=mo(i==null?void 0:i.data,x,n),z(this,Or,x),z(this,nn,null)}catch(O){z(this,nn,O)}g(this,nn)&&(w=g(this,nn),x=g(this,Or),y=Date.now(),S="error");const f=d.fetchStatus==="fetching",p=S==="pending",j=S==="error",C=p&&f,N=x!==void 0,E={status:S,fetchStatus:d.fetchStatus,isPending:p,isSuccess:S==="success",isError:j,isInitialLoading:C,isLoading:C,data:x,dataUpdatedAt:d.dataUpdatedAt,error:w,errorUpdatedAt:y,failureCount:d.fetchFailureCount,failureReason:d.fetchFailureReason,errorUpdateCount:d.errorUpdateCount,isFetched:d.dataUpdateCount>0||d.errorUpdateCount>0,isFetchedAfterMount:d.dataUpdateCount>c.dataUpdateCount||d.errorUpdateCount>c.errorUpdateCount,isFetching:f,isRefetching:f&&!p,isLoadingError:j&&!N,isPaused:d.fetchStatus==="paused",isPlaceholderData:h,isRefetchError:j&&N,isStale:Mu(t,n),refetch:this.refetch,promise:g(this,Lt),isEnabled:nt(n.enabled,t)!==!1};if(this.options.experimental_prefetchInRender){const O=E.data!==void 0,Q=E.status==="error"&&!O,D=me=>{Q?me.reject(E.error):O&&me.resolve(E.data)},$=()=>{const me=z(this,Lt,E.promise=po());D(me)},te=g(this,Lt);switch(te.status){case"pending":t.queryHash===r.queryHash&&D(te);break;case"fulfilled":(Q||E.data!==te.value)&&$();break;case"rejected":(!Q||E.error!==te.reason)&&$();break}}return E}updateResult(){const t=g(this,Me),n=this.createResult(g(this,G),this.options);if(z(this,Bn,g(this,G).state),z(this,Tr,this.options),g(this,Bn).data!==void 0&&z(this,Lr,g(this,G)),da(n,t))return;z(this,Me,n);const r=()=>{if(!t)return!0;const{notifyOnChangeProps:s}=this.options,i=typeof s=="function"?s():s;if(i==="all"||!i&&!g(this,Rr).size)return!0;const l=new Set(i??g(this,Rr));return this.options.throwOnError&&l.add("error"),Object.keys(g(this,Me)).some(o=>{const u=o;return g(this,Me)[u]!==t[u]&&l.has(u)})};W(this,ee,lm).call(this,{listeners:r()})}onQueryUpdate(){this.updateResult(),this.hasListeners()&&W(this,ee,jo).call(this)}},$e=new WeakMap,G=new WeakMap,Gs=new WeakMap,Me=new WeakMap,Bn=new WeakMap,Tr=new WeakMap,Lt=new WeakMap,nn=new WeakMap,Ys=new WeakMap,Or=new WeakMap,Lr=new WeakMap,Qn=new WeakMap,Vn=new WeakMap,rn=new WeakMap,Rr=new WeakMap,ee=new WeakSet,hs=function(t){W(this,ee,So).call(this);let n=g(this,G).fetch(this.options,t);return t!=null&&t.throwOnError||(n=n.catch(Fe)),n},xo=function(){W(this,ee,wo).call(this);const t=kn(this.options.staleTime,g(this,G));if(er||g(this,Me).isStale||!fo(t))return;const r=em(g(this,Me).dataUpdatedAt,t)+1;z(this,Qn,Fn.setTimeout(()=>{g(this,Me).isStale||this.updateResult()},r))},go=function(){return(typeof this.options.refetchInterval=="function"?this.options.refetchInterval(g(this,G)):this.options.refetchInterval)??!1},yo=function(t){W(this,ee,ko).call(this),z(this,rn,t),!(er||nt(this.options.enabled,g(this,G))===!1||!fo(g(this,rn))||g(this,rn)===0)&&z(this,Vn,Fn.setInterval(()=>{(this.options.refetchIntervalInBackground||Ru.isFocused())&&W(this,ee,hs).call(this)},g(this,rn)))},jo=function(){W(this,ee,xo).call(this),W(this,ee,yo).call(this,W(this,ee,go).call(this))},wo=function(){g(this,Qn)&&(Fn.clearTimeout(g(this,Qn)),z(this,Qn,void 0))},ko=function(){g(this,Vn)&&(Fn.clearInterval(g(this,Vn)),z(this,Vn,void 0))},So=function(){const t=g(this,$e).getQueryCache().build(g(this,$e),this.options);if(t===g(this,G))return;const n=g(this,G);z(this,G,t),z(this,Gs,t.state),this.hasListeners()&&(n==null||n.removeObserver(this),t.addObserver(this))},lm=function(t){je.batch(()=>{t.listeners&&this.listeners.forEach(n=>{n(g(this,Me))}),g(this,$e).getQueryCache().notify({query:g(this,G),type:"observerResultsUpdated"})})},Md);function Mx(e,t){return nt(t.enabled,e)!==!1&&e.state.data===void 0&&!(e.state.status==="error"&&t.retryOnMount===!1)}function ad(e,t){return Mx(e,t)||e.state.data!==void 0&&No(e,t,t.refetchOnMount)}function No(e,t,n){if(nt(t.enabled,e)!==!1&&kn(t.staleTime,e)!=="static"){const r=typeof n=="function"?n(e):n;return r==="always"||r!==!1&&Mu(e,t)}return!1}function ld(e,t,n,r){return(e!==t||nt(r.enabled,e)===!1)&&(!n.suspense||e.state.status!=="error")&&Mu(e,n)}function Mu(e,t){return nt(t.enabled,e)!==!1&&e.isStaleByTime(kn(t.staleTime,e))}function zx(e,t){return!da(e.getCurrentResult(),t)}function od(e){return{onFetch:(t,n)=>{var m,d,h,x,w;const r=t.options,s=(h=(d=(m=t.fetchOptions)==null?void 0:m.meta)==null?void 0:d.fetchMore)==null?void 0:h.direction,i=((x=t.state.data)==null?void 0:x.pages)||[],l=((w=t.state.data)==null?void 0:w.pageParams)||[];let o={pages:[],pageParams:[]},u=0;const c=async()=>{let y=!1;const S=p=>{Cx(p,()=>t.signal,()=>y=!0)},v=nm(t.options,t.fetchOptions),f=async(p,j,C)=>{if(y)return Promise.reject();if(j==null&&p.pages.length)return Promise.resolve(p);const b=(()=>{const Q={client:t.client,queryKey:t.queryKey,pageParam:j,direction:C?"backward":"forward",meta:t.options.meta};return S(Q),Q})(),E=await v(b),{maxPages:F}=t.options,O=C?bx:Nx;return{pages:O(p.pages,E,F),pageParams:O(p.pageParams,j,F)}};if(s&&i.length){const p=s==="backward",j=p?Fx:ud,C={pages:i,pageParams:l},N=j(r,C);o=await f(C,N,p)}else{const p=e??i.length;do{const j=u===0?l[0]??r.initialPageParam:ud(r,o);if(u>0&&j==null)break;o=await f(o,j),u++}while(u{var y,S;return(S=(y=t.options).persister)==null?void 0:S.call(y,c,{client:t.client,queryKey:t.queryKey,meta:t.options.meta,signal:t.signal},n)}:t.fetchFn=c}}}function ud(e,{pages:t,pageParams:n}){const r=t.length-1;return t.length>0?e.getNextPageParam(t[r],t,n[r],n):void 0}function Fx(e,{pages:t,pageParams:n}){var r;return t.length>0?(r=e.getPreviousPageParam)==null?void 0:r.call(e,t[0],t,n[0],n):void 0}var Xs,wt,Oe,Kn,kt,qt,zd,Ix=(zd=class extends im{constructor(t){super();U(this,kt);U(this,Xs);U(this,wt);U(this,Oe);U(this,Kn);z(this,Xs,t.client),this.mutationId=t.mutationId,z(this,Oe,t.mutationCache),z(this,wt,[]),this.state=t.state||om(),this.setOptions(t.options),this.scheduleGc()}setOptions(t){this.options=t,this.updateGcTime(this.options.gcTime)}get meta(){return this.options.meta}addObserver(t){g(this,wt).includes(t)||(g(this,wt).push(t),this.clearGcTimeout(),g(this,Oe).notify({type:"observerAdded",mutation:this,observer:t}))}removeObserver(t){z(this,wt,g(this,wt).filter(n=>n!==t)),this.scheduleGc(),g(this,Oe).notify({type:"observerRemoved",mutation:this,observer:t})}optionalRemove(){g(this,wt).length||(this.state.status==="pending"?this.scheduleGc():g(this,Oe).remove(this))}continue(){var t;return((t=g(this,Kn))==null?void 0:t.continue())??this.execute(this.state.variables)}async execute(t){var l,o,u,c,m,d,h,x,w,y,S,v,f,p,j,C,N,b;const n=()=>{W(this,kt,qt).call(this,{type:"continue"})},r={client:g(this,Xs),meta:this.options.meta,mutationKey:this.options.mutationKey};z(this,Kn,sm({fn:()=>this.options.mutationFn?this.options.mutationFn(t,r):Promise.reject(new Error("No mutationFn found")),onFail:(E,F)=>{W(this,kt,qt).call(this,{type:"failed",failureCount:E,error:F})},onPause:()=>{W(this,kt,qt).call(this,{type:"pause"})},onContinue:n,retry:this.options.retry??0,retryDelay:this.options.retryDelay,networkMode:this.options.networkMode,canRun:()=>g(this,Oe).canRun(this)}));const s=this.state.status==="pending",i=!g(this,Kn).canStart();try{if(s)n();else{W(this,kt,qt).call(this,{type:"pending",variables:t,isPaused:i}),g(this,Oe).config.onMutate&&await g(this,Oe).config.onMutate(t,this,r);const F=await((o=(l=this.options).onMutate)==null?void 0:o.call(l,t,r));F!==this.state.context&&W(this,kt,qt).call(this,{type:"pending",context:F,variables:t,isPaused:i})}const E=await g(this,Kn).start();return await((c=(u=g(this,Oe).config).onSuccess)==null?void 0:c.call(u,E,t,this.state.context,this,r)),await((d=(m=this.options).onSuccess)==null?void 0:d.call(m,E,t,this.state.context,r)),await((x=(h=g(this,Oe).config).onSettled)==null?void 0:x.call(h,E,null,this.state.variables,this.state.context,this,r)),await((y=(w=this.options).onSettled)==null?void 0:y.call(w,E,null,t,this.state.context,r)),W(this,kt,qt).call(this,{type:"success",data:E}),E}catch(E){try{await((v=(S=g(this,Oe).config).onError)==null?void 0:v.call(S,E,t,this.state.context,this,r))}catch(F){Promise.reject(F)}try{await((p=(f=this.options).onError)==null?void 0:p.call(f,E,t,this.state.context,r))}catch(F){Promise.reject(F)}try{await((C=(j=g(this,Oe).config).onSettled)==null?void 0:C.call(j,void 0,E,this.state.variables,this.state.context,this,r))}catch(F){Promise.reject(F)}try{await((b=(N=this.options).onSettled)==null?void 0:b.call(N,void 0,E,t,this.state.context,r))}catch(F){Promise.reject(F)}throw W(this,kt,qt).call(this,{type:"error",error:E}),E}finally{g(this,Oe).runNext(this)}}},Xs=new WeakMap,wt=new WeakMap,Oe=new WeakMap,Kn=new WeakMap,kt=new WeakSet,qt=function(t){const n=r=>{switch(t.type){case"failed":return{...r,failureCount:t.failureCount,failureReason:t.error};case"pause":return{...r,isPaused:!0};case"continue":return{...r,isPaused:!1};case"pending":return{...r,context:t.context,data:void 0,failureCount:0,failureReason:null,error:null,isPaused:t.isPaused,status:"pending",variables:t.variables,submittedAt:Date.now()};case"success":return{...r,data:t.data,failureCount:0,failureReason:null,error:null,status:"success",isPaused:!1};case"error":return{...r,data:void 0,error:t.error,failureCount:r.failureCount+1,failureReason:t.error,isPaused:!1,status:"error"}}};this.state=n(this.state),je.batch(()=>{g(this,wt).forEach(r=>{r.onMutationUpdate(t)}),g(this,Oe).notify({mutation:this,type:"updated",action:t})})},zd);function om(){return{context:void 0,data:void 0,error:null,failureCount:0,failureReason:null,isPaused:!1,status:"idle",variables:void 0,submittedAt:0}}var Rt,ft,Zs,Fd,Dx=(Fd=class extends Gr{constructor(t={}){super();U(this,Rt);U(this,ft);U(this,Zs);this.config=t,z(this,Rt,new Set),z(this,ft,new Map),z(this,Zs,0)}build(t,n,r){const s=new Ix({client:t,mutationCache:this,mutationId:++li(this,Zs)._,options:t.defaultMutationOptions(n),state:r});return this.add(s),s}add(t){g(this,Rt).add(t);const n=bi(t);if(typeof n=="string"){const r=g(this,ft).get(n);r?r.push(t):g(this,ft).set(n,[t])}this.notify({type:"added",mutation:t})}remove(t){if(g(this,Rt).delete(t)){const n=bi(t);if(typeof n=="string"){const r=g(this,ft).get(n);if(r)if(r.length>1){const s=r.indexOf(t);s!==-1&&r.splice(s,1)}else r[0]===t&&g(this,ft).delete(n)}}this.notify({type:"removed",mutation:t})}canRun(t){const n=bi(t);if(typeof n=="string"){const r=g(this,ft).get(n),s=r==null?void 0:r.find(i=>i.state.status==="pending");return!s||s===t}else return!0}runNext(t){var r;const n=bi(t);if(typeof n=="string"){const s=(r=g(this,ft).get(n))==null?void 0:r.find(i=>i!==t&&i.state.isPaused);return(s==null?void 0:s.continue())??Promise.resolve()}else return Promise.resolve()}clear(){je.batch(()=>{g(this,Rt).forEach(t=>{this.notify({type:"removed",mutation:t})}),g(this,Rt).clear(),g(this,ft).clear()})}getAll(){return Array.from(g(this,Rt))}find(t){const n={exact:!0,...t};return this.getAll().find(r=>td(n,r))}findAll(t={}){return this.getAll().filter(n=>td(t,n))}notify(t){je.batch(()=>{this.listeners.forEach(n=>{n(t)})})}resumePausedMutations(){const t=this.getAll().filter(n=>n.state.isPaused);return je.batch(()=>Promise.all(t.map(n=>n.continue().catch(Fe))))}},Rt=new WeakMap,ft=new WeakMap,Zs=new WeakMap,Fd);function bi(e){var t;return(t=e.options.scope)==null?void 0:t.id}var Mt,sn,Ue,zt,$t,$i,bo,Id,Ax=(Id=class extends Gr{constructor(n,r){super();U(this,$t);U(this,Mt);U(this,sn);U(this,Ue);U(this,zt);z(this,Mt,n),this.setOptions(r),this.bindMethods(),W(this,$t,$i).call(this)}bindMethods(){this.mutate=this.mutate.bind(this),this.reset=this.reset.bind(this)}setOptions(n){var s;const r=this.options;this.options=g(this,Mt).defaultMutationOptions(n),da(this.options,r)||g(this,Mt).getMutationCache().notify({type:"observerOptionsUpdated",mutation:g(this,Ue),observer:this}),r!=null&&r.mutationKey&&this.options.mutationKey&&tr(r.mutationKey)!==tr(this.options.mutationKey)?this.reset():((s=g(this,Ue))==null?void 0:s.state.status)==="pending"&&g(this,Ue).setOptions(this.options)}onUnsubscribe(){var n;this.hasListeners()||(n=g(this,Ue))==null||n.removeObserver(this)}onMutationUpdate(n){W(this,$t,$i).call(this),W(this,$t,bo).call(this,n)}getCurrentResult(){return g(this,sn)}reset(){var n;(n=g(this,Ue))==null||n.removeObserver(this),z(this,Ue,void 0),W(this,$t,$i).call(this),W(this,$t,bo).call(this)}mutate(n,r){var s;return z(this,zt,r),(s=g(this,Ue))==null||s.removeObserver(this),z(this,Ue,g(this,Mt).getMutationCache().build(g(this,Mt),this.options)),g(this,Ue).addObserver(this),g(this,Ue).execute(n)}},Mt=new WeakMap,sn=new WeakMap,Ue=new WeakMap,zt=new WeakMap,$t=new WeakSet,$i=function(){var r;const n=((r=g(this,Ue))==null?void 0:r.state)??om();z(this,sn,{...n,isPending:n.status==="pending",isSuccess:n.status==="success",isError:n.status==="error",isIdle:n.status==="idle",mutate:this.mutate,reset:this.reset})},bo=function(n){je.batch(()=>{var r,s,i,l,o,u,c,m;if(g(this,zt)&&this.hasListeners()){const d=g(this,sn).variables,h=g(this,sn).context,x={client:g(this,Mt),meta:this.options.meta,mutationKey:this.options.mutationKey};if((n==null?void 0:n.type)==="success"){try{(s=(r=g(this,zt)).onSuccess)==null||s.call(r,n.data,d,h,x)}catch(w){Promise.reject(w)}try{(l=(i=g(this,zt)).onSettled)==null||l.call(i,n.data,null,d,h,x)}catch(w){Promise.reject(w)}}else if((n==null?void 0:n.type)==="error"){try{(u=(o=g(this,zt)).onError)==null||u.call(o,n.error,d,h,x)}catch(w){Promise.reject(w)}try{(m=(c=g(this,zt)).onSettled)==null||m.call(c,void 0,n.error,d,h,x)}catch(w){Promise.reject(w)}}}this.listeners.forEach(d=>{d(g(this,sn))})})},Id),St,Dd,$x=(Dd=class extends Gr{constructor(t={}){super();U(this,St);this.config=t,z(this,St,new Map)}build(t,n,r){const s=n.queryKey,i=n.queryHash??Tu(s,n);let l=this.get(i);return l||(l=new Lx({client:t,queryKey:s,queryHash:i,options:t.defaultQueryOptions(n),state:r,defaultOptions:t.getQueryDefaults(s)}),this.add(l)),l}add(t){g(this,St).has(t.queryHash)||(g(this,St).set(t.queryHash,t),this.notify({type:"added",query:t}))}remove(t){const n=g(this,St).get(t.queryHash);n&&(t.destroy(),n===t&&g(this,St).delete(t.queryHash),this.notify({type:"removed",query:t}))}clear(){je.batch(()=>{this.getAll().forEach(t=>{this.remove(t)})})}get(t){return g(this,St).get(t)}getAll(){return[...g(this,St).values()]}find(t){const n={exact:!0,...t};return this.getAll().find(r=>ed(n,r))}findAll(t={}){const n=this.getAll();return Object.keys(t).length>0?n.filter(r=>ed(t,r)):n}notify(t){je.batch(()=>{this.listeners.forEach(n=>{n(t)})})}onFocus(){je.batch(()=>{this.getAll().forEach(t=>{t.onFocus()})})}onOnline(){je.batch(()=>{this.getAll().forEach(t=>{t.onOnline()})})}},St=new WeakMap,Dd),de,an,ln,Mr,zr,on,Fr,Ir,Ad,Ux=(Ad=class{constructor(e={}){U(this,de);U(this,an);U(this,ln);U(this,Mr);U(this,zr);U(this,on);U(this,Fr);U(this,Ir);z(this,de,e.queryCache||new $x),z(this,an,e.mutationCache||new Dx),z(this,ln,e.defaultOptions||{}),z(this,Mr,new Map),z(this,zr,new Map),z(this,on,0)}mount(){li(this,on)._++,g(this,on)===1&&(z(this,Fr,Ru.subscribe(async e=>{e&&(await this.resumePausedMutations(),g(this,de).onFocus())})),z(this,Ir,fa.subscribe(async e=>{e&&(await this.resumePausedMutations(),g(this,de).onOnline())})))}unmount(){var e,t;li(this,on)._--,g(this,on)===0&&((e=g(this,Fr))==null||e.call(this),z(this,Fr,void 0),(t=g(this,Ir))==null||t.call(this),z(this,Ir,void 0))}isFetching(e){return g(this,de).findAll({...e,fetchStatus:"fetching"}).length}isMutating(e){return g(this,an).findAll({...e,status:"pending"}).length}getQueryData(e){var n;const t=this.defaultQueryOptions({queryKey:e});return(n=g(this,de).get(t.queryHash))==null?void 0:n.state.data}ensureQueryData(e){const t=this.defaultQueryOptions(e),n=g(this,de).build(this,t),r=n.state.data;return r===void 0?this.fetchQuery(e):(e.revalidateIfStale&&n.isStaleByTime(kn(t.staleTime,n))&&this.prefetchQuery(t),Promise.resolve(r))}getQueriesData(e){return g(this,de).findAll(e).map(({queryKey:t,state:n})=>{const r=n.data;return[t,r]})}setQueryData(e,t,n){const r=this.defaultQueryOptions({queryKey:e}),s=g(this,de).get(r.queryHash),i=s==null?void 0:s.state.data,l=wx(t,i);if(l!==void 0)return g(this,de).build(this,r).setData(l,{...n,manual:!0})}setQueriesData(e,t,n){return je.batch(()=>g(this,de).findAll(e).map(({queryKey:r})=>[r,this.setQueryData(r,t,n)]))}getQueryState(e){var n;const t=this.defaultQueryOptions({queryKey:e});return(n=g(this,de).get(t.queryHash))==null?void 0:n.state}removeQueries(e){const t=g(this,de);je.batch(()=>{t.findAll(e).forEach(n=>{t.remove(n)})})}resetQueries(e,t){const n=g(this,de);return je.batch(()=>(n.findAll(e).forEach(r=>{r.reset()}),this.refetchQueries({type:"active",...e},t)))}cancelQueries(e,t={}){const n={revert:!0,...t},r=je.batch(()=>g(this,de).findAll(e).map(s=>s.cancel(n)));return Promise.all(r).then(Fe).catch(Fe)}invalidateQueries(e,t={}){return je.batch(()=>(g(this,de).findAll(e).forEach(n=>{n.invalidate()}),(e==null?void 0:e.refetchType)==="none"?Promise.resolve():this.refetchQueries({...e,type:(e==null?void 0:e.refetchType)??(e==null?void 0:e.type)??"active"},t)))}refetchQueries(e,t={}){const n={...t,cancelRefetch:t.cancelRefetch??!0},r=je.batch(()=>g(this,de).findAll(e).filter(s=>!s.isDisabled()&&!s.isStatic()).map(s=>{let i=s.fetch(void 0,n);return n.throwOnError||(i=i.catch(Fe)),s.state.fetchStatus==="paused"?Promise.resolve():i}));return Promise.all(r).then(Fe)}fetchQuery(e){const t=this.defaultQueryOptions(e);t.retry===void 0&&(t.retry=!1);const n=g(this,de).build(this,t);return n.isStaleByTime(kn(t.staleTime,n))?n.fetch(t):Promise.resolve(n.state.data)}prefetchQuery(e){return this.fetchQuery(e).then(Fe).catch(Fe)}fetchInfiniteQuery(e){return e.behavior=od(e.pages),this.fetchQuery(e)}prefetchInfiniteQuery(e){return this.fetchInfiniteQuery(e).then(Fe).catch(Fe)}ensureInfiniteQueryData(e){return e.behavior=od(e.pages),this.ensureQueryData(e)}resumePausedMutations(){return fa.isOnline()?g(this,an).resumePausedMutations():Promise.resolve()}getQueryCache(){return g(this,de)}getMutationCache(){return g(this,an)}getDefaultOptions(){return g(this,ln)}setDefaultOptions(e){z(this,ln,e)}setQueryDefaults(e,t){g(this,Mr).set(tr(e),{queryKey:e,defaultOptions:t})}getQueryDefaults(e){const t=[...g(this,Mr).values()],n={};return t.forEach(r=>{Bs(e,r.queryKey)&&Object.assign(n,r.defaultOptions)}),n}setMutationDefaults(e,t){g(this,zr).set(tr(e),{mutationKey:e,defaultOptions:t})}getMutationDefaults(e){const t=[...g(this,zr).values()],n={};return t.forEach(r=>{Bs(e,r.mutationKey)&&Object.assign(n,r.defaultOptions)}),n}defaultQueryOptions(e){if(e._defaulted)return e;const t={...g(this,ln).queries,...this.getQueryDefaults(e.queryKey),...e,_defaulted:!0};return t.queryHash||(t.queryHash=Tu(t.queryKey,t)),t.refetchOnReconnect===void 0&&(t.refetchOnReconnect=t.networkMode!=="always"),t.throwOnError===void 0&&(t.throwOnError=!!t.suspense),!t.networkMode&&t.persister&&(t.networkMode="offlineFirst"),t.queryFn===Ou&&(t.enabled=!1),t}defaultMutationOptions(e){return e!=null&&e._defaulted?e:{...g(this,ln).mutations,...(e==null?void 0:e.mutationKey)&&this.getMutationDefaults(e.mutationKey),...e,_defaulted:!0}}clear(){g(this,de).clear(),g(this,an).clear()}},de=new WeakMap,an=new WeakMap,ln=new WeakMap,Mr=new WeakMap,zr=new WeakMap,on=new WeakMap,Fr=new WeakMap,Ir=new WeakMap,Ad),um=k.createContext(void 0),Pn=e=>{const t=k.useContext(um);if(!t)throw new Error("No QueryClient set, use QueryClientProvider to set one");return t},Bx=({client:e,children:t})=>(k.useEffect(()=>(e.mount(),()=>{e.unmount()}),[e]),a.jsx(um.Provider,{value:e,children:t})),cm=k.createContext(!1),Qx=()=>k.useContext(cm);cm.Provider;function Vx(){let e=!1;return{clearReset:()=>{e=!1},reset:()=>{e=!0},isReset:()=>e}}var Kx=k.createContext(Vx()),Hx=()=>k.useContext(Kx),Wx=(e,t,n)=>{const r=n!=null&&n.state.error&&typeof e.throwOnError=="function"?Lu(e.throwOnError,[n.state.error,n]):e.throwOnError;(e.suspense||e.experimental_prefetchInRender||r)&&(t.isReset()||(e.retryOnMount=!1))},qx=e=>{k.useEffect(()=>{e.clearReset()},[e])},Jx=({result:e,errorResetBoundary:t,throwOnError:n,query:r,suspense:s})=>e.isError&&!t.isReset()&&!e.isFetching&&r&&(s&&e.data===void 0||Lu(n,[e.error,r])),Gx=e=>{if(e.suspense){const n=s=>s==="static"?s:Math.max(s??1e3,1e3),r=e.staleTime;e.staleTime=typeof r=="function"?(...s)=>n(r(...s)):n(r),typeof e.gcTime=="number"&&(e.gcTime=Math.max(e.gcTime,1e3))}},Yx=(e,t)=>e.isLoading&&e.isFetching&&!t,Xx=(e,t)=>(e==null?void 0:e.suspense)&&t.isPending,cd=(e,t,n)=>t.fetchOptimistic(e).catch(()=>{n.clearReset()});function Zx(e,t,n){var h,x,w,y;const r=Qx(),s=Hx(),i=Pn(),l=i.defaultQueryOptions(e);(x=(h=i.getDefaultOptions().queries)==null?void 0:h._experimental_beforeQuery)==null||x.call(h,l);const o=i.getQueryCache().get(l.queryHash);l._optimisticResults=r?"isRestoring":"optimistic",Gx(l),Wx(l,s,o),qx(s);const u=!i.getQueryCache().get(l.queryHash),[c]=k.useState(()=>new t(i,l)),m=c.getOptimisticResult(l),d=!r&&e.subscribed!==!1;if(k.useSyncExternalStore(k.useCallback(S=>{const v=d?c.subscribe(je.batchCalls(S)):Fe;return c.updateResult(),v},[c,d]),()=>c.getCurrentResult(),()=>c.getCurrentResult()),k.useEffect(()=>{c.setOptions(l)},[l,c]),Xx(l,m))throw cd(l,c,s);if(Jx({result:m,errorResetBoundary:s,throwOnError:l.throwOnError,query:o,suspense:l.suspense}))throw m.error;if((y=(w=i.getDefaultOptions().queries)==null?void 0:w._experimental_afterQuery)==null||y.call(w,l,m),l.experimental_prefetchInRender&&!er&&Yx(m,r)){const S=u?cd(l,c,s):o==null?void 0:o.promise;S==null||S.catch(Fe).finally(()=>{c.updateResult()})}return l.notifyOnChangeProps?m:c.trackResult(m)}function ve(e,t){return Zx(e,Rx)}function Ge(e,t){const n=Pn(),[r]=k.useState(()=>new Ax(n,e));k.useEffect(()=>{r.setOptions(e)},[r,e]);const s=k.useSyncExternalStore(k.useCallback(l=>r.subscribe(je.batchCalls(l)),[r]),()=>r.getCurrentResult(),()=>r.getCurrentResult()),i=k.useCallback((l,o)=>{r.mutate(l,o).catch(Fe)},[r]);if(s.error&&Lu(r.options.throwOnError,[s.error]))throw s.error;return{...s,mutate:i,mutateAsync:s.mutate}}/** + * @remix-run/router v1.23.2 + * + * Copyright (c) Remix Software Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE.md file in the root directory of this source tree. + * + * @license MIT + */function Qs(){return Qs=Object.assign?Object.assign.bind():function(e){for(var t=1;t"u")throw new Error(t)}function zu(e,t){if(!e){typeof console<"u"&&console.warn(t);try{throw new Error(t)}catch{}}}function tg(){return Math.random().toString(36).substr(2,8)}function fd(e,t){return{usr:e.state,key:e.key,idx:t}}function Co(e,t,n,r){return n===void 0&&(n=null),Qs({pathname:typeof e=="string"?e:e.pathname,search:"",hash:""},typeof t=="string"?Yr(t):t,{state:n,key:t&&t.key||r||tg()})}function ha(e){let{pathname:t="/",search:n="",hash:r=""}=e;return n&&n!=="?"&&(t+=n.charAt(0)==="?"?n:"?"+n),r&&r!=="#"&&(t+=r.charAt(0)==="#"?r:"#"+r),t}function Yr(e){let t={};if(e){let n=e.indexOf("#");n>=0&&(t.hash=e.substr(n),e=e.substr(0,n));let r=e.indexOf("?");r>=0&&(t.search=e.substr(r),e=e.substr(0,r)),e&&(t.pathname=e)}return t}function ng(e,t,n,r){r===void 0&&(r={});let{window:s=document.defaultView,v5Compat:i=!1}=r,l=s.history,o=dn.Pop,u=null,c=m();c==null&&(c=0,l.replaceState(Qs({},l.state,{idx:c}),""));function m(){return(l.state||{idx:null}).idx}function d(){o=dn.Pop;let S=m(),v=S==null?null:S-c;c=S,u&&u({action:o,location:y.location,delta:v})}function h(S,v){o=dn.Push;let f=Co(y.location,S,v);c=m()+1;let p=fd(f,c),j=y.createHref(f);try{l.pushState(p,"",j)}catch(C){if(C instanceof DOMException&&C.name==="DataCloneError")throw C;s.location.assign(j)}i&&u&&u({action:o,location:y.location,delta:1})}function x(S,v){o=dn.Replace;let f=Co(y.location,S,v);c=m();let p=fd(f,c),j=y.createHref(f);l.replaceState(p,"",j),i&&u&&u({action:o,location:y.location,delta:0})}function w(S){let v=s.location.origin!=="null"?s.location.origin:s.location.href,f=typeof S=="string"?S:ha(S);return f=f.replace(/ $/,"%20"),he(v,"No window.location.(origin|href) available to create URL for href: "+f),new URL(f,v)}let y={get action(){return o},get location(){return e(s,l)},listen(S){if(u)throw new Error("A history only accepts one active listener");return s.addEventListener(dd,d),u=S,()=>{s.removeEventListener(dd,d),u=null}},createHref(S){return t(s,S)},createURL:w,encodeLocation(S){let v=w(S);return{pathname:v.pathname,search:v.search,hash:v.hash}},push:h,replace:x,go(S){return l.go(S)}};return y}var hd;(function(e){e.data="data",e.deferred="deferred",e.redirect="redirect",e.error="error"})(hd||(hd={}));function rg(e,t,n){return n===void 0&&(n="/"),sg(e,t,n)}function sg(e,t,n,r){let s=typeof t=="string"?Yr(t):t,i=Kr(s.pathname||"/",n);if(i==null)return null;let l=dm(e);ig(l);let o=null;for(let u=0;o==null&&u{let u={relativePath:o===void 0?i.path||"":o,caseSensitive:i.caseSensitive===!0,childrenIndex:l,route:i};u.relativePath.startsWith("/")&&(he(u.relativePath.startsWith(r),'Absolute route path "'+u.relativePath+'" nested under path '+('"'+r+'" is not valid. An absolute child route path ')+"must start with the combined path of all its parent routes."),u.relativePath=u.relativePath.slice(r.length));let c=Sn([r,u.relativePath]),m=n.concat(u);i.children&&i.children.length>0&&(he(i.index!==!0,"Index routes must not have child routes. Please remove "+('all child routes from route path "'+c+'".')),dm(i.children,t,m,c)),!(i.path==null&&!i.index)&&t.push({path:c,score:fg(c,i.index),routesMeta:m})};return e.forEach((i,l)=>{var o;if(i.path===""||!((o=i.path)!=null&&o.includes("?")))s(i,l);else for(let u of fm(i.path))s(i,l,u)}),t}function fm(e){let t=e.split("/");if(t.length===0)return[];let[n,...r]=t,s=n.endsWith("?"),i=n.replace(/\?$/,"");if(r.length===0)return s?[i,""]:[i];let l=fm(r.join("/")),o=[];return o.push(...l.map(u=>u===""?i:[i,u].join("/"))),s&&o.push(...l),o.map(u=>e.startsWith("/")&&u===""?"/":u)}function ig(e){e.sort((t,n)=>t.score!==n.score?n.score-t.score:hg(t.routesMeta.map(r=>r.childrenIndex),n.routesMeta.map(r=>r.childrenIndex)))}const ag=/^:[\w-]+$/,lg=3,og=2,ug=1,cg=10,dg=-2,md=e=>e==="*";function fg(e,t){let n=e.split("/"),r=n.length;return n.some(md)&&(r+=dg),t&&(r+=og),n.filter(s=>!md(s)).reduce((s,i)=>s+(ag.test(i)?lg:i===""?ug:cg),r)}function hg(e,t){return e.length===t.length&&e.slice(0,-1).every((r,s)=>r===t[s])?e[e.length-1]-t[t.length-1]:0}function mg(e,t,n){let{routesMeta:r}=e,s={},i="/",l=[];for(let o=0;o{let{paramName:h,isOptional:x}=m;if(h==="*"){let y=o[d]||"";l=i.slice(0,i.length-y.length).replace(/(.)\/+$/,"$1")}const w=o[d];return x&&!w?c[h]=void 0:c[h]=(w||"").replace(/%2F/g,"/"),c},{}),pathname:i,pathnameBase:l,pattern:e}}function pg(e,t,n){t===void 0&&(t=!1),n===void 0&&(n=!0),zu(e==="*"||!e.endsWith("*")||e.endsWith("/*"),'Route path "'+e+'" will be treated as if it were '+('"'+e.replace(/\*$/,"/*")+'" because the `*` character must ')+"always follow a `/` in the pattern. To get rid of this warning, "+('please change the route path to "'+e.replace(/\*$/,"/*")+'".'));let r=[],s="^"+e.replace(/\/*\*?$/,"").replace(/^\/*/,"/").replace(/[\\.*+^${}|()[\]]/g,"\\$&").replace(/\/:([\w-]+)(\?)?/g,(l,o,u)=>(r.push({paramName:o,isOptional:u!=null}),u?"/?([^\\/]+)?":"/([^\\/]+)"));return e.endsWith("*")?(r.push({paramName:"*"}),s+=e==="*"||e==="/*"?"(.*)$":"(?:\\/(.+)|\\/*)$"):n?s+="\\/*$":e!==""&&e!=="/"&&(s+="(?:(?=\\/|$))"),[new RegExp(s,t?void 0:"i"),r]}function vg(e){try{return e.split("/").map(t=>decodeURIComponent(t).replace(/\//g,"%2F")).join("/")}catch(t){return zu(!1,'The URL path "'+e+'" could not be decoded because it is is a malformed URL segment. This is probably due to a bad percent '+("encoding ("+t+").")),e}}function Kr(e,t){if(t==="/")return e;if(!e.toLowerCase().startsWith(t.toLowerCase()))return null;let n=t.endsWith("/")?t.length-1:t.length,r=e.charAt(n);return r&&r!=="/"?null:e.slice(n)||"/"}const xg=/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i,gg=e=>xg.test(e);function yg(e,t){t===void 0&&(t="/");let{pathname:n,search:r="",hash:s=""}=typeof e=="string"?Yr(e):e,i;if(n)if(gg(n))i=n;else{if(n.includes("//")){let l=n;n=n.replace(/\/\/+/g,"/"),zu(!1,"Pathnames cannot have embedded double slashes - normalizing "+(l+" -> "+n))}n.startsWith("/")?i=pd(n.substring(1),"/"):i=pd(n,t)}else i=t;return{pathname:i,search:kg(r),hash:Sg(s)}}function pd(e,t){let n=t.replace(/\/+$/,"").split("/");return e.split("/").forEach(s=>{s===".."?n.length>1&&n.pop():s!=="."&&n.push(s)}),n.length>1?n.join("/"):"/"}function ml(e,t,n,r){return"Cannot include a '"+e+"' character in a manually specified "+("`to."+t+"` field ["+JSON.stringify(r)+"]. Please separate it out to the ")+("`to."+n+"` field. Alternatively you may provide the full path as ")+'a string in and the router will parse it for you.'}function jg(e){return e.filter((t,n)=>n===0||t.route.path&&t.route.path.length>0)}function hm(e,t){let n=jg(e);return t?n.map((r,s)=>s===n.length-1?r.pathname:r.pathnameBase):n.map(r=>r.pathnameBase)}function mm(e,t,n,r){r===void 0&&(r=!1);let s;typeof e=="string"?s=Yr(e):(s=Qs({},e),he(!s.pathname||!s.pathname.includes("?"),ml("?","pathname","search",s)),he(!s.pathname||!s.pathname.includes("#"),ml("#","pathname","hash",s)),he(!s.search||!s.search.includes("#"),ml("#","search","hash",s)));let i=e===""||s.pathname==="",l=i?"/":s.pathname,o;if(l==null)o=n;else{let d=t.length-1;if(!r&&l.startsWith("..")){let h=l.split("/");for(;h[0]==="..";)h.shift(),d-=1;s.pathname=h.join("/")}o=d>=0?t[d]:"/"}let u=yg(s,o),c=l&&l!=="/"&&l.endsWith("/"),m=(i||l===".")&&n.endsWith("/");return!u.pathname.endsWith("/")&&(c||m)&&(u.pathname+="/"),u}const Sn=e=>e.join("/").replace(/\/\/+/g,"/"),wg=e=>e.replace(/\/+$/,"").replace(/^\/*/,"/"),kg=e=>!e||e==="?"?"":e.startsWith("?")?e:"?"+e,Sg=e=>!e||e==="#"?"":e.startsWith("#")?e:"#"+e;function Ng(e){return e!=null&&typeof e.status=="number"&&typeof e.statusText=="string"&&typeof e.internal=="boolean"&&"data"in e}const pm=["post","put","patch","delete"];new Set(pm);const bg=["get",...pm];new Set(bg);/** + * React Router v6.30.3 + * + * Copyright (c) Remix Software Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE.md file in the root directory of this source tree. + * + * @license MIT + */function Vs(){return Vs=Object.assign?Object.assign.bind():function(e){for(var t=1;t{o.current=!0}),k.useCallback(function(c,m){if(m===void 0&&(m={}),!o.current)return;if(typeof c=="number"){r.go(c);return}let d=mm(c,JSON.parse(l),i,m.relative==="path");e==null&&t!=="/"&&(d.pathname=d.pathname==="/"?t:Sn([t,d.pathname])),(m.replace?r.replace:r.push)(d,m.state,m)},[t,r,l,i,e])}const Eg=k.createContext(null);function Pg(e){let t=k.useContext(Ht).outlet;return t&&k.createElement(Eg.Provider,{value:e},t)}function Ra(){let{matches:e}=k.useContext(Ht),t=e[e.length-1];return t?t.params:{}}function Ma(e,t){let{relative:n}=t===void 0?{}:t,{future:r}=k.useContext(Tn),{matches:s}=k.useContext(Ht),{pathname:i}=Xr(),l=JSON.stringify(hm(s,r.v7_relativeSplatPath));return k.useMemo(()=>mm(e,JSON.parse(l),i,n==="path"),[e,l,i,n])}function Tg(e,t){return Og(e,t)}function Og(e,t,n,r){ii()||he(!1);let{navigator:s}=k.useContext(Tn),{matches:i}=k.useContext(Ht),l=i[i.length-1],o=l?l.params:{};l&&l.pathname;let u=l?l.pathnameBase:"/";l&&l.route;let c=Xr(),m;if(t){var d;let S=typeof t=="string"?Yr(t):t;u==="/"||(d=S.pathname)!=null&&d.startsWith(u)||he(!1),m=S}else m=c;let h=m.pathname||"/",x=h;if(u!=="/"){let S=u.replace(/^\//,"").split("/");x="/"+h.replace(/^\//,"").split("/").slice(S.length).join("/")}let w=rg(e,{pathname:x}),y=Fg(w&&w.map(S=>Object.assign({},S,{params:Object.assign({},o,S.params),pathname:Sn([u,s.encodeLocation?s.encodeLocation(S.pathname).pathname:S.pathname]),pathnameBase:S.pathnameBase==="/"?u:Sn([u,s.encodeLocation?s.encodeLocation(S.pathnameBase).pathname:S.pathnameBase])})),i,n,r);return t&&y?k.createElement(La.Provider,{value:{location:Vs({pathname:"/",search:"",hash:"",state:null,key:"default"},m),navigationType:dn.Pop}},y):y}function Lg(){let e=$g(),t=Ng(e)?e.status+" "+e.statusText:e instanceof Error?e.message:JSON.stringify(e),n=e instanceof Error?e.stack:null,s={padding:"0.5rem",backgroundColor:"rgba(200,200,200, 0.5)"};return k.createElement(k.Fragment,null,k.createElement("h2",null,"Unexpected Application Error!"),k.createElement("h3",{style:{fontStyle:"italic"}},t),n?k.createElement("pre",{style:s},n):null,null)}const Rg=k.createElement(Lg,null);class Mg extends k.Component{constructor(t){super(t),this.state={location:t.location,revalidation:t.revalidation,error:t.error}}static getDerivedStateFromError(t){return{error:t}}static getDerivedStateFromProps(t,n){return n.location!==t.location||n.revalidation!=="idle"&&t.revalidation==="idle"?{error:t.error,location:t.location,revalidation:t.revalidation}:{error:t.error!==void 0?t.error:n.error,location:n.location,revalidation:t.revalidation||n.revalidation}}componentDidCatch(t,n){console.error("React Router caught the following error during render",t,n)}render(){return this.state.error!==void 0?k.createElement(Ht.Provider,{value:this.props.routeContext},k.createElement(xm.Provider,{value:this.state.error,children:this.props.component})):this.props.children}}function zg(e){let{routeContext:t,match:n,children:r}=e,s=k.useContext(Oa);return s&&s.static&&s.staticContext&&(n.route.errorElement||n.route.ErrorBoundary)&&(s.staticContext._deepestRenderedBoundaryId=n.route.id),k.createElement(Ht.Provider,{value:t},r)}function Fg(e,t,n,r){var s;if(t===void 0&&(t=[]),n===void 0&&(n=null),r===void 0&&(r=null),e==null){var i;if(!n)return null;if(n.errors)e=n.matches;else if((i=r)!=null&&i.v7_partialHydration&&t.length===0&&!n.initialized&&n.matches.length>0)e=n.matches;else return null}let l=e,o=(s=n)==null?void 0:s.errors;if(o!=null){let m=l.findIndex(d=>d.route.id&&(o==null?void 0:o[d.route.id])!==void 0);m>=0||he(!1),l=l.slice(0,Math.min(l.length,m+1))}let u=!1,c=-1;if(n&&r&&r.v7_partialHydration)for(let m=0;m=0?l=l.slice(0,c+1):l=[l[0]];break}}}return l.reduceRight((m,d,h)=>{let x,w=!1,y=null,S=null;n&&(x=o&&d.route.id?o[d.route.id]:void 0,y=d.route.errorElement||Rg,u&&(c<0&&h===0?(Bg("route-fallback"),w=!0,S=null):c===h&&(w=!0,S=d.route.hydrateFallbackElement||null)));let v=t.concat(l.slice(0,h+1)),f=()=>{let p;return x?p=y:w?p=S:d.route.Component?p=k.createElement(d.route.Component,null):d.route.element?p=d.route.element:p=m,k.createElement(zg,{match:d,routeContext:{outlet:m,matches:v,isDataRoute:n!=null},children:p})};return n&&(d.route.ErrorBoundary||d.route.errorElement||h===0)?k.createElement(Mg,{location:n.location,revalidation:n.revalidation,component:y,error:x,children:f(),routeContext:{outlet:null,matches:v,isDataRoute:!0}}):f()},null)}var ym=function(e){return e.UseBlocker="useBlocker",e.UseRevalidator="useRevalidator",e.UseNavigateStable="useNavigate",e}(ym||{}),jm=function(e){return e.UseBlocker="useBlocker",e.UseLoaderData="useLoaderData",e.UseActionData="useActionData",e.UseRouteError="useRouteError",e.UseNavigation="useNavigation",e.UseRouteLoaderData="useRouteLoaderData",e.UseMatches="useMatches",e.UseRevalidator="useRevalidator",e.UseNavigateStable="useNavigate",e.UseRouteId="useRouteId",e}(jm||{});function Ig(e){let t=k.useContext(Oa);return t||he(!1),t}function Dg(e){let t=k.useContext(vm);return t||he(!1),t}function Ag(e){let t=k.useContext(Ht);return t||he(!1),t}function wm(e){let t=Ag(),n=t.matches[t.matches.length-1];return n.route.id||he(!1),n.route.id}function $g(){var e;let t=k.useContext(xm),n=Dg(),r=wm();return t!==void 0?t:(e=n.errors)==null?void 0:e[r]}function Ug(){let{router:e}=Ig(ym.UseNavigateStable),t=wm(jm.UseNavigateStable),n=k.useRef(!1);return gm(()=>{n.current=!0}),k.useCallback(function(s,i){i===void 0&&(i={}),n.current&&(typeof s=="number"?e.navigate(s):e.navigate(s,Vs({fromRouteId:t},i)))},[e,t])}const vd={};function Bg(e,t,n){vd[e]||(vd[e]=!0)}function Qg(e,t){e==null||e.v7_startTransition,e==null||e.v7_relativeSplatPath}function Vg(e){return Pg(e.context)}function yt(e){he(!1)}function Kg(e){let{basename:t="/",children:n=null,location:r,navigationType:s=dn.Pop,navigator:i,static:l=!1,future:o}=e;ii()&&he(!1);let u=t.replace(/^\/*/,"/"),c=k.useMemo(()=>({basename:u,navigator:i,static:l,future:Vs({v7_relativeSplatPath:!1},o)}),[u,o,i,l]);typeof r=="string"&&(r=Yr(r));let{pathname:m="/",search:d="",hash:h="",state:x=null,key:w="default"}=r,y=k.useMemo(()=>{let S=Kr(m,u);return S==null?null:{location:{pathname:S,search:d,hash:h,state:x,key:w},navigationType:s}},[u,m,d,h,x,w,s]);return y==null?null:k.createElement(Tn.Provider,{value:c},k.createElement(La.Provider,{children:n,value:y}))}function Hg(e){let{children:t,location:n}=e;return Tg(Eo(t),n)}new Promise(()=>{});function Eo(e,t){t===void 0&&(t=[]);let n=[];return k.Children.forEach(e,(r,s)=>{if(!k.isValidElement(r))return;let i=[...t,s];if(r.type===k.Fragment){n.push.apply(n,Eo(r.props.children,i));return}r.type!==yt&&he(!1),!r.props.index||!r.props.children||he(!1);let l={id:r.props.id||i.join("-"),caseSensitive:r.props.caseSensitive,element:r.props.element,Component:r.props.Component,index:r.props.index,path:r.props.path,loader:r.props.loader,action:r.props.action,errorElement:r.props.errorElement,ErrorBoundary:r.props.ErrorBoundary,hasErrorBoundary:r.props.ErrorBoundary!=null||r.props.errorElement!=null,shouldRevalidate:r.props.shouldRevalidate,handle:r.props.handle,lazy:r.props.lazy};r.props.children&&(l.children=Eo(r.props.children,i)),n.push(l)}),n}/** + * React Router DOM v6.30.3 + * + * Copyright (c) Remix Software Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE.md file in the root directory of this source tree. + * + * @license MIT + */function ma(){return ma=Object.assign?Object.assign.bind():function(e){for(var t=1;t=0)&&(n[s]=e[s]);return n}function Wg(e){return!!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)}function qg(e,t){return e.button===0&&(!t||t==="_self")&&!Wg(e)}const Jg=["onClick","relative","reloadDocument","replace","state","target","to","preventScrollReset","viewTransition"],Gg=["aria-current","caseSensitive","className","end","style","to","viewTransition","children"],Yg="6";try{window.__reactRouterVersion=Yg}catch{}const Xg=k.createContext({isTransitioning:!1}),Zg="startTransition",xd=ap[Zg];function ey(e){let{basename:t,children:n,future:r,window:s}=e,i=k.useRef();i.current==null&&(i.current=eg({window:s,v5Compat:!0}));let l=i.current,[o,u]=k.useState({action:l.action,location:l.location}),{v7_startTransition:c}=r||{},m=k.useCallback(d=>{c&&xd?xd(()=>u(d)):u(d)},[u,c]);return k.useLayoutEffect(()=>l.listen(m),[l,m]),k.useEffect(()=>Qg(r),[r]),k.createElement(Kg,{basename:t,children:n,location:o.location,navigationType:o.action,navigator:l,future:r})}const ty=typeof window<"u"&&typeof window.document<"u"&&typeof window.document.createElement<"u",ny=/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i,Ks=k.forwardRef(function(t,n){let{onClick:r,relative:s,reloadDocument:i,replace:l,state:o,target:u,to:c,preventScrollReset:m,viewTransition:d}=t,h=km(t,Jg),{basename:x}=k.useContext(Tn),w,y=!1;if(typeof c=="string"&&ny.test(c)&&(w=c,ty))try{let p=new URL(window.location.href),j=c.startsWith("//")?new URL(p.protocol+c):new URL(c),C=Kr(j.pathname,x);j.origin===p.origin&&C!=null?c=C+j.search+j.hash:y=!0}catch{}let S=Cg(c,{relative:s}),v=sy(c,{replace:l,state:o,target:u,preventScrollReset:m,relative:s,viewTransition:d});function f(p){r&&r(p),p.defaultPrevented||v(p)}return k.createElement("a",ma({},h,{href:w||S,onClick:y||i?r:f,ref:n,target:u}))}),gd=k.forwardRef(function(t,n){let{"aria-current":r="page",caseSensitive:s=!1,className:i="",end:l=!1,style:o,to:u,viewTransition:c,children:m}=t,d=km(t,Gg),h=Ma(u,{relative:d.relative}),x=Xr(),w=k.useContext(vm),{navigator:y,basename:S}=k.useContext(Tn),v=w!=null&&iy(h)&&c===!0,f=y.encodeLocation?y.encodeLocation(h).pathname:h.pathname,p=x.pathname,j=w&&w.navigation&&w.navigation.location?w.navigation.location.pathname:null;s||(p=p.toLowerCase(),j=j?j.toLowerCase():null,f=f.toLowerCase()),j&&S&&(j=Kr(j,S)||j);const C=f!=="/"&&f.endsWith("/")?f.length-1:f.length;let N=p===f||!l&&p.startsWith(f)&&p.charAt(C)==="/",b=j!=null&&(j===f||!l&&j.startsWith(f)&&j.charAt(f.length)==="/"),E={isActive:N,isPending:b,isTransitioning:v},F=N?r:void 0,O;typeof i=="function"?O=i(E):O=[i,N?"active":null,b?"pending":null,v?"transitioning":null].filter(Boolean).join(" ");let Q=typeof o=="function"?o(E):o;return k.createElement(Ks,ma({},d,{"aria-current":F,className:O,ref:n,style:Q,to:u,viewTransition:c}),typeof m=="function"?m(E):m)});var Po;(function(e){e.UseScrollRestoration="useScrollRestoration",e.UseSubmit="useSubmit",e.UseSubmitFetcher="useSubmitFetcher",e.UseFetcher="useFetcher",e.useViewTransitionState="useViewTransitionState"})(Po||(Po={}));var yd;(function(e){e.UseFetcher="useFetcher",e.UseFetchers="useFetchers",e.UseScrollRestoration="useScrollRestoration"})(yd||(yd={}));function ry(e){let t=k.useContext(Oa);return t||he(!1),t}function sy(e,t){let{target:n,replace:r,state:s,preventScrollReset:i,relative:l,viewTransition:o}=t===void 0?{}:t,u=Et(),c=Xr(),m=Ma(e,{relative:l});return k.useCallback(d=>{if(qg(d,n)){d.preventDefault();let h=r!==void 0?r:ha(c)===ha(m);u(e,{replace:h,state:s,preventScrollReset:i,relative:l,viewTransition:o})}},[c,u,m,r,s,n,e,i,l,o])}function iy(e,t){t===void 0&&(t={});let n=k.useContext(Xg);n==null&&he(!1);let{basename:r}=ry(Po.useViewTransitionState),s=Ma(e,{relative:t.relative});if(!n.isTransitioning)return!1;let i=Kr(n.currentLocation.pathname,r)||n.currentLocation.pathname,l=Kr(n.nextLocation.pathname,r)||n.nextLocation.pathname;return _o(s.pathname,l)!=null||_o(s.pathname,i)!=null}/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */var ay={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"};/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const ly=e=>e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase().trim(),Y=(e,t)=>{const n=k.forwardRef(({color:r="currentColor",size:s=24,strokeWidth:i=2,absoluteStrokeWidth:l,className:o="",children:u,...c},m)=>k.createElement("svg",{ref:m,...ay,width:s,height:s,stroke:r,strokeWidth:l?Number(i)*24/Number(s):i,className:["lucide",`lucide-${ly(e)}`,o].join(" "),...c},[...t.map(([d,h])=>k.createElement(d,h)),...Array.isArray(u)?u:[u]]));return n.displayName=`${e}`,n};/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Sm=Y("AlertCircle",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["line",{x1:"12",x2:"12",y1:"8",y2:"12",key:"1pkeuh"}],["line",{x1:"12",x2:"12.01",y1:"16",y2:"16",key:"4dfq90"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const oy=Y("ArrowUpDown",[["path",{d:"m21 16-4 4-4-4",key:"f6ql7i"}],["path",{d:"M17 20V4",key:"1ejh1v"}],["path",{d:"m3 8 4-4 4 4",key:"11wl7u"}],["path",{d:"M7 4v16",key:"1glfcx"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const uy=Y("BarChart3",[["path",{d:"M3 3v18h18",key:"1s2lah"}],["path",{d:"M18 17V9",key:"2bz60n"}],["path",{d:"M13 17V5",key:"1frdt8"}],["path",{d:"M8 17v-3",key:"17ska0"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const cy=Y("Bot",[["path",{d:"M12 8V4H8",key:"hb8ula"}],["rect",{width:"16",height:"12",x:"4",y:"8",rx:"2",key:"enze0r"}],["path",{d:"M2 14h2",key:"vft8re"}],["path",{d:"M20 14h2",key:"4cs60a"}],["path",{d:"M15 13v2",key:"1xurst"}],["path",{d:"M9 13v2",key:"rq6x2g"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Nm=Y("CheckCircle",[["path",{d:"M22 11.08V12a10 10 0 1 1-5.93-9.14",key:"g774vq"}],["path",{d:"m9 11 3 3L22 4",key:"1pflzl"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const dy=Y("Check",[["path",{d:"M20 6 9 17l-5-5",key:"1gmf2c"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const fy=Y("ChevronDown",[["path",{d:"m6 9 6 6 6-6",key:"qrunsl"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const hy=Y("ChevronLeft",[["path",{d:"m15 18-6-6 6-6",key:"1wnfg3"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Ss=Y("ChevronRight",[["path",{d:"m9 18 6-6-6-6",key:"mthhwq"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const my=Y("Clock",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["polyline",{points:"12 6 12 12 16 14",key:"68esgv"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const py=Y("Coins",[["circle",{cx:"8",cy:"8",r:"6",key:"3yglwk"}],["path",{d:"M18.09 10.37A6 6 0 1 1 10.34 18",key:"t5s6rm"}],["path",{d:"M7 6h1v4",key:"1obek4"}],["path",{d:"m16.71 13.88.7.71-2.82 2.82",key:"1rbuyh"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const vy=Y("Copy",[["rect",{width:"14",height:"14",x:"8",y:"8",rx:"2",ry:"2",key:"17jyea"}],["path",{d:"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2",key:"zix9uf"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const jd=Y("Download",[["path",{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4",key:"ih7n3h"}],["polyline",{points:"7 10 12 15 17 10",key:"2ggqvy"}],["line",{x1:"12",x2:"12",y1:"15",y2:"3",key:"1vk2je"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const xy=Y("ExternalLink",[["path",{d:"M15 3h6v6",key:"1q9fwt"}],["path",{d:"M10 14 21 3",key:"gplh6r"}],["path",{d:"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6",key:"a6xqqp"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const gy=Y("GitCompare",[["circle",{cx:"18",cy:"18",r:"3",key:"1xkwt0"}],["circle",{cx:"6",cy:"6",r:"3",key:"1lh9wr"}],["path",{d:"M13 6h3a2 2 0 0 1 2 2v7",key:"1yeb86"}],["path",{d:"M11 18H8a2 2 0 0 1-2-2V9",key:"19pyzm"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const yy=Y("Github",[["path",{d:"M15 22v-4a4.8 4.8 0 0 0-1-3.5c3 0 6-2 6-5.5.08-1.25-.27-2.48-1-3.5.28-1.15.28-2.35 0-3.5 0 0-1 0-3 1.5-2.64-.5-5.36-.5-8 0C6 2 5 2 5 2c-.3 1.15-.3 2.35 0 3.5A5.403 5.403 0 0 0 4 9c0 3.5 3 5.5 6 5.5-.39.49-.68 1.05-.85 1.65-.17.6-.22 1.23-.15 1.85v4",key:"tonef"}],["path",{d:"M9 18c-4.51 2-5-2-7-2",key:"9comsn"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const za=Y("Globe",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20",key:"13o1zl"}],["path",{d:"M2 12h20",key:"9i4pu4"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const jy=Y("History",[["path",{d:"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8",key:"1357e3"}],["path",{d:"M3 3v5h5",key:"1xhq8a"}],["path",{d:"M12 7v5l4 2",key:"1fdv2h"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const wy=Y("ListTodo",[["rect",{x:"3",y:"5",width:"6",height:"6",rx:"1",key:"1defrl"}],["path",{d:"m3 17 2 2 4-4",key:"1jhpwq"}],["path",{d:"M13 6h8",key:"15sg57"}],["path",{d:"M13 12h8",key:"h98zly"}],["path",{d:"M13 18h8",key:"oe0vm4"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const ky=Y("List",[["line",{x1:"8",x2:"21",y1:"6",y2:"6",key:"7ey8pc"}],["line",{x1:"8",x2:"21",y1:"12",y2:"12",key:"rjfblc"}],["line",{x1:"8",x2:"21",y1:"18",y2:"18",key:"c3b1m8"}],["line",{x1:"3",x2:"3.01",y1:"6",y2:"6",key:"1g7gq3"}],["line",{x1:"3",x2:"3.01",y1:"12",y2:"12",key:"1pjlvk"}],["line",{x1:"3",x2:"3.01",y1:"18",y2:"18",key:"28t2mc"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Fa=Y("Loader2",[["path",{d:"M21 12a9 9 0 1 1-6.219-8.56",key:"13zald"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const bm=Y("Lock",[["rect",{width:"18",height:"11",x:"3",y:"11",rx:"2",ry:"2",key:"1w4ew1"}],["path",{d:"M7 11V7a5 5 0 0 1 10 0v4",key:"fwvmzm"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Sy=Y("LogOut",[["path",{d:"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4",key:"1uf3rs"}],["polyline",{points:"16 17 21 12 16 7",key:"1gabdz"}],["line",{x1:"21",x2:"9",y1:"12",y2:"12",key:"1uyos4"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Ny=Y("Moon",[["path",{d:"M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z",key:"a7tn18"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Hs=Y("Play",[["polygon",{points:"5 3 19 12 5 21 5 3",key:"191637"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Ia=Y("Plus",[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"M12 5v14",key:"s699le"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Cm=Y("Settings",[["path",{d:"M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z",key:"1qme2f"}],["circle",{cx:"12",cy:"12",r:"3",key:"1v7zrd"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const by=Y("Share2",[["circle",{cx:"18",cy:"5",r:"3",key:"gq8acd"}],["circle",{cx:"6",cy:"12",r:"3",key:"w7nqdw"}],["circle",{cx:"18",cy:"19",r:"3",key:"1xt0gg"}],["line",{x1:"8.59",x2:"15.42",y1:"13.51",y2:"17.49",key:"47mynk"}],["line",{x1:"15.41",x2:"8.59",y1:"6.51",y2:"10.49",key:"1n3mei"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Cy=Y("Square",[["rect",{width:"18",height:"18",x:"3",y:"3",rx:"2",key:"afitv7"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const _y=Y("Sun",[["circle",{cx:"12",cy:"12",r:"4",key:"4exip2"}],["path",{d:"M12 2v2",key:"tus03m"}],["path",{d:"M12 20v2",key:"1lh1kg"}],["path",{d:"m4.93 4.93 1.41 1.41",key:"149t6j"}],["path",{d:"m17.66 17.66 1.41 1.41",key:"ptbguv"}],["path",{d:"M2 12h2",key:"1t8f8n"}],["path",{d:"M20 12h2",key:"1q8mjw"}],["path",{d:"m6.34 17.66-1.41 1.41",key:"1m8zz5"}],["path",{d:"m19.07 4.93-1.41 1.41",key:"1shlcs"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const _m=Y("Trash2",[["path",{d:"M3 6h18",key:"d0wm0j"}],["path",{d:"M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6",key:"4alrt4"}],["path",{d:"M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2",key:"v07s0e"}],["line",{x1:"10",x2:"10",y1:"11",y2:"17",key:"1uufr5"}],["line",{x1:"14",x2:"14",y1:"11",y2:"17",key:"xtxkd"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Em=Y("User",[["path",{d:"M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2",key:"975kel"}],["circle",{cx:"12",cy:"7",r:"4",key:"17ys0d"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Ey=Y("XCircle",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"m15 9-6 6",key:"1uzhvr"}],["path",{d:"m9 9 6 6",key:"z0biqf"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Pm=Y("X",[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Da=Y("Zap",[["polygon",{points:"13 2 3 14 12 14 11 22 21 10 12 10 13 2",key:"45s27k"}]]),Py={},wd=e=>{let t;const n=new Set,r=(m,d)=>{const h=typeof m=="function"?m(t):m;if(!Object.is(h,t)){const x=t;t=d??(typeof h!="object"||h===null)?h:Object.assign({},t,h),n.forEach(w=>w(t,x))}},s=()=>t,u={setState:r,getState:s,getInitialState:()=>c,subscribe:m=>(n.add(m),()=>n.delete(m)),destroy:()=>{(Py?"production":void 0)!=="production"&&console.warn("[DEPRECATED] The `destroy` method will be unsupported in a future version. Instead use unsubscribe function returned by subscribe. Everything will be garbage-collected if store is garbage-collected."),n.clear()}},c=t=e(r,s,u);return u},Ty=e=>e?wd(e):wd;var Tm={exports:{}},Om={},Lm={exports:{}},Rm={};/** + * @license React + * use-sync-external-store-shim.production.js + * + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var Hr=k;function Oy(e,t){return e===t&&(e!==0||1/e===1/t)||e!==e&&t!==t}var Ly=typeof Object.is=="function"?Object.is:Oy,Ry=Hr.useState,My=Hr.useEffect,zy=Hr.useLayoutEffect,Fy=Hr.useDebugValue;function Iy(e,t){var n=t(),r=Ry({inst:{value:n,getSnapshot:t}}),s=r[0].inst,i=r[1];return zy(function(){s.value=n,s.getSnapshot=t,pl(s)&&i({inst:s})},[e,n,t]),My(function(){return pl(s)&&i({inst:s}),e(function(){pl(s)&&i({inst:s})})},[e]),Fy(n),n}function pl(e){var t=e.getSnapshot;e=e.value;try{var n=t();return!Ly(e,n)}catch{return!0}}function Dy(e,t){return t()}var Ay=typeof window>"u"||typeof window.document>"u"||typeof window.document.createElement>"u"?Dy:Iy;Rm.useSyncExternalStore=Hr.useSyncExternalStore!==void 0?Hr.useSyncExternalStore:Ay;Lm.exports=Rm;var $y=Lm.exports;/** + * @license React + * use-sync-external-store-shim/with-selector.production.js + * + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var Aa=k,Uy=$y;function By(e,t){return e===t&&(e!==0||1/e===1/t)||e!==e&&t!==t}var Qy=typeof Object.is=="function"?Object.is:By,Vy=Uy.useSyncExternalStore,Ky=Aa.useRef,Hy=Aa.useEffect,Wy=Aa.useMemo,qy=Aa.useDebugValue;Om.useSyncExternalStoreWithSelector=function(e,t,n,r,s){var i=Ky(null);if(i.current===null){var l={hasValue:!1,value:null};i.current=l}else l=i.current;i=Wy(function(){function u(x){if(!c){if(c=!0,m=x,x=r(x),s!==void 0&&l.hasValue){var w=l.value;if(s(w,x))return d=w}return d=x}if(w=d,Qy(m,x))return w;var y=r(x);return s!==void 0&&s(w,y)?(m=x,w):(m=x,d=y)}var c=!1,m,d,h=n===void 0?null:n;return[function(){return u(t())},h===null?void 0:function(){return u(h())}]},[t,n,r,s]);var o=Vy(e,i[0],i[1]);return Hy(function(){l.hasValue=!0,l.value=o},[o]),qy(o),o};Tm.exports=Om;var Jy=Tm.exports;const Gy=$d(Jy),Mm={},{useDebugValue:Yy}=Ao,{useSyncExternalStoreWithSelector:Xy}=Gy;let kd=!1;const Zy=e=>e;function e0(e,t=Zy,n){(Mm?"production":void 0)!=="production"&&n&&!kd&&(console.warn("[DEPRECATED] Use `createWithEqualityFn` instead of `create` or use `useStoreWithEqualityFn` instead of `useStore`. They can be imported from 'zustand/traditional'. https://github.com/pmndrs/zustand/discussions/1937"),kd=!0);const r=Xy(e.subscribe,e.getState,e.getServerState||e.getInitialState,t,n);return Yy(r),r}const Sd=e=>{(Mm?"production":void 0)!=="production"&&typeof e!="function"&&console.warn("[DEPRECATED] Passing a vanilla store will be unsupported in a future version. Instead use `import { useStore } from 'zustand'`.");const t=typeof e=="function"?Ty(e):e,n=(r,s)=>e0(t,r,s);return Object.assign(n,t),n},Fu=e=>e?Sd(e):Sd,$a="/api",Iu="flow_auth_token",Du="flow_auth_expires",Au="flow_auth_username";function Ws(){const e=localStorage.getItem(Iu),t=localStorage.getItem(Du);return!e||!t?null:new Date(t)<=new Date?(qn(),null):e}function Nd(e,t,n){localStorage.setItem(Iu,e),localStorage.setItem(Du,t),localStorage.setItem(Au,n)}function qn(){localStorage.removeItem(Iu),localStorage.removeItem(Du),localStorage.removeItem(Au)}function $u(){return localStorage.getItem(Au)}let nr=null;function t0(e){nr=e}async function V(e,t,n=!1){const r={"Content-Type":"application/json",...t==null?void 0:t.headers};if(!n){const i=Ws();i&&(r.Authorization=`Bearer ${i}`)}const s=await fetch(`${$a}${e}`,{...t,headers:r});if(s.status===401){qn(),nr&&nr();const i=await s.json().catch(()=>({detail:"Not authenticated"}));throw new Error(i.detail||"Not authenticated")}if(!s.ok){const i=await s.json().catch(()=>({detail:s.statusText}));throw new Error(i.detail||"API request failed")}if(s.status!==204)return s.json()}const ar={getConfig:()=>V("/auth/config",void 0,!0),login:e=>V("/auth/login",{method:"POST",body:JSON.stringify(e)},!0),getGitHubAuthUrl:()=>`${$a}/auth/github`,getCurrentUser:()=>V("/auth/me"),logout:()=>V("/auth/logout",{method:"POST"})},br={list:e=>{const t=new URLSearchParams;e!=null&&e.include_auto_generated&&t.set("include_auto_generated","true"),e!=null&&e.include_public&&t.set("include_public","true");const n=t.toString();return V(`/configs${n?`?${n}`:""}`)},get:e=>V(`/configs/${e}`),create:e=>V("/configs",{method:"POST",body:JSON.stringify(e)}),update:(e,t)=>V(`/configs/${e}`,{method:"PUT",body:JSON.stringify(t)}),delete:e=>V(`/configs/${e}`,{method:"DELETE"})},Dt={list:e=>{const t=new URLSearchParams;e!=null&&e.category&&t.set("category",e.category),e!=null&&e.suite&&t.set("suite",e.suite);const n=t.toString();return V(`/tasks${n?`?${n}`:""}`)},get:e=>V(`/tasks/${e}`),create:e=>V("/tasks",{method:"POST",body:JSON.stringify(e)}),update:(e,t)=>V(`/tasks/${e}`,{method:"PUT",body:JSON.stringify(t)}),delete:e=>V(`/tasks/${e}`,{method:"DELETE"}),listSuites:()=>V("/tasks/suites"),importSuite:e=>V(`/tasks/import-suite?suite_name=${encodeURIComponent(e)}`,{method:"POST"})},_t={list:e=>{const t=new URLSearchParams;e!=null&&e.status&&t.set("status",e.status),e!=null&&e.include_public&&t.set("include_public","true");const n=t.toString();return V(`/jobs${n?`?${n}`:""}`)},get:e=>V(`/jobs/${e}`),create:e=>V("/jobs",{method:"POST",body:JSON.stringify(e)}),update:(e,t)=>V(`/jobs/${e}`,{method:"PUT",body:JSON.stringify(t)}),start:async function*(e){var o;const t={},n=Ws();n&&(t.Authorization=`Bearer ${n}`);const r=await fetch(`${$a}/jobs/${e}/start`,{method:"POST",headers:t});if(r.status===401)throw qn(),nr&&nr(),new Error("Not authenticated");if(!r.ok)throw new Error("Failed to start job");const s=(o=r.body)==null?void 0:o.getReader();if(!s)throw new Error("No response body");const i=new TextDecoder;let l="";for(;;){const{done:u,value:c}=await s.read();if(u)break;l+=i.decode(c,{stream:!0});const m=l.split(` +`);l=m.pop()||"";for(const d of m)d.startsWith("data: ")&&(yield JSON.parse(d.slice(6)))}},cancel:e=>V(`/jobs/${e}/cancel`,{method:"POST"}),delete:e=>V(`/jobs/${e}`,{method:"DELETE"})},To={list:e=>{const t=new URLSearchParams;e!=null&&e.job_id&&t.set("job_id",e.job_id),e!=null&&e.candidate_name&&t.set("candidate_name",e.candidate_name),e!=null&&e.task_name&&t.set("task_name",e.task_name),(e==null?void 0:e.is_pareto)!==void 0&&t.set("is_pareto",String(e.is_pareto));const n=t.toString();return V(`/runs${n?`?${n}`:""}`)},get:e=>V(`/runs/${e}`),getJobSummary:e=>V(`/runs/job/${e}/summary`)},Ns={list:e=>{const t=new URLSearchParams;e!=null&&e.agent_id&&t.set("agent_id",e.agent_id),e!=null&&e.limit&&t.set("limit",String(e.limit));const n=t.toString();return V(`/tests${n?`?${n}`:""}`)},get:e=>V(`/tests/${e}`),create:e=>V("/tests",{method:"POST",body:JSON.stringify(e)}),start:async function*(e){var o;const t={},n=Ws();n&&(t.Authorization=`Bearer ${n}`);const r=await fetch(`${$a}/tests/${e}/start`,{method:"POST",headers:t});if(r.status===401)throw qn(),nr&&nr(),new Error("Not authenticated");if(!r.ok){const u=await r.json().catch(()=>({detail:"Failed to start test"}));throw new Error(u.detail||"Failed to start test")}const s=(o=r.body)==null?void 0:o.getReader();if(!s)throw new Error("No response body");const i=new TextDecoder;let l="";for(;;){const{done:u,value:c}=await s.read();if(u)break;l+=i.decode(c,{stream:!0});const m=l.split(` +`);l=m.pop()||"";for(const d of m)d.startsWith("data: ")&&(yield JSON.parse(d.slice(6)))}},cancel:e=>V(`/tests/${e}/cancel`,{method:"POST"}),delete:e=>V(`/tests/${e}`,{method:"DELETE"})},n0={list:()=>V("/llm-configs"),get:e=>V(`/llm-configs/${e}`),getDefault:()=>V("/llm-configs/default"),create:e=>V("/llm-configs",{method:"POST",body:JSON.stringify(e)}),update:(e,t)=>V(`/llm-configs/${e}`,{method:"PUT",body:JSON.stringify(t)}),delete:e=>V(`/llm-configs/${e}`,{method:"DELETE"}),setDefault:e=>V(`/llm-configs/${e}/set-default`,{method:"POST"}),test:e=>V(`/llm-configs/${e}/test`,{method:"POST"})},r0={list:()=>V("/tools"),get:e=>V(`/tools/${e}`)},zm={getAgentSchema:()=>V("/schema/agent")},Oo={design:e=>V("/experiment/design",{method:"POST",body:JSON.stringify(e)}),importYaml:e=>V("/experiment/import-yaml",{method:"POST",body:JSON.stringify(e)}),validate:e=>V("/experiment/validate",{method:"POST",body:JSON.stringify(e)}),generateCandidates:e=>V("/experiment/generate-candidates",{method:"POST",body:JSON.stringify(e)})},Uu=Fu((e,t)=>(t0(()=>{e({isAuthenticated:!1,user:null,error:"Session expired. Please log in again."})}),{authConfig:null,isLoadingConfig:!0,isAuthenticated:!1,isLoading:!1,user:null,error:null,loadAuthConfig:async()=>{e({isLoadingConfig:!0});try{const n=await ar.getConfig();if(e({authConfig:n,isLoadingConfig:!1}),n.enabled){const r=Ws(),s=$u();if(r&&s)try{const i=await ar.getCurrentUser();e({isAuthenticated:!0,user:i})}catch{qn(),e({isAuthenticated:!1,user:null})}}else e({isAuthenticated:!0,user:{username:"anonymous",auth_mode:"none"}})}catch(n){console.error("Failed to load auth config:",n),e({isLoadingConfig:!1,error:"Failed to connect to server"})}},login:async(n,r)=>{e({isLoading:!0,error:null});try{const s=await ar.login({username:n,password:r});return Nd(s.access_token,s.expires_at,s.username),e({isAuthenticated:!0,isLoading:!1,user:{username:s.username,auth_mode:"basic"}}),!0}catch(s){return e({isLoading:!1,error:s instanceof Error?s.message:"Login failed"}),!1}},loginWithGitHub:()=>{window.location.href=ar.getGitHubAuthUrl()},handleOAuthCallback:()=>{const n=new URLSearchParams(window.location.search),r=n.get("auth_error");if(r)return e({error:r}),window.history.replaceState({},"",window.location.pathname),!0;if(n.get("auth_callback")==="true"){const s=n.get("token"),i=n.get("expires_at"),l=n.get("username");return s&&i&&l&&(Nd(s,i,l),e({isAuthenticated:!0,user:{username:l,auth_mode:"github"}})),window.history.replaceState({},"",window.location.pathname),!0}return!1},logout:async()=>{try{await ar.logout()}catch{}qn(),e({isAuthenticated:!1,user:null,error:null})},checkAuth:async()=>{const{authConfig:n}=t();if(!(n!=null&&n.enabled)){e({isAuthenticated:!0});return}if(!Ws()){e({isAuthenticated:!1,user:null});return}try{const s=await ar.getCurrentUser();e({isAuthenticated:!0,user:s})}catch{qn(),e({isAuthenticated:!1,user:null})}},clearError:()=>e({error:null})}));function K({variant:e="secondary",size:t="md",className:n="",icon:r,iconRight:s,loading:i=!1,children:l,disabled:o,...u}){const c="font-medium transition-colors disabled:opacity-50 disabled:cursor-not-allowed inline-flex items-center gap-1.5",m={primary:"bg-[var(--accent)] text-black hover:bg-[#16a34a]",secondary:"bg-[var(--bg-tertiary)] text-[var(--text-primary)] border border-[var(--border)] hover:bg-[var(--border)]",danger:"bg-[var(--error)] text-white hover:bg-red-600",ghost:"text-[var(--text-secondary)] hover:text-[var(--text-primary)] hover:bg-[var(--bg-tertiary)]"},d={sm:"px-2 py-1 text-xs",md:"px-3 py-1.5 text-sm"},h=t==="sm"?14:16;return a.jsxs("button",{className:`${c} ${m[e]} ${d[t]} ${n}`,disabled:o||i,...u,children:[i?a.jsx(Fa,{size:h,className:"animate-spin"}):r?a.jsx(r,{size:h}):null,l,s&&!i&&a.jsx(s,{size:h})]})}const s0={};function i0(e,t){let n;try{n=e()}catch{return}return{getItem:s=>{var i;const l=u=>u===null?null:JSON.parse(u,void 0),o=(i=n.getItem(s))!=null?i:null;return o instanceof Promise?o.then(l):l(o)},setItem:(s,i)=>n.setItem(s,JSON.stringify(i,void 0)),removeItem:s=>n.removeItem(s)}}const qs=e=>t=>{try{const n=e(t);return n instanceof Promise?n:{then(r){return qs(r)(n)},catch(r){return this}}}catch(n){return{then(r){return this},catch(r){return qs(r)(n)}}}},a0=(e,t)=>(n,r,s)=>{let i={getStorage:()=>localStorage,serialize:JSON.stringify,deserialize:JSON.parse,partialize:S=>S,version:0,merge:(S,v)=>({...v,...S}),...t},l=!1;const o=new Set,u=new Set;let c;try{c=i.getStorage()}catch{}if(!c)return e((...S)=>{console.warn(`[zustand persist middleware] Unable to update item '${i.name}', the given storage is currently unavailable.`),n(...S)},r,s);const m=qs(i.serialize),d=()=>{const S=i.partialize({...r()});let v;const f=m({state:S,version:i.version}).then(p=>c.setItem(i.name,p)).catch(p=>{v=p});if(v)throw v;return f},h=s.setState;s.setState=(S,v)=>{h(S,v),d()};const x=e((...S)=>{n(...S),d()},r,s);let w;const y=()=>{var S;if(!c)return;l=!1,o.forEach(f=>f(r()));const v=((S=i.onRehydrateStorage)==null?void 0:S.call(i,r()))||void 0;return qs(c.getItem.bind(c))(i.name).then(f=>{if(f)return i.deserialize(f)}).then(f=>{if(f)if(typeof f.version=="number"&&f.version!==i.version){if(i.migrate)return i.migrate(f.state,f.version);console.error("State loaded from storage couldn't be migrated since no migrate function was provided")}else return f.state}).then(f=>{var p;return w=i.merge(f,(p=r())!=null?p:x),n(w,!0),d()}).then(()=>{v==null||v(w,void 0),l=!0,u.forEach(f=>f(w))}).catch(f=>{v==null||v(void 0,f)})};return s.persist={setOptions:S=>{i={...i,...S},S.getStorage&&(c=S.getStorage())},clearStorage:()=>{c==null||c.removeItem(i.name)},getOptions:()=>i,rehydrate:()=>y(),hasHydrated:()=>l,onHydrate:S=>(o.add(S),()=>{o.delete(S)}),onFinishHydration:S=>(u.add(S),()=>{u.delete(S)})},y(),w||x},l0=(e,t)=>(n,r,s)=>{let i={storage:i0(()=>localStorage),partialize:y=>y,version:0,merge:(y,S)=>({...S,...y}),...t},l=!1;const o=new Set,u=new Set;let c=i.storage;if(!c)return e((...y)=>{console.warn(`[zustand persist middleware] Unable to update item '${i.name}', the given storage is currently unavailable.`),n(...y)},r,s);const m=()=>{const y=i.partialize({...r()});return c.setItem(i.name,{state:y,version:i.version})},d=s.setState;s.setState=(y,S)=>{d(y,S),m()};const h=e((...y)=>{n(...y),m()},r,s);s.getInitialState=()=>h;let x;const w=()=>{var y,S;if(!c)return;l=!1,o.forEach(f=>{var p;return f((p=r())!=null?p:h)});const v=((S=i.onRehydrateStorage)==null?void 0:S.call(i,(y=r())!=null?y:h))||void 0;return qs(c.getItem.bind(c))(i.name).then(f=>{if(f)if(typeof f.version=="number"&&f.version!==i.version){if(i.migrate)return[!0,i.migrate(f.state,f.version)];console.error("State loaded from storage couldn't be migrated since no migrate function was provided")}else return[!1,f.state];return[!1,void 0]}).then(f=>{var p;const[j,C]=f;if(x=i.merge(C,(p=r())!=null?p:h),n(x,!0),j)return m()}).then(()=>{v==null||v(x,void 0),x=r(),l=!0,u.forEach(f=>f(x))}).catch(f=>{v==null||v(void 0,f)})};return s.persist={setOptions:y=>{i={...i,...y},y.storage&&(c=y.storage)},clearStorage:()=>{c==null||c.removeItem(i.name)},getOptions:()=>i,rehydrate:()=>w(),hasHydrated:()=>l,onHydrate:y=>(o.add(y),()=>{o.delete(y)}),onFinishHydration:y=>(u.add(y),()=>{u.delete(y)})},i.skipHydration||w(),x||h},o0=(e,t)=>"getStorage"in t||"serialize"in t||"deserialize"in t?((s0?"production":void 0)!=="production"&&console.warn("[DEPRECATED] `getStorage`, `serialize` and `deserialize` options are deprecated. Use `storage` option instead."),a0(e,t)):l0(e,t),u0=o0,c0=Fu()(u0((e,t)=>({theme:"dark",setTheme:n=>{document.documentElement.setAttribute("data-theme",n),e({theme:n})},toggleTheme:()=>{const n=t().theme==="dark"?"light":"dark";document.documentElement.setAttribute("data-theme",n),e({theme:n})}}),{name:"flow-theme",onRehydrateStorage:()=>e=>{e!=null&&e.theme&&document.documentElement.setAttribute("data-theme",e.theme)}}));function d0(){const{theme:e,toggleTheme:t}=c0();return a.jsx("button",{onClick:t,className:"p-2 rounded-md text-[var(--text-secondary)] hover:text-[var(--text-primary)] hover:bg-[var(--bg-tertiary)] transition-colors focus:outline-none focus:ring-2 focus:ring-[var(--accent)]","aria-label":`Switch to ${e==="dark"?"light":"dark"} mode`,title:`Switch to ${e==="dark"?"light":"dark"} mode`,children:e==="dark"?a.jsx(_y,{size:16}):a.jsx(Ny,{size:16})})}const f0=[{path:"/agents",label:"Agents",icon:cy},{path:"/jobs",label:"Jobs",icon:Hs},{path:"/tasks",label:"Tasks",icon:wy}];function h0(){const e=Xr(),{authConfig:t,user:n,logout:r}=Uu(),s=l=>l==="/agents"?e.pathname==="/"||e.pathname==="/agents":e.pathname.startsWith(l),i=async()=>{await r()};return a.jsxs("div",{className:"min-h-screen flex flex-col",children:[a.jsx("header",{className:"border-b border-[var(--border)] bg-[var(--bg-secondary)]",children:a.jsxs("div",{className:"max-w-7xl mx-auto px-4 py-3 flex items-center justify-between",children:[a.jsxs("div",{className:"flex items-center gap-8",children:[a.jsxs(gd,{to:"/",className:"text-lg font-bold text-[var(--accent)] flex items-center gap-2 hover:opacity-80",children:[a.jsx(Da,{size:20}),"flow",a.jsx("span",{className:"text-[var(--text-secondary)]",children:"/optimize"})]}),a.jsx("nav",{className:"flex gap-1",children:f0.map(l=>a.jsxs(gd,{to:l.path,className:`px-3 py-1.5 rounded text-sm transition-colors flex items-center gap-2 ${s(l.path)?"bg-[var(--accent)] text-black font-medium":"text-[var(--text-secondary)] hover:text-[var(--text-primary)] hover:bg-[var(--bg-tertiary)]"}`,children:[a.jsx(l.icon,{size:16}),l.label]},l.path))})]}),a.jsxs("div",{className:"flex items-center gap-4",children:[a.jsx(d0,{}),(t==null?void 0:t.enabled)&&n&&a.jsxs("div",{className:"flex items-center gap-3",children:[a.jsxs("div",{className:"flex items-center gap-2 text-sm text-[var(--text-secondary)]",children:[a.jsx(Em,{size:14}),a.jsx("span",{children:n.username})]}),a.jsx(K,{variant:"ghost",size:"sm",icon:Sy,onClick:i,title:"Sign out",children:"Sign out"})]})]})]})}),a.jsx("main",{className:"flex-1 bg-[var(--bg-primary)]",children:a.jsx("div",{className:"max-w-7xl mx-auto p-4",children:a.jsx(Vg,{})})})]})}const m0=["maf","miniagent","langgraph"],p0={maf:"Microsoft Agent Framework",miniagent:"MiniAgent",langgraph:"LangGraph"},v0={openai:"OpenAI",azure_openai:"Azure OpenAI",anthropic:"Anthropic",ollama:"Ollama",custom:"Custom (OpenAI-compatible)"};function re({children:e,className:t="",onClick:n,selected:r=!1,selectable:s=!1}){const i="bg-[var(--bg-secondary)] border border-[var(--border)] p-4",l=s?"cursor-pointer hover:border-[var(--accent-dim)] transition-colors":"",o=r?"border-[var(--accent)]":"";return a.jsx("div",{className:`${i} ${l} ${o} ${t}`,onClick:n,children:e})}function q({children:e,variant:t="default"}){const n={default:"bg-[var(--bg-tertiary)] text-[var(--text-primary)] border border-[var(--border)]",success:"bg-green-600 text-white",warning:"bg-yellow-500 text-black",error:"bg-red-600 text-white",info:"bg-blue-600 text-white"};return a.jsx("span",{className:`inline-block px-2 py-0.5 text-xs font-medium rounded ${n[t]}`,children:e})}const x0={pending:"default",running:"info",completed:"success",failed:"error",cancelled:"warning"};function Fm({job:e,onDelete:t}){const n=Et(),r=e.total_experiments>0?e.completed_experiments/e.total_experiments*100:0;return a.jsxs(re,{className:"cursor-pointer hover:border-[var(--accent-dim)] flex flex-col",onClick:()=>n(`/jobs/${e.id}`),children:[a.jsxs("div",{className:"flex items-start justify-between mb-3",children:[a.jsxs("div",{className:"flex-1 min-w-0",children:[a.jsxs("div",{className:"flex items-center gap-2 flex-wrap",children:[a.jsx(q,{variant:x0[e.status]||"default",children:e.status}),e.is_public&&a.jsxs(q,{variant:"info",children:[a.jsx(za,{className:"w-3 h-3 mr-1 inline"}),"Public"]}),e.pareto_frontier.length>0&&a.jsxs(q,{variant:"success",children:[e.pareto_frontier.length," Pareto"]}),e.use_llm_eval&&a.jsx(q,{children:"LLM"})]}),a.jsx("h3",{className:"font-medium mt-2 truncate",title:e.name||`Job ${e.id.slice(0,8)}`,children:e.name||`Job ${e.id.slice(0,8)}`}),a.jsxs("code",{className:"text-xs text-[var(--text-secondary)] font-mono",children:[e.id.slice(0,8),"..."]})]}),t&&a.jsx(K,{variant:"ghost",size:"sm",onClick:s=>{s.stopPropagation(),confirm("Delete this job?")&&t(e.id)},disabled:e.status==="running",children:"×"})]}),(e.status==="running"||e.status==="completed")&&a.jsxs("div",{className:"mb-3",children:[a.jsxs("div",{className:"flex justify-between text-xs text-[var(--text-secondary)] mb-1",children:[a.jsx("span",{children:"Progress"}),a.jsxs("span",{children:[e.completed_experiments,"/",e.total_experiments]})]}),a.jsx("div",{className:"w-full bg-[var(--bg-primary)] h-1.5 rounded-full overflow-hidden",children:a.jsx("div",{className:`h-full transition-all ${e.status==="completed"?"bg-green-500":"bg-[var(--accent)]"}`,style:{width:`${r}%`}})})]}),e.status==="failed"&&e.error&&a.jsx("div",{className:"mb-3 px-2 py-1.5 bg-red-500/10 border border-red-500/30 rounded text-xs text-red-400 line-clamp-2",children:e.error}),a.jsxs("div",{className:"grid grid-cols-3 gap-2 text-center py-2 border-t border-[var(--border)] mt-auto",children:[a.jsxs("div",{children:[a.jsx("div",{className:"text-lg font-bold",children:e.candidate_ids.length}),a.jsx("div",{className:"text-xs text-[var(--text-secondary)]",children:"candidates"})]}),a.jsxs("div",{children:[a.jsx("div",{className:"text-lg font-bold",children:e.task_ids.length}),a.jsx("div",{className:"text-xs text-[var(--text-secondary)]",children:"tasks"})]}),a.jsxs("div",{children:[a.jsx("div",{className:"text-lg font-bold",children:e.total_experiments}),a.jsx("div",{className:"text-xs text-[var(--text-secondary)]",children:"runs"})]})]}),a.jsxs("div",{className:"text-xs text-[var(--text-secondary)] pt-2 border-t border-[var(--border)] flex justify-between items-center",children:[a.jsxs("span",{children:[new Date(e.created_at).toLocaleDateString()," ",new Date(e.created_at).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})]}),e.is_public&&e.created_by_name&&a.jsxs("span",{className:"text-[var(--text-secondary)]",children:["by ",e.created_by_name]})]})]})}function ai({isOpen:e,onClose:t,title:n,children:r,footer:s}){return k.useEffect(()=>{const i=l=>{l.key==="Escape"&&t()};return e&&(document.addEventListener("keydown",i),document.body.style.overflow="hidden"),()=>{document.removeEventListener("keydown",i),document.body.style.overflow=""}},[e,t]),e?a.jsxs("div",{className:"fixed inset-0 z-50 flex items-center justify-center",children:[a.jsx("div",{className:"absolute inset-0 bg-black/80",onClick:t}),a.jsxs("div",{className:"relative bg-[var(--bg-secondary)] border border-[var(--border)] max-w-lg w-full mx-4 max-h-[80vh] flex flex-col",children:[a.jsxs("div",{className:"flex-shrink-0 bg-[var(--bg-secondary)] border-b border-[var(--border)] px-4 py-3 flex items-center justify-between",children:[a.jsx("h2",{className:"font-semibold",children:n}),a.jsx("button",{onClick:t,className:"text-[var(--text-secondary)] hover:text-[var(--text-primary)]",children:"×"})]}),a.jsx("div",{className:"flex-1 overflow-y-auto p-4",children:r}),s&&a.jsx("div",{className:"flex-shrink-0 bg-[var(--bg-secondary)] border-t border-[var(--border)] px-4 py-3",children:s})]})]}):null}function fn({label:e,className:t="",...n}){return a.jsxs("div",{className:"space-y-1",children:[e&&a.jsx("label",{className:"block text-sm text-[var(--text-secondary)]",children:e}),a.jsx("input",{className:`w-full bg-[var(--bg-primary)] border border-[var(--border)] px-3 py-2 text-sm focus:outline-none focus:border-[var(--accent)] ${t}`,...n})]})}function g0({label:e,className:t="",...n}){return a.jsxs("div",{className:"space-y-1",children:[e&&a.jsx("label",{className:"block text-sm text-[var(--text-secondary)]",children:e}),a.jsx("textarea",{className:`w-full bg-[var(--bg-primary)] border border-[var(--border)] px-3 py-2 text-sm focus:outline-none focus:border-[var(--accent)] resize-y min-h-[100px] ${t}`,...n})]})}function Lo({label:e,className:t="",...n}){return a.jsxs("label",{className:`flex items-center gap-2 cursor-pointer ${t}`,children:[a.jsx("input",{type:"checkbox",className:"w-4 h-4 bg-[var(--bg-primary)] border border-[var(--border)] accent-[var(--accent)]",...n}),a.jsx("span",{className:"text-sm",children:e})]})}function y0({variations:e,onChange:t,strategies:n,availableStrategies:r}){const s=r??Object.keys(n),i=()=>{const c=e.map(x=>x.strategy),m=s.find(x=>!c.includes(x))||"none",d=n[m],h={strategy:m};if(d!=null&&d.params)for(const[x,w]of Object.entries(d.params))w.default!==void 0&&(h[x]=w.default);t([...e,h])},l=c=>{t(e.filter((m,d)=>d!==c))},o=(c,m)=>{t(e.map((d,h)=>h===c?{...d,...m}:d))},u=(c,m)=>{const d=n[m],h={strategy:m};if(d!=null&&d.params)for(const[x,w]of Object.entries(d.params))w.default!==void 0&&(h[x]=w.default);o(c,h)};return a.jsxs("div",{className:"space-y-3",children:[a.jsxs("div",{className:"flex items-center justify-between",children:[a.jsx("label",{className:"text-sm font-medium",children:"Compaction Strategies"}),a.jsx(K,{type:"button",variant:"ghost",size:"sm",icon:Ia,onClick:i,disabled:e.length>=s.length,children:"Add"})]}),e.length===0?a.jsx("p",{className:"text-sm text-[var(--text-secondary)] italic",children:'No compaction variations. Click "Add" to test different strategies.'}):a.jsx("div",{className:"space-y-2",children:e.map((c,m)=>{const d=n[c.strategy];return a.jsx("div",{className:"p-3 border border-[var(--border)] rounded bg-[var(--bg-secondary)]",children:a.jsxs("div",{className:"flex items-start justify-between gap-2",children:[a.jsxs("div",{className:"flex-1 space-y-2",children:[a.jsx("select",{className:"w-full px-2 py-1.5 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm",value:c.strategy,onChange:h=>u(m,h.target.value),children:s.map(h=>{var x;return a.jsx("option",{value:h,children:((x=n[h])==null?void 0:x.label)||h},h)})}),(d==null?void 0:d.description)&&a.jsx("p",{className:"text-xs text-[var(--text-secondary)]",children:d.description}),(d==null?void 0:d.params)&&Object.keys(d.params).length>0&&a.jsx("div",{className:"grid grid-cols-2 gap-2 mt-2",children:Object.entries(d.params).map(([h,x])=>a.jsx(j0,{name:h,schema:x,value:c[h],onChange:w=>o(m,{[h]:w})},h))})]}),a.jsx("button",{type:"button",onClick:()=>l(m),className:"p-1 text-[var(--text-secondary)] hover:text-[var(--error)] transition-colors",children:a.jsx(Pm,{size:16})})]})},m)})})]})}function j0({name:e,schema:t,value:n,onChange:r}){const s=e.replace(/_/g," ");return t.type==="boolean"?a.jsxs("label",{className:"flex items-center gap-2 text-xs",children:[a.jsx("input",{type:"checkbox",checked:!!(n??t.default),onChange:i=>r(i.target.checked),className:"accent-[var(--accent)]"}),a.jsx("span",{className:"capitalize",children:s})]}):a.jsxs("div",{children:[a.jsx("label",{className:"text-xs font-medium block mb-1 capitalize",children:s}),a.jsx("input",{type:t.type==="number"?"number":"text",className:"w-full px-2 py-1 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-xs",value:String(n!==void 0?n:t.default??""),onChange:i=>{if(t.type==="number"){const l=parseFloat(i.target.value);r(isNaN(l)?t.default:l)}else r(i.target.value)},min:t.min,max:t.max,step:t.max&&t.max<=1?.1:1})]})}function w0({variations:e,onChange:t,providers:n}){const r=()=>{const o=n[0],u={provider:(o==null?void 0:o.name)||"azure_openai",model:(o==null?void 0:o.models[0])||"gpt-4o"};t([...e,u])},s=o=>{t(e.filter((u,c)=>c!==o))},i=(o,u)=>{t(e.map((c,m)=>m===o?{...c,...u}:c))},l=(o,u)=>{const c=n.find(m=>m.name===u);i(o,{provider:u,model:(c==null?void 0:c.models[0])||""})};return a.jsxs("div",{className:"space-y-3",children:[a.jsxs("div",{className:"flex items-center justify-between",children:[a.jsx("label",{className:"text-sm font-medium",children:"LLM Configurations"}),a.jsx(K,{type:"button",variant:"ghost",size:"sm",icon:Ia,onClick:r,children:"Add"})]}),e.length===0?a.jsx("p",{className:"text-sm text-[var(--text-secondary)] italic",children:`Uses agent's default LLM. Click "Add" to test different models.`}):a.jsx("div",{className:"space-y-2",children:e.map((o,u)=>{const c=n.find(m=>m.name===o.provider);return a.jsxs("div",{className:"flex items-center gap-2 p-2 border border-[var(--border)] rounded bg-[var(--bg-secondary)]",children:[a.jsx("select",{className:"flex-1 px-2 py-1.5 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm",value:o.provider,onChange:m=>l(u,m.target.value),children:n.map(m=>a.jsx("option",{value:m.name,children:m.label},m.name))}),c&&c.models.length>0?a.jsxs("select",{className:"flex-1 px-2 py-1.5 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm",value:o.model,onChange:m=>i(u,{model:m.target.value}),children:[c.models.map(m=>a.jsx("option",{value:m,children:m},m)),!c.models.includes(o.model)&&o.model&&a.jsx("option",{value:o.model,children:o.model})]}):a.jsx("input",{type:"text",className:"flex-1 px-2 py-1.5 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm",value:o.model,onChange:m=>i(u,{model:m.target.value}),placeholder:"Model ID"}),a.jsx("button",{type:"button",onClick:()=>s(u),className:"p-1 text-[var(--text-secondary)] hover:text-[var(--error)] transition-colors",children:a.jsx(Pm,{size:16})})]},u)})})]})}const Ro={compaction:[],tools:[],llm_config:[],instructions:[],instruction_strategies:[]};function k0({agentId:e,agentName:t,agentFramework:n="maf",taskSuite:r,taskCount:s,schema:i,onVariationsChange:l,parallel:o,onParallelChange:u,budget:c,onBudgetChange:m,useLlmEval:d,onUseLlmEvalChange:h}){const[x,w]=k.useState(Ro),[y,S]=k.useState(!1),[v,f]=k.useState(""),[p,j]=k.useState(null),C=i.frameworks[n],N=(C==null?void 0:C.compaction_strategies)||Object.keys(i.compaction_strategies),b=i.tool_presets||[],E=i.llm_providers||[],O=(()=>{let R=1;x.compaction.length>0&&(R*=x.compaction.length),x.tools.length>0&&(R*=x.tools.length),x.llm_config.length>0&&(R*=x.llm_config.length);const H=x.instructions.length+x.instruction_strategies.reduce((M,P)=>M+P.max_candidates,0);return H>0&&(R*=H),Math.min(R,c)})(),Q=O*s,D=R=>{w(R),l==null||l(R)},$=Ge({mutationFn:R=>Oo.design(R),onSuccess:R=>{f(R.yaml_content),S(!0)}}),te=Ge({mutationFn:R=>Oo.validate(R),onSuccess:R=>{j({valid:R.valid,errors:R.errors,warnings:R.warnings})}}),me=()=>({base_agent_id:e,task_suite:r,variations:x,parallel:o,budget:c,use_llm_eval:d}),et=()=>{$.mutate(me())},be=()=>{te.mutate(me())},L=()=>{const R=new Blob([v],{type:"text/yaml"}),H=URL.createObjectURL(R),M=document.createElement("a");M.href=H,M.download=`${t}_experiment.yaml`,M.click(),URL.revokeObjectURL(H)},A=x.compaction.length>0||x.tools.length>0||x.llm_config.length>0||x.instructions.length>0||x.instruction_strategies.length>0;return a.jsxs("div",{className:"space-y-6",children:[a.jsxs("div",{className:"flex flex-wrap gap-2",children:[a.jsxs(q,{variant:"info",children:[O," candidates"]}),a.jsxs(q,{children:[s," tasks"]}),a.jsxs(q,{variant:Q>100?"warning":"success",children:[Q," total runs"]})]}),a.jsx(y0,{variations:x.compaction,onChange:R=>D({...x,compaction:R}),strategies:i.compaction_strategies,availableStrategies:N}),a.jsxs("div",{className:"space-y-3",children:[a.jsx("label",{className:"text-sm font-medium",children:"Tool Presets"}),a.jsx("div",{className:"flex flex-wrap gap-2",children:b.map(R=>a.jsxs("label",{className:`flex items-center gap-2 px-3 py-1.5 border rounded cursor-pointer transition-colors ${x.tools.includes(R.name)?"border-[var(--accent)] bg-[var(--accent)]/10":"border-[var(--border)] hover:border-[var(--accent-dim)]"}`,children:[a.jsx("input",{type:"checkbox",checked:x.tools.includes(R.name),onChange:H=>{const M=H.target.checked?[...x.tools,R.name]:x.tools.filter(P=>P!==R.name);D({...x,tools:M})},className:"accent-[var(--accent)]"}),a.jsx("span",{className:"text-sm",children:R.name}),a.jsxs("span",{className:"text-xs text-[var(--text-secondary)]",children:["(",R.tools.length,")"]})]},R.name))}),x.tools.length>0&&a.jsxs("p",{className:"text-xs text-[var(--text-secondary)]",children:["Selected: ",x.tools.join(", ")]})]}),a.jsx(w0,{variations:x.llm_config,onChange:R=>D({...x,llm_config:R}),providers:E}),a.jsxs("div",{className:"border-t border-[var(--border)] pt-4 space-y-4",children:[a.jsx("h4",{className:"text-sm font-medium",children:"Execution Settings"}),a.jsxs("div",{className:"grid grid-cols-2 gap-4",children:[a.jsx(fn,{label:"Parallel Workers",type:"number",value:o,onChange:R=>u(parseInt(R.target.value)||1),min:1,max:16}),a.jsx(fn,{label:"Budget (max candidates)",type:"number",value:c,onChange:R=>m(parseInt(R.target.value)||100),min:1,max:1e3})]}),a.jsx(Lo,{label:"Use LLM evaluation",checked:d,onChange:R=>h(R.target.checked)}),a.jsx("p",{className:"text-xs text-[var(--text-secondary)] ml-6 -mt-2",children:d?"LLM-as-Judge scores task completion (0-1)":"Simple pass/fail based on task success"})]}),a.jsxs("div",{className:"flex items-center gap-2 border-t border-[var(--border)] pt-4",children:[a.jsx(K,{variant:"secondary",size:"sm",onClick:be,loading:te.isPending,children:"Validate"}),a.jsx(K,{variant:"secondary",size:"sm",icon:jd,onClick:et,loading:$.isPending,children:"Export YAML"})]}),p&&a.jsxs("div",{className:`p-3 rounded border ${p.valid?"border-green-500/50 bg-green-500/10":"border-red-500/50 bg-red-500/10"}`,children:[a.jsxs("div",{className:"flex items-center gap-2 mb-2",children:[p.valid?a.jsx(Nm,{size:16,className:"text-green-500"}):a.jsx(Sm,{size:16,className:"text-red-500"}),a.jsx("span",{className:"font-medium text-sm",children:p.valid?"Configuration valid":"Configuration has issues"})]}),p.errors.length>0&&a.jsx("ul",{className:"text-sm text-red-500 list-disc ml-6",children:p.errors.map((R,H)=>a.jsx("li",{children:R},H))}),p.warnings.length>0&&a.jsx("ul",{className:"text-sm text-yellow-500 list-disc ml-6 mt-1",children:p.warnings.map((R,H)=>a.jsx("li",{children:R},H))})]}),y&&a.jsx("div",{className:"fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4",children:a.jsxs("div",{className:"bg-[var(--bg-primary)] rounded-lg shadow-xl max-w-2xl w-full max-h-[80vh] flex flex-col",children:[a.jsxs("div",{className:"flex items-center justify-between p-4 border-b border-[var(--border)]",children:[a.jsx("h3",{className:"font-medium",children:"Experiment YAML"}),a.jsxs("div",{className:"flex items-center gap-2",children:[a.jsx(K,{variant:"secondary",size:"sm",icon:jd,onClick:L,children:"Download"}),a.jsx(K,{variant:"ghost",size:"sm",onClick:()=>S(!1),children:"Close"})]})]}),a.jsx("pre",{className:"flex-1 overflow-auto p-4 text-xs font-mono bg-[var(--bg-secondary)]",children:v})]})}),!A&&a.jsx("p",{className:"text-sm text-[var(--text-secondary)] italic",children:"No variations selected. Only the baseline agent will be tested. Add compaction strategies, tool presets, or LLM configs to generate candidates."})]})}function bd(){const e=Et(),t=Pn(),[n,r]=k.useState(!1),[s,i]=k.useState(null),{data:l=[],isLoading:o}=ve({queryKey:["configs"],queryFn:()=>br.list()}),{data:u=[]}=ve({queryKey:["jobs"],queryFn:()=>_t.list()}),c=Ge({mutationFn:br.create,onSuccess:()=>{t.invalidateQueries({queryKey:["configs"]}),r(!1)}}),m=Ge({mutationFn:br.delete,onSuccess:()=>t.invalidateQueries({queryKey:["configs"]})}),d=h=>{const x=u.filter(S=>S.candidate_ids.includes(h)),w=x.filter(S=>S.status==="running").length,y=x.filter(S=>S.status==="completed").length;return{running:w,completed:y,total:x.length}};return a.jsxs("div",{children:[a.jsxs("div",{className:"flex items-center justify-between mb-6",children:[a.jsxs("div",{children:[a.jsx("h2",{className:"text-xl font-bold",children:"Agents"}),a.jsx("p",{className:"text-sm text-[var(--text-secondary)] mt-1",children:"Define and optimize your agent configurations."})]}),a.jsx(K,{variant:"primary",icon:Ia,onClick:()=>r(!0),children:"New Agent"})]}),o?a.jsxs("div",{className:"flex items-center gap-2 text-[var(--text-secondary)]",children:[a.jsx(Fa,{size:16,className:"animate-spin"}),"Loading agents..."]}):l.length===0?a.jsx(S0,{onCreateClick:()=>r(!0)}):a.jsx("div",{className:"grid gap-4 md:grid-cols-2 lg:grid-cols-3",children:l.map(h=>{const x=d(h.id);return a.jsx(b0,{agent:h,stats:x,onClick:()=>e(`/agents/${h.id}`),onOptimize:()=>i(h),onDelete:()=>{confirm(`Delete agent "${h.name}"?`)&&m.mutate(h.id)}},h.id)})}),u.length>0&&a.jsxs("div",{className:"mt-8",children:[a.jsx("h3",{className:"text-lg font-medium mb-4",children:"Recent Optimization Jobs"}),a.jsx("div",{className:"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4",children:u.slice(0,6).map(h=>a.jsx(Fm,{job:h},h.id))}),u.length>6&&a.jsxs(K,{variant:"ghost",className:"mt-4",onClick:()=>e("/jobs"),children:["View all ",u.length," jobs →"]})]}),a.jsx(C0,{isOpen:n,onClose:()=>r(!1),onSubmit:h=>c.mutate(h),isLoading:c.isPending}),s&&a.jsx(_0,{agent:s,isOpen:!!s,onClose:()=>i(null)})]})}function S0({onCreateClick:e}){return a.jsxs("div",{className:"text-center py-16 border border-dashed border-[var(--border)] rounded-lg",children:[a.jsx("div",{className:"inline-flex items-center justify-center w-12 h-12 rounded-full bg-[var(--bg-tertiary)] mb-4",children:a.jsx(Cm,{size:24,className:"text-[var(--text-secondary)]"})}),a.jsx("h3",{className:"text-lg font-medium mb-2",children:"No agents yet"}),a.jsx("p",{className:"text-[var(--text-secondary)] mb-4 max-w-md mx-auto",children:"Create your first agent to start optimizing. Each agent defines instructions, model, compaction strategy, and tool settings."}),a.jsx(K,{variant:"primary",icon:Ia,onClick:e,children:"Create Your First Agent"})]})}function N0(e){return typeof e=="string"?`tools: ${e}`:Array.isArray(e)?`tools: [${e.length}]`:typeof e=="object"?`tools: [${Object.keys(e).length}]`:"tools: standard"}function b0({agent:e,stats:t,onClick:n,onOptimize:r,onDelete:s}){const i=e.config.compaction,l=(i==null?void 0:i.strategy)==="head_tail"?`compaction ${i.params.head_size}/${i.params.tail_size}`:(i==null?void 0:i.strategy)==="none"?null:(i==null?void 0:i.strategy)||null,o=N0(e.config.tools),u=e.config.framework||"maf";return a.jsxs(re,{className:"flex flex-col cursor-pointer hover:border-[var(--accent-dim)] transition-colors",onClick:n,children:[a.jsxs("div",{className:"flex-1",children:[a.jsxs("div",{className:"flex items-start justify-between mb-3",children:[a.jsxs("div",{children:[a.jsx("h3",{className:"font-medium text-lg",children:e.name}),e.description&&a.jsx("p",{className:"text-sm text-[var(--text-secondary)] mt-1",children:e.description})]}),a.jsx(K,{variant:"ghost",size:"sm",icon:_m,onClick:c=>{c.stopPropagation(),s()}})]}),a.jsxs("div",{className:"flex flex-wrap gap-1.5 mb-4",children:[a.jsx(q,{variant:u==="miniagent"?"success":"default",children:u}),l&&a.jsx(q,{children:l}),a.jsx(q,{children:o})]}),t.total>0&&a.jsxs("div",{className:"text-xs text-[var(--text-secondary)] mb-3",children:[t.running>0&&a.jsxs("span",{className:"text-[var(--accent)]",children:[t.running," running "]}),t.completed>0&&a.jsxs("span",{children:[t.completed," completed"]})]})]}),a.jsx("div",{className:"flex gap-2",children:a.jsx(K,{variant:"primary",icon:Da,onClick:c=>{c.stopPropagation(),r()},className:"flex-1",children:"Optimize"})})]})}function C0({isOpen:e,onClose:t,onSubmit:n,isLoading:r}){var be,L,A,R,H,M,P;const s=["read_file","write_file","edit_file","bash","grep","think"],[i,l]=k.useState({name:"",description:"",instructions:null,model:null,compaction:{strategy:"none",params:{}},tools:s,framework:"maf",llm_config_id:null}),[o,u]=k.useState(!1),[c,m]=k.useState("custom"),[d,h]=k.useState([...s]),[x,w]=k.useState(!1),{data:y}=ve({queryKey:["agent-schema"],queryFn:()=>zm.getAgentSchema()}),{data:S=[]}=ve({queryKey:["llm-configs"],queryFn:()=>n0.list()}),{data:v}=ve({queryKey:["tools"],queryFn:()=>r0.list()}),f=((be=v==null?void 0:v.tools)==null?void 0:be.map(_=>_.name))??s,p=(v==null?void 0:v.presets)??{},j=Object.keys(p),C=(y==null?void 0:y.frameworks)??{},N=Object.keys(C).length>0?Object.keys(C):m0,b=i.framework||"maf",E=((A=(L=y==null?void 0:y.frameworks)==null?void 0:L[b])==null?void 0:A.compaction_strategies)??["none","head_tail"],F=(y==null?void 0:y.compaction_strategies)??{},O=_=>{if(_.preventDefault(),!i.name.trim())return;const B={...i};c==="custom"&&(B.tools=d),n(B)},Q=((R=i.compaction)==null?void 0:R.strategy)!=="none",D=((H=i.compaction)==null?void 0:H.strategy)||"none",$=F[D],te=_=>{h(B=>B.includes(_)?B.filter(Z=>Z!==_):[...B,_])},me=_=>{const B=F[_],Z={};if(B!=null&&B.params)for(const[ge,Zr]of Object.entries(B.params))Zr.default!==void 0&&(Z[ge]=Zr.default);l({...i,compaction:{strategy:_,params:Z}})},et=a.jsxs("div",{className:"flex justify-end gap-2",children:[a.jsx(K,{type:"button",variant:"secondary",onClick:t,children:"Cancel"}),a.jsx(K,{type:"submit",form:"create-agent-form",variant:"primary",disabled:!i.name.trim(),loading:r,children:"Create Agent"})]});return a.jsx(ai,{isOpen:e,onClose:t,title:"Create Agent",footer:et,children:a.jsxs("form",{id:"create-agent-form",onSubmit:O,className:"space-y-4",children:[a.jsx(fn,{label:"Name",value:i.name,onChange:_=>l({...i,name:_.target.value}),placeholder:"e.g., my-coding-agent",required:!0}),a.jsxs("div",{children:[a.jsx("label",{className:"text-sm font-medium block mb-1.5",children:"LLM Configuration"}),a.jsxs("select",{className:"w-full px-3 py-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm",value:i.llm_config_id||"",onChange:_=>l({...i,llm_config_id:_.target.value||null}),children:[a.jsx("option",{value:"",children:"Use environment variables"}),S.map(_=>a.jsxs("option",{value:_.id,children:[_.name," (",v0[_.provider],_.model_id?` - ${_.model_id}`:"",")",_.is_default?" (default)":""]},_.id))]}),a.jsx("p",{className:"text-xs text-[var(--text-secondary)] mt-1",children:S.length===0?"No LLM configs found. Uses environment variables (AZURE_OPENAI_ENDPOINT, OPENAI_API_KEY, etc.)":i.llm_config_id?"Uses the selected LLM configuration.":"Uses environment variables (AZURE_OPENAI_ENDPOINT, OPENAI_API_KEY, etc.)"})]}),a.jsxs("div",{children:[a.jsx("label",{className:"text-sm font-medium block mb-1.5",children:"Framework"}),a.jsx("select",{className:"w-full px-3 py-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm",value:i.framework||"maf",onChange:_=>{const B=_.target.value;l({...i,framework:B,compaction:{strategy:"none",params:{}}})},children:N.map(_=>{var B;return a.jsx("option",{value:_,children:((B=C[_])==null?void 0:B.label)||p0[_]||_},_)})}),a.jsx("p",{className:"text-xs text-[var(--text-secondary)] mt-1",children:((M=C[b])==null?void 0:M.description)||(b==="miniagent"?"Lightweight agent with token-aware context management.":b==="langgraph"?"Graph-based workflows with state management.":"Default agent implementation.")})]}),a.jsxs("div",{className:"grid grid-cols-2 gap-4",children:[a.jsx(Lo,{label:"Custom instructions",checked:o,onChange:_=>{u(_.target.checked),_.target.checked||l({...i,instructions:null})}}),a.jsx(Lo,{label:"Enable compaction",checked:Q,onChange:_=>{if(_.target.checked){const B=E.find(Z=>Z!=="none")||"head_tail";me(B)}else l({...i,compaction:{strategy:"none",params:{}}})}})]}),o&&a.jsx("textarea",{className:"w-full h-32 px-3 py-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm font-mono resize-y",value:i.instructions||"",onChange:_=>l({...i,instructions:_.target.value||null}),placeholder:"System prompt / instructions for the agent..."}),Q&&a.jsxs("div",{className:"space-y-3 p-3 border border-[var(--border)] rounded bg-[var(--bg-secondary)]",children:[a.jsxs("div",{children:[a.jsx("label",{className:"text-sm font-medium block mb-1.5",children:"Compaction Strategy"}),a.jsx("select",{className:"w-full px-3 py-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm",value:D,onChange:_=>me(_.target.value),children:E.filter(_=>_!=="none").map(_=>{var B;return a.jsx("option",{value:_,children:((B=F[_])==null?void 0:B.label)||_},_)})}),($==null?void 0:$.description)&&a.jsx("p",{className:"text-xs text-[var(--text-secondary)] mt-1",children:$.description})]}),($==null?void 0:$.params)&&Object.keys($.params).length>0&&a.jsx("div",{className:"grid grid-cols-2 gap-3",children:Object.entries($.params).map(([_,B])=>{var Zr;const Z=(Zr=i.compaction)==null?void 0:Zr.params[_],ge=Z!==void 0?Z:B.default;return a.jsxs("div",{children:[a.jsx("label",{className:"text-xs font-medium block mb-1 capitalize",children:_.replace(/_/g," ")}),a.jsx("input",{type:"number",className:"w-full px-3 py-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm",value:typeof ge=="number"?ge:Number(ge)||0,onChange:Qm=>{const Qu=parseFloat(Qm.target.value);l({...i,compaction:{...i.compaction,params:{...i.compaction.params,[_]:isNaN(Qu)?typeof B.default=="number"?B.default:0:Qu}}})},min:B.min,max:B.max,step:B.max&&B.max<=1?.1:1}),a.jsx("p",{className:"text-xs text-[var(--text-secondary)] mt-0.5",children:B.description})]},_)})})]}),a.jsxs("div",{className:"space-y-2",children:[a.jsx("label",{className:"text-sm font-medium",children:"Tools"}),a.jsxs("div",{className:"flex gap-4",children:[a.jsxs("label",{className:"flex items-center gap-2",children:[a.jsx("input",{type:"radio",checked:c==="custom",onChange:()=>m("custom"),className:"accent-[var(--accent)]"}),a.jsx("span",{className:"text-sm",children:"Custom"})]}),a.jsxs("label",{className:"flex items-center gap-2",children:[a.jsx("input",{type:"radio",checked:c==="preset",onChange:()=>m("preset"),className:"accent-[var(--accent)]"}),a.jsx("span",{className:"text-sm",children:"Preset"})]})]}),c==="custom"?a.jsx("div",{className:"grid grid-cols-2 gap-1 p-2 border border-[var(--border)] rounded bg-[var(--bg-secondary)]",children:f.map(_=>a.jsxs("label",{className:"flex items-center gap-2 p-1 text-sm cursor-pointer hover:bg-[var(--bg-tertiary)]",children:[a.jsx("input",{type:"checkbox",checked:d.includes(_),onChange:()=>te(_),className:"accent-[var(--accent)]"}),a.jsx("span",{className:"font-mono text-xs",children:_})]},_))}):a.jsxs(a.Fragment,{children:[a.jsx("select",{className:"w-full px-3 py-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm",value:typeof i.tools=="string"?i.tools:"standard",onChange:_=>l({...i,tools:_.target.value}),children:j.map(_=>a.jsx("option",{value:_,children:_},_))}),a.jsx("p",{className:"text-xs text-[var(--text-secondary)] mt-1",children:((P=p[typeof i.tools=="string"?i.tools:"standard"])==null?void 0:P.join(", "))??""})]})]}),a.jsxs("div",{className:"border-t border-[var(--border)] pt-3",children:[a.jsxs("button",{type:"button",className:"flex items-center gap-2 text-sm text-[var(--text-secondary)] hover:text-[var(--text-primary)] transition-colors",onClick:()=>w(!x),children:[a.jsx(Ss,{size:14,className:`transition-transform ${x?"rotate-90":""}`}),"More options"]}),x&&a.jsx("div",{className:"mt-3",children:a.jsx(fn,{label:"Description (optional)",value:i.description,onChange:_=>l({...i,description:_.target.value}),placeholder:"Brief description of this agent"})})]})]})})}function _0({agent:e,isOpen:t,onClose:n}){var H;const r=Et(),s=Pn(),[i,l]=k.useState("suite"),[o,u]=k.useState("quick"),[c,m]=k.useState(!1),[d,h]=k.useState([]),[x,w]=k.useState(Ro),[y,S]=k.useState(4),[v,f]=k.useState(100),[p,j]=k.useState(!1),[C,N]=k.useState(null),{data:b=[]}=ve({queryKey:["tasks"],queryFn:()=>Dt.list()}),{data:E=[]}=ve({queryKey:["suites"],queryFn:()=>Dt.listSuites()}),{data:F}=ve({queryKey:["agent-schema"],queryFn:()=>zm.getAgentSchema()}),O=E.map(M=>({value:M.name,label:M.name.charAt(0).toUpperCase()+M.name.slice(1),description:M.description,tasks:M.task_count})),Q=Ge({mutationFn:Dt.importSuite,onSuccess:M=>{s.invalidateQueries({queryKey:["tasks"]}),h(M.map(P=>P.id))}}),D=Ge({mutationFn:async M=>{const P=await _t.create(M);return _t.start(P.id).next(),P},onSuccess:M=>{s.invalidateQueries({queryKey:["jobs"]}),N(M.id),l("success")}}),te=(()=>{let M=1;x.compaction.length>0&&(M*=x.compaction.length),x.tools.length>0&&(M*=x.tools.length),x.llm_config.length>0&&(M*=x.llm_config.length);const P=x.instructions.length+x.instruction_strategies.reduce((_,B)=>_+B.max_candidates,0);return P>0&&(M*=P),Math.min(M,v)})(),me=c?d.length:((H=O.find(M=>M.value===o))==null?void 0:H.tasks)||3,et=te*me,be=async()=>{l("starting");let M=d;if(!c)try{M=(await Q.mutateAsync(o)).map(ge=>ge.id)}catch(Z){console.error("Failed to import suite:",Z),alert(`Failed to import task suite: ${o}`),l("design");return}if(M.length===0){alert("No tasks selected. Please select tasks or choose a task suite."),l("design");return}let P;if(x.compaction.length>0||x.tools.length>0||x.llm_config.length>0||x.instructions.length>0||x.instruction_strategies.length>0)try{P=(await Oo.generateCandidates({base_agent_id:e.id,variations:x,budget:v})).candidate_ids}catch(Z){console.error("Failed to generate candidates:",Z),alert(`Failed to generate candidates: ${Z instanceof Error?Z.message:"Unknown error"}`),l("design");return}else P=[e.id];const B={name:`${e.name} optimization (${P.length} candidates × ${M.length} tasks)`,candidate_ids:P,task_ids:M,parallel:y,use_llm_eval:p};D.mutate(B)},L=M=>{h(P=>P.includes(M)?P.filter(_=>_!==M):[...P,M])},A=()=>{l("suite"),N(null),w(Ro),n()},R=()=>i==="success"&&C?a.jsxs("div",{className:"flex justify-end gap-3",children:[a.jsx(K,{variant:"secondary",onClick:A,children:"Close"}),a.jsx(K,{variant:"primary",icon:Hs,onClick:()=>{A(),r(`/jobs/${C}`)},children:"View Job"})]}):i==="starting"?null:i==="design"?a.jsxs("div",{className:"flex justify-between gap-2",children:[a.jsx(K,{variant:"secondary",icon:hy,onClick:()=>l("suite"),children:"Back"}),a.jsxs(K,{variant:"primary",icon:Hs,onClick:be,children:["Start Optimization (",et," runs)"]})]}):a.jsxs("div",{className:"flex justify-end gap-2",children:[a.jsx(K,{variant:"secondary",onClick:n,children:"Cancel"}),a.jsx(K,{variant:"primary",icon:Ss,onClick:()=>l("design"),disabled:c&&d.length===0,children:"Next: Experiment Design"})]});return a.jsx(ai,{isOpen:t,onClose:A,title:`Optimize: ${e.name}`,footer:R(),children:i==="success"&&C?a.jsxs("div",{className:"flex flex-col items-center py-8",children:[a.jsx("div",{className:"w-12 h-12 rounded-full bg-green-500/20 flex items-center justify-center mb-4",children:a.jsx(Da,{size:24,className:"text-green-500"})}),a.jsx("h3",{className:"text-lg font-medium mb-2",children:"Job Started!"}),a.jsx("p",{className:"text-[var(--text-secondary)] text-center mb-2",children:"Optimization job is now running"}),a.jsxs("code",{className:"text-xs bg-[var(--bg-primary)] px-3 py-1.5 rounded font-mono",children:["ID: ",C.slice(0,8),"..."]})]}):i==="starting"?a.jsxs("div",{className:"flex flex-col items-center py-8",children:[a.jsx(Fa,{size:32,className:"animate-spin text-[var(--accent)] mb-4"}),a.jsx("p",{className:"text-[var(--text-secondary)]",children:Q.isPending?"Importing tasks...":"Creating optimization job..."})]}):i==="design"&&F?a.jsxs("div",{className:"space-y-6",children:[a.jsxs("div",{className:"flex items-center gap-2 text-sm text-[var(--text-secondary)]",children:[a.jsx("span",{className:"text-[var(--text-primary)]",children:"1. Tasks"}),a.jsx(Ss,{size:14}),a.jsx("span",{className:"text-[var(--accent)] font-medium",children:"2. Experiment Design"})]}),a.jsx(k0,{agentId:e.id,agentName:e.name,agentFramework:e.config.framework,taskSuite:c?void 0:o,taskCount:me,schema:F,onVariationsChange:w,parallel:y,onParallelChange:S,budget:v,onBudgetChange:f,useLlmEval:p,onUseLlmEvalChange:j})]}):a.jsxs("div",{className:"space-y-6",children:[a.jsxs("div",{className:"flex items-center gap-2 text-sm text-[var(--text-secondary)]",children:[a.jsx("span",{className:"text-[var(--accent)] font-medium",children:"1. Tasks"}),a.jsx(Ss,{size:14}),a.jsx("span",{children:"2. Experiment Design"})]}),a.jsxs("div",{children:[a.jsx("label",{className:"text-sm font-medium mb-3 block",children:"Select Task Suite"}),a.jsx("div",{className:"space-y-2",children:O.map(M=>{const P=b.filter(_=>_.suite===M.value).length;return a.jsxs("label",{className:`flex items-center gap-3 p-3 border cursor-pointer transition-colors ${o===M.value&&!c?"border-[var(--accent)] bg-[var(--accent)]/10":"border-[var(--border)] hover:border-[var(--accent-dim)]"}`,children:[a.jsx("input",{type:"radio",name:"suite",value:M.value,checked:o===M.value&&!c,onChange:()=>{u(M.value),m(!1)},className:"accent-[var(--accent)]"}),a.jsxs("div",{className:"flex-1",children:[a.jsxs("div",{className:"flex items-center gap-2",children:[a.jsx("span",{className:"font-medium",children:M.label}),a.jsxs(q,{children:[M.tasks," tasks"]}),P>0&&a.jsxs(q,{variant:"success",children:[P," imported"]})]}),a.jsx("p",{className:"text-sm text-[var(--text-secondary)]",children:M.description})]})]},M.value)})})]}),b.length>0&&a.jsxs("div",{children:[a.jsxs("label",{className:`flex items-center gap-3 p-3 border cursor-pointer transition-colors ${c?"border-[var(--accent)] bg-[var(--accent)]/10":"border-[var(--border)] hover:border-[var(--accent-dim)]"}`,children:[a.jsx("input",{type:"radio",checked:c,onChange:()=>m(!0),className:"accent-[var(--accent)]"}),a.jsxs("div",{className:"flex-1",children:[a.jsx("span",{className:"font-medium",children:"Custom Selection"}),a.jsx("p",{className:"text-sm text-[var(--text-secondary)]",children:"Choose specific tasks from your library"})]})]}),c&&a.jsx("div",{className:"mt-3 max-h-48 overflow-y-auto border border-[var(--border)] p-2 space-y-1",children:b.map(M=>a.jsxs("label",{className:"flex items-center gap-2 p-2 hover:bg-[var(--bg-tertiary)] cursor-pointer",children:[a.jsx("input",{type:"checkbox",checked:d.includes(M.id),onChange:()=>L(M.id),className:"accent-[var(--accent)]"}),a.jsx("span",{className:"text-sm",children:M.name}),M.suite&&a.jsx(q,{children:M.suite})]},M.id))})]})]})})}function E0(e){const t=[],n=r=>r.type==="trace_span"&&typeof r.data=="object"&&r.data!==null?r.data:"span_id"in r?r:null;if(Array.isArray(e.spans)){for(const r of e.spans)if(typeof r=="object"&&r!==null){const s=n(r);s&&t.push(s)}}else if(e.span_id)t.push(e);else for(const r in e){const s=e[r];if(typeof s=="object"&&s!==null){const i=n(s);if(i)t.push(i);else if(Array.isArray(s)){for(const l of s)if(typeof l=="object"&&l!==null){const o=n(l);o&&t.push(o)}}}}return t}function Im(e){const t=new Map,n=[];for(const s of e)t.set(s.span_id,{span:s,children:[]});for(const s of e){const i=t.get(s.span_id);s.parent_span_id&&t.has(s.parent_span_id)?t.get(s.parent_span_id).children.push(i):n.push(i)}const r=s=>{s.sort((i,l)=>(i.span.start_time||0)-(l.span.start_time||0)),s.forEach(i=>r(i.children))};return r(n),n}function P0(e){return e.includes("Agent")||e.includes("agent")?"bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-200":e.includes("chat")||e.includes("Chat")||e.includes("llm")?"bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200":e.includes("tool")||e.includes("execute")||e.includes("bash")?"bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200":"bg-orange-100 text-orange-800 dark:bg-orange-900 dark:text-orange-200"}function T0(e){return e>=1e3?`${(e/1e3).toFixed(2)}s`:`${e.toFixed(0)}ms`}function Bu({node:e,depth:t=0}){var d,h;const[n,r]=k.useState(t<2),[s,i]=k.useState(!1),{span:l}=e,o=e.children.length>0,u=(d=l.attributes)==null?void 0:d["gen_ai.usage.input_tokens"],c=(h=l.attributes)==null?void 0:h["gen_ai.usage.output_tokens"],m=u!==void 0||c!==void 0;return a.jsxs("div",{className:"relative",children:[t>0&&a.jsx("div",{className:"absolute left-0 top-0 bottom-0 border-l-2 border-[var(--border)]",style:{marginLeft:`${(t-1)*16+8}px`}}),a.jsxs("div",{className:"flex items-center gap-2 py-1.5 px-1 hover:bg-[var(--bg-primary)] rounded transition-colors cursor-pointer",style:{paddingLeft:`${t*16}px`},onClick:()=>o?r(!n):i(!s),children:[a.jsx("div",{className:"w-4 h-4 flex items-center justify-center text-[var(--text-secondary)]",children:o?n?"▼":"▶":s?"▼":"▶"}),a.jsx("span",{className:`text-xs px-1.5 py-0.5 rounded font-medium ${P0(l.operation_name)}`,children:l.operation_name.replace("ChatAgent.","").replace("invoke_agent ","")}),l.duration_ms!==void 0&&a.jsx("span",{className:"text-xs text-[var(--text-secondary)] font-mono",children:T0(l.duration_ms)}),m&&a.jsxs("span",{className:"text-xs text-[var(--text-secondary)] font-mono",children:[u!==void 0&&a.jsxs("span",{className:"text-blue-400",children:["↑",String(u)]}),u!==void 0&&c!==void 0&&a.jsx("span",{className:"mx-0.5",children:"/"}),c!==void 0&&a.jsxs("span",{className:"text-green-400",children:["↓",String(c)]})]})]}),s&&!o&&a.jsx("div",{className:"ml-4 mt-1 mb-2 p-2 bg-[var(--bg-primary)] rounded border border-[var(--border)] text-xs",style:{marginLeft:`${t*16+20}px`},children:a.jsxs("div",{className:"space-y-1",children:[l.span_id&&a.jsxs("div",{className:"flex gap-2",children:[a.jsx("span",{className:"text-[var(--text-secondary)] w-20",children:"Span ID:"}),a.jsx("span",{className:"font-mono text-xs break-all",children:l.span_id})]}),l.trace_id&&a.jsxs("div",{className:"flex gap-2",children:[a.jsx("span",{className:"text-[var(--text-secondary)] w-20",children:"Trace ID:"}),a.jsx("span",{className:"font-mono text-xs break-all",children:l.trace_id})]}),l.status&&a.jsxs("div",{className:"flex gap-2",children:[a.jsx("span",{className:"text-[var(--text-secondary)] w-20",children:"Status:"}),a.jsx("span",{className:`px-1.5 py-0.5 rounded text-xs ${l.status==="OK"||l.status==="StatusCode.UNSET"?"bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200":"bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200"}`,children:l.status})]}),Object.keys(l.attributes||{}).length>0&&a.jsxs("div",{className:"mt-2",children:[a.jsx("span",{className:"text-[var(--text-secondary)] block mb-1",children:"Attributes:"}),a.jsx("pre",{className:"text-xs bg-[var(--bg-secondary)] border border-[var(--border)] rounded p-2 overflow-auto max-h-32 whitespace-pre-wrap break-all",children:JSON.stringify(l.attributes,null,2)})]})]})}),o&&n&&a.jsx("div",{children:e.children.map((x,w)=>a.jsx(Bu,{node:x,depth:t+1},x.span.span_id||w))})]})}function Dm({trace:e}){const[t,n]=k.useState("tree"),r=k.useMemo(()=>E0(e),[e]),s=k.useMemo(()=>Im(r),[r]);return Object.keys(e).length===0?null:a.jsxs(re,{className:"mb-6",children:[a.jsxs("div",{className:"flex items-center justify-between mb-3",children:[a.jsx("h3",{className:"font-medium",children:"Trace Data"}),a.jsxs("div",{className:"flex gap-1",children:[a.jsx("button",{onClick:()=>n("tree"),className:`px-2 py-1 text-xs rounded ${t==="tree"?"bg-[var(--accent)] text-white":"bg-[var(--bg-primary)] text-[var(--text-secondary)] hover:text-[var(--text-primary)]"}`,children:"Tree"}),a.jsx("button",{onClick:()=>n("raw"),className:`px-2 py-1 text-xs rounded ${t==="raw"?"bg-[var(--accent)] text-white":"bg-[var(--bg-primary)] text-[var(--text-secondary)] hover:text-[var(--text-primary)]"}`,children:"Raw"})]})]}),t==="tree"?r.length>0?a.jsx("div",{className:"border border-[var(--border)] rounded overflow-hidden",children:a.jsxs("div",{className:"p-2",children:[a.jsxs("div",{className:"flex items-center gap-2 mb-2 text-xs text-[var(--text-secondary)]",children:[a.jsxs(q,{variant:"default",children:[r.length," spans"]}),a.jsx("span",{children:"•"}),a.jsx("span",{children:"Click to expand details"})]}),s.map((i,l)=>a.jsx(Bu,{node:i,depth:0},i.span.span_id||l))]})}):a.jsx("div",{className:"text-sm text-[var(--text-secondary)] text-center py-4",children:"No structured spans found. View raw data below."}):a.jsx("pre",{className:"text-xs bg-[var(--bg-primary)] p-3 overflow-x-auto border border-[var(--border)] max-h-96 whitespace-pre-wrap",children:JSON.stringify(e,null,2)})]})}function O0({spans:e,isLive:t=!1}){const n=k.useRef(null),r=k.useMemo(()=>Im(e),[e]);return k.useEffect(()=>{n.current&&t&&n.current.scrollTo({top:n.current.scrollHeight,behavior:"smooth"})},[e.length,t]),a.jsxs("div",{className:"border border-[var(--border)] rounded overflow-hidden h-full flex flex-col",children:[a.jsxs("div",{className:"flex items-center gap-2 p-2 border-b border-[var(--border)] bg-[var(--bg-secondary)]",children:[a.jsxs(q,{variant:"default",children:[e.length," spans"]}),t&&a.jsx("span",{className:"animate-pulse",children:a.jsx(q,{variant:"info",children:"Live"})})]}),a.jsx("div",{ref:n,className:"flex-1 overflow-auto p-2",children:r.length>0?r.map((s,i)=>a.jsx(Bu,{node:s,depth:0},s.span.span_id||i)):a.jsx("div",{className:"text-sm text-[var(--text-secondary)] text-center py-4",children:t?"Waiting for spans...":"No spans recorded"})})]})}function L0({agent:e}){const[t,n]=k.useState(""),[r,s]=k.useState(null),[i,l]=k.useState("idle"),[o,u]=k.useState(null),[c,m]=k.useState(""),[d,h]=k.useState([]),[x,w]=k.useState(null),[y,S]=k.useState(null),[v,f]=k.useState([]),p=k.useRef(null),{data:j=[]}=ve({queryKey:["tasks"],queryFn:()=>Dt.list()});k.useEffect(()=>{p.current&&i==="running"&&(p.current.scrollTop=p.current.scrollHeight)},[c,i]);const C=D=>{if(s(D),D){const $=j.find(te=>te.id===D);$&&n($.prompt)}},N=async()=>{if(t.trim()){l("running"),m(""),h([]),w(null),S(null),f([]);try{const D=await Ns.create({agent_id:e.id,prompt:t.trim(),task_id:r||void 0});u(D.id);for await(const $ of Ns.start(D.id))b($)}catch(D){S(D instanceof Error?D.message:"Test failed"),l("failed")}}},b=D=>{switch(D.event){case"started":break;case"execution":D.execution_event==="text_delta"&&D.content?m($=>$+D.content):D.execution_event==="tool_call_start"&&D.tool_name?f($=>[...$,{name:D.tool_name}]):D.execution_event==="tool_result"&&D.content&&f($=>{if($.length>0){const te=[...$];return te[te.length-1]={...te[te.length-1],content:D.content},te}return $});break;case"span":if(D.span){const $=D.span;if($.data){const te={span_id:$.data.span_id||"",trace_id:$.data.trace_id||"",parent_span_id:$.data.parent_span_id||null,operation_name:$.data.operation_name||"",start_time:$.timestamp?new Date($.timestamp).getTime():Date.now(),end_time:Date.now(),duration_ms:$.data.duration_ms||0,status:$.data.status||"OK",attributes:$.data.attributes||{}};h(me=>[...me,te])}}break;case"complete":l("completed"),D.result&&w(D.result);break;case"error":S(D.message),l("failed");break}},E=async()=>{if(o)try{await Ns.cancel(o)}catch{}l("idle")},F=()=>{l("idle"),u(null),m(""),h([]),w(null),S(null),f([])},O=i==="running",Q=i==="completed"||i==="failed";return a.jsxs("div",{className:"h-full flex flex-col",children:[!O&&!Q&&a.jsxs("div",{className:"mb-4 space-y-3",children:[a.jsxs("div",{className:"flex gap-3",children:[a.jsxs("div",{className:"flex-1",children:[a.jsx("label",{className:"block text-sm font-medium mb-1",children:"Select Task (optional)"}),a.jsxs("select",{value:r||"",onChange:D=>C(D.target.value||null),className:"w-full px-3 py-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm",children:[a.jsx("option",{value:"",children:"Custom prompt..."}),j.map(D=>a.jsx("option",{value:D.id,children:D.name},D.id))]})]}),a.jsx("div",{className:"flex items-end",children:a.jsx(K,{variant:"primary",icon:Hs,onClick:N,disabled:!t.trim(),children:"Run Test"})})]}),a.jsxs("div",{children:[a.jsx("label",{className:"block text-sm font-medium mb-1",children:"Prompt"}),a.jsx("textarea",{value:t,onChange:D=>n(D.target.value),placeholder:"Enter a test prompt for the agent...",className:"w-full h-32 px-3 py-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm font-mono resize-none"})]})]}),(O||Q)&&a.jsxs("div",{className:"flex-1 flex flex-col min-h-0",children:[a.jsxs("div",{className:"flex items-center justify-between mb-3",children:[a.jsxs("div",{className:"flex items-center gap-2",children:[O&&a.jsxs(a.Fragment,{children:[a.jsx("span",{className:"animate-pulse",children:a.jsx(q,{variant:"info",children:"Running"})}),a.jsx(K,{variant:"ghost",size:"sm",icon:Cy,onClick:E,children:"Cancel"})]}),i==="completed"&&a.jsx(q,{variant:"success",children:"Completed"}),i==="failed"&&a.jsx(q,{variant:"error",children:"Failed"})]}),a.jsxs("div",{className:"flex items-center gap-3",children:[x&&a.jsxs("div",{className:"flex items-center gap-3 text-xs text-[var(--text-secondary)]",children:[a.jsxs("span",{className:"flex items-center gap-1",children:[a.jsx(my,{size:12}),x.duration_seconds.toFixed(2),"s"]}),a.jsxs("span",{className:"flex items-center gap-1",children:[a.jsx(py,{size:12}),x.tokens_total," tokens"]}),x.passed!==null&&(x.passed?a.jsx(Nm,{size:14,className:"text-green-500"}):a.jsx(Ey,{size:14,className:"text-red-500"}))]}),Q&&a.jsx(K,{variant:"secondary",size:"sm",onClick:F,children:"New Test"})]})]}),a.jsxs("div",{className:"flex-1 grid grid-cols-2 gap-4 min-h-0",children:[a.jsxs("div",{className:"flex flex-col border border-[var(--border)] rounded overflow-hidden",children:[a.jsx("div",{className:"px-3 py-2 border-b border-[var(--border)] bg-[var(--bg-secondary)] text-sm font-medium",children:"Output"}),a.jsxs("div",{ref:p,className:"flex-1 overflow-auto p-3 font-mono text-sm whitespace-pre-wrap bg-[var(--bg-primary)]",children:[c||(O?"Waiting for response...":"No output"),v.length>0&&a.jsxs("div",{className:"mt-3 space-y-2 border-t border-[var(--border)] pt-3",children:[a.jsx("div",{className:"text-xs text-[var(--text-secondary)] uppercase tracking-wider",children:"Tool Calls"}),v.map((D,$)=>a.jsxs("div",{className:"p-2 bg-green-500/10 border border-green-500/20 rounded text-xs",children:[a.jsx(q,{variant:"success",children:D.name}),D.content&&a.jsxs("div",{className:"mt-1 text-[var(--text-secondary)] truncate max-w-full",children:[D.content.substring(0,200),D.content.length>200&&"..."]})]},$))]})]})]}),a.jsx(O0,{spans:d,isLive:O})]}),y&&a.jsx("div",{className:"mt-3 p-3 bg-red-500/10 border border-red-500/20 rounded text-sm text-red-400",children:y}),Q&&o&&a.jsx("div",{className:"mt-3 flex items-center justify-end pt-3 border-t border-[var(--border)]",children:a.jsx(Ks,{to:`/tests/${o}`,children:a.jsx(K,{variant:"primary",iconRight:xy,children:"View Full Details"})})})]})]})}function R0(){const{agentId:e}=Ra(),t=Et(),n=Pn(),[r,s]=k.useState("overview"),{data:i,isLoading:l}=ve({queryKey:["configs",e],queryFn:()=>br.get(e),enabled:!!e}),{data:o=[]}=ve({queryKey:["tests",{agent_id:e}],queryFn:()=>Ns.list({agent_id:e}),enabled:!!e}),{data:u=[]}=ve({queryKey:["jobs"],queryFn:()=>_t.list()}),c=Ge({mutationFn:d=>br.delete(d),onSuccess:()=>{n.invalidateQueries({queryKey:["configs"]}),t("/agents")}}),m=u.filter(d=>d.candidate_ids.includes(e||""));return l?a.jsx("div",{className:"text-[var(--text-secondary)]",children:"Loading..."}):i?a.jsxs("div",{className:"h-full flex flex-col",children:[a.jsxs("div",{className:"mb-6",children:[a.jsx("div",{className:"flex items-center gap-3 mb-2",children:a.jsx("button",{onClick:()=>t("/agents"),className:"text-[var(--text-secondary)] hover:text-[var(--text-primary)]",children:"← Back to Agents"})}),a.jsxs("div",{className:"flex items-center justify-between",children:[a.jsxs("div",{className:"flex items-center gap-3",children:[a.jsx("h2",{className:"text-xl font-bold",children:i.name}),i.is_auto_generated&&a.jsx(q,{variant:"info",children:"Auto-generated"})]}),a.jsx("div",{className:"flex gap-2",children:a.jsx(K,{variant:"secondary",icon:_m,onClick:()=>{confirm(`Delete agent "${i.name}"?`)&&c.mutate(i.id)},children:"Delete"})})]}),i.description&&a.jsx("p",{className:"text-sm text-[var(--text-secondary)] mt-1",children:i.description})]}),a.jsxs("div",{className:"flex gap-1 mb-6 border-b border-[var(--border)]",children:[a.jsx(vl,{active:r==="overview",onClick:()=>s("overview"),icon:a.jsx(Cm,{size:16}),children:"Overview"}),a.jsx(vl,{active:r==="test",onClick:()=>s("test"),icon:a.jsx(Hs,{size:16}),children:"Test"}),a.jsx(vl,{active:r==="history",onClick:()=>s("history"),icon:a.jsx(jy,{size:16}),badge:o.length,children:"History"})]}),a.jsxs("div",{className:"flex-1 min-h-0",children:[r==="overview"&&a.jsx(M0,{agent:i,recentTests:o,jobs:m}),r==="test"&&a.jsx(L0,{agent:i}),r==="history"&&a.jsx(z0,{tests:o})]})]}):a.jsx("div",{className:"text-[var(--text-secondary)]",children:"Agent not found"})}function vl({active:e,onClick:t,icon:n,badge:r,children:s}){return a.jsxs("button",{onClick:t,className:`flex items-center gap-2 px-4 py-2 text-sm font-medium border-b-2 transition-colors ${e?"border-[var(--accent)] text-[var(--text-primary)]":"border-transparent text-[var(--text-secondary)] hover:text-[var(--text-primary)]"}`,children:[n,s,r!==void 0&&r>0&&a.jsx("span",{className:"ml-1 px-1.5 py-0.5 text-xs bg-[var(--bg-tertiary)] rounded",children:r})]})}function M0({agent:e,recentTests:t,jobs:n}){var l,o,u,c,m,d;const r=Et(),s=e.config,i=()=>{const h=s.tools;return typeof h=="string"?h:Array.isArray(h)?h.join(", "):typeof h=="object"?Object.keys(h).join(", "):"standard"};return a.jsxs("div",{className:"space-y-6",children:[a.jsxs(re,{children:[a.jsx("h3",{className:"font-medium mb-4",children:"Configuration"}),a.jsxs("div",{className:"grid grid-cols-2 gap-4 text-sm",children:[a.jsxs("div",{children:[a.jsx("span",{className:"text-[var(--text-secondary)]",children:"Model:"}),a.jsx("div",{className:"font-mono",children:s.model||"default"})]}),a.jsxs("div",{children:[a.jsx("span",{className:"text-[var(--text-secondary)]",children:"Compaction:"}),a.jsx("div",{className:"font-mono",children:((l=s.compaction)==null?void 0:l.strategy)==="none"?"disabled":`${(o=s.compaction)==null?void 0:o.strategy} (${((c=(u=s.compaction)==null?void 0:u.params)==null?void 0:c.head_size)||0}/${((d=(m=s.compaction)==null?void 0:m.params)==null?void 0:d.tail_size)||0})`})]}),a.jsxs("div",{className:"col-span-2",children:[a.jsx("span",{className:"text-[var(--text-secondary)]",children:"Tools:"}),a.jsx("div",{className:"font-mono",children:i()})]}),s.instructions&&a.jsxs("div",{className:"col-span-2",children:[a.jsx("span",{className:"text-[var(--text-secondary)]",children:"Instructions:"}),a.jsx("pre",{className:"mt-1 p-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-xs whitespace-pre-wrap max-h-32 overflow-auto",children:s.instructions})]})]})]}),a.jsxs(re,{children:[a.jsxs("div",{className:"flex items-center justify-between mb-4",children:[a.jsx("h3",{className:"font-medium",children:"Recent Tests"}),t.length>0&&a.jsxs("span",{className:"text-xs text-[var(--text-secondary)]",children:[t.length," total"]})]}),t.length===0?a.jsx("div",{className:"text-sm text-[var(--text-secondary)] text-center py-4",children:'No tests yet. Click the "Test" tab to run one.'}):a.jsx("div",{className:"space-y-2",children:t.slice(0,5).map(h=>a.jsxs(Ks,{to:`/tests/${h.id}`,className:"flex items-center justify-between p-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded hover:border-[var(--accent-dim)] transition-colors",children:[a.jsxs("div",{className:"flex items-center gap-2",children:[a.jsx(Am,{status:h.status}),a.jsxs("span",{className:"text-sm truncate max-w-[200px]",children:[h.prompt.slice(0,50),"..."]})]}),a.jsxs("div",{className:"flex items-center gap-3 text-xs text-[var(--text-secondary)]",children:[a.jsxs("span",{children:[h.duration_seconds.toFixed(1),"s"]}),a.jsxs("span",{children:[h.tokens_total," tok"]})]})]},h.id))})]}),a.jsxs(re,{children:[a.jsxs("div",{className:"flex items-center justify-between mb-4",children:[a.jsx("h3",{className:"font-medium",children:"Optimization Jobs"}),a.jsx(K,{variant:"secondary",size:"sm",icon:Da,onClick:()=>r("/agents",{state:{optimizeAgent:e}}),children:"New Job"})]}),n.length===0?a.jsx("div",{className:"text-sm text-[var(--text-secondary)] text-center py-4",children:"No optimization jobs yet."}):a.jsx("div",{className:"space-y-2",children:n.slice(0,5).map(h=>a.jsxs(Ks,{to:`/jobs/${h.id}`,className:"flex items-center justify-between p-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded hover:border-[var(--accent-dim)] transition-colors",children:[a.jsxs("div",{className:"flex items-center gap-2",children:[a.jsx(q,{variant:h.status==="completed"?"success":h.status==="running"?"info":"default",children:h.status}),a.jsx("span",{className:"text-sm",children:h.name})]}),a.jsx("span",{className:"text-xs text-[var(--text-secondary)]",children:new Date(h.created_at).toLocaleDateString()})]},h.id))})]})]})}function z0({tests:e}){return e.length===0?a.jsx("div",{className:"text-center py-8 text-[var(--text-secondary)]",children:"No test history yet. Run a test to see results here."}):a.jsx("div",{className:"space-y-2",children:e.map(t=>a.jsxs(Ks,{to:`/tests/${t.id}`,className:"flex items-center justify-between p-3 bg-[var(--bg-secondary)] border border-[var(--border)] rounded hover:border-[var(--accent-dim)] transition-colors",children:[a.jsxs("div",{className:"flex-1 min-w-0",children:[a.jsxs("div",{className:"flex items-center gap-2 mb-1",children:[a.jsx(Am,{status:t.status}),t.score!==null&&a.jsxs("span",{className:`text-sm font-medium ${t.passed?"text-green-400":"text-red-400"}`,children:[(t.score*100).toFixed(0),"%"]})]}),a.jsx("p",{className:"text-sm truncate",children:t.prompt})]}),a.jsxs("div",{className:"flex flex-col items-end gap-1 ml-4",children:[a.jsx("span",{className:"text-xs text-[var(--text-secondary)]",children:new Date(t.created_at).toLocaleString()}),a.jsxs("div",{className:"flex items-center gap-2 text-xs text-[var(--text-secondary)]",children:[a.jsxs("span",{children:[t.duration_seconds.toFixed(1),"s"]}),a.jsx("span",{children:"•"}),a.jsxs("span",{children:[t.tokens_total," tokens"]})]})]})]},t.id))})}function Am({status:e}){const t={completed:"success",failed:"error",running:"info",cancelled:"warning",pending:"default"};return a.jsx(q,{variant:t[e]||"default",children:e})}const $m=Fu(e=>({tasks:[],selectedTaskIds:[],setTasks:t=>e({tasks:t}),toggleTaskSelection:t=>e(n=>({selectedTaskIds:n.selectedTaskIds.includes(t)?n.selectedTaskIds.filter(r=>r!==t):[...n.selectedTaskIds,t]})),jobs:[],setJobs:t=>e({jobs:t})}));function F0(){const e=Pn(),[t,n]=k.useState(!1),[r,s]=k.useState(!1),[i,l]=k.useState(new Set(["custom"])),{selectedTaskIds:o,toggleTaskSelection:u,setTasks:c}=$m(),m=f=>{l(p=>{const j=new Set(p);return j.has(f)?j.delete(f):j.add(f),j})},{data:d=[],isLoading:h}=ve({queryKey:["tasks"],queryFn:()=>Dt.list()});k.useEffect(()=>{d.length>0&&c(d)},[d,c]);const x=Ge({mutationFn:Dt.create,onSuccess:()=>{e.invalidateQueries({queryKey:["tasks"]}),n(!1)}}),w=Ge({mutationFn:Dt.importSuite,onSuccess:()=>{e.invalidateQueries({queryKey:["tasks"]}),s(!1)}}),y=Ge({mutationFn:Dt.delete,onSuccess:()=>e.invalidateQueries({queryKey:["tasks"]})}),S=d.reduce((f,p)=>{const j=p.suite||"custom";return f[j]||(f[j]=[]),f[j].push(p),f},{}),v=Object.keys(S).sort((f,p)=>f==="custom"?-1:p==="custom"?1:f.localeCompare(p));return a.jsxs("div",{children:[a.jsxs("div",{className:"flex items-center justify-between mb-6",children:[a.jsxs("div",{children:[a.jsx("h2",{className:"text-xl font-bold",children:"Tasks"}),a.jsxs("p",{className:"text-sm text-[var(--text-secondary)] mt-1",children:["Define tasks to evaluate agent configurations.",o.length>0&&a.jsxs("span",{className:"ml-2 text-[var(--accent)]",children:[o.length," selected"]})]})]}),a.jsxs("div",{className:"flex gap-2",children:[a.jsx(K,{variant:"secondary",onClick:()=>s(!0),children:"Import Suite"}),a.jsx(K,{variant:"primary",onClick:()=>n(!0),children:"+ New Task"})]})]}),h?a.jsx("div",{className:"text-[var(--text-secondary)]",children:"Loading..."}):d.length===0?a.jsx("div",{className:"text-center py-12 text-[var(--text-secondary)]",children:"No tasks yet. Create one or import a built-in suite."}):a.jsx("div",{className:"space-y-4",children:v.map(f=>{const p=S[f],j=i.has(f),C=p.filter(N=>o.includes(N.id)).length;return a.jsxs("div",{children:[a.jsxs("button",{onClick:()=>m(f),className:"flex items-center gap-2 py-2 hover:text-[var(--accent)] transition-colors",children:[j?a.jsx(fy,{size:16,className:"text-[var(--text-secondary)]"}):a.jsx(Ss,{size:16,className:"text-[var(--text-secondary)]"}),a.jsx("h3",{className:"text-sm font-medium uppercase tracking-wide",children:f==="custom"?"Custom Tasks":`${f} Suite`}),a.jsx(q,{variant:f==="custom"?"default":"info",children:p.length}),C>0&&a.jsxs(q,{variant:"success",children:[C," selected"]})]}),j&&a.jsx("div",{className:"grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-3 mt-2",children:p.map(N=>a.jsx(re,{selectable:!0,selected:o.includes(N.id),onClick:()=>u(N.id),children:a.jsxs("div",{className:"flex flex-col h-full",children:[a.jsxs("div",{className:"flex items-start justify-between gap-2",children:[a.jsxs("div",{className:"flex items-center gap-2 flex-wrap",children:[a.jsx("span",{className:"font-medium",children:N.name}),o.includes(N.id)&&a.jsx(q,{variant:"success",children:"Selected"}),N.category&&N.category!=="default"&&a.jsx(q,{variant:"default",children:N.category})]}),a.jsx(K,{variant:"ghost",size:"sm",onClick:b=>{b.stopPropagation(),confirm("Delete this task?")&&y.mutate(N.id)},children:"Delete"})]}),a.jsx("p",{className:"text-sm text-[var(--text-secondary)] mt-2 line-clamp-3 flex-1",children:N.prompt}),N.criteria.length>0&&a.jsx("div",{className:"flex gap-1 mt-2 flex-wrap",children:N.criteria.map(b=>a.jsx(q,{variant:"default",children:b.name},b.name))})]})},N.id))})]},f)})}),a.jsx(I0,{isOpen:t,onClose:()=>n(!1),onSubmit:f=>x.mutate(f),isLoading:x.isPending}),a.jsx(D0,{isOpen:r,onClose:()=>s(!1),onSubmit:f=>w.mutate(f),isLoading:w.isPending})]})}function I0({isOpen:e,onClose:t,onSubmit:n,isLoading:r}){const[s,i]=k.useState({name:"",prompt:"",criteria:[],category:"default"}),l=()=>{i({...s,criteria:[...s.criteria,{name:"",instruction:"",weight:1}]})},o=(m,d)=>{const h=[...s.criteria];h[m]={...h[m],...d},i({...s,criteria:h})},u=m=>{i({...s,criteria:s.criteria.filter((d,h)=>h!==m)})},c=m=>{m.preventDefault(),!(!s.name.trim()||!s.prompt.trim())&&n({...s,criteria:s.criteria.filter(d=>d.name.trim()&&d.instruction.trim())})};return a.jsx(ai,{isOpen:e,onClose:t,title:"Create Task",children:a.jsxs("form",{onSubmit:c,className:"space-y-4",children:[a.jsx(fn,{label:"Name",value:s.name,onChange:m=>i({...s,name:m.target.value}),placeholder:"e.g., fizzbuzz",required:!0}),a.jsx(g0,{label:"Prompt",value:s.prompt,onChange:m=>i({...s,prompt:m.target.value}),placeholder:"The task description for the agent...",required:!0}),a.jsx(fn,{label:"Category",value:s.category,onChange:m=>i({...s,category:m.target.value}),placeholder:"e.g., coding, research"}),a.jsxs("div",{children:[a.jsxs("div",{className:"flex items-center justify-between mb-2",children:[a.jsx("label",{className:"text-sm text-[var(--text-secondary)]",children:"Evaluation Criteria"}),a.jsx(K,{type:"button",variant:"ghost",size:"sm",onClick:l,children:"+ Add"})]}),a.jsx("div",{className:"space-y-2",children:s.criteria.map((m,d)=>a.jsxs("div",{className:"flex gap-2 items-start",children:[a.jsx(fn,{value:m.name,onChange:h=>o(d,{name:h.target.value}),placeholder:"Name",className:"w-32"}),a.jsx(fn,{value:m.instruction,onChange:h=>o(d,{instruction:h.target.value}),placeholder:"Instruction",className:"flex-1"}),a.jsx(K,{type:"button",variant:"ghost",size:"sm",onClick:()=>u(d),children:"×"})]},d))})]}),a.jsxs("div",{className:"flex justify-end gap-2 pt-4",children:[a.jsx(K,{type:"button",variant:"secondary",onClick:t,children:"Cancel"}),a.jsx(K,{type:"submit",variant:"primary",disabled:r||!s.name.trim()||!s.prompt.trim(),children:r?"Creating...":"Create"})]})]})})}function D0({isOpen:e,onClose:t,onSubmit:n,isLoading:r}){const[s,i]=k.useState(""),{data:l=[],isLoading:o}=ve({queryKey:["suites"],queryFn:()=>Dt.listSuites(),enabled:e});return k.useEffect(()=>{l.length>0&&!s&&i(l[0].name)},[l,s]),a.jsx(ai,{isOpen:e,onClose:t,title:"Import Task Suite",children:a.jsxs("div",{className:"space-y-4",children:[a.jsx("p",{className:"text-sm text-[var(--text-secondary)]",children:"Import a built-in task suite for evaluation."}),o?a.jsx("div",{className:"text-[var(--text-secondary)]",children:"Loading suites..."}):l.length===0?a.jsx("div",{className:"text-[var(--text-secondary)]",children:"No suites available."}):a.jsx("div",{className:"space-y-2 max-h-80 overflow-y-auto",children:l.map(u=>a.jsxs("label",{className:`flex items-center gap-3 p-3 border cursor-pointer ${s===u.name?"border-[var(--accent)] bg-[var(--accent)]/10":"border-[var(--border)] hover:border-[var(--accent-dim)]"}`,children:[a.jsx("input",{type:"radio",name:"suite",value:u.name,checked:s===u.name,onChange:()=>i(u.name),className:"accent-[var(--accent)]"}),a.jsxs("span",{className:"capitalize",children:[u.name.replace(/_/g," ")," (",u.task_count," tasks) - ",u.description]})]},u.name))}),a.jsxs("div",{className:"flex justify-end gap-2 pt-4",children:[a.jsx(K,{type:"button",variant:"secondary",onClick:t,children:"Cancel"}),a.jsx(K,{variant:"primary",onClick:()=>n(s),disabled:r||!s,children:r?"Importing...":"Import"})]})]})})}function A0(){const e=Et(),t=Pn(),[n,r]=k.useState(!1),{setJobs:s}=$m(),i=$u(),{data:l=[],isLoading:o}=ve({queryKey:["jobs",n],queryFn:()=>_t.list({include_public:n}),refetchInterval:5e3});k.useEffect(()=>{l.length>0&&s(l)},[l,s]);const u=Ge({mutationFn:_t.delete,onSuccess:()=>t.invalidateQueries({queryKey:["jobs"]})});return a.jsxs("div",{children:[a.jsxs("div",{className:"flex items-center justify-between mb-6",children:[a.jsxs("div",{children:[a.jsx("h2",{className:"text-xl font-bold",children:"Optimization Jobs"}),a.jsx("p",{className:"text-sm text-[var(--text-secondary)] mt-1",children:"View and manage optimization experiments. Start new jobs from the Agents page."})]}),a.jsxs("div",{className:"flex items-center gap-3",children:[a.jsxs("label",{className:"flex items-center gap-2 text-sm text-[var(--text-secondary)] cursor-pointer",children:[a.jsx("input",{type:"checkbox",checked:n,onChange:c=>r(c.target.checked),className:"rounded border-[var(--border)]"}),a.jsx(za,{className:"w-4 h-4"}),"Show public"]}),a.jsx(K,{variant:"secondary",onClick:()=>e("/agents"),children:"Go to Agents"})]})]}),o?a.jsx("div",{className:"text-[var(--text-secondary)]",children:"Loading..."}):l.length===0?a.jsx("div",{className:"text-center py-12 text-[var(--text-secondary)]",children:"No jobs yet. Go to Agents page to start an optimization."}):a.jsx("div",{className:"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4",children:l.map(c=>{const m=!c.user_id||c.user_id==="anonymous"||i&&c.created_by_name===i;return a.jsx(Fm,{job:c,onDelete:m?d=>u.mutate(d):void 0},c.id)})})]})}function $0(e,t=!0){return Math.abs(e)<10?"text-[var(--text-secondary)]":(t?e<0:e>0)?"text-green-400":"text-red-400"}function U0(e){return`${e>0?"+":""}${e.toFixed(1)}%`}function Um(e,t){return t===0?0:(e-t)/t*100}function os({label:e,values:t,baselineIndex:n,formatter:r,isLowerBetter:s=!0}){const i=t[n];return a.jsxs("tr",{className:"border-b border-[var(--border)] last:border-0",children:[a.jsx("td",{className:"py-2 pr-4 text-[var(--text-secondary)] text-sm",children:e}),t.map((l,o)=>{const u=Um(l,i),c=o===n;return a.jsxs("td",{className:"py-2 px-4 text-right",children:[a.jsx("div",{className:"font-mono",children:r(l)}),!c&&a.jsx("div",{className:`text-xs ${$0(u,s)}`,children:U0(u)}),c&&a.jsx("div",{className:"text-xs text-[var(--text-secondary)]",children:"(baseline)"})]},o)})]})}function B0({runs:e,baselineRunId:t}){const n=k.useMemo(()=>{if(t){const i=e.findIndex(l=>l.id===t);if(i>=0)return i}return 0},[e,t]);if(e.length<2)return null;const r=Math.min(...e.map(i=>i.tokens_total)),s=Math.max(...e.map(i=>i.score));return a.jsxs(re,{className:"mb-6",children:[a.jsx("h3",{className:"font-medium mb-4",children:"Candidate Comparison"}),a.jsx("div",{className:"overflow-x-auto",children:a.jsxs("table",{className:"w-full text-sm",children:[a.jsx("thead",{children:a.jsxs("tr",{className:"border-b border-[var(--border)]",children:[a.jsx("th",{className:"pb-2 pr-4 text-left text-[var(--text-secondary)] font-medium",children:"Metric"}),e.map((i,l)=>a.jsx("th",{className:"pb-2 px-4 text-right",children:a.jsxs("div",{className:"flex items-center justify-end gap-2",children:[a.jsx("span",{className:"font-medium",children:i.candidate_name}),i.is_pareto&&a.jsx(q,{variant:"success",children:"Pareto"}),l===n&&a.jsx(q,{variant:"info",children:"Base"})]})},i.id))]})}),a.jsxs("tbody",{children:[a.jsx(os,{label:"Total Tokens",values:e.map(i=>i.tokens_total),baselineIndex:n,formatter:i=>i.toLocaleString(),isLowerBetter:!0}),a.jsx(os,{label:"Input Tokens",values:e.map(i=>i.tokens_input),baselineIndex:n,formatter:i=>i.toLocaleString(),isLowerBetter:!0}),a.jsx(os,{label:"Output Tokens",values:e.map(i=>i.tokens_output),baselineIndex:n,formatter:i=>i.toLocaleString(),isLowerBetter:!0}),a.jsx(os,{label:"Duration",values:e.map(i=>i.duration_seconds),baselineIndex:n,formatter:i=>`${i.toFixed(1)}s`,isLowerBetter:!0}),a.jsx(os,{label:"Score",values:e.map(i=>i.score*100),baselineIndex:n,formatter:i=>`${i.toFixed(1)}%`,isLowerBetter:!1})]})]})}),a.jsxs("div",{className:"mt-4 pt-4 border-t border-[var(--border)]",children:[a.jsx("h4",{className:"text-sm font-medium mb-2 text-[var(--text-secondary)]",children:"Key Insights"}),a.jsxs("ul",{className:"text-sm space-y-1 text-[var(--text-secondary)]",children:[e.map(i=>{const l=Um(i.tokens_total,e[n].tokens_total);return i.tokens_total===r&&l<-5?a.jsxs("li",{className:"flex items-center gap-2",children:[a.jsx("span",{className:"text-green-400",children:"✓"}),a.jsxs("span",{children:[a.jsx("strong",{children:i.candidate_name})," uses ",Math.abs(l).toFixed(0),"% fewer tokens"]})]},`token-${i.id}`):null}),e.map(i=>i.score===s&&i.passed?a.jsxs("li",{className:"flex items-center gap-2",children:[a.jsx("span",{className:"text-green-400",children:"✓"}),a.jsxs("span",{children:[a.jsx("strong",{children:i.candidate_name})," achieved highest score (",(i.score*100).toFixed(0),"%)"]})]},`score-${i.id}`):null),e.filter(i=>i.is_pareto).length>0&&a.jsxs("li",{className:"flex items-center gap-2",children:[a.jsx("span",{className:"text-purple-400",children:"★"}),a.jsxs("span",{children:["Pareto-optimal candidates:"," ",e.filter(i=>i.is_pareto).map(i=>i.candidate_name).join(", ")]})]})]})]}),a.jsxs("div",{className:"mt-4 pt-4 border-t border-[var(--border)]",children:[a.jsx("h4",{className:"text-sm font-medium mb-3 text-[var(--text-secondary)]",children:"Token Efficiency"}),a.jsx("div",{className:"space-y-2",children:e.map(i=>{const l=i.tokens_total/e[n].tokens_total*100,o=i.tokens_total<=r;return a.jsxs("div",{className:"flex items-center gap-3",children:[a.jsx("div",{className:"w-24 text-sm truncate",title:i.candidate_name,children:i.candidate_name}),a.jsx("div",{className:"flex-1 h-6 bg-[var(--bg-primary)] rounded overflow-hidden",children:a.jsx("div",{className:`h-full transition-all duration-300 ${o?"bg-green-500":"bg-blue-500"}`,style:{width:`${Math.min(l,100)}%`}})}),a.jsx("div",{className:"w-20 text-right font-mono text-sm",children:i.tokens_total.toLocaleString()})]},i.id)})})]})]})}function Q0({summaries:e,height:t=350}){const n=k.useRef(null),[r,s]=k.useState(600),[i,l]=k.useState("tokens"),[o,u]=k.useState(null),[c,m]=k.useState({x:0,y:0});k.useEffect(()=>{const N=()=>{n.current&&s(n.current.clientWidth)};return N(),window.addEventListener("resize",N),()=>window.removeEventListener("resize",N)},[]);const d={top:30,right:30,bottom:50,left:60},h=r-d.left-d.right,x=t-d.top-d.bottom,w=N=>i==="tokens"?N.avg_tokens:N.avg_duration,{xScale:y,yScale:S,xTicks:v,yTicks:f,paretoLine:p}=k.useMemo(()=>{if(e.length===0||h<=0)return{xScale:()=>0,yScale:()=>0,xTicks:[],yTicks:[],paretoLine:[]};const N=e.map(w),b=e.map(L=>L.avg_score),E=Math.min(...N)*.9,F=Math.max(...N)*1.1,O=Math.min(...b,.5),Q=Math.min(Math.max(...b)*1.05,1),D=L=>(L-E)/(F-E)*h,$=L=>x-(L-O)/(Q-O)*x,te=Array.from({length:5},(L,A)=>E+A/4*(F-E)),me=Array.from({length:5},(L,A)=>O+A/4*(Q-O)),be=e.filter(L=>L.is_pareto).sort((L,A)=>w(L)-w(A)).map(L=>({x:D(w(L)),y:$(L.avg_score)}));return{xScale:D,yScale:$,xTicks:te,yTicks:me,paretoLine:be}},[e,h,x,i]);if(e.length===0)return a.jsx("div",{className:"text-center py-8 text-[var(--text-secondary)]",children:"No data to display"});const j=N=>i==="tokens"?N>=1e6?`${(N/1e6).toFixed(1)}M`:N>=1e3?`${(N/1e3).toFixed(0)}K`:N.toFixed(0):`${N.toFixed(1)}s`,C=(N,b)=>{var F;const E=(F=n.current)==null?void 0:F.getBoundingClientRect();E&&m({x:b.clientX-E.left,y:b.clientY-E.top}),u(N)};return a.jsxs("div",{ref:n,className:"w-full relative",children:[a.jsx("div",{className:"flex justify-end mb-2",children:a.jsxs("div",{className:"inline-flex rounded border border-[var(--border)] text-xs",children:[a.jsx("button",{className:`px-3 py-1 ${i==="tokens"?"bg-[var(--accent)] text-black":"text-[var(--text-secondary)] hover:text-[var(--text-primary)]"}`,onClick:()=>l("tokens"),children:"Tokens"}),a.jsx("button",{className:`px-3 py-1 ${i==="duration"?"bg-[var(--accent)] text-black":"text-[var(--text-secondary)] hover:text-[var(--text-primary)]"}`,onClick:()=>l("duration"),children:"Latency"})]})}),a.jsx("svg",{width:r,height:t,className:"font-mono text-xs",children:a.jsxs("g",{transform:`translate(${d.left}, ${d.top})`,children:[v.map((N,b)=>a.jsx("line",{x1:y(N),y1:0,x2:y(N),y2:x,stroke:"var(--border)",strokeDasharray:"2,2"},`x-grid-${b}`)),f.map((N,b)=>a.jsx("line",{x1:0,y1:S(N),x2:h,y2:S(N),stroke:"var(--border)",strokeDasharray:"2,2"},`y-grid-${b}`)),p.length>1&&a.jsx("polyline",{points:p.map(N=>`${N.x},${N.y}`).join(" "),fill:"none",stroke:"var(--accent)",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"}),e.slice().sort((N,b)=>(N.is_pareto?1:0)-(b.is_pareto?1:0)).map(N=>{const b=y(w(N)),E=S(N.avg_score),F=N.is_pareto,O=(o==null?void 0:o.candidate_name)===N.candidate_name;return a.jsxs("g",{onMouseEnter:Q=>C(N,Q),onMouseLeave:()=>u(null),children:[a.jsx("circle",{cx:b,cy:E,r:O?10:F?8:6,fill:F?"var(--accent)":"transparent",stroke:O?"var(--text-primary)":F?"var(--accent)":"var(--text-secondary)",strokeWidth:O?3:2,className:"cursor-pointer transition-all"}),F&&!O&&a.jsx("text",{x:b,y:E-12,textAnchor:"middle",fill:"var(--text-primary)",fontSize:10,className:"pointer-events-none",children:N.candidate_name.replace(/^baseline_/,"").slice(0,15)})]},N.candidate_name)}),a.jsx("line",{x1:0,y1:x,x2:h,y2:x,stroke:"var(--text-secondary)"}),v.map((N,b)=>a.jsxs("g",{transform:`translate(${y(N)}, ${x})`,children:[a.jsx("line",{y2:5,stroke:"var(--text-secondary)"}),a.jsx("text",{y:20,textAnchor:"middle",fill:"var(--text-secondary)",fontSize:10,children:j(N)})]},`x-tick-${b}`)),a.jsx("text",{x:h/2,y:x+40,textAnchor:"middle",fill:"var(--text-secondary)",fontSize:11,children:i==="tokens"?"Tokens (cost)":"Duration (latency)"}),a.jsx("line",{x1:0,y1:0,x2:0,y2:x,stroke:"var(--text-secondary)"}),f.map((N,b)=>a.jsxs("g",{transform:`translate(0, ${S(N)})`,children:[a.jsx("line",{x2:-5,stroke:"var(--text-secondary)"}),a.jsxs("text",{x:-10,textAnchor:"end",dominantBaseline:"middle",fill:"var(--text-secondary)",fontSize:10,children:[(N*100).toFixed(0),"%"]})]},`y-tick-${b}`)),a.jsx("text",{transform:`translate(-45, ${x/2}) rotate(-90)`,textAnchor:"middle",fill:"var(--text-secondary)",fontSize:11,children:"Score (quality)"})]})}),o&&a.jsxs("div",{className:"absolute z-10 bg-[var(--bg-secondary)] border border-[var(--border)] rounded-lg shadow-lg p-3 text-sm pointer-events-none",style:{left:Math.min(c.x+15,r-200),top:c.y-10,maxWidth:220},children:[a.jsx("div",{className:"font-medium text-[var(--text-primary)] truncate mb-2",children:o.candidate_name.replace(/^baseline_/,"")}),a.jsxs("div",{className:"grid grid-cols-2 gap-x-4 gap-y-1 text-xs",children:[a.jsx("span",{className:"text-[var(--text-secondary)]",children:"Score:"}),a.jsxs("span",{className:"text-right font-medium",children:[(o.avg_score*100).toFixed(1),"%"]}),a.jsx("span",{className:"text-[var(--text-secondary)]",children:"Tokens:"}),a.jsxs("span",{className:"text-right",children:[(o.avg_tokens/1e3).toFixed(1),"K"]}),a.jsx("span",{className:"text-[var(--text-secondary)]",children:"Duration:"}),a.jsxs("span",{className:"text-right",children:[o.avg_duration.toFixed(1),"s"]}),a.jsx("span",{className:"text-[var(--text-secondary)]",children:"Pass rate:"}),a.jsxs("span",{className:"text-right",children:[o.passed_runs,"/",o.total_runs]})]}),o.is_pareto&&a.jsx("div",{className:"mt-2 pt-2 border-t border-[var(--border)] text-xs text-[var(--accent)]",children:"Pareto optimal"})]})]})}function V0(e=2e3){const[t,n]=k.useState(!1),[r,s]=k.useState(null),i=k.useCallback(async o=>{try{return await navigator.clipboard.writeText(o),n(!0),s(null),setTimeout(()=>n(!1),e),!0}catch{return s("Failed to copy to clipboard"),n(!1),!1}},[e]),l=k.useCallback(()=>{n(!1),s(null)},[]);return{copy:i,copied:t,error:r,reset:l}}function K0({isOpen:e,onClose:t,title:n,itemId:r,itemType:s,isPublic:i,createdByName:l,onTogglePublic:o}){const[u,c]=k.useState(!1),{copy:m,copied:d}=V0(),h=`${window.location.origin}/${s}s/${r}`,x=async()=>{c(!0);try{await o(!i)}finally{c(!1)}},w=()=>{m(h)};return a.jsx(ai,{isOpen:e,onClose:t,title:n,children:a.jsxs("div",{className:"space-y-4",children:[a.jsxs("div",{className:"flex items-center justify-between p-3 bg-[var(--bg-tertiary)] rounded",children:[a.jsxs("div",{className:"flex items-center gap-3",children:[i?a.jsx(za,{className:"w-5 h-5 text-[var(--accent)]"}):a.jsx(bm,{className:"w-5 h-5 text-[var(--text-secondary)]"}),a.jsxs("div",{children:[a.jsx("div",{className:"font-medium",children:i?"Public":"Private"}),a.jsx("div",{className:"text-sm text-[var(--text-secondary)]",children:i?"Anyone with the link can view":"Only you can access"})]})]}),a.jsx("button",{onClick:x,disabled:u,className:`relative inline-flex h-6 w-11 items-center rounded-full transition-colors ${i?"bg-[var(--accent)]":"bg-[var(--border)]"} ${u?"opacity-50 cursor-not-allowed":""}`,children:a.jsx("span",{className:`inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${i?"translate-x-6":"translate-x-1"}`})})]}),i&&a.jsxs("div",{className:"space-y-2",children:[a.jsx("label",{className:"text-sm text-[var(--text-secondary)]",children:"Share link"}),a.jsxs("div",{className:"flex gap-2",children:[a.jsx("input",{type:"text",readOnly:!0,value:h,className:"flex-1 px-3 py-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm font-mono"}),a.jsx(K,{variant:"secondary",onClick:w,children:d?a.jsxs(a.Fragment,{children:[a.jsx(dy,{className:"w-4 h-4 mr-1"}),"Copied"]}):a.jsxs(a.Fragment,{children:[a.jsx(vy,{className:"w-4 h-4 mr-1"}),"Copy"]})})]})]}),l&&a.jsxs("div",{className:"text-sm text-[var(--text-secondary)]",children:["Created by ",a.jsx("span",{className:"text-[var(--text-primary)]",children:l})]}),a.jsx("div",{className:"text-xs text-[var(--text-secondary)] pt-2 border-t border-[var(--border)]",children:i?a.jsxs(a.Fragment,{children:[a.jsxs("p",{children:["Public ",s,"s can be viewed by anyone with the link."]}),a.jsxs("p",{className:"mt-1",children:["Only you can edit or delete this ",s,"."]})]}):a.jsxs("p",{children:["Make this ",s," public to share it with others."]})})]})})}function H0({job:e,onUpdate:t}){const[n,r]=k.useState(!1),s=async i=>{await _t.update(e.id,{is_public:i}),t()};return a.jsxs(a.Fragment,{children:[a.jsxs(K,{variant:"secondary",size:"sm",onClick:()=>r(!0),title:e.is_public?"Sharing settings":"Share this job",children:[a.jsx(by,{className:"w-4 h-4 mr-1"}),e.is_public?"Shared":"Share"]}),a.jsx(K0,{isOpen:n,onClose:()=>r(!1),title:"Share Job",itemId:e.id,itemType:"job",isPublic:e.is_public,createdByName:e.created_by_name,onTogglePublic:s})]})}function W0(){const{jobId:e}=Ra(),t=Et(),n=Pn(),[r,s]=k.useState(null),[i,l]=k.useState(!1),[o,u]=k.useState(null),[c,m]=k.useState([]),[d,h]=k.useState(null),[x,w]=k.useState(null),[y,S]=k.useState("results"),[v,f]=k.useState("score"),[p,j]=k.useState("desc"),[C,N]=k.useState(!1),{data:b,isLoading:E}=ve({queryKey:["jobs",e],queryFn:()=>_t.get(e),enabled:!!e,refetchInterval:i?2e3:!1}),{data:F=[]}=ve({queryKey:["runs",e],queryFn:()=>To.list({job_id:e}),enabled:!!e,refetchInterval:i?2e3:!1}),{data:O}=ve({queryKey:["job-summary",e],queryFn:()=>To.getJobSummary(e),enabled:!!e&&(b==null?void 0:b.status)==="completed"}),Q=Ge({mutationFn:async()=>{l(!0),m([]),h(null),w(null);for await(const P of _t.start(e))s(P),P.current_candidate&&P.current_task&&h(_=>(_&&(_.candidate!==P.current_candidate||_.task!==P.current_task)&&m(B=>[...B,{candidate_name:_.candidate,task_name:_.task,completed_at:Date.now()}]),{candidate:P.current_candidate,task:P.current_task})),P.event==="error"&&(w(P.message),l(!1),n.invalidateQueries({queryKey:["jobs",e]})),P.event==="complete"&&(h(_=>(_&&m(B=>[...B,{candidate_name:_.candidate,task_name:_.task,completed_at:Date.now()}]),null)),l(!1),n.invalidateQueries({queryKey:["jobs",e]}),n.invalidateQueries({queryKey:["runs",e]}),n.invalidateQueries({queryKey:["job-summary",e]}))}}),D=Ge({mutationFn:()=>_t.cancel(e),onSuccess:()=>{l(!1),n.invalidateQueries({queryKey:["jobs",e]})}});k.useEffect(()=>{(b==null?void 0:b.status)==="running"&&l(!0)},[b==null?void 0:b.status]);const $=k.useMemo(()=>{const P=new Map;for(const _ of F)P.has(_.task_name)||P.set(_.task_name,[]),P.get(_.task_name).push(_);return P},[F]),te=k.useMemo(()=>Array.from($.keys()),[$]),me=k.useMemo(()=>{if(!(O!=null&&O.candidate_summaries))return[];let P=[...O.candidate_summaries];return C&&(P=P.filter(_=>_.is_pareto)),P.sort((_,B)=>{let Z,ge;switch(v){case"score":Z=_.avg_score,ge=B.avg_score;break;case"tokens":Z=_.avg_tokens,ge=B.avg_tokens;break;case"duration":Z=_.avg_duration,ge=B.avg_duration;break;case"pass_rate":Z=_.passed_runs/_.total_runs,ge=B.passed_runs/B.total_runs;break}return p==="desc"?ge-Z:Z-ge}),P},[O,v,p,C]),et=P=>{v===P?j(p==="desc"?"asc":"desc"):(f(P),j(P==="tokens"||P==="duration"?"asc":"desc"))},be=({label:P,sortKeyVal:_})=>a.jsx("th",{className:"pb-2 cursor-pointer hover:text-[var(--text-primary)] select-none",onClick:()=>et(_),children:a.jsxs("div",{className:"flex items-center gap-1",children:[P,v===_&&a.jsx(oy,{size:12,className:p==="asc"?"rotate-180":""})]})});if(E)return a.jsx("div",{className:"text-[var(--text-secondary)]",children:"Loading..."});if(!b)return a.jsx("div",{className:"text-[var(--text-secondary)]",children:"Job not found"});const L=$u(),A=!b.user_id||b.user_id==="anonymous"||L&&b.created_by_name===L,R=b.is_public&&!A,H=()=>{n.invalidateQueries({queryKey:["jobs",e]})},M=P=>{const _={pending:"default",running:"info",completed:"success",failed:"error",cancelled:"warning"};return a.jsx(q,{variant:_[P]||"default",children:P})};return a.jsxs("div",{children:[a.jsxs("div",{className:"flex items-center justify-between mb-6",children:[a.jsxs("div",{children:[a.jsxs("div",{className:"flex items-center gap-3",children:[a.jsx("button",{onClick:()=>t("/jobs"),className:"text-[var(--text-secondary)] hover:text-[var(--text-primary)]",children:"← Jobs"}),a.jsx("h2",{className:"text-xl font-bold",children:b.name||`Job ${b.id.slice(0,8)}`}),M(b.status),b.is_public&&a.jsxs(q,{variant:"info",children:[a.jsx(za,{className:"w-3 h-3 mr-1 inline"}),"Public"]})]}),a.jsxs("div",{className:"flex items-center gap-3 mt-1",children:[a.jsxs("code",{className:"text-xs bg-[var(--bg-primary)] px-2 py-0.5 rounded font-mono text-[var(--text-secondary)]",children:[b.id.slice(0,8),"..."]}),a.jsxs("span",{className:"text-sm text-[var(--text-secondary)]",children:[b.candidate_ids.length," candidates × ",b.task_ids.length," tasks = ",b.total_experiments," experiments"]}),b.is_public&&b.created_by_name&&a.jsxs("span",{className:"text-sm text-[var(--text-secondary)]",children:["Created by ",a.jsx("span",{className:"text-[var(--text-primary)]",children:b.created_by_name})]})]})]}),a.jsxs("div",{className:"flex gap-2",children:[A&&a.jsx(H0,{job:b,onUpdate:H}),R&&a.jsx(q,{variant:"default",children:"View Only"}),A&&b.status==="pending"&&a.jsx(K,{variant:"primary",onClick:()=>Q.mutate(),disabled:Q.isPending,children:Q.isPending?"Starting...":"Start"}),A&&b.status==="running"&&a.jsx(K,{variant:"danger",onClick:()=>D.mutate(),disabled:D.isPending,children:"Cancel"})]})]}),(x||b.error)&&a.jsx(re,{className:"mb-6 border-red-500/50 bg-red-500/10",children:a.jsxs("div",{className:"flex items-start gap-3",children:[a.jsx("div",{className:"w-5 h-5 rounded-full bg-red-500 flex items-center justify-center text-white text-xs font-bold flex-shrink-0 mt-0.5",children:"!"}),a.jsxs("div",{children:[a.jsx("h3",{className:"font-medium text-red-400",children:"Error"}),a.jsx("p",{className:"text-sm text-[var(--text-secondary)] mt-1",children:x||b.error})]})]})}),(i||r)&&a.jsxs(re,{className:"mb-6",children:[a.jsxs("div",{className:"flex items-center justify-between mb-2",children:[a.jsx("span",{className:"font-medium",children:"Progress"}),a.jsxs("span",{className:"text-[var(--accent)]",children:[(r==null?void 0:r.completed)||b.completed_experiments,"/",(r==null?void 0:r.total)||b.total_experiments]})]}),a.jsx("div",{className:"w-full bg-[var(--bg-primary)] h-2 mb-2",children:a.jsx("div",{className:"h-full bg-[var(--accent)] transition-all",style:{width:`${((r==null?void 0:r.completed)||b.completed_experiments)/((r==null?void 0:r.total)||b.total_experiments)*100}%`}})}),(r==null?void 0:r.message)&&a.jsx("p",{className:"text-sm text-[var(--text-secondary)]",children:r.message}),i&&a.jsxs("div",{className:"mt-4 border-t border-[var(--border)] pt-4",children:[(r==null?void 0:r.current_candidate)&&(r==null?void 0:r.current_task)&&a.jsxs("div",{className:"mb-3",children:[a.jsx("span",{className:"text-xs text-[var(--text-secondary)] uppercase tracking-wider",children:"Currently Running"}),a.jsxs("div",{className:"flex items-center gap-2 mt-1 px-3 py-2 bg-blue-500/10 border border-blue-500/30 rounded",children:[a.jsx("div",{className:"w-2 h-2 bg-blue-400 rounded-full animate-pulse"}),a.jsx("span",{className:"font-medium",children:r.current_candidate}),a.jsx("span",{className:"text-[var(--text-secondary)]",children:"→"}),a.jsx("span",{children:r.current_task})]})]}),c.length>0&&a.jsxs("div",{children:[a.jsxs("span",{className:"text-xs text-[var(--text-secondary)] uppercase tracking-wider",children:["Completed (",c.length,")"]}),a.jsx("div",{className:"mt-1 max-h-40 overflow-y-auto space-y-1",children:c.map((P,_)=>a.jsxs("div",{className:"flex items-center gap-2 px-3 py-1.5 bg-green-500/10 border border-green-500/30 rounded text-sm",children:[a.jsx("div",{className:"w-2 h-2 bg-green-400 rounded-full"}),a.jsx("span",{className:"font-medium",children:P.candidate_name}),a.jsx("span",{className:"text-[var(--text-secondary)]",children:"→"}),a.jsx("span",{children:P.task_name})]},`${P.candidate_name}-${P.task_name}-${_}`))})]})]})]}),(b.status==="completed"||F.length>0)&&a.jsxs("div",{className:"flex gap-1 mb-6 border-b border-[var(--border)]",children:[a.jsxs("button",{onClick:()=>S("results"),className:`flex items-center gap-2 px-4 py-2 text-sm font-medium border-b-2 transition-colors ${y==="results"?"border-[var(--accent)] text-[var(--accent)]":"border-transparent text-[var(--text-secondary)] hover:text-[var(--text-primary)]"}`,children:[a.jsx(uy,{size:16}),"Results"]}),a.jsxs("button",{onClick:()=>S("compare"),className:`flex items-center gap-2 px-4 py-2 text-sm font-medium border-b-2 transition-colors ${y==="compare"?"border-[var(--accent)] text-[var(--accent)]":"border-transparent text-[var(--text-secondary)] hover:text-[var(--text-primary)]"}`,children:[a.jsx(gy,{size:16}),"Compare"]}),a.jsxs("button",{onClick:()=>S("runs"),className:`flex items-center gap-2 px-4 py-2 text-sm font-medium border-b-2 transition-colors ${y==="runs"?"border-[var(--accent)] text-[var(--accent)]":"border-transparent text-[var(--text-secondary)] hover:text-[var(--text-primary)]"}`,children:[a.jsx(ky,{size:16}),"Runs (",F.length,")"]})]}),y==="results"&&a.jsxs(a.Fragment,{children:[O&&O.candidate_summaries.length>1&&a.jsxs(re,{className:"mb-6",children:[a.jsx("div",{className:"flex items-start justify-between mb-4",children:a.jsxs("div",{children:[a.jsx("h3",{className:"font-medium",children:"Pareto Frontier"}),a.jsxs("p",{className:"text-sm text-[var(--text-secondary)] mt-1",children:["Candidates on the frontier (connected line) are ",a.jsx("strong",{children:"Pareto optimal"})," - no other candidate beats them on both score AND cost."]})]})}),a.jsxs("div",{className:"mb-4 p-3 bg-[var(--bg-primary)] rounded border border-[var(--border)] text-xs text-[var(--text-secondary)]",children:[a.jsx("strong",{className:"text-[var(--text-primary)]",children:"How Pareto optimal is calculated:"})," A candidate is Pareto optimal if there's no other candidate that has both a higher score AND lower cost. For example, if Candidate A has 95% score at 50K tokens and Candidate B has 90% score at 40K tokens, both are Pareto optimal - A is better on score, B is better on cost. But if Candidate C has 85% score at 60K tokens, it's ",a.jsx("em",{children:"not"})," Pareto optimal because B beats it on both metrics."]}),a.jsx(Q0,{summaries:O.candidate_summaries,height:350})]}),O&&a.jsxs(re,{className:"mb-6",children:[a.jsxs("div",{className:"flex items-center justify-between mb-4",children:[a.jsx("h3",{className:"font-medium",children:"Results Summary"}),a.jsxs("label",{className:"flex items-center gap-2 text-sm text-[var(--text-secondary)] cursor-pointer",children:[a.jsx("input",{type:"checkbox",checked:C,onChange:P=>N(P.target.checked),className:"rounded border-[var(--border)]"}),"Pareto only"]})]}),a.jsx("div",{className:"overflow-x-auto",children:a.jsxs("table",{className:"w-full text-sm",children:[a.jsx("thead",{children:a.jsxs("tr",{className:"text-left text-[var(--text-secondary)] border-b border-[var(--border)]",children:[a.jsx("th",{className:"pb-2",children:"Candidate"}),a.jsx(be,{label:"Score",sortKeyVal:"score"}),a.jsx(be,{label:"Tokens",sortKeyVal:"tokens"}),a.jsx(be,{label:"Duration",sortKeyVal:"duration"}),a.jsx(be,{label:"Pass Rate",sortKeyVal:"pass_rate"}),a.jsx("th",{className:"pb-2",children:"Pareto"})]})}),a.jsx("tbody",{children:me.map((P,_)=>a.jsxs("tr",{className:`border-b border-[var(--border)] ${_===0?"bg-[var(--accent)]/10":""}`,children:[a.jsxs("td",{className:"py-2 font-medium",children:[_===0&&a.jsx("span",{className:"text-[var(--accent)] mr-1",children:"#1"}),P.candidate_name.replace(/^baseline_/,"")]}),a.jsxs("td",{className:"py-2",children:[(P.avg_score*100).toFixed(1),"%"]}),a.jsxs("td",{className:"py-2",children:[(P.avg_tokens/1e3).toFixed(1),"K"]}),a.jsxs("td",{className:"py-2",children:[P.avg_duration.toFixed(1),"s"]}),a.jsxs("td",{className:"py-2",children:[P.passed_runs,"/",P.total_runs]}),a.jsx("td",{className:"py-2",children:P.is_pareto&&a.jsx(q,{variant:"success",children:"Pareto"})})]},P.candidate_name))})]})}),a.jsx("p",{className:"text-xs text-[var(--text-secondary)] mt-3",children:"Click column headers to sort. The #1 ranked candidate is highlighted based on your sort criteria."})]}),!O&&a.jsx(re,{children:a.jsx("div",{className:"text-center py-8 text-[var(--text-secondary)]",children:i?"Results will appear here after the job completes.":"No results yet. Start the job to see results."})})]}),y==="compare"&&a.jsxs(re,{children:[a.jsx("h3",{className:"font-medium mb-4",children:"Compare Candidates by Task"}),te.length>0?a.jsxs(a.Fragment,{children:[a.jsx("div",{className:"flex flex-wrap gap-2 mb-4",children:te.map(P=>a.jsx("button",{onClick:()=>u(o===P?null:P),className:`px-3 py-1 text-sm rounded border transition-colors ${o===P?"bg-[var(--accent)] text-white border-[var(--accent)]":"border-[var(--border)] hover:border-[var(--accent-dim)]"}`,children:P},P))}),o&&$.get(o)?a.jsx(B0,{runs:$.get(o).map(P=>({id:P.id,candidate_name:P.candidate_name,tokens_input:0,tokens_output:0,tokens_total:P.tokens_total,duration_seconds:P.duration_seconds,score:P.score,passed:P.passed,is_pareto:P.is_pareto}))}):a.jsx("div",{className:"text-center py-8 text-[var(--text-secondary)]",children:"Select a task above to compare how different candidates performed on it."})]}):a.jsx("div",{className:"text-center py-8 text-[var(--text-secondary)]",children:i?"Comparison data will appear here after runs complete.":"No runs yet. Start the job to compare candidates."})]}),y==="runs"&&a.jsxs(re,{children:[a.jsx("h3",{className:"font-medium mb-4",children:"All Experiment Runs"}),F.length===0?a.jsx("div",{className:"text-center py-8 text-[var(--text-secondary)]",children:i?"Runs will appear here as they complete. See progress above for live status.":"No runs yet. Start the job to see results."}):a.jsx("div",{className:"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-3",children:F.map(P=>a.jsxs("div",{className:"p-3 bg-[var(--bg-primary)] rounded border border-[var(--border)] cursor-pointer hover:border-[var(--accent-dim)] transition-colors",onClick:()=>t(`/runs/${P.id}`),children:[a.jsxs("div",{className:"flex items-center justify-between mb-2",children:[a.jsxs("span",{className:`text-lg font-bold ${P.passed?"text-green-400":"text-red-400"}`,children:[(P.score*100).toFixed(0),"%"]}),P.is_pareto&&a.jsx(q,{variant:"success",children:"Pareto"})]}),a.jsx("div",{className:"text-sm font-medium truncate",title:P.candidate_name,children:P.candidate_name.replace(/^baseline_/,"")}),a.jsx("div",{className:"text-xs text-[var(--text-secondary)] truncate",children:P.task_name}),a.jsxs("div",{className:"flex items-center gap-3 mt-2 text-xs text-[var(--text-secondary)]",children:[a.jsxs("span",{children:[(P.tokens_total/1e3).toFixed(1),"K tokens"]}),a.jsxs("span",{children:[P.duration_seconds.toFixed(1),"s"]})]})]},P.id))})]})]})}const hn={input:"bg-blue-500",output:"bg-emerald-500",inputText:"text-blue-400",outputText:"text-emerald-400"};function Cd(e){return e>=1e3?`${(e/1e3).toFixed(1)}k`:String(e)}function _d({input:e,output:t,maxValue:n,height:r=24,showLabels:s=!0}){const i=e+t;if(i===0)return a.jsx("div",{className:"flex items-center gap-2 w-full",children:a.jsx("div",{className:"rounded bg-[var(--bg-primary)] flex-1",style:{height:`${r}px`}})});const l=n>0?i/n*100:100;return a.jsxs("div",{className:"flex items-center gap-3 w-full",children:[a.jsx("div",{className:"relative rounded overflow-hidden bg-[var(--bg-primary)] flex-1",style:{height:`${r}px`},children:a.jsxs("div",{className:"h-full flex transition-all duration-300",style:{width:`${l}%`},children:[a.jsx("div",{className:`h-full ${hn.input} transition-all`,style:{width:`${e/i*100}%`},title:`Input: ${e.toLocaleString()} tokens`}),a.jsx("div",{className:`h-full ${hn.output} transition-all`,style:{width:`${t/i*100}%`},title:`Output: ${t.toLocaleString()} tokens`})]})}),s&&a.jsxs("div",{className:"flex items-center gap-1 text-xs font-mono text-[var(--text-secondary)] min-w-[90px] justify-end",children:[a.jsxs("span",{className:hn.inputText,children:["↑",Cd(e)]}),a.jsx("span",{children:"/"}),a.jsxs("span",{className:hn.outputText,children:["↓",Cd(t)]})]})]})}function xl({label:e,value:t,color:n="default"}){const r={default:"text-[var(--text-primary)]",input:hn.inputText,output:hn.outputText}[n];return a.jsxs("div",{className:"flex-1 p-3 bg-[var(--bg-primary)] border border-[var(--border)] rounded",children:[a.jsx("div",{className:"text-xs text-[var(--text-secondary)] mb-1",children:e}),a.jsx("div",{className:`font-mono text-lg font-bold ${r}`,children:t})]})}function Bm({tokensInput:e,tokensOutput:t,tokensTotal:n,turns:r}){const s=n>0?Math.round(e/n*100):0,i=n>0?Math.round(t/n*100):0,l=k.useMemo(()=>{if(!r||r.length===0)return null;let u=0,c=0;return r.map(m=>(u+=m.input,c+=m.output,{input:u,output:c,total:u+c}))},[r]),o=l?Math.max(...l.map(u=>u.total)):n;return a.jsxs(re,{className:"mb-6",children:[a.jsx("h3",{className:"font-medium mb-4",children:"Token Usage"}),a.jsx("div",{className:"mb-4",children:a.jsx(_d,{input:e,output:t,maxValue:n,height:32})}),a.jsxs("div",{className:"flex items-center gap-6 text-xs mb-4",children:[a.jsxs("div",{className:"flex items-center gap-2",children:[a.jsx("div",{className:`w-3 h-3 rounded ${hn.input}`}),a.jsxs("span",{className:"text-[var(--text-secondary)]",children:["Input (",s,"%)"]})]}),a.jsxs("div",{className:"flex items-center gap-2",children:[a.jsx("div",{className:`w-3 h-3 rounded ${hn.output}`}),a.jsxs("span",{className:"text-[var(--text-secondary)]",children:["Output (",i,"%)"]})]})]}),a.jsxs("div",{className:"flex gap-3 mb-4",children:[a.jsx(xl,{label:"Input Tokens",value:e.toLocaleString(),color:"input"}),a.jsx(xl,{label:"Output Tokens",value:t.toLocaleString(),color:"output"}),a.jsx(xl,{label:"Total Tokens",value:n.toLocaleString()})]}),l&&l.length>1&&a.jsxs("div",{className:"border-t border-[var(--border)] pt-4",children:[a.jsxs("h4",{className:"text-sm font-medium mb-3 text-[var(--text-secondary)]",children:["Token Accumulation (",r.length," turns)"]}),a.jsx("div",{className:"space-y-2",children:r.map((u,c)=>a.jsxs("div",{className:"flex items-center gap-3",children:[a.jsx("div",{className:"w-6 h-6 rounded-full bg-[var(--bg-primary)] border border-[var(--border)] flex items-center justify-center text-xs font-medium",children:c+1}),a.jsx("div",{className:"flex-1",children:a.jsx(_d,{input:l[c].input,output:l[c].output,maxValue:o,height:16})})]},c))})]}),a.jsx("div",{className:"mt-4 text-xs text-[var(--text-secondary)] border-t border-[var(--border)] pt-3",children:"Token usage affects API cost. Input tokens are typically cheaper than output tokens."})]})}function q0(){const{runId:e}=Ra(),t=Et(),{data:n,isLoading:r}=ve({queryKey:["runs",e],queryFn:()=>To.get(e),enabled:!!e});return r?a.jsx("div",{className:"text-[var(--text-secondary)]",children:"Loading..."}):n?a.jsxs("div",{children:[a.jsxs("div",{className:"mb-6",children:[a.jsx("div",{className:"flex items-center gap-3 mb-2",children:a.jsx("button",{onClick:()=>t(`/jobs/${n.job_id}`),className:"text-[var(--text-secondary)] hover:text-[var(--text-primary)]",children:"← Back to Job"})}),a.jsxs("div",{className:"flex items-center gap-3",children:[a.jsx("h2",{className:"text-xl font-bold",children:n.candidate_name}),a.jsx("span",{className:"text-[var(--text-secondary)]",children:"→"}),a.jsx("span",{className:"text-lg",children:n.task_name}),n.is_pareto&&a.jsx(q,{variant:"success",children:"Pareto Optimal"})]})]}),a.jsxs("div",{className:"grid grid-cols-4 gap-4 mb-6",children:[a.jsx(Ci,{label:"Score",value:`${(n.score*100).toFixed(1)}%`,status:n.passed?"success":"error"}),a.jsx(Ci,{label:"Total Tokens",value:n.tokens_total.toLocaleString()}),a.jsx(Ci,{label:"Duration",value:`${n.duration_seconds.toFixed(1)}s`}),a.jsx(Ci,{label:"Status",value:n.passed?"Passed":"Failed",status:n.passed?"success":"error"})]}),a.jsx(Bm,{tokensInput:n.tokens_input,tokensOutput:n.tokens_output,tokensTotal:n.tokens_total}),a.jsxs(re,{className:"mb-6",children:[a.jsx("h3",{className:"font-medium mb-3",children:"Evaluation"}),n.reasoning&&a.jsx("p",{className:"text-sm text-[var(--text-secondary)] mb-4",children:n.reasoning}),n.criteria_results.length>0&&a.jsx("div",{className:"space-y-2",children:n.criteria_results.map(s=>a.jsx("div",{className:"flex items-start justify-between p-3 bg-[var(--bg-primary)] border border-[var(--border)]",children:a.jsxs("div",{className:"flex-1",children:[a.jsxs("div",{className:"flex items-center gap-2",children:[a.jsx("span",{className:"font-medium",children:s.name}),a.jsxs(q,{variant:s.passed?"success":"error",children:[(s.score*100).toFixed(0),"%"]})]}),s.reasoning&&a.jsx("p",{className:"text-sm text-[var(--text-secondary)] mt-1",children:s.reasoning})]})},s.name))})]}),a.jsxs(re,{className:"mb-6",children:[a.jsx("h3",{className:"font-medium mb-3",children:"Agent Output"}),a.jsx("pre",{className:"text-sm bg-[var(--bg-primary)] p-3 overflow-x-auto whitespace-pre-wrap border border-[var(--border)]",children:n.output||"(no output)"})]}),n.files_created.length>0&&a.jsxs(re,{className:"mb-6",children:[a.jsx("h3",{className:"font-medium mb-3",children:"Files Created"}),a.jsx("div",{className:"space-y-1",children:n.files_created.map(s=>a.jsx("div",{className:"text-sm font-mono text-[var(--text-secondary)]",children:s},s))})]}),Object.keys(n.trace).length>0&&a.jsx(Dm,{trace:n.trace})]}):a.jsx("div",{className:"text-[var(--text-secondary)]",children:"Run not found"})}function Ci({label:e,value:t,status:n}){const r={success:"text-green-400",error:"text-red-400"};return a.jsxs(re,{children:[a.jsx("div",{className:"text-sm text-[var(--text-secondary)]",children:e}),a.jsx("div",{className:`text-xl font-bold ${n?r[n]:""}`,children:t})]})}function J0(){const{testId:e}=Ra(),t=Et(),{data:n,isLoading:r}=ve({queryKey:["tests",e],queryFn:()=>Ns.get(e),enabled:!!e}),{data:s}=ve({queryKey:["configs",n==null?void 0:n.agent_id],queryFn:()=>br.get(n.agent_id),enabled:!!(n!=null&&n.agent_id)});if(r)return a.jsx("div",{className:"text-[var(--text-secondary)]",children:"Loading..."});if(!n)return a.jsx("div",{className:"text-[var(--text-secondary)]",children:"Test not found"});const i={completed:"success",failed:"error",running:"info",pending:"default",cancelled:"warning"};return a.jsxs("div",{children:[a.jsxs("div",{className:"mb-6",children:[a.jsx("div",{className:"flex items-center gap-3 mb-2",children:a.jsx("button",{onClick:()=>t("/agents"),className:"text-[var(--text-secondary)] hover:text-[var(--text-primary)]",children:"← Back to Agents"})}),a.jsxs("div",{className:"flex items-center gap-3",children:[a.jsx("h2",{className:"text-xl font-bold",children:"Test Run"}),s&&a.jsxs(a.Fragment,{children:[a.jsx("span",{className:"text-[var(--text-secondary)]",children:"•"}),a.jsx("span",{className:"text-lg",children:s.name})]}),a.jsx(q,{variant:i[n.status]||"default",children:n.status})]}),a.jsxs("p",{className:"text-sm text-[var(--text-secondary)] mt-1 font-mono",children:["ID: ",n.id.slice(0,8),"..."]})]}),a.jsxs("div",{className:"grid grid-cols-4 gap-4 mb-6",children:[a.jsx(_i,{label:"Duration",value:`${n.duration_seconds.toFixed(2)}s`}),a.jsx(_i,{label:"Total Tokens",value:n.tokens_total.toLocaleString()}),n.score!==null&&a.jsx(_i,{label:"Score",value:`${(n.score*100).toFixed(1)}%`,status:n.passed?"success":"error"}),a.jsx(_i,{label:"Status",value:n.status.charAt(0).toUpperCase()+n.status.slice(1),status:n.status==="completed"?"success":n.status==="failed"?"error":void 0})]}),a.jsx(Bm,{tokensInput:n.tokens_input,tokensOutput:n.tokens_output,tokensTotal:n.tokens_total}),a.jsxs(re,{className:"mb-6",children:[a.jsx("h3",{className:"font-medium mb-3",children:"Prompt"}),a.jsx("pre",{className:"text-sm bg-[var(--bg-primary)] p-3 overflow-x-auto whitespace-pre-wrap border border-[var(--border)] font-mono",children:n.prompt})]}),n.error&&a.jsxs(re,{className:"mb-6 border-red-500/30 bg-red-500/5",children:[a.jsx("h3",{className:"font-medium mb-3 text-red-400",children:"Error"}),a.jsx("pre",{className:"text-sm text-red-300 overflow-x-auto whitespace-pre-wrap",children:n.error})]}),n.reasoning&&a.jsxs(re,{className:"mb-6",children:[a.jsx("h3",{className:"font-medium mb-3",children:"Evaluation"}),a.jsx("p",{className:"text-sm text-[var(--text-secondary)]",children:n.reasoning})]}),a.jsxs(re,{className:"mb-6",children:[a.jsx("h3",{className:"font-medium mb-3",children:"Agent Output"}),a.jsx("pre",{className:"text-sm bg-[var(--bg-primary)] p-3 overflow-x-auto whitespace-pre-wrap border border-[var(--border)]",children:n.output||"(no output)"})]}),n.files_created&&n.files_created.length>0&&a.jsxs(re,{className:"mb-6",children:[a.jsx("h3",{className:"font-medium mb-3",children:"Files Created"}),a.jsx("div",{className:"space-y-1",children:n.files_created.map(l=>a.jsx("div",{className:"text-sm font-mono text-[var(--text-secondary)]",children:l},l))})]}),n.trace&&Object.keys(n.trace).length>0&&a.jsx(Dm,{trace:n.trace}),a.jsxs(re,{className:"mb-6",children:[a.jsx("h3",{className:"font-medium mb-3",children:"Timestamps"}),a.jsxs("div",{className:"grid grid-cols-3 gap-4 text-sm",children:[a.jsxs("div",{children:[a.jsx("span",{className:"text-[var(--text-secondary)]",children:"Created:"}),a.jsx("div",{className:"font-mono",children:new Date(n.created_at).toLocaleString()})]}),n.started_at&&a.jsxs("div",{children:[a.jsx("span",{className:"text-[var(--text-secondary)]",children:"Started:"}),a.jsx("div",{className:"font-mono",children:new Date(n.started_at).toLocaleString()})]}),n.completed_at&&a.jsxs("div",{children:[a.jsx("span",{className:"text-[var(--text-secondary)]",children:"Completed:"}),a.jsx("div",{className:"font-mono",children:new Date(n.completed_at).toLocaleString()})]})]})]})]})}function _i({label:e,value:t,status:n}){const r={success:"text-green-400",error:"text-red-400"};return a.jsxs(re,{children:[a.jsx("div",{className:"text-sm text-[var(--text-secondary)]",children:e}),a.jsx("div",{className:`text-xl font-bold ${n?r[n]:""}`,children:t})]})}function G0(){const{authConfig:e,isLoading:t,error:n,login:r,loginWithGitHub:s,clearError:i}=Uu(),[l,o]=k.useState(""),[u,c]=k.useState("");k.useEffect(()=>{n&&i()},[l,u]);const m=async h=>{h.preventDefault(),!(!l||!u)&&await r(l,u)},d=()=>{s()};return a.jsx("div",{className:"min-h-screen bg-[var(--bg-primary)] flex items-center justify-center p-4",children:a.jsxs("div",{className:"w-full max-w-md",children:[a.jsxs("div",{className:"text-center mb-8",children:[a.jsx("h1",{className:"text-2xl font-bold text-[var(--text-primary)] mb-2",children:"Flow"}),a.jsx("p",{className:"text-[var(--text-secondary)]",children:"Sign in to access the optimization dashboard"})]}),a.jsxs("div",{className:"bg-[var(--bg-secondary)] border border-[var(--border)] p-6 space-y-6",children:[n&&a.jsxs("div",{className:"flex items-start gap-3 p-3 bg-[var(--error)]/10 border border-[var(--error)]/20 text-[var(--error)]",children:[a.jsx(Sm,{size:18,className:"mt-0.5 flex-shrink-0"}),a.jsx("p",{className:"text-sm",children:n})]}),(e==null?void 0:e.mode)==="basic"&&a.jsxs("form",{onSubmit:m,className:"space-y-4",children:[a.jsxs("div",{className:"space-y-1",children:[a.jsx("label",{className:"block text-sm text-[var(--text-secondary)]",children:"Username"}),a.jsxs("div",{className:"relative",children:[a.jsx(Em,{size:16,className:"absolute left-3 top-1/2 -translate-y-1/2 text-[var(--text-tertiary)]"}),a.jsx("input",{type:"text",value:l,onChange:h=>o(h.target.value),className:"w-full bg-[var(--bg-primary)] border border-[var(--border)] pl-10 pr-3 py-2 text-sm focus:outline-none focus:border-[var(--accent)]",placeholder:"Enter username",autoComplete:"username",autoFocus:!0})]})]}),a.jsxs("div",{className:"space-y-1",children:[a.jsx("label",{className:"block text-sm text-[var(--text-secondary)]",children:"Password"}),a.jsxs("div",{className:"relative",children:[a.jsx(bm,{size:16,className:"absolute left-3 top-1/2 -translate-y-1/2 text-[var(--text-tertiary)]"}),a.jsx("input",{type:"password",value:u,onChange:h=>c(h.target.value),className:"w-full bg-[var(--bg-primary)] border border-[var(--border)] pl-10 pr-3 py-2 text-sm focus:outline-none focus:border-[var(--accent)]",placeholder:"Enter password",autoComplete:"current-password"})]})]}),a.jsx(K,{type:"submit",variant:"primary",className:"w-full justify-center",loading:t,disabled:!l||!u,children:"Sign In"})]}),(e==null?void 0:e.mode)==="github"&&a.jsxs("div",{className:"space-y-4",children:[a.jsx("p",{className:"text-sm text-[var(--text-secondary)] text-center",children:"Sign in with your GitHub account to continue"}),a.jsx(K,{onClick:d,variant:"secondary",className:"w-full justify-center",icon:yy,children:"Continue with GitHub"})]})]})]})})}function Y0({children:e}){const{authConfig:t,isLoadingConfig:n,isAuthenticated:r,loadAuthConfig:s,handleOAuthCallback:i}=Uu();return k.useEffect(()=>{s()},[s]),k.useEffect(()=>{n||i()},[n,i]),n?a.jsx("div",{className:"min-h-screen bg-[var(--bg-primary)] flex items-center justify-center",children:a.jsxs("div",{className:"text-center",children:[a.jsx(Fa,{className:"w-8 h-8 animate-spin text-[var(--accent)] mx-auto mb-4"}),a.jsx("p",{className:"text-[var(--text-secondary)]",children:"Loading..."})]})}):t!=null&&t.enabled&&!r?a.jsx(G0,{}):a.jsx(a.Fragment,{children:e})}function X0(){return a.jsx(ey,{children:a.jsx(Y0,{children:a.jsx(Hg,{children:a.jsxs(yt,{path:"/",element:a.jsx(h0,{}),children:[a.jsx(yt,{index:!0,element:a.jsx(bd,{})}),a.jsx(yt,{path:"agents",element:a.jsx(bd,{})}),a.jsx(yt,{path:"agents/:agentId",element:a.jsx(R0,{})}),a.jsx(yt,{path:"tasks",element:a.jsx(F0,{})}),a.jsx(yt,{path:"jobs",element:a.jsx(A0,{})}),a.jsx(yt,{path:"jobs/:jobId",element:a.jsx(W0,{})}),a.jsx(yt,{path:"runs/:runId",element:a.jsx(q0,{})}),a.jsx(yt,{path:"tests/:testId",element:a.jsx(J0,{})})]})})})})}const Ed=localStorage.getItem("flow-theme");if(Ed)try{const{state:e}=JSON.parse(Ed);e!=null&&e.theme&&document.documentElement.setAttribute("data-theme",e.theme)}catch{}const Z0=new Ux({defaultOptions:{queries:{staleTime:5e3,refetchOnWindowFocus:!1}}});gl.createRoot(document.getElementById("root")).render(a.jsx(Ao.StrictMode,{children:a.jsx(Bx,{client:Z0,children:a.jsx(X0,{})})})); diff --git a/src/flow/ui/ui/assets/index-B9Pa5b9x.js b/src/flow/ui/ui/assets/index-B9Pa5b9x.js new file mode 100644 index 0000000000000000000000000000000000000000..489c7cf57dea95f7c80af59a17b769afa35201b7 --- /dev/null +++ b/src/flow/ui/ui/assets/index-B9Pa5b9x.js @@ -0,0 +1,270 @@ +var Qu=e=>{throw TypeError(e)};var Ua=(e,t,n)=>t.has(e)||Qu("Cannot "+n);var y=(e,t,n)=>(Ua(e,t,"read from private field"),n?n.call(e):t.get(e)),U=(e,t,n)=>t.has(e)?Qu("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(e):t.set(e,n),z=(e,t,n,r)=>(Ua(e,t,"write to private field"),r?r.call(e,n):t.set(e,n),n),W=(e,t,n)=>(Ua(e,t,"access private method"),n);var li=(e,t,n,r)=>({set _(s){z(e,t,s,n)},get _(){return y(e,t,r)}});function Vm(e,t){for(var n=0;nr[s]})}}}return Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const s of document.querySelectorAll('link[rel="modulepreload"]'))r(s);new MutationObserver(s=>{for(const i of s)if(i.type==="childList")for(const l of i.addedNodes)l.tagName==="LINK"&&l.rel==="modulepreload"&&r(l)}).observe(document,{childList:!0,subtree:!0});function n(s){const i={};return s.integrity&&(i.integrity=s.integrity),s.referrerPolicy&&(i.referrerPolicy=s.referrerPolicy),s.crossOrigin==="use-credentials"?i.credentials="include":s.crossOrigin==="anonymous"?i.credentials="omit":i.credentials="same-origin",i}function r(s){if(s.ep)return;s.ep=!0;const i=n(s);fetch(s.href,i)}})();function $d(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var Ud={exports:{}},pa={},Bd={exports:{}},J={};/** + * @license React + * react.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var ei=Symbol.for("react.element"),Km=Symbol.for("react.portal"),Hm=Symbol.for("react.fragment"),Wm=Symbol.for("react.strict_mode"),qm=Symbol.for("react.profiler"),Jm=Symbol.for("react.provider"),Gm=Symbol.for("react.context"),Ym=Symbol.for("react.forward_ref"),Xm=Symbol.for("react.suspense"),Zm=Symbol.for("react.memo"),ep=Symbol.for("react.lazy"),Vu=Symbol.iterator;function tp(e){return e===null||typeof e!="object"?null:(e=Vu&&e[Vu]||e["@@iterator"],typeof e=="function"?e:null)}var Qd={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},Vd=Object.assign,Kd={};function Wr(e,t,n){this.props=e,this.context=t,this.refs=Kd,this.updater=n||Qd}Wr.prototype.isReactComponent={};Wr.prototype.setState=function(e,t){if(typeof e!="object"&&typeof e!="function"&&e!=null)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")};Wr.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")};function Hd(){}Hd.prototype=Wr.prototype;function Mo(e,t,n){this.props=e,this.context=t,this.refs=Kd,this.updater=n||Qd}var zo=Mo.prototype=new Hd;zo.constructor=Mo;Vd(zo,Wr.prototype);zo.isPureReactComponent=!0;var Ku=Array.isArray,Wd=Object.prototype.hasOwnProperty,Fo={current:null},qd={key:!0,ref:!0,__self:!0,__source:!0};function Jd(e,t,n){var r,s={},i=null,l=null;if(t!=null)for(r in t.ref!==void 0&&(l=t.ref),t.key!==void 0&&(i=""+t.key),t)Wd.call(t,r)&&!qd.hasOwnProperty(r)&&(s[r]=t[r]);var o=arguments.length-2;if(o===1)s.children=n;else if(1>>1,M=L[H];if(0>>1;Hs(B,R))res(be,B)?(L[H]=be,L[re]=R,H=re):(L[H]=B,L[_]=R,H=_);else if(res(be,R))L[H]=be,L[re]=R,H=re;else break e}}return A}function s(L,A){var R=L.sortIndex-A.sortIndex;return R!==0?R:L.id-A.id}if(typeof performance=="object"&&typeof performance.now=="function"){var i=performance;e.unstable_now=function(){return i.now()}}else{var l=Date,o=l.now();e.unstable_now=function(){return l.now()-o}}var u=[],c=[],m=1,d=null,h=3,x=!1,w=!1,g=!1,S=typeof setTimeout=="function"?setTimeout:null,v=typeof clearTimeout=="function"?clearTimeout:null,f=typeof setImmediate<"u"?setImmediate:null;typeof navigator<"u"&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function p(L){for(var A=n(c);A!==null;){if(A.callback===null)r(c);else if(A.startTime<=L)r(c),A.sortIndex=A.expirationTime,t(u,A);else break;A=n(c)}}function j(L){if(g=!1,p(L),!w)if(n(u)!==null)w=!0,et(C);else{var A=n(c);A!==null&&Ne(j,A.startTime-L)}}function C(L,A){w=!1,g&&(g=!1,v(E),E=-1),x=!0;var R=h;try{for(p(A),d=n(u);d!==null&&(!(d.expirationTime>A)||L&&!Q());){var H=d.callback;if(typeof H=="function"){d.callback=null,h=d.priorityLevel;var M=H(d.expirationTime<=A);A=e.unstable_now(),typeof M=="function"?d.callback=M:d===n(u)&&r(u),p(A)}else r(u);d=n(u)}if(d!==null)var P=!0;else{var _=n(c);_!==null&&Ne(j,_.startTime-A),P=!1}return P}finally{d=null,h=R,x=!1}}var N=!1,b=null,E=-1,F=5,O=-1;function Q(){return!(e.unstable_now()-OL||125H?(L.sortIndex=R,t(c,L),n(u)===null&&L===n(c)&&(g?(v(E),E=-1):g=!0,Ne(j,R-H))):(L.sortIndex=M,t(u,L),w||x||(w=!0,et(C))),L},e.unstable_shouldYield=Q,e.unstable_wrapCallback=function(L){var A=h;return function(){var R=h;h=A;try{return L.apply(this,arguments)}finally{h=R}}}})(ef);Zd.exports=ef;var hp=Zd.exports;/** + * @license React + * react-dom.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var mp=k,Ye=hp;function T(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),gl=Object.prototype.hasOwnProperty,pp=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,Wu={},qu={};function vp(e){return gl.call(qu,e)?!0:gl.call(Wu,e)?!1:pp.test(e)?qu[e]=!0:(Wu[e]=!0,!1)}function xp(e,t,n,r){if(n!==null&&n.type===0)return!1;switch(typeof t){case"function":case"symbol":return!0;case"boolean":return r?!1:n!==null?!n.acceptsBooleans:(e=e.toLowerCase().slice(0,5),e!=="data-"&&e!=="aria-");default:return!1}}function yp(e,t,n,r){if(t===null||typeof t>"u"||xp(e,t,n,r))return!0;if(r)return!1;if(n!==null)switch(n.type){case 3:return!t;case 4:return t===!1;case 5:return isNaN(t);case 6:return isNaN(t)||1>t}return!1}function Ae(e,t,n,r,s,i,l){this.acceptsBooleans=t===2||t===3||t===4,this.attributeName=r,this.attributeNamespace=s,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=i,this.removeEmptyString=l}var Ee={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(e){Ee[e]=new Ae(e,0,!1,e,null,!1,!1)});[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(e){var t=e[0];Ee[t]=new Ae(t,1,!1,e[1],null,!1,!1)});["contentEditable","draggable","spellCheck","value"].forEach(function(e){Ee[e]=new Ae(e,2,!1,e.toLowerCase(),null,!1,!1)});["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(e){Ee[e]=new Ae(e,2,!1,e,null,!1,!1)});"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(e){Ee[e]=new Ae(e,3,!1,e.toLowerCase(),null,!1,!1)});["checked","multiple","muted","selected"].forEach(function(e){Ee[e]=new Ae(e,3,!0,e,null,!1,!1)});["capture","download"].forEach(function(e){Ee[e]=new Ae(e,4,!1,e,null,!1,!1)});["cols","rows","size","span"].forEach(function(e){Ee[e]=new Ae(e,6,!1,e,null,!1,!1)});["rowSpan","start"].forEach(function(e){Ee[e]=new Ae(e,5,!1,e.toLowerCase(),null,!1,!1)});var Ao=/[\-:]([a-z])/g;function $o(e){return e[1].toUpperCase()}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(e){var t=e.replace(Ao,$o);Ee[t]=new Ae(t,1,!1,e,null,!1,!1)});"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(e){var t=e.replace(Ao,$o);Ee[t]=new Ae(t,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)});["xml:base","xml:lang","xml:space"].forEach(function(e){var t=e.replace(Ao,$o);Ee[t]=new Ae(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)});["tabIndex","crossOrigin"].forEach(function(e){Ee[e]=new Ae(e,1,!1,e.toLowerCase(),null,!1,!1)});Ee.xlinkHref=new Ae("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1);["src","href","action","formAction"].forEach(function(e){Ee[e]=new Ae(e,1,!1,e.toLowerCase(),null,!0,!0)});function Uo(e,t,n,r){var s=Ee.hasOwnProperty(t)?Ee[t]:null;(s!==null?s.type!==0:r||!(2o||s[l]!==i[o]){var u=` +`+s[l].replace(" at new "," at ");return e.displayName&&u.includes("")&&(u=u.replace("",e.displayName)),u}while(1<=l&&0<=o);break}}}finally{Va=!1,Error.prepareStackTrace=n}return(e=e?e.displayName||e.name:"")?us(e):""}function gp(e){switch(e.tag){case 5:return us(e.type);case 16:return us("Lazy");case 13:return us("Suspense");case 19:return us("SuspenseList");case 0:case 2:case 15:return e=Ka(e.type,!1),e;case 11:return e=Ka(e.type.render,!1),e;case 1:return e=Ka(e.type,!0),e;default:return""}}function Sl(e){if(e==null)return null;if(typeof e=="function")return e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case or:return"Fragment";case lr:return"Portal";case jl:return"Profiler";case Bo:return"StrictMode";case wl:return"Suspense";case kl:return"SuspenseList"}if(typeof e=="object")switch(e.$$typeof){case rf:return(e.displayName||"Context")+".Consumer";case nf:return(e._context.displayName||"Context")+".Provider";case Qo:var t=e.render;return e=e.displayName,e||(e=t.displayName||t.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case Vo:return t=e.displayName||null,t!==null?t:Sl(e.type)||"Memo";case Jt:t=e._payload,e=e._init;try{return Sl(e(t))}catch{}}return null}function jp(e){var t=e.type;switch(e.tag){case 24:return"Cache";case 9:return(t.displayName||"Context")+".Consumer";case 10:return(t._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return e=t.render,e=e.displayName||e.name||"",t.displayName||(e!==""?"ForwardRef("+e+")":"ForwardRef");case 7:return"Fragment";case 5:return t;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return Sl(t);case 8:return t===Bo?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if(typeof t=="function")return t.displayName||t.name||null;if(typeof t=="string")return t}return null}function Nn(e){switch(typeof e){case"boolean":case"number":case"string":case"undefined":return e;case"object":return e;default:return""}}function af(e){var t=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(t==="checkbox"||t==="radio")}function wp(e){var t=af(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),r=""+e[t];if(!e.hasOwnProperty(t)&&typeof n<"u"&&typeof n.get=="function"&&typeof n.set=="function"){var s=n.get,i=n.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return s.call(this)},set:function(l){r=""+l,i.call(this,l)}}),Object.defineProperty(e,t,{enumerable:n.enumerable}),{getValue:function(){return r},setValue:function(l){r=""+l},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}function ci(e){e._valueTracker||(e._valueTracker=wp(e))}function lf(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),r="";return e&&(r=af(e)?e.checked?"true":"false":e.value),e=r,e!==n?(t.setValue(e),!0):!1}function Ui(e){if(e=e||(typeof document<"u"?document:void 0),typeof e>"u")return null;try{return e.activeElement||e.body}catch{return e.body}}function Nl(e,t){var n=t.checked;return ce({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:n??e._wrapperState.initialChecked})}function Gu(e,t){var n=t.defaultValue==null?"":t.defaultValue,r=t.checked!=null?t.checked:t.defaultChecked;n=Nn(t.value!=null?t.value:n),e._wrapperState={initialChecked:r,initialValue:n,controlled:t.type==="checkbox"||t.type==="radio"?t.checked!=null:t.value!=null}}function of(e,t){t=t.checked,t!=null&&Uo(e,"checked",t,!1)}function bl(e,t){of(e,t);var n=Nn(t.value),r=t.type;if(n!=null)r==="number"?(n===0&&e.value===""||e.value!=n)&&(e.value=""+n):e.value!==""+n&&(e.value=""+n);else if(r==="submit"||r==="reset"){e.removeAttribute("value");return}t.hasOwnProperty("value")?Cl(e,t.type,n):t.hasOwnProperty("defaultValue")&&Cl(e,t.type,Nn(t.defaultValue)),t.checked==null&&t.defaultChecked!=null&&(e.defaultChecked=!!t.defaultChecked)}function Yu(e,t,n){if(t.hasOwnProperty("value")||t.hasOwnProperty("defaultValue")){var r=t.type;if(!(r!=="submit"&&r!=="reset"||t.value!==void 0&&t.value!==null))return;t=""+e._wrapperState.initialValue,n||t===e.value||(e.value=t),e.defaultValue=t}n=e.name,n!==""&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,n!==""&&(e.name=n)}function Cl(e,t,n){(t!=="number"||Ui(e.ownerDocument)!==e)&&(n==null?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+n&&(e.defaultValue=""+n))}var cs=Array.isArray;function gr(e,t,n,r){if(e=e.options,t){t={};for(var s=0;s"+t.valueOf().toString()+"",t=di.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}});function Cs(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&n.nodeType===3){n.nodeValue=t;return}}e.textContent=t}var ms={animationIterationCount:!0,aspectRatio:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},kp=["Webkit","ms","Moz","O"];Object.keys(ms).forEach(function(e){kp.forEach(function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),ms[t]=ms[e]})});function ff(e,t,n){return t==null||typeof t=="boolean"||t===""?"":n||typeof t!="number"||t===0||ms.hasOwnProperty(e)&&ms[e]?(""+t).trim():t+"px"}function hf(e,t){e=e.style;for(var n in t)if(t.hasOwnProperty(n)){var r=n.indexOf("--")===0,s=ff(n,t[n],r);n==="float"&&(n="cssFloat"),r?e.setProperty(n,s):e[n]=s}}var Sp=ce({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function Pl(e,t){if(t){if(Sp[e]&&(t.children!=null||t.dangerouslySetInnerHTML!=null))throw Error(T(137,e));if(t.dangerouslySetInnerHTML!=null){if(t.children!=null)throw Error(T(60));if(typeof t.dangerouslySetInnerHTML!="object"||!("__html"in t.dangerouslySetInnerHTML))throw Error(T(61))}if(t.style!=null&&typeof t.style!="object")throw Error(T(62))}}function Tl(e,t){if(e.indexOf("-")===-1)return typeof t.is=="string";switch(e){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}var Ol=null;function Ko(e){return e=e.target||e.srcElement||window,e.correspondingUseElement&&(e=e.correspondingUseElement),e.nodeType===3?e.parentNode:e}var Ll=null,jr=null,wr=null;function ec(e){if(e=ri(e)){if(typeof Ll!="function")throw Error(T(280));var t=e.stateNode;t&&(t=ja(t),Ll(e.stateNode,e.type,t))}}function mf(e){jr?wr?wr.push(e):wr=[e]:jr=e}function pf(){if(jr){var e=jr,t=wr;if(wr=jr=null,ec(e),t)for(e=0;e>>=0,e===0?32:31-(Mp(e)/zp|0)|0}var fi=64,hi=4194304;function ds(e){switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return e&4194240;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return e&130023424;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 1073741824;default:return e}}function Ki(e,t){var n=e.pendingLanes;if(n===0)return 0;var r=0,s=e.suspendedLanes,i=e.pingedLanes,l=n&268435455;if(l!==0){var o=l&~s;o!==0?r=ds(o):(i&=l,i!==0&&(r=ds(i)))}else l=n&~s,l!==0?r=ds(l):i!==0&&(r=ds(i));if(r===0)return 0;if(t!==0&&t!==r&&!(t&s)&&(s=r&-r,i=t&-t,s>=i||s===16&&(i&4194240)!==0))return t;if(r&4&&(r|=n&16),t=e.entangledLanes,t!==0)for(e=e.entanglements,t&=r;0n;n++)t.push(e);return t}function ti(e,t,n){e.pendingLanes|=t,t!==536870912&&(e.suspendedLanes=0,e.pingedLanes=0),e=e.eventTimes,t=31-pt(t),e[t]=n}function Ap(e,t){var n=e.pendingLanes&~t;e.pendingLanes=t,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=t,e.mutableReadLanes&=t,e.entangledLanes&=t,t=e.entanglements;var r=e.eventTimes;for(e=e.expirationTimes;0=vs),uc=" ",cc=!1;function zf(e,t){switch(e){case"keyup":return hv.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function Ff(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var ur=!1;function pv(e,t){switch(e){case"compositionend":return Ff(t);case"keypress":return t.which!==32?null:(cc=!0,uc);case"textInput":return e=t.data,e===uc&&cc?null:e;default:return null}}function vv(e,t){if(ur)return e==="compositionend"||!Zo&&zf(e,t)?(e=Rf(),Oi=Go=un=null,ur=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:n,offset:t-e};e=r}e:{for(;n;){if(n.nextSibling){n=n.nextSibling;break e}n=n.parentNode}n=void 0}n=mc(n)}}function $f(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?$f(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function Uf(){for(var e=window,t=Ui();t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href=="string"}catch{n=!1}if(n)e=t.contentWindow;else break;t=Ui(e.document)}return t}function eu(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}function bv(e){var t=Uf(),n=e.focusedElem,r=e.selectionRange;if(t!==n&&n&&n.ownerDocument&&$f(n.ownerDocument.documentElement,n)){if(r!==null&&eu(n)){if(t=r.start,e=r.end,e===void 0&&(e=t),"selectionStart"in n)n.selectionStart=t,n.selectionEnd=Math.min(e,n.value.length);else if(e=(t=n.ownerDocument||document)&&t.defaultView||window,e.getSelection){e=e.getSelection();var s=n.textContent.length,i=Math.min(r.start,s);r=r.end===void 0?i:Math.min(r.end,s),!e.extend&&i>r&&(s=r,r=i,i=s),s=pc(n,i);var l=pc(n,r);s&&l&&(e.rangeCount!==1||e.anchorNode!==s.node||e.anchorOffset!==s.offset||e.focusNode!==l.node||e.focusOffset!==l.offset)&&(t=t.createRange(),t.setStart(s.node,s.offset),e.removeAllRanges(),i>r?(e.addRange(t),e.extend(l.node,l.offset)):(t.setEnd(l.node,l.offset),e.addRange(t)))}}for(t=[],e=n;e=e.parentNode;)e.nodeType===1&&t.push({element:e,left:e.scrollLeft,top:e.scrollTop});for(typeof n.focus=="function"&&n.focus(),n=0;n=document.documentMode,cr=null,Dl=null,ys=null,Al=!1;function vc(e,t,n){var r=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;Al||cr==null||cr!==Ui(r)||(r=cr,"selectionStart"in r&&eu(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),ys&&Ls(ys,r)||(ys=r,r=qi(Dl,"onSelect"),0hr||(e.current=Kl[hr],Kl[hr]=null,hr--)}function se(e,t){hr++,Kl[hr]=e.current,e.current=t}var bn={},Re=_n(bn),Ve=_n(!1),Jn=bn;function Ar(e,t){var n=e.type.contextTypes;if(!n)return bn;var r=e.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===t)return r.__reactInternalMemoizedMaskedChildContext;var s={},i;for(i in n)s[i]=t[i];return r&&(e=e.stateNode,e.__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=s),s}function Ke(e){return e=e.childContextTypes,e!=null}function Gi(){ae(Ve),ae(Re)}function Sc(e,t,n){if(Re.current!==bn)throw Error(T(168));se(Re,t),se(Ve,n)}function Gf(e,t,n){var r=e.stateNode;if(t=t.childContextTypes,typeof r.getChildContext!="function")return n;r=r.getChildContext();for(var s in r)if(!(s in t))throw Error(T(108,jp(e)||"Unknown",s));return ce({},n,r)}function Yi(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||bn,Jn=Re.current,se(Re,e),se(Ve,Ve.current),!0}function Nc(e,t,n){var r=e.stateNode;if(!r)throw Error(T(169));n?(e=Gf(e,t,Jn),r.__reactInternalMemoizedMergedChildContext=e,ae(Ve),ae(Re),se(Re,e)):ae(Ve),se(Ve,n)}var Ot=null,wa=!1,il=!1;function Yf(e){Ot===null?Ot=[e]:Ot.push(e)}function Iv(e){wa=!0,Yf(e)}function En(){if(!il&&Ot!==null){il=!0;var e=0,t=te;try{var n=Ot;for(te=1;e>=l,s-=l,Ft=1<<32-pt(t)+s|n<E?(F=b,b=null):F=b.sibling;var O=h(v,b,p[E],j);if(O===null){b===null&&(b=F);break}e&&b&&O.alternate===null&&t(v,b),f=i(O,f,E),N===null?C=O:N.sibling=O,N=O,b=F}if(E===p.length)return n(v,b),le&&On(v,E),C;if(b===null){for(;EE?(F=b,b=null):F=b.sibling;var Q=h(v,b,O.value,j);if(Q===null){b===null&&(b=F);break}e&&b&&Q.alternate===null&&t(v,b),f=i(Q,f,E),N===null?C=Q:N.sibling=Q,N=Q,b=F}if(O.done)return n(v,b),le&&On(v,E),C;if(b===null){for(;!O.done;E++,O=p.next())O=d(v,O.value,j),O!==null&&(f=i(O,f,E),N===null?C=O:N.sibling=O,N=O);return le&&On(v,E),C}for(b=r(v,b);!O.done;E++,O=p.next())O=x(b,v,E,O.value,j),O!==null&&(e&&O.alternate!==null&&b.delete(O.key===null?E:O.key),f=i(O,f,E),N===null?C=O:N.sibling=O,N=O);return e&&b.forEach(function(D){return t(v,D)}),le&&On(v,E),C}function S(v,f,p,j){if(typeof p=="object"&&p!==null&&p.type===or&&p.key===null&&(p=p.props.children),typeof p=="object"&&p!==null){switch(p.$$typeof){case ui:e:{for(var C=p.key,N=f;N!==null;){if(N.key===C){if(C=p.type,C===or){if(N.tag===7){n(v,N.sibling),f=s(N,p.props.children),f.return=v,v=f;break e}}else if(N.elementType===C||typeof C=="object"&&C!==null&&C.$$typeof===Jt&&_c(C)===N.type){n(v,N.sibling),f=s(N,p.props),f.ref=is(v,N,p),f.return=v,v=f;break e}n(v,N);break}else t(v,N);N=N.sibling}p.type===or?(f=Wn(p.props.children,v.mode,j,p.key),f.return=v,v=f):(j=Ai(p.type,p.key,p.props,null,v.mode,j),j.ref=is(v,f,p),j.return=v,v=j)}return l(v);case lr:e:{for(N=p.key;f!==null;){if(f.key===N)if(f.tag===4&&f.stateNode.containerInfo===p.containerInfo&&f.stateNode.implementation===p.implementation){n(v,f.sibling),f=s(f,p.children||[]),f.return=v,v=f;break e}else{n(v,f);break}else t(v,f);f=f.sibling}f=hl(p,v.mode,j),f.return=v,v=f}return l(v);case Jt:return N=p._init,S(v,f,N(p._payload),j)}if(cs(p))return w(v,f,p,j);if(es(p))return g(v,f,p,j);ji(v,p)}return typeof p=="string"&&p!==""||typeof p=="number"?(p=""+p,f!==null&&f.tag===6?(n(v,f.sibling),f=s(f,p),f.return=v,v=f):(n(v,f),f=fl(p,v.mode,j),f.return=v,v=f),l(v)):n(v,f)}return S}var Ur=th(!0),nh=th(!1),ea=_n(null),ta=null,vr=null,su=null;function iu(){su=vr=ta=null}function au(e){var t=ea.current;ae(ea),e._currentValue=t}function ql(e,t,n){for(;e!==null;){var r=e.alternate;if((e.childLanes&t)!==t?(e.childLanes|=t,r!==null&&(r.childLanes|=t)):r!==null&&(r.childLanes&t)!==t&&(r.childLanes|=t),e===n)break;e=e.return}}function Sr(e,t){ta=e,su=vr=null,e=e.dependencies,e!==null&&e.firstContext!==null&&(e.lanes&t&&(Qe=!0),e.firstContext=null)}function lt(e){var t=e._currentValue;if(su!==e)if(e={context:e,memoizedValue:t,next:null},vr===null){if(ta===null)throw Error(T(308));vr=e,ta.dependencies={lanes:0,firstContext:e}}else vr=vr.next=e;return t}var Mn=null;function lu(e){Mn===null?Mn=[e]:Mn.push(e)}function rh(e,t,n,r){var s=t.interleaved;return s===null?(n.next=n,lu(t)):(n.next=s.next,s.next=n),t.interleaved=n,Qt(e,r)}function Qt(e,t){e.lanes|=t;var n=e.alternate;for(n!==null&&(n.lanes|=t),n=e,e=e.return;e!==null;)e.childLanes|=t,n=e.alternate,n!==null&&(n.childLanes|=t),n=e,e=e.return;return n.tag===3?n.stateNode:null}var Gt=!1;function ou(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,interleaved:null,lanes:0},effects:null}}function sh(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,effects:e.effects})}function At(e,t){return{eventTime:e,lane:t,tag:0,payload:null,callback:null,next:null}}function yn(e,t,n){var r=e.updateQueue;if(r===null)return null;if(r=r.shared,X&2){var s=r.pending;return s===null?t.next=t:(t.next=s.next,s.next=t),r.pending=t,Qt(e,n)}return s=r.interleaved,s===null?(t.next=t,lu(r)):(t.next=s.next,s.next=t),r.interleaved=t,Qt(e,n)}function Ri(e,t,n){if(t=t.updateQueue,t!==null&&(t=t.shared,(n&4194240)!==0)){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,Wo(e,n)}}function Ec(e,t){var n=e.updateQueue,r=e.alternate;if(r!==null&&(r=r.updateQueue,n===r)){var s=null,i=null;if(n=n.firstBaseUpdate,n!==null){do{var l={eventTime:n.eventTime,lane:n.lane,tag:n.tag,payload:n.payload,callback:n.callback,next:null};i===null?s=i=l:i=i.next=l,n=n.next}while(n!==null);i===null?s=i=t:i=i.next=t}else s=i=t;n={baseState:r.baseState,firstBaseUpdate:s,lastBaseUpdate:i,shared:r.shared,effects:r.effects},e.updateQueue=n;return}e=n.lastBaseUpdate,e===null?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}function na(e,t,n,r){var s=e.updateQueue;Gt=!1;var i=s.firstBaseUpdate,l=s.lastBaseUpdate,o=s.shared.pending;if(o!==null){s.shared.pending=null;var u=o,c=u.next;u.next=null,l===null?i=c:l.next=c,l=u;var m=e.alternate;m!==null&&(m=m.updateQueue,o=m.lastBaseUpdate,o!==l&&(o===null?m.firstBaseUpdate=c:o.next=c,m.lastBaseUpdate=u))}if(i!==null){var d=s.baseState;l=0,m=c=u=null,o=i;do{var h=o.lane,x=o.eventTime;if((r&h)===h){m!==null&&(m=m.next={eventTime:x,lane:0,tag:o.tag,payload:o.payload,callback:o.callback,next:null});e:{var w=e,g=o;switch(h=t,x=n,g.tag){case 1:if(w=g.payload,typeof w=="function"){d=w.call(x,d,h);break e}d=w;break e;case 3:w.flags=w.flags&-65537|128;case 0:if(w=g.payload,h=typeof w=="function"?w.call(x,d,h):w,h==null)break e;d=ce({},d,h);break e;case 2:Gt=!0}}o.callback!==null&&o.lane!==0&&(e.flags|=64,h=s.effects,h===null?s.effects=[o]:h.push(o))}else x={eventTime:x,lane:h,tag:o.tag,payload:o.payload,callback:o.callback,next:null},m===null?(c=m=x,u=d):m=m.next=x,l|=h;if(o=o.next,o===null){if(o=s.shared.pending,o===null)break;h=o,o=h.next,h.next=null,s.lastBaseUpdate=h,s.shared.pending=null}}while(!0);if(m===null&&(u=d),s.baseState=u,s.firstBaseUpdate=c,s.lastBaseUpdate=m,t=s.shared.interleaved,t!==null){s=t;do l|=s.lane,s=s.next;while(s!==t)}else i===null&&(s.shared.lanes=0);Xn|=l,e.lanes=l,e.memoizedState=d}}function Pc(e,t,n){if(e=t.effects,t.effects=null,e!==null)for(t=0;tn?n:4,e(!0);var r=ll.transition;ll.transition={};try{e(!1),t()}finally{te=n,ll.transition=r}}function wh(){return ot().memoizedState}function Uv(e,t,n){var r=jn(e);if(n={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null},kh(e))Sh(t,n);else if(n=rh(e,t,n,r),n!==null){var s=Ie();vt(n,e,r,s),Nh(n,t,r)}}function Bv(e,t,n){var r=jn(e),s={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null};if(kh(e))Sh(t,s);else{var i=e.alternate;if(e.lanes===0&&(i===null||i.lanes===0)&&(i=t.lastRenderedReducer,i!==null))try{var l=t.lastRenderedState,o=i(l,n);if(s.hasEagerState=!0,s.eagerState=o,xt(o,l)){var u=t.interleaved;u===null?(s.next=s,lu(t)):(s.next=u.next,u.next=s),t.interleaved=s;return}}catch{}finally{}n=rh(e,t,s,r),n!==null&&(s=Ie(),vt(n,e,r,s),Nh(n,t,r))}}function kh(e){var t=e.alternate;return e===ue||t!==null&&t===ue}function Sh(e,t){gs=sa=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function Nh(e,t,n){if(n&4194240){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,Wo(e,n)}}var ia={readContext:lt,useCallback:Pe,useContext:Pe,useEffect:Pe,useImperativeHandle:Pe,useInsertionEffect:Pe,useLayoutEffect:Pe,useMemo:Pe,useReducer:Pe,useRef:Pe,useState:Pe,useDebugValue:Pe,useDeferredValue:Pe,useTransition:Pe,useMutableSource:Pe,useSyncExternalStore:Pe,useId:Pe,unstable_isNewReconciler:!1},Qv={readContext:lt,useCallback:function(e,t){return jt().memoizedState=[e,t===void 0?null:t],e},useContext:lt,useEffect:Oc,useImperativeHandle:function(e,t,n){return n=n!=null?n.concat([e]):null,zi(4194308,4,vh.bind(null,t,e),n)},useLayoutEffect:function(e,t){return zi(4194308,4,e,t)},useInsertionEffect:function(e,t){return zi(4,2,e,t)},useMemo:function(e,t){var n=jt();return t=t===void 0?null:t,e=e(),n.memoizedState=[e,t],e},useReducer:function(e,t,n){var r=jt();return t=n!==void 0?n(t):t,r.memoizedState=r.baseState=t,e={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:t},r.queue=e,e=e.dispatch=Uv.bind(null,ue,e),[r.memoizedState,e]},useRef:function(e){var t=jt();return e={current:e},t.memoizedState=e},useState:Tc,useDebugValue:vu,useDeferredValue:function(e){return jt().memoizedState=e},useTransition:function(){var e=Tc(!1),t=e[0];return e=$v.bind(null,e[1]),jt().memoizedState=e,[t,e]},useMutableSource:function(){},useSyncExternalStore:function(e,t,n){var r=ue,s=jt();if(le){if(n===void 0)throw Error(T(407));n=n()}else{if(n=t(),Se===null)throw Error(T(349));Yn&30||oh(r,t,n)}s.memoizedState=n;var i={value:n,getSnapshot:t};return s.queue=i,Oc(ch.bind(null,r,i,e),[e]),r.flags|=2048,$s(9,uh.bind(null,r,i,n,t),void 0,null),n},useId:function(){var e=jt(),t=Se.identifierPrefix;if(le){var n=It,r=Ft;n=(r&~(1<<32-pt(r)-1)).toString(32)+n,t=":"+t+"R"+n,n=Ds++,0<\/script>",e=e.removeChild(e.firstChild)):typeof r.is=="string"?e=l.createElement(n,{is:r.is}):(e=l.createElement(n),n==="select"&&(l=e,r.multiple?l.multiple=!0:r.size&&(l.size=r.size))):e=l.createElementNS(e,n),e[Nt]=t,e[zs]=r,Mh(e,t,!1,!1),t.stateNode=e;e:{switch(l=Tl(n,r),n){case"dialog":ie("cancel",e),ie("close",e),s=r;break;case"iframe":case"object":case"embed":ie("load",e),s=r;break;case"video":case"audio":for(s=0;sVr&&(t.flags|=128,r=!0,as(i,!1),t.lanes=4194304)}else{if(!r)if(e=ra(l),e!==null){if(t.flags|=128,r=!0,n=e.updateQueue,n!==null&&(t.updateQueue=n,t.flags|=4),as(i,!0),i.tail===null&&i.tailMode==="hidden"&&!l.alternate&&!le)return Te(t),null}else 2*pe()-i.renderingStartTime>Vr&&n!==1073741824&&(t.flags|=128,r=!0,as(i,!1),t.lanes=4194304);i.isBackwards?(l.sibling=t.child,t.child=l):(n=i.last,n!==null?n.sibling=l:t.child=l,i.last=l)}return i.tail!==null?(t=i.tail,i.rendering=t,i.tail=t.sibling,i.renderingStartTime=pe(),t.sibling=null,n=oe.current,se(oe,r?n&1|2:n&1),t):(Te(t),null);case 22:case 23:return ku(),r=t.memoizedState!==null,e!==null&&e.memoizedState!==null!==r&&(t.flags|=8192),r&&t.mode&1?We&1073741824&&(Te(t),t.subtreeFlags&6&&(t.flags|=8192)):Te(t),null;case 24:return null;case 25:return null}throw Error(T(156,t.tag))}function Yv(e,t){switch(nu(t),t.tag){case 1:return Ke(t.type)&&Gi(),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return Br(),ae(Ve),ae(Re),du(),e=t.flags,e&65536&&!(e&128)?(t.flags=e&-65537|128,t):null;case 5:return cu(t),null;case 13:if(ae(oe),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(T(340));$r()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return ae(oe),null;case 4:return Br(),null;case 10:return au(t.type._context),null;case 22:case 23:return ku(),null;case 24:return null;default:return null}}var ki=!1,Le=!1,Xv=typeof WeakSet=="function"?WeakSet:Set,I=null;function xr(e,t){var n=e.ref;if(n!==null)if(typeof n=="function")try{n(null)}catch(r){fe(e,t,r)}else n.current=null}function ro(e,t,n){try{n()}catch(r){fe(e,t,r)}}var Bc=!1;function Zv(e,t){if($l=Hi,e=Uf(),eu(e)){if("selectionStart"in e)var n={start:e.selectionStart,end:e.selectionEnd};else e:{n=(n=e.ownerDocument)&&n.defaultView||window;var r=n.getSelection&&n.getSelection();if(r&&r.rangeCount!==0){n=r.anchorNode;var s=r.anchorOffset,i=r.focusNode;r=r.focusOffset;try{n.nodeType,i.nodeType}catch{n=null;break e}var l=0,o=-1,u=-1,c=0,m=0,d=e,h=null;t:for(;;){for(var x;d!==n||s!==0&&d.nodeType!==3||(o=l+s),d!==i||r!==0&&d.nodeType!==3||(u=l+r),d.nodeType===3&&(l+=d.nodeValue.length),(x=d.firstChild)!==null;)h=d,d=x;for(;;){if(d===e)break t;if(h===n&&++c===s&&(o=l),h===i&&++m===r&&(u=l),(x=d.nextSibling)!==null)break;d=h,h=d.parentNode}d=x}n=o===-1||u===-1?null:{start:o,end:u}}else n=null}n=n||{start:0,end:0}}else n=null;for(Ul={focusedElem:e,selectionRange:n},Hi=!1,I=t;I!==null;)if(t=I,e=t.child,(t.subtreeFlags&1028)!==0&&e!==null)e.return=t,I=e;else for(;I!==null;){t=I;try{var w=t.alternate;if(t.flags&1024)switch(t.tag){case 0:case 11:case 15:break;case 1:if(w!==null){var g=w.memoizedProps,S=w.memoizedState,v=t.stateNode,f=v.getSnapshotBeforeUpdate(t.elementType===t.type?g:ct(t.type,g),S);v.__reactInternalSnapshotBeforeUpdate=f}break;case 3:var p=t.stateNode.containerInfo;p.nodeType===1?p.textContent="":p.nodeType===9&&p.documentElement&&p.removeChild(p.documentElement);break;case 5:case 6:case 4:case 17:break;default:throw Error(T(163))}}catch(j){fe(t,t.return,j)}if(e=t.sibling,e!==null){e.return=t.return,I=e;break}I=t.return}return w=Bc,Bc=!1,w}function js(e,t,n){var r=t.updateQueue;if(r=r!==null?r.lastEffect:null,r!==null){var s=r=r.next;do{if((s.tag&e)===e){var i=s.destroy;s.destroy=void 0,i!==void 0&&ro(t,n,i)}s=s.next}while(s!==r)}}function Na(e,t){if(t=t.updateQueue,t=t!==null?t.lastEffect:null,t!==null){var n=t=t.next;do{if((n.tag&e)===e){var r=n.create;n.destroy=r()}n=n.next}while(n!==t)}}function so(e){var t=e.ref;if(t!==null){var n=e.stateNode;switch(e.tag){case 5:e=n;break;default:e=n}typeof t=="function"?t(e):t.current=e}}function Ih(e){var t=e.alternate;t!==null&&(e.alternate=null,Ih(t)),e.child=null,e.deletions=null,e.sibling=null,e.tag===5&&(t=e.stateNode,t!==null&&(delete t[Nt],delete t[zs],delete t[Vl],delete t[zv],delete t[Fv])),e.stateNode=null,e.return=null,e.dependencies=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.stateNode=null,e.updateQueue=null}function Dh(e){return e.tag===5||e.tag===3||e.tag===4}function Qc(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||Dh(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.flags&2||e.child===null||e.tag===4)continue e;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function io(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.nodeType===8?n.parentNode.insertBefore(e,t):n.insertBefore(e,t):(n.nodeType===8?(t=n.parentNode,t.insertBefore(e,n)):(t=n,t.appendChild(e)),n=n._reactRootContainer,n!=null||t.onclick!==null||(t.onclick=Ji));else if(r!==4&&(e=e.child,e!==null))for(io(e,t,n),e=e.sibling;e!==null;)io(e,t,n),e=e.sibling}function ao(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(r!==4&&(e=e.child,e!==null))for(ao(e,t,n),e=e.sibling;e!==null;)ao(e,t,n),e=e.sibling}var Ce=null,ht=!1;function Wt(e,t,n){for(n=n.child;n!==null;)Ah(e,t,n),n=n.sibling}function Ah(e,t,n){if(bt&&typeof bt.onCommitFiberUnmount=="function")try{bt.onCommitFiberUnmount(va,n)}catch{}switch(n.tag){case 5:Le||xr(n,t);case 6:var r=Ce,s=ht;Ce=null,Wt(e,t,n),Ce=r,ht=s,Ce!==null&&(ht?(e=Ce,n=n.stateNode,e.nodeType===8?e.parentNode.removeChild(n):e.removeChild(n)):Ce.removeChild(n.stateNode));break;case 18:Ce!==null&&(ht?(e=Ce,n=n.stateNode,e.nodeType===8?sl(e.parentNode,n):e.nodeType===1&&sl(e,n),Ts(e)):sl(Ce,n.stateNode));break;case 4:r=Ce,s=ht,Ce=n.stateNode.containerInfo,ht=!0,Wt(e,t,n),Ce=r,ht=s;break;case 0:case 11:case 14:case 15:if(!Le&&(r=n.updateQueue,r!==null&&(r=r.lastEffect,r!==null))){s=r=r.next;do{var i=s,l=i.destroy;i=i.tag,l!==void 0&&(i&2||i&4)&&ro(n,t,l),s=s.next}while(s!==r)}Wt(e,t,n);break;case 1:if(!Le&&(xr(n,t),r=n.stateNode,typeof r.componentWillUnmount=="function"))try{r.props=n.memoizedProps,r.state=n.memoizedState,r.componentWillUnmount()}catch(o){fe(n,t,o)}Wt(e,t,n);break;case 21:Wt(e,t,n);break;case 22:n.mode&1?(Le=(r=Le)||n.memoizedState!==null,Wt(e,t,n),Le=r):Wt(e,t,n);break;default:Wt(e,t,n)}}function Vc(e){var t=e.updateQueue;if(t!==null){e.updateQueue=null;var n=e.stateNode;n===null&&(n=e.stateNode=new Xv),t.forEach(function(r){var s=ox.bind(null,e,r);n.has(r)||(n.add(r),r.then(s,s))})}}function ut(e,t){var n=t.deletions;if(n!==null)for(var r=0;rs&&(s=l),r&=~i}if(r=s,r=pe()-r,r=(120>r?120:480>r?480:1080>r?1080:1920>r?1920:3e3>r?3e3:4320>r?4320:1960*tx(r/1960))-r,10e?16:e,cn===null)var r=!1;else{if(e=cn,cn=null,oa=0,X&6)throw Error(T(331));var s=X;for(X|=4,I=e.current;I!==null;){var i=I,l=i.child;if(I.flags&16){var o=i.deletions;if(o!==null){for(var u=0;upe()-ju?Hn(e,0):gu|=n),He(e,t)}function Wh(e,t){t===0&&(e.mode&1?(t=hi,hi<<=1,!(hi&130023424)&&(hi=4194304)):t=1);var n=Ie();e=Qt(e,t),e!==null&&(ti(e,t,n),He(e,n))}function lx(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),Wh(e,n)}function ox(e,t){var n=0;switch(e.tag){case 13:var r=e.stateNode,s=e.memoizedState;s!==null&&(n=s.retryLane);break;case 19:r=e.stateNode;break;default:throw Error(T(314))}r!==null&&r.delete(t),Wh(e,n)}var qh;qh=function(e,t,n){if(e!==null)if(e.memoizedProps!==t.pendingProps||Ve.current)Qe=!0;else{if(!(e.lanes&n)&&!(t.flags&128))return Qe=!1,Jv(e,t,n);Qe=!!(e.flags&131072)}else Qe=!1,le&&t.flags&1048576&&Xf(t,Zi,t.index);switch(t.lanes=0,t.tag){case 2:var r=t.type;Fi(e,t),e=t.pendingProps;var s=Ar(t,Re.current);Sr(t,n),s=hu(null,t,r,e,s,n);var i=mu();return t.flags|=1,typeof s=="object"&&s!==null&&typeof s.render=="function"&&s.$$typeof===void 0?(t.tag=1,t.memoizedState=null,t.updateQueue=null,Ke(r)?(i=!0,Yi(t)):i=!1,t.memoizedState=s.state!==null&&s.state!==void 0?s.state:null,ou(t),s.updater=Sa,t.stateNode=s,s._reactInternals=t,Gl(t,r,e,n),t=Zl(null,t,r,!0,i,n)):(t.tag=0,le&&i&&tu(t),ze(null,t,s,n),t=t.child),t;case 16:r=t.elementType;e:{switch(Fi(e,t),e=t.pendingProps,s=r._init,r=s(r._payload),t.type=r,s=t.tag=cx(r),e=ct(r,e),s){case 0:t=Xl(null,t,r,e,n);break e;case 1:t=Ac(null,t,r,e,n);break e;case 11:t=Ic(null,t,r,e,n);break e;case 14:t=Dc(null,t,r,ct(r.type,e),n);break e}throw Error(T(306,r,""))}return t;case 0:return r=t.type,s=t.pendingProps,s=t.elementType===r?s:ct(r,s),Xl(e,t,r,s,n);case 1:return r=t.type,s=t.pendingProps,s=t.elementType===r?s:ct(r,s),Ac(e,t,r,s,n);case 3:e:{if(Oh(t),e===null)throw Error(T(387));r=t.pendingProps,i=t.memoizedState,s=i.element,sh(e,t),na(t,r,null,n);var l=t.memoizedState;if(r=l.element,i.isDehydrated)if(i={element:r,isDehydrated:!1,cache:l.cache,pendingSuspenseBoundaries:l.pendingSuspenseBoundaries,transitions:l.transitions},t.updateQueue.baseState=i,t.memoizedState=i,t.flags&256){s=Qr(Error(T(423)),t),t=$c(e,t,r,n,s);break e}else if(r!==s){s=Qr(Error(T(424)),t),t=$c(e,t,r,n,s);break e}else for(qe=xn(t.stateNode.containerInfo.firstChild),Je=t,le=!0,mt=null,n=nh(t,null,r,n),t.child=n;n;)n.flags=n.flags&-3|4096,n=n.sibling;else{if($r(),r===s){t=Vt(e,t,n);break e}ze(e,t,r,n)}t=t.child}return t;case 5:return ih(t),e===null&&Wl(t),r=t.type,s=t.pendingProps,i=e!==null?e.memoizedProps:null,l=s.children,Bl(r,s)?l=null:i!==null&&Bl(r,i)&&(t.flags|=32),Th(e,t),ze(e,t,l,n),t.child;case 6:return e===null&&Wl(t),null;case 13:return Lh(e,t,n);case 4:return uu(t,t.stateNode.containerInfo),r=t.pendingProps,e===null?t.child=Ur(t,null,r,n):ze(e,t,r,n),t.child;case 11:return r=t.type,s=t.pendingProps,s=t.elementType===r?s:ct(r,s),Ic(e,t,r,s,n);case 7:return ze(e,t,t.pendingProps,n),t.child;case 8:return ze(e,t,t.pendingProps.children,n),t.child;case 12:return ze(e,t,t.pendingProps.children,n),t.child;case 10:e:{if(r=t.type._context,s=t.pendingProps,i=t.memoizedProps,l=s.value,se(ea,r._currentValue),r._currentValue=l,i!==null)if(xt(i.value,l)){if(i.children===s.children&&!Ve.current){t=Vt(e,t,n);break e}}else for(i=t.child,i!==null&&(i.return=t);i!==null;){var o=i.dependencies;if(o!==null){l=i.child;for(var u=o.firstContext;u!==null;){if(u.context===r){if(i.tag===1){u=At(-1,n&-n),u.tag=2;var c=i.updateQueue;if(c!==null){c=c.shared;var m=c.pending;m===null?u.next=u:(u.next=m.next,m.next=u),c.pending=u}}i.lanes|=n,u=i.alternate,u!==null&&(u.lanes|=n),ql(i.return,n,t),o.lanes|=n;break}u=u.next}}else if(i.tag===10)l=i.type===t.type?null:i.child;else if(i.tag===18){if(l=i.return,l===null)throw Error(T(341));l.lanes|=n,o=l.alternate,o!==null&&(o.lanes|=n),ql(l,n,t),l=i.sibling}else l=i.child;if(l!==null)l.return=i;else for(l=i;l!==null;){if(l===t){l=null;break}if(i=l.sibling,i!==null){i.return=l.return,l=i;break}l=l.return}i=l}ze(e,t,s.children,n),t=t.child}return t;case 9:return s=t.type,r=t.pendingProps.children,Sr(t,n),s=lt(s),r=r(s),t.flags|=1,ze(e,t,r,n),t.child;case 14:return r=t.type,s=ct(r,t.pendingProps),s=ct(r.type,s),Dc(e,t,r,s,n);case 15:return Eh(e,t,t.type,t.pendingProps,n);case 17:return r=t.type,s=t.pendingProps,s=t.elementType===r?s:ct(r,s),Fi(e,t),t.tag=1,Ke(r)?(e=!0,Yi(t)):e=!1,Sr(t,n),bh(t,r,s),Gl(t,r,s,n),Zl(null,t,r,!0,e,n);case 19:return Rh(e,t,n);case 22:return Ph(e,t,n)}throw Error(T(156,t.tag))};function Jh(e,t){return kf(e,t)}function ux(e,t,n,r){this.tag=e,this.key=n,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=t,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function it(e,t,n,r){return new ux(e,t,n,r)}function Nu(e){return e=e.prototype,!(!e||!e.isReactComponent)}function cx(e){if(typeof e=="function")return Nu(e)?1:0;if(e!=null){if(e=e.$$typeof,e===Qo)return 11;if(e===Vo)return 14}return 2}function wn(e,t){var n=e.alternate;return n===null?(n=it(e.tag,t,e.key,e.mode),n.elementType=e.elementType,n.type=e.type,n.stateNode=e.stateNode,n.alternate=e,e.alternate=n):(n.pendingProps=t,n.type=e.type,n.flags=0,n.subtreeFlags=0,n.deletions=null),n.flags=e.flags&14680064,n.childLanes=e.childLanes,n.lanes=e.lanes,n.child=e.child,n.memoizedProps=e.memoizedProps,n.memoizedState=e.memoizedState,n.updateQueue=e.updateQueue,t=e.dependencies,n.dependencies=t===null?null:{lanes:t.lanes,firstContext:t.firstContext},n.sibling=e.sibling,n.index=e.index,n.ref=e.ref,n}function Ai(e,t,n,r,s,i){var l=2;if(r=e,typeof e=="function")Nu(e)&&(l=1);else if(typeof e=="string")l=5;else e:switch(e){case or:return Wn(n.children,s,i,t);case Bo:l=8,s|=8;break;case jl:return e=it(12,n,t,s|2),e.elementType=jl,e.lanes=i,e;case wl:return e=it(13,n,t,s),e.elementType=wl,e.lanes=i,e;case kl:return e=it(19,n,t,s),e.elementType=kl,e.lanes=i,e;case sf:return Ca(n,s,i,t);default:if(typeof e=="object"&&e!==null)switch(e.$$typeof){case nf:l=10;break e;case rf:l=9;break e;case Qo:l=11;break e;case Vo:l=14;break e;case Jt:l=16,r=null;break e}throw Error(T(130,e==null?e:typeof e,""))}return t=it(l,n,t,s),t.elementType=e,t.type=r,t.lanes=i,t}function Wn(e,t,n,r){return e=it(7,e,r,t),e.lanes=n,e}function Ca(e,t,n,r){return e=it(22,e,r,t),e.elementType=sf,e.lanes=n,e.stateNode={isHidden:!1},e}function fl(e,t,n){return e=it(6,e,null,t),e.lanes=n,e}function hl(e,t,n){return t=it(4,e.children!==null?e.children:[],e.key,t),t.lanes=n,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}function dx(e,t,n,r,s){this.tag=t,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.pendingContext=this.context=null,this.callbackPriority=0,this.eventTimes=Wa(0),this.expirationTimes=Wa(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=Wa(0),this.identifierPrefix=r,this.onRecoverableError=s,this.mutableSourceEagerHydrationData=null}function bu(e,t,n,r,s,i,l,o,u){return e=new dx(e,t,n,o,u),t===1?(t=1,i===!0&&(t|=8)):t=0,i=it(3,null,null,t),e.current=i,i.stateNode=e,i.memoizedState={element:r,isDehydrated:n,cache:null,transitions:null,pendingSuspenseBoundaries:null},ou(i),e}function fx(e,t,n){var r=3"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(Zh)}catch(e){console.error(e)}}Zh(),Xd.exports=Xe;var xx=Xd.exports,Xc=xx;yl.createRoot=Xc.createRoot,yl.hydrateRoot=Xc.hydrateRoot;var Gr=class{constructor(){this.listeners=new Set,this.subscribe=this.subscribe.bind(this)}subscribe(e){return this.listeners.add(e),this.onSubscribe(),()=>{this.listeners.delete(e),this.onUnsubscribe()}}hasListeners(){return this.listeners.size>0}onSubscribe(){}onUnsubscribe(){}},yx={setTimeout:(e,t)=>setTimeout(e,t),clearTimeout:e=>clearTimeout(e),setInterval:(e,t)=>setInterval(e,t),clearInterval:e=>clearInterval(e)},Zt,Ro,Pd,gx=(Pd=class{constructor(){U(this,Zt,yx);U(this,Ro,!1)}setTimeoutProvider(e){z(this,Zt,e)}setTimeout(e,t){return y(this,Zt).setTimeout(e,t)}clearTimeout(e){y(this,Zt).clearTimeout(e)}setInterval(e,t){return y(this,Zt).setInterval(e,t)}clearInterval(e){y(this,Zt).clearInterval(e)}},Zt=new WeakMap,Ro=new WeakMap,Pd),Fn=new gx;function jx(e){setTimeout(e,0)}var er=typeof window>"u"||"Deno"in globalThis;function Fe(){}function wx(e,t){return typeof e=="function"?e(t):e}function fo(e){return typeof e=="number"&&e>=0&&e!==1/0}function em(e,t){return Math.max(e+(t||0)-Date.now(),0)}function kn(e,t){return typeof e=="function"?e(t):e}function nt(e,t){return typeof e=="function"?e(t):e}function Zc(e,t){const{type:n="all",exact:r,fetchStatus:s,predicate:i,queryKey:l,stale:o}=e;if(l){if(r){if(t.queryHash!==Pu(l,t.options))return!1}else if(!Bs(t.queryKey,l))return!1}if(n!=="all"){const u=t.isActive();if(n==="active"&&!u||n==="inactive"&&u)return!1}return!(typeof o=="boolean"&&t.isStale()!==o||s&&s!==t.state.fetchStatus||i&&!i(t))}function ed(e,t){const{exact:n,status:r,predicate:s,mutationKey:i}=e;if(i){if(!t.options.mutationKey)return!1;if(n){if(tr(t.options.mutationKey)!==tr(i))return!1}else if(!Bs(t.options.mutationKey,i))return!1}return!(r&&t.state.status!==r||s&&!s(t))}function Pu(e,t){return((t==null?void 0:t.queryKeyHashFn)||tr)(e)}function tr(e){return JSON.stringify(e,(t,n)=>ho(n)?Object.keys(n).sort().reduce((r,s)=>(r[s]=n[s],r),{}):n)}function Bs(e,t){return e===t?!0:typeof e!=typeof t?!1:e&&t&&typeof e=="object"&&typeof t=="object"?Object.keys(t).every(n=>Bs(e[n],t[n])):!1}var kx=Object.prototype.hasOwnProperty;function tm(e,t,n=0){if(e===t)return e;if(n>500)return t;const r=td(e)&&td(t);if(!r&&!(ho(e)&&ho(t)))return t;const i=(r?e:Object.keys(e)).length,l=r?t:Object.keys(t),o=l.length,u=r?new Array(o):{};let c=0;for(let m=0;m{Fn.setTimeout(t,e)})}function mo(e,t,n){return typeof n.structuralSharing=="function"?n.structuralSharing(e,t):n.structuralSharing!==!1?tm(e,t):t}function Nx(e,t,n=0){const r=[...e,t];return n&&r.length>n?r.slice(1):r}function bx(e,t,n=0){const r=[t,...e];return n&&r.length>n?r.slice(0,-1):r}var Tu=Symbol();function nm(e,t){return!e.queryFn&&(t!=null&&t.initialPromise)?()=>t.initialPromise:!e.queryFn||e.queryFn===Tu?()=>Promise.reject(new Error(`Missing queryFn: '${e.queryHash}'`)):e.queryFn}function Ou(e,t){return typeof e=="function"?e(...t):!!e}function Cx(e,t,n){let r=!1,s;return Object.defineProperty(e,"signal",{enumerable:!0,get:()=>(s??(s=t()),r||(r=!0,s.aborted?n():s.addEventListener("abort",n,{once:!0})),s)}),e}var In,en,Cr,Td,_x=(Td=class extends Gr{constructor(){super();U(this,In);U(this,en);U(this,Cr);z(this,Cr,t=>{if(!er&&window.addEventListener){const n=()=>t();return window.addEventListener("visibilitychange",n,!1),()=>{window.removeEventListener("visibilitychange",n)}}})}onSubscribe(){y(this,en)||this.setEventListener(y(this,Cr))}onUnsubscribe(){var t;this.hasListeners()||((t=y(this,en))==null||t.call(this),z(this,en,void 0))}setEventListener(t){var n;z(this,Cr,t),(n=y(this,en))==null||n.call(this),z(this,en,t(r=>{typeof r=="boolean"?this.setFocused(r):this.onFocus()}))}setFocused(t){y(this,In)!==t&&(z(this,In,t),this.onFocus())}onFocus(){const t=this.isFocused();this.listeners.forEach(n=>{n(t)})}isFocused(){var t;return typeof y(this,In)=="boolean"?y(this,In):((t=globalThis.document)==null?void 0:t.visibilityState)!=="hidden"}},In=new WeakMap,en=new WeakMap,Cr=new WeakMap,Td),Lu=new _x;function po(){let e,t;const n=new Promise((s,i)=>{e=s,t=i});n.status="pending",n.catch(()=>{});function r(s){Object.assign(n,s),delete n.resolve,delete n.reject}return n.resolve=s=>{r({status:"fulfilled",value:s}),e(s)},n.reject=s=>{r({status:"rejected",reason:s}),t(s)},n}var Ex=jx;function Px(){let e=[],t=0,n=o=>{o()},r=o=>{o()},s=Ex;const i=o=>{t?e.push(o):s(()=>{n(o)})},l=()=>{const o=e;e=[],o.length&&s(()=>{r(()=>{o.forEach(u=>{n(u)})})})};return{batch:o=>{let u;t++;try{u=o()}finally{t--,t||l()}return u},batchCalls:o=>(...u)=>{i(()=>{o(...u)})},schedule:i,setNotifyFunction:o=>{n=o},setBatchNotifyFunction:o=>{r=o},setScheduler:o=>{s=o}}}var ge=Px(),_r,tn,Er,Od,Tx=(Od=class extends Gr{constructor(){super();U(this,_r,!0);U(this,tn);U(this,Er);z(this,Er,t=>{if(!er&&window.addEventListener){const n=()=>t(!0),r=()=>t(!1);return window.addEventListener("online",n,!1),window.addEventListener("offline",r,!1),()=>{window.removeEventListener("online",n),window.removeEventListener("offline",r)}}})}onSubscribe(){y(this,tn)||this.setEventListener(y(this,Er))}onUnsubscribe(){var t;this.hasListeners()||((t=y(this,tn))==null||t.call(this),z(this,tn,void 0))}setEventListener(t){var n;z(this,Er,t),(n=y(this,tn))==null||n.call(this),z(this,tn,t(this.setOnline.bind(this)))}setOnline(t){y(this,_r)!==t&&(z(this,_r,t),this.listeners.forEach(r=>{r(t)}))}isOnline(){return y(this,_r)}},_r=new WeakMap,tn=new WeakMap,Er=new WeakMap,Od),fa=new Tx;function Ox(e){return Math.min(1e3*2**e,3e4)}function rm(e){return(e??"online")==="online"?fa.isOnline():!0}var vo=class extends Error{constructor(e){super("CancelledError"),this.revert=e==null?void 0:e.revert,this.silent=e==null?void 0:e.silent}};function sm(e){let t=!1,n=0,r;const s=po(),i=()=>s.status!=="pending",l=g=>{var S;if(!i()){const v=new vo(g);h(v),(S=e.onCancel)==null||S.call(e,v)}},o=()=>{t=!0},u=()=>{t=!1},c=()=>Lu.isFocused()&&(e.networkMode==="always"||fa.isOnline())&&e.canRun(),m=()=>rm(e.networkMode)&&e.canRun(),d=g=>{i()||(r==null||r(),s.resolve(g))},h=g=>{i()||(r==null||r(),s.reject(g))},x=()=>new Promise(g=>{var S;r=v=>{(i()||c())&&g(v)},(S=e.onPause)==null||S.call(e)}).then(()=>{var g;r=void 0,i()||(g=e.onContinue)==null||g.call(e)}),w=()=>{if(i())return;let g;const S=n===0?e.initialPromise:void 0;try{g=S??e.fn()}catch(v){g=Promise.reject(v)}Promise.resolve(g).then(d).catch(v=>{var N;if(i())return;const f=e.retry??(er?0:3),p=e.retryDelay??Ox,j=typeof p=="function"?p(n,v):p,C=f===!0||typeof f=="number"&&nc()?void 0:x()).then(()=>{t?h(v):w()})})};return{promise:s,status:()=>s.status,cancel:l,continue:()=>(r==null||r(),s),cancelRetry:o,continueRetry:u,canStart:m,start:()=>(m()?w():x().then(w),s)}}var Dn,Ld,im=(Ld=class{constructor(){U(this,Dn)}destroy(){this.clearGcTimeout()}scheduleGc(){this.clearGcTimeout(),fo(this.gcTime)&&z(this,Dn,Fn.setTimeout(()=>{this.optionalRemove()},this.gcTime))}updateGcTime(e){this.gcTime=Math.max(this.gcTime||0,e??(er?1/0:5*60*1e3))}clearGcTimeout(){y(this,Dn)&&(Fn.clearTimeout(y(this,Dn)),z(this,Dn,void 0))}},Dn=new WeakMap,Ld),An,Pr,tt,$n,we,Js,Un,dt,Pt,Rd,Lx=(Rd=class extends im{constructor(t){super();U(this,dt);U(this,An);U(this,Pr);U(this,tt);U(this,$n);U(this,we);U(this,Js);U(this,Un);z(this,Un,!1),z(this,Js,t.defaultOptions),this.setOptions(t.options),this.observers=[],z(this,$n,t.client),z(this,tt,y(this,$n).getQueryCache()),this.queryKey=t.queryKey,this.queryHash=t.queryHash,z(this,An,sd(this.options)),this.state=t.state??y(this,An),this.scheduleGc()}get meta(){return this.options.meta}get promise(){var t;return(t=y(this,we))==null?void 0:t.promise}setOptions(t){if(this.options={...y(this,Js),...t},this.updateGcTime(this.options.gcTime),this.state&&this.state.data===void 0){const n=sd(this.options);n.data!==void 0&&(this.setState(rd(n.data,n.dataUpdatedAt)),z(this,An,n))}}optionalRemove(){!this.observers.length&&this.state.fetchStatus==="idle"&&y(this,tt).remove(this)}setData(t,n){const r=mo(this.state.data,t,this.options);return W(this,dt,Pt).call(this,{data:r,type:"success",dataUpdatedAt:n==null?void 0:n.updatedAt,manual:n==null?void 0:n.manual}),r}setState(t,n){W(this,dt,Pt).call(this,{type:"setState",state:t,setStateOptions:n})}cancel(t){var r,s;const n=(r=y(this,we))==null?void 0:r.promise;return(s=y(this,we))==null||s.cancel(t),n?n.then(Fe).catch(Fe):Promise.resolve()}destroy(){super.destroy(),this.cancel({silent:!0})}reset(){this.destroy(),this.setState(y(this,An))}isActive(){return this.observers.some(t=>nt(t.options.enabled,this)!==!1)}isDisabled(){return this.getObserversCount()>0?!this.isActive():this.options.queryFn===Tu||this.state.dataUpdateCount+this.state.errorUpdateCount===0}isStatic(){return this.getObserversCount()>0?this.observers.some(t=>kn(t.options.staleTime,this)==="static"):!1}isStale(){return this.getObserversCount()>0?this.observers.some(t=>t.getCurrentResult().isStale):this.state.data===void 0||this.state.isInvalidated}isStaleByTime(t=0){return this.state.data===void 0?!0:t==="static"?!1:this.state.isInvalidated?!0:!em(this.state.dataUpdatedAt,t)}onFocus(){var n;const t=this.observers.find(r=>r.shouldFetchOnWindowFocus());t==null||t.refetch({cancelRefetch:!1}),(n=y(this,we))==null||n.continue()}onOnline(){var n;const t=this.observers.find(r=>r.shouldFetchOnReconnect());t==null||t.refetch({cancelRefetch:!1}),(n=y(this,we))==null||n.continue()}addObserver(t){this.observers.includes(t)||(this.observers.push(t),this.clearGcTimeout(),y(this,tt).notify({type:"observerAdded",query:this,observer:t}))}removeObserver(t){this.observers.includes(t)&&(this.observers=this.observers.filter(n=>n!==t),this.observers.length||(y(this,we)&&(y(this,Un)?y(this,we).cancel({revert:!0}):y(this,we).cancelRetry()),this.scheduleGc()),y(this,tt).notify({type:"observerRemoved",query:this,observer:t}))}getObserversCount(){return this.observers.length}invalidate(){this.state.isInvalidated||W(this,dt,Pt).call(this,{type:"invalidate"})}async fetch(t,n){var u,c,m,d,h,x,w,g,S,v,f,p;if(this.state.fetchStatus!=="idle"&&((u=y(this,we))==null?void 0:u.status())!=="rejected"){if(this.state.data!==void 0&&(n!=null&&n.cancelRefetch))this.cancel({silent:!0});else if(y(this,we))return y(this,we).continueRetry(),y(this,we).promise}if(t&&this.setOptions(t),!this.options.queryFn){const j=this.observers.find(C=>C.options.queryFn);j&&this.setOptions(j.options)}const r=new AbortController,s=j=>{Object.defineProperty(j,"signal",{enumerable:!0,get:()=>(z(this,Un,!0),r.signal)})},i=()=>{const j=nm(this.options,n),N=(()=>{const b={client:y(this,$n),queryKey:this.queryKey,meta:this.meta};return s(b),b})();return z(this,Un,!1),this.options.persister?this.options.persister(j,N,this):j(N)},o=(()=>{const j={fetchOptions:n,options:this.options,queryKey:this.queryKey,client:y(this,$n),state:this.state,fetchFn:i};return s(j),j})();(c=this.options.behavior)==null||c.onFetch(o,this),z(this,Pr,this.state),(this.state.fetchStatus==="idle"||this.state.fetchMeta!==((m=o.fetchOptions)==null?void 0:m.meta))&&W(this,dt,Pt).call(this,{type:"fetch",meta:(d=o.fetchOptions)==null?void 0:d.meta}),z(this,we,sm({initialPromise:n==null?void 0:n.initialPromise,fn:o.fetchFn,onCancel:j=>{j instanceof vo&&j.revert&&this.setState({...y(this,Pr),fetchStatus:"idle"}),r.abort()},onFail:(j,C)=>{W(this,dt,Pt).call(this,{type:"failed",failureCount:j,error:C})},onPause:()=>{W(this,dt,Pt).call(this,{type:"pause"})},onContinue:()=>{W(this,dt,Pt).call(this,{type:"continue"})},retry:o.options.retry,retryDelay:o.options.retryDelay,networkMode:o.options.networkMode,canRun:()=>!0}));try{const j=await y(this,we).start();if(j===void 0)throw new Error(`${this.queryHash} data is undefined`);return this.setData(j),(x=(h=y(this,tt).config).onSuccess)==null||x.call(h,j,this),(g=(w=y(this,tt).config).onSettled)==null||g.call(w,j,this.state.error,this),j}catch(j){if(j instanceof vo){if(j.silent)return y(this,we).promise;if(j.revert){if(this.state.data===void 0)throw j;return this.state.data}}throw W(this,dt,Pt).call(this,{type:"error",error:j}),(v=(S=y(this,tt).config).onError)==null||v.call(S,j,this),(p=(f=y(this,tt).config).onSettled)==null||p.call(f,this.state.data,j,this),j}finally{this.scheduleGc()}}},An=new WeakMap,Pr=new WeakMap,tt=new WeakMap,$n=new WeakMap,we=new WeakMap,Js=new WeakMap,Un=new WeakMap,dt=new WeakSet,Pt=function(t){const n=r=>{switch(t.type){case"failed":return{...r,fetchFailureCount:t.failureCount,fetchFailureReason:t.error};case"pause":return{...r,fetchStatus:"paused"};case"continue":return{...r,fetchStatus:"fetching"};case"fetch":return{...r,...am(r.data,this.options),fetchMeta:t.meta??null};case"success":const s={...r,...rd(t.data,t.dataUpdatedAt),dataUpdateCount:r.dataUpdateCount+1,...!t.manual&&{fetchStatus:"idle",fetchFailureCount:0,fetchFailureReason:null}};return z(this,Pr,t.manual?s:void 0),s;case"error":const i=t.error;return{...r,error:i,errorUpdateCount:r.errorUpdateCount+1,errorUpdatedAt:Date.now(),fetchFailureCount:r.fetchFailureCount+1,fetchFailureReason:i,fetchStatus:"idle",status:"error",isInvalidated:!0};case"invalidate":return{...r,isInvalidated:!0};case"setState":return{...r,...t.state}}};this.state=n(this.state),ge.batch(()=>{this.observers.forEach(r=>{r.onQueryUpdate()}),y(this,tt).notify({query:this,type:"updated",action:t})})},Rd);function am(e,t){return{fetchFailureCount:0,fetchFailureReason:null,fetchStatus:rm(t.networkMode)?"fetching":"paused",...e===void 0&&{error:null,status:"pending"}}}function rd(e,t){return{data:e,dataUpdatedAt:t??Date.now(),error:null,isInvalidated:!1,status:"success"}}function sd(e){const t=typeof e.initialData=="function"?e.initialData():e.initialData,n=t!==void 0,r=n?typeof e.initialDataUpdatedAt=="function"?e.initialDataUpdatedAt():e.initialDataUpdatedAt:0;return{data:t,dataUpdateCount:0,dataUpdatedAt:n?r??Date.now():0,error:null,errorUpdateCount:0,errorUpdatedAt:0,fetchFailureCount:0,fetchFailureReason:null,fetchMeta:null,isInvalidated:!1,status:n?"success":"pending",fetchStatus:"idle"}}var $e,G,Gs,Me,Bn,Tr,Lt,nn,Ys,Or,Lr,Qn,Vn,rn,Rr,ee,hs,xo,yo,go,jo,wo,ko,So,lm,Md,Rx=(Md=class extends Gr{constructor(t,n){super();U(this,ee);U(this,$e);U(this,G);U(this,Gs);U(this,Me);U(this,Bn);U(this,Tr);U(this,Lt);U(this,nn);U(this,Ys);U(this,Or);U(this,Lr);U(this,Qn);U(this,Vn);U(this,rn);U(this,Rr,new Set);this.options=n,z(this,$e,t),z(this,nn,null),z(this,Lt,po()),this.bindMethods(),this.setOptions(n)}bindMethods(){this.refetch=this.refetch.bind(this)}onSubscribe(){this.listeners.size===1&&(y(this,G).addObserver(this),id(y(this,G),this.options)?W(this,ee,hs).call(this):this.updateResult(),W(this,ee,jo).call(this))}onUnsubscribe(){this.hasListeners()||this.destroy()}shouldFetchOnReconnect(){return No(y(this,G),this.options,this.options.refetchOnReconnect)}shouldFetchOnWindowFocus(){return No(y(this,G),this.options,this.options.refetchOnWindowFocus)}destroy(){this.listeners=new Set,W(this,ee,wo).call(this),W(this,ee,ko).call(this),y(this,G).removeObserver(this)}setOptions(t){const n=this.options,r=y(this,G);if(this.options=y(this,$e).defaultQueryOptions(t),this.options.enabled!==void 0&&typeof this.options.enabled!="boolean"&&typeof this.options.enabled!="function"&&typeof nt(this.options.enabled,y(this,G))!="boolean")throw new Error("Expected enabled to be a boolean or a callback that returns a boolean");W(this,ee,So).call(this),y(this,G).setOptions(this.options),n._defaulted&&!da(this.options,n)&&y(this,$e).getQueryCache().notify({type:"observerOptionsUpdated",query:y(this,G),observer:this});const s=this.hasListeners();s&&ad(y(this,G),r,this.options,n)&&W(this,ee,hs).call(this),this.updateResult(),s&&(y(this,G)!==r||nt(this.options.enabled,y(this,G))!==nt(n.enabled,y(this,G))||kn(this.options.staleTime,y(this,G))!==kn(n.staleTime,y(this,G)))&&W(this,ee,xo).call(this);const i=W(this,ee,yo).call(this);s&&(y(this,G)!==r||nt(this.options.enabled,y(this,G))!==nt(n.enabled,y(this,G))||i!==y(this,rn))&&W(this,ee,go).call(this,i)}getOptimisticResult(t){const n=y(this,$e).getQueryCache().build(y(this,$e),t),r=this.createResult(n,t);return zx(this,r)&&(z(this,Me,r),z(this,Tr,this.options),z(this,Bn,y(this,G).state)),r}getCurrentResult(){return y(this,Me)}trackResult(t,n){return new Proxy(t,{get:(r,s)=>(this.trackProp(s),n==null||n(s),s==="promise"&&(this.trackProp("data"),!this.options.experimental_prefetchInRender&&y(this,Lt).status==="pending"&&y(this,Lt).reject(new Error("experimental_prefetchInRender feature flag is not enabled"))),Reflect.get(r,s))})}trackProp(t){y(this,Rr).add(t)}getCurrentQuery(){return y(this,G)}refetch({...t}={}){return this.fetch({...t})}fetchOptimistic(t){const n=y(this,$e).defaultQueryOptions(t),r=y(this,$e).getQueryCache().build(y(this,$e),n);return r.fetch().then(()=>this.createResult(r,n))}fetch(t){return W(this,ee,hs).call(this,{...t,cancelRefetch:t.cancelRefetch??!0}).then(()=>(this.updateResult(),y(this,Me)))}createResult(t,n){var F;const r=y(this,G),s=this.options,i=y(this,Me),l=y(this,Bn),o=y(this,Tr),c=t!==r?t.state:y(this,Gs),{state:m}=t;let d={...m},h=!1,x;if(n._optimisticResults){const O=this.hasListeners(),Q=!O&&id(t,n),D=O&&ad(t,r,n,s);(Q||D)&&(d={...d,...am(m.data,t.options)}),n._optimisticResults==="isRestoring"&&(d.fetchStatus="idle")}let{error:w,errorUpdatedAt:g,status:S}=d;x=d.data;let v=!1;if(n.placeholderData!==void 0&&x===void 0&&S==="pending"){let O;i!=null&&i.isPlaceholderData&&n.placeholderData===(o==null?void 0:o.placeholderData)?(O=i.data,v=!0):O=typeof n.placeholderData=="function"?n.placeholderData((F=y(this,Lr))==null?void 0:F.state.data,y(this,Lr)):n.placeholderData,O!==void 0&&(S="success",x=mo(i==null?void 0:i.data,O,n),h=!0)}if(n.select&&x!==void 0&&!v)if(i&&x===(l==null?void 0:l.data)&&n.select===y(this,Ys))x=y(this,Or);else try{z(this,Ys,n.select),x=n.select(x),x=mo(i==null?void 0:i.data,x,n),z(this,Or,x),z(this,nn,null)}catch(O){z(this,nn,O)}y(this,nn)&&(w=y(this,nn),x=y(this,Or),g=Date.now(),S="error");const f=d.fetchStatus==="fetching",p=S==="pending",j=S==="error",C=p&&f,N=x!==void 0,E={status:S,fetchStatus:d.fetchStatus,isPending:p,isSuccess:S==="success",isError:j,isInitialLoading:C,isLoading:C,data:x,dataUpdatedAt:d.dataUpdatedAt,error:w,errorUpdatedAt:g,failureCount:d.fetchFailureCount,failureReason:d.fetchFailureReason,errorUpdateCount:d.errorUpdateCount,isFetched:d.dataUpdateCount>0||d.errorUpdateCount>0,isFetchedAfterMount:d.dataUpdateCount>c.dataUpdateCount||d.errorUpdateCount>c.errorUpdateCount,isFetching:f,isRefetching:f&&!p,isLoadingError:j&&!N,isPaused:d.fetchStatus==="paused",isPlaceholderData:h,isRefetchError:j&&N,isStale:Ru(t,n),refetch:this.refetch,promise:y(this,Lt),isEnabled:nt(n.enabled,t)!==!1};if(this.options.experimental_prefetchInRender){const O=E.data!==void 0,Q=E.status==="error"&&!O,D=me=>{Q?me.reject(E.error):O&&me.resolve(E.data)},$=()=>{const me=z(this,Lt,E.promise=po());D(me)},Z=y(this,Lt);switch(Z.status){case"pending":t.queryHash===r.queryHash&&D(Z);break;case"fulfilled":(Q||E.data!==Z.value)&&$();break;case"rejected":(!Q||E.error!==Z.reason)&&$();break}}return E}updateResult(){const t=y(this,Me),n=this.createResult(y(this,G),this.options);if(z(this,Bn,y(this,G).state),z(this,Tr,this.options),y(this,Bn).data!==void 0&&z(this,Lr,y(this,G)),da(n,t))return;z(this,Me,n);const r=()=>{if(!t)return!0;const{notifyOnChangeProps:s}=this.options,i=typeof s=="function"?s():s;if(i==="all"||!i&&!y(this,Rr).size)return!0;const l=new Set(i??y(this,Rr));return this.options.throwOnError&&l.add("error"),Object.keys(y(this,Me)).some(o=>{const u=o;return y(this,Me)[u]!==t[u]&&l.has(u)})};W(this,ee,lm).call(this,{listeners:r()})}onQueryUpdate(){this.updateResult(),this.hasListeners()&&W(this,ee,jo).call(this)}},$e=new WeakMap,G=new WeakMap,Gs=new WeakMap,Me=new WeakMap,Bn=new WeakMap,Tr=new WeakMap,Lt=new WeakMap,nn=new WeakMap,Ys=new WeakMap,Or=new WeakMap,Lr=new WeakMap,Qn=new WeakMap,Vn=new WeakMap,rn=new WeakMap,Rr=new WeakMap,ee=new WeakSet,hs=function(t){W(this,ee,So).call(this);let n=y(this,G).fetch(this.options,t);return t!=null&&t.throwOnError||(n=n.catch(Fe)),n},xo=function(){W(this,ee,wo).call(this);const t=kn(this.options.staleTime,y(this,G));if(er||y(this,Me).isStale||!fo(t))return;const r=em(y(this,Me).dataUpdatedAt,t)+1;z(this,Qn,Fn.setTimeout(()=>{y(this,Me).isStale||this.updateResult()},r))},yo=function(){return(typeof this.options.refetchInterval=="function"?this.options.refetchInterval(y(this,G)):this.options.refetchInterval)??!1},go=function(t){W(this,ee,ko).call(this),z(this,rn,t),!(er||nt(this.options.enabled,y(this,G))===!1||!fo(y(this,rn))||y(this,rn)===0)&&z(this,Vn,Fn.setInterval(()=>{(this.options.refetchIntervalInBackground||Lu.isFocused())&&W(this,ee,hs).call(this)},y(this,rn)))},jo=function(){W(this,ee,xo).call(this),W(this,ee,go).call(this,W(this,ee,yo).call(this))},wo=function(){y(this,Qn)&&(Fn.clearTimeout(y(this,Qn)),z(this,Qn,void 0))},ko=function(){y(this,Vn)&&(Fn.clearInterval(y(this,Vn)),z(this,Vn,void 0))},So=function(){const t=y(this,$e).getQueryCache().build(y(this,$e),this.options);if(t===y(this,G))return;const n=y(this,G);z(this,G,t),z(this,Gs,t.state),this.hasListeners()&&(n==null||n.removeObserver(this),t.addObserver(this))},lm=function(t){ge.batch(()=>{t.listeners&&this.listeners.forEach(n=>{n(y(this,Me))}),y(this,$e).getQueryCache().notify({query:y(this,G),type:"observerResultsUpdated"})})},Md);function Mx(e,t){return nt(t.enabled,e)!==!1&&e.state.data===void 0&&!(e.state.status==="error"&&t.retryOnMount===!1)}function id(e,t){return Mx(e,t)||e.state.data!==void 0&&No(e,t,t.refetchOnMount)}function No(e,t,n){if(nt(t.enabled,e)!==!1&&kn(t.staleTime,e)!=="static"){const r=typeof n=="function"?n(e):n;return r==="always"||r!==!1&&Ru(e,t)}return!1}function ad(e,t,n,r){return(e!==t||nt(r.enabled,e)===!1)&&(!n.suspense||e.state.status!=="error")&&Ru(e,n)}function Ru(e,t){return nt(t.enabled,e)!==!1&&e.isStaleByTime(kn(t.staleTime,e))}function zx(e,t){return!da(e.getCurrentResult(),t)}function ld(e){return{onFetch:(t,n)=>{var m,d,h,x,w;const r=t.options,s=(h=(d=(m=t.fetchOptions)==null?void 0:m.meta)==null?void 0:d.fetchMore)==null?void 0:h.direction,i=((x=t.state.data)==null?void 0:x.pages)||[],l=((w=t.state.data)==null?void 0:w.pageParams)||[];let o={pages:[],pageParams:[]},u=0;const c=async()=>{let g=!1;const S=p=>{Cx(p,()=>t.signal,()=>g=!0)},v=nm(t.options,t.fetchOptions),f=async(p,j,C)=>{if(g)return Promise.reject();if(j==null&&p.pages.length)return Promise.resolve(p);const b=(()=>{const Q={client:t.client,queryKey:t.queryKey,pageParam:j,direction:C?"backward":"forward",meta:t.options.meta};return S(Q),Q})(),E=await v(b),{maxPages:F}=t.options,O=C?bx:Nx;return{pages:O(p.pages,E,F),pageParams:O(p.pageParams,j,F)}};if(s&&i.length){const p=s==="backward",j=p?Fx:od,C={pages:i,pageParams:l},N=j(r,C);o=await f(C,N,p)}else{const p=e??i.length;do{const j=u===0?l[0]??r.initialPageParam:od(r,o);if(u>0&&j==null)break;o=await f(o,j),u++}while(u{var g,S;return(S=(g=t.options).persister)==null?void 0:S.call(g,c,{client:t.client,queryKey:t.queryKey,meta:t.options.meta,signal:t.signal},n)}:t.fetchFn=c}}}function od(e,{pages:t,pageParams:n}){const r=t.length-1;return t.length>0?e.getNextPageParam(t[r],t,n[r],n):void 0}function Fx(e,{pages:t,pageParams:n}){var r;return t.length>0?(r=e.getPreviousPageParam)==null?void 0:r.call(e,t[0],t,n[0],n):void 0}var Xs,wt,Oe,Kn,kt,qt,zd,Ix=(zd=class extends im{constructor(t){super();U(this,kt);U(this,Xs);U(this,wt);U(this,Oe);U(this,Kn);z(this,Xs,t.client),this.mutationId=t.mutationId,z(this,Oe,t.mutationCache),z(this,wt,[]),this.state=t.state||om(),this.setOptions(t.options),this.scheduleGc()}setOptions(t){this.options=t,this.updateGcTime(this.options.gcTime)}get meta(){return this.options.meta}addObserver(t){y(this,wt).includes(t)||(y(this,wt).push(t),this.clearGcTimeout(),y(this,Oe).notify({type:"observerAdded",mutation:this,observer:t}))}removeObserver(t){z(this,wt,y(this,wt).filter(n=>n!==t)),this.scheduleGc(),y(this,Oe).notify({type:"observerRemoved",mutation:this,observer:t})}optionalRemove(){y(this,wt).length||(this.state.status==="pending"?this.scheduleGc():y(this,Oe).remove(this))}continue(){var t;return((t=y(this,Kn))==null?void 0:t.continue())??this.execute(this.state.variables)}async execute(t){var l,o,u,c,m,d,h,x,w,g,S,v,f,p,j,C,N,b;const n=()=>{W(this,kt,qt).call(this,{type:"continue"})},r={client:y(this,Xs),meta:this.options.meta,mutationKey:this.options.mutationKey};z(this,Kn,sm({fn:()=>this.options.mutationFn?this.options.mutationFn(t,r):Promise.reject(new Error("No mutationFn found")),onFail:(E,F)=>{W(this,kt,qt).call(this,{type:"failed",failureCount:E,error:F})},onPause:()=>{W(this,kt,qt).call(this,{type:"pause"})},onContinue:n,retry:this.options.retry??0,retryDelay:this.options.retryDelay,networkMode:this.options.networkMode,canRun:()=>y(this,Oe).canRun(this)}));const s=this.state.status==="pending",i=!y(this,Kn).canStart();try{if(s)n();else{W(this,kt,qt).call(this,{type:"pending",variables:t,isPaused:i}),y(this,Oe).config.onMutate&&await y(this,Oe).config.onMutate(t,this,r);const F=await((o=(l=this.options).onMutate)==null?void 0:o.call(l,t,r));F!==this.state.context&&W(this,kt,qt).call(this,{type:"pending",context:F,variables:t,isPaused:i})}const E=await y(this,Kn).start();return await((c=(u=y(this,Oe).config).onSuccess)==null?void 0:c.call(u,E,t,this.state.context,this,r)),await((d=(m=this.options).onSuccess)==null?void 0:d.call(m,E,t,this.state.context,r)),await((x=(h=y(this,Oe).config).onSettled)==null?void 0:x.call(h,E,null,this.state.variables,this.state.context,this,r)),await((g=(w=this.options).onSettled)==null?void 0:g.call(w,E,null,t,this.state.context,r)),W(this,kt,qt).call(this,{type:"success",data:E}),E}catch(E){try{await((v=(S=y(this,Oe).config).onError)==null?void 0:v.call(S,E,t,this.state.context,this,r))}catch(F){Promise.reject(F)}try{await((p=(f=this.options).onError)==null?void 0:p.call(f,E,t,this.state.context,r))}catch(F){Promise.reject(F)}try{await((C=(j=y(this,Oe).config).onSettled)==null?void 0:C.call(j,void 0,E,this.state.variables,this.state.context,this,r))}catch(F){Promise.reject(F)}try{await((b=(N=this.options).onSettled)==null?void 0:b.call(N,void 0,E,t,this.state.context,r))}catch(F){Promise.reject(F)}throw W(this,kt,qt).call(this,{type:"error",error:E}),E}finally{y(this,Oe).runNext(this)}}},Xs=new WeakMap,wt=new WeakMap,Oe=new WeakMap,Kn=new WeakMap,kt=new WeakSet,qt=function(t){const n=r=>{switch(t.type){case"failed":return{...r,failureCount:t.failureCount,failureReason:t.error};case"pause":return{...r,isPaused:!0};case"continue":return{...r,isPaused:!1};case"pending":return{...r,context:t.context,data:void 0,failureCount:0,failureReason:null,error:null,isPaused:t.isPaused,status:"pending",variables:t.variables,submittedAt:Date.now()};case"success":return{...r,data:t.data,failureCount:0,failureReason:null,error:null,status:"success",isPaused:!1};case"error":return{...r,data:void 0,error:t.error,failureCount:r.failureCount+1,failureReason:t.error,isPaused:!1,status:"error"}}};this.state=n(this.state),ge.batch(()=>{y(this,wt).forEach(r=>{r.onMutationUpdate(t)}),y(this,Oe).notify({mutation:this,type:"updated",action:t})})},zd);function om(){return{context:void 0,data:void 0,error:null,failureCount:0,failureReason:null,isPaused:!1,status:"idle",variables:void 0,submittedAt:0}}var Rt,ft,Zs,Fd,Dx=(Fd=class extends Gr{constructor(t={}){super();U(this,Rt);U(this,ft);U(this,Zs);this.config=t,z(this,Rt,new Set),z(this,ft,new Map),z(this,Zs,0)}build(t,n,r){const s=new Ix({client:t,mutationCache:this,mutationId:++li(this,Zs)._,options:t.defaultMutationOptions(n),state:r});return this.add(s),s}add(t){y(this,Rt).add(t);const n=bi(t);if(typeof n=="string"){const r=y(this,ft).get(n);r?r.push(t):y(this,ft).set(n,[t])}this.notify({type:"added",mutation:t})}remove(t){if(y(this,Rt).delete(t)){const n=bi(t);if(typeof n=="string"){const r=y(this,ft).get(n);if(r)if(r.length>1){const s=r.indexOf(t);s!==-1&&r.splice(s,1)}else r[0]===t&&y(this,ft).delete(n)}}this.notify({type:"removed",mutation:t})}canRun(t){const n=bi(t);if(typeof n=="string"){const r=y(this,ft).get(n),s=r==null?void 0:r.find(i=>i.state.status==="pending");return!s||s===t}else return!0}runNext(t){var r;const n=bi(t);if(typeof n=="string"){const s=(r=y(this,ft).get(n))==null?void 0:r.find(i=>i!==t&&i.state.isPaused);return(s==null?void 0:s.continue())??Promise.resolve()}else return Promise.resolve()}clear(){ge.batch(()=>{y(this,Rt).forEach(t=>{this.notify({type:"removed",mutation:t})}),y(this,Rt).clear(),y(this,ft).clear()})}getAll(){return Array.from(y(this,Rt))}find(t){const n={exact:!0,...t};return this.getAll().find(r=>ed(n,r))}findAll(t={}){return this.getAll().filter(n=>ed(t,n))}notify(t){ge.batch(()=>{this.listeners.forEach(n=>{n(t)})})}resumePausedMutations(){const t=this.getAll().filter(n=>n.state.isPaused);return ge.batch(()=>Promise.all(t.map(n=>n.continue().catch(Fe))))}},Rt=new WeakMap,ft=new WeakMap,Zs=new WeakMap,Fd);function bi(e){var t;return(t=e.options.scope)==null?void 0:t.id}var Mt,sn,Ue,zt,$t,$i,bo,Id,Ax=(Id=class extends Gr{constructor(n,r){super();U(this,$t);U(this,Mt);U(this,sn);U(this,Ue);U(this,zt);z(this,Mt,n),this.setOptions(r),this.bindMethods(),W(this,$t,$i).call(this)}bindMethods(){this.mutate=this.mutate.bind(this),this.reset=this.reset.bind(this)}setOptions(n){var s;const r=this.options;this.options=y(this,Mt).defaultMutationOptions(n),da(this.options,r)||y(this,Mt).getMutationCache().notify({type:"observerOptionsUpdated",mutation:y(this,Ue),observer:this}),r!=null&&r.mutationKey&&this.options.mutationKey&&tr(r.mutationKey)!==tr(this.options.mutationKey)?this.reset():((s=y(this,Ue))==null?void 0:s.state.status)==="pending"&&y(this,Ue).setOptions(this.options)}onUnsubscribe(){var n;this.hasListeners()||(n=y(this,Ue))==null||n.removeObserver(this)}onMutationUpdate(n){W(this,$t,$i).call(this),W(this,$t,bo).call(this,n)}getCurrentResult(){return y(this,sn)}reset(){var n;(n=y(this,Ue))==null||n.removeObserver(this),z(this,Ue,void 0),W(this,$t,$i).call(this),W(this,$t,bo).call(this)}mutate(n,r){var s;return z(this,zt,r),(s=y(this,Ue))==null||s.removeObserver(this),z(this,Ue,y(this,Mt).getMutationCache().build(y(this,Mt),this.options)),y(this,Ue).addObserver(this),y(this,Ue).execute(n)}},Mt=new WeakMap,sn=new WeakMap,Ue=new WeakMap,zt=new WeakMap,$t=new WeakSet,$i=function(){var r;const n=((r=y(this,Ue))==null?void 0:r.state)??om();z(this,sn,{...n,isPending:n.status==="pending",isSuccess:n.status==="success",isError:n.status==="error",isIdle:n.status==="idle",mutate:this.mutate,reset:this.reset})},bo=function(n){ge.batch(()=>{var r,s,i,l,o,u,c,m;if(y(this,zt)&&this.hasListeners()){const d=y(this,sn).variables,h=y(this,sn).context,x={client:y(this,Mt),meta:this.options.meta,mutationKey:this.options.mutationKey};if((n==null?void 0:n.type)==="success"){try{(s=(r=y(this,zt)).onSuccess)==null||s.call(r,n.data,d,h,x)}catch(w){Promise.reject(w)}try{(l=(i=y(this,zt)).onSettled)==null||l.call(i,n.data,null,d,h,x)}catch(w){Promise.reject(w)}}else if((n==null?void 0:n.type)==="error"){try{(u=(o=y(this,zt)).onError)==null||u.call(o,n.error,d,h,x)}catch(w){Promise.reject(w)}try{(m=(c=y(this,zt)).onSettled)==null||m.call(c,void 0,n.error,d,h,x)}catch(w){Promise.reject(w)}}}this.listeners.forEach(d=>{d(y(this,sn))})})},Id),St,Dd,$x=(Dd=class extends Gr{constructor(t={}){super();U(this,St);this.config=t,z(this,St,new Map)}build(t,n,r){const s=n.queryKey,i=n.queryHash??Pu(s,n);let l=this.get(i);return l||(l=new Lx({client:t,queryKey:s,queryHash:i,options:t.defaultQueryOptions(n),state:r,defaultOptions:t.getQueryDefaults(s)}),this.add(l)),l}add(t){y(this,St).has(t.queryHash)||(y(this,St).set(t.queryHash,t),this.notify({type:"added",query:t}))}remove(t){const n=y(this,St).get(t.queryHash);n&&(t.destroy(),n===t&&y(this,St).delete(t.queryHash),this.notify({type:"removed",query:t}))}clear(){ge.batch(()=>{this.getAll().forEach(t=>{this.remove(t)})})}get(t){return y(this,St).get(t)}getAll(){return[...y(this,St).values()]}find(t){const n={exact:!0,...t};return this.getAll().find(r=>Zc(n,r))}findAll(t={}){const n=this.getAll();return Object.keys(t).length>0?n.filter(r=>Zc(t,r)):n}notify(t){ge.batch(()=>{this.listeners.forEach(n=>{n(t)})})}onFocus(){ge.batch(()=>{this.getAll().forEach(t=>{t.onFocus()})})}onOnline(){ge.batch(()=>{this.getAll().forEach(t=>{t.onOnline()})})}},St=new WeakMap,Dd),de,an,ln,Mr,zr,on,Fr,Ir,Ad,Ux=(Ad=class{constructor(e={}){U(this,de);U(this,an);U(this,ln);U(this,Mr);U(this,zr);U(this,on);U(this,Fr);U(this,Ir);z(this,de,e.queryCache||new $x),z(this,an,e.mutationCache||new Dx),z(this,ln,e.defaultOptions||{}),z(this,Mr,new Map),z(this,zr,new Map),z(this,on,0)}mount(){li(this,on)._++,y(this,on)===1&&(z(this,Fr,Lu.subscribe(async e=>{e&&(await this.resumePausedMutations(),y(this,de).onFocus())})),z(this,Ir,fa.subscribe(async e=>{e&&(await this.resumePausedMutations(),y(this,de).onOnline())})))}unmount(){var e,t;li(this,on)._--,y(this,on)===0&&((e=y(this,Fr))==null||e.call(this),z(this,Fr,void 0),(t=y(this,Ir))==null||t.call(this),z(this,Ir,void 0))}isFetching(e){return y(this,de).findAll({...e,fetchStatus:"fetching"}).length}isMutating(e){return y(this,an).findAll({...e,status:"pending"}).length}getQueryData(e){var n;const t=this.defaultQueryOptions({queryKey:e});return(n=y(this,de).get(t.queryHash))==null?void 0:n.state.data}ensureQueryData(e){const t=this.defaultQueryOptions(e),n=y(this,de).build(this,t),r=n.state.data;return r===void 0?this.fetchQuery(e):(e.revalidateIfStale&&n.isStaleByTime(kn(t.staleTime,n))&&this.prefetchQuery(t),Promise.resolve(r))}getQueriesData(e){return y(this,de).findAll(e).map(({queryKey:t,state:n})=>{const r=n.data;return[t,r]})}setQueryData(e,t,n){const r=this.defaultQueryOptions({queryKey:e}),s=y(this,de).get(r.queryHash),i=s==null?void 0:s.state.data,l=wx(t,i);if(l!==void 0)return y(this,de).build(this,r).setData(l,{...n,manual:!0})}setQueriesData(e,t,n){return ge.batch(()=>y(this,de).findAll(e).map(({queryKey:r})=>[r,this.setQueryData(r,t,n)]))}getQueryState(e){var n;const t=this.defaultQueryOptions({queryKey:e});return(n=y(this,de).get(t.queryHash))==null?void 0:n.state}removeQueries(e){const t=y(this,de);ge.batch(()=>{t.findAll(e).forEach(n=>{t.remove(n)})})}resetQueries(e,t){const n=y(this,de);return ge.batch(()=>(n.findAll(e).forEach(r=>{r.reset()}),this.refetchQueries({type:"active",...e},t)))}cancelQueries(e,t={}){const n={revert:!0,...t},r=ge.batch(()=>y(this,de).findAll(e).map(s=>s.cancel(n)));return Promise.all(r).then(Fe).catch(Fe)}invalidateQueries(e,t={}){return ge.batch(()=>(y(this,de).findAll(e).forEach(n=>{n.invalidate()}),(e==null?void 0:e.refetchType)==="none"?Promise.resolve():this.refetchQueries({...e,type:(e==null?void 0:e.refetchType)??(e==null?void 0:e.type)??"active"},t)))}refetchQueries(e,t={}){const n={...t,cancelRefetch:t.cancelRefetch??!0},r=ge.batch(()=>y(this,de).findAll(e).filter(s=>!s.isDisabled()&&!s.isStatic()).map(s=>{let i=s.fetch(void 0,n);return n.throwOnError||(i=i.catch(Fe)),s.state.fetchStatus==="paused"?Promise.resolve():i}));return Promise.all(r).then(Fe)}fetchQuery(e){const t=this.defaultQueryOptions(e);t.retry===void 0&&(t.retry=!1);const n=y(this,de).build(this,t);return n.isStaleByTime(kn(t.staleTime,n))?n.fetch(t):Promise.resolve(n.state.data)}prefetchQuery(e){return this.fetchQuery(e).then(Fe).catch(Fe)}fetchInfiniteQuery(e){return e.behavior=ld(e.pages),this.fetchQuery(e)}prefetchInfiniteQuery(e){return this.fetchInfiniteQuery(e).then(Fe).catch(Fe)}ensureInfiniteQueryData(e){return e.behavior=ld(e.pages),this.ensureQueryData(e)}resumePausedMutations(){return fa.isOnline()?y(this,an).resumePausedMutations():Promise.resolve()}getQueryCache(){return y(this,de)}getMutationCache(){return y(this,an)}getDefaultOptions(){return y(this,ln)}setDefaultOptions(e){z(this,ln,e)}setQueryDefaults(e,t){y(this,Mr).set(tr(e),{queryKey:e,defaultOptions:t})}getQueryDefaults(e){const t=[...y(this,Mr).values()],n={};return t.forEach(r=>{Bs(e,r.queryKey)&&Object.assign(n,r.defaultOptions)}),n}setMutationDefaults(e,t){y(this,zr).set(tr(e),{mutationKey:e,defaultOptions:t})}getMutationDefaults(e){const t=[...y(this,zr).values()],n={};return t.forEach(r=>{Bs(e,r.mutationKey)&&Object.assign(n,r.defaultOptions)}),n}defaultQueryOptions(e){if(e._defaulted)return e;const t={...y(this,ln).queries,...this.getQueryDefaults(e.queryKey),...e,_defaulted:!0};return t.queryHash||(t.queryHash=Pu(t.queryKey,t)),t.refetchOnReconnect===void 0&&(t.refetchOnReconnect=t.networkMode!=="always"),t.throwOnError===void 0&&(t.throwOnError=!!t.suspense),!t.networkMode&&t.persister&&(t.networkMode="offlineFirst"),t.queryFn===Tu&&(t.enabled=!1),t}defaultMutationOptions(e){return e!=null&&e._defaulted?e:{...y(this,ln).mutations,...(e==null?void 0:e.mutationKey)&&this.getMutationDefaults(e.mutationKey),...e,_defaulted:!0}}clear(){y(this,de).clear(),y(this,an).clear()}},de=new WeakMap,an=new WeakMap,ln=new WeakMap,Mr=new WeakMap,zr=new WeakMap,on=new WeakMap,Fr=new WeakMap,Ir=new WeakMap,Ad),um=k.createContext(void 0),Pn=e=>{const t=k.useContext(um);if(!t)throw new Error("No QueryClient set, use QueryClientProvider to set one");return t},Bx=({client:e,children:t})=>(k.useEffect(()=>(e.mount(),()=>{e.unmount()}),[e]),a.jsx(um.Provider,{value:e,children:t})),cm=k.createContext(!1),Qx=()=>k.useContext(cm);cm.Provider;function Vx(){let e=!1;return{clearReset:()=>{e=!1},reset:()=>{e=!0},isReset:()=>e}}var Kx=k.createContext(Vx()),Hx=()=>k.useContext(Kx),Wx=(e,t,n)=>{const r=n!=null&&n.state.error&&typeof e.throwOnError=="function"?Ou(e.throwOnError,[n.state.error,n]):e.throwOnError;(e.suspense||e.experimental_prefetchInRender||r)&&(t.isReset()||(e.retryOnMount=!1))},qx=e=>{k.useEffect(()=>{e.clearReset()},[e])},Jx=({result:e,errorResetBoundary:t,throwOnError:n,query:r,suspense:s})=>e.isError&&!t.isReset()&&!e.isFetching&&r&&(s&&e.data===void 0||Ou(n,[e.error,r])),Gx=e=>{if(e.suspense){const n=s=>s==="static"?s:Math.max(s??1e3,1e3),r=e.staleTime;e.staleTime=typeof r=="function"?(...s)=>n(r(...s)):n(r),typeof e.gcTime=="number"&&(e.gcTime=Math.max(e.gcTime,1e3))}},Yx=(e,t)=>e.isLoading&&e.isFetching&&!t,Xx=(e,t)=>(e==null?void 0:e.suspense)&&t.isPending,ud=(e,t,n)=>t.fetchOptimistic(e).catch(()=>{n.clearReset()});function Zx(e,t,n){var h,x,w,g;const r=Qx(),s=Hx(),i=Pn(),l=i.defaultQueryOptions(e);(x=(h=i.getDefaultOptions().queries)==null?void 0:h._experimental_beforeQuery)==null||x.call(h,l);const o=i.getQueryCache().get(l.queryHash);l._optimisticResults=r?"isRestoring":"optimistic",Gx(l),Wx(l,s,o),qx(s);const u=!i.getQueryCache().get(l.queryHash),[c]=k.useState(()=>new t(i,l)),m=c.getOptimisticResult(l),d=!r&&e.subscribed!==!1;if(k.useSyncExternalStore(k.useCallback(S=>{const v=d?c.subscribe(ge.batchCalls(S)):Fe;return c.updateResult(),v},[c,d]),()=>c.getCurrentResult(),()=>c.getCurrentResult()),k.useEffect(()=>{c.setOptions(l)},[l,c]),Xx(l,m))throw ud(l,c,s);if(Jx({result:m,errorResetBoundary:s,throwOnError:l.throwOnError,query:o,suspense:l.suspense}))throw m.error;if((g=(w=i.getDefaultOptions().queries)==null?void 0:w._experimental_afterQuery)==null||g.call(w,l,m),l.experimental_prefetchInRender&&!er&&Yx(m,r)){const S=u?ud(l,c,s):o==null?void 0:o.promise;S==null||S.catch(Fe).finally(()=>{c.updateResult()})}return l.notifyOnChangeProps?m:c.trackResult(m)}function ve(e,t){return Zx(e,Rx)}function Ge(e,t){const n=Pn(),[r]=k.useState(()=>new Ax(n,e));k.useEffect(()=>{r.setOptions(e)},[r,e]);const s=k.useSyncExternalStore(k.useCallback(l=>r.subscribe(ge.batchCalls(l)),[r]),()=>r.getCurrentResult(),()=>r.getCurrentResult()),i=k.useCallback((l,o)=>{r.mutate(l,o).catch(Fe)},[r]);if(s.error&&Ou(r.options.throwOnError,[s.error]))throw s.error;return{...s,mutate:i,mutateAsync:s.mutate}}/** + * @remix-run/router v1.23.2 + * + * Copyright (c) Remix Software Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE.md file in the root directory of this source tree. + * + * @license MIT + */function Qs(){return Qs=Object.assign?Object.assign.bind():function(e){for(var t=1;t"u")throw new Error(t)}function Mu(e,t){if(!e){typeof console<"u"&&console.warn(t);try{throw new Error(t)}catch{}}}function ty(){return Math.random().toString(36).substr(2,8)}function dd(e,t){return{usr:e.state,key:e.key,idx:t}}function Co(e,t,n,r){return n===void 0&&(n=null),Qs({pathname:typeof e=="string"?e:e.pathname,search:"",hash:""},typeof t=="string"?Yr(t):t,{state:n,key:t&&t.key||r||ty()})}function ha(e){let{pathname:t="/",search:n="",hash:r=""}=e;return n&&n!=="?"&&(t+=n.charAt(0)==="?"?n:"?"+n),r&&r!=="#"&&(t+=r.charAt(0)==="#"?r:"#"+r),t}function Yr(e){let t={};if(e){let n=e.indexOf("#");n>=0&&(t.hash=e.substr(n),e=e.substr(0,n));let r=e.indexOf("?");r>=0&&(t.search=e.substr(r),e=e.substr(0,r)),e&&(t.pathname=e)}return t}function ny(e,t,n,r){r===void 0&&(r={});let{window:s=document.defaultView,v5Compat:i=!1}=r,l=s.history,o=dn.Pop,u=null,c=m();c==null&&(c=0,l.replaceState(Qs({},l.state,{idx:c}),""));function m(){return(l.state||{idx:null}).idx}function d(){o=dn.Pop;let S=m(),v=S==null?null:S-c;c=S,u&&u({action:o,location:g.location,delta:v})}function h(S,v){o=dn.Push;let f=Co(g.location,S,v);c=m()+1;let p=dd(f,c),j=g.createHref(f);try{l.pushState(p,"",j)}catch(C){if(C instanceof DOMException&&C.name==="DataCloneError")throw C;s.location.assign(j)}i&&u&&u({action:o,location:g.location,delta:1})}function x(S,v){o=dn.Replace;let f=Co(g.location,S,v);c=m();let p=dd(f,c),j=g.createHref(f);l.replaceState(p,"",j),i&&u&&u({action:o,location:g.location,delta:0})}function w(S){let v=s.location.origin!=="null"?s.location.origin:s.location.href,f=typeof S=="string"?S:ha(S);return f=f.replace(/ $/,"%20"),he(v,"No window.location.(origin|href) available to create URL for href: "+f),new URL(f,v)}let g={get action(){return o},get location(){return e(s,l)},listen(S){if(u)throw new Error("A history only accepts one active listener");return s.addEventListener(cd,d),u=S,()=>{s.removeEventListener(cd,d),u=null}},createHref(S){return t(s,S)},createURL:w,encodeLocation(S){let v=w(S);return{pathname:v.pathname,search:v.search,hash:v.hash}},push:h,replace:x,go(S){return l.go(S)}};return g}var fd;(function(e){e.data="data",e.deferred="deferred",e.redirect="redirect",e.error="error"})(fd||(fd={}));function ry(e,t,n){return n===void 0&&(n="/"),sy(e,t,n)}function sy(e,t,n,r){let s=typeof t=="string"?Yr(t):t,i=Kr(s.pathname||"/",n);if(i==null)return null;let l=dm(e);iy(l);let o=null;for(let u=0;o==null&&u{let u={relativePath:o===void 0?i.path||"":o,caseSensitive:i.caseSensitive===!0,childrenIndex:l,route:i};u.relativePath.startsWith("/")&&(he(u.relativePath.startsWith(r),'Absolute route path "'+u.relativePath+'" nested under path '+('"'+r+'" is not valid. An absolute child route path ')+"must start with the combined path of all its parent routes."),u.relativePath=u.relativePath.slice(r.length));let c=Sn([r,u.relativePath]),m=n.concat(u);i.children&&i.children.length>0&&(he(i.index!==!0,"Index routes must not have child routes. Please remove "+('all child routes from route path "'+c+'".')),dm(i.children,t,m,c)),!(i.path==null&&!i.index)&&t.push({path:c,score:fy(c,i.index),routesMeta:m})};return e.forEach((i,l)=>{var o;if(i.path===""||!((o=i.path)!=null&&o.includes("?")))s(i,l);else for(let u of fm(i.path))s(i,l,u)}),t}function fm(e){let t=e.split("/");if(t.length===0)return[];let[n,...r]=t,s=n.endsWith("?"),i=n.replace(/\?$/,"");if(r.length===0)return s?[i,""]:[i];let l=fm(r.join("/")),o=[];return o.push(...l.map(u=>u===""?i:[i,u].join("/"))),s&&o.push(...l),o.map(u=>e.startsWith("/")&&u===""?"/":u)}function iy(e){e.sort((t,n)=>t.score!==n.score?n.score-t.score:hy(t.routesMeta.map(r=>r.childrenIndex),n.routesMeta.map(r=>r.childrenIndex)))}const ay=/^:[\w-]+$/,ly=3,oy=2,uy=1,cy=10,dy=-2,hd=e=>e==="*";function fy(e,t){let n=e.split("/"),r=n.length;return n.some(hd)&&(r+=dy),t&&(r+=oy),n.filter(s=>!hd(s)).reduce((s,i)=>s+(ay.test(i)?ly:i===""?uy:cy),r)}function hy(e,t){return e.length===t.length&&e.slice(0,-1).every((r,s)=>r===t[s])?e[e.length-1]-t[t.length-1]:0}function my(e,t,n){let{routesMeta:r}=e,s={},i="/",l=[];for(let o=0;o{let{paramName:h,isOptional:x}=m;if(h==="*"){let g=o[d]||"";l=i.slice(0,i.length-g.length).replace(/(.)\/+$/,"$1")}const w=o[d];return x&&!w?c[h]=void 0:c[h]=(w||"").replace(/%2F/g,"/"),c},{}),pathname:i,pathnameBase:l,pattern:e}}function py(e,t,n){t===void 0&&(t=!1),n===void 0&&(n=!0),Mu(e==="*"||!e.endsWith("*")||e.endsWith("/*"),'Route path "'+e+'" will be treated as if it were '+('"'+e.replace(/\*$/,"/*")+'" because the `*` character must ')+"always follow a `/` in the pattern. To get rid of this warning, "+('please change the route path to "'+e.replace(/\*$/,"/*")+'".'));let r=[],s="^"+e.replace(/\/*\*?$/,"").replace(/^\/*/,"/").replace(/[\\.*+^${}|()[\]]/g,"\\$&").replace(/\/:([\w-]+)(\?)?/g,(l,o,u)=>(r.push({paramName:o,isOptional:u!=null}),u?"/?([^\\/]+)?":"/([^\\/]+)"));return e.endsWith("*")?(r.push({paramName:"*"}),s+=e==="*"||e==="/*"?"(.*)$":"(?:\\/(.+)|\\/*)$"):n?s+="\\/*$":e!==""&&e!=="/"&&(s+="(?:(?=\\/|$))"),[new RegExp(s,t?void 0:"i"),r]}function vy(e){try{return e.split("/").map(t=>decodeURIComponent(t).replace(/\//g,"%2F")).join("/")}catch(t){return Mu(!1,'The URL path "'+e+'" could not be decoded because it is is a malformed URL segment. This is probably due to a bad percent '+("encoding ("+t+").")),e}}function Kr(e,t){if(t==="/")return e;if(!e.toLowerCase().startsWith(t.toLowerCase()))return null;let n=t.endsWith("/")?t.length-1:t.length,r=e.charAt(n);return r&&r!=="/"?null:e.slice(n)||"/"}const xy=/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i,yy=e=>xy.test(e);function gy(e,t){t===void 0&&(t="/");let{pathname:n,search:r="",hash:s=""}=typeof e=="string"?Yr(e):e,i;if(n)if(yy(n))i=n;else{if(n.includes("//")){let l=n;n=n.replace(/\/\/+/g,"/"),Mu(!1,"Pathnames cannot have embedded double slashes - normalizing "+(l+" -> "+n))}n.startsWith("/")?i=md(n.substring(1),"/"):i=md(n,t)}else i=t;return{pathname:i,search:ky(r),hash:Sy(s)}}function md(e,t){let n=t.replace(/\/+$/,"").split("/");return e.split("/").forEach(s=>{s===".."?n.length>1&&n.pop():s!=="."&&n.push(s)}),n.length>1?n.join("/"):"/"}function ml(e,t,n,r){return"Cannot include a '"+e+"' character in a manually specified "+("`to."+t+"` field ["+JSON.stringify(r)+"]. Please separate it out to the ")+("`to."+n+"` field. Alternatively you may provide the full path as ")+'a string in and the router will parse it for you.'}function jy(e){return e.filter((t,n)=>n===0||t.route.path&&t.route.path.length>0)}function hm(e,t){let n=jy(e);return t?n.map((r,s)=>s===n.length-1?r.pathname:r.pathnameBase):n.map(r=>r.pathnameBase)}function mm(e,t,n,r){r===void 0&&(r=!1);let s;typeof e=="string"?s=Yr(e):(s=Qs({},e),he(!s.pathname||!s.pathname.includes("?"),ml("?","pathname","search",s)),he(!s.pathname||!s.pathname.includes("#"),ml("#","pathname","hash",s)),he(!s.search||!s.search.includes("#"),ml("#","search","hash",s)));let i=e===""||s.pathname==="",l=i?"/":s.pathname,o;if(l==null)o=n;else{let d=t.length-1;if(!r&&l.startsWith("..")){let h=l.split("/");for(;h[0]==="..";)h.shift(),d-=1;s.pathname=h.join("/")}o=d>=0?t[d]:"/"}let u=gy(s,o),c=l&&l!=="/"&&l.endsWith("/"),m=(i||l===".")&&n.endsWith("/");return!u.pathname.endsWith("/")&&(c||m)&&(u.pathname+="/"),u}const Sn=e=>e.join("/").replace(/\/\/+/g,"/"),wy=e=>e.replace(/\/+$/,"").replace(/^\/*/,"/"),ky=e=>!e||e==="?"?"":e.startsWith("?")?e:"?"+e,Sy=e=>!e||e==="#"?"":e.startsWith("#")?e:"#"+e;function Ny(e){return e!=null&&typeof e.status=="number"&&typeof e.statusText=="string"&&typeof e.internal=="boolean"&&"data"in e}const pm=["post","put","patch","delete"];new Set(pm);const by=["get",...pm];new Set(by);/** + * React Router v6.30.3 + * + * Copyright (c) Remix Software Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE.md file in the root directory of this source tree. + * + * @license MIT + */function Vs(){return Vs=Object.assign?Object.assign.bind():function(e){for(var t=1;t{o.current=!0}),k.useCallback(function(c,m){if(m===void 0&&(m={}),!o.current)return;if(typeof c=="number"){r.go(c);return}let d=mm(c,JSON.parse(l),i,m.relative==="path");e==null&&t!=="/"&&(d.pathname=d.pathname==="/"?t:Sn([t,d.pathname])),(m.replace?r.replace:r.push)(d,m.state,m)},[t,r,l,i,e])}const Ey=k.createContext(null);function Py(e){let t=k.useContext(Ht).outlet;return t&&k.createElement(Ey.Provider,{value:e},t)}function Ra(){let{matches:e}=k.useContext(Ht),t=e[e.length-1];return t?t.params:{}}function Ma(e,t){let{relative:n}=t===void 0?{}:t,{future:r}=k.useContext(Tn),{matches:s}=k.useContext(Ht),{pathname:i}=Xr(),l=JSON.stringify(hm(s,r.v7_relativeSplatPath));return k.useMemo(()=>mm(e,JSON.parse(l),i,n==="path"),[e,l,i,n])}function Ty(e,t){return Oy(e,t)}function Oy(e,t,n,r){ii()||he(!1);let{navigator:s}=k.useContext(Tn),{matches:i}=k.useContext(Ht),l=i[i.length-1],o=l?l.params:{};l&&l.pathname;let u=l?l.pathnameBase:"/";l&&l.route;let c=Xr(),m;if(t){var d;let S=typeof t=="string"?Yr(t):t;u==="/"||(d=S.pathname)!=null&&d.startsWith(u)||he(!1),m=S}else m=c;let h=m.pathname||"/",x=h;if(u!=="/"){let S=u.replace(/^\//,"").split("/");x="/"+h.replace(/^\//,"").split("/").slice(S.length).join("/")}let w=ry(e,{pathname:x}),g=Fy(w&&w.map(S=>Object.assign({},S,{params:Object.assign({},o,S.params),pathname:Sn([u,s.encodeLocation?s.encodeLocation(S.pathname).pathname:S.pathname]),pathnameBase:S.pathnameBase==="/"?u:Sn([u,s.encodeLocation?s.encodeLocation(S.pathnameBase).pathname:S.pathnameBase])})),i,n,r);return t&&g?k.createElement(La.Provider,{value:{location:Vs({pathname:"/",search:"",hash:"",state:null,key:"default"},m),navigationType:dn.Pop}},g):g}function Ly(){let e=$y(),t=Ny(e)?e.status+" "+e.statusText:e instanceof Error?e.message:JSON.stringify(e),n=e instanceof Error?e.stack:null,s={padding:"0.5rem",backgroundColor:"rgba(200,200,200, 0.5)"};return k.createElement(k.Fragment,null,k.createElement("h2",null,"Unexpected Application Error!"),k.createElement("h3",{style:{fontStyle:"italic"}},t),n?k.createElement("pre",{style:s},n):null,null)}const Ry=k.createElement(Ly,null);class My extends k.Component{constructor(t){super(t),this.state={location:t.location,revalidation:t.revalidation,error:t.error}}static getDerivedStateFromError(t){return{error:t}}static getDerivedStateFromProps(t,n){return n.location!==t.location||n.revalidation!=="idle"&&t.revalidation==="idle"?{error:t.error,location:t.location,revalidation:t.revalidation}:{error:t.error!==void 0?t.error:n.error,location:n.location,revalidation:t.revalidation||n.revalidation}}componentDidCatch(t,n){console.error("React Router caught the following error during render",t,n)}render(){return this.state.error!==void 0?k.createElement(Ht.Provider,{value:this.props.routeContext},k.createElement(xm.Provider,{value:this.state.error,children:this.props.component})):this.props.children}}function zy(e){let{routeContext:t,match:n,children:r}=e,s=k.useContext(Oa);return s&&s.static&&s.staticContext&&(n.route.errorElement||n.route.ErrorBoundary)&&(s.staticContext._deepestRenderedBoundaryId=n.route.id),k.createElement(Ht.Provider,{value:t},r)}function Fy(e,t,n,r){var s;if(t===void 0&&(t=[]),n===void 0&&(n=null),r===void 0&&(r=null),e==null){var i;if(!n)return null;if(n.errors)e=n.matches;else if((i=r)!=null&&i.v7_partialHydration&&t.length===0&&!n.initialized&&n.matches.length>0)e=n.matches;else return null}let l=e,o=(s=n)==null?void 0:s.errors;if(o!=null){let m=l.findIndex(d=>d.route.id&&(o==null?void 0:o[d.route.id])!==void 0);m>=0||he(!1),l=l.slice(0,Math.min(l.length,m+1))}let u=!1,c=-1;if(n&&r&&r.v7_partialHydration)for(let m=0;m=0?l=l.slice(0,c+1):l=[l[0]];break}}}return l.reduceRight((m,d,h)=>{let x,w=!1,g=null,S=null;n&&(x=o&&d.route.id?o[d.route.id]:void 0,g=d.route.errorElement||Ry,u&&(c<0&&h===0?(By("route-fallback"),w=!0,S=null):c===h&&(w=!0,S=d.route.hydrateFallbackElement||null)));let v=t.concat(l.slice(0,h+1)),f=()=>{let p;return x?p=g:w?p=S:d.route.Component?p=k.createElement(d.route.Component,null):d.route.element?p=d.route.element:p=m,k.createElement(zy,{match:d,routeContext:{outlet:m,matches:v,isDataRoute:n!=null},children:p})};return n&&(d.route.ErrorBoundary||d.route.errorElement||h===0)?k.createElement(My,{location:n.location,revalidation:n.revalidation,component:g,error:x,children:f(),routeContext:{outlet:null,matches:v,isDataRoute:!0}}):f()},null)}var gm=function(e){return e.UseBlocker="useBlocker",e.UseRevalidator="useRevalidator",e.UseNavigateStable="useNavigate",e}(gm||{}),jm=function(e){return e.UseBlocker="useBlocker",e.UseLoaderData="useLoaderData",e.UseActionData="useActionData",e.UseRouteError="useRouteError",e.UseNavigation="useNavigation",e.UseRouteLoaderData="useRouteLoaderData",e.UseMatches="useMatches",e.UseRevalidator="useRevalidator",e.UseNavigateStable="useNavigate",e.UseRouteId="useRouteId",e}(jm||{});function Iy(e){let t=k.useContext(Oa);return t||he(!1),t}function Dy(e){let t=k.useContext(vm);return t||he(!1),t}function Ay(e){let t=k.useContext(Ht);return t||he(!1),t}function wm(e){let t=Ay(),n=t.matches[t.matches.length-1];return n.route.id||he(!1),n.route.id}function $y(){var e;let t=k.useContext(xm),n=Dy(),r=wm();return t!==void 0?t:(e=n.errors)==null?void 0:e[r]}function Uy(){let{router:e}=Iy(gm.UseNavigateStable),t=wm(jm.UseNavigateStable),n=k.useRef(!1);return ym(()=>{n.current=!0}),k.useCallback(function(s,i){i===void 0&&(i={}),n.current&&(typeof s=="number"?e.navigate(s):e.navigate(s,Vs({fromRouteId:t},i)))},[e,t])}const pd={};function By(e,t,n){pd[e]||(pd[e]=!0)}function Qy(e,t){e==null||e.v7_startTransition,e==null||e.v7_relativeSplatPath}function Vy(e){return Py(e.context)}function gt(e){he(!1)}function Ky(e){let{basename:t="/",children:n=null,location:r,navigationType:s=dn.Pop,navigator:i,static:l=!1,future:o}=e;ii()&&he(!1);let u=t.replace(/^\/*/,"/"),c=k.useMemo(()=>({basename:u,navigator:i,static:l,future:Vs({v7_relativeSplatPath:!1},o)}),[u,o,i,l]);typeof r=="string"&&(r=Yr(r));let{pathname:m="/",search:d="",hash:h="",state:x=null,key:w="default"}=r,g=k.useMemo(()=>{let S=Kr(m,u);return S==null?null:{location:{pathname:S,search:d,hash:h,state:x,key:w},navigationType:s}},[u,m,d,h,x,w,s]);return g==null?null:k.createElement(Tn.Provider,{value:c},k.createElement(La.Provider,{children:n,value:g}))}function Hy(e){let{children:t,location:n}=e;return Ty(Eo(t),n)}new Promise(()=>{});function Eo(e,t){t===void 0&&(t=[]);let n=[];return k.Children.forEach(e,(r,s)=>{if(!k.isValidElement(r))return;let i=[...t,s];if(r.type===k.Fragment){n.push.apply(n,Eo(r.props.children,i));return}r.type!==gt&&he(!1),!r.props.index||!r.props.children||he(!1);let l={id:r.props.id||i.join("-"),caseSensitive:r.props.caseSensitive,element:r.props.element,Component:r.props.Component,index:r.props.index,path:r.props.path,loader:r.props.loader,action:r.props.action,errorElement:r.props.errorElement,ErrorBoundary:r.props.ErrorBoundary,hasErrorBoundary:r.props.ErrorBoundary!=null||r.props.errorElement!=null,shouldRevalidate:r.props.shouldRevalidate,handle:r.props.handle,lazy:r.props.lazy};r.props.children&&(l.children=Eo(r.props.children,i)),n.push(l)}),n}/** + * React Router DOM v6.30.3 + * + * Copyright (c) Remix Software Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE.md file in the root directory of this source tree. + * + * @license MIT + */function ma(){return ma=Object.assign?Object.assign.bind():function(e){for(var t=1;t=0)&&(n[s]=e[s]);return n}function Wy(e){return!!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)}function qy(e,t){return e.button===0&&(!t||t==="_self")&&!Wy(e)}const Jy=["onClick","relative","reloadDocument","replace","state","target","to","preventScrollReset","viewTransition"],Gy=["aria-current","caseSensitive","className","end","style","to","viewTransition","children"],Yy="6";try{window.__reactRouterVersion=Yy}catch{}const Xy=k.createContext({isTransitioning:!1}),Zy="startTransition",vd=ap[Zy];function eg(e){let{basename:t,children:n,future:r,window:s}=e,i=k.useRef();i.current==null&&(i.current=ey({window:s,v5Compat:!0}));let l=i.current,[o,u]=k.useState({action:l.action,location:l.location}),{v7_startTransition:c}=r||{},m=k.useCallback(d=>{c&&vd?vd(()=>u(d)):u(d)},[u,c]);return k.useLayoutEffect(()=>l.listen(m),[l,m]),k.useEffect(()=>Qy(r),[r]),k.createElement(Ky,{basename:t,children:n,location:o.location,navigationType:o.action,navigator:l,future:r})}const tg=typeof window<"u"&&typeof window.document<"u"&&typeof window.document.createElement<"u",ng=/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i,Ks=k.forwardRef(function(t,n){let{onClick:r,relative:s,reloadDocument:i,replace:l,state:o,target:u,to:c,preventScrollReset:m,viewTransition:d}=t,h=km(t,Jy),{basename:x}=k.useContext(Tn),w,g=!1;if(typeof c=="string"&&ng.test(c)&&(w=c,tg))try{let p=new URL(window.location.href),j=c.startsWith("//")?new URL(p.protocol+c):new URL(c),C=Kr(j.pathname,x);j.origin===p.origin&&C!=null?c=C+j.search+j.hash:g=!0}catch{}let S=Cy(c,{relative:s}),v=sg(c,{replace:l,state:o,target:u,preventScrollReset:m,relative:s,viewTransition:d});function f(p){r&&r(p),p.defaultPrevented||v(p)}return k.createElement("a",ma({},h,{href:w||S,onClick:g||i?r:f,ref:n,target:u}))}),xd=k.forwardRef(function(t,n){let{"aria-current":r="page",caseSensitive:s=!1,className:i="",end:l=!1,style:o,to:u,viewTransition:c,children:m}=t,d=km(t,Gy),h=Ma(u,{relative:d.relative}),x=Xr(),w=k.useContext(vm),{navigator:g,basename:S}=k.useContext(Tn),v=w!=null&&ig(h)&&c===!0,f=g.encodeLocation?g.encodeLocation(h).pathname:h.pathname,p=x.pathname,j=w&&w.navigation&&w.navigation.location?w.navigation.location.pathname:null;s||(p=p.toLowerCase(),j=j?j.toLowerCase():null,f=f.toLowerCase()),j&&S&&(j=Kr(j,S)||j);const C=f!=="/"&&f.endsWith("/")?f.length-1:f.length;let N=p===f||!l&&p.startsWith(f)&&p.charAt(C)==="/",b=j!=null&&(j===f||!l&&j.startsWith(f)&&j.charAt(f.length)==="/"),E={isActive:N,isPending:b,isTransitioning:v},F=N?r:void 0,O;typeof i=="function"?O=i(E):O=[i,N?"active":null,b?"pending":null,v?"transitioning":null].filter(Boolean).join(" ");let Q=typeof o=="function"?o(E):o;return k.createElement(Ks,ma({},d,{"aria-current":F,className:O,ref:n,style:Q,to:u,viewTransition:c}),typeof m=="function"?m(E):m)});var Po;(function(e){e.UseScrollRestoration="useScrollRestoration",e.UseSubmit="useSubmit",e.UseSubmitFetcher="useSubmitFetcher",e.UseFetcher="useFetcher",e.useViewTransitionState="useViewTransitionState"})(Po||(Po={}));var yd;(function(e){e.UseFetcher="useFetcher",e.UseFetchers="useFetchers",e.UseScrollRestoration="useScrollRestoration"})(yd||(yd={}));function rg(e){let t=k.useContext(Oa);return t||he(!1),t}function sg(e,t){let{target:n,replace:r,state:s,preventScrollReset:i,relative:l,viewTransition:o}=t===void 0?{}:t,u=Et(),c=Xr(),m=Ma(e,{relative:l});return k.useCallback(d=>{if(qy(d,n)){d.preventDefault();let h=r!==void 0?r:ha(c)===ha(m);u(e,{replace:h,state:s,preventScrollReset:i,relative:l,viewTransition:o})}},[c,u,m,r,s,n,e,i,l,o])}function ig(e,t){t===void 0&&(t={});let n=k.useContext(Xy);n==null&&he(!1);let{basename:r}=rg(Po.useViewTransitionState),s=Ma(e,{relative:t.relative});if(!n.isTransitioning)return!1;let i=Kr(n.currentLocation.pathname,r)||n.currentLocation.pathname,l=Kr(n.nextLocation.pathname,r)||n.nextLocation.pathname;return _o(s.pathname,l)!=null||_o(s.pathname,i)!=null}/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */var ag={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"};/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const lg=e=>e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase().trim(),Y=(e,t)=>{const n=k.forwardRef(({color:r="currentColor",size:s=24,strokeWidth:i=2,absoluteStrokeWidth:l,className:o="",children:u,...c},m)=>k.createElement("svg",{ref:m,...ag,width:s,height:s,stroke:r,strokeWidth:l?Number(i)*24/Number(s):i,className:["lucide",`lucide-${lg(e)}`,o].join(" "),...c},[...t.map(([d,h])=>k.createElement(d,h)),...Array.isArray(u)?u:[u]]));return n.displayName=`${e}`,n};/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Sm=Y("AlertCircle",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["line",{x1:"12",x2:"12",y1:"8",y2:"12",key:"1pkeuh"}],["line",{x1:"12",x2:"12.01",y1:"16",y2:"16",key:"4dfq90"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const og=Y("ArrowUpDown",[["path",{d:"m21 16-4 4-4-4",key:"f6ql7i"}],["path",{d:"M17 20V4",key:"1ejh1v"}],["path",{d:"m3 8 4-4 4 4",key:"11wl7u"}],["path",{d:"M7 4v16",key:"1glfcx"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const ug=Y("BarChart3",[["path",{d:"M3 3v18h18",key:"1s2lah"}],["path",{d:"M18 17V9",key:"2bz60n"}],["path",{d:"M13 17V5",key:"1frdt8"}],["path",{d:"M8 17v-3",key:"17ska0"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const cg=Y("Bot",[["path",{d:"M12 8V4H8",key:"hb8ula"}],["rect",{width:"16",height:"12",x:"4",y:"8",rx:"2",key:"enze0r"}],["path",{d:"M2 14h2",key:"vft8re"}],["path",{d:"M20 14h2",key:"4cs60a"}],["path",{d:"M15 13v2",key:"1xurst"}],["path",{d:"M9 13v2",key:"rq6x2g"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Nm=Y("CheckCircle",[["path",{d:"M22 11.08V12a10 10 0 1 1-5.93-9.14",key:"g774vq"}],["path",{d:"m9 11 3 3L22 4",key:"1pflzl"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const dg=Y("Check",[["path",{d:"M20 6 9 17l-5-5",key:"1gmf2c"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const fg=Y("ChevronDown",[["path",{d:"m6 9 6 6 6-6",key:"qrunsl"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const hg=Y("ChevronLeft",[["path",{d:"m15 18-6-6 6-6",key:"1wnfg3"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Ss=Y("ChevronRight",[["path",{d:"m9 18 6-6-6-6",key:"mthhwq"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const mg=Y("Clock",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["polyline",{points:"12 6 12 12 16 14",key:"68esgv"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const pg=Y("Coins",[["circle",{cx:"8",cy:"8",r:"6",key:"3yglwk"}],["path",{d:"M18.09 10.37A6 6 0 1 1 10.34 18",key:"t5s6rm"}],["path",{d:"M7 6h1v4",key:"1obek4"}],["path",{d:"m16.71 13.88.7.71-2.82 2.82",key:"1rbuyh"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const vg=Y("Copy",[["rect",{width:"14",height:"14",x:"8",y:"8",rx:"2",ry:"2",key:"17jyea"}],["path",{d:"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2",key:"zix9uf"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const gd=Y("Download",[["path",{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4",key:"ih7n3h"}],["polyline",{points:"7 10 12 15 17 10",key:"2ggqvy"}],["line",{x1:"12",x2:"12",y1:"15",y2:"3",key:"1vk2je"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const xg=Y("ExternalLink",[["path",{d:"M15 3h6v6",key:"1q9fwt"}],["path",{d:"M10 14 21 3",key:"gplh6r"}],["path",{d:"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6",key:"a6xqqp"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const yg=Y("GitCompare",[["circle",{cx:"18",cy:"18",r:"3",key:"1xkwt0"}],["circle",{cx:"6",cy:"6",r:"3",key:"1lh9wr"}],["path",{d:"M13 6h3a2 2 0 0 1 2 2v7",key:"1yeb86"}],["path",{d:"M11 18H8a2 2 0 0 1-2-2V9",key:"19pyzm"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const gg=Y("Github",[["path",{d:"M15 22v-4a4.8 4.8 0 0 0-1-3.5c3 0 6-2 6-5.5.08-1.25-.27-2.48-1-3.5.28-1.15.28-2.35 0-3.5 0 0-1 0-3 1.5-2.64-.5-5.36-.5-8 0C6 2 5 2 5 2c-.3 1.15-.3 2.35 0 3.5A5.403 5.403 0 0 0 4 9c0 3.5 3 5.5 6 5.5-.39.49-.68 1.05-.85 1.65-.17.6-.22 1.23-.15 1.85v4",key:"tonef"}],["path",{d:"M9 18c-4.51 2-5-2-7-2",key:"9comsn"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const za=Y("Globe",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20",key:"13o1zl"}],["path",{d:"M2 12h20",key:"9i4pu4"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const jg=Y("History",[["path",{d:"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8",key:"1357e3"}],["path",{d:"M3 3v5h5",key:"1xhq8a"}],["path",{d:"M12 7v5l4 2",key:"1fdv2h"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const wg=Y("ListTodo",[["rect",{x:"3",y:"5",width:"6",height:"6",rx:"1",key:"1defrl"}],["path",{d:"m3 17 2 2 4-4",key:"1jhpwq"}],["path",{d:"M13 6h8",key:"15sg57"}],["path",{d:"M13 12h8",key:"h98zly"}],["path",{d:"M13 18h8",key:"oe0vm4"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const kg=Y("List",[["line",{x1:"8",x2:"21",y1:"6",y2:"6",key:"7ey8pc"}],["line",{x1:"8",x2:"21",y1:"12",y2:"12",key:"rjfblc"}],["line",{x1:"8",x2:"21",y1:"18",y2:"18",key:"c3b1m8"}],["line",{x1:"3",x2:"3.01",y1:"6",y2:"6",key:"1g7gq3"}],["line",{x1:"3",x2:"3.01",y1:"12",y2:"12",key:"1pjlvk"}],["line",{x1:"3",x2:"3.01",y1:"18",y2:"18",key:"28t2mc"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Fa=Y("Loader2",[["path",{d:"M21 12a9 9 0 1 1-6.219-8.56",key:"13zald"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const bm=Y("Lock",[["rect",{width:"18",height:"11",x:"3",y:"11",rx:"2",ry:"2",key:"1w4ew1"}],["path",{d:"M7 11V7a5 5 0 0 1 10 0v4",key:"fwvmzm"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Sg=Y("LogOut",[["path",{d:"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4",key:"1uf3rs"}],["polyline",{points:"16 17 21 12 16 7",key:"1gabdz"}],["line",{x1:"21",x2:"9",y1:"12",y2:"12",key:"1uyos4"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Ng=Y("Moon",[["path",{d:"M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z",key:"a7tn18"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Hs=Y("Play",[["polygon",{points:"5 3 19 12 5 21 5 3",key:"191637"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Ia=Y("Plus",[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"M12 5v14",key:"s699le"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Cm=Y("Settings",[["path",{d:"M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z",key:"1qme2f"}],["circle",{cx:"12",cy:"12",r:"3",key:"1v7zrd"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const bg=Y("Share2",[["circle",{cx:"18",cy:"5",r:"3",key:"gq8acd"}],["circle",{cx:"6",cy:"12",r:"3",key:"w7nqdw"}],["circle",{cx:"18",cy:"19",r:"3",key:"1xt0gg"}],["line",{x1:"8.59",x2:"15.42",y1:"13.51",y2:"17.49",key:"47mynk"}],["line",{x1:"15.41",x2:"8.59",y1:"6.51",y2:"10.49",key:"1n3mei"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Cg=Y("Square",[["rect",{width:"18",height:"18",x:"3",y:"3",rx:"2",key:"afitv7"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const _g=Y("Sun",[["circle",{cx:"12",cy:"12",r:"4",key:"4exip2"}],["path",{d:"M12 2v2",key:"tus03m"}],["path",{d:"M12 20v2",key:"1lh1kg"}],["path",{d:"m4.93 4.93 1.41 1.41",key:"149t6j"}],["path",{d:"m17.66 17.66 1.41 1.41",key:"ptbguv"}],["path",{d:"M2 12h2",key:"1t8f8n"}],["path",{d:"M20 12h2",key:"1q8mjw"}],["path",{d:"m6.34 17.66-1.41 1.41",key:"1m8zz5"}],["path",{d:"m19.07 4.93-1.41 1.41",key:"1shlcs"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const _m=Y("Trash2",[["path",{d:"M3 6h18",key:"d0wm0j"}],["path",{d:"M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6",key:"4alrt4"}],["path",{d:"M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2",key:"v07s0e"}],["line",{x1:"10",x2:"10",y1:"11",y2:"17",key:"1uufr5"}],["line",{x1:"14",x2:"14",y1:"11",y2:"17",key:"xtxkd"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Em=Y("User",[["path",{d:"M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2",key:"975kel"}],["circle",{cx:"12",cy:"7",r:"4",key:"17ys0d"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Eg=Y("XCircle",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"m15 9-6 6",key:"1uzhvr"}],["path",{d:"m9 9 6 6",key:"z0biqf"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Pm=Y("X",[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Da=Y("Zap",[["polygon",{points:"13 2 3 14 12 14 11 22 21 10 12 10 13 2",key:"45s27k"}]]),Pg={},jd=e=>{let t;const n=new Set,r=(m,d)=>{const h=typeof m=="function"?m(t):m;if(!Object.is(h,t)){const x=t;t=d??(typeof h!="object"||h===null)?h:Object.assign({},t,h),n.forEach(w=>w(t,x))}},s=()=>t,u={setState:r,getState:s,getInitialState:()=>c,subscribe:m=>(n.add(m),()=>n.delete(m)),destroy:()=>{(Pg?"production":void 0)!=="production"&&console.warn("[DEPRECATED] The `destroy` method will be unsupported in a future version. Instead use unsubscribe function returned by subscribe. Everything will be garbage-collected if store is garbage-collected."),n.clear()}},c=t=e(r,s,u);return u},Tg=e=>e?jd(e):jd;var Tm={exports:{}},Om={},Lm={exports:{}},Rm={};/** + * @license React + * use-sync-external-store-shim.production.js + * + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var Hr=k;function Og(e,t){return e===t&&(e!==0||1/e===1/t)||e!==e&&t!==t}var Lg=typeof Object.is=="function"?Object.is:Og,Rg=Hr.useState,Mg=Hr.useEffect,zg=Hr.useLayoutEffect,Fg=Hr.useDebugValue;function Ig(e,t){var n=t(),r=Rg({inst:{value:n,getSnapshot:t}}),s=r[0].inst,i=r[1];return zg(function(){s.value=n,s.getSnapshot=t,pl(s)&&i({inst:s})},[e,n,t]),Mg(function(){return pl(s)&&i({inst:s}),e(function(){pl(s)&&i({inst:s})})},[e]),Fg(n),n}function pl(e){var t=e.getSnapshot;e=e.value;try{var n=t();return!Lg(e,n)}catch{return!0}}function Dg(e,t){return t()}var Ag=typeof window>"u"||typeof window.document>"u"||typeof window.document.createElement>"u"?Dg:Ig;Rm.useSyncExternalStore=Hr.useSyncExternalStore!==void 0?Hr.useSyncExternalStore:Ag;Lm.exports=Rm;var $g=Lm.exports;/** + * @license React + * use-sync-external-store-shim/with-selector.production.js + * + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var Aa=k,Ug=$g;function Bg(e,t){return e===t&&(e!==0||1/e===1/t)||e!==e&&t!==t}var Qg=typeof Object.is=="function"?Object.is:Bg,Vg=Ug.useSyncExternalStore,Kg=Aa.useRef,Hg=Aa.useEffect,Wg=Aa.useMemo,qg=Aa.useDebugValue;Om.useSyncExternalStoreWithSelector=function(e,t,n,r,s){var i=Kg(null);if(i.current===null){var l={hasValue:!1,value:null};i.current=l}else l=i.current;i=Wg(function(){function u(x){if(!c){if(c=!0,m=x,x=r(x),s!==void 0&&l.hasValue){var w=l.value;if(s(w,x))return d=w}return d=x}if(w=d,Qg(m,x))return w;var g=r(x);return s!==void 0&&s(w,g)?(m=x,w):(m=x,d=g)}var c=!1,m,d,h=n===void 0?null:n;return[function(){return u(t())},h===null?void 0:function(){return u(h())}]},[t,n,r,s]);var o=Vg(e,i[0],i[1]);return Hg(function(){l.hasValue=!0,l.value=o},[o]),qg(o),o};Tm.exports=Om;var Jg=Tm.exports;const Gg=$d(Jg),Mm={},{useDebugValue:Yg}=Do,{useSyncExternalStoreWithSelector:Xg}=Gg;let wd=!1;const Zg=e=>e;function e0(e,t=Zg,n){(Mm?"production":void 0)!=="production"&&n&&!wd&&(console.warn("[DEPRECATED] Use `createWithEqualityFn` instead of `create` or use `useStoreWithEqualityFn` instead of `useStore`. They can be imported from 'zustand/traditional'. https://github.com/pmndrs/zustand/discussions/1937"),wd=!0);const r=Xg(e.subscribe,e.getState,e.getServerState||e.getInitialState,t,n);return Yg(r),r}const kd=e=>{(Mm?"production":void 0)!=="production"&&typeof e!="function"&&console.warn("[DEPRECATED] Passing a vanilla store will be unsupported in a future version. Instead use `import { useStore } from 'zustand'`.");const t=typeof e=="function"?Tg(e):e,n=(r,s)=>e0(t,r,s);return Object.assign(n,t),n},zu=e=>e?kd(e):kd,$a="/api",Fu="flow_auth_token",Iu="flow_auth_expires",Du="flow_auth_username";function Ws(){const e=localStorage.getItem(Fu),t=localStorage.getItem(Iu);return!e||!t?null:new Date(t)<=new Date?(qn(),null):e}function Sd(e,t,n){localStorage.setItem(Fu,e),localStorage.setItem(Iu,t),localStorage.setItem(Du,n)}function qn(){localStorage.removeItem(Fu),localStorage.removeItem(Iu),localStorage.removeItem(Du)}function Au(){return localStorage.getItem(Du)}let nr=null;function t0(e){nr=e}async function V(e,t,n=!1){const r={"Content-Type":"application/json",...t==null?void 0:t.headers};if(!n){const i=Ws();i&&(r.Authorization=`Bearer ${i}`)}const s=await fetch(`${$a}${e}`,{...t,headers:r});if(s.status===401){qn(),nr&&nr();const i=await s.json().catch(()=>({detail:"Not authenticated"}));throw new Error(i.detail||"Not authenticated")}if(!s.ok){const i=await s.json().catch(()=>({detail:s.statusText}));throw new Error(i.detail||"API request failed")}if(s.status!==204)return s.json()}const ar={getConfig:()=>V("/auth/config",void 0,!0),login:e=>V("/auth/login",{method:"POST",body:JSON.stringify(e)},!0),getGitHubAuthUrl:()=>`${$a}/auth/github`,getCurrentUser:()=>V("/auth/me"),logout:()=>V("/auth/logout",{method:"POST"})},br={list:e=>{const t=new URLSearchParams;e!=null&&e.include_auto_generated&&t.set("include_auto_generated","true"),e!=null&&e.include_public&&t.set("include_public","true");const n=t.toString();return V(`/configs${n?`?${n}`:""}`)},get:e=>V(`/configs/${e}`),create:e=>V("/configs",{method:"POST",body:JSON.stringify(e)}),update:(e,t)=>V(`/configs/${e}`,{method:"PUT",body:JSON.stringify(t)}),delete:e=>V(`/configs/${e}`,{method:"DELETE"})},Dt={list:e=>{const t=new URLSearchParams;e!=null&&e.category&&t.set("category",e.category),e!=null&&e.suite&&t.set("suite",e.suite);const n=t.toString();return V(`/tasks${n?`?${n}`:""}`)},get:e=>V(`/tasks/${e}`),create:e=>V("/tasks",{method:"POST",body:JSON.stringify(e)}),update:(e,t)=>V(`/tasks/${e}`,{method:"PUT",body:JSON.stringify(t)}),delete:e=>V(`/tasks/${e}`,{method:"DELETE"}),listSuites:()=>V("/tasks/suites"),importSuite:e=>V(`/tasks/import-suite?suite_name=${encodeURIComponent(e)}`,{method:"POST"})},_t={list:e=>{const t=new URLSearchParams;e!=null&&e.status&&t.set("status",e.status),e!=null&&e.include_public&&t.set("include_public","true");const n=t.toString();return V(`/jobs${n?`?${n}`:""}`)},get:e=>V(`/jobs/${e}`),create:e=>V("/jobs",{method:"POST",body:JSON.stringify(e)}),update:(e,t)=>V(`/jobs/${e}`,{method:"PUT",body:JSON.stringify(t)}),start:async function*(e){var o;const t={},n=Ws();n&&(t.Authorization=`Bearer ${n}`);const r=await fetch(`${$a}/jobs/${e}/start`,{method:"POST",headers:t});if(r.status===401)throw qn(),nr&&nr(),new Error("Not authenticated");if(!r.ok)throw new Error("Failed to start job");const s=(o=r.body)==null?void 0:o.getReader();if(!s)throw new Error("No response body");const i=new TextDecoder;let l="";for(;;){const{done:u,value:c}=await s.read();if(u)break;l+=i.decode(c,{stream:!0});const m=l.split(` +`);l=m.pop()||"";for(const d of m)d.startsWith("data: ")&&(yield JSON.parse(d.slice(6)))}},cancel:e=>V(`/jobs/${e}/cancel`,{method:"POST"}),delete:e=>V(`/jobs/${e}`,{method:"DELETE"})},To={list:e=>{const t=new URLSearchParams;e!=null&&e.job_id&&t.set("job_id",e.job_id),e!=null&&e.candidate_name&&t.set("candidate_name",e.candidate_name),e!=null&&e.task_name&&t.set("task_name",e.task_name),(e==null?void 0:e.is_pareto)!==void 0&&t.set("is_pareto",String(e.is_pareto));const n=t.toString();return V(`/runs${n?`?${n}`:""}`)},get:e=>V(`/runs/${e}`),getJobSummary:e=>V(`/runs/job/${e}/summary`)},Ns={list:e=>{const t=new URLSearchParams;e!=null&&e.agent_id&&t.set("agent_id",e.agent_id),e!=null&&e.limit&&t.set("limit",String(e.limit));const n=t.toString();return V(`/tests${n?`?${n}`:""}`)},get:e=>V(`/tests/${e}`),create:e=>V("/tests",{method:"POST",body:JSON.stringify(e)}),start:async function*(e){var o;const t={},n=Ws();n&&(t.Authorization=`Bearer ${n}`);const r=await fetch(`${$a}/tests/${e}/start`,{method:"POST",headers:t});if(r.status===401)throw qn(),nr&&nr(),new Error("Not authenticated");if(!r.ok){const u=await r.json().catch(()=>({detail:"Failed to start test"}));throw new Error(u.detail||"Failed to start test")}const s=(o=r.body)==null?void 0:o.getReader();if(!s)throw new Error("No response body");const i=new TextDecoder;let l="";for(;;){const{done:u,value:c}=await s.read();if(u)break;l+=i.decode(c,{stream:!0});const m=l.split(` +`);l=m.pop()||"";for(const d of m)d.startsWith("data: ")&&(yield JSON.parse(d.slice(6)))}},cancel:e=>V(`/tests/${e}/cancel`,{method:"POST"}),delete:e=>V(`/tests/${e}`,{method:"DELETE"})},n0={list:()=>V("/llm-configs"),get:e=>V(`/llm-configs/${e}`),getDefault:()=>V("/llm-configs/default"),create:e=>V("/llm-configs",{method:"POST",body:JSON.stringify(e)}),update:(e,t)=>V(`/llm-configs/${e}`,{method:"PUT",body:JSON.stringify(t)}),delete:e=>V(`/llm-configs/${e}`,{method:"DELETE"}),setDefault:e=>V(`/llm-configs/${e}/set-default`,{method:"POST"}),test:e=>V(`/llm-configs/${e}/test`,{method:"POST"})},r0={list:()=>V("/tools"),get:e=>V(`/tools/${e}`)},zm={getAgentSchema:()=>V("/schema/agent")},Nd={design:e=>V("/experiment/design",{method:"POST",body:JSON.stringify(e)}),importYaml:e=>V("/experiment/import-yaml",{method:"POST",body:JSON.stringify(e)}),validate:e=>V("/experiment/validate",{method:"POST",body:JSON.stringify(e)})},$u=zu((e,t)=>(t0(()=>{e({isAuthenticated:!1,user:null,error:"Session expired. Please log in again."})}),{authConfig:null,isLoadingConfig:!0,isAuthenticated:!1,isLoading:!1,user:null,error:null,loadAuthConfig:async()=>{e({isLoadingConfig:!0});try{const n=await ar.getConfig();if(e({authConfig:n,isLoadingConfig:!1}),n.enabled){const r=Ws(),s=Au();if(r&&s)try{const i=await ar.getCurrentUser();e({isAuthenticated:!0,user:i})}catch{qn(),e({isAuthenticated:!1,user:null})}}else e({isAuthenticated:!0,user:{username:"anonymous",auth_mode:"none"}})}catch(n){console.error("Failed to load auth config:",n),e({isLoadingConfig:!1,error:"Failed to connect to server"})}},login:async(n,r)=>{e({isLoading:!0,error:null});try{const s=await ar.login({username:n,password:r});return Sd(s.access_token,s.expires_at,s.username),e({isAuthenticated:!0,isLoading:!1,user:{username:s.username,auth_mode:"basic"}}),!0}catch(s){return e({isLoading:!1,error:s instanceof Error?s.message:"Login failed"}),!1}},loginWithGitHub:()=>{window.location.href=ar.getGitHubAuthUrl()},handleOAuthCallback:()=>{const n=new URLSearchParams(window.location.search),r=n.get("auth_error");if(r)return e({error:r}),window.history.replaceState({},"",window.location.pathname),!0;if(n.get("auth_callback")==="true"){const s=n.get("token"),i=n.get("expires_at"),l=n.get("username");return s&&i&&l&&(Sd(s,i,l),e({isAuthenticated:!0,user:{username:l,auth_mode:"github"}})),window.history.replaceState({},"",window.location.pathname),!0}return!1},logout:async()=>{try{await ar.logout()}catch{}qn(),e({isAuthenticated:!1,user:null,error:null})},checkAuth:async()=>{const{authConfig:n}=t();if(!(n!=null&&n.enabled)){e({isAuthenticated:!0});return}if(!Ws()){e({isAuthenticated:!1,user:null});return}try{const s=await ar.getCurrentUser();e({isAuthenticated:!0,user:s})}catch{qn(),e({isAuthenticated:!1,user:null})}},clearError:()=>e({error:null})}));function K({variant:e="secondary",size:t="md",className:n="",icon:r,iconRight:s,loading:i=!1,children:l,disabled:o,...u}){const c="font-medium transition-colors disabled:opacity-50 disabled:cursor-not-allowed inline-flex items-center gap-1.5",m={primary:"bg-[var(--accent)] text-black hover:bg-[#16a34a]",secondary:"bg-[var(--bg-tertiary)] text-[var(--text-primary)] border border-[var(--border)] hover:bg-[var(--border)]",danger:"bg-[var(--error)] text-white hover:bg-red-600",ghost:"text-[var(--text-secondary)] hover:text-[var(--text-primary)] hover:bg-[var(--bg-tertiary)]"},d={sm:"px-2 py-1 text-xs",md:"px-3 py-1.5 text-sm"},h=t==="sm"?14:16;return a.jsxs("button",{className:`${c} ${m[e]} ${d[t]} ${n}`,disabled:o||i,...u,children:[i?a.jsx(Fa,{size:h,className:"animate-spin"}):r?a.jsx(r,{size:h}):null,l,s&&!i&&a.jsx(s,{size:h})]})}const s0={};function i0(e,t){let n;try{n=e()}catch{return}return{getItem:s=>{var i;const l=u=>u===null?null:JSON.parse(u,void 0),o=(i=n.getItem(s))!=null?i:null;return o instanceof Promise?o.then(l):l(o)},setItem:(s,i)=>n.setItem(s,JSON.stringify(i,void 0)),removeItem:s=>n.removeItem(s)}}const qs=e=>t=>{try{const n=e(t);return n instanceof Promise?n:{then(r){return qs(r)(n)},catch(r){return this}}}catch(n){return{then(r){return this},catch(r){return qs(r)(n)}}}},a0=(e,t)=>(n,r,s)=>{let i={getStorage:()=>localStorage,serialize:JSON.stringify,deserialize:JSON.parse,partialize:S=>S,version:0,merge:(S,v)=>({...v,...S}),...t},l=!1;const o=new Set,u=new Set;let c;try{c=i.getStorage()}catch{}if(!c)return e((...S)=>{console.warn(`[zustand persist middleware] Unable to update item '${i.name}', the given storage is currently unavailable.`),n(...S)},r,s);const m=qs(i.serialize),d=()=>{const S=i.partialize({...r()});let v;const f=m({state:S,version:i.version}).then(p=>c.setItem(i.name,p)).catch(p=>{v=p});if(v)throw v;return f},h=s.setState;s.setState=(S,v)=>{h(S,v),d()};const x=e((...S)=>{n(...S),d()},r,s);let w;const g=()=>{var S;if(!c)return;l=!1,o.forEach(f=>f(r()));const v=((S=i.onRehydrateStorage)==null?void 0:S.call(i,r()))||void 0;return qs(c.getItem.bind(c))(i.name).then(f=>{if(f)return i.deserialize(f)}).then(f=>{if(f)if(typeof f.version=="number"&&f.version!==i.version){if(i.migrate)return i.migrate(f.state,f.version);console.error("State loaded from storage couldn't be migrated since no migrate function was provided")}else return f.state}).then(f=>{var p;return w=i.merge(f,(p=r())!=null?p:x),n(w,!0),d()}).then(()=>{v==null||v(w,void 0),l=!0,u.forEach(f=>f(w))}).catch(f=>{v==null||v(void 0,f)})};return s.persist={setOptions:S=>{i={...i,...S},S.getStorage&&(c=S.getStorage())},clearStorage:()=>{c==null||c.removeItem(i.name)},getOptions:()=>i,rehydrate:()=>g(),hasHydrated:()=>l,onHydrate:S=>(o.add(S),()=>{o.delete(S)}),onFinishHydration:S=>(u.add(S),()=>{u.delete(S)})},g(),w||x},l0=(e,t)=>(n,r,s)=>{let i={storage:i0(()=>localStorage),partialize:g=>g,version:0,merge:(g,S)=>({...S,...g}),...t},l=!1;const o=new Set,u=new Set;let c=i.storage;if(!c)return e((...g)=>{console.warn(`[zustand persist middleware] Unable to update item '${i.name}', the given storage is currently unavailable.`),n(...g)},r,s);const m=()=>{const g=i.partialize({...r()});return c.setItem(i.name,{state:g,version:i.version})},d=s.setState;s.setState=(g,S)=>{d(g,S),m()};const h=e((...g)=>{n(...g),m()},r,s);s.getInitialState=()=>h;let x;const w=()=>{var g,S;if(!c)return;l=!1,o.forEach(f=>{var p;return f((p=r())!=null?p:h)});const v=((S=i.onRehydrateStorage)==null?void 0:S.call(i,(g=r())!=null?g:h))||void 0;return qs(c.getItem.bind(c))(i.name).then(f=>{if(f)if(typeof f.version=="number"&&f.version!==i.version){if(i.migrate)return[!0,i.migrate(f.state,f.version)];console.error("State loaded from storage couldn't be migrated since no migrate function was provided")}else return[!1,f.state];return[!1,void 0]}).then(f=>{var p;const[j,C]=f;if(x=i.merge(C,(p=r())!=null?p:h),n(x,!0),j)return m()}).then(()=>{v==null||v(x,void 0),x=r(),l=!0,u.forEach(f=>f(x))}).catch(f=>{v==null||v(void 0,f)})};return s.persist={setOptions:g=>{i={...i,...g},g.storage&&(c=g.storage)},clearStorage:()=>{c==null||c.removeItem(i.name)},getOptions:()=>i,rehydrate:()=>w(),hasHydrated:()=>l,onHydrate:g=>(o.add(g),()=>{o.delete(g)}),onFinishHydration:g=>(u.add(g),()=>{u.delete(g)})},i.skipHydration||w(),x||h},o0=(e,t)=>"getStorage"in t||"serialize"in t||"deserialize"in t?((s0?"production":void 0)!=="production"&&console.warn("[DEPRECATED] `getStorage`, `serialize` and `deserialize` options are deprecated. Use `storage` option instead."),a0(e,t)):l0(e,t),u0=o0,c0=zu()(u0((e,t)=>({theme:"dark",setTheme:n=>{document.documentElement.setAttribute("data-theme",n),e({theme:n})},toggleTheme:()=>{const n=t().theme==="dark"?"light":"dark";document.documentElement.setAttribute("data-theme",n),e({theme:n})}}),{name:"flow-theme",onRehydrateStorage:()=>e=>{e!=null&&e.theme&&document.documentElement.setAttribute("data-theme",e.theme)}}));function d0(){const{theme:e,toggleTheme:t}=c0();return a.jsx("button",{onClick:t,className:"p-2 rounded-md text-[var(--text-secondary)] hover:text-[var(--text-primary)] hover:bg-[var(--bg-tertiary)] transition-colors focus:outline-none focus:ring-2 focus:ring-[var(--accent)]","aria-label":`Switch to ${e==="dark"?"light":"dark"} mode`,title:`Switch to ${e==="dark"?"light":"dark"} mode`,children:e==="dark"?a.jsx(_g,{size:16}):a.jsx(Ng,{size:16})})}const f0=[{path:"/agents",label:"Agents",icon:cg},{path:"/jobs",label:"Jobs",icon:Hs},{path:"/tasks",label:"Tasks",icon:wg}];function h0(){const e=Xr(),{authConfig:t,user:n,logout:r}=$u(),s=l=>l==="/agents"?e.pathname==="/"||e.pathname==="/agents":e.pathname.startsWith(l),i=async()=>{await r()};return a.jsxs("div",{className:"min-h-screen flex flex-col",children:[a.jsx("header",{className:"border-b border-[var(--border)] bg-[var(--bg-secondary)]",children:a.jsxs("div",{className:"max-w-7xl mx-auto px-4 py-3 flex items-center justify-between",children:[a.jsxs("div",{className:"flex items-center gap-8",children:[a.jsxs(xd,{to:"/",className:"text-lg font-bold text-[var(--accent)] flex items-center gap-2 hover:opacity-80",children:[a.jsx(Da,{size:20}),"flow",a.jsx("span",{className:"text-[var(--text-secondary)]",children:"/optimize"})]}),a.jsx("nav",{className:"flex gap-1",children:f0.map(l=>a.jsxs(xd,{to:l.path,className:`px-3 py-1.5 rounded text-sm transition-colors flex items-center gap-2 ${s(l.path)?"bg-[var(--accent)] text-black font-medium":"text-[var(--text-secondary)] hover:text-[var(--text-primary)] hover:bg-[var(--bg-tertiary)]"}`,children:[a.jsx(l.icon,{size:16}),l.label]},l.path))})]}),a.jsxs("div",{className:"flex items-center gap-4",children:[a.jsx(d0,{}),(t==null?void 0:t.enabled)&&n&&a.jsxs("div",{className:"flex items-center gap-3",children:[a.jsxs("div",{className:"flex items-center gap-2 text-sm text-[var(--text-secondary)]",children:[a.jsx(Em,{size:14}),a.jsx("span",{children:n.username})]}),a.jsx(K,{variant:"ghost",size:"sm",icon:Sg,onClick:i,title:"Sign out",children:"Sign out"})]})]})]})}),a.jsx("main",{className:"flex-1 bg-[var(--bg-primary)]",children:a.jsx("div",{className:"max-w-7xl mx-auto p-4",children:a.jsx(Vy,{})})})]})}const m0=["maf","miniagent","langgraph"],p0={maf:"Microsoft Agent Framework",miniagent:"MiniAgent",langgraph:"LangGraph"},v0={openai:"OpenAI",azure_openai:"Azure OpenAI",anthropic:"Anthropic",ollama:"Ollama",custom:"Custom (OpenAI-compatible)"};function ne({children:e,className:t="",onClick:n,selected:r=!1,selectable:s=!1}){const i="bg-[var(--bg-secondary)] border border-[var(--border)] p-4",l=s?"cursor-pointer hover:border-[var(--accent-dim)] transition-colors":"",o=r?"border-[var(--accent)]":"";return a.jsx("div",{className:`${i} ${l} ${o} ${t}`,onClick:n,children:e})}function q({children:e,variant:t="default"}){const n={default:"bg-[var(--bg-tertiary)] text-[var(--text-primary)] border border-[var(--border)]",success:"bg-green-600 text-white",warning:"bg-yellow-500 text-black",error:"bg-red-600 text-white",info:"bg-blue-600 text-white"};return a.jsx("span",{className:`inline-block px-2 py-0.5 text-xs font-medium rounded ${n[t]}`,children:e})}const x0={pending:"default",running:"info",completed:"success",failed:"error",cancelled:"warning"};function Fm({job:e,onDelete:t}){const n=Et(),r=e.total_experiments>0?e.completed_experiments/e.total_experiments*100:0;return a.jsxs(ne,{className:"cursor-pointer hover:border-[var(--accent-dim)] flex flex-col",onClick:()=>n(`/jobs/${e.id}`),children:[a.jsxs("div",{className:"flex items-start justify-between mb-3",children:[a.jsxs("div",{className:"flex-1 min-w-0",children:[a.jsxs("div",{className:"flex items-center gap-2 flex-wrap",children:[a.jsx(q,{variant:x0[e.status]||"default",children:e.status}),e.is_public&&a.jsxs(q,{variant:"info",children:[a.jsx(za,{className:"w-3 h-3 mr-1 inline"}),"Public"]}),e.pareto_frontier.length>0&&a.jsxs(q,{variant:"success",children:[e.pareto_frontier.length," Pareto"]}),e.use_llm_eval&&a.jsx(q,{children:"LLM"})]}),a.jsx("h3",{className:"font-medium mt-2 truncate",title:e.name||`Job ${e.id.slice(0,8)}`,children:e.name||`Job ${e.id.slice(0,8)}`}),a.jsxs("code",{className:"text-xs text-[var(--text-secondary)] font-mono",children:[e.id.slice(0,8),"..."]})]}),t&&a.jsx(K,{variant:"ghost",size:"sm",onClick:s=>{s.stopPropagation(),confirm("Delete this job?")&&t(e.id)},disabled:e.status==="running",children:"×"})]}),(e.status==="running"||e.status==="completed")&&a.jsxs("div",{className:"mb-3",children:[a.jsxs("div",{className:"flex justify-between text-xs text-[var(--text-secondary)] mb-1",children:[a.jsx("span",{children:"Progress"}),a.jsxs("span",{children:[e.completed_experiments,"/",e.total_experiments]})]}),a.jsx("div",{className:"w-full bg-[var(--bg-primary)] h-1.5 rounded-full overflow-hidden",children:a.jsx("div",{className:`h-full transition-all ${e.status==="completed"?"bg-green-500":"bg-[var(--accent)]"}`,style:{width:`${r}%`}})})]}),e.status==="failed"&&e.error&&a.jsx("div",{className:"mb-3 px-2 py-1.5 bg-red-500/10 border border-red-500/30 rounded text-xs text-red-400 line-clamp-2",children:e.error}),a.jsxs("div",{className:"grid grid-cols-3 gap-2 text-center py-2 border-t border-[var(--border)] mt-auto",children:[a.jsxs("div",{children:[a.jsx("div",{className:"text-lg font-bold",children:e.candidate_ids.length}),a.jsx("div",{className:"text-xs text-[var(--text-secondary)]",children:"candidates"})]}),a.jsxs("div",{children:[a.jsx("div",{className:"text-lg font-bold",children:e.task_ids.length}),a.jsx("div",{className:"text-xs text-[var(--text-secondary)]",children:"tasks"})]}),a.jsxs("div",{children:[a.jsx("div",{className:"text-lg font-bold",children:e.total_experiments}),a.jsx("div",{className:"text-xs text-[var(--text-secondary)]",children:"runs"})]})]}),a.jsxs("div",{className:"text-xs text-[var(--text-secondary)] pt-2 border-t border-[var(--border)] flex justify-between items-center",children:[a.jsxs("span",{children:[new Date(e.created_at).toLocaleDateString()," ",new Date(e.created_at).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})]}),e.is_public&&e.created_by_name&&a.jsxs("span",{className:"text-[var(--text-secondary)]",children:["by ",e.created_by_name]})]})]})}function ai({isOpen:e,onClose:t,title:n,children:r,footer:s}){return k.useEffect(()=>{const i=l=>{l.key==="Escape"&&t()};return e&&(document.addEventListener("keydown",i),document.body.style.overflow="hidden"),()=>{document.removeEventListener("keydown",i),document.body.style.overflow=""}},[e,t]),e?a.jsxs("div",{className:"fixed inset-0 z-50 flex items-center justify-center",children:[a.jsx("div",{className:"absolute inset-0 bg-black/80",onClick:t}),a.jsxs("div",{className:"relative bg-[var(--bg-secondary)] border border-[var(--border)] max-w-lg w-full mx-4 max-h-[80vh] flex flex-col",children:[a.jsxs("div",{className:"flex-shrink-0 bg-[var(--bg-secondary)] border-b border-[var(--border)] px-4 py-3 flex items-center justify-between",children:[a.jsx("h2",{className:"font-semibold",children:n}),a.jsx("button",{onClick:t,className:"text-[var(--text-secondary)] hover:text-[var(--text-primary)]",children:"×"})]}),a.jsx("div",{className:"flex-1 overflow-y-auto p-4",children:r}),s&&a.jsx("div",{className:"flex-shrink-0 bg-[var(--bg-secondary)] border-t border-[var(--border)] px-4 py-3",children:s})]})]}):null}function fn({label:e,className:t="",...n}){return a.jsxs("div",{className:"space-y-1",children:[e&&a.jsx("label",{className:"block text-sm text-[var(--text-secondary)]",children:e}),a.jsx("input",{className:`w-full bg-[var(--bg-primary)] border border-[var(--border)] px-3 py-2 text-sm focus:outline-none focus:border-[var(--accent)] ${t}`,...n})]})}function y0({label:e,className:t="",...n}){return a.jsxs("div",{className:"space-y-1",children:[e&&a.jsx("label",{className:"block text-sm text-[var(--text-secondary)]",children:e}),a.jsx("textarea",{className:`w-full bg-[var(--bg-primary)] border border-[var(--border)] px-3 py-2 text-sm focus:outline-none focus:border-[var(--accent)] resize-y min-h-[100px] ${t}`,...n})]})}function Oo({label:e,className:t="",...n}){return a.jsxs("label",{className:`flex items-center gap-2 cursor-pointer ${t}`,children:[a.jsx("input",{type:"checkbox",className:"w-4 h-4 bg-[var(--bg-primary)] border border-[var(--border)] accent-[var(--accent)]",...n}),a.jsx("span",{className:"text-sm",children:e})]})}function g0({variations:e,onChange:t,strategies:n,availableStrategies:r}){const s=r??Object.keys(n),i=()=>{const c=e.map(x=>x.strategy),m=s.find(x=>!c.includes(x))||"none",d=n[m],h={strategy:m};if(d!=null&&d.params)for(const[x,w]of Object.entries(d.params))w.default!==void 0&&(h[x]=w.default);t([...e,h])},l=c=>{t(e.filter((m,d)=>d!==c))},o=(c,m)=>{t(e.map((d,h)=>h===c?{...d,...m}:d))},u=(c,m)=>{const d=n[m],h={strategy:m};if(d!=null&&d.params)for(const[x,w]of Object.entries(d.params))w.default!==void 0&&(h[x]=w.default);o(c,h)};return a.jsxs("div",{className:"space-y-3",children:[a.jsxs("div",{className:"flex items-center justify-between",children:[a.jsx("label",{className:"text-sm font-medium",children:"Compaction Strategies"}),a.jsx(K,{type:"button",variant:"ghost",size:"sm",icon:Ia,onClick:i,disabled:e.length>=s.length,children:"Add"})]}),e.length===0?a.jsx("p",{className:"text-sm text-[var(--text-secondary)] italic",children:'No compaction variations. Click "Add" to test different strategies.'}):a.jsx("div",{className:"space-y-2",children:e.map((c,m)=>{const d=n[c.strategy];return a.jsx("div",{className:"p-3 border border-[var(--border)] rounded bg-[var(--bg-secondary)]",children:a.jsxs("div",{className:"flex items-start justify-between gap-2",children:[a.jsxs("div",{className:"flex-1 space-y-2",children:[a.jsx("select",{className:"w-full px-2 py-1.5 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm",value:c.strategy,onChange:h=>u(m,h.target.value),children:s.map(h=>{var x;return a.jsx("option",{value:h,children:((x=n[h])==null?void 0:x.label)||h},h)})}),(d==null?void 0:d.description)&&a.jsx("p",{className:"text-xs text-[var(--text-secondary)]",children:d.description}),(d==null?void 0:d.params)&&Object.keys(d.params).length>0&&a.jsx("div",{className:"grid grid-cols-2 gap-2 mt-2",children:Object.entries(d.params).map(([h,x])=>a.jsx(j0,{name:h,schema:x,value:c[h],onChange:w=>o(m,{[h]:w})},h))})]}),a.jsx("button",{type:"button",onClick:()=>l(m),className:"p-1 text-[var(--text-secondary)] hover:text-[var(--error)] transition-colors",children:a.jsx(Pm,{size:16})})]})},m)})})]})}function j0({name:e,schema:t,value:n,onChange:r}){const s=e.replace(/_/g," ");return t.type==="boolean"?a.jsxs("label",{className:"flex items-center gap-2 text-xs",children:[a.jsx("input",{type:"checkbox",checked:!!(n??t.default),onChange:i=>r(i.target.checked),className:"accent-[var(--accent)]"}),a.jsx("span",{className:"capitalize",children:s})]}):a.jsxs("div",{children:[a.jsx("label",{className:"text-xs font-medium block mb-1 capitalize",children:s}),a.jsx("input",{type:t.type==="number"?"number":"text",className:"w-full px-2 py-1 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-xs",value:String(n!==void 0?n:t.default??""),onChange:i=>{if(t.type==="number"){const l=parseFloat(i.target.value);r(isNaN(l)?t.default:l)}else r(i.target.value)},min:t.min,max:t.max,step:t.max&&t.max<=1?.1:1})]})}function w0({variations:e,onChange:t,providers:n}){const r=()=>{const o=n[0],u={provider:(o==null?void 0:o.name)||"azure_openai",model:(o==null?void 0:o.models[0])||"gpt-4o"};t([...e,u])},s=o=>{t(e.filter((u,c)=>c!==o))},i=(o,u)=>{t(e.map((c,m)=>m===o?{...c,...u}:c))},l=(o,u)=>{const c=n.find(m=>m.name===u);i(o,{provider:u,model:(c==null?void 0:c.models[0])||""})};return a.jsxs("div",{className:"space-y-3",children:[a.jsxs("div",{className:"flex items-center justify-between",children:[a.jsx("label",{className:"text-sm font-medium",children:"LLM Configurations"}),a.jsx(K,{type:"button",variant:"ghost",size:"sm",icon:Ia,onClick:r,children:"Add"})]}),e.length===0?a.jsx("p",{className:"text-sm text-[var(--text-secondary)] italic",children:`Uses agent's default LLM. Click "Add" to test different models.`}):a.jsx("div",{className:"space-y-2",children:e.map((o,u)=>{const c=n.find(m=>m.name===o.provider);return a.jsxs("div",{className:"flex items-center gap-2 p-2 border border-[var(--border)] rounded bg-[var(--bg-secondary)]",children:[a.jsx("select",{className:"flex-1 px-2 py-1.5 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm",value:o.provider,onChange:m=>l(u,m.target.value),children:n.map(m=>a.jsx("option",{value:m.name,children:m.label},m.name))}),c&&c.models.length>0?a.jsxs("select",{className:"flex-1 px-2 py-1.5 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm",value:o.model,onChange:m=>i(u,{model:m.target.value}),children:[c.models.map(m=>a.jsx("option",{value:m,children:m},m)),!c.models.includes(o.model)&&o.model&&a.jsx("option",{value:o.model,children:o.model})]}):a.jsx("input",{type:"text",className:"flex-1 px-2 py-1.5 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm",value:o.model,onChange:m=>i(u,{model:m.target.value}),placeholder:"Model ID"}),a.jsx("button",{type:"button",onClick:()=>s(u),className:"p-1 text-[var(--text-secondary)] hover:text-[var(--error)] transition-colors",children:a.jsx(Pm,{size:16})})]},u)})})]})}const Lo={compaction:[],tools:[],llm_config:[],instructions:[],instruction_strategies:[]};function k0({agentId:e,agentName:t,agentFramework:n="maf",taskSuite:r,taskCount:s,schema:i,onVariationsChange:l,parallel:o,onParallelChange:u,budget:c,onBudgetChange:m,useLlmEval:d,onUseLlmEvalChange:h}){const[x,w]=k.useState(Lo),[g,S]=k.useState(!1),[v,f]=k.useState(""),[p,j]=k.useState(null),C=i.frameworks[n],N=(C==null?void 0:C.compaction_strategies)||Object.keys(i.compaction_strategies),b=i.tool_presets||[],E=i.llm_providers||[],O=(()=>{let R=1;x.compaction.length>0&&(R*=x.compaction.length),x.tools.length>0&&(R*=x.tools.length),x.llm_config.length>0&&(R*=x.llm_config.length);const H=x.instructions.length+x.instruction_strategies.reduce((M,P)=>M+P.max_candidates,0);return H>0&&(R*=H),Math.min(R,c)})(),Q=O*s,D=R=>{w(R),l==null||l(R)},$=Ge({mutationFn:R=>Nd.design(R),onSuccess:R=>{f(R.yaml_content),S(!0)}}),Z=Ge({mutationFn:R=>Nd.validate(R),onSuccess:R=>{j({valid:R.valid,errors:R.errors,warnings:R.warnings})}}),me=()=>({base_agent_id:e,task_suite:r,variations:x,parallel:o,budget:c,use_llm_eval:d}),et=()=>{$.mutate(me())},Ne=()=>{Z.mutate(me())},L=()=>{const R=new Blob([v],{type:"text/yaml"}),H=URL.createObjectURL(R),M=document.createElement("a");M.href=H,M.download=`${t}_experiment.yaml`,M.click(),URL.revokeObjectURL(H)},A=x.compaction.length>0||x.tools.length>0||x.llm_config.length>0||x.instructions.length>0||x.instruction_strategies.length>0;return a.jsxs("div",{className:"space-y-6",children:[a.jsxs("div",{className:"flex flex-wrap gap-2",children:[a.jsxs(q,{variant:"info",children:[O," candidates"]}),a.jsxs(q,{children:[s," tasks"]}),a.jsxs(q,{variant:Q>100?"warning":"success",children:[Q," total runs"]})]}),a.jsx(g0,{variations:x.compaction,onChange:R=>D({...x,compaction:R}),strategies:i.compaction_strategies,availableStrategies:N}),a.jsxs("div",{className:"space-y-3",children:[a.jsx("label",{className:"text-sm font-medium",children:"Tool Presets"}),a.jsx("div",{className:"flex flex-wrap gap-2",children:b.map(R=>a.jsxs("label",{className:`flex items-center gap-2 px-3 py-1.5 border rounded cursor-pointer transition-colors ${x.tools.includes(R.name)?"border-[var(--accent)] bg-[var(--accent)]/10":"border-[var(--border)] hover:border-[var(--accent-dim)]"}`,children:[a.jsx("input",{type:"checkbox",checked:x.tools.includes(R.name),onChange:H=>{const M=H.target.checked?[...x.tools,R.name]:x.tools.filter(P=>P!==R.name);D({...x,tools:M})},className:"accent-[var(--accent)]"}),a.jsx("span",{className:"text-sm",children:R.name}),a.jsxs("span",{className:"text-xs text-[var(--text-secondary)]",children:["(",R.tools.length,")"]})]},R.name))}),x.tools.length>0&&a.jsxs("p",{className:"text-xs text-[var(--text-secondary)]",children:["Selected: ",x.tools.join(", ")]})]}),a.jsx(w0,{variations:x.llm_config,onChange:R=>D({...x,llm_config:R}),providers:E}),a.jsxs("div",{className:"border-t border-[var(--border)] pt-4 space-y-4",children:[a.jsx("h4",{className:"text-sm font-medium",children:"Execution Settings"}),a.jsxs("div",{className:"grid grid-cols-2 gap-4",children:[a.jsx(fn,{label:"Parallel Workers",type:"number",value:o,onChange:R=>u(parseInt(R.target.value)||1),min:1,max:16}),a.jsx(fn,{label:"Budget (max candidates)",type:"number",value:c,onChange:R=>m(parseInt(R.target.value)||100),min:1,max:1e3})]}),a.jsx(Oo,{label:"Use LLM evaluation",checked:d,onChange:R=>h(R.target.checked)}),a.jsx("p",{className:"text-xs text-[var(--text-secondary)] ml-6 -mt-2",children:d?"LLM-as-Judge scores task completion (0-1)":"Simple pass/fail based on task success"})]}),a.jsxs("div",{className:"flex items-center gap-2 border-t border-[var(--border)] pt-4",children:[a.jsx(K,{variant:"secondary",size:"sm",onClick:Ne,loading:Z.isPending,children:"Validate"}),a.jsx(K,{variant:"secondary",size:"sm",icon:gd,onClick:et,loading:$.isPending,children:"Export YAML"})]}),p&&a.jsxs("div",{className:`p-3 rounded border ${p.valid?"border-green-500/50 bg-green-500/10":"border-red-500/50 bg-red-500/10"}`,children:[a.jsxs("div",{className:"flex items-center gap-2 mb-2",children:[p.valid?a.jsx(Nm,{size:16,className:"text-green-500"}):a.jsx(Sm,{size:16,className:"text-red-500"}),a.jsx("span",{className:"font-medium text-sm",children:p.valid?"Configuration valid":"Configuration has issues"})]}),p.errors.length>0&&a.jsx("ul",{className:"text-sm text-red-500 list-disc ml-6",children:p.errors.map((R,H)=>a.jsx("li",{children:R},H))}),p.warnings.length>0&&a.jsx("ul",{className:"text-sm text-yellow-500 list-disc ml-6 mt-1",children:p.warnings.map((R,H)=>a.jsx("li",{children:R},H))})]}),g&&a.jsx("div",{className:"fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4",children:a.jsxs("div",{className:"bg-[var(--bg-primary)] rounded-lg shadow-xl max-w-2xl w-full max-h-[80vh] flex flex-col",children:[a.jsxs("div",{className:"flex items-center justify-between p-4 border-b border-[var(--border)]",children:[a.jsx("h3",{className:"font-medium",children:"Experiment YAML"}),a.jsxs("div",{className:"flex items-center gap-2",children:[a.jsx(K,{variant:"secondary",size:"sm",icon:gd,onClick:L,children:"Download"}),a.jsx(K,{variant:"ghost",size:"sm",onClick:()=>S(!1),children:"Close"})]})]}),a.jsx("pre",{className:"flex-1 overflow-auto p-4 text-xs font-mono bg-[var(--bg-secondary)]",children:v})]})}),!A&&a.jsx("p",{className:"text-sm text-[var(--text-secondary)] italic",children:"No variations selected. Only the baseline agent will be tested. Add compaction strategies, tool presets, or LLM configs to generate candidates."})]})}function bd(){const e=Et(),t=Pn(),[n,r]=k.useState(!1),[s,i]=k.useState(null),{data:l=[],isLoading:o}=ve({queryKey:["configs"],queryFn:()=>br.list()}),{data:u=[]}=ve({queryKey:["jobs"],queryFn:()=>_t.list()}),c=Ge({mutationFn:br.create,onSuccess:()=>{t.invalidateQueries({queryKey:["configs"]}),r(!1)}}),m=Ge({mutationFn:br.delete,onSuccess:()=>t.invalidateQueries({queryKey:["configs"]})}),d=h=>{const x=u.filter(S=>S.candidate_ids.includes(h)),w=x.filter(S=>S.status==="running").length,g=x.filter(S=>S.status==="completed").length;return{running:w,completed:g,total:x.length}};return a.jsxs("div",{children:[a.jsxs("div",{className:"flex items-center justify-between mb-6",children:[a.jsxs("div",{children:[a.jsx("h2",{className:"text-xl font-bold",children:"Agents"}),a.jsx("p",{className:"text-sm text-[var(--text-secondary)] mt-1",children:"Define and optimize your agent configurations."})]}),a.jsx(K,{variant:"primary",icon:Ia,onClick:()=>r(!0),children:"New Agent"})]}),o?a.jsxs("div",{className:"flex items-center gap-2 text-[var(--text-secondary)]",children:[a.jsx(Fa,{size:16,className:"animate-spin"}),"Loading agents..."]}):l.length===0?a.jsx(S0,{onCreateClick:()=>r(!0)}):a.jsx("div",{className:"grid gap-4 md:grid-cols-2 lg:grid-cols-3",children:l.map(h=>{const x=d(h.id);return a.jsx(b0,{agent:h,stats:x,onClick:()=>e(`/agents/${h.id}`),onOptimize:()=>i(h),onDelete:()=>{confirm(`Delete agent "${h.name}"?`)&&m.mutate(h.id)}},h.id)})}),u.length>0&&a.jsxs("div",{className:"mt-8",children:[a.jsx("h3",{className:"text-lg font-medium mb-4",children:"Recent Optimization Jobs"}),a.jsx("div",{className:"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4",children:u.slice(0,6).map(h=>a.jsx(Fm,{job:h},h.id))}),u.length>6&&a.jsxs(K,{variant:"ghost",className:"mt-4",onClick:()=>e("/jobs"),children:["View all ",u.length," jobs →"]})]}),a.jsx(C0,{isOpen:n,onClose:()=>r(!1),onSubmit:h=>c.mutate(h),isLoading:c.isPending}),s&&a.jsx(_0,{agent:s,isOpen:!!s,onClose:()=>i(null)})]})}function S0({onCreateClick:e}){return a.jsxs("div",{className:"text-center py-16 border border-dashed border-[var(--border)] rounded-lg",children:[a.jsx("div",{className:"inline-flex items-center justify-center w-12 h-12 rounded-full bg-[var(--bg-tertiary)] mb-4",children:a.jsx(Cm,{size:24,className:"text-[var(--text-secondary)]"})}),a.jsx("h3",{className:"text-lg font-medium mb-2",children:"No agents yet"}),a.jsx("p",{className:"text-[var(--text-secondary)] mb-4 max-w-md mx-auto",children:"Create your first agent to start optimizing. Each agent defines instructions, model, compaction strategy, and tool settings."}),a.jsx(K,{variant:"primary",icon:Ia,onClick:e,children:"Create Your First Agent"})]})}function N0(e){return typeof e=="string"?`tools: ${e}`:Array.isArray(e)?`tools: [${e.length}]`:typeof e=="object"?`tools: [${Object.keys(e).length}]`:"tools: standard"}function b0({agent:e,stats:t,onClick:n,onOptimize:r,onDelete:s}){const i=e.config.compaction,l=(i==null?void 0:i.strategy)==="head_tail"?`compaction ${i.params.head_size}/${i.params.tail_size}`:(i==null?void 0:i.strategy)==="none"?null:(i==null?void 0:i.strategy)||null,o=N0(e.config.tools),u=e.config.framework||"maf";return a.jsxs(ne,{className:"flex flex-col cursor-pointer hover:border-[var(--accent-dim)] transition-colors",onClick:n,children:[a.jsxs("div",{className:"flex-1",children:[a.jsxs("div",{className:"flex items-start justify-between mb-3",children:[a.jsxs("div",{children:[a.jsx("h3",{className:"font-medium text-lg",children:e.name}),e.description&&a.jsx("p",{className:"text-sm text-[var(--text-secondary)] mt-1",children:e.description})]}),a.jsx(K,{variant:"ghost",size:"sm",icon:_m,onClick:c=>{c.stopPropagation(),s()}})]}),a.jsxs("div",{className:"flex flex-wrap gap-1.5 mb-4",children:[a.jsx(q,{variant:u==="miniagent"?"success":"default",children:u}),l&&a.jsx(q,{children:l}),a.jsx(q,{children:o})]}),t.total>0&&a.jsxs("div",{className:"text-xs text-[var(--text-secondary)] mb-3",children:[t.running>0&&a.jsxs("span",{className:"text-[var(--accent)]",children:[t.running," running "]}),t.completed>0&&a.jsxs("span",{children:[t.completed," completed"]})]})]}),a.jsx("div",{className:"flex gap-2",children:a.jsx(K,{variant:"primary",icon:Da,onClick:c=>{c.stopPropagation(),r()},className:"flex-1",children:"Optimize"})})]})}function C0({isOpen:e,onClose:t,onSubmit:n,isLoading:r}){var Ne,L,A,R,H,M,P;const s=["read_file","write_file","edit_file","bash","grep","think"],[i,l]=k.useState({name:"",description:"",instructions:null,model:null,compaction:{strategy:"none",params:{}},tools:s,framework:"maf",llm_config_id:null}),[o,u]=k.useState(!1),[c,m]=k.useState("custom"),[d,h]=k.useState([...s]),[x,w]=k.useState(!1),{data:g}=ve({queryKey:["agent-schema"],queryFn:()=>zm.getAgentSchema()}),{data:S=[]}=ve({queryKey:["llm-configs"],queryFn:()=>n0.list()}),{data:v}=ve({queryKey:["tools"],queryFn:()=>r0.list()}),f=((Ne=v==null?void 0:v.tools)==null?void 0:Ne.map(_=>_.name))??s,p=(v==null?void 0:v.presets)??{},j=Object.keys(p),C=(g==null?void 0:g.frameworks)??{},N=Object.keys(C).length>0?Object.keys(C):m0,b=i.framework||"maf",E=((A=(L=g==null?void 0:g.frameworks)==null?void 0:L[b])==null?void 0:A.compaction_strategies)??["none","head_tail"],F=(g==null?void 0:g.compaction_strategies)??{},O=_=>{if(_.preventDefault(),!i.name.trim())return;const B={...i};c==="custom"&&(B.tools=d),n(B)},Q=((R=i.compaction)==null?void 0:R.strategy)!=="none",D=((H=i.compaction)==null?void 0:H.strategy)||"none",$=F[D],Z=_=>{h(B=>B.includes(_)?B.filter(re=>re!==_):[...B,_])},me=_=>{const B=F[_],re={};if(B!=null&&B.params)for(const[be,Zr]of Object.entries(B.params))Zr.default!==void 0&&(re[be]=Zr.default);l({...i,compaction:{strategy:_,params:re}})},et=a.jsxs("div",{className:"flex justify-end gap-2",children:[a.jsx(K,{type:"button",variant:"secondary",onClick:t,children:"Cancel"}),a.jsx(K,{type:"submit",form:"create-agent-form",variant:"primary",disabled:!i.name.trim(),loading:r,children:"Create Agent"})]});return a.jsx(ai,{isOpen:e,onClose:t,title:"Create Agent",footer:et,children:a.jsxs("form",{id:"create-agent-form",onSubmit:O,className:"space-y-4",children:[a.jsx(fn,{label:"Name",value:i.name,onChange:_=>l({...i,name:_.target.value}),placeholder:"e.g., my-coding-agent",required:!0}),a.jsxs("div",{children:[a.jsx("label",{className:"text-sm font-medium block mb-1.5",children:"LLM Configuration"}),a.jsxs("select",{className:"w-full px-3 py-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm",value:i.llm_config_id||"",onChange:_=>l({...i,llm_config_id:_.target.value||null}),children:[a.jsx("option",{value:"",children:"Use environment variables"}),S.map(_=>a.jsxs("option",{value:_.id,children:[_.name," (",v0[_.provider],_.model_id?` - ${_.model_id}`:"",")",_.is_default?" (default)":""]},_.id))]}),a.jsx("p",{className:"text-xs text-[var(--text-secondary)] mt-1",children:S.length===0?"No LLM configs found. Uses environment variables (AZURE_OPENAI_ENDPOINT, OPENAI_API_KEY, etc.)":i.llm_config_id?"Uses the selected LLM configuration.":"Uses environment variables (AZURE_OPENAI_ENDPOINT, OPENAI_API_KEY, etc.)"})]}),a.jsxs("div",{children:[a.jsx("label",{className:"text-sm font-medium block mb-1.5",children:"Framework"}),a.jsx("select",{className:"w-full px-3 py-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm",value:i.framework||"maf",onChange:_=>{const B=_.target.value;l({...i,framework:B,compaction:{strategy:"none",params:{}}})},children:N.map(_=>{var B;return a.jsx("option",{value:_,children:((B=C[_])==null?void 0:B.label)||p0[_]||_},_)})}),a.jsx("p",{className:"text-xs text-[var(--text-secondary)] mt-1",children:((M=C[b])==null?void 0:M.description)||(b==="miniagent"?"Lightweight agent with token-aware context management.":b==="langgraph"?"Graph-based workflows with state management.":"Default agent implementation.")})]}),a.jsxs("div",{className:"grid grid-cols-2 gap-4",children:[a.jsx(Oo,{label:"Custom instructions",checked:o,onChange:_=>{u(_.target.checked),_.target.checked||l({...i,instructions:null})}}),a.jsx(Oo,{label:"Enable compaction",checked:Q,onChange:_=>{if(_.target.checked){const B=E.find(re=>re!=="none")||"head_tail";me(B)}else l({...i,compaction:{strategy:"none",params:{}}})}})]}),o&&a.jsx("textarea",{className:"w-full h-32 px-3 py-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm font-mono resize-y",value:i.instructions||"",onChange:_=>l({...i,instructions:_.target.value||null}),placeholder:"System prompt / instructions for the agent..."}),Q&&a.jsxs("div",{className:"space-y-3 p-3 border border-[var(--border)] rounded bg-[var(--bg-secondary)]",children:[a.jsxs("div",{children:[a.jsx("label",{className:"text-sm font-medium block mb-1.5",children:"Compaction Strategy"}),a.jsx("select",{className:"w-full px-3 py-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm",value:D,onChange:_=>me(_.target.value),children:E.filter(_=>_!=="none").map(_=>{var B;return a.jsx("option",{value:_,children:((B=F[_])==null?void 0:B.label)||_},_)})}),($==null?void 0:$.description)&&a.jsx("p",{className:"text-xs text-[var(--text-secondary)] mt-1",children:$.description})]}),($==null?void 0:$.params)&&Object.keys($.params).length>0&&a.jsx("div",{className:"grid grid-cols-2 gap-3",children:Object.entries($.params).map(([_,B])=>{var Zr;const re=(Zr=i.compaction)==null?void 0:Zr.params[_],be=re!==void 0?re:B.default;return a.jsxs("div",{children:[a.jsx("label",{className:"text-xs font-medium block mb-1 capitalize",children:_.replace(/_/g," ")}),a.jsx("input",{type:"number",className:"w-full px-3 py-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm",value:typeof be=="number"?be:Number(be)||0,onChange:Qm=>{const Bu=parseFloat(Qm.target.value);l({...i,compaction:{...i.compaction,params:{...i.compaction.params,[_]:isNaN(Bu)?typeof B.default=="number"?B.default:0:Bu}}})},min:B.min,max:B.max,step:B.max&&B.max<=1?.1:1}),a.jsx("p",{className:"text-xs text-[var(--text-secondary)] mt-0.5",children:B.description})]},_)})})]}),a.jsxs("div",{className:"space-y-2",children:[a.jsx("label",{className:"text-sm font-medium",children:"Tools"}),a.jsxs("div",{className:"flex gap-4",children:[a.jsxs("label",{className:"flex items-center gap-2",children:[a.jsx("input",{type:"radio",checked:c==="custom",onChange:()=>m("custom"),className:"accent-[var(--accent)]"}),a.jsx("span",{className:"text-sm",children:"Custom"})]}),a.jsxs("label",{className:"flex items-center gap-2",children:[a.jsx("input",{type:"radio",checked:c==="preset",onChange:()=>m("preset"),className:"accent-[var(--accent)]"}),a.jsx("span",{className:"text-sm",children:"Preset"})]})]}),c==="custom"?a.jsx("div",{className:"grid grid-cols-2 gap-1 p-2 border border-[var(--border)] rounded bg-[var(--bg-secondary)]",children:f.map(_=>a.jsxs("label",{className:"flex items-center gap-2 p-1 text-sm cursor-pointer hover:bg-[var(--bg-tertiary)]",children:[a.jsx("input",{type:"checkbox",checked:d.includes(_),onChange:()=>Z(_),className:"accent-[var(--accent)]"}),a.jsx("span",{className:"font-mono text-xs",children:_})]},_))}):a.jsxs(a.Fragment,{children:[a.jsx("select",{className:"w-full px-3 py-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm",value:typeof i.tools=="string"?i.tools:"standard",onChange:_=>l({...i,tools:_.target.value}),children:j.map(_=>a.jsx("option",{value:_,children:_},_))}),a.jsx("p",{className:"text-xs text-[var(--text-secondary)] mt-1",children:((P=p[typeof i.tools=="string"?i.tools:"standard"])==null?void 0:P.join(", "))??""})]})]}),a.jsxs("div",{className:"border-t border-[var(--border)] pt-3",children:[a.jsxs("button",{type:"button",className:"flex items-center gap-2 text-sm text-[var(--text-secondary)] hover:text-[var(--text-primary)] transition-colors",onClick:()=>w(!x),children:[a.jsx(Ss,{size:14,className:`transition-transform ${x?"rotate-90":""}`}),"More options"]}),x&&a.jsx("div",{className:"mt-3",children:a.jsx(fn,{label:"Description (optional)",value:i.description,onChange:_=>l({...i,description:_.target.value}),placeholder:"Brief description of this agent"})})]})]})})}function _0({agent:e,isOpen:t,onClose:n}){var H;const r=Et(),s=Pn(),[i,l]=k.useState("suite"),[o,u]=k.useState("quick"),[c,m]=k.useState(!1),[d,h]=k.useState([]),[x,w]=k.useState(Lo),[g,S]=k.useState(4),[v,f]=k.useState(100),[p,j]=k.useState(!1),[C,N]=k.useState(null),{data:b=[]}=ve({queryKey:["tasks"],queryFn:()=>Dt.list()}),{data:E=[]}=ve({queryKey:["suites"],queryFn:()=>Dt.listSuites()}),{data:F}=ve({queryKey:["agent-schema"],queryFn:()=>zm.getAgentSchema()}),O=E.map(M=>({value:M.name,label:M.name.charAt(0).toUpperCase()+M.name.slice(1),description:M.description,tasks:M.task_count})),Q=Ge({mutationFn:Dt.importSuite,onSuccess:M=>{s.invalidateQueries({queryKey:["tasks"]}),h(M.map(P=>P.id))}}),D=Ge({mutationFn:async M=>{const P=await _t.create(M);return _t.start(P.id).next(),P},onSuccess:M=>{s.invalidateQueries({queryKey:["jobs"]}),N(M.id),l("success")}}),Z=(()=>{let M=1;x.compaction.length>0&&(M*=x.compaction.length),x.tools.length>0&&(M*=x.tools.length),x.llm_config.length>0&&(M*=x.llm_config.length);const P=x.instructions.length+x.instruction_strategies.reduce((_,B)=>_+B.max_candidates,0);return P>0&&(M*=P),Math.min(M,v)})(),me=c?d.length:((H=O.find(M=>M.value===o))==null?void 0:H.tasks)||3,et=Z*me,Ne=async()=>{l("starting");let M=d;if(!c)try{M=(await Q.mutateAsync(o)).map(re=>re.id)}catch(B){console.error("Failed to import suite:",B),alert(`Failed to import task suite: ${o}`),l("design");return}if(M.length===0){alert("No tasks selected. Please select tasks or choose a task suite."),l("design");return}const P=[e.id],_={name:`${e.name} optimization (${Z} candidates × ${M.length} tasks)`,candidate_ids:P,task_ids:M,parallel:g,use_llm_eval:p};D.mutate(_)},L=M=>{h(P=>P.includes(M)?P.filter(_=>_!==M):[...P,M])},A=()=>{l("suite"),N(null),w(Lo),n()},R=()=>i==="success"&&C?a.jsxs("div",{className:"flex justify-end gap-3",children:[a.jsx(K,{variant:"secondary",onClick:A,children:"Close"}),a.jsx(K,{variant:"primary",icon:Hs,onClick:()=>{A(),r(`/jobs/${C}`)},children:"View Job"})]}):i==="starting"?null:i==="design"?a.jsxs("div",{className:"flex justify-between gap-2",children:[a.jsx(K,{variant:"secondary",icon:hg,onClick:()=>l("suite"),children:"Back"}),a.jsxs(K,{variant:"primary",icon:Hs,onClick:Ne,children:["Start Optimization (",et," runs)"]})]}):a.jsxs("div",{className:"flex justify-end gap-2",children:[a.jsx(K,{variant:"secondary",onClick:n,children:"Cancel"}),a.jsx(K,{variant:"primary",icon:Ss,onClick:()=>l("design"),disabled:c&&d.length===0,children:"Next: Experiment Design"})]});return a.jsx(ai,{isOpen:t,onClose:A,title:`Optimize: ${e.name}`,footer:R(),children:i==="success"&&C?a.jsxs("div",{className:"flex flex-col items-center py-8",children:[a.jsx("div",{className:"w-12 h-12 rounded-full bg-green-500/20 flex items-center justify-center mb-4",children:a.jsx(Da,{size:24,className:"text-green-500"})}),a.jsx("h3",{className:"text-lg font-medium mb-2",children:"Job Started!"}),a.jsx("p",{className:"text-[var(--text-secondary)] text-center mb-2",children:"Optimization job is now running"}),a.jsxs("code",{className:"text-xs bg-[var(--bg-primary)] px-3 py-1.5 rounded font-mono",children:["ID: ",C.slice(0,8),"..."]})]}):i==="starting"?a.jsxs("div",{className:"flex flex-col items-center py-8",children:[a.jsx(Fa,{size:32,className:"animate-spin text-[var(--accent)] mb-4"}),a.jsx("p",{className:"text-[var(--text-secondary)]",children:Q.isPending?"Importing tasks...":"Creating optimization job..."})]}):i==="design"&&F?a.jsxs("div",{className:"space-y-6",children:[a.jsxs("div",{className:"flex items-center gap-2 text-sm text-[var(--text-secondary)]",children:[a.jsx("span",{className:"text-[var(--text-primary)]",children:"1. Tasks"}),a.jsx(Ss,{size:14}),a.jsx("span",{className:"text-[var(--accent)] font-medium",children:"2. Experiment Design"})]}),a.jsx(k0,{agentId:e.id,agentName:e.name,agentFramework:e.config.framework,taskSuite:c?void 0:o,taskCount:me,schema:F,onVariationsChange:w,parallel:g,onParallelChange:S,budget:v,onBudgetChange:f,useLlmEval:p,onUseLlmEvalChange:j})]}):a.jsxs("div",{className:"space-y-6",children:[a.jsxs("div",{className:"flex items-center gap-2 text-sm text-[var(--text-secondary)]",children:[a.jsx("span",{className:"text-[var(--accent)] font-medium",children:"1. Tasks"}),a.jsx(Ss,{size:14}),a.jsx("span",{children:"2. Experiment Design"})]}),a.jsxs("div",{children:[a.jsx("label",{className:"text-sm font-medium mb-3 block",children:"Select Task Suite"}),a.jsx("div",{className:"space-y-2",children:O.map(M=>{const P=b.filter(_=>_.suite===M.value).length;return a.jsxs("label",{className:`flex items-center gap-3 p-3 border cursor-pointer transition-colors ${o===M.value&&!c?"border-[var(--accent)] bg-[var(--accent)]/10":"border-[var(--border)] hover:border-[var(--accent-dim)]"}`,children:[a.jsx("input",{type:"radio",name:"suite",value:M.value,checked:o===M.value&&!c,onChange:()=>{u(M.value),m(!1)},className:"accent-[var(--accent)]"}),a.jsxs("div",{className:"flex-1",children:[a.jsxs("div",{className:"flex items-center gap-2",children:[a.jsx("span",{className:"font-medium",children:M.label}),a.jsxs(q,{children:[M.tasks," tasks"]}),P>0&&a.jsxs(q,{variant:"success",children:[P," imported"]})]}),a.jsx("p",{className:"text-sm text-[var(--text-secondary)]",children:M.description})]})]},M.value)})})]}),b.length>0&&a.jsxs("div",{children:[a.jsxs("label",{className:`flex items-center gap-3 p-3 border cursor-pointer transition-colors ${c?"border-[var(--accent)] bg-[var(--accent)]/10":"border-[var(--border)] hover:border-[var(--accent-dim)]"}`,children:[a.jsx("input",{type:"radio",checked:c,onChange:()=>m(!0),className:"accent-[var(--accent)]"}),a.jsxs("div",{className:"flex-1",children:[a.jsx("span",{className:"font-medium",children:"Custom Selection"}),a.jsx("p",{className:"text-sm text-[var(--text-secondary)]",children:"Choose specific tasks from your library"})]})]}),c&&a.jsx("div",{className:"mt-3 max-h-48 overflow-y-auto border border-[var(--border)] p-2 space-y-1",children:b.map(M=>a.jsxs("label",{className:"flex items-center gap-2 p-2 hover:bg-[var(--bg-tertiary)] cursor-pointer",children:[a.jsx("input",{type:"checkbox",checked:d.includes(M.id),onChange:()=>L(M.id),className:"accent-[var(--accent)]"}),a.jsx("span",{className:"text-sm",children:M.name}),M.suite&&a.jsx(q,{children:M.suite})]},M.id))})]})]})})}function E0(e){const t=[],n=r=>r.type==="trace_span"&&typeof r.data=="object"&&r.data!==null?r.data:"span_id"in r?r:null;if(Array.isArray(e.spans)){for(const r of e.spans)if(typeof r=="object"&&r!==null){const s=n(r);s&&t.push(s)}}else if(e.span_id)t.push(e);else for(const r in e){const s=e[r];if(typeof s=="object"&&s!==null){const i=n(s);if(i)t.push(i);else if(Array.isArray(s)){for(const l of s)if(typeof l=="object"&&l!==null){const o=n(l);o&&t.push(o)}}}}return t}function Im(e){const t=new Map,n=[];for(const s of e)t.set(s.span_id,{span:s,children:[]});for(const s of e){const i=t.get(s.span_id);s.parent_span_id&&t.has(s.parent_span_id)?t.get(s.parent_span_id).children.push(i):n.push(i)}const r=s=>{s.sort((i,l)=>(i.span.start_time||0)-(l.span.start_time||0)),s.forEach(i=>r(i.children))};return r(n),n}function P0(e){return e.includes("Agent")||e.includes("agent")?"bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-200":e.includes("chat")||e.includes("Chat")||e.includes("llm")?"bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200":e.includes("tool")||e.includes("execute")||e.includes("bash")?"bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200":"bg-orange-100 text-orange-800 dark:bg-orange-900 dark:text-orange-200"}function T0(e){return e>=1e3?`${(e/1e3).toFixed(2)}s`:`${e.toFixed(0)}ms`}function Uu({node:e,depth:t=0}){var d,h;const[n,r]=k.useState(t<2),[s,i]=k.useState(!1),{span:l}=e,o=e.children.length>0,u=(d=l.attributes)==null?void 0:d["gen_ai.usage.input_tokens"],c=(h=l.attributes)==null?void 0:h["gen_ai.usage.output_tokens"],m=u!==void 0||c!==void 0;return a.jsxs("div",{className:"relative",children:[t>0&&a.jsx("div",{className:"absolute left-0 top-0 bottom-0 border-l-2 border-[var(--border)]",style:{marginLeft:`${(t-1)*16+8}px`}}),a.jsxs("div",{className:"flex items-center gap-2 py-1.5 px-1 hover:bg-[var(--bg-primary)] rounded transition-colors cursor-pointer",style:{paddingLeft:`${t*16}px`},onClick:()=>o?r(!n):i(!s),children:[a.jsx("div",{className:"w-4 h-4 flex items-center justify-center text-[var(--text-secondary)]",children:o?n?"▼":"▶":s?"▼":"▶"}),a.jsx("span",{className:`text-xs px-1.5 py-0.5 rounded font-medium ${P0(l.operation_name)}`,children:l.operation_name.replace("ChatAgent.","").replace("invoke_agent ","")}),l.duration_ms!==void 0&&a.jsx("span",{className:"text-xs text-[var(--text-secondary)] font-mono",children:T0(l.duration_ms)}),m&&a.jsxs("span",{className:"text-xs text-[var(--text-secondary)] font-mono",children:[u!==void 0&&a.jsxs("span",{className:"text-blue-400",children:["↑",String(u)]}),u!==void 0&&c!==void 0&&a.jsx("span",{className:"mx-0.5",children:"/"}),c!==void 0&&a.jsxs("span",{className:"text-green-400",children:["↓",String(c)]})]})]}),s&&!o&&a.jsx("div",{className:"ml-4 mt-1 mb-2 p-2 bg-[var(--bg-primary)] rounded border border-[var(--border)] text-xs",style:{marginLeft:`${t*16+20}px`},children:a.jsxs("div",{className:"space-y-1",children:[l.span_id&&a.jsxs("div",{className:"flex gap-2",children:[a.jsx("span",{className:"text-[var(--text-secondary)] w-20",children:"Span ID:"}),a.jsx("span",{className:"font-mono text-xs break-all",children:l.span_id})]}),l.trace_id&&a.jsxs("div",{className:"flex gap-2",children:[a.jsx("span",{className:"text-[var(--text-secondary)] w-20",children:"Trace ID:"}),a.jsx("span",{className:"font-mono text-xs break-all",children:l.trace_id})]}),l.status&&a.jsxs("div",{className:"flex gap-2",children:[a.jsx("span",{className:"text-[var(--text-secondary)] w-20",children:"Status:"}),a.jsx("span",{className:`px-1.5 py-0.5 rounded text-xs ${l.status==="OK"||l.status==="StatusCode.UNSET"?"bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200":"bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200"}`,children:l.status})]}),Object.keys(l.attributes||{}).length>0&&a.jsxs("div",{className:"mt-2",children:[a.jsx("span",{className:"text-[var(--text-secondary)] block mb-1",children:"Attributes:"}),a.jsx("pre",{className:"text-xs bg-[var(--bg-secondary)] border border-[var(--border)] rounded p-2 overflow-auto max-h-32 whitespace-pre-wrap break-all",children:JSON.stringify(l.attributes,null,2)})]})]})}),o&&n&&a.jsx("div",{children:e.children.map((x,w)=>a.jsx(Uu,{node:x,depth:t+1},x.span.span_id||w))})]})}function Dm({trace:e}){const[t,n]=k.useState("tree"),r=k.useMemo(()=>E0(e),[e]),s=k.useMemo(()=>Im(r),[r]);return Object.keys(e).length===0?null:a.jsxs(ne,{className:"mb-6",children:[a.jsxs("div",{className:"flex items-center justify-between mb-3",children:[a.jsx("h3",{className:"font-medium",children:"Trace Data"}),a.jsxs("div",{className:"flex gap-1",children:[a.jsx("button",{onClick:()=>n("tree"),className:`px-2 py-1 text-xs rounded ${t==="tree"?"bg-[var(--accent)] text-white":"bg-[var(--bg-primary)] text-[var(--text-secondary)] hover:text-[var(--text-primary)]"}`,children:"Tree"}),a.jsx("button",{onClick:()=>n("raw"),className:`px-2 py-1 text-xs rounded ${t==="raw"?"bg-[var(--accent)] text-white":"bg-[var(--bg-primary)] text-[var(--text-secondary)] hover:text-[var(--text-primary)]"}`,children:"Raw"})]})]}),t==="tree"?r.length>0?a.jsx("div",{className:"border border-[var(--border)] rounded overflow-hidden",children:a.jsxs("div",{className:"p-2",children:[a.jsxs("div",{className:"flex items-center gap-2 mb-2 text-xs text-[var(--text-secondary)]",children:[a.jsxs(q,{variant:"default",children:[r.length," spans"]}),a.jsx("span",{children:"•"}),a.jsx("span",{children:"Click to expand details"})]}),s.map((i,l)=>a.jsx(Uu,{node:i,depth:0},i.span.span_id||l))]})}):a.jsx("div",{className:"text-sm text-[var(--text-secondary)] text-center py-4",children:"No structured spans found. View raw data below."}):a.jsx("pre",{className:"text-xs bg-[var(--bg-primary)] p-3 overflow-x-auto border border-[var(--border)] max-h-96 whitespace-pre-wrap",children:JSON.stringify(e,null,2)})]})}function O0({spans:e,isLive:t=!1}){const n=k.useRef(null),r=k.useMemo(()=>Im(e),[e]);return k.useEffect(()=>{n.current&&t&&n.current.scrollTo({top:n.current.scrollHeight,behavior:"smooth"})},[e.length,t]),a.jsxs("div",{className:"border border-[var(--border)] rounded overflow-hidden h-full flex flex-col",children:[a.jsxs("div",{className:"flex items-center gap-2 p-2 border-b border-[var(--border)] bg-[var(--bg-secondary)]",children:[a.jsxs(q,{variant:"default",children:[e.length," spans"]}),t&&a.jsx("span",{className:"animate-pulse",children:a.jsx(q,{variant:"info",children:"Live"})})]}),a.jsx("div",{ref:n,className:"flex-1 overflow-auto p-2",children:r.length>0?r.map((s,i)=>a.jsx(Uu,{node:s,depth:0},s.span.span_id||i)):a.jsx("div",{className:"text-sm text-[var(--text-secondary)] text-center py-4",children:t?"Waiting for spans...":"No spans recorded"})})]})}function L0({agent:e}){const[t,n]=k.useState(""),[r,s]=k.useState(null),[i,l]=k.useState("idle"),[o,u]=k.useState(null),[c,m]=k.useState(""),[d,h]=k.useState([]),[x,w]=k.useState(null),[g,S]=k.useState(null),[v,f]=k.useState([]),p=k.useRef(null),{data:j=[]}=ve({queryKey:["tasks"],queryFn:()=>Dt.list()});k.useEffect(()=>{p.current&&i==="running"&&(p.current.scrollTop=p.current.scrollHeight)},[c,i]);const C=D=>{if(s(D),D){const $=j.find(Z=>Z.id===D);$&&n($.prompt)}},N=async()=>{if(t.trim()){l("running"),m(""),h([]),w(null),S(null),f([]);try{const D=await Ns.create({agent_id:e.id,prompt:t.trim(),task_id:r||void 0});u(D.id);for await(const $ of Ns.start(D.id))b($)}catch(D){S(D instanceof Error?D.message:"Test failed"),l("failed")}}},b=D=>{switch(D.event){case"started":break;case"execution":D.execution_event==="text_delta"&&D.content?m($=>$+D.content):D.execution_event==="tool_call_start"&&D.tool_name?f($=>[...$,{name:D.tool_name}]):D.execution_event==="tool_result"&&D.content&&f($=>{if($.length>0){const Z=[...$];return Z[Z.length-1]={...Z[Z.length-1],content:D.content},Z}return $});break;case"span":if(D.span){const $=D.span;if($.data){const Z={span_id:$.data.span_id||"",trace_id:$.data.trace_id||"",parent_span_id:$.data.parent_span_id||null,operation_name:$.data.operation_name||"",start_time:$.timestamp?new Date($.timestamp).getTime():Date.now(),end_time:Date.now(),duration_ms:$.data.duration_ms||0,status:$.data.status||"OK",attributes:$.data.attributes||{}};h(me=>[...me,Z])}}break;case"complete":l("completed"),D.result&&w(D.result);break;case"error":S(D.message),l("failed");break}},E=async()=>{if(o)try{await Ns.cancel(o)}catch{}l("idle")},F=()=>{l("idle"),u(null),m(""),h([]),w(null),S(null),f([])},O=i==="running",Q=i==="completed"||i==="failed";return a.jsxs("div",{className:"h-full flex flex-col",children:[!O&&!Q&&a.jsxs("div",{className:"mb-4 space-y-3",children:[a.jsxs("div",{className:"flex gap-3",children:[a.jsxs("div",{className:"flex-1",children:[a.jsx("label",{className:"block text-sm font-medium mb-1",children:"Select Task (optional)"}),a.jsxs("select",{value:r||"",onChange:D=>C(D.target.value||null),className:"w-full px-3 py-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm",children:[a.jsx("option",{value:"",children:"Custom prompt..."}),j.map(D=>a.jsx("option",{value:D.id,children:D.name},D.id))]})]}),a.jsx("div",{className:"flex items-end",children:a.jsx(K,{variant:"primary",icon:Hs,onClick:N,disabled:!t.trim(),children:"Run Test"})})]}),a.jsxs("div",{children:[a.jsx("label",{className:"block text-sm font-medium mb-1",children:"Prompt"}),a.jsx("textarea",{value:t,onChange:D=>n(D.target.value),placeholder:"Enter a test prompt for the agent...",className:"w-full h-32 px-3 py-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm font-mono resize-none"})]})]}),(O||Q)&&a.jsxs("div",{className:"flex-1 flex flex-col min-h-0",children:[a.jsxs("div",{className:"flex items-center justify-between mb-3",children:[a.jsxs("div",{className:"flex items-center gap-2",children:[O&&a.jsxs(a.Fragment,{children:[a.jsx("span",{className:"animate-pulse",children:a.jsx(q,{variant:"info",children:"Running"})}),a.jsx(K,{variant:"ghost",size:"sm",icon:Cg,onClick:E,children:"Cancel"})]}),i==="completed"&&a.jsx(q,{variant:"success",children:"Completed"}),i==="failed"&&a.jsx(q,{variant:"error",children:"Failed"})]}),a.jsxs("div",{className:"flex items-center gap-3",children:[x&&a.jsxs("div",{className:"flex items-center gap-3 text-xs text-[var(--text-secondary)]",children:[a.jsxs("span",{className:"flex items-center gap-1",children:[a.jsx(mg,{size:12}),x.duration_seconds.toFixed(2),"s"]}),a.jsxs("span",{className:"flex items-center gap-1",children:[a.jsx(pg,{size:12}),x.tokens_total," tokens"]}),x.passed!==null&&(x.passed?a.jsx(Nm,{size:14,className:"text-green-500"}):a.jsx(Eg,{size:14,className:"text-red-500"}))]}),Q&&a.jsx(K,{variant:"secondary",size:"sm",onClick:F,children:"New Test"})]})]}),a.jsxs("div",{className:"flex-1 grid grid-cols-2 gap-4 min-h-0",children:[a.jsxs("div",{className:"flex flex-col border border-[var(--border)] rounded overflow-hidden",children:[a.jsx("div",{className:"px-3 py-2 border-b border-[var(--border)] bg-[var(--bg-secondary)] text-sm font-medium",children:"Output"}),a.jsxs("div",{ref:p,className:"flex-1 overflow-auto p-3 font-mono text-sm whitespace-pre-wrap bg-[var(--bg-primary)]",children:[c||(O?"Waiting for response...":"No output"),v.length>0&&a.jsxs("div",{className:"mt-3 space-y-2 border-t border-[var(--border)] pt-3",children:[a.jsx("div",{className:"text-xs text-[var(--text-secondary)] uppercase tracking-wider",children:"Tool Calls"}),v.map((D,$)=>a.jsxs("div",{className:"p-2 bg-green-500/10 border border-green-500/20 rounded text-xs",children:[a.jsx(q,{variant:"success",children:D.name}),D.content&&a.jsxs("div",{className:"mt-1 text-[var(--text-secondary)] truncate max-w-full",children:[D.content.substring(0,200),D.content.length>200&&"..."]})]},$))]})]})]}),a.jsx(O0,{spans:d,isLive:O})]}),g&&a.jsx("div",{className:"mt-3 p-3 bg-red-500/10 border border-red-500/20 rounded text-sm text-red-400",children:g}),Q&&o&&a.jsx("div",{className:"mt-3 flex items-center justify-end pt-3 border-t border-[var(--border)]",children:a.jsx(Ks,{to:`/tests/${o}`,children:a.jsx(K,{variant:"primary",iconRight:xg,children:"View Full Details"})})})]})]})}function R0(){const{agentId:e}=Ra(),t=Et(),n=Pn(),[r,s]=k.useState("overview"),{data:i,isLoading:l}=ve({queryKey:["configs",e],queryFn:()=>br.get(e),enabled:!!e}),{data:o=[]}=ve({queryKey:["tests",{agent_id:e}],queryFn:()=>Ns.list({agent_id:e}),enabled:!!e}),{data:u=[]}=ve({queryKey:["jobs"],queryFn:()=>_t.list()}),c=Ge({mutationFn:d=>br.delete(d),onSuccess:()=>{n.invalidateQueries({queryKey:["configs"]}),t("/agents")}}),m=u.filter(d=>d.candidate_ids.includes(e||""));return l?a.jsx("div",{className:"text-[var(--text-secondary)]",children:"Loading..."}):i?a.jsxs("div",{className:"h-full flex flex-col",children:[a.jsxs("div",{className:"mb-6",children:[a.jsx("div",{className:"flex items-center gap-3 mb-2",children:a.jsx("button",{onClick:()=>t("/agents"),className:"text-[var(--text-secondary)] hover:text-[var(--text-primary)]",children:"← Back to Agents"})}),a.jsxs("div",{className:"flex items-center justify-between",children:[a.jsxs("div",{className:"flex items-center gap-3",children:[a.jsx("h2",{className:"text-xl font-bold",children:i.name}),i.is_auto_generated&&a.jsx(q,{variant:"info",children:"Auto-generated"})]}),a.jsx("div",{className:"flex gap-2",children:a.jsx(K,{variant:"secondary",icon:_m,onClick:()=>{confirm(`Delete agent "${i.name}"?`)&&c.mutate(i.id)},children:"Delete"})})]}),i.description&&a.jsx("p",{className:"text-sm text-[var(--text-secondary)] mt-1",children:i.description})]}),a.jsxs("div",{className:"flex gap-1 mb-6 border-b border-[var(--border)]",children:[a.jsx(vl,{active:r==="overview",onClick:()=>s("overview"),icon:a.jsx(Cm,{size:16}),children:"Overview"}),a.jsx(vl,{active:r==="test",onClick:()=>s("test"),icon:a.jsx(Hs,{size:16}),children:"Test"}),a.jsx(vl,{active:r==="history",onClick:()=>s("history"),icon:a.jsx(jg,{size:16}),badge:o.length,children:"History"})]}),a.jsxs("div",{className:"flex-1 min-h-0",children:[r==="overview"&&a.jsx(M0,{agent:i,recentTests:o,jobs:m}),r==="test"&&a.jsx(L0,{agent:i}),r==="history"&&a.jsx(z0,{tests:o})]})]}):a.jsx("div",{className:"text-[var(--text-secondary)]",children:"Agent not found"})}function vl({active:e,onClick:t,icon:n,badge:r,children:s}){return a.jsxs("button",{onClick:t,className:`flex items-center gap-2 px-4 py-2 text-sm font-medium border-b-2 transition-colors ${e?"border-[var(--accent)] text-[var(--text-primary)]":"border-transparent text-[var(--text-secondary)] hover:text-[var(--text-primary)]"}`,children:[n,s,r!==void 0&&r>0&&a.jsx("span",{className:"ml-1 px-1.5 py-0.5 text-xs bg-[var(--bg-tertiary)] rounded",children:r})]})}function M0({agent:e,recentTests:t,jobs:n}){var l,o,u,c,m,d;const r=Et(),s=e.config,i=()=>{const h=s.tools;return typeof h=="string"?h:Array.isArray(h)?h.join(", "):typeof h=="object"?Object.keys(h).join(", "):"standard"};return a.jsxs("div",{className:"space-y-6",children:[a.jsxs(ne,{children:[a.jsx("h3",{className:"font-medium mb-4",children:"Configuration"}),a.jsxs("div",{className:"grid grid-cols-2 gap-4 text-sm",children:[a.jsxs("div",{children:[a.jsx("span",{className:"text-[var(--text-secondary)]",children:"Model:"}),a.jsx("div",{className:"font-mono",children:s.model||"default"})]}),a.jsxs("div",{children:[a.jsx("span",{className:"text-[var(--text-secondary)]",children:"Compaction:"}),a.jsx("div",{className:"font-mono",children:((l=s.compaction)==null?void 0:l.strategy)==="none"?"disabled":`${(o=s.compaction)==null?void 0:o.strategy} (${((c=(u=s.compaction)==null?void 0:u.params)==null?void 0:c.head_size)||0}/${((d=(m=s.compaction)==null?void 0:m.params)==null?void 0:d.tail_size)||0})`})]}),a.jsxs("div",{className:"col-span-2",children:[a.jsx("span",{className:"text-[var(--text-secondary)]",children:"Tools:"}),a.jsx("div",{className:"font-mono",children:i()})]}),s.instructions&&a.jsxs("div",{className:"col-span-2",children:[a.jsx("span",{className:"text-[var(--text-secondary)]",children:"Instructions:"}),a.jsx("pre",{className:"mt-1 p-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-xs whitespace-pre-wrap max-h-32 overflow-auto",children:s.instructions})]})]})]}),a.jsxs(ne,{children:[a.jsxs("div",{className:"flex items-center justify-between mb-4",children:[a.jsx("h3",{className:"font-medium",children:"Recent Tests"}),t.length>0&&a.jsxs("span",{className:"text-xs text-[var(--text-secondary)]",children:[t.length," total"]})]}),t.length===0?a.jsx("div",{className:"text-sm text-[var(--text-secondary)] text-center py-4",children:'No tests yet. Click the "Test" tab to run one.'}):a.jsx("div",{className:"space-y-2",children:t.slice(0,5).map(h=>a.jsxs(Ks,{to:`/tests/${h.id}`,className:"flex items-center justify-between p-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded hover:border-[var(--accent-dim)] transition-colors",children:[a.jsxs("div",{className:"flex items-center gap-2",children:[a.jsx(Am,{status:h.status}),a.jsxs("span",{className:"text-sm truncate max-w-[200px]",children:[h.prompt.slice(0,50),"..."]})]}),a.jsxs("div",{className:"flex items-center gap-3 text-xs text-[var(--text-secondary)]",children:[a.jsxs("span",{children:[h.duration_seconds.toFixed(1),"s"]}),a.jsxs("span",{children:[h.tokens_total," tok"]})]})]},h.id))})]}),a.jsxs(ne,{children:[a.jsxs("div",{className:"flex items-center justify-between mb-4",children:[a.jsx("h3",{className:"font-medium",children:"Optimization Jobs"}),a.jsx(K,{variant:"secondary",size:"sm",icon:Da,onClick:()=>r("/agents",{state:{optimizeAgent:e}}),children:"New Job"})]}),n.length===0?a.jsx("div",{className:"text-sm text-[var(--text-secondary)] text-center py-4",children:"No optimization jobs yet."}):a.jsx("div",{className:"space-y-2",children:n.slice(0,5).map(h=>a.jsxs(Ks,{to:`/jobs/${h.id}`,className:"flex items-center justify-between p-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded hover:border-[var(--accent-dim)] transition-colors",children:[a.jsxs("div",{className:"flex items-center gap-2",children:[a.jsx(q,{variant:h.status==="completed"?"success":h.status==="running"?"info":"default",children:h.status}),a.jsx("span",{className:"text-sm",children:h.name})]}),a.jsx("span",{className:"text-xs text-[var(--text-secondary)]",children:new Date(h.created_at).toLocaleDateString()})]},h.id))})]})]})}function z0({tests:e}){return e.length===0?a.jsx("div",{className:"text-center py-8 text-[var(--text-secondary)]",children:"No test history yet. Run a test to see results here."}):a.jsx("div",{className:"space-y-2",children:e.map(t=>a.jsxs(Ks,{to:`/tests/${t.id}`,className:"flex items-center justify-between p-3 bg-[var(--bg-secondary)] border border-[var(--border)] rounded hover:border-[var(--accent-dim)] transition-colors",children:[a.jsxs("div",{className:"flex-1 min-w-0",children:[a.jsxs("div",{className:"flex items-center gap-2 mb-1",children:[a.jsx(Am,{status:t.status}),t.score!==null&&a.jsxs("span",{className:`text-sm font-medium ${t.passed?"text-green-400":"text-red-400"}`,children:[(t.score*100).toFixed(0),"%"]})]}),a.jsx("p",{className:"text-sm truncate",children:t.prompt})]}),a.jsxs("div",{className:"flex flex-col items-end gap-1 ml-4",children:[a.jsx("span",{className:"text-xs text-[var(--text-secondary)]",children:new Date(t.created_at).toLocaleString()}),a.jsxs("div",{className:"flex items-center gap-2 text-xs text-[var(--text-secondary)]",children:[a.jsxs("span",{children:[t.duration_seconds.toFixed(1),"s"]}),a.jsx("span",{children:"•"}),a.jsxs("span",{children:[t.tokens_total," tokens"]})]})]})]},t.id))})}function Am({status:e}){const t={completed:"success",failed:"error",running:"info",cancelled:"warning",pending:"default"};return a.jsx(q,{variant:t[e]||"default",children:e})}const $m=zu(e=>({tasks:[],selectedTaskIds:[],setTasks:t=>e({tasks:t}),toggleTaskSelection:t=>e(n=>({selectedTaskIds:n.selectedTaskIds.includes(t)?n.selectedTaskIds.filter(r=>r!==t):[...n.selectedTaskIds,t]})),jobs:[],setJobs:t=>e({jobs:t})}));function F0(){const e=Pn(),[t,n]=k.useState(!1),[r,s]=k.useState(!1),[i,l]=k.useState(new Set(["custom"])),{selectedTaskIds:o,toggleTaskSelection:u,setTasks:c}=$m(),m=f=>{l(p=>{const j=new Set(p);return j.has(f)?j.delete(f):j.add(f),j})},{data:d=[],isLoading:h}=ve({queryKey:["tasks"],queryFn:()=>Dt.list()});k.useEffect(()=>{d.length>0&&c(d)},[d,c]);const x=Ge({mutationFn:Dt.create,onSuccess:()=>{e.invalidateQueries({queryKey:["tasks"]}),n(!1)}}),w=Ge({mutationFn:Dt.importSuite,onSuccess:()=>{e.invalidateQueries({queryKey:["tasks"]}),s(!1)}}),g=Ge({mutationFn:Dt.delete,onSuccess:()=>e.invalidateQueries({queryKey:["tasks"]})}),S=d.reduce((f,p)=>{const j=p.suite||"custom";return f[j]||(f[j]=[]),f[j].push(p),f},{}),v=Object.keys(S).sort((f,p)=>f==="custom"?-1:p==="custom"?1:f.localeCompare(p));return a.jsxs("div",{children:[a.jsxs("div",{className:"flex items-center justify-between mb-6",children:[a.jsxs("div",{children:[a.jsx("h2",{className:"text-xl font-bold",children:"Tasks"}),a.jsxs("p",{className:"text-sm text-[var(--text-secondary)] mt-1",children:["Define tasks to evaluate agent configurations.",o.length>0&&a.jsxs("span",{className:"ml-2 text-[var(--accent)]",children:[o.length," selected"]})]})]}),a.jsxs("div",{className:"flex gap-2",children:[a.jsx(K,{variant:"secondary",onClick:()=>s(!0),children:"Import Suite"}),a.jsx(K,{variant:"primary",onClick:()=>n(!0),children:"+ New Task"})]})]}),h?a.jsx("div",{className:"text-[var(--text-secondary)]",children:"Loading..."}):d.length===0?a.jsx("div",{className:"text-center py-12 text-[var(--text-secondary)]",children:"No tasks yet. Create one or import a built-in suite."}):a.jsx("div",{className:"space-y-4",children:v.map(f=>{const p=S[f],j=i.has(f),C=p.filter(N=>o.includes(N.id)).length;return a.jsxs("div",{children:[a.jsxs("button",{onClick:()=>m(f),className:"flex items-center gap-2 py-2 hover:text-[var(--accent)] transition-colors",children:[j?a.jsx(fg,{size:16,className:"text-[var(--text-secondary)]"}):a.jsx(Ss,{size:16,className:"text-[var(--text-secondary)]"}),a.jsx("h3",{className:"text-sm font-medium uppercase tracking-wide",children:f==="custom"?"Custom Tasks":`${f} Suite`}),a.jsx(q,{variant:f==="custom"?"default":"info",children:p.length}),C>0&&a.jsxs(q,{variant:"success",children:[C," selected"]})]}),j&&a.jsx("div",{className:"grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-3 mt-2",children:p.map(N=>a.jsx(ne,{selectable:!0,selected:o.includes(N.id),onClick:()=>u(N.id),children:a.jsxs("div",{className:"flex flex-col h-full",children:[a.jsxs("div",{className:"flex items-start justify-between gap-2",children:[a.jsxs("div",{className:"flex items-center gap-2 flex-wrap",children:[a.jsx("span",{className:"font-medium",children:N.name}),o.includes(N.id)&&a.jsx(q,{variant:"success",children:"Selected"}),N.category&&N.category!=="default"&&a.jsx(q,{variant:"default",children:N.category})]}),a.jsx(K,{variant:"ghost",size:"sm",onClick:b=>{b.stopPropagation(),confirm("Delete this task?")&&g.mutate(N.id)},children:"Delete"})]}),a.jsx("p",{className:"text-sm text-[var(--text-secondary)] mt-2 line-clamp-3 flex-1",children:N.prompt}),N.criteria.length>0&&a.jsx("div",{className:"flex gap-1 mt-2 flex-wrap",children:N.criteria.map(b=>a.jsx(q,{variant:"default",children:b.name},b.name))})]})},N.id))})]},f)})}),a.jsx(I0,{isOpen:t,onClose:()=>n(!1),onSubmit:f=>x.mutate(f),isLoading:x.isPending}),a.jsx(D0,{isOpen:r,onClose:()=>s(!1),onSubmit:f=>w.mutate(f),isLoading:w.isPending})]})}function I0({isOpen:e,onClose:t,onSubmit:n,isLoading:r}){const[s,i]=k.useState({name:"",prompt:"",criteria:[],category:"default"}),l=()=>{i({...s,criteria:[...s.criteria,{name:"",instruction:"",weight:1}]})},o=(m,d)=>{const h=[...s.criteria];h[m]={...h[m],...d},i({...s,criteria:h})},u=m=>{i({...s,criteria:s.criteria.filter((d,h)=>h!==m)})},c=m=>{m.preventDefault(),!(!s.name.trim()||!s.prompt.trim())&&n({...s,criteria:s.criteria.filter(d=>d.name.trim()&&d.instruction.trim())})};return a.jsx(ai,{isOpen:e,onClose:t,title:"Create Task",children:a.jsxs("form",{onSubmit:c,className:"space-y-4",children:[a.jsx(fn,{label:"Name",value:s.name,onChange:m=>i({...s,name:m.target.value}),placeholder:"e.g., fizzbuzz",required:!0}),a.jsx(y0,{label:"Prompt",value:s.prompt,onChange:m=>i({...s,prompt:m.target.value}),placeholder:"The task description for the agent...",required:!0}),a.jsx(fn,{label:"Category",value:s.category,onChange:m=>i({...s,category:m.target.value}),placeholder:"e.g., coding, research"}),a.jsxs("div",{children:[a.jsxs("div",{className:"flex items-center justify-between mb-2",children:[a.jsx("label",{className:"text-sm text-[var(--text-secondary)]",children:"Evaluation Criteria"}),a.jsx(K,{type:"button",variant:"ghost",size:"sm",onClick:l,children:"+ Add"})]}),a.jsx("div",{className:"space-y-2",children:s.criteria.map((m,d)=>a.jsxs("div",{className:"flex gap-2 items-start",children:[a.jsx(fn,{value:m.name,onChange:h=>o(d,{name:h.target.value}),placeholder:"Name",className:"w-32"}),a.jsx(fn,{value:m.instruction,onChange:h=>o(d,{instruction:h.target.value}),placeholder:"Instruction",className:"flex-1"}),a.jsx(K,{type:"button",variant:"ghost",size:"sm",onClick:()=>u(d),children:"×"})]},d))})]}),a.jsxs("div",{className:"flex justify-end gap-2 pt-4",children:[a.jsx(K,{type:"button",variant:"secondary",onClick:t,children:"Cancel"}),a.jsx(K,{type:"submit",variant:"primary",disabled:r||!s.name.trim()||!s.prompt.trim(),children:r?"Creating...":"Create"})]})]})})}function D0({isOpen:e,onClose:t,onSubmit:n,isLoading:r}){const[s,i]=k.useState(""),{data:l=[],isLoading:o}=ve({queryKey:["suites"],queryFn:()=>Dt.listSuites(),enabled:e});return k.useEffect(()=>{l.length>0&&!s&&i(l[0].name)},[l,s]),a.jsx(ai,{isOpen:e,onClose:t,title:"Import Task Suite",children:a.jsxs("div",{className:"space-y-4",children:[a.jsx("p",{className:"text-sm text-[var(--text-secondary)]",children:"Import a built-in task suite for evaluation."}),o?a.jsx("div",{className:"text-[var(--text-secondary)]",children:"Loading suites..."}):l.length===0?a.jsx("div",{className:"text-[var(--text-secondary)]",children:"No suites available."}):a.jsx("div",{className:"space-y-2 max-h-80 overflow-y-auto",children:l.map(u=>a.jsxs("label",{className:`flex items-center gap-3 p-3 border cursor-pointer ${s===u.name?"border-[var(--accent)] bg-[var(--accent)]/10":"border-[var(--border)] hover:border-[var(--accent-dim)]"}`,children:[a.jsx("input",{type:"radio",name:"suite",value:u.name,checked:s===u.name,onChange:()=>i(u.name),className:"accent-[var(--accent)]"}),a.jsxs("span",{className:"capitalize",children:[u.name.replace(/_/g," ")," (",u.task_count," tasks) - ",u.description]})]},u.name))}),a.jsxs("div",{className:"flex justify-end gap-2 pt-4",children:[a.jsx(K,{type:"button",variant:"secondary",onClick:t,children:"Cancel"}),a.jsx(K,{variant:"primary",onClick:()=>n(s),disabled:r||!s,children:r?"Importing...":"Import"})]})]})})}function A0(){const e=Et(),t=Pn(),[n,r]=k.useState(!1),{setJobs:s}=$m(),i=Au(),{data:l=[],isLoading:o}=ve({queryKey:["jobs",n],queryFn:()=>_t.list({include_public:n}),refetchInterval:5e3});k.useEffect(()=>{l.length>0&&s(l)},[l,s]);const u=Ge({mutationFn:_t.delete,onSuccess:()=>t.invalidateQueries({queryKey:["jobs"]})});return a.jsxs("div",{children:[a.jsxs("div",{className:"flex items-center justify-between mb-6",children:[a.jsxs("div",{children:[a.jsx("h2",{className:"text-xl font-bold",children:"Optimization Jobs"}),a.jsx("p",{className:"text-sm text-[var(--text-secondary)] mt-1",children:"View and manage optimization experiments. Start new jobs from the Agents page."})]}),a.jsxs("div",{className:"flex items-center gap-3",children:[a.jsxs("label",{className:"flex items-center gap-2 text-sm text-[var(--text-secondary)] cursor-pointer",children:[a.jsx("input",{type:"checkbox",checked:n,onChange:c=>r(c.target.checked),className:"rounded border-[var(--border)]"}),a.jsx(za,{className:"w-4 h-4"}),"Show public"]}),a.jsx(K,{variant:"secondary",onClick:()=>e("/agents"),children:"Go to Agents"})]})]}),o?a.jsx("div",{className:"text-[var(--text-secondary)]",children:"Loading..."}):l.length===0?a.jsx("div",{className:"text-center py-12 text-[var(--text-secondary)]",children:"No jobs yet. Go to Agents page to start an optimization."}):a.jsx("div",{className:"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4",children:l.map(c=>{const m=!c.user_id||c.user_id==="anonymous"||i&&c.created_by_name===i;return a.jsx(Fm,{job:c,onDelete:m?d=>u.mutate(d):void 0},c.id)})})]})}function $0(e,t=!0){return Math.abs(e)<10?"text-[var(--text-secondary)]":(t?e<0:e>0)?"text-green-400":"text-red-400"}function U0(e){return`${e>0?"+":""}${e.toFixed(1)}%`}function Um(e,t){return t===0?0:(e-t)/t*100}function os({label:e,values:t,baselineIndex:n,formatter:r,isLowerBetter:s=!0}){const i=t[n];return a.jsxs("tr",{className:"border-b border-[var(--border)] last:border-0",children:[a.jsx("td",{className:"py-2 pr-4 text-[var(--text-secondary)] text-sm",children:e}),t.map((l,o)=>{const u=Um(l,i),c=o===n;return a.jsxs("td",{className:"py-2 px-4 text-right",children:[a.jsx("div",{className:"font-mono",children:r(l)}),!c&&a.jsx("div",{className:`text-xs ${$0(u,s)}`,children:U0(u)}),c&&a.jsx("div",{className:"text-xs text-[var(--text-secondary)]",children:"(baseline)"})]},o)})]})}function B0({runs:e,baselineRunId:t}){const n=k.useMemo(()=>{if(t){const i=e.findIndex(l=>l.id===t);if(i>=0)return i}return 0},[e,t]);if(e.length<2)return null;const r=Math.min(...e.map(i=>i.tokens_total)),s=Math.max(...e.map(i=>i.score));return a.jsxs(ne,{className:"mb-6",children:[a.jsx("h3",{className:"font-medium mb-4",children:"Candidate Comparison"}),a.jsx("div",{className:"overflow-x-auto",children:a.jsxs("table",{className:"w-full text-sm",children:[a.jsx("thead",{children:a.jsxs("tr",{className:"border-b border-[var(--border)]",children:[a.jsx("th",{className:"pb-2 pr-4 text-left text-[var(--text-secondary)] font-medium",children:"Metric"}),e.map((i,l)=>a.jsx("th",{className:"pb-2 px-4 text-right",children:a.jsxs("div",{className:"flex items-center justify-end gap-2",children:[a.jsx("span",{className:"font-medium",children:i.candidate_name}),i.is_pareto&&a.jsx(q,{variant:"success",children:"Pareto"}),l===n&&a.jsx(q,{variant:"info",children:"Base"})]})},i.id))]})}),a.jsxs("tbody",{children:[a.jsx(os,{label:"Total Tokens",values:e.map(i=>i.tokens_total),baselineIndex:n,formatter:i=>i.toLocaleString(),isLowerBetter:!0}),a.jsx(os,{label:"Input Tokens",values:e.map(i=>i.tokens_input),baselineIndex:n,formatter:i=>i.toLocaleString(),isLowerBetter:!0}),a.jsx(os,{label:"Output Tokens",values:e.map(i=>i.tokens_output),baselineIndex:n,formatter:i=>i.toLocaleString(),isLowerBetter:!0}),a.jsx(os,{label:"Duration",values:e.map(i=>i.duration_seconds),baselineIndex:n,formatter:i=>`${i.toFixed(1)}s`,isLowerBetter:!0}),a.jsx(os,{label:"Score",values:e.map(i=>i.score*100),baselineIndex:n,formatter:i=>`${i.toFixed(1)}%`,isLowerBetter:!1})]})]})}),a.jsxs("div",{className:"mt-4 pt-4 border-t border-[var(--border)]",children:[a.jsx("h4",{className:"text-sm font-medium mb-2 text-[var(--text-secondary)]",children:"Key Insights"}),a.jsxs("ul",{className:"text-sm space-y-1 text-[var(--text-secondary)]",children:[e.map(i=>{const l=Um(i.tokens_total,e[n].tokens_total);return i.tokens_total===r&&l<-5?a.jsxs("li",{className:"flex items-center gap-2",children:[a.jsx("span",{className:"text-green-400",children:"✓"}),a.jsxs("span",{children:[a.jsx("strong",{children:i.candidate_name})," uses ",Math.abs(l).toFixed(0),"% fewer tokens"]})]},`token-${i.id}`):null}),e.map(i=>i.score===s&&i.passed?a.jsxs("li",{className:"flex items-center gap-2",children:[a.jsx("span",{className:"text-green-400",children:"✓"}),a.jsxs("span",{children:[a.jsx("strong",{children:i.candidate_name})," achieved highest score (",(i.score*100).toFixed(0),"%)"]})]},`score-${i.id}`):null),e.filter(i=>i.is_pareto).length>0&&a.jsxs("li",{className:"flex items-center gap-2",children:[a.jsx("span",{className:"text-purple-400",children:"★"}),a.jsxs("span",{children:["Pareto-optimal candidates:"," ",e.filter(i=>i.is_pareto).map(i=>i.candidate_name).join(", ")]})]})]})]}),a.jsxs("div",{className:"mt-4 pt-4 border-t border-[var(--border)]",children:[a.jsx("h4",{className:"text-sm font-medium mb-3 text-[var(--text-secondary)]",children:"Token Efficiency"}),a.jsx("div",{className:"space-y-2",children:e.map(i=>{const l=i.tokens_total/e[n].tokens_total*100,o=i.tokens_total<=r;return a.jsxs("div",{className:"flex items-center gap-3",children:[a.jsx("div",{className:"w-24 text-sm truncate",title:i.candidate_name,children:i.candidate_name}),a.jsx("div",{className:"flex-1 h-6 bg-[var(--bg-primary)] rounded overflow-hidden",children:a.jsx("div",{className:`h-full transition-all duration-300 ${o?"bg-green-500":"bg-blue-500"}`,style:{width:`${Math.min(l,100)}%`}})}),a.jsx("div",{className:"w-20 text-right font-mono text-sm",children:i.tokens_total.toLocaleString()})]},i.id)})})]})]})}function Q0({summaries:e,height:t=350}){const n=k.useRef(null),[r,s]=k.useState(600),[i,l]=k.useState("tokens"),[o,u]=k.useState(null),[c,m]=k.useState({x:0,y:0});k.useEffect(()=>{const N=()=>{n.current&&s(n.current.clientWidth)};return N(),window.addEventListener("resize",N),()=>window.removeEventListener("resize",N)},[]);const d={top:30,right:30,bottom:50,left:60},h=r-d.left-d.right,x=t-d.top-d.bottom,w=N=>i==="tokens"?N.avg_tokens:N.avg_duration,{xScale:g,yScale:S,xTicks:v,yTicks:f,paretoLine:p}=k.useMemo(()=>{if(e.length===0||h<=0)return{xScale:()=>0,yScale:()=>0,xTicks:[],yTicks:[],paretoLine:[]};const N=e.map(w),b=e.map(L=>L.avg_score),E=Math.min(...N)*.9,F=Math.max(...N)*1.1,O=Math.min(...b,.5),Q=Math.min(Math.max(...b)*1.05,1),D=L=>(L-E)/(F-E)*h,$=L=>x-(L-O)/(Q-O)*x,Z=Array.from({length:5},(L,A)=>E+A/4*(F-E)),me=Array.from({length:5},(L,A)=>O+A/4*(Q-O)),Ne=e.filter(L=>L.is_pareto).sort((L,A)=>w(L)-w(A)).map(L=>({x:D(w(L)),y:$(L.avg_score)}));return{xScale:D,yScale:$,xTicks:Z,yTicks:me,paretoLine:Ne}},[e,h,x,i]);if(e.length===0)return a.jsx("div",{className:"text-center py-8 text-[var(--text-secondary)]",children:"No data to display"});const j=N=>i==="tokens"?N>=1e6?`${(N/1e6).toFixed(1)}M`:N>=1e3?`${(N/1e3).toFixed(0)}K`:N.toFixed(0):`${N.toFixed(1)}s`,C=(N,b)=>{var F;const E=(F=n.current)==null?void 0:F.getBoundingClientRect();E&&m({x:b.clientX-E.left,y:b.clientY-E.top}),u(N)};return a.jsxs("div",{ref:n,className:"w-full relative",children:[a.jsx("div",{className:"flex justify-end mb-2",children:a.jsxs("div",{className:"inline-flex rounded border border-[var(--border)] text-xs",children:[a.jsx("button",{className:`px-3 py-1 ${i==="tokens"?"bg-[var(--accent)] text-black":"text-[var(--text-secondary)] hover:text-[var(--text-primary)]"}`,onClick:()=>l("tokens"),children:"Tokens"}),a.jsx("button",{className:`px-3 py-1 ${i==="duration"?"bg-[var(--accent)] text-black":"text-[var(--text-secondary)] hover:text-[var(--text-primary)]"}`,onClick:()=>l("duration"),children:"Latency"})]})}),a.jsx("svg",{width:r,height:t,className:"font-mono text-xs",children:a.jsxs("g",{transform:`translate(${d.left}, ${d.top})`,children:[v.map((N,b)=>a.jsx("line",{x1:g(N),y1:0,x2:g(N),y2:x,stroke:"var(--border)",strokeDasharray:"2,2"},`x-grid-${b}`)),f.map((N,b)=>a.jsx("line",{x1:0,y1:S(N),x2:h,y2:S(N),stroke:"var(--border)",strokeDasharray:"2,2"},`y-grid-${b}`)),p.length>1&&a.jsx("polyline",{points:p.map(N=>`${N.x},${N.y}`).join(" "),fill:"none",stroke:"var(--accent)",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"}),e.slice().sort((N,b)=>(N.is_pareto?1:0)-(b.is_pareto?1:0)).map(N=>{const b=g(w(N)),E=S(N.avg_score),F=N.is_pareto,O=(o==null?void 0:o.candidate_name)===N.candidate_name;return a.jsxs("g",{onMouseEnter:Q=>C(N,Q),onMouseLeave:()=>u(null),children:[a.jsx("circle",{cx:b,cy:E,r:O?10:F?8:6,fill:F?"var(--accent)":"transparent",stroke:O?"var(--text-primary)":F?"var(--accent)":"var(--text-secondary)",strokeWidth:O?3:2,className:"cursor-pointer transition-all"}),F&&!O&&a.jsx("text",{x:b,y:E-12,textAnchor:"middle",fill:"var(--text-primary)",fontSize:10,className:"pointer-events-none",children:N.candidate_name.replace(/^baseline_/,"").slice(0,15)})]},N.candidate_name)}),a.jsx("line",{x1:0,y1:x,x2:h,y2:x,stroke:"var(--text-secondary)"}),v.map((N,b)=>a.jsxs("g",{transform:`translate(${g(N)}, ${x})`,children:[a.jsx("line",{y2:5,stroke:"var(--text-secondary)"}),a.jsx("text",{y:20,textAnchor:"middle",fill:"var(--text-secondary)",fontSize:10,children:j(N)})]},`x-tick-${b}`)),a.jsx("text",{x:h/2,y:x+40,textAnchor:"middle",fill:"var(--text-secondary)",fontSize:11,children:i==="tokens"?"Tokens (cost)":"Duration (latency)"}),a.jsx("line",{x1:0,y1:0,x2:0,y2:x,stroke:"var(--text-secondary)"}),f.map((N,b)=>a.jsxs("g",{transform:`translate(0, ${S(N)})`,children:[a.jsx("line",{x2:-5,stroke:"var(--text-secondary)"}),a.jsxs("text",{x:-10,textAnchor:"end",dominantBaseline:"middle",fill:"var(--text-secondary)",fontSize:10,children:[(N*100).toFixed(0),"%"]})]},`y-tick-${b}`)),a.jsx("text",{transform:`translate(-45, ${x/2}) rotate(-90)`,textAnchor:"middle",fill:"var(--text-secondary)",fontSize:11,children:"Score (quality)"})]})}),o&&a.jsxs("div",{className:"absolute z-10 bg-[var(--bg-secondary)] border border-[var(--border)] rounded-lg shadow-lg p-3 text-sm pointer-events-none",style:{left:Math.min(c.x+15,r-200),top:c.y-10,maxWidth:220},children:[a.jsx("div",{className:"font-medium text-[var(--text-primary)] truncate mb-2",children:o.candidate_name.replace(/^baseline_/,"")}),a.jsxs("div",{className:"grid grid-cols-2 gap-x-4 gap-y-1 text-xs",children:[a.jsx("span",{className:"text-[var(--text-secondary)]",children:"Score:"}),a.jsxs("span",{className:"text-right font-medium",children:[(o.avg_score*100).toFixed(1),"%"]}),a.jsx("span",{className:"text-[var(--text-secondary)]",children:"Tokens:"}),a.jsxs("span",{className:"text-right",children:[(o.avg_tokens/1e3).toFixed(1),"K"]}),a.jsx("span",{className:"text-[var(--text-secondary)]",children:"Duration:"}),a.jsxs("span",{className:"text-right",children:[o.avg_duration.toFixed(1),"s"]}),a.jsx("span",{className:"text-[var(--text-secondary)]",children:"Pass rate:"}),a.jsxs("span",{className:"text-right",children:[o.passed_runs,"/",o.total_runs]})]}),o.is_pareto&&a.jsx("div",{className:"mt-2 pt-2 border-t border-[var(--border)] text-xs text-[var(--accent)]",children:"Pareto optimal"})]})]})}function V0(e=2e3){const[t,n]=k.useState(!1),[r,s]=k.useState(null),i=k.useCallback(async o=>{try{return await navigator.clipboard.writeText(o),n(!0),s(null),setTimeout(()=>n(!1),e),!0}catch{return s("Failed to copy to clipboard"),n(!1),!1}},[e]),l=k.useCallback(()=>{n(!1),s(null)},[]);return{copy:i,copied:t,error:r,reset:l}}function K0({isOpen:e,onClose:t,title:n,itemId:r,itemType:s,isPublic:i,createdByName:l,onTogglePublic:o}){const[u,c]=k.useState(!1),{copy:m,copied:d}=V0(),h=`${window.location.origin}/${s}s/${r}`,x=async()=>{c(!0);try{await o(!i)}finally{c(!1)}},w=()=>{m(h)};return a.jsx(ai,{isOpen:e,onClose:t,title:n,children:a.jsxs("div",{className:"space-y-4",children:[a.jsxs("div",{className:"flex items-center justify-between p-3 bg-[var(--bg-tertiary)] rounded",children:[a.jsxs("div",{className:"flex items-center gap-3",children:[i?a.jsx(za,{className:"w-5 h-5 text-[var(--accent)]"}):a.jsx(bm,{className:"w-5 h-5 text-[var(--text-secondary)]"}),a.jsxs("div",{children:[a.jsx("div",{className:"font-medium",children:i?"Public":"Private"}),a.jsx("div",{className:"text-sm text-[var(--text-secondary)]",children:i?"Anyone with the link can view":"Only you can access"})]})]}),a.jsx("button",{onClick:x,disabled:u,className:`relative inline-flex h-6 w-11 items-center rounded-full transition-colors ${i?"bg-[var(--accent)]":"bg-[var(--border)]"} ${u?"opacity-50 cursor-not-allowed":""}`,children:a.jsx("span",{className:`inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${i?"translate-x-6":"translate-x-1"}`})})]}),i&&a.jsxs("div",{className:"space-y-2",children:[a.jsx("label",{className:"text-sm text-[var(--text-secondary)]",children:"Share link"}),a.jsxs("div",{className:"flex gap-2",children:[a.jsx("input",{type:"text",readOnly:!0,value:h,className:"flex-1 px-3 py-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm font-mono"}),a.jsx(K,{variant:"secondary",onClick:w,children:d?a.jsxs(a.Fragment,{children:[a.jsx(dg,{className:"w-4 h-4 mr-1"}),"Copied"]}):a.jsxs(a.Fragment,{children:[a.jsx(vg,{className:"w-4 h-4 mr-1"}),"Copy"]})})]})]}),l&&a.jsxs("div",{className:"text-sm text-[var(--text-secondary)]",children:["Created by ",a.jsx("span",{className:"text-[var(--text-primary)]",children:l})]}),a.jsx("div",{className:"text-xs text-[var(--text-secondary)] pt-2 border-t border-[var(--border)]",children:i?a.jsxs(a.Fragment,{children:[a.jsxs("p",{children:["Public ",s,"s can be viewed by anyone with the link."]}),a.jsxs("p",{className:"mt-1",children:["Only you can edit or delete this ",s,"."]})]}):a.jsxs("p",{children:["Make this ",s," public to share it with others."]})})]})})}function H0({job:e,onUpdate:t}){const[n,r]=k.useState(!1),s=async i=>{await _t.update(e.id,{is_public:i}),t()};return a.jsxs(a.Fragment,{children:[a.jsxs(K,{variant:"secondary",size:"sm",onClick:()=>r(!0),title:e.is_public?"Sharing settings":"Share this job",children:[a.jsx(bg,{className:"w-4 h-4 mr-1"}),e.is_public?"Shared":"Share"]}),a.jsx(K0,{isOpen:n,onClose:()=>r(!1),title:"Share Job",itemId:e.id,itemType:"job",isPublic:e.is_public,createdByName:e.created_by_name,onTogglePublic:s})]})}function W0(){const{jobId:e}=Ra(),t=Et(),n=Pn(),[r,s]=k.useState(null),[i,l]=k.useState(!1),[o,u]=k.useState(null),[c,m]=k.useState([]),[d,h]=k.useState(null),[x,w]=k.useState(null),[g,S]=k.useState("results"),[v,f]=k.useState("score"),[p,j]=k.useState("desc"),[C,N]=k.useState(!1),{data:b,isLoading:E}=ve({queryKey:["jobs",e],queryFn:()=>_t.get(e),enabled:!!e,refetchInterval:i?2e3:!1}),{data:F=[]}=ve({queryKey:["runs",e],queryFn:()=>To.list({job_id:e}),enabled:!!e,refetchInterval:i?2e3:!1}),{data:O}=ve({queryKey:["job-summary",e],queryFn:()=>To.getJobSummary(e),enabled:!!e&&(b==null?void 0:b.status)==="completed"}),Q=Ge({mutationFn:async()=>{l(!0),m([]),h(null),w(null);for await(const P of _t.start(e))s(P),P.current_candidate&&P.current_task&&h(_=>(_&&(_.candidate!==P.current_candidate||_.task!==P.current_task)&&m(B=>[...B,{candidate_name:_.candidate,task_name:_.task,completed_at:Date.now()}]),{candidate:P.current_candidate,task:P.current_task})),P.event==="error"&&(w(P.message),l(!1),n.invalidateQueries({queryKey:["jobs",e]})),P.event==="complete"&&(h(_=>(_&&m(B=>[...B,{candidate_name:_.candidate,task_name:_.task,completed_at:Date.now()}]),null)),l(!1),n.invalidateQueries({queryKey:["jobs",e]}),n.invalidateQueries({queryKey:["runs",e]}),n.invalidateQueries({queryKey:["job-summary",e]}))}}),D=Ge({mutationFn:()=>_t.cancel(e),onSuccess:()=>{l(!1),n.invalidateQueries({queryKey:["jobs",e]})}});k.useEffect(()=>{(b==null?void 0:b.status)==="running"&&l(!0)},[b==null?void 0:b.status]);const $=k.useMemo(()=>{const P=new Map;for(const _ of F)P.has(_.task_name)||P.set(_.task_name,[]),P.get(_.task_name).push(_);return P},[F]),Z=k.useMemo(()=>Array.from($.keys()),[$]),me=k.useMemo(()=>{if(!(O!=null&&O.candidate_summaries))return[];let P=[...O.candidate_summaries];return C&&(P=P.filter(_=>_.is_pareto)),P.sort((_,B)=>{let re,be;switch(v){case"score":re=_.avg_score,be=B.avg_score;break;case"tokens":re=_.avg_tokens,be=B.avg_tokens;break;case"duration":re=_.avg_duration,be=B.avg_duration;break;case"pass_rate":re=_.passed_runs/_.total_runs,be=B.passed_runs/B.total_runs;break}return p==="desc"?be-re:re-be}),P},[O,v,p,C]),et=P=>{v===P?j(p==="desc"?"asc":"desc"):(f(P),j(P==="tokens"||P==="duration"?"asc":"desc"))},Ne=({label:P,sortKeyVal:_})=>a.jsx("th",{className:"pb-2 cursor-pointer hover:text-[var(--text-primary)] select-none",onClick:()=>et(_),children:a.jsxs("div",{className:"flex items-center gap-1",children:[P,v===_&&a.jsx(og,{size:12,className:p==="asc"?"rotate-180":""})]})});if(E)return a.jsx("div",{className:"text-[var(--text-secondary)]",children:"Loading..."});if(!b)return a.jsx("div",{className:"text-[var(--text-secondary)]",children:"Job not found"});const L=Au(),A=!b.user_id||b.user_id==="anonymous"||L&&b.created_by_name===L,R=b.is_public&&!A,H=()=>{n.invalidateQueries({queryKey:["jobs",e]})},M=P=>{const _={pending:"default",running:"info",completed:"success",failed:"error",cancelled:"warning"};return a.jsx(q,{variant:_[P]||"default",children:P})};return a.jsxs("div",{children:[a.jsxs("div",{className:"flex items-center justify-between mb-6",children:[a.jsxs("div",{children:[a.jsxs("div",{className:"flex items-center gap-3",children:[a.jsx("button",{onClick:()=>t("/jobs"),className:"text-[var(--text-secondary)] hover:text-[var(--text-primary)]",children:"← Jobs"}),a.jsx("h2",{className:"text-xl font-bold",children:b.name||`Job ${b.id.slice(0,8)}`}),M(b.status),b.is_public&&a.jsxs(q,{variant:"info",children:[a.jsx(za,{className:"w-3 h-3 mr-1 inline"}),"Public"]})]}),a.jsxs("div",{className:"flex items-center gap-3 mt-1",children:[a.jsxs("code",{className:"text-xs bg-[var(--bg-primary)] px-2 py-0.5 rounded font-mono text-[var(--text-secondary)]",children:[b.id.slice(0,8),"..."]}),a.jsxs("span",{className:"text-sm text-[var(--text-secondary)]",children:[b.candidate_ids.length," candidates × ",b.task_ids.length," tasks = ",b.total_experiments," experiments"]}),b.is_public&&b.created_by_name&&a.jsxs("span",{className:"text-sm text-[var(--text-secondary)]",children:["Created by ",a.jsx("span",{className:"text-[var(--text-primary)]",children:b.created_by_name})]})]})]}),a.jsxs("div",{className:"flex gap-2",children:[A&&a.jsx(H0,{job:b,onUpdate:H}),R&&a.jsx(q,{variant:"default",children:"View Only"}),A&&b.status==="pending"&&a.jsx(K,{variant:"primary",onClick:()=>Q.mutate(),disabled:Q.isPending,children:Q.isPending?"Starting...":"Start"}),A&&b.status==="running"&&a.jsx(K,{variant:"danger",onClick:()=>D.mutate(),disabled:D.isPending,children:"Cancel"})]})]}),(x||b.error)&&a.jsx(ne,{className:"mb-6 border-red-500/50 bg-red-500/10",children:a.jsxs("div",{className:"flex items-start gap-3",children:[a.jsx("div",{className:"w-5 h-5 rounded-full bg-red-500 flex items-center justify-center text-white text-xs font-bold flex-shrink-0 mt-0.5",children:"!"}),a.jsxs("div",{children:[a.jsx("h3",{className:"font-medium text-red-400",children:"Error"}),a.jsx("p",{className:"text-sm text-[var(--text-secondary)] mt-1",children:x||b.error})]})]})}),(i||r)&&a.jsxs(ne,{className:"mb-6",children:[a.jsxs("div",{className:"flex items-center justify-between mb-2",children:[a.jsx("span",{className:"font-medium",children:"Progress"}),a.jsxs("span",{className:"text-[var(--accent)]",children:[(r==null?void 0:r.completed)||b.completed_experiments,"/",(r==null?void 0:r.total)||b.total_experiments]})]}),a.jsx("div",{className:"w-full bg-[var(--bg-primary)] h-2 mb-2",children:a.jsx("div",{className:"h-full bg-[var(--accent)] transition-all",style:{width:`${((r==null?void 0:r.completed)||b.completed_experiments)/((r==null?void 0:r.total)||b.total_experiments)*100}%`}})}),(r==null?void 0:r.message)&&a.jsx("p",{className:"text-sm text-[var(--text-secondary)]",children:r.message}),i&&a.jsxs("div",{className:"mt-4 border-t border-[var(--border)] pt-4",children:[(r==null?void 0:r.current_candidate)&&(r==null?void 0:r.current_task)&&a.jsxs("div",{className:"mb-3",children:[a.jsx("span",{className:"text-xs text-[var(--text-secondary)] uppercase tracking-wider",children:"Currently Running"}),a.jsxs("div",{className:"flex items-center gap-2 mt-1 px-3 py-2 bg-blue-500/10 border border-blue-500/30 rounded",children:[a.jsx("div",{className:"w-2 h-2 bg-blue-400 rounded-full animate-pulse"}),a.jsx("span",{className:"font-medium",children:r.current_candidate}),a.jsx("span",{className:"text-[var(--text-secondary)]",children:"→"}),a.jsx("span",{children:r.current_task})]})]}),c.length>0&&a.jsxs("div",{children:[a.jsxs("span",{className:"text-xs text-[var(--text-secondary)] uppercase tracking-wider",children:["Completed (",c.length,")"]}),a.jsx("div",{className:"mt-1 max-h-40 overflow-y-auto space-y-1",children:c.map((P,_)=>a.jsxs("div",{className:"flex items-center gap-2 px-3 py-1.5 bg-green-500/10 border border-green-500/30 rounded text-sm",children:[a.jsx("div",{className:"w-2 h-2 bg-green-400 rounded-full"}),a.jsx("span",{className:"font-medium",children:P.candidate_name}),a.jsx("span",{className:"text-[var(--text-secondary)]",children:"→"}),a.jsx("span",{children:P.task_name})]},`${P.candidate_name}-${P.task_name}-${_}`))})]})]})]}),(b.status==="completed"||F.length>0)&&a.jsxs("div",{className:"flex gap-1 mb-6 border-b border-[var(--border)]",children:[a.jsxs("button",{onClick:()=>S("results"),className:`flex items-center gap-2 px-4 py-2 text-sm font-medium border-b-2 transition-colors ${g==="results"?"border-[var(--accent)] text-[var(--accent)]":"border-transparent text-[var(--text-secondary)] hover:text-[var(--text-primary)]"}`,children:[a.jsx(ug,{size:16}),"Results"]}),a.jsxs("button",{onClick:()=>S("compare"),className:`flex items-center gap-2 px-4 py-2 text-sm font-medium border-b-2 transition-colors ${g==="compare"?"border-[var(--accent)] text-[var(--accent)]":"border-transparent text-[var(--text-secondary)] hover:text-[var(--text-primary)]"}`,children:[a.jsx(yg,{size:16}),"Compare"]}),a.jsxs("button",{onClick:()=>S("runs"),className:`flex items-center gap-2 px-4 py-2 text-sm font-medium border-b-2 transition-colors ${g==="runs"?"border-[var(--accent)] text-[var(--accent)]":"border-transparent text-[var(--text-secondary)] hover:text-[var(--text-primary)]"}`,children:[a.jsx(kg,{size:16}),"Runs (",F.length,")"]})]}),g==="results"&&a.jsxs(a.Fragment,{children:[O&&O.candidate_summaries.length>1&&a.jsxs(ne,{className:"mb-6",children:[a.jsx("div",{className:"flex items-start justify-between mb-4",children:a.jsxs("div",{children:[a.jsx("h3",{className:"font-medium",children:"Pareto Frontier"}),a.jsxs("p",{className:"text-sm text-[var(--text-secondary)] mt-1",children:["Candidates on the frontier (connected line) are ",a.jsx("strong",{children:"Pareto optimal"})," - no other candidate beats them on both score AND cost."]})]})}),a.jsxs("div",{className:"mb-4 p-3 bg-[var(--bg-primary)] rounded border border-[var(--border)] text-xs text-[var(--text-secondary)]",children:[a.jsx("strong",{className:"text-[var(--text-primary)]",children:"How Pareto optimal is calculated:"})," A candidate is Pareto optimal if there's no other candidate that has both a higher score AND lower cost. For example, if Candidate A has 95% score at 50K tokens and Candidate B has 90% score at 40K tokens, both are Pareto optimal - A is better on score, B is better on cost. But if Candidate C has 85% score at 60K tokens, it's ",a.jsx("em",{children:"not"})," Pareto optimal because B beats it on both metrics."]}),a.jsx(Q0,{summaries:O.candidate_summaries,height:350})]}),O&&a.jsxs(ne,{className:"mb-6",children:[a.jsxs("div",{className:"flex items-center justify-between mb-4",children:[a.jsx("h3",{className:"font-medium",children:"Results Summary"}),a.jsxs("label",{className:"flex items-center gap-2 text-sm text-[var(--text-secondary)] cursor-pointer",children:[a.jsx("input",{type:"checkbox",checked:C,onChange:P=>N(P.target.checked),className:"rounded border-[var(--border)]"}),"Pareto only"]})]}),a.jsx("div",{className:"overflow-x-auto",children:a.jsxs("table",{className:"w-full text-sm",children:[a.jsx("thead",{children:a.jsxs("tr",{className:"text-left text-[var(--text-secondary)] border-b border-[var(--border)]",children:[a.jsx("th",{className:"pb-2",children:"Candidate"}),a.jsx(Ne,{label:"Score",sortKeyVal:"score"}),a.jsx(Ne,{label:"Tokens",sortKeyVal:"tokens"}),a.jsx(Ne,{label:"Duration",sortKeyVal:"duration"}),a.jsx(Ne,{label:"Pass Rate",sortKeyVal:"pass_rate"}),a.jsx("th",{className:"pb-2",children:"Pareto"})]})}),a.jsx("tbody",{children:me.map((P,_)=>a.jsxs("tr",{className:`border-b border-[var(--border)] ${_===0?"bg-[var(--accent)]/10":""}`,children:[a.jsxs("td",{className:"py-2 font-medium",children:[_===0&&a.jsx("span",{className:"text-[var(--accent)] mr-1",children:"#1"}),P.candidate_name.replace(/^baseline_/,"")]}),a.jsxs("td",{className:"py-2",children:[(P.avg_score*100).toFixed(1),"%"]}),a.jsxs("td",{className:"py-2",children:[(P.avg_tokens/1e3).toFixed(1),"K"]}),a.jsxs("td",{className:"py-2",children:[P.avg_duration.toFixed(1),"s"]}),a.jsxs("td",{className:"py-2",children:[P.passed_runs,"/",P.total_runs]}),a.jsx("td",{className:"py-2",children:P.is_pareto&&a.jsx(q,{variant:"success",children:"Pareto"})})]},P.candidate_name))})]})}),a.jsx("p",{className:"text-xs text-[var(--text-secondary)] mt-3",children:"Click column headers to sort. The #1 ranked candidate is highlighted based on your sort criteria."})]}),!O&&a.jsx(ne,{children:a.jsx("div",{className:"text-center py-8 text-[var(--text-secondary)]",children:i?"Results will appear here after the job completes.":"No results yet. Start the job to see results."})})]}),g==="compare"&&a.jsxs(ne,{children:[a.jsx("h3",{className:"font-medium mb-4",children:"Compare Candidates by Task"}),Z.length>0?a.jsxs(a.Fragment,{children:[a.jsx("div",{className:"flex flex-wrap gap-2 mb-4",children:Z.map(P=>a.jsx("button",{onClick:()=>u(o===P?null:P),className:`px-3 py-1 text-sm rounded border transition-colors ${o===P?"bg-[var(--accent)] text-white border-[var(--accent)]":"border-[var(--border)] hover:border-[var(--accent-dim)]"}`,children:P},P))}),o&&$.get(o)?a.jsx(B0,{runs:$.get(o).map(P=>({id:P.id,candidate_name:P.candidate_name,tokens_input:0,tokens_output:0,tokens_total:P.tokens_total,duration_seconds:P.duration_seconds,score:P.score,passed:P.passed,is_pareto:P.is_pareto}))}):a.jsx("div",{className:"text-center py-8 text-[var(--text-secondary)]",children:"Select a task above to compare how different candidates performed on it."})]}):a.jsx("div",{className:"text-center py-8 text-[var(--text-secondary)]",children:i?"Comparison data will appear here after runs complete.":"No runs yet. Start the job to compare candidates."})]}),g==="runs"&&a.jsxs(ne,{children:[a.jsx("h3",{className:"font-medium mb-4",children:"All Experiment Runs"}),F.length===0?a.jsx("div",{className:"text-center py-8 text-[var(--text-secondary)]",children:i?"Runs will appear here as they complete. See progress above for live status.":"No runs yet. Start the job to see results."}):a.jsx("div",{className:"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-3",children:F.map(P=>a.jsxs("div",{className:"p-3 bg-[var(--bg-primary)] rounded border border-[var(--border)] cursor-pointer hover:border-[var(--accent-dim)] transition-colors",onClick:()=>t(`/runs/${P.id}`),children:[a.jsxs("div",{className:"flex items-center justify-between mb-2",children:[a.jsxs("span",{className:`text-lg font-bold ${P.passed?"text-green-400":"text-red-400"}`,children:[(P.score*100).toFixed(0),"%"]}),P.is_pareto&&a.jsx(q,{variant:"success",children:"Pareto"})]}),a.jsx("div",{className:"text-sm font-medium truncate",title:P.candidate_name,children:P.candidate_name.replace(/^baseline_/,"")}),a.jsx("div",{className:"text-xs text-[var(--text-secondary)] truncate",children:P.task_name}),a.jsxs("div",{className:"flex items-center gap-3 mt-2 text-xs text-[var(--text-secondary)]",children:[a.jsxs("span",{children:[(P.tokens_total/1e3).toFixed(1),"K tokens"]}),a.jsxs("span",{children:[P.duration_seconds.toFixed(1),"s"]})]})]},P.id))})]})]})}const hn={input:"bg-blue-500",output:"bg-emerald-500",inputText:"text-blue-400",outputText:"text-emerald-400"};function Cd(e){return e>=1e3?`${(e/1e3).toFixed(1)}k`:String(e)}function _d({input:e,output:t,maxValue:n,height:r=24,showLabels:s=!0}){const i=e+t;if(i===0)return a.jsx("div",{className:"flex items-center gap-2 w-full",children:a.jsx("div",{className:"rounded bg-[var(--bg-primary)] flex-1",style:{height:`${r}px`}})});const l=n>0?i/n*100:100;return a.jsxs("div",{className:"flex items-center gap-3 w-full",children:[a.jsx("div",{className:"relative rounded overflow-hidden bg-[var(--bg-primary)] flex-1",style:{height:`${r}px`},children:a.jsxs("div",{className:"h-full flex transition-all duration-300",style:{width:`${l}%`},children:[a.jsx("div",{className:`h-full ${hn.input} transition-all`,style:{width:`${e/i*100}%`},title:`Input: ${e.toLocaleString()} tokens`}),a.jsx("div",{className:`h-full ${hn.output} transition-all`,style:{width:`${t/i*100}%`},title:`Output: ${t.toLocaleString()} tokens`})]})}),s&&a.jsxs("div",{className:"flex items-center gap-1 text-xs font-mono text-[var(--text-secondary)] min-w-[90px] justify-end",children:[a.jsxs("span",{className:hn.inputText,children:["↑",Cd(e)]}),a.jsx("span",{children:"/"}),a.jsxs("span",{className:hn.outputText,children:["↓",Cd(t)]})]})]})}function xl({label:e,value:t,color:n="default"}){const r={default:"text-[var(--text-primary)]",input:hn.inputText,output:hn.outputText}[n];return a.jsxs("div",{className:"flex-1 p-3 bg-[var(--bg-primary)] border border-[var(--border)] rounded",children:[a.jsx("div",{className:"text-xs text-[var(--text-secondary)] mb-1",children:e}),a.jsx("div",{className:`font-mono text-lg font-bold ${r}`,children:t})]})}function Bm({tokensInput:e,tokensOutput:t,tokensTotal:n,turns:r}){const s=n>0?Math.round(e/n*100):0,i=n>0?Math.round(t/n*100):0,l=k.useMemo(()=>{if(!r||r.length===0)return null;let u=0,c=0;return r.map(m=>(u+=m.input,c+=m.output,{input:u,output:c,total:u+c}))},[r]),o=l?Math.max(...l.map(u=>u.total)):n;return a.jsxs(ne,{className:"mb-6",children:[a.jsx("h3",{className:"font-medium mb-4",children:"Token Usage"}),a.jsx("div",{className:"mb-4",children:a.jsx(_d,{input:e,output:t,maxValue:n,height:32})}),a.jsxs("div",{className:"flex items-center gap-6 text-xs mb-4",children:[a.jsxs("div",{className:"flex items-center gap-2",children:[a.jsx("div",{className:`w-3 h-3 rounded ${hn.input}`}),a.jsxs("span",{className:"text-[var(--text-secondary)]",children:["Input (",s,"%)"]})]}),a.jsxs("div",{className:"flex items-center gap-2",children:[a.jsx("div",{className:`w-3 h-3 rounded ${hn.output}`}),a.jsxs("span",{className:"text-[var(--text-secondary)]",children:["Output (",i,"%)"]})]})]}),a.jsxs("div",{className:"flex gap-3 mb-4",children:[a.jsx(xl,{label:"Input Tokens",value:e.toLocaleString(),color:"input"}),a.jsx(xl,{label:"Output Tokens",value:t.toLocaleString(),color:"output"}),a.jsx(xl,{label:"Total Tokens",value:n.toLocaleString()})]}),l&&l.length>1&&a.jsxs("div",{className:"border-t border-[var(--border)] pt-4",children:[a.jsxs("h4",{className:"text-sm font-medium mb-3 text-[var(--text-secondary)]",children:["Token Accumulation (",r.length," turns)"]}),a.jsx("div",{className:"space-y-2",children:r.map((u,c)=>a.jsxs("div",{className:"flex items-center gap-3",children:[a.jsx("div",{className:"w-6 h-6 rounded-full bg-[var(--bg-primary)] border border-[var(--border)] flex items-center justify-center text-xs font-medium",children:c+1}),a.jsx("div",{className:"flex-1",children:a.jsx(_d,{input:l[c].input,output:l[c].output,maxValue:o,height:16})})]},c))})]}),a.jsx("div",{className:"mt-4 text-xs text-[var(--text-secondary)] border-t border-[var(--border)] pt-3",children:"Token usage affects API cost. Input tokens are typically cheaper than output tokens."})]})}function q0(){const{runId:e}=Ra(),t=Et(),{data:n,isLoading:r}=ve({queryKey:["runs",e],queryFn:()=>To.get(e),enabled:!!e});return r?a.jsx("div",{className:"text-[var(--text-secondary)]",children:"Loading..."}):n?a.jsxs("div",{children:[a.jsxs("div",{className:"mb-6",children:[a.jsx("div",{className:"flex items-center gap-3 mb-2",children:a.jsx("button",{onClick:()=>t(`/jobs/${n.job_id}`),className:"text-[var(--text-secondary)] hover:text-[var(--text-primary)]",children:"← Back to Job"})}),a.jsxs("div",{className:"flex items-center gap-3",children:[a.jsx("h2",{className:"text-xl font-bold",children:n.candidate_name}),a.jsx("span",{className:"text-[var(--text-secondary)]",children:"→"}),a.jsx("span",{className:"text-lg",children:n.task_name}),n.is_pareto&&a.jsx(q,{variant:"success",children:"Pareto Optimal"})]})]}),a.jsxs("div",{className:"grid grid-cols-4 gap-4 mb-6",children:[a.jsx(Ci,{label:"Score",value:`${(n.score*100).toFixed(1)}%`,status:n.passed?"success":"error"}),a.jsx(Ci,{label:"Total Tokens",value:n.tokens_total.toLocaleString()}),a.jsx(Ci,{label:"Duration",value:`${n.duration_seconds.toFixed(1)}s`}),a.jsx(Ci,{label:"Status",value:n.passed?"Passed":"Failed",status:n.passed?"success":"error"})]}),a.jsx(Bm,{tokensInput:n.tokens_input,tokensOutput:n.tokens_output,tokensTotal:n.tokens_total}),a.jsxs(ne,{className:"mb-6",children:[a.jsx("h3",{className:"font-medium mb-3",children:"Evaluation"}),n.reasoning&&a.jsx("p",{className:"text-sm text-[var(--text-secondary)] mb-4",children:n.reasoning}),n.criteria_results.length>0&&a.jsx("div",{className:"space-y-2",children:n.criteria_results.map(s=>a.jsx("div",{className:"flex items-start justify-between p-3 bg-[var(--bg-primary)] border border-[var(--border)]",children:a.jsxs("div",{className:"flex-1",children:[a.jsxs("div",{className:"flex items-center gap-2",children:[a.jsx("span",{className:"font-medium",children:s.name}),a.jsxs(q,{variant:s.passed?"success":"error",children:[(s.score*100).toFixed(0),"%"]})]}),s.reasoning&&a.jsx("p",{className:"text-sm text-[var(--text-secondary)] mt-1",children:s.reasoning})]})},s.name))})]}),a.jsxs(ne,{className:"mb-6",children:[a.jsx("h3",{className:"font-medium mb-3",children:"Agent Output"}),a.jsx("pre",{className:"text-sm bg-[var(--bg-primary)] p-3 overflow-x-auto whitespace-pre-wrap border border-[var(--border)]",children:n.output||"(no output)"})]}),n.files_created.length>0&&a.jsxs(ne,{className:"mb-6",children:[a.jsx("h3",{className:"font-medium mb-3",children:"Files Created"}),a.jsx("div",{className:"space-y-1",children:n.files_created.map(s=>a.jsx("div",{className:"text-sm font-mono text-[var(--text-secondary)]",children:s},s))})]}),Object.keys(n.trace).length>0&&a.jsx(Dm,{trace:n.trace})]}):a.jsx("div",{className:"text-[var(--text-secondary)]",children:"Run not found"})}function Ci({label:e,value:t,status:n}){const r={success:"text-green-400",error:"text-red-400"};return a.jsxs(ne,{children:[a.jsx("div",{className:"text-sm text-[var(--text-secondary)]",children:e}),a.jsx("div",{className:`text-xl font-bold ${n?r[n]:""}`,children:t})]})}function J0(){const{testId:e}=Ra(),t=Et(),{data:n,isLoading:r}=ve({queryKey:["tests",e],queryFn:()=>Ns.get(e),enabled:!!e}),{data:s}=ve({queryKey:["configs",n==null?void 0:n.agent_id],queryFn:()=>br.get(n.agent_id),enabled:!!(n!=null&&n.agent_id)});if(r)return a.jsx("div",{className:"text-[var(--text-secondary)]",children:"Loading..."});if(!n)return a.jsx("div",{className:"text-[var(--text-secondary)]",children:"Test not found"});const i={completed:"success",failed:"error",running:"info",pending:"default",cancelled:"warning"};return a.jsxs("div",{children:[a.jsxs("div",{className:"mb-6",children:[a.jsx("div",{className:"flex items-center gap-3 mb-2",children:a.jsx("button",{onClick:()=>t("/agents"),className:"text-[var(--text-secondary)] hover:text-[var(--text-primary)]",children:"← Back to Agents"})}),a.jsxs("div",{className:"flex items-center gap-3",children:[a.jsx("h2",{className:"text-xl font-bold",children:"Test Run"}),s&&a.jsxs(a.Fragment,{children:[a.jsx("span",{className:"text-[var(--text-secondary)]",children:"•"}),a.jsx("span",{className:"text-lg",children:s.name})]}),a.jsx(q,{variant:i[n.status]||"default",children:n.status})]}),a.jsxs("p",{className:"text-sm text-[var(--text-secondary)] mt-1 font-mono",children:["ID: ",n.id.slice(0,8),"..."]})]}),a.jsxs("div",{className:"grid grid-cols-4 gap-4 mb-6",children:[a.jsx(_i,{label:"Duration",value:`${n.duration_seconds.toFixed(2)}s`}),a.jsx(_i,{label:"Total Tokens",value:n.tokens_total.toLocaleString()}),n.score!==null&&a.jsx(_i,{label:"Score",value:`${(n.score*100).toFixed(1)}%`,status:n.passed?"success":"error"}),a.jsx(_i,{label:"Status",value:n.status.charAt(0).toUpperCase()+n.status.slice(1),status:n.status==="completed"?"success":n.status==="failed"?"error":void 0})]}),a.jsx(Bm,{tokensInput:n.tokens_input,tokensOutput:n.tokens_output,tokensTotal:n.tokens_total}),a.jsxs(ne,{className:"mb-6",children:[a.jsx("h3",{className:"font-medium mb-3",children:"Prompt"}),a.jsx("pre",{className:"text-sm bg-[var(--bg-primary)] p-3 overflow-x-auto whitespace-pre-wrap border border-[var(--border)] font-mono",children:n.prompt})]}),n.error&&a.jsxs(ne,{className:"mb-6 border-red-500/30 bg-red-500/5",children:[a.jsx("h3",{className:"font-medium mb-3 text-red-400",children:"Error"}),a.jsx("pre",{className:"text-sm text-red-300 overflow-x-auto whitespace-pre-wrap",children:n.error})]}),n.reasoning&&a.jsxs(ne,{className:"mb-6",children:[a.jsx("h3",{className:"font-medium mb-3",children:"Evaluation"}),a.jsx("p",{className:"text-sm text-[var(--text-secondary)]",children:n.reasoning})]}),a.jsxs(ne,{className:"mb-6",children:[a.jsx("h3",{className:"font-medium mb-3",children:"Agent Output"}),a.jsx("pre",{className:"text-sm bg-[var(--bg-primary)] p-3 overflow-x-auto whitespace-pre-wrap border border-[var(--border)]",children:n.output||"(no output)"})]}),n.files_created&&n.files_created.length>0&&a.jsxs(ne,{className:"mb-6",children:[a.jsx("h3",{className:"font-medium mb-3",children:"Files Created"}),a.jsx("div",{className:"space-y-1",children:n.files_created.map(l=>a.jsx("div",{className:"text-sm font-mono text-[var(--text-secondary)]",children:l},l))})]}),n.trace&&Object.keys(n.trace).length>0&&a.jsx(Dm,{trace:n.trace}),a.jsxs(ne,{className:"mb-6",children:[a.jsx("h3",{className:"font-medium mb-3",children:"Timestamps"}),a.jsxs("div",{className:"grid grid-cols-3 gap-4 text-sm",children:[a.jsxs("div",{children:[a.jsx("span",{className:"text-[var(--text-secondary)]",children:"Created:"}),a.jsx("div",{className:"font-mono",children:new Date(n.created_at).toLocaleString()})]}),n.started_at&&a.jsxs("div",{children:[a.jsx("span",{className:"text-[var(--text-secondary)]",children:"Started:"}),a.jsx("div",{className:"font-mono",children:new Date(n.started_at).toLocaleString()})]}),n.completed_at&&a.jsxs("div",{children:[a.jsx("span",{className:"text-[var(--text-secondary)]",children:"Completed:"}),a.jsx("div",{className:"font-mono",children:new Date(n.completed_at).toLocaleString()})]})]})]})]})}function _i({label:e,value:t,status:n}){const r={success:"text-green-400",error:"text-red-400"};return a.jsxs(ne,{children:[a.jsx("div",{className:"text-sm text-[var(--text-secondary)]",children:e}),a.jsx("div",{className:`text-xl font-bold ${n?r[n]:""}`,children:t})]})}function G0(){const{authConfig:e,isLoading:t,error:n,login:r,loginWithGitHub:s,clearError:i}=$u(),[l,o]=k.useState(""),[u,c]=k.useState("");k.useEffect(()=>{n&&i()},[l,u]);const m=async h=>{h.preventDefault(),!(!l||!u)&&await r(l,u)},d=()=>{s()};return a.jsx("div",{className:"min-h-screen bg-[var(--bg-primary)] flex items-center justify-center p-4",children:a.jsxs("div",{className:"w-full max-w-md",children:[a.jsxs("div",{className:"text-center mb-8",children:[a.jsx("h1",{className:"text-2xl font-bold text-[var(--text-primary)] mb-2",children:"Flow"}),a.jsx("p",{className:"text-[var(--text-secondary)]",children:"Sign in to access the optimization dashboard"})]}),a.jsxs("div",{className:"bg-[var(--bg-secondary)] border border-[var(--border)] p-6 space-y-6",children:[n&&a.jsxs("div",{className:"flex items-start gap-3 p-3 bg-[var(--error)]/10 border border-[var(--error)]/20 text-[var(--error)]",children:[a.jsx(Sm,{size:18,className:"mt-0.5 flex-shrink-0"}),a.jsx("p",{className:"text-sm",children:n})]}),(e==null?void 0:e.mode)==="basic"&&a.jsxs("form",{onSubmit:m,className:"space-y-4",children:[a.jsxs("div",{className:"space-y-1",children:[a.jsx("label",{className:"block text-sm text-[var(--text-secondary)]",children:"Username"}),a.jsxs("div",{className:"relative",children:[a.jsx(Em,{size:16,className:"absolute left-3 top-1/2 -translate-y-1/2 text-[var(--text-tertiary)]"}),a.jsx("input",{type:"text",value:l,onChange:h=>o(h.target.value),className:"w-full bg-[var(--bg-primary)] border border-[var(--border)] pl-10 pr-3 py-2 text-sm focus:outline-none focus:border-[var(--accent)]",placeholder:"Enter username",autoComplete:"username",autoFocus:!0})]})]}),a.jsxs("div",{className:"space-y-1",children:[a.jsx("label",{className:"block text-sm text-[var(--text-secondary)]",children:"Password"}),a.jsxs("div",{className:"relative",children:[a.jsx(bm,{size:16,className:"absolute left-3 top-1/2 -translate-y-1/2 text-[var(--text-tertiary)]"}),a.jsx("input",{type:"password",value:u,onChange:h=>c(h.target.value),className:"w-full bg-[var(--bg-primary)] border border-[var(--border)] pl-10 pr-3 py-2 text-sm focus:outline-none focus:border-[var(--accent)]",placeholder:"Enter password",autoComplete:"current-password"})]})]}),a.jsx(K,{type:"submit",variant:"primary",className:"w-full justify-center",loading:t,disabled:!l||!u,children:"Sign In"})]}),(e==null?void 0:e.mode)==="github"&&a.jsxs("div",{className:"space-y-4",children:[a.jsx("p",{className:"text-sm text-[var(--text-secondary)] text-center",children:"Sign in with your GitHub account to continue"}),a.jsx(K,{onClick:d,variant:"secondary",className:"w-full justify-center",icon:gg,children:"Continue with GitHub"})]})]})]})})}function Y0({children:e}){const{authConfig:t,isLoadingConfig:n,isAuthenticated:r,loadAuthConfig:s,handleOAuthCallback:i}=$u();return k.useEffect(()=>{s()},[s]),k.useEffect(()=>{n||i()},[n,i]),n?a.jsx("div",{className:"min-h-screen bg-[var(--bg-primary)] flex items-center justify-center",children:a.jsxs("div",{className:"text-center",children:[a.jsx(Fa,{className:"w-8 h-8 animate-spin text-[var(--accent)] mx-auto mb-4"}),a.jsx("p",{className:"text-[var(--text-secondary)]",children:"Loading..."})]})}):t!=null&&t.enabled&&!r?a.jsx(G0,{}):a.jsx(a.Fragment,{children:e})}function X0(){return a.jsx(eg,{children:a.jsx(Y0,{children:a.jsx(Hy,{children:a.jsxs(gt,{path:"/",element:a.jsx(h0,{}),children:[a.jsx(gt,{index:!0,element:a.jsx(bd,{})}),a.jsx(gt,{path:"agents",element:a.jsx(bd,{})}),a.jsx(gt,{path:"agents/:agentId",element:a.jsx(R0,{})}),a.jsx(gt,{path:"tasks",element:a.jsx(F0,{})}),a.jsx(gt,{path:"jobs",element:a.jsx(A0,{})}),a.jsx(gt,{path:"jobs/:jobId",element:a.jsx(W0,{})}),a.jsx(gt,{path:"runs/:runId",element:a.jsx(q0,{})}),a.jsx(gt,{path:"tests/:testId",element:a.jsx(J0,{})})]})})})})}const Ed=localStorage.getItem("flow-theme");if(Ed)try{const{state:e}=JSON.parse(Ed);e!=null&&e.theme&&document.documentElement.setAttribute("data-theme",e.theme)}catch{}const Z0=new Ux({defaultOptions:{queries:{staleTime:5e3,refetchOnWindowFocus:!1}}});yl.createRoot(document.getElementById("root")).render(a.jsx(Do.StrictMode,{children:a.jsx(Bx,{client:Z0,children:a.jsx(X0,{})})})); diff --git a/src/flow/ui/ui/assets/index-Bk6M5bbz.js b/src/flow/ui/ui/assets/index-Bk6M5bbz.js new file mode 100644 index 0000000000000000000000000000000000000000..45f6f56bc31b547b4700a1f8d74fec964d2d1c50 --- /dev/null +++ b/src/flow/ui/ui/assets/index-Bk6M5bbz.js @@ -0,0 +1,270 @@ +var qu=e=>{throw TypeError(e)};var Ki=(e,t,n)=>t.has(e)||qu("Cannot "+n);var y=(e,t,n)=>(Ki(e,t,"read from private field"),n?n.call(e):t.get(e)),$=(e,t,n)=>t.has(e)?qu("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(e):t.set(e,n),z=(e,t,n,r)=>(Ki(e,t,"write to private field"),r?r.call(e,n):t.set(e,n),n),W=(e,t,n)=>(Ki(e,t,"access private method"),n);var da=(e,t,n,r)=>({set _(s){z(e,t,s,n)},get _(){return y(e,t,r)}});function Wm(e,t){for(var n=0;nr[s]})}}}return Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const s of document.querySelectorAll('link[rel="modulepreload"]'))r(s);new MutationObserver(s=>{for(const a of s)if(a.type==="childList")for(const l of a.addedNodes)l.tagName==="LINK"&&l.rel==="modulepreload"&&r(l)}).observe(document,{childList:!0,subtree:!0});function n(s){const a={};return s.integrity&&(a.integrity=s.integrity),s.referrerPolicy&&(a.referrerPolicy=s.referrerPolicy),s.crossOrigin==="use-credentials"?a.credentials="include":s.crossOrigin==="anonymous"?a.credentials="omit":a.credentials="same-origin",a}function r(s){if(s.ep)return;s.ep=!0;const a=n(s);fetch(s.href,a)}})();function Vd(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var Kd={exports:{}},ji={},Hd={exports:{}},q={};/** + * @license React + * react.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var sa=Symbol.for("react.element"),qm=Symbol.for("react.portal"),Jm=Symbol.for("react.fragment"),Gm=Symbol.for("react.strict_mode"),Ym=Symbol.for("react.profiler"),Xm=Symbol.for("react.provider"),Zm=Symbol.for("react.context"),ep=Symbol.for("react.forward_ref"),tp=Symbol.for("react.suspense"),np=Symbol.for("react.memo"),rp=Symbol.for("react.lazy"),Ju=Symbol.iterator;function sp(e){return e===null||typeof e!="object"?null:(e=Ju&&e[Ju]||e["@@iterator"],typeof e=="function"?e:null)}var Wd={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},qd=Object.assign,Jd={};function Gr(e,t,n){this.props=e,this.context=t,this.refs=Jd,this.updater=n||Wd}Gr.prototype.isReactComponent={};Gr.prototype.setState=function(e,t){if(typeof e!="object"&&typeof e!="function"&&e!=null)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")};Gr.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")};function Gd(){}Gd.prototype=Gr.prototype;function Ao(e,t,n){this.props=e,this.context=t,this.refs=Jd,this.updater=n||Wd}var $o=Ao.prototype=new Gd;$o.constructor=Ao;qd($o,Gr.prototype);$o.isPureReactComponent=!0;var Gu=Array.isArray,Yd=Object.prototype.hasOwnProperty,Uo={current:null},Xd={key:!0,ref:!0,__self:!0,__source:!0};function Zd(e,t,n){var r,s={},a=null,l=null;if(t!=null)for(r in t.ref!==void 0&&(l=t.ref),t.key!==void 0&&(a=""+t.key),t)Yd.call(t,r)&&!Xd.hasOwnProperty(r)&&(s[r]=t[r]);var o=arguments.length-2;if(o===1)s.children=n;else if(1>>1,X=T[K];if(0>>1;Ks(Z,L))hes(Ne,Z)?(T[K]=Ne,T[he]=L,K=he):(T[K]=Z,T[O]=L,K=O);else if(hes(Ne,L))T[K]=Ne,T[he]=L,K=he;else break e}}return A}function s(T,A){var L=T.sortIndex-A.sortIndex;return L!==0?L:T.id-A.id}if(typeof performance=="object"&&typeof performance.now=="function"){var a=performance;e.unstable_now=function(){return a.now()}}else{var l=Date,o=l.now();e.unstable_now=function(){return l.now()-o}}var u=[],c=[],h=1,d=null,m=3,x=!1,k=!1,g=!1,j=typeof setTimeout=="function"?setTimeout:null,p=typeof clearTimeout=="function"?clearTimeout:null,f=typeof setImmediate<"u"?setImmediate:null;typeof navigator<"u"&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function v(T){for(var A=n(c);A!==null;){if(A.callback===null)r(c);else if(A.startTime<=T)r(c),A.sortIndex=A.expirationTime,t(u,A);else break;A=n(c)}}function w(T){if(g=!1,v(T),!k)if(n(u)!==null)k=!0,Ge(C);else{var A=n(c);A!==null&&ie(w,A.startTime-T)}}function C(T,A){k=!1,g&&(g=!1,p(_),_=-1),x=!0;var L=m;try{for(v(A),d=n(u);d!==null&&(!(d.expirationTime>A)||T&&!B());){var K=d.callback;if(typeof K=="function"){d.callback=null,m=d.priorityLevel;var X=K(d.expirationTime<=A);A=e.unstable_now(),typeof X=="function"?d.callback=X:d===n(u)&&r(u),v(A)}else r(u);d=n(u)}if(d!==null)var R=!0;else{var O=n(c);O!==null&&ie(w,O.startTime-A),R=!1}return R}finally{d=null,m=L,x=!1}}var b=!1,N=null,_=-1,F=5,P=-1;function B(){return!(e.unstable_now()-PT||125K?(T.sortIndex=L,t(c,T),n(u)===null&&T===n(c)&&(g?(p(_),_=-1):g=!0,ie(w,L-K))):(T.sortIndex=X,t(u,T),k||x||(k=!0,Ge(C))),T},e.unstable_shouldYield=B,e.unstable_wrapCallback=function(T){var A=m;return function(){var L=m;m=A;try{return T.apply(this,arguments)}finally{m=L}}}})(sf);rf.exports=sf;var vp=rf.exports;/** + * @license React + * react-dom.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var xp=S,et=vp;function E(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),Sl=Object.prototype.hasOwnProperty,yp=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,Xu={},Zu={};function gp(e){return Sl.call(Zu,e)?!0:Sl.call(Xu,e)?!1:yp.test(e)?Zu[e]=!0:(Xu[e]=!0,!1)}function jp(e,t,n,r){if(n!==null&&n.type===0)return!1;switch(typeof t){case"function":case"symbol":return!0;case"boolean":return r?!1:n!==null?!n.acceptsBooleans:(e=e.toLowerCase().slice(0,5),e!=="data-"&&e!=="aria-");default:return!1}}function wp(e,t,n,r){if(t===null||typeof t>"u"||jp(e,t,n,r))return!0;if(r)return!1;if(n!==null)switch(n.type){case 3:return!t;case 4:return t===!1;case 5:return isNaN(t);case 6:return isNaN(t)||1>t}return!1}function Ue(e,t,n,r,s,a,l){this.acceptsBooleans=t===2||t===3||t===4,this.attributeName=r,this.attributeNamespace=s,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=a,this.removeEmptyString=l}var Te={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(e){Te[e]=new Ue(e,0,!1,e,null,!1,!1)});[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(e){var t=e[0];Te[t]=new Ue(t,1,!1,e[1],null,!1,!1)});["contentEditable","draggable","spellCheck","value"].forEach(function(e){Te[e]=new Ue(e,2,!1,e.toLowerCase(),null,!1,!1)});["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(e){Te[e]=new Ue(e,2,!1,e,null,!1,!1)});"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(e){Te[e]=new Ue(e,3,!1,e.toLowerCase(),null,!1,!1)});["checked","multiple","muted","selected"].forEach(function(e){Te[e]=new Ue(e,3,!0,e,null,!1,!1)});["capture","download"].forEach(function(e){Te[e]=new Ue(e,4,!1,e,null,!1,!1)});["cols","rows","size","span"].forEach(function(e){Te[e]=new Ue(e,6,!1,e,null,!1,!1)});["rowSpan","start"].forEach(function(e){Te[e]=new Ue(e,5,!1,e.toLowerCase(),null,!1,!1)});var Vo=/[\-:]([a-z])/g;function Ko(e){return e[1].toUpperCase()}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(e){var t=e.replace(Vo,Ko);Te[t]=new Ue(t,1,!1,e,null,!1,!1)});"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(e){var t=e.replace(Vo,Ko);Te[t]=new Ue(t,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)});["xml:base","xml:lang","xml:space"].forEach(function(e){var t=e.replace(Vo,Ko);Te[t]=new Ue(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)});["tabIndex","crossOrigin"].forEach(function(e){Te[e]=new Ue(e,1,!1,e.toLowerCase(),null,!1,!1)});Te.xlinkHref=new Ue("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1);["src","href","action","formAction"].forEach(function(e){Te[e]=new Ue(e,1,!1,e.toLowerCase(),null,!0,!0)});function Ho(e,t,n,r){var s=Te.hasOwnProperty(t)?Te[t]:null;(s!==null?s.type!==0:r||!(2o||s[l]!==a[o]){var u=` +`+s[l].replace(" at new "," at ");return e.displayName&&u.includes("")&&(u=u.replace("",e.displayName)),u}while(1<=l&&0<=o);break}}}finally{qi=!1,Error.prepareStackTrace=n}return(e=e?e.displayName||e.name:"")?ms(e):""}function kp(e){switch(e.tag){case 5:return ms(e.type);case 16:return ms("Lazy");case 13:return ms("Suspense");case 19:return ms("SuspenseList");case 0:case 2:case 15:return e=Ji(e.type,!1),e;case 11:return e=Ji(e.type.render,!1),e;case 1:return e=Ji(e.type,!0),e;default:return""}}function _l(e){if(e==null)return null;if(typeof e=="function")return e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case dr:return"Fragment";case cr:return"Portal";case Nl:return"Profiler";case Wo:return"StrictMode";case bl:return"Suspense";case Cl:return"SuspenseList"}if(typeof e=="object")switch(e.$$typeof){case of:return(e.displayName||"Context")+".Consumer";case lf:return(e._context.displayName||"Context")+".Provider";case qo:var t=e.render;return e=e.displayName,e||(e=t.displayName||t.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case Jo:return t=e.displayName||null,t!==null?t:_l(e.type)||"Memo";case Zt:t=e._payload,e=e._init;try{return _l(e(t))}catch{}}return null}function Sp(e){var t=e.type;switch(e.tag){case 24:return"Cache";case 9:return(t.displayName||"Context")+".Consumer";case 10:return(t._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return e=t.render,e=e.displayName||e.name||"",t.displayName||(e!==""?"ForwardRef("+e+")":"ForwardRef");case 7:return"Fragment";case 5:return t;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return _l(t);case 8:return t===Wo?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if(typeof t=="function")return t.displayName||t.name||null;if(typeof t=="string")return t}return null}function En(e){switch(typeof e){case"boolean":case"number":case"string":case"undefined":return e;case"object":return e;default:return""}}function cf(e){var t=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(t==="checkbox"||t==="radio")}function Np(e){var t=cf(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),r=""+e[t];if(!e.hasOwnProperty(t)&&typeof n<"u"&&typeof n.get=="function"&&typeof n.set=="function"){var s=n.get,a=n.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return s.call(this)},set:function(l){r=""+l,a.call(this,l)}}),Object.defineProperty(e,t,{enumerable:n.enumerable}),{getValue:function(){return r},setValue:function(l){r=""+l},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}function ma(e){e._valueTracker||(e._valueTracker=Np(e))}function df(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),r="";return e&&(r=cf(e)?e.checked?"true":"false":e.value),e=r,e!==n?(t.setValue(e),!0):!1}function Ka(e){if(e=e||(typeof document<"u"?document:void 0),typeof e>"u")return null;try{return e.activeElement||e.body}catch{return e.body}}function El(e,t){var n=t.checked;return fe({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:n??e._wrapperState.initialChecked})}function tc(e,t){var n=t.defaultValue==null?"":t.defaultValue,r=t.checked!=null?t.checked:t.defaultChecked;n=En(t.value!=null?t.value:n),e._wrapperState={initialChecked:r,initialValue:n,controlled:t.type==="checkbox"||t.type==="radio"?t.checked!=null:t.value!=null}}function ff(e,t){t=t.checked,t!=null&&Ho(e,"checked",t,!1)}function Pl(e,t){ff(e,t);var n=En(t.value),r=t.type;if(n!=null)r==="number"?(n===0&&e.value===""||e.value!=n)&&(e.value=""+n):e.value!==""+n&&(e.value=""+n);else if(r==="submit"||r==="reset"){e.removeAttribute("value");return}t.hasOwnProperty("value")?Tl(e,t.type,n):t.hasOwnProperty("defaultValue")&&Tl(e,t.type,En(t.defaultValue)),t.checked==null&&t.defaultChecked!=null&&(e.defaultChecked=!!t.defaultChecked)}function nc(e,t,n){if(t.hasOwnProperty("value")||t.hasOwnProperty("defaultValue")){var r=t.type;if(!(r!=="submit"&&r!=="reset"||t.value!==void 0&&t.value!==null))return;t=""+e._wrapperState.initialValue,n||t===e.value||(e.value=t),e.defaultValue=t}n=e.name,n!==""&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,n!==""&&(e.name=n)}function Tl(e,t,n){(t!=="number"||Ka(e.ownerDocument)!==e)&&(n==null?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+n&&(e.defaultValue=""+n))}var ps=Array.isArray;function kr(e,t,n,r){if(e=e.options,t){t={};for(var s=0;s"+t.valueOf().toString()+"",t=pa.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}});function Ts(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&n.nodeType===3){n.nodeValue=t;return}}e.textContent=t}var gs={animationIterationCount:!0,aspectRatio:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},bp=["Webkit","ms","Moz","O"];Object.keys(gs).forEach(function(e){bp.forEach(function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),gs[t]=gs[e]})});function vf(e,t,n){return t==null||typeof t=="boolean"||t===""?"":n||typeof t!="number"||t===0||gs.hasOwnProperty(e)&&gs[e]?(""+t).trim():t+"px"}function xf(e,t){e=e.style;for(var n in t)if(t.hasOwnProperty(n)){var r=n.indexOf("--")===0,s=vf(n,t[n],r);n==="float"&&(n="cssFloat"),r?e.setProperty(n,s):e[n]=s}}var Cp=fe({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function Rl(e,t){if(t){if(Cp[e]&&(t.children!=null||t.dangerouslySetInnerHTML!=null))throw Error(E(137,e));if(t.dangerouslySetInnerHTML!=null){if(t.children!=null)throw Error(E(60));if(typeof t.dangerouslySetInnerHTML!="object"||!("__html"in t.dangerouslySetInnerHTML))throw Error(E(61))}if(t.style!=null&&typeof t.style!="object")throw Error(E(62))}}function Ml(e,t){if(e.indexOf("-")===-1)return typeof t.is=="string";switch(e){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}var zl=null;function Go(e){return e=e.target||e.srcElement||window,e.correspondingUseElement&&(e=e.correspondingUseElement),e.nodeType===3?e.parentNode:e}var Fl=null,Sr=null,Nr=null;function ac(e){if(e=la(e)){if(typeof Fl!="function")throw Error(E(280));var t=e.stateNode;t&&(t=bi(t),Fl(e.stateNode,e.type,t))}}function yf(e){Sr?Nr?Nr.push(e):Nr=[e]:Sr=e}function gf(){if(Sr){var e=Sr,t=Nr;if(Nr=Sr=null,ac(e),t)for(e=0;e>>=0,e===0?32:31-(Ip(e)/Dp|0)|0}var va=64,xa=4194304;function vs(e){switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return e&4194240;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return e&130023424;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 1073741824;default:return e}}function Ja(e,t){var n=e.pendingLanes;if(n===0)return 0;var r=0,s=e.suspendedLanes,a=e.pingedLanes,l=n&268435455;if(l!==0){var o=l&~s;o!==0?r=vs(o):(a&=l,a!==0&&(r=vs(a)))}else l=n&~s,l!==0?r=vs(l):a!==0&&(r=vs(a));if(r===0)return 0;if(t!==0&&t!==r&&!(t&s)&&(s=r&-r,a=t&-t,s>=a||s===16&&(a&4194240)!==0))return t;if(r&4&&(r|=n&16),t=e.entangledLanes,t!==0)for(e=e.entanglements,t&=r;0n;n++)t.push(e);return t}function aa(e,t,n){e.pendingLanes|=t,t!==536870912&&(e.suspendedLanes=0,e.pingedLanes=0),e=e.eventTimes,t=31-yt(t),e[t]=n}function Bp(e,t){var n=e.pendingLanes&~t;e.pendingLanes=t,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=t,e.mutableReadLanes&=t,e.entangledLanes&=t,t=e.entanglements;var r=e.eventTimes;for(e=e.expirationTimes;0=ws),mc=" ",pc=!1;function Af(e,t){switch(e){case"keyup":return vv.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function $f(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var fr=!1;function yv(e,t){switch(e){case"compositionend":return $f(t);case"keypress":return t.which!==32?null:(pc=!0,mc);case"textInput":return e=t.data,e===mc&&pc?null:e;default:return null}}function gv(e,t){if(fr)return e==="compositionend"||!su&&Af(e,t)?(e=If(),za=tu=hn=null,fr=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:n,offset:t-e};e=r}e:{for(;n;){if(n.nextSibling){n=n.nextSibling;break e}n=n.parentNode}n=void 0}n=gc(n)}}function Vf(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?Vf(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function Kf(){for(var e=window,t=Ka();t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href=="string"}catch{n=!1}if(n)e=t.contentWindow;else break;t=Ka(e.document)}return t}function au(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}function Ev(e){var t=Kf(),n=e.focusedElem,r=e.selectionRange;if(t!==n&&n&&n.ownerDocument&&Vf(n.ownerDocument.documentElement,n)){if(r!==null&&au(n)){if(t=r.start,e=r.end,e===void 0&&(e=t),"selectionStart"in n)n.selectionStart=t,n.selectionEnd=Math.min(e,n.value.length);else if(e=(t=n.ownerDocument||document)&&t.defaultView||window,e.getSelection){e=e.getSelection();var s=n.textContent.length,a=Math.min(r.start,s);r=r.end===void 0?a:Math.min(r.end,s),!e.extend&&a>r&&(s=r,r=a,a=s),s=jc(n,a);var l=jc(n,r);s&&l&&(e.rangeCount!==1||e.anchorNode!==s.node||e.anchorOffset!==s.offset||e.focusNode!==l.node||e.focusOffset!==l.offset)&&(t=t.createRange(),t.setStart(s.node,s.offset),e.removeAllRanges(),a>r?(e.addRange(t),e.extend(l.node,l.offset)):(t.setEnd(l.node,l.offset),e.addRange(t)))}}for(t=[],e=n;e=e.parentNode;)e.nodeType===1&&t.push({element:e,left:e.scrollLeft,top:e.scrollTop});for(typeof n.focus=="function"&&n.focus(),n=0;n=document.documentMode,hr=null,Bl=null,Ss=null,Ql=!1;function wc(e,t,n){var r=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;Ql||hr==null||hr!==Ka(r)||(r=hr,"selectionStart"in r&&au(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),Ss&&Fs(Ss,r)||(Ss=r,r=Xa(Bl,"onSelect"),0vr||(e.current=Jl[vr],Jl[vr]=null,vr--)}function ae(e,t){vr++,Jl[vr]=e.current,e.current=t}var Pn={},ze=On(Pn),He=On(!1),Xn=Pn;function Br(e,t){var n=e.type.contextTypes;if(!n)return Pn;var r=e.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===t)return r.__reactInternalMemoizedMaskedChildContext;var s={},a;for(a in n)s[a]=t[a];return r&&(e=e.stateNode,e.__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=s),s}function We(e){return e=e.childContextTypes,e!=null}function ei(){oe(He),oe(ze)}function Ec(e,t,n){if(ze.current!==Pn)throw Error(E(168));ae(ze,t),ae(He,n)}function eh(e,t,n){var r=e.stateNode;if(t=t.childContextTypes,typeof r.getChildContext!="function")return n;r=r.getChildContext();for(var s in r)if(!(s in t))throw Error(E(108,Sp(e)||"Unknown",s));return fe({},n,r)}function ti(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||Pn,Xn=ze.current,ae(ze,e),ae(He,He.current),!0}function Pc(e,t,n){var r=e.stateNode;if(!r)throw Error(E(169));n?(e=eh(e,t,Xn),r.__reactInternalMemoizedMergedChildContext=e,oe(He),oe(ze),ae(ze,e)):oe(He),ae(He,n)}var zt=null,Ci=!1,ul=!1;function th(e){zt===null?zt=[e]:zt.push(e)}function $v(e){Ci=!0,th(e)}function Ln(){if(!ul&&zt!==null){ul=!0;var e=0,t=re;try{var n=zt;for(re=1;e>=l,s-=l,$t=1<<32-yt(t)+s|n<_?(F=N,N=null):F=N.sibling;var P=m(p,N,v[_],w);if(P===null){N===null&&(N=F);break}e&&N&&P.alternate===null&&t(p,N),f=a(P,f,_),b===null?C=P:b.sibling=P,b=P,N=F}if(_===v.length)return n(p,N),ue&&Mn(p,_),C;if(N===null){for(;__?(F=N,N=null):F=N.sibling;var B=m(p,N,P.value,w);if(B===null){N===null&&(N=F);break}e&&N&&B.alternate===null&&t(p,N),f=a(B,f,_),b===null?C=B:b.sibling=B,b=B,N=F}if(P.done)return n(p,N),ue&&Mn(p,_),C;if(N===null){for(;!P.done;_++,P=v.next())P=d(p,P.value,w),P!==null&&(f=a(P,f,_),b===null?C=P:b.sibling=P,b=P);return ue&&Mn(p,_),C}for(N=r(p,N);!P.done;_++,P=v.next())P=x(N,p,_,P.value,w),P!==null&&(e&&P.alternate!==null&&N.delete(P.key===null?_:P.key),f=a(P,f,_),b===null?C=P:b.sibling=P,b=P);return e&&N.forEach(function(D){return t(p,D)}),ue&&Mn(p,_),C}function j(p,f,v,w){if(typeof v=="object"&&v!==null&&v.type===dr&&v.key===null&&(v=v.props.children),typeof v=="object"&&v!==null){switch(v.$$typeof){case ha:e:{for(var C=v.key,b=f;b!==null;){if(b.key===C){if(C=v.type,C===dr){if(b.tag===7){n(p,b.sibling),f=s(b,v.props.children),f.return=p,p=f;break e}}else if(b.elementType===C||typeof C=="object"&&C!==null&&C.$$typeof===Zt&&Lc(C)===b.type){n(p,b.sibling),f=s(b,v.props),f.ref=cs(p,b,v),f.return=p,p=f;break e}n(p,b);break}else t(p,b);b=b.sibling}v.type===dr?(f=Gn(v.props.children,p.mode,w,v.key),f.return=p,p=f):(w=Qa(v.type,v.key,v.props,null,p.mode,w),w.ref=cs(p,f,v),w.return=p,p=w)}return l(p);case cr:e:{for(b=v.key;f!==null;){if(f.key===b)if(f.tag===4&&f.stateNode.containerInfo===v.containerInfo&&f.stateNode.implementation===v.implementation){n(p,f.sibling),f=s(f,v.children||[]),f.return=p,p=f;break e}else{n(p,f);break}else t(p,f);f=f.sibling}f=xl(v,p.mode,w),f.return=p,p=f}return l(p);case Zt:return b=v._init,j(p,f,b(v._payload),w)}if(ps(v))return k(p,f,v,w);if(as(v))return g(p,f,v,w);Na(p,v)}return typeof v=="string"&&v!==""||typeof v=="number"?(v=""+v,f!==null&&f.tag===6?(n(p,f.sibling),f=s(f,v),f.return=p,p=f):(n(p,f),f=vl(v,p.mode,w),f.return=p,p=f),l(p)):n(p,f)}return j}var Vr=ah(!0),ih=ah(!1),si=On(null),ai=null,gr=null,uu=null;function cu(){uu=gr=ai=null}function du(e){var t=si.current;oe(si),e._currentValue=t}function Xl(e,t,n){for(;e!==null;){var r=e.alternate;if((e.childLanes&t)!==t?(e.childLanes|=t,r!==null&&(r.childLanes|=t)):r!==null&&(r.childLanes&t)!==t&&(r.childLanes|=t),e===n)break;e=e.return}}function Cr(e,t){ai=e,uu=gr=null,e=e.dependencies,e!==null&&e.firstContext!==null&&(e.lanes&t&&(Ke=!0),e.firstContext=null)}function ut(e){var t=e._currentValue;if(uu!==e)if(e={context:e,memoizedValue:t,next:null},gr===null){if(ai===null)throw Error(E(308));gr=e,ai.dependencies={lanes:0,firstContext:e}}else gr=gr.next=e;return t}var In=null;function fu(e){In===null?In=[e]:In.push(e)}function lh(e,t,n,r){var s=t.interleaved;return s===null?(n.next=n,fu(t)):(n.next=s.next,s.next=n),t.interleaved=n,Ht(e,r)}function Ht(e,t){e.lanes|=t;var n=e.alternate;for(n!==null&&(n.lanes|=t),n=e,e=e.return;e!==null;)e.childLanes|=t,n=e.alternate,n!==null&&(n.childLanes|=t),n=e,e=e.return;return n.tag===3?n.stateNode:null}var en=!1;function hu(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,interleaved:null,lanes:0},effects:null}}function oh(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,effects:e.effects})}function Bt(e,t){return{eventTime:e,lane:t,tag:0,payload:null,callback:null,next:null}}function kn(e,t,n){var r=e.updateQueue;if(r===null)return null;if(r=r.shared,ee&2){var s=r.pending;return s===null?t.next=t:(t.next=s.next,s.next=t),r.pending=t,Ht(e,n)}return s=r.interleaved,s===null?(t.next=t,fu(r)):(t.next=s.next,s.next=t),r.interleaved=t,Ht(e,n)}function Ia(e,t,n){if(t=t.updateQueue,t!==null&&(t=t.shared,(n&4194240)!==0)){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,Xo(e,n)}}function Rc(e,t){var n=e.updateQueue,r=e.alternate;if(r!==null&&(r=r.updateQueue,n===r)){var s=null,a=null;if(n=n.firstBaseUpdate,n!==null){do{var l={eventTime:n.eventTime,lane:n.lane,tag:n.tag,payload:n.payload,callback:n.callback,next:null};a===null?s=a=l:a=a.next=l,n=n.next}while(n!==null);a===null?s=a=t:a=a.next=t}else s=a=t;n={baseState:r.baseState,firstBaseUpdate:s,lastBaseUpdate:a,shared:r.shared,effects:r.effects},e.updateQueue=n;return}e=n.lastBaseUpdate,e===null?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}function ii(e,t,n,r){var s=e.updateQueue;en=!1;var a=s.firstBaseUpdate,l=s.lastBaseUpdate,o=s.shared.pending;if(o!==null){s.shared.pending=null;var u=o,c=u.next;u.next=null,l===null?a=c:l.next=c,l=u;var h=e.alternate;h!==null&&(h=h.updateQueue,o=h.lastBaseUpdate,o!==l&&(o===null?h.firstBaseUpdate=c:o.next=c,h.lastBaseUpdate=u))}if(a!==null){var d=s.baseState;l=0,h=c=u=null,o=a;do{var m=o.lane,x=o.eventTime;if((r&m)===m){h!==null&&(h=h.next={eventTime:x,lane:0,tag:o.tag,payload:o.payload,callback:o.callback,next:null});e:{var k=e,g=o;switch(m=t,x=n,g.tag){case 1:if(k=g.payload,typeof k=="function"){d=k.call(x,d,m);break e}d=k;break e;case 3:k.flags=k.flags&-65537|128;case 0:if(k=g.payload,m=typeof k=="function"?k.call(x,d,m):k,m==null)break e;d=fe({},d,m);break e;case 2:en=!0}}o.callback!==null&&o.lane!==0&&(e.flags|=64,m=s.effects,m===null?s.effects=[o]:m.push(o))}else x={eventTime:x,lane:m,tag:o.tag,payload:o.payload,callback:o.callback,next:null},h===null?(c=h=x,u=d):h=h.next=x,l|=m;if(o=o.next,o===null){if(o=s.shared.pending,o===null)break;m=o,o=m.next,m.next=null,s.lastBaseUpdate=m,s.shared.pending=null}}while(!0);if(h===null&&(u=d),s.baseState=u,s.firstBaseUpdate=c,s.lastBaseUpdate=h,t=s.shared.interleaved,t!==null){s=t;do l|=s.lane,s=s.next;while(s!==t)}else a===null&&(s.shared.lanes=0);tr|=l,e.lanes=l,e.memoizedState=d}}function Mc(e,t,n){if(e=t.effects,t.effects=null,e!==null)for(t=0;tn?n:4,e(!0);var r=dl.transition;dl.transition={};try{e(!1),t()}finally{re=n,dl.transition=r}}function bh(){return ct().memoizedState}function Vv(e,t,n){var r=Nn(e);if(n={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null},Ch(e))_h(t,n);else if(n=lh(e,t,n,r),n!==null){var s=Ae();gt(n,e,r,s),Eh(n,t,r)}}function Kv(e,t,n){var r=Nn(e),s={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null};if(Ch(e))_h(t,s);else{var a=e.alternate;if(e.lanes===0&&(a===null||a.lanes===0)&&(a=t.lastRenderedReducer,a!==null))try{var l=t.lastRenderedState,o=a(l,n);if(s.hasEagerState=!0,s.eagerState=o,jt(o,l)){var u=t.interleaved;u===null?(s.next=s,fu(t)):(s.next=u.next,u.next=s),t.interleaved=s;return}}catch{}finally{}n=lh(e,t,s,r),n!==null&&(s=Ae(),gt(n,e,r,s),Eh(n,t,r))}}function Ch(e){var t=e.alternate;return e===de||t!==null&&t===de}function _h(e,t){Ns=oi=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function Eh(e,t,n){if(n&4194240){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,Xo(e,n)}}var ui={readContext:ut,useCallback:Oe,useContext:Oe,useEffect:Oe,useImperativeHandle:Oe,useInsertionEffect:Oe,useLayoutEffect:Oe,useMemo:Oe,useReducer:Oe,useRef:Oe,useState:Oe,useDebugValue:Oe,useDeferredValue:Oe,useTransition:Oe,useMutableSource:Oe,useSyncExternalStore:Oe,useId:Oe,unstable_isNewReconciler:!1},Hv={readContext:ut,useCallback:function(e,t){return St().memoizedState=[e,t===void 0?null:t],e},useContext:ut,useEffect:Fc,useImperativeHandle:function(e,t,n){return n=n!=null?n.concat([e]):null,Aa(4194308,4,jh.bind(null,t,e),n)},useLayoutEffect:function(e,t){return Aa(4194308,4,e,t)},useInsertionEffect:function(e,t){return Aa(4,2,e,t)},useMemo:function(e,t){var n=St();return t=t===void 0?null:t,e=e(),n.memoizedState=[e,t],e},useReducer:function(e,t,n){var r=St();return t=n!==void 0?n(t):t,r.memoizedState=r.baseState=t,e={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:t},r.queue=e,e=e.dispatch=Vv.bind(null,de,e),[r.memoizedState,e]},useRef:function(e){var t=St();return e={current:e},t.memoizedState=e},useState:zc,useDebugValue:wu,useDeferredValue:function(e){return St().memoizedState=e},useTransition:function(){var e=zc(!1),t=e[0];return e=Qv.bind(null,e[1]),St().memoizedState=e,[t,e]},useMutableSource:function(){},useSyncExternalStore:function(e,t,n){var r=de,s=St();if(ue){if(n===void 0)throw Error(E(407));n=n()}else{if(n=t(),_e===null)throw Error(E(349));er&30||fh(r,t,n)}s.memoizedState=n;var a={value:n,getSnapshot:t};return s.queue=a,Fc(mh.bind(null,r,a,e),[e]),r.flags|=2048,Vs(9,hh.bind(null,r,a,n,t),void 0,null),n},useId:function(){var e=St(),t=_e.identifierPrefix;if(ue){var n=Ut,r=$t;n=(r&~(1<<32-yt(r)-1)).toString(32)+n,t=":"+t+"R"+n,n=Bs++,0<\/script>",e=e.removeChild(e.firstChild)):typeof r.is=="string"?e=l.createElement(n,{is:r.is}):(e=l.createElement(n),n==="select"&&(l=e,r.multiple?l.multiple=!0:r.size&&(l.size=r.size))):e=l.createElementNS(e,n),e[_t]=t,e[As]=r,Dh(e,t,!1,!1),t.stateNode=e;e:{switch(l=Ml(n,r),n){case"dialog":le("cancel",e),le("close",e),s=r;break;case"iframe":case"object":case"embed":le("load",e),s=r;break;case"video":case"audio":for(s=0;sWr&&(t.flags|=128,r=!0,ds(a,!1),t.lanes=4194304)}else{if(!r)if(e=li(l),e!==null){if(t.flags|=128,r=!0,n=e.updateQueue,n!==null&&(t.updateQueue=n,t.flags|=4),ds(a,!0),a.tail===null&&a.tailMode==="hidden"&&!l.alternate&&!ue)return Le(t),null}else 2*ye()-a.renderingStartTime>Wr&&n!==1073741824&&(t.flags|=128,r=!0,ds(a,!1),t.lanes=4194304);a.isBackwards?(l.sibling=t.child,t.child=l):(n=a.last,n!==null?n.sibling=l:t.child=l,a.last=l)}return a.tail!==null?(t=a.tail,a.rendering=t,a.tail=t.sibling,a.renderingStartTime=ye(),t.sibling=null,n=ce.current,ae(ce,r?n&1|2:n&1),t):(Le(t),null);case 22:case 23:return _u(),r=t.memoizedState!==null,e!==null&&e.memoizedState!==null!==r&&(t.flags|=8192),r&&t.mode&1?Ye&1073741824&&(Le(t),t.subtreeFlags&6&&(t.flags|=8192)):Le(t),null;case 24:return null;case 25:return null}throw Error(E(156,t.tag))}function ex(e,t){switch(lu(t),t.tag){case 1:return We(t.type)&&ei(),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return Kr(),oe(He),oe(ze),vu(),e=t.flags,e&65536&&!(e&128)?(t.flags=e&-65537|128,t):null;case 5:return pu(t),null;case 13:if(oe(ce),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(E(340));Qr()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return oe(ce),null;case 4:return Kr(),null;case 10:return du(t.type._context),null;case 22:case 23:return _u(),null;case 24:return null;default:return null}}var Ca=!1,Me=!1,tx=typeof WeakSet=="function"?WeakSet:Set,I=null;function jr(e,t){var n=e.ref;if(n!==null)if(typeof n=="function")try{n(null)}catch(r){pe(e,t,r)}else n.current=null}function lo(e,t,n){try{n()}catch(r){pe(e,t,r)}}var Wc=!1;function nx(e,t){if(Vl=Ga,e=Kf(),au(e)){if("selectionStart"in e)var n={start:e.selectionStart,end:e.selectionEnd};else e:{n=(n=e.ownerDocument)&&n.defaultView||window;var r=n.getSelection&&n.getSelection();if(r&&r.rangeCount!==0){n=r.anchorNode;var s=r.anchorOffset,a=r.focusNode;r=r.focusOffset;try{n.nodeType,a.nodeType}catch{n=null;break e}var l=0,o=-1,u=-1,c=0,h=0,d=e,m=null;t:for(;;){for(var x;d!==n||s!==0&&d.nodeType!==3||(o=l+s),d!==a||r!==0&&d.nodeType!==3||(u=l+r),d.nodeType===3&&(l+=d.nodeValue.length),(x=d.firstChild)!==null;)m=d,d=x;for(;;){if(d===e)break t;if(m===n&&++c===s&&(o=l),m===a&&++h===r&&(u=l),(x=d.nextSibling)!==null)break;d=m,m=d.parentNode}d=x}n=o===-1||u===-1?null:{start:o,end:u}}else n=null}n=n||{start:0,end:0}}else n=null;for(Kl={focusedElem:e,selectionRange:n},Ga=!1,I=t;I!==null;)if(t=I,e=t.child,(t.subtreeFlags&1028)!==0&&e!==null)e.return=t,I=e;else for(;I!==null;){t=I;try{var k=t.alternate;if(t.flags&1024)switch(t.tag){case 0:case 11:case 15:break;case 1:if(k!==null){var g=k.memoizedProps,j=k.memoizedState,p=t.stateNode,f=p.getSnapshotBeforeUpdate(t.elementType===t.type?g:ht(t.type,g),j);p.__reactInternalSnapshotBeforeUpdate=f}break;case 3:var v=t.stateNode.containerInfo;v.nodeType===1?v.textContent="":v.nodeType===9&&v.documentElement&&v.removeChild(v.documentElement);break;case 5:case 6:case 4:case 17:break;default:throw Error(E(163))}}catch(w){pe(t,t.return,w)}if(e=t.sibling,e!==null){e.return=t.return,I=e;break}I=t.return}return k=Wc,Wc=!1,k}function bs(e,t,n){var r=t.updateQueue;if(r=r!==null?r.lastEffect:null,r!==null){var s=r=r.next;do{if((s.tag&e)===e){var a=s.destroy;s.destroy=void 0,a!==void 0&&lo(t,n,a)}s=s.next}while(s!==r)}}function Pi(e,t){if(t=t.updateQueue,t=t!==null?t.lastEffect:null,t!==null){var n=t=t.next;do{if((n.tag&e)===e){var r=n.create;n.destroy=r()}n=n.next}while(n!==t)}}function oo(e){var t=e.ref;if(t!==null){var n=e.stateNode;switch(e.tag){case 5:e=n;break;default:e=n}typeof t=="function"?t(e):t.current=e}}function Uh(e){var t=e.alternate;t!==null&&(e.alternate=null,Uh(t)),e.child=null,e.deletions=null,e.sibling=null,e.tag===5&&(t=e.stateNode,t!==null&&(delete t[_t],delete t[As],delete t[ql],delete t[Dv],delete t[Av])),e.stateNode=null,e.return=null,e.dependencies=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.stateNode=null,e.updateQueue=null}function Bh(e){return e.tag===5||e.tag===3||e.tag===4}function qc(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||Bh(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.flags&2||e.child===null||e.tag===4)continue e;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function uo(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.nodeType===8?n.parentNode.insertBefore(e,t):n.insertBefore(e,t):(n.nodeType===8?(t=n.parentNode,t.insertBefore(e,n)):(t=n,t.appendChild(e)),n=n._reactRootContainer,n!=null||t.onclick!==null||(t.onclick=Za));else if(r!==4&&(e=e.child,e!==null))for(uo(e,t,n),e=e.sibling;e!==null;)uo(e,t,n),e=e.sibling}function co(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(r!==4&&(e=e.child,e!==null))for(co(e,t,n),e=e.sibling;e!==null;)co(e,t,n),e=e.sibling}var Ee=null,vt=!1;function Yt(e,t,n){for(n=n.child;n!==null;)Qh(e,t,n),n=n.sibling}function Qh(e,t,n){if(Pt&&typeof Pt.onCommitFiberUnmount=="function")try{Pt.onCommitFiberUnmount(wi,n)}catch{}switch(n.tag){case 5:Me||jr(n,t);case 6:var r=Ee,s=vt;Ee=null,Yt(e,t,n),Ee=r,vt=s,Ee!==null&&(vt?(e=Ee,n=n.stateNode,e.nodeType===8?e.parentNode.removeChild(n):e.removeChild(n)):Ee.removeChild(n.stateNode));break;case 18:Ee!==null&&(vt?(e=Ee,n=n.stateNode,e.nodeType===8?ol(e.parentNode,n):e.nodeType===1&&ol(e,n),Ms(e)):ol(Ee,n.stateNode));break;case 4:r=Ee,s=vt,Ee=n.stateNode.containerInfo,vt=!0,Yt(e,t,n),Ee=r,vt=s;break;case 0:case 11:case 14:case 15:if(!Me&&(r=n.updateQueue,r!==null&&(r=r.lastEffect,r!==null))){s=r=r.next;do{var a=s,l=a.destroy;a=a.tag,l!==void 0&&(a&2||a&4)&&lo(n,t,l),s=s.next}while(s!==r)}Yt(e,t,n);break;case 1:if(!Me&&(jr(n,t),r=n.stateNode,typeof r.componentWillUnmount=="function"))try{r.props=n.memoizedProps,r.state=n.memoizedState,r.componentWillUnmount()}catch(o){pe(n,t,o)}Yt(e,t,n);break;case 21:Yt(e,t,n);break;case 22:n.mode&1?(Me=(r=Me)||n.memoizedState!==null,Yt(e,t,n),Me=r):Yt(e,t,n);break;default:Yt(e,t,n)}}function Jc(e){var t=e.updateQueue;if(t!==null){e.updateQueue=null;var n=e.stateNode;n===null&&(n=e.stateNode=new tx),t.forEach(function(r){var s=dx.bind(null,e,r);n.has(r)||(n.add(r),r.then(s,s))})}}function ft(e,t){var n=t.deletions;if(n!==null)for(var r=0;rs&&(s=l),r&=~a}if(r=s,r=ye()-r,r=(120>r?120:480>r?480:1080>r?1080:1920>r?1920:3e3>r?3e3:4320>r?4320:1960*sx(r/1960))-r,10e?16:e,mn===null)var r=!1;else{if(e=mn,mn=null,fi=0,ee&6)throw Error(E(331));var s=ee;for(ee|=4,I=e.current;I!==null;){var a=I,l=a.child;if(I.flags&16){var o=a.deletions;if(o!==null){for(var u=0;uye()-bu?Jn(e,0):Nu|=n),qe(e,t)}function Yh(e,t){t===0&&(e.mode&1?(t=xa,xa<<=1,!(xa&130023424)&&(xa=4194304)):t=1);var n=Ae();e=Ht(e,t),e!==null&&(aa(e,t,n),qe(e,n))}function cx(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),Yh(e,n)}function dx(e,t){var n=0;switch(e.tag){case 13:var r=e.stateNode,s=e.memoizedState;s!==null&&(n=s.retryLane);break;case 19:r=e.stateNode;break;default:throw Error(E(314))}r!==null&&r.delete(t),Yh(e,n)}var Xh;Xh=function(e,t,n){if(e!==null)if(e.memoizedProps!==t.pendingProps||He.current)Ke=!0;else{if(!(e.lanes&n)&&!(t.flags&128))return Ke=!1,Xv(e,t,n);Ke=!!(e.flags&131072)}else Ke=!1,ue&&t.flags&1048576&&nh(t,ri,t.index);switch(t.lanes=0,t.tag){case 2:var r=t.type;$a(e,t),e=t.pendingProps;var s=Br(t,ze.current);Cr(t,n),s=yu(null,t,r,e,s,n);var a=gu();return t.flags|=1,typeof s=="object"&&s!==null&&typeof s.render=="function"&&s.$$typeof===void 0?(t.tag=1,t.memoizedState=null,t.updateQueue=null,We(r)?(a=!0,ti(t)):a=!1,t.memoizedState=s.state!==null&&s.state!==void 0?s.state:null,hu(t),s.updater=Ei,t.stateNode=s,s._reactInternals=t,eo(t,r,e,n),t=ro(null,t,r,!0,a,n)):(t.tag=0,ue&&a&&iu(t),Ie(null,t,s,n),t=t.child),t;case 16:r=t.elementType;e:{switch($a(e,t),e=t.pendingProps,s=r._init,r=s(r._payload),t.type=r,s=t.tag=hx(r),e=ht(r,e),s){case 0:t=no(null,t,r,e,n);break e;case 1:t=Vc(null,t,r,e,n);break e;case 11:t=Bc(null,t,r,e,n);break e;case 14:t=Qc(null,t,r,ht(r.type,e),n);break e}throw Error(E(306,r,""))}return t;case 0:return r=t.type,s=t.pendingProps,s=t.elementType===r?s:ht(r,s),no(e,t,r,s,n);case 1:return r=t.type,s=t.pendingProps,s=t.elementType===r?s:ht(r,s),Vc(e,t,r,s,n);case 3:e:{if(zh(t),e===null)throw Error(E(387));r=t.pendingProps,a=t.memoizedState,s=a.element,oh(e,t),ii(t,r,null,n);var l=t.memoizedState;if(r=l.element,a.isDehydrated)if(a={element:r,isDehydrated:!1,cache:l.cache,pendingSuspenseBoundaries:l.pendingSuspenseBoundaries,transitions:l.transitions},t.updateQueue.baseState=a,t.memoizedState=a,t.flags&256){s=Hr(Error(E(423)),t),t=Kc(e,t,r,n,s);break e}else if(r!==s){s=Hr(Error(E(424)),t),t=Kc(e,t,r,n,s);break e}else for(Xe=wn(t.stateNode.containerInfo.firstChild),Ze=t,ue=!0,xt=null,n=ih(t,null,r,n),t.child=n;n;)n.flags=n.flags&-3|4096,n=n.sibling;else{if(Qr(),r===s){t=Wt(e,t,n);break e}Ie(e,t,r,n)}t=t.child}return t;case 5:return uh(t),e===null&&Yl(t),r=t.type,s=t.pendingProps,a=e!==null?e.memoizedProps:null,l=s.children,Hl(r,s)?l=null:a!==null&&Hl(r,a)&&(t.flags|=32),Mh(e,t),Ie(e,t,l,n),t.child;case 6:return e===null&&Yl(t),null;case 13:return Fh(e,t,n);case 4:return mu(t,t.stateNode.containerInfo),r=t.pendingProps,e===null?t.child=Vr(t,null,r,n):Ie(e,t,r,n),t.child;case 11:return r=t.type,s=t.pendingProps,s=t.elementType===r?s:ht(r,s),Bc(e,t,r,s,n);case 7:return Ie(e,t,t.pendingProps,n),t.child;case 8:return Ie(e,t,t.pendingProps.children,n),t.child;case 12:return Ie(e,t,t.pendingProps.children,n),t.child;case 10:e:{if(r=t.type._context,s=t.pendingProps,a=t.memoizedProps,l=s.value,ae(si,r._currentValue),r._currentValue=l,a!==null)if(jt(a.value,l)){if(a.children===s.children&&!He.current){t=Wt(e,t,n);break e}}else for(a=t.child,a!==null&&(a.return=t);a!==null;){var o=a.dependencies;if(o!==null){l=a.child;for(var u=o.firstContext;u!==null;){if(u.context===r){if(a.tag===1){u=Bt(-1,n&-n),u.tag=2;var c=a.updateQueue;if(c!==null){c=c.shared;var h=c.pending;h===null?u.next=u:(u.next=h.next,h.next=u),c.pending=u}}a.lanes|=n,u=a.alternate,u!==null&&(u.lanes|=n),Xl(a.return,n,t),o.lanes|=n;break}u=u.next}}else if(a.tag===10)l=a.type===t.type?null:a.child;else if(a.tag===18){if(l=a.return,l===null)throw Error(E(341));l.lanes|=n,o=l.alternate,o!==null&&(o.lanes|=n),Xl(l,n,t),l=a.sibling}else l=a.child;if(l!==null)l.return=a;else for(l=a;l!==null;){if(l===t){l=null;break}if(a=l.sibling,a!==null){a.return=l.return,l=a;break}l=l.return}a=l}Ie(e,t,s.children,n),t=t.child}return t;case 9:return s=t.type,r=t.pendingProps.children,Cr(t,n),s=ut(s),r=r(s),t.flags|=1,Ie(e,t,r,n),t.child;case 14:return r=t.type,s=ht(r,t.pendingProps),s=ht(r.type,s),Qc(e,t,r,s,n);case 15:return Lh(e,t,t.type,t.pendingProps,n);case 17:return r=t.type,s=t.pendingProps,s=t.elementType===r?s:ht(r,s),$a(e,t),t.tag=1,We(r)?(e=!0,ti(t)):e=!1,Cr(t,n),Ph(t,r,s),eo(t,r,s,n),ro(null,t,r,!0,e,n);case 19:return Ih(e,t,n);case 22:return Rh(e,t,n)}throw Error(E(156,t.tag))};function Zh(e,t){return Cf(e,t)}function fx(e,t,n,r){this.tag=e,this.key=n,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=t,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function lt(e,t,n,r){return new fx(e,t,n,r)}function Pu(e){return e=e.prototype,!(!e||!e.isReactComponent)}function hx(e){if(typeof e=="function")return Pu(e)?1:0;if(e!=null){if(e=e.$$typeof,e===qo)return 11;if(e===Jo)return 14}return 2}function bn(e,t){var n=e.alternate;return n===null?(n=lt(e.tag,t,e.key,e.mode),n.elementType=e.elementType,n.type=e.type,n.stateNode=e.stateNode,n.alternate=e,e.alternate=n):(n.pendingProps=t,n.type=e.type,n.flags=0,n.subtreeFlags=0,n.deletions=null),n.flags=e.flags&14680064,n.childLanes=e.childLanes,n.lanes=e.lanes,n.child=e.child,n.memoizedProps=e.memoizedProps,n.memoizedState=e.memoizedState,n.updateQueue=e.updateQueue,t=e.dependencies,n.dependencies=t===null?null:{lanes:t.lanes,firstContext:t.firstContext},n.sibling=e.sibling,n.index=e.index,n.ref=e.ref,n}function Qa(e,t,n,r,s,a){var l=2;if(r=e,typeof e=="function")Pu(e)&&(l=1);else if(typeof e=="string")l=5;else e:switch(e){case dr:return Gn(n.children,s,a,t);case Wo:l=8,s|=8;break;case Nl:return e=lt(12,n,t,s|2),e.elementType=Nl,e.lanes=a,e;case bl:return e=lt(13,n,t,s),e.elementType=bl,e.lanes=a,e;case Cl:return e=lt(19,n,t,s),e.elementType=Cl,e.lanes=a,e;case uf:return Oi(n,s,a,t);default:if(typeof e=="object"&&e!==null)switch(e.$$typeof){case lf:l=10;break e;case of:l=9;break e;case qo:l=11;break e;case Jo:l=14;break e;case Zt:l=16,r=null;break e}throw Error(E(130,e==null?e:typeof e,""))}return t=lt(l,n,t,s),t.elementType=e,t.type=r,t.lanes=a,t}function Gn(e,t,n,r){return e=lt(7,e,r,t),e.lanes=n,e}function Oi(e,t,n,r){return e=lt(22,e,r,t),e.elementType=uf,e.lanes=n,e.stateNode={isHidden:!1},e}function vl(e,t,n){return e=lt(6,e,null,t),e.lanes=n,e}function xl(e,t,n){return t=lt(4,e.children!==null?e.children:[],e.key,t),t.lanes=n,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}function mx(e,t,n,r,s){this.tag=t,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.pendingContext=this.context=null,this.callbackPriority=0,this.eventTimes=Yi(0),this.expirationTimes=Yi(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=Yi(0),this.identifierPrefix=r,this.onRecoverableError=s,this.mutableSourceEagerHydrationData=null}function Tu(e,t,n,r,s,a,l,o,u){return e=new mx(e,t,n,o,u),t===1?(t=1,a===!0&&(t|=8)):t=0,a=lt(3,null,null,t),e.current=a,a.stateNode=e,a.memoizedState={element:r,isDehydrated:n,cache:null,transitions:null,pendingSuspenseBoundaries:null},hu(a),e}function px(e,t,n){var r=3"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(rm)}catch(e){console.error(e)}}rm(),nf.exports=tt;var jx=nf.exports,rd=jx;kl.createRoot=rd.createRoot,kl.hydrateRoot=rd.hydrateRoot;var Zr=class{constructor(){this.listeners=new Set,this.subscribe=this.subscribe.bind(this)}subscribe(e){return this.listeners.add(e),this.onSubscribe(),()=>{this.listeners.delete(e),this.onUnsubscribe()}}hasListeners(){return this.listeners.size>0}onSubscribe(){}onUnsubscribe(){}},wx={setTimeout:(e,t)=>setTimeout(e,t),clearTimeout:e=>clearTimeout(e),setInterval:(e,t)=>setInterval(e,t),clearInterval:e=>clearInterval(e)},rn,Do,Rd,kx=(Rd=class{constructor(){$(this,rn,wx);$(this,Do,!1)}setTimeoutProvider(e){z(this,rn,e)}setTimeout(e,t){return y(this,rn).setTimeout(e,t)}clearTimeout(e){y(this,rn).clearTimeout(e)}setInterval(e,t){return y(this,rn).setInterval(e,t)}clearInterval(e){y(this,rn).clearInterval(e)}},rn=new WeakMap,Do=new WeakMap,Rd),An=new kx;function Sx(e){setTimeout(e,0)}var rr=typeof window>"u"||"Deno"in globalThis;function De(){}function Nx(e,t){return typeof e=="function"?e(t):e}function vo(e){return typeof e=="number"&&e>=0&&e!==1/0}function sm(e,t){return Math.max(e+(t||0)-Date.now(),0)}function Cn(e,t){return typeof e=="function"?e(t):e}function st(e,t){return typeof e=="function"?e(t):e}function sd(e,t){const{type:n="all",exact:r,fetchStatus:s,predicate:a,queryKey:l,stale:o}=e;if(l){if(r){if(t.queryHash!==Mu(l,t.options))return!1}else if(!Hs(t.queryKey,l))return!1}if(n!=="all"){const u=t.isActive();if(n==="active"&&!u||n==="inactive"&&u)return!1}return!(typeof o=="boolean"&&t.isStale()!==o||s&&s!==t.state.fetchStatus||a&&!a(t))}function ad(e,t){const{exact:n,status:r,predicate:s,mutationKey:a}=e;if(a){if(!t.options.mutationKey)return!1;if(n){if(sr(t.options.mutationKey)!==sr(a))return!1}else if(!Hs(t.options.mutationKey,a))return!1}return!(r&&t.state.status!==r||s&&!s(t))}function Mu(e,t){return((t==null?void 0:t.queryKeyHashFn)||sr)(e)}function sr(e){return JSON.stringify(e,(t,n)=>xo(n)?Object.keys(n).sort().reduce((r,s)=>(r[s]=n[s],r),{}):n)}function Hs(e,t){return e===t?!0:typeof e!=typeof t?!1:e&&t&&typeof e=="object"&&typeof t=="object"?Object.keys(t).every(n=>Hs(e[n],t[n])):!1}var bx=Object.prototype.hasOwnProperty;function am(e,t,n=0){if(e===t)return e;if(n>500)return t;const r=id(e)&&id(t);if(!r&&!(xo(e)&&xo(t)))return t;const a=(r?e:Object.keys(e)).length,l=r?t:Object.keys(t),o=l.length,u=r?new Array(o):{};let c=0;for(let h=0;h{An.setTimeout(t,e)})}function yo(e,t,n){return typeof n.structuralSharing=="function"?n.structuralSharing(e,t):n.structuralSharing!==!1?am(e,t):t}function _x(e,t,n=0){const r=[...e,t];return n&&r.length>n?r.slice(1):r}function Ex(e,t,n=0){const r=[t,...e];return n&&r.length>n?r.slice(0,-1):r}var zu=Symbol();function im(e,t){return!e.queryFn&&(t!=null&&t.initialPromise)?()=>t.initialPromise:!e.queryFn||e.queryFn===zu?()=>Promise.reject(new Error(`Missing queryFn: '${e.queryHash}'`)):e.queryFn}function Fu(e,t){return typeof e=="function"?e(...t):!!e}function Px(e,t,n){let r=!1,s;return Object.defineProperty(e,"signal",{enumerable:!0,get:()=>(s??(s=t()),r||(r=!0,s.aborted?n():s.addEventListener("abort",n,{once:!0})),s)}),e}var $n,sn,Pr,Md,Tx=(Md=class extends Zr{constructor(){super();$(this,$n);$(this,sn);$(this,Pr);z(this,Pr,t=>{if(!rr&&window.addEventListener){const n=()=>t();return window.addEventListener("visibilitychange",n,!1),()=>{window.removeEventListener("visibilitychange",n)}}})}onSubscribe(){y(this,sn)||this.setEventListener(y(this,Pr))}onUnsubscribe(){var t;this.hasListeners()||((t=y(this,sn))==null||t.call(this),z(this,sn,void 0))}setEventListener(t){var n;z(this,Pr,t),(n=y(this,sn))==null||n.call(this),z(this,sn,t(r=>{typeof r=="boolean"?this.setFocused(r):this.onFocus()}))}setFocused(t){y(this,$n)!==t&&(z(this,$n,t),this.onFocus())}onFocus(){const t=this.isFocused();this.listeners.forEach(n=>{n(t)})}isFocused(){var t;return typeof y(this,$n)=="boolean"?y(this,$n):((t=globalThis.document)==null?void 0:t.visibilityState)!=="hidden"}},$n=new WeakMap,sn=new WeakMap,Pr=new WeakMap,Md),Iu=new Tx;function go(){let e,t;const n=new Promise((s,a)=>{e=s,t=a});n.status="pending",n.catch(()=>{});function r(s){Object.assign(n,s),delete n.resolve,delete n.reject}return n.resolve=s=>{r({status:"fulfilled",value:s}),e(s)},n.reject=s=>{r({status:"rejected",reason:s}),t(s)},n}var Ox=Sx;function Lx(){let e=[],t=0,n=o=>{o()},r=o=>{o()},s=Ox;const a=o=>{t?e.push(o):s(()=>{n(o)})},l=()=>{const o=e;e=[],o.length&&s(()=>{r(()=>{o.forEach(u=>{n(u)})})})};return{batch:o=>{let u;t++;try{u=o()}finally{t--,t||l()}return u},batchCalls:o=>(...u)=>{a(()=>{o(...u)})},schedule:a,setNotifyFunction:o=>{n=o},setBatchNotifyFunction:o=>{r=o},setScheduler:o=>{s=o}}}var ke=Lx(),Tr,an,Or,zd,Rx=(zd=class extends Zr{constructor(){super();$(this,Tr,!0);$(this,an);$(this,Or);z(this,Or,t=>{if(!rr&&window.addEventListener){const n=()=>t(!0),r=()=>t(!1);return window.addEventListener("online",n,!1),window.addEventListener("offline",r,!1),()=>{window.removeEventListener("online",n),window.removeEventListener("offline",r)}}})}onSubscribe(){y(this,an)||this.setEventListener(y(this,Or))}onUnsubscribe(){var t;this.hasListeners()||((t=y(this,an))==null||t.call(this),z(this,an,void 0))}setEventListener(t){var n;z(this,Or,t),(n=y(this,an))==null||n.call(this),z(this,an,t(this.setOnline.bind(this)))}setOnline(t){y(this,Tr)!==t&&(z(this,Tr,t),this.listeners.forEach(r=>{r(t)}))}isOnline(){return y(this,Tr)}},Tr=new WeakMap,an=new WeakMap,Or=new WeakMap,zd),vi=new Rx;function Mx(e){return Math.min(1e3*2**e,3e4)}function lm(e){return(e??"online")==="online"?vi.isOnline():!0}var jo=class extends Error{constructor(e){super("CancelledError"),this.revert=e==null?void 0:e.revert,this.silent=e==null?void 0:e.silent}};function om(e){let t=!1,n=0,r;const s=go(),a=()=>s.status!=="pending",l=g=>{var j;if(!a()){const p=new jo(g);m(p),(j=e.onCancel)==null||j.call(e,p)}},o=()=>{t=!0},u=()=>{t=!1},c=()=>Iu.isFocused()&&(e.networkMode==="always"||vi.isOnline())&&e.canRun(),h=()=>lm(e.networkMode)&&e.canRun(),d=g=>{a()||(r==null||r(),s.resolve(g))},m=g=>{a()||(r==null||r(),s.reject(g))},x=()=>new Promise(g=>{var j;r=p=>{(a()||c())&&g(p)},(j=e.onPause)==null||j.call(e)}).then(()=>{var g;r=void 0,a()||(g=e.onContinue)==null||g.call(e)}),k=()=>{if(a())return;let g;const j=n===0?e.initialPromise:void 0;try{g=j??e.fn()}catch(p){g=Promise.reject(p)}Promise.resolve(g).then(d).catch(p=>{var b;if(a())return;const f=e.retry??(rr?0:3),v=e.retryDelay??Mx,w=typeof v=="function"?v(n,p):v,C=f===!0||typeof f=="number"&&nc()?void 0:x()).then(()=>{t?m(p):k()})})};return{promise:s,status:()=>s.status,cancel:l,continue:()=>(r==null||r(),s),cancelRetry:o,continueRetry:u,canStart:h,start:()=>(h()?k():x().then(k),s)}}var Un,Fd,um=(Fd=class{constructor(){$(this,Un)}destroy(){this.clearGcTimeout()}scheduleGc(){this.clearGcTimeout(),vo(this.gcTime)&&z(this,Un,An.setTimeout(()=>{this.optionalRemove()},this.gcTime))}updateGcTime(e){this.gcTime=Math.max(this.gcTime||0,e??(rr?1/0:5*60*1e3))}clearGcTimeout(){y(this,Un)&&(An.clearTimeout(y(this,Un)),z(this,Un,void 0))}},Un=new WeakMap,Fd),Bn,Lr,rt,Qn,be,Zs,Vn,mt,Rt,Id,zx=(Id=class extends um{constructor(t){super();$(this,mt);$(this,Bn);$(this,Lr);$(this,rt);$(this,Qn);$(this,be);$(this,Zs);$(this,Vn);z(this,Vn,!1),z(this,Zs,t.defaultOptions),this.setOptions(t.options),this.observers=[],z(this,Qn,t.client),z(this,rt,y(this,Qn).getQueryCache()),this.queryKey=t.queryKey,this.queryHash=t.queryHash,z(this,Bn,ud(this.options)),this.state=t.state??y(this,Bn),this.scheduleGc()}get meta(){return this.options.meta}get promise(){var t;return(t=y(this,be))==null?void 0:t.promise}setOptions(t){if(this.options={...y(this,Zs),...t},this.updateGcTime(this.options.gcTime),this.state&&this.state.data===void 0){const n=ud(this.options);n.data!==void 0&&(this.setState(od(n.data,n.dataUpdatedAt)),z(this,Bn,n))}}optionalRemove(){!this.observers.length&&this.state.fetchStatus==="idle"&&y(this,rt).remove(this)}setData(t,n){const r=yo(this.state.data,t,this.options);return W(this,mt,Rt).call(this,{data:r,type:"success",dataUpdatedAt:n==null?void 0:n.updatedAt,manual:n==null?void 0:n.manual}),r}setState(t,n){W(this,mt,Rt).call(this,{type:"setState",state:t,setStateOptions:n})}cancel(t){var r,s;const n=(r=y(this,be))==null?void 0:r.promise;return(s=y(this,be))==null||s.cancel(t),n?n.then(De).catch(De):Promise.resolve()}destroy(){super.destroy(),this.cancel({silent:!0})}reset(){this.destroy(),this.setState(y(this,Bn))}isActive(){return this.observers.some(t=>st(t.options.enabled,this)!==!1)}isDisabled(){return this.getObserversCount()>0?!this.isActive():this.options.queryFn===zu||this.state.dataUpdateCount+this.state.errorUpdateCount===0}isStatic(){return this.getObserversCount()>0?this.observers.some(t=>Cn(t.options.staleTime,this)==="static"):!1}isStale(){return this.getObserversCount()>0?this.observers.some(t=>t.getCurrentResult().isStale):this.state.data===void 0||this.state.isInvalidated}isStaleByTime(t=0){return this.state.data===void 0?!0:t==="static"?!1:this.state.isInvalidated?!0:!sm(this.state.dataUpdatedAt,t)}onFocus(){var n;const t=this.observers.find(r=>r.shouldFetchOnWindowFocus());t==null||t.refetch({cancelRefetch:!1}),(n=y(this,be))==null||n.continue()}onOnline(){var n;const t=this.observers.find(r=>r.shouldFetchOnReconnect());t==null||t.refetch({cancelRefetch:!1}),(n=y(this,be))==null||n.continue()}addObserver(t){this.observers.includes(t)||(this.observers.push(t),this.clearGcTimeout(),y(this,rt).notify({type:"observerAdded",query:this,observer:t}))}removeObserver(t){this.observers.includes(t)&&(this.observers=this.observers.filter(n=>n!==t),this.observers.length||(y(this,be)&&(y(this,Vn)?y(this,be).cancel({revert:!0}):y(this,be).cancelRetry()),this.scheduleGc()),y(this,rt).notify({type:"observerRemoved",query:this,observer:t}))}getObserversCount(){return this.observers.length}invalidate(){this.state.isInvalidated||W(this,mt,Rt).call(this,{type:"invalidate"})}async fetch(t,n){var u,c,h,d,m,x,k,g,j,p,f,v;if(this.state.fetchStatus!=="idle"&&((u=y(this,be))==null?void 0:u.status())!=="rejected"){if(this.state.data!==void 0&&(n!=null&&n.cancelRefetch))this.cancel({silent:!0});else if(y(this,be))return y(this,be).continueRetry(),y(this,be).promise}if(t&&this.setOptions(t),!this.options.queryFn){const w=this.observers.find(C=>C.options.queryFn);w&&this.setOptions(w.options)}const r=new AbortController,s=w=>{Object.defineProperty(w,"signal",{enumerable:!0,get:()=>(z(this,Vn,!0),r.signal)})},a=()=>{const w=im(this.options,n),b=(()=>{const N={client:y(this,Qn),queryKey:this.queryKey,meta:this.meta};return s(N),N})();return z(this,Vn,!1),this.options.persister?this.options.persister(w,b,this):w(b)},o=(()=>{const w={fetchOptions:n,options:this.options,queryKey:this.queryKey,client:y(this,Qn),state:this.state,fetchFn:a};return s(w),w})();(c=this.options.behavior)==null||c.onFetch(o,this),z(this,Lr,this.state),(this.state.fetchStatus==="idle"||this.state.fetchMeta!==((h=o.fetchOptions)==null?void 0:h.meta))&&W(this,mt,Rt).call(this,{type:"fetch",meta:(d=o.fetchOptions)==null?void 0:d.meta}),z(this,be,om({initialPromise:n==null?void 0:n.initialPromise,fn:o.fetchFn,onCancel:w=>{w instanceof jo&&w.revert&&this.setState({...y(this,Lr),fetchStatus:"idle"}),r.abort()},onFail:(w,C)=>{W(this,mt,Rt).call(this,{type:"failed",failureCount:w,error:C})},onPause:()=>{W(this,mt,Rt).call(this,{type:"pause"})},onContinue:()=>{W(this,mt,Rt).call(this,{type:"continue"})},retry:o.options.retry,retryDelay:o.options.retryDelay,networkMode:o.options.networkMode,canRun:()=>!0}));try{const w=await y(this,be).start();if(w===void 0)throw new Error(`${this.queryHash} data is undefined`);return this.setData(w),(x=(m=y(this,rt).config).onSuccess)==null||x.call(m,w,this),(g=(k=y(this,rt).config).onSettled)==null||g.call(k,w,this.state.error,this),w}catch(w){if(w instanceof jo){if(w.silent)return y(this,be).promise;if(w.revert){if(this.state.data===void 0)throw w;return this.state.data}}throw W(this,mt,Rt).call(this,{type:"error",error:w}),(p=(j=y(this,rt).config).onError)==null||p.call(j,w,this),(v=(f=y(this,rt).config).onSettled)==null||v.call(f,this.state.data,w,this),w}finally{this.scheduleGc()}}},Bn=new WeakMap,Lr=new WeakMap,rt=new WeakMap,Qn=new WeakMap,be=new WeakMap,Zs=new WeakMap,Vn=new WeakMap,mt=new WeakSet,Rt=function(t){const n=r=>{switch(t.type){case"failed":return{...r,fetchFailureCount:t.failureCount,fetchFailureReason:t.error};case"pause":return{...r,fetchStatus:"paused"};case"continue":return{...r,fetchStatus:"fetching"};case"fetch":return{...r,...cm(r.data,this.options),fetchMeta:t.meta??null};case"success":const s={...r,...od(t.data,t.dataUpdatedAt),dataUpdateCount:r.dataUpdateCount+1,...!t.manual&&{fetchStatus:"idle",fetchFailureCount:0,fetchFailureReason:null}};return z(this,Lr,t.manual?s:void 0),s;case"error":const a=t.error;return{...r,error:a,errorUpdateCount:r.errorUpdateCount+1,errorUpdatedAt:Date.now(),fetchFailureCount:r.fetchFailureCount+1,fetchFailureReason:a,fetchStatus:"idle",status:"error",isInvalidated:!0};case"invalidate":return{...r,isInvalidated:!0};case"setState":return{...r,...t.state}}};this.state=n(this.state),ke.batch(()=>{this.observers.forEach(r=>{r.onQueryUpdate()}),y(this,rt).notify({query:this,type:"updated",action:t})})},Id);function cm(e,t){return{fetchFailureCount:0,fetchFailureReason:null,fetchStatus:lm(t.networkMode)?"fetching":"paused",...e===void 0&&{error:null,status:"pending"}}}function od(e,t){return{data:e,dataUpdatedAt:t??Date.now(),error:null,isInvalidated:!1,status:"success"}}function ud(e){const t=typeof e.initialData=="function"?e.initialData():e.initialData,n=t!==void 0,r=n?typeof e.initialDataUpdatedAt=="function"?e.initialDataUpdatedAt():e.initialDataUpdatedAt:0;return{data:t,dataUpdateCount:0,dataUpdatedAt:n?r??Date.now():0,error:null,errorUpdateCount:0,errorUpdatedAt:0,fetchFailureCount:0,fetchFailureReason:null,fetchMeta:null,isInvalidated:!1,status:n?"success":"pending",fetchStatus:"idle"}}var Be,G,ea,Fe,Kn,Rr,Ft,ln,ta,Mr,zr,Hn,Wn,on,Fr,te,ys,wo,ko,So,No,bo,Co,_o,dm,Dd,Fx=(Dd=class extends Zr{constructor(t,n){super();$(this,te);$(this,Be);$(this,G);$(this,ea);$(this,Fe);$(this,Kn);$(this,Rr);$(this,Ft);$(this,ln);$(this,ta);$(this,Mr);$(this,zr);$(this,Hn);$(this,Wn);$(this,on);$(this,Fr,new Set);this.options=n,z(this,Be,t),z(this,ln,null),z(this,Ft,go()),this.bindMethods(),this.setOptions(n)}bindMethods(){this.refetch=this.refetch.bind(this)}onSubscribe(){this.listeners.size===1&&(y(this,G).addObserver(this),cd(y(this,G),this.options)?W(this,te,ys).call(this):this.updateResult(),W(this,te,No).call(this))}onUnsubscribe(){this.hasListeners()||this.destroy()}shouldFetchOnReconnect(){return Eo(y(this,G),this.options,this.options.refetchOnReconnect)}shouldFetchOnWindowFocus(){return Eo(y(this,G),this.options,this.options.refetchOnWindowFocus)}destroy(){this.listeners=new Set,W(this,te,bo).call(this),W(this,te,Co).call(this),y(this,G).removeObserver(this)}setOptions(t){const n=this.options,r=y(this,G);if(this.options=y(this,Be).defaultQueryOptions(t),this.options.enabled!==void 0&&typeof this.options.enabled!="boolean"&&typeof this.options.enabled!="function"&&typeof st(this.options.enabled,y(this,G))!="boolean")throw new Error("Expected enabled to be a boolean or a callback that returns a boolean");W(this,te,_o).call(this),y(this,G).setOptions(this.options),n._defaulted&&!pi(this.options,n)&&y(this,Be).getQueryCache().notify({type:"observerOptionsUpdated",query:y(this,G),observer:this});const s=this.hasListeners();s&&dd(y(this,G),r,this.options,n)&&W(this,te,ys).call(this),this.updateResult(),s&&(y(this,G)!==r||st(this.options.enabled,y(this,G))!==st(n.enabled,y(this,G))||Cn(this.options.staleTime,y(this,G))!==Cn(n.staleTime,y(this,G)))&&W(this,te,wo).call(this);const a=W(this,te,ko).call(this);s&&(y(this,G)!==r||st(this.options.enabled,y(this,G))!==st(n.enabled,y(this,G))||a!==y(this,on))&&W(this,te,So).call(this,a)}getOptimisticResult(t){const n=y(this,Be).getQueryCache().build(y(this,Be),t),r=this.createResult(n,t);return Dx(this,r)&&(z(this,Fe,r),z(this,Rr,this.options),z(this,Kn,y(this,G).state)),r}getCurrentResult(){return y(this,Fe)}trackResult(t,n){return new Proxy(t,{get:(r,s)=>(this.trackProp(s),n==null||n(s),s==="promise"&&(this.trackProp("data"),!this.options.experimental_prefetchInRender&&y(this,Ft).status==="pending"&&y(this,Ft).reject(new Error("experimental_prefetchInRender feature flag is not enabled"))),Reflect.get(r,s))})}trackProp(t){y(this,Fr).add(t)}getCurrentQuery(){return y(this,G)}refetch({...t}={}){return this.fetch({...t})}fetchOptimistic(t){const n=y(this,Be).defaultQueryOptions(t),r=y(this,Be).getQueryCache().build(y(this,Be),n);return r.fetch().then(()=>this.createResult(r,n))}fetch(t){return W(this,te,ys).call(this,{...t,cancelRefetch:t.cancelRefetch??!0}).then(()=>(this.updateResult(),y(this,Fe)))}createResult(t,n){var F;const r=y(this,G),s=this.options,a=y(this,Fe),l=y(this,Kn),o=y(this,Rr),c=t!==r?t.state:y(this,ea),{state:h}=t;let d={...h},m=!1,x;if(n._optimisticResults){const P=this.hasListeners(),B=!P&&cd(t,n),D=P&&dd(t,r,n,s);(B||D)&&(d={...d,...cm(h.data,t.options)}),n._optimisticResults==="isRestoring"&&(d.fetchStatus="idle")}let{error:k,errorUpdatedAt:g,status:j}=d;x=d.data;let p=!1;if(n.placeholderData!==void 0&&x===void 0&&j==="pending"){let P;a!=null&&a.isPlaceholderData&&n.placeholderData===(o==null?void 0:o.placeholderData)?(P=a.data,p=!0):P=typeof n.placeholderData=="function"?n.placeholderData((F=y(this,zr))==null?void 0:F.state.data,y(this,zr)):n.placeholderData,P!==void 0&&(j="success",x=yo(a==null?void 0:a.data,P,n),m=!0)}if(n.select&&x!==void 0&&!p)if(a&&x===(l==null?void 0:l.data)&&n.select===y(this,ta))x=y(this,Mr);else try{z(this,ta,n.select),x=n.select(x),x=yo(a==null?void 0:a.data,x,n),z(this,Mr,x),z(this,ln,null)}catch(P){z(this,ln,P)}y(this,ln)&&(k=y(this,ln),x=y(this,Mr),g=Date.now(),j="error");const f=d.fetchStatus==="fetching",v=j==="pending",w=j==="error",C=v&&f,b=x!==void 0,_={status:j,fetchStatus:d.fetchStatus,isPending:v,isSuccess:j==="success",isError:w,isInitialLoading:C,isLoading:C,data:x,dataUpdatedAt:d.dataUpdatedAt,error:k,errorUpdatedAt:g,failureCount:d.fetchFailureCount,failureReason:d.fetchFailureReason,errorUpdateCount:d.errorUpdateCount,isFetched:d.dataUpdateCount>0||d.errorUpdateCount>0,isFetchedAfterMount:d.dataUpdateCount>c.dataUpdateCount||d.errorUpdateCount>c.errorUpdateCount,isFetching:f,isRefetching:f&&!v,isLoadingError:w&&!b,isPaused:d.fetchStatus==="paused",isPlaceholderData:m,isRefetchError:w&&b,isStale:Du(t,n),refetch:this.refetch,promise:y(this,Ft),isEnabled:st(n.enabled,t)!==!1};if(this.options.experimental_prefetchInRender){const P=_.data!==void 0,B=_.status==="error"&&!P,D=je=>{B?je.reject(_.error):P&&je.resolve(_.data)},U=()=>{const je=z(this,Ft,_.promise=go());D(je)},ne=y(this,Ft);switch(ne.status){case"pending":t.queryHash===r.queryHash&&D(ne);break;case"fulfilled":(B||_.data!==ne.value)&&U();break;case"rejected":(!B||_.error!==ne.reason)&&U();break}}return _}updateResult(){const t=y(this,Fe),n=this.createResult(y(this,G),this.options);if(z(this,Kn,y(this,G).state),z(this,Rr,this.options),y(this,Kn).data!==void 0&&z(this,zr,y(this,G)),pi(n,t))return;z(this,Fe,n);const r=()=>{if(!t)return!0;const{notifyOnChangeProps:s}=this.options,a=typeof s=="function"?s():s;if(a==="all"||!a&&!y(this,Fr).size)return!0;const l=new Set(a??y(this,Fr));return this.options.throwOnError&&l.add("error"),Object.keys(y(this,Fe)).some(o=>{const u=o;return y(this,Fe)[u]!==t[u]&&l.has(u)})};W(this,te,dm).call(this,{listeners:r()})}onQueryUpdate(){this.updateResult(),this.hasListeners()&&W(this,te,No).call(this)}},Be=new WeakMap,G=new WeakMap,ea=new WeakMap,Fe=new WeakMap,Kn=new WeakMap,Rr=new WeakMap,Ft=new WeakMap,ln=new WeakMap,ta=new WeakMap,Mr=new WeakMap,zr=new WeakMap,Hn=new WeakMap,Wn=new WeakMap,on=new WeakMap,Fr=new WeakMap,te=new WeakSet,ys=function(t){W(this,te,_o).call(this);let n=y(this,G).fetch(this.options,t);return t!=null&&t.throwOnError||(n=n.catch(De)),n},wo=function(){W(this,te,bo).call(this);const t=Cn(this.options.staleTime,y(this,G));if(rr||y(this,Fe).isStale||!vo(t))return;const r=sm(y(this,Fe).dataUpdatedAt,t)+1;z(this,Hn,An.setTimeout(()=>{y(this,Fe).isStale||this.updateResult()},r))},ko=function(){return(typeof this.options.refetchInterval=="function"?this.options.refetchInterval(y(this,G)):this.options.refetchInterval)??!1},So=function(t){W(this,te,Co).call(this),z(this,on,t),!(rr||st(this.options.enabled,y(this,G))===!1||!vo(y(this,on))||y(this,on)===0)&&z(this,Wn,An.setInterval(()=>{(this.options.refetchIntervalInBackground||Iu.isFocused())&&W(this,te,ys).call(this)},y(this,on)))},No=function(){W(this,te,wo).call(this),W(this,te,So).call(this,W(this,te,ko).call(this))},bo=function(){y(this,Hn)&&(An.clearTimeout(y(this,Hn)),z(this,Hn,void 0))},Co=function(){y(this,Wn)&&(An.clearInterval(y(this,Wn)),z(this,Wn,void 0))},_o=function(){const t=y(this,Be).getQueryCache().build(y(this,Be),this.options);if(t===y(this,G))return;const n=y(this,G);z(this,G,t),z(this,ea,t.state),this.hasListeners()&&(n==null||n.removeObserver(this),t.addObserver(this))},dm=function(t){ke.batch(()=>{t.listeners&&this.listeners.forEach(n=>{n(y(this,Fe))}),y(this,Be).getQueryCache().notify({query:y(this,G),type:"observerResultsUpdated"})})},Dd);function Ix(e,t){return st(t.enabled,e)!==!1&&e.state.data===void 0&&!(e.state.status==="error"&&t.retryOnMount===!1)}function cd(e,t){return Ix(e,t)||e.state.data!==void 0&&Eo(e,t,t.refetchOnMount)}function Eo(e,t,n){if(st(t.enabled,e)!==!1&&Cn(t.staleTime,e)!=="static"){const r=typeof n=="function"?n(e):n;return r==="always"||r!==!1&&Du(e,t)}return!1}function dd(e,t,n,r){return(e!==t||st(r.enabled,e)===!1)&&(!n.suspense||e.state.status!=="error")&&Du(e,n)}function Du(e,t){return st(t.enabled,e)!==!1&&e.isStaleByTime(Cn(t.staleTime,e))}function Dx(e,t){return!pi(e.getCurrentResult(),t)}function fd(e){return{onFetch:(t,n)=>{var h,d,m,x,k;const r=t.options,s=(m=(d=(h=t.fetchOptions)==null?void 0:h.meta)==null?void 0:d.fetchMore)==null?void 0:m.direction,a=((x=t.state.data)==null?void 0:x.pages)||[],l=((k=t.state.data)==null?void 0:k.pageParams)||[];let o={pages:[],pageParams:[]},u=0;const c=async()=>{let g=!1;const j=v=>{Px(v,()=>t.signal,()=>g=!0)},p=im(t.options,t.fetchOptions),f=async(v,w,C)=>{if(g)return Promise.reject();if(w==null&&v.pages.length)return Promise.resolve(v);const N=(()=>{const B={client:t.client,queryKey:t.queryKey,pageParam:w,direction:C?"backward":"forward",meta:t.options.meta};return j(B),B})(),_=await p(N),{maxPages:F}=t.options,P=C?Ex:_x;return{pages:P(v.pages,_,F),pageParams:P(v.pageParams,w,F)}};if(s&&a.length){const v=s==="backward",w=v?Ax:hd,C={pages:a,pageParams:l},b=w(r,C);o=await f(C,b,v)}else{const v=e??a.length;do{const w=u===0?l[0]??r.initialPageParam:hd(r,o);if(u>0&&w==null)break;o=await f(o,w),u++}while(u{var g,j;return(j=(g=t.options).persister)==null?void 0:j.call(g,c,{client:t.client,queryKey:t.queryKey,meta:t.options.meta,signal:t.signal},n)}:t.fetchFn=c}}}function hd(e,{pages:t,pageParams:n}){const r=t.length-1;return t.length>0?e.getNextPageParam(t[r],t,n[r],n):void 0}function Ax(e,{pages:t,pageParams:n}){var r;return t.length>0?(r=e.getPreviousPageParam)==null?void 0:r.call(e,t[0],t,n[0],n):void 0}var na,Nt,Re,qn,bt,Xt,Ad,$x=(Ad=class extends um{constructor(t){super();$(this,bt);$(this,na);$(this,Nt);$(this,Re);$(this,qn);z(this,na,t.client),this.mutationId=t.mutationId,z(this,Re,t.mutationCache),z(this,Nt,[]),this.state=t.state||fm(),this.setOptions(t.options),this.scheduleGc()}setOptions(t){this.options=t,this.updateGcTime(this.options.gcTime)}get meta(){return this.options.meta}addObserver(t){y(this,Nt).includes(t)||(y(this,Nt).push(t),this.clearGcTimeout(),y(this,Re).notify({type:"observerAdded",mutation:this,observer:t}))}removeObserver(t){z(this,Nt,y(this,Nt).filter(n=>n!==t)),this.scheduleGc(),y(this,Re).notify({type:"observerRemoved",mutation:this,observer:t})}optionalRemove(){y(this,Nt).length||(this.state.status==="pending"?this.scheduleGc():y(this,Re).remove(this))}continue(){var t;return((t=y(this,qn))==null?void 0:t.continue())??this.execute(this.state.variables)}async execute(t){var l,o,u,c,h,d,m,x,k,g,j,p,f,v,w,C,b,N;const n=()=>{W(this,bt,Xt).call(this,{type:"continue"})},r={client:y(this,na),meta:this.options.meta,mutationKey:this.options.mutationKey};z(this,qn,om({fn:()=>this.options.mutationFn?this.options.mutationFn(t,r):Promise.reject(new Error("No mutationFn found")),onFail:(_,F)=>{W(this,bt,Xt).call(this,{type:"failed",failureCount:_,error:F})},onPause:()=>{W(this,bt,Xt).call(this,{type:"pause"})},onContinue:n,retry:this.options.retry??0,retryDelay:this.options.retryDelay,networkMode:this.options.networkMode,canRun:()=>y(this,Re).canRun(this)}));const s=this.state.status==="pending",a=!y(this,qn).canStart();try{if(s)n();else{W(this,bt,Xt).call(this,{type:"pending",variables:t,isPaused:a}),y(this,Re).config.onMutate&&await y(this,Re).config.onMutate(t,this,r);const F=await((o=(l=this.options).onMutate)==null?void 0:o.call(l,t,r));F!==this.state.context&&W(this,bt,Xt).call(this,{type:"pending",context:F,variables:t,isPaused:a})}const _=await y(this,qn).start();return await((c=(u=y(this,Re).config).onSuccess)==null?void 0:c.call(u,_,t,this.state.context,this,r)),await((d=(h=this.options).onSuccess)==null?void 0:d.call(h,_,t,this.state.context,r)),await((x=(m=y(this,Re).config).onSettled)==null?void 0:x.call(m,_,null,this.state.variables,this.state.context,this,r)),await((g=(k=this.options).onSettled)==null?void 0:g.call(k,_,null,t,this.state.context,r)),W(this,bt,Xt).call(this,{type:"success",data:_}),_}catch(_){try{await((p=(j=y(this,Re).config).onError)==null?void 0:p.call(j,_,t,this.state.context,this,r))}catch(F){Promise.reject(F)}try{await((v=(f=this.options).onError)==null?void 0:v.call(f,_,t,this.state.context,r))}catch(F){Promise.reject(F)}try{await((C=(w=y(this,Re).config).onSettled)==null?void 0:C.call(w,void 0,_,this.state.variables,this.state.context,this,r))}catch(F){Promise.reject(F)}try{await((N=(b=this.options).onSettled)==null?void 0:N.call(b,void 0,_,t,this.state.context,r))}catch(F){Promise.reject(F)}throw W(this,bt,Xt).call(this,{type:"error",error:_}),_}finally{y(this,Re).runNext(this)}}},na=new WeakMap,Nt=new WeakMap,Re=new WeakMap,qn=new WeakMap,bt=new WeakSet,Xt=function(t){const n=r=>{switch(t.type){case"failed":return{...r,failureCount:t.failureCount,failureReason:t.error};case"pause":return{...r,isPaused:!0};case"continue":return{...r,isPaused:!1};case"pending":return{...r,context:t.context,data:void 0,failureCount:0,failureReason:null,error:null,isPaused:t.isPaused,status:"pending",variables:t.variables,submittedAt:Date.now()};case"success":return{...r,data:t.data,failureCount:0,failureReason:null,error:null,status:"success",isPaused:!1};case"error":return{...r,data:void 0,error:t.error,failureCount:r.failureCount+1,failureReason:t.error,isPaused:!1,status:"error"}}};this.state=n(this.state),ke.batch(()=>{y(this,Nt).forEach(r=>{r.onMutationUpdate(t)}),y(this,Re).notify({mutation:this,type:"updated",action:t})})},Ad);function fm(){return{context:void 0,data:void 0,error:null,failureCount:0,failureReason:null,isPaused:!1,status:"idle",variables:void 0,submittedAt:0}}var It,pt,ra,$d,Ux=($d=class extends Zr{constructor(t={}){super();$(this,It);$(this,pt);$(this,ra);this.config=t,z(this,It,new Set),z(this,pt,new Map),z(this,ra,0)}build(t,n,r){const s=new $x({client:t,mutationCache:this,mutationId:++da(this,ra)._,options:t.defaultMutationOptions(n),state:r});return this.add(s),s}add(t){y(this,It).add(t);const n=Pa(t);if(typeof n=="string"){const r=y(this,pt).get(n);r?r.push(t):y(this,pt).set(n,[t])}this.notify({type:"added",mutation:t})}remove(t){if(y(this,It).delete(t)){const n=Pa(t);if(typeof n=="string"){const r=y(this,pt).get(n);if(r)if(r.length>1){const s=r.indexOf(t);s!==-1&&r.splice(s,1)}else r[0]===t&&y(this,pt).delete(n)}}this.notify({type:"removed",mutation:t})}canRun(t){const n=Pa(t);if(typeof n=="string"){const r=y(this,pt).get(n),s=r==null?void 0:r.find(a=>a.state.status==="pending");return!s||s===t}else return!0}runNext(t){var r;const n=Pa(t);if(typeof n=="string"){const s=(r=y(this,pt).get(n))==null?void 0:r.find(a=>a!==t&&a.state.isPaused);return(s==null?void 0:s.continue())??Promise.resolve()}else return Promise.resolve()}clear(){ke.batch(()=>{y(this,It).forEach(t=>{this.notify({type:"removed",mutation:t})}),y(this,It).clear(),y(this,pt).clear()})}getAll(){return Array.from(y(this,It))}find(t){const n={exact:!0,...t};return this.getAll().find(r=>ad(n,r))}findAll(t={}){return this.getAll().filter(n=>ad(t,n))}notify(t){ke.batch(()=>{this.listeners.forEach(n=>{n(t)})})}resumePausedMutations(){const t=this.getAll().filter(n=>n.state.isPaused);return ke.batch(()=>Promise.all(t.map(n=>n.continue().catch(De))))}},It=new WeakMap,pt=new WeakMap,ra=new WeakMap,$d);function Pa(e){var t;return(t=e.options.scope)==null?void 0:t.id}var Dt,un,Qe,At,Qt,Va,Po,Ud,Bx=(Ud=class extends Zr{constructor(n,r){super();$(this,Qt);$(this,Dt);$(this,un);$(this,Qe);$(this,At);z(this,Dt,n),this.setOptions(r),this.bindMethods(),W(this,Qt,Va).call(this)}bindMethods(){this.mutate=this.mutate.bind(this),this.reset=this.reset.bind(this)}setOptions(n){var s;const r=this.options;this.options=y(this,Dt).defaultMutationOptions(n),pi(this.options,r)||y(this,Dt).getMutationCache().notify({type:"observerOptionsUpdated",mutation:y(this,Qe),observer:this}),r!=null&&r.mutationKey&&this.options.mutationKey&&sr(r.mutationKey)!==sr(this.options.mutationKey)?this.reset():((s=y(this,Qe))==null?void 0:s.state.status)==="pending"&&y(this,Qe).setOptions(this.options)}onUnsubscribe(){var n;this.hasListeners()||(n=y(this,Qe))==null||n.removeObserver(this)}onMutationUpdate(n){W(this,Qt,Va).call(this),W(this,Qt,Po).call(this,n)}getCurrentResult(){return y(this,un)}reset(){var n;(n=y(this,Qe))==null||n.removeObserver(this),z(this,Qe,void 0),W(this,Qt,Va).call(this),W(this,Qt,Po).call(this)}mutate(n,r){var s;return z(this,At,r),(s=y(this,Qe))==null||s.removeObserver(this),z(this,Qe,y(this,Dt).getMutationCache().build(y(this,Dt),this.options)),y(this,Qe).addObserver(this),y(this,Qe).execute(n)}},Dt=new WeakMap,un=new WeakMap,Qe=new WeakMap,At=new WeakMap,Qt=new WeakSet,Va=function(){var r;const n=((r=y(this,Qe))==null?void 0:r.state)??fm();z(this,un,{...n,isPending:n.status==="pending",isSuccess:n.status==="success",isError:n.status==="error",isIdle:n.status==="idle",mutate:this.mutate,reset:this.reset})},Po=function(n){ke.batch(()=>{var r,s,a,l,o,u,c,h;if(y(this,At)&&this.hasListeners()){const d=y(this,un).variables,m=y(this,un).context,x={client:y(this,Dt),meta:this.options.meta,mutationKey:this.options.mutationKey};if((n==null?void 0:n.type)==="success"){try{(s=(r=y(this,At)).onSuccess)==null||s.call(r,n.data,d,m,x)}catch(k){Promise.reject(k)}try{(l=(a=y(this,At)).onSettled)==null||l.call(a,n.data,null,d,m,x)}catch(k){Promise.reject(k)}}else if((n==null?void 0:n.type)==="error"){try{(u=(o=y(this,At)).onError)==null||u.call(o,n.error,d,m,x)}catch(k){Promise.reject(k)}try{(h=(c=y(this,At)).onSettled)==null||h.call(c,void 0,n.error,d,m,x)}catch(k){Promise.reject(k)}}}this.listeners.forEach(d=>{d(y(this,un))})})},Ud),Ct,Bd,Qx=(Bd=class extends Zr{constructor(t={}){super();$(this,Ct);this.config=t,z(this,Ct,new Map)}build(t,n,r){const s=n.queryKey,a=n.queryHash??Mu(s,n);let l=this.get(a);return l||(l=new zx({client:t,queryKey:s,queryHash:a,options:t.defaultQueryOptions(n),state:r,defaultOptions:t.getQueryDefaults(s)}),this.add(l)),l}add(t){y(this,Ct).has(t.queryHash)||(y(this,Ct).set(t.queryHash,t),this.notify({type:"added",query:t}))}remove(t){const n=y(this,Ct).get(t.queryHash);n&&(t.destroy(),n===t&&y(this,Ct).delete(t.queryHash),this.notify({type:"removed",query:t}))}clear(){ke.batch(()=>{this.getAll().forEach(t=>{this.remove(t)})})}get(t){return y(this,Ct).get(t)}getAll(){return[...y(this,Ct).values()]}find(t){const n={exact:!0,...t};return this.getAll().find(r=>sd(n,r))}findAll(t={}){const n=this.getAll();return Object.keys(t).length>0?n.filter(r=>sd(t,r)):n}notify(t){ke.batch(()=>{this.listeners.forEach(n=>{n(t)})})}onFocus(){ke.batch(()=>{this.getAll().forEach(t=>{t.onFocus()})})}onOnline(){ke.batch(()=>{this.getAll().forEach(t=>{t.onOnline()})})}},Ct=new WeakMap,Bd),me,cn,dn,Ir,Dr,fn,Ar,$r,Qd,Vx=(Qd=class{constructor(e={}){$(this,me);$(this,cn);$(this,dn);$(this,Ir);$(this,Dr);$(this,fn);$(this,Ar);$(this,$r);z(this,me,e.queryCache||new Qx),z(this,cn,e.mutationCache||new Ux),z(this,dn,e.defaultOptions||{}),z(this,Ir,new Map),z(this,Dr,new Map),z(this,fn,0)}mount(){da(this,fn)._++,y(this,fn)===1&&(z(this,Ar,Iu.subscribe(async e=>{e&&(await this.resumePausedMutations(),y(this,me).onFocus())})),z(this,$r,vi.subscribe(async e=>{e&&(await this.resumePausedMutations(),y(this,me).onOnline())})))}unmount(){var e,t;da(this,fn)._--,y(this,fn)===0&&((e=y(this,Ar))==null||e.call(this),z(this,Ar,void 0),(t=y(this,$r))==null||t.call(this),z(this,$r,void 0))}isFetching(e){return y(this,me).findAll({...e,fetchStatus:"fetching"}).length}isMutating(e){return y(this,cn).findAll({...e,status:"pending"}).length}getQueryData(e){var n;const t=this.defaultQueryOptions({queryKey:e});return(n=y(this,me).get(t.queryHash))==null?void 0:n.state.data}ensureQueryData(e){const t=this.defaultQueryOptions(e),n=y(this,me).build(this,t),r=n.state.data;return r===void 0?this.fetchQuery(e):(e.revalidateIfStale&&n.isStaleByTime(Cn(t.staleTime,n))&&this.prefetchQuery(t),Promise.resolve(r))}getQueriesData(e){return y(this,me).findAll(e).map(({queryKey:t,state:n})=>{const r=n.data;return[t,r]})}setQueryData(e,t,n){const r=this.defaultQueryOptions({queryKey:e}),s=y(this,me).get(r.queryHash),a=s==null?void 0:s.state.data,l=Nx(t,a);if(l!==void 0)return y(this,me).build(this,r).setData(l,{...n,manual:!0})}setQueriesData(e,t,n){return ke.batch(()=>y(this,me).findAll(e).map(({queryKey:r})=>[r,this.setQueryData(r,t,n)]))}getQueryState(e){var n;const t=this.defaultQueryOptions({queryKey:e});return(n=y(this,me).get(t.queryHash))==null?void 0:n.state}removeQueries(e){const t=y(this,me);ke.batch(()=>{t.findAll(e).forEach(n=>{t.remove(n)})})}resetQueries(e,t){const n=y(this,me);return ke.batch(()=>(n.findAll(e).forEach(r=>{r.reset()}),this.refetchQueries({type:"active",...e},t)))}cancelQueries(e,t={}){const n={revert:!0,...t},r=ke.batch(()=>y(this,me).findAll(e).map(s=>s.cancel(n)));return Promise.all(r).then(De).catch(De)}invalidateQueries(e,t={}){return ke.batch(()=>(y(this,me).findAll(e).forEach(n=>{n.invalidate()}),(e==null?void 0:e.refetchType)==="none"?Promise.resolve():this.refetchQueries({...e,type:(e==null?void 0:e.refetchType)??(e==null?void 0:e.type)??"active"},t)))}refetchQueries(e,t={}){const n={...t,cancelRefetch:t.cancelRefetch??!0},r=ke.batch(()=>y(this,me).findAll(e).filter(s=>!s.isDisabled()&&!s.isStatic()).map(s=>{let a=s.fetch(void 0,n);return n.throwOnError||(a=a.catch(De)),s.state.fetchStatus==="paused"?Promise.resolve():a}));return Promise.all(r).then(De)}fetchQuery(e){const t=this.defaultQueryOptions(e);t.retry===void 0&&(t.retry=!1);const n=y(this,me).build(this,t);return n.isStaleByTime(Cn(t.staleTime,n))?n.fetch(t):Promise.resolve(n.state.data)}prefetchQuery(e){return this.fetchQuery(e).then(De).catch(De)}fetchInfiniteQuery(e){return e.behavior=fd(e.pages),this.fetchQuery(e)}prefetchInfiniteQuery(e){return this.fetchInfiniteQuery(e).then(De).catch(De)}ensureInfiniteQueryData(e){return e.behavior=fd(e.pages),this.ensureQueryData(e)}resumePausedMutations(){return vi.isOnline()?y(this,cn).resumePausedMutations():Promise.resolve()}getQueryCache(){return y(this,me)}getMutationCache(){return y(this,cn)}getDefaultOptions(){return y(this,dn)}setDefaultOptions(e){z(this,dn,e)}setQueryDefaults(e,t){y(this,Ir).set(sr(e),{queryKey:e,defaultOptions:t})}getQueryDefaults(e){const t=[...y(this,Ir).values()],n={};return t.forEach(r=>{Hs(e,r.queryKey)&&Object.assign(n,r.defaultOptions)}),n}setMutationDefaults(e,t){y(this,Dr).set(sr(e),{mutationKey:e,defaultOptions:t})}getMutationDefaults(e){const t=[...y(this,Dr).values()],n={};return t.forEach(r=>{Hs(e,r.mutationKey)&&Object.assign(n,r.defaultOptions)}),n}defaultQueryOptions(e){if(e._defaulted)return e;const t={...y(this,dn).queries,...this.getQueryDefaults(e.queryKey),...e,_defaulted:!0};return t.queryHash||(t.queryHash=Mu(t.queryKey,t)),t.refetchOnReconnect===void 0&&(t.refetchOnReconnect=t.networkMode!=="always"),t.throwOnError===void 0&&(t.throwOnError=!!t.suspense),!t.networkMode&&t.persister&&(t.networkMode="offlineFirst"),t.queryFn===zu&&(t.enabled=!1),t}defaultMutationOptions(e){return e!=null&&e._defaulted?e:{...y(this,dn).mutations,...(e==null?void 0:e.mutationKey)&&this.getMutationDefaults(e.mutationKey),...e,_defaulted:!0}}clear(){y(this,me).clear(),y(this,cn).clear()}},me=new WeakMap,cn=new WeakMap,dn=new WeakMap,Ir=new WeakMap,Dr=new WeakMap,fn=new WeakMap,Ar=new WeakMap,$r=new WeakMap,Qd),hm=S.createContext(void 0),Jt=e=>{const t=S.useContext(hm);if(!t)throw new Error("No QueryClient set, use QueryClientProvider to set one");return t},Kx=({client:e,children:t})=>(S.useEffect(()=>(e.mount(),()=>{e.unmount()}),[e]),i.jsx(hm.Provider,{value:e,children:t})),mm=S.createContext(!1),Hx=()=>S.useContext(mm);mm.Provider;function Wx(){let e=!1;return{clearReset:()=>{e=!1},reset:()=>{e=!0},isReset:()=>e}}var qx=S.createContext(Wx()),Jx=()=>S.useContext(qx),Gx=(e,t,n)=>{const r=n!=null&&n.state.error&&typeof e.throwOnError=="function"?Fu(e.throwOnError,[n.state.error,n]):e.throwOnError;(e.suspense||e.experimental_prefetchInRender||r)&&(t.isReset()||(e.retryOnMount=!1))},Yx=e=>{S.useEffect(()=>{e.clearReset()},[e])},Xx=({result:e,errorResetBoundary:t,throwOnError:n,query:r,suspense:s})=>e.isError&&!t.isReset()&&!e.isFetching&&r&&(s&&e.data===void 0||Fu(n,[e.error,r])),Zx=e=>{if(e.suspense){const n=s=>s==="static"?s:Math.max(s??1e3,1e3),r=e.staleTime;e.staleTime=typeof r=="function"?(...s)=>n(r(...s)):n(r),typeof e.gcTime=="number"&&(e.gcTime=Math.max(e.gcTime,1e3))}},ey=(e,t)=>e.isLoading&&e.isFetching&&!t,ty=(e,t)=>(e==null?void 0:e.suspense)&&t.isPending,md=(e,t,n)=>t.fetchOptimistic(e).catch(()=>{n.clearReset()});function ny(e,t,n){var m,x,k,g;const r=Hx(),s=Jx(),a=Jt(),l=a.defaultQueryOptions(e);(x=(m=a.getDefaultOptions().queries)==null?void 0:m._experimental_beforeQuery)==null||x.call(m,l);const o=a.getQueryCache().get(l.queryHash);l._optimisticResults=r?"isRestoring":"optimistic",Zx(l),Gx(l,s,o),Yx(s);const u=!a.getQueryCache().get(l.queryHash),[c]=S.useState(()=>new t(a,l)),h=c.getOptimisticResult(l),d=!r&&e.subscribed!==!1;if(S.useSyncExternalStore(S.useCallback(j=>{const p=d?c.subscribe(ke.batchCalls(j)):De;return c.updateResult(),p},[c,d]),()=>c.getCurrentResult(),()=>c.getCurrentResult()),S.useEffect(()=>{c.setOptions(l)},[l,c]),ty(l,h))throw md(l,c,s);if(Xx({result:h,errorResetBoundary:s,throwOnError:l.throwOnError,query:o,suspense:l.suspense}))throw h.error;if((g=(k=a.getDefaultOptions().queries)==null?void 0:k._experimental_afterQuery)==null||g.call(k,l,h),l.experimental_prefetchInRender&&!rr&&ey(h,r)){const j=u?md(l,c,s):o==null?void 0:o.promise;j==null||j.catch(De).finally(()=>{c.updateResult()})}return l.notifyOnChangeProps?h:c.trackResult(h)}function ve(e,t){return ny(e,Fx)}function Je(e,t){const n=Jt(),[r]=S.useState(()=>new Bx(n,e));S.useEffect(()=>{r.setOptions(e)},[r,e]);const s=S.useSyncExternalStore(S.useCallback(l=>r.subscribe(ke.batchCalls(l)),[r]),()=>r.getCurrentResult(),()=>r.getCurrentResult()),a=S.useCallback((l,o)=>{r.mutate(l,o).catch(De)},[r]);if(s.error&&Fu(r.options.throwOnError,[s.error]))throw s.error;return{...s,mutate:a,mutateAsync:s.mutate}}/** + * @remix-run/router v1.23.2 + * + * Copyright (c) Remix Software Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE.md file in the root directory of this source tree. + * + * @license MIT + */function Ws(){return Ws=Object.assign?Object.assign.bind():function(e){for(var t=1;t"u")throw new Error(t)}function Au(e,t){if(!e){typeof console<"u"&&console.warn(t);try{throw new Error(t)}catch{}}}function sy(){return Math.random().toString(36).substr(2,8)}function vd(e,t){return{usr:e.state,key:e.key,idx:t}}function To(e,t,n,r){return n===void 0&&(n=null),Ws({pathname:typeof e=="string"?e:e.pathname,search:"",hash:""},typeof t=="string"?es(t):t,{state:n,key:t&&t.key||r||sy()})}function xi(e){let{pathname:t="/",search:n="",hash:r=""}=e;return n&&n!=="?"&&(t+=n.charAt(0)==="?"?n:"?"+n),r&&r!=="#"&&(t+=r.charAt(0)==="#"?r:"#"+r),t}function es(e){let t={};if(e){let n=e.indexOf("#");n>=0&&(t.hash=e.substr(n),e=e.substr(0,n));let r=e.indexOf("?");r>=0&&(t.search=e.substr(r),e=e.substr(0,r)),e&&(t.pathname=e)}return t}function ay(e,t,n,r){r===void 0&&(r={});let{window:s=document.defaultView,v5Compat:a=!1}=r,l=s.history,o=pn.Pop,u=null,c=h();c==null&&(c=0,l.replaceState(Ws({},l.state,{idx:c}),""));function h(){return(l.state||{idx:null}).idx}function d(){o=pn.Pop;let j=h(),p=j==null?null:j-c;c=j,u&&u({action:o,location:g.location,delta:p})}function m(j,p){o=pn.Push;let f=To(g.location,j,p);c=h()+1;let v=vd(f,c),w=g.createHref(f);try{l.pushState(v,"",w)}catch(C){if(C instanceof DOMException&&C.name==="DataCloneError")throw C;s.location.assign(w)}a&&u&&u({action:o,location:g.location,delta:1})}function x(j,p){o=pn.Replace;let f=To(g.location,j,p);c=h();let v=vd(f,c),w=g.createHref(f);l.replaceState(v,"",w),a&&u&&u({action:o,location:g.location,delta:0})}function k(j){let p=s.location.origin!=="null"?s.location.origin:s.location.href,f=typeof j=="string"?j:xi(j);return f=f.replace(/ $/,"%20"),xe(p,"No window.location.(origin|href) available to create URL for href: "+f),new URL(f,p)}let g={get action(){return o},get location(){return e(s,l)},listen(j){if(u)throw new Error("A history only accepts one active listener");return s.addEventListener(pd,d),u=j,()=>{s.removeEventListener(pd,d),u=null}},createHref(j){return t(s,j)},createURL:k,encodeLocation(j){let p=k(j);return{pathname:p.pathname,search:p.search,hash:p.hash}},push:m,replace:x,go(j){return l.go(j)}};return g}var xd;(function(e){e.data="data",e.deferred="deferred",e.redirect="redirect",e.error="error"})(xd||(xd={}));function iy(e,t,n){return n===void 0&&(n="/"),ly(e,t,n)}function ly(e,t,n,r){let s=typeof t=="string"?es(t):t,a=qr(s.pathname||"/",n);if(a==null)return null;let l=pm(e);oy(l);let o=null;for(let u=0;o==null&&u{let u={relativePath:o===void 0?a.path||"":o,caseSensitive:a.caseSensitive===!0,childrenIndex:l,route:a};u.relativePath.startsWith("/")&&(xe(u.relativePath.startsWith(r),'Absolute route path "'+u.relativePath+'" nested under path '+('"'+r+'" is not valid. An absolute child route path ')+"must start with the combined path of all its parent routes."),u.relativePath=u.relativePath.slice(r.length));let c=_n([r,u.relativePath]),h=n.concat(u);a.children&&a.children.length>0&&(xe(a.index!==!0,"Index routes must not have child routes. Please remove "+('all child routes from route path "'+c+'".')),pm(a.children,t,h,c)),!(a.path==null&&!a.index)&&t.push({path:c,score:py(c,a.index),routesMeta:h})};return e.forEach((a,l)=>{var o;if(a.path===""||!((o=a.path)!=null&&o.includes("?")))s(a,l);else for(let u of vm(a.path))s(a,l,u)}),t}function vm(e){let t=e.split("/");if(t.length===0)return[];let[n,...r]=t,s=n.endsWith("?"),a=n.replace(/\?$/,"");if(r.length===0)return s?[a,""]:[a];let l=vm(r.join("/")),o=[];return o.push(...l.map(u=>u===""?a:[a,u].join("/"))),s&&o.push(...l),o.map(u=>e.startsWith("/")&&u===""?"/":u)}function oy(e){e.sort((t,n)=>t.score!==n.score?n.score-t.score:vy(t.routesMeta.map(r=>r.childrenIndex),n.routesMeta.map(r=>r.childrenIndex)))}const uy=/^:[\w-]+$/,cy=3,dy=2,fy=1,hy=10,my=-2,yd=e=>e==="*";function py(e,t){let n=e.split("/"),r=n.length;return n.some(yd)&&(r+=my),t&&(r+=dy),n.filter(s=>!yd(s)).reduce((s,a)=>s+(uy.test(a)?cy:a===""?fy:hy),r)}function vy(e,t){return e.length===t.length&&e.slice(0,-1).every((r,s)=>r===t[s])?e[e.length-1]-t[t.length-1]:0}function xy(e,t,n){let{routesMeta:r}=e,s={},a="/",l=[];for(let o=0;o{let{paramName:m,isOptional:x}=h;if(m==="*"){let g=o[d]||"";l=a.slice(0,a.length-g.length).replace(/(.)\/+$/,"$1")}const k=o[d];return x&&!k?c[m]=void 0:c[m]=(k||"").replace(/%2F/g,"/"),c},{}),pathname:a,pathnameBase:l,pattern:e}}function yy(e,t,n){t===void 0&&(t=!1),n===void 0&&(n=!0),Au(e==="*"||!e.endsWith("*")||e.endsWith("/*"),'Route path "'+e+'" will be treated as if it were '+('"'+e.replace(/\*$/,"/*")+'" because the `*` character must ')+"always follow a `/` in the pattern. To get rid of this warning, "+('please change the route path to "'+e.replace(/\*$/,"/*")+'".'));let r=[],s="^"+e.replace(/\/*\*?$/,"").replace(/^\/*/,"/").replace(/[\\.*+^${}|()[\]]/g,"\\$&").replace(/\/:([\w-]+)(\?)?/g,(l,o,u)=>(r.push({paramName:o,isOptional:u!=null}),u?"/?([^\\/]+)?":"/([^\\/]+)"));return e.endsWith("*")?(r.push({paramName:"*"}),s+=e==="*"||e==="/*"?"(.*)$":"(?:\\/(.+)|\\/*)$"):n?s+="\\/*$":e!==""&&e!=="/"&&(s+="(?:(?=\\/|$))"),[new RegExp(s,t?void 0:"i"),r]}function gy(e){try{return e.split("/").map(t=>decodeURIComponent(t).replace(/\//g,"%2F")).join("/")}catch(t){return Au(!1,'The URL path "'+e+'" could not be decoded because it is is a malformed URL segment. This is probably due to a bad percent '+("encoding ("+t+").")),e}}function qr(e,t){if(t==="/")return e;if(!e.toLowerCase().startsWith(t.toLowerCase()))return null;let n=t.endsWith("/")?t.length-1:t.length,r=e.charAt(n);return r&&r!=="/"?null:e.slice(n)||"/"}const jy=/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i,wy=e=>jy.test(e);function ky(e,t){t===void 0&&(t="/");let{pathname:n,search:r="",hash:s=""}=typeof e=="string"?es(e):e,a;if(n)if(wy(n))a=n;else{if(n.includes("//")){let l=n;n=n.replace(/\/\/+/g,"/"),Au(!1,"Pathnames cannot have embedded double slashes - normalizing "+(l+" -> "+n))}n.startsWith("/")?a=gd(n.substring(1),"/"):a=gd(n,t)}else a=t;return{pathname:a,search:by(r),hash:Cy(s)}}function gd(e,t){let n=t.replace(/\/+$/,"").split("/");return e.split("/").forEach(s=>{s===".."?n.length>1&&n.pop():s!=="."&&n.push(s)}),n.length>1?n.join("/"):"/"}function yl(e,t,n,r){return"Cannot include a '"+e+"' character in a manually specified "+("`to."+t+"` field ["+JSON.stringify(r)+"]. Please separate it out to the ")+("`to."+n+"` field. Alternatively you may provide the full path as ")+'a string in and the router will parse it for you.'}function Sy(e){return e.filter((t,n)=>n===0||t.route.path&&t.route.path.length>0)}function xm(e,t){let n=Sy(e);return t?n.map((r,s)=>s===n.length-1?r.pathname:r.pathnameBase):n.map(r=>r.pathnameBase)}function ym(e,t,n,r){r===void 0&&(r=!1);let s;typeof e=="string"?s=es(e):(s=Ws({},e),xe(!s.pathname||!s.pathname.includes("?"),yl("?","pathname","search",s)),xe(!s.pathname||!s.pathname.includes("#"),yl("#","pathname","hash",s)),xe(!s.search||!s.search.includes("#"),yl("#","search","hash",s)));let a=e===""||s.pathname==="",l=a?"/":s.pathname,o;if(l==null)o=n;else{let d=t.length-1;if(!r&&l.startsWith("..")){let m=l.split("/");for(;m[0]==="..";)m.shift(),d-=1;s.pathname=m.join("/")}o=d>=0?t[d]:"/"}let u=ky(s,o),c=l&&l!=="/"&&l.endsWith("/"),h=(a||l===".")&&n.endsWith("/");return!u.pathname.endsWith("/")&&(c||h)&&(u.pathname+="/"),u}const _n=e=>e.join("/").replace(/\/\/+/g,"/"),Ny=e=>e.replace(/\/+$/,"").replace(/^\/*/,"/"),by=e=>!e||e==="?"?"":e.startsWith("?")?e:"?"+e,Cy=e=>!e||e==="#"?"":e.startsWith("#")?e:"#"+e;function _y(e){return e!=null&&typeof e.status=="number"&&typeof e.statusText=="string"&&typeof e.internal=="boolean"&&"data"in e}const gm=["post","put","patch","delete"];new Set(gm);const Ey=["get",...gm];new Set(Ey);/** + * React Router v6.30.3 + * + * Copyright (c) Remix Software Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE.md file in the root directory of this source tree. + * + * @license MIT + */function qs(){return qs=Object.assign?Object.assign.bind():function(e){for(var t=1;t{o.current=!0}),S.useCallback(function(c,h){if(h===void 0&&(h={}),!o.current)return;if(typeof c=="number"){r.go(c);return}let d=ym(c,JSON.parse(l),a,h.relative==="path");e==null&&t!=="/"&&(d.pathname=d.pathname==="/"?t:_n([t,d.pathname])),(h.replace?r.replace:r.push)(d,h.state,h)},[t,r,l,a,e])}const Oy=S.createContext(null);function Ly(e){let t=S.useContext(Gt).outlet;return t&&S.createElement(Oy.Provider,{value:e},t)}function Di(){let{matches:e}=S.useContext(Gt),t=e[e.length-1];return t?t.params:{}}function Ai(e,t){let{relative:n}=t===void 0?{}:t,{future:r}=S.useContext(Rn),{matches:s}=S.useContext(Gt),{pathname:a}=ts(),l=JSON.stringify(xm(s,r.v7_relativeSplatPath));return S.useMemo(()=>ym(e,JSON.parse(l),a,n==="path"),[e,l,a,n])}function Ry(e,t){return My(e,t)}function My(e,t,n,r){ua()||xe(!1);let{navigator:s}=S.useContext(Rn),{matches:a}=S.useContext(Gt),l=a[a.length-1],o=l?l.params:{};l&&l.pathname;let u=l?l.pathnameBase:"/";l&&l.route;let c=ts(),h;if(t){var d;let j=typeof t=="string"?es(t):t;u==="/"||(d=j.pathname)!=null&&d.startsWith(u)||xe(!1),h=j}else h=c;let m=h.pathname||"/",x=m;if(u!=="/"){let j=u.replace(/^\//,"").split("/");x="/"+m.replace(/^\//,"").split("/").slice(j.length).join("/")}let k=iy(e,{pathname:x}),g=Ay(k&&k.map(j=>Object.assign({},j,{params:Object.assign({},o,j.params),pathname:_n([u,s.encodeLocation?s.encodeLocation(j.pathname).pathname:j.pathname]),pathnameBase:j.pathnameBase==="/"?u:_n([u,s.encodeLocation?s.encodeLocation(j.pathnameBase).pathname:j.pathnameBase])})),a,n,r);return t&&g?S.createElement(Ii.Provider,{value:{location:qs({pathname:"/",search:"",hash:"",state:null,key:"default"},h),navigationType:pn.Pop}},g):g}function zy(){let e=Qy(),t=_y(e)?e.status+" "+e.statusText:e instanceof Error?e.message:JSON.stringify(e),n=e instanceof Error?e.stack:null,s={padding:"0.5rem",backgroundColor:"rgba(200,200,200, 0.5)"};return S.createElement(S.Fragment,null,S.createElement("h2",null,"Unexpected Application Error!"),S.createElement("h3",{style:{fontStyle:"italic"}},t),n?S.createElement("pre",{style:s},n):null,null)}const Fy=S.createElement(zy,null);class Iy extends S.Component{constructor(t){super(t),this.state={location:t.location,revalidation:t.revalidation,error:t.error}}static getDerivedStateFromError(t){return{error:t}}static getDerivedStateFromProps(t,n){return n.location!==t.location||n.revalidation!=="idle"&&t.revalidation==="idle"?{error:t.error,location:t.location,revalidation:t.revalidation}:{error:t.error!==void 0?t.error:n.error,location:n.location,revalidation:t.revalidation||n.revalidation}}componentDidCatch(t,n){console.error("React Router caught the following error during render",t,n)}render(){return this.state.error!==void 0?S.createElement(Gt.Provider,{value:this.props.routeContext},S.createElement(wm.Provider,{value:this.state.error,children:this.props.component})):this.props.children}}function Dy(e){let{routeContext:t,match:n,children:r}=e,s=S.useContext(Fi);return s&&s.static&&s.staticContext&&(n.route.errorElement||n.route.ErrorBoundary)&&(s.staticContext._deepestRenderedBoundaryId=n.route.id),S.createElement(Gt.Provider,{value:t},r)}function Ay(e,t,n,r){var s;if(t===void 0&&(t=[]),n===void 0&&(n=null),r===void 0&&(r=null),e==null){var a;if(!n)return null;if(n.errors)e=n.matches;else if((a=r)!=null&&a.v7_partialHydration&&t.length===0&&!n.initialized&&n.matches.length>0)e=n.matches;else return null}let l=e,o=(s=n)==null?void 0:s.errors;if(o!=null){let h=l.findIndex(d=>d.route.id&&(o==null?void 0:o[d.route.id])!==void 0);h>=0||xe(!1),l=l.slice(0,Math.min(l.length,h+1))}let u=!1,c=-1;if(n&&r&&r.v7_partialHydration)for(let h=0;h=0?l=l.slice(0,c+1):l=[l[0]];break}}}return l.reduceRight((h,d,m)=>{let x,k=!1,g=null,j=null;n&&(x=o&&d.route.id?o[d.route.id]:void 0,g=d.route.errorElement||Fy,u&&(c<0&&m===0?(Ky("route-fallback"),k=!0,j=null):c===m&&(k=!0,j=d.route.hydrateFallbackElement||null)));let p=t.concat(l.slice(0,m+1)),f=()=>{let v;return x?v=g:k?v=j:d.route.Component?v=S.createElement(d.route.Component,null):d.route.element?v=d.route.element:v=h,S.createElement(Dy,{match:d,routeContext:{outlet:h,matches:p,isDataRoute:n!=null},children:v})};return n&&(d.route.ErrorBoundary||d.route.errorElement||m===0)?S.createElement(Iy,{location:n.location,revalidation:n.revalidation,component:g,error:x,children:f(),routeContext:{outlet:null,matches:p,isDataRoute:!0}}):f()},null)}var Sm=function(e){return e.UseBlocker="useBlocker",e.UseRevalidator="useRevalidator",e.UseNavigateStable="useNavigate",e}(Sm||{}),Nm=function(e){return e.UseBlocker="useBlocker",e.UseLoaderData="useLoaderData",e.UseActionData="useActionData",e.UseRouteError="useRouteError",e.UseNavigation="useNavigation",e.UseRouteLoaderData="useRouteLoaderData",e.UseMatches="useMatches",e.UseRevalidator="useRevalidator",e.UseNavigateStable="useNavigate",e.UseRouteId="useRouteId",e}(Nm||{});function $y(e){let t=S.useContext(Fi);return t||xe(!1),t}function Uy(e){let t=S.useContext(jm);return t||xe(!1),t}function By(e){let t=S.useContext(Gt);return t||xe(!1),t}function bm(e){let t=By(),n=t.matches[t.matches.length-1];return n.route.id||xe(!1),n.route.id}function Qy(){var e;let t=S.useContext(wm),n=Uy(),r=bm();return t!==void 0?t:(e=n.errors)==null?void 0:e[r]}function Vy(){let{router:e}=$y(Sm.UseNavigateStable),t=bm(Nm.UseNavigateStable),n=S.useRef(!1);return km(()=>{n.current=!0}),S.useCallback(function(s,a){a===void 0&&(a={}),n.current&&(typeof s=="number"?e.navigate(s):e.navigate(s,qs({fromRouteId:t},a)))},[e,t])}const jd={};function Ky(e,t,n){jd[e]||(jd[e]=!0)}function Hy(e,t){e==null||e.v7_startTransition,e==null||e.v7_relativeSplatPath}function Wy(e){return Ly(e.context)}function kt(e){xe(!1)}function qy(e){let{basename:t="/",children:n=null,location:r,navigationType:s=pn.Pop,navigator:a,static:l=!1,future:o}=e;ua()&&xe(!1);let u=t.replace(/^\/*/,"/"),c=S.useMemo(()=>({basename:u,navigator:a,static:l,future:qs({v7_relativeSplatPath:!1},o)}),[u,o,a,l]);typeof r=="string"&&(r=es(r));let{pathname:h="/",search:d="",hash:m="",state:x=null,key:k="default"}=r,g=S.useMemo(()=>{let j=qr(h,u);return j==null?null:{location:{pathname:j,search:d,hash:m,state:x,key:k},navigationType:s}},[u,h,d,m,x,k,s]);return g==null?null:S.createElement(Rn.Provider,{value:c},S.createElement(Ii.Provider,{children:n,value:g}))}function Jy(e){let{children:t,location:n}=e;return Ry(Lo(t),n)}new Promise(()=>{});function Lo(e,t){t===void 0&&(t=[]);let n=[];return S.Children.forEach(e,(r,s)=>{if(!S.isValidElement(r))return;let a=[...t,s];if(r.type===S.Fragment){n.push.apply(n,Lo(r.props.children,a));return}r.type!==kt&&xe(!1),!r.props.index||!r.props.children||xe(!1);let l={id:r.props.id||a.join("-"),caseSensitive:r.props.caseSensitive,element:r.props.element,Component:r.props.Component,index:r.props.index,path:r.props.path,loader:r.props.loader,action:r.props.action,errorElement:r.props.errorElement,ErrorBoundary:r.props.ErrorBoundary,hasErrorBoundary:r.props.ErrorBoundary!=null||r.props.errorElement!=null,shouldRevalidate:r.props.shouldRevalidate,handle:r.props.handle,lazy:r.props.lazy};r.props.children&&(l.children=Lo(r.props.children,a)),n.push(l)}),n}/** + * React Router DOM v6.30.3 + * + * Copyright (c) Remix Software Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE.md file in the root directory of this source tree. + * + * @license MIT + */function yi(){return yi=Object.assign?Object.assign.bind():function(e){for(var t=1;t=0)&&(n[s]=e[s]);return n}function Gy(e){return!!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)}function Yy(e,t){return e.button===0&&(!t||t==="_self")&&!Gy(e)}const Xy=["onClick","relative","reloadDocument","replace","state","target","to","preventScrollReset","viewTransition"],Zy=["aria-current","caseSensitive","className","end","style","to","viewTransition","children"],eg="6";try{window.__reactRouterVersion=eg}catch{}const tg=S.createContext({isTransitioning:!1}),ng="startTransition",wd=up[ng];function rg(e){let{basename:t,children:n,future:r,window:s}=e,a=S.useRef();a.current==null&&(a.current=ry({window:s,v5Compat:!0}));let l=a.current,[o,u]=S.useState({action:l.action,location:l.location}),{v7_startTransition:c}=r||{},h=S.useCallback(d=>{c&&wd?wd(()=>u(d)):u(d)},[u,c]);return S.useLayoutEffect(()=>l.listen(h),[l,h]),S.useEffect(()=>Hy(r),[r]),S.createElement(qy,{basename:t,children:n,location:o.location,navigationType:o.action,navigator:l,future:r})}const sg=typeof window<"u"&&typeof window.document<"u"&&typeof window.document.createElement<"u",ag=/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i,Js=S.forwardRef(function(t,n){let{onClick:r,relative:s,reloadDocument:a,replace:l,state:o,target:u,to:c,preventScrollReset:h,viewTransition:d}=t,m=Cm(t,Xy),{basename:x}=S.useContext(Rn),k,g=!1;if(typeof c=="string"&&ag.test(c)&&(k=c,sg))try{let v=new URL(window.location.href),w=c.startsWith("//")?new URL(v.protocol+c):new URL(c),C=qr(w.pathname,x);w.origin===v.origin&&C!=null?c=C+w.search+w.hash:g=!0}catch{}let j=Py(c,{relative:s}),p=lg(c,{replace:l,state:o,target:u,preventScrollReset:h,relative:s,viewTransition:d});function f(v){r&&r(v),v.defaultPrevented||p(v)}return S.createElement("a",yi({},m,{href:k||j,onClick:g||a?r:f,ref:n,target:u}))}),kd=S.forwardRef(function(t,n){let{"aria-current":r="page",caseSensitive:s=!1,className:a="",end:l=!1,style:o,to:u,viewTransition:c,children:h}=t,d=Cm(t,Zy),m=Ai(u,{relative:d.relative}),x=ts(),k=S.useContext(jm),{navigator:g,basename:j}=S.useContext(Rn),p=k!=null&&og(m)&&c===!0,f=g.encodeLocation?g.encodeLocation(m).pathname:m.pathname,v=x.pathname,w=k&&k.navigation&&k.navigation.location?k.navigation.location.pathname:null;s||(v=v.toLowerCase(),w=w?w.toLowerCase():null,f=f.toLowerCase()),w&&j&&(w=qr(w,j)||w);const C=f!=="/"&&f.endsWith("/")?f.length-1:f.length;let b=v===f||!l&&v.startsWith(f)&&v.charAt(C)==="/",N=w!=null&&(w===f||!l&&w.startsWith(f)&&w.charAt(f.length)==="/"),_={isActive:b,isPending:N,isTransitioning:p},F=b?r:void 0,P;typeof a=="function"?P=a(_):P=[a,b?"active":null,N?"pending":null,p?"transitioning":null].filter(Boolean).join(" ");let B=typeof o=="function"?o(_):o;return S.createElement(Js,yi({},d,{"aria-current":F,className:P,ref:n,style:B,to:u,viewTransition:c}),typeof h=="function"?h(_):h)});var Ro;(function(e){e.UseScrollRestoration="useScrollRestoration",e.UseSubmit="useSubmit",e.UseSubmitFetcher="useSubmitFetcher",e.UseFetcher="useFetcher",e.useViewTransitionState="useViewTransitionState"})(Ro||(Ro={}));var Sd;(function(e){e.UseFetcher="useFetcher",e.UseFetchers="useFetchers",e.UseScrollRestoration="useScrollRestoration"})(Sd||(Sd={}));function ig(e){let t=S.useContext(Fi);return t||xe(!1),t}function lg(e,t){let{target:n,replace:r,state:s,preventScrollReset:a,relative:l,viewTransition:o}=t===void 0?{}:t,u=Lt(),c=ts(),h=Ai(e,{relative:l});return S.useCallback(d=>{if(Yy(d,n)){d.preventDefault();let m=r!==void 0?r:xi(c)===xi(h);u(e,{replace:m,state:s,preventScrollReset:a,relative:l,viewTransition:o})}},[c,u,h,r,s,n,e,a,l,o])}function og(e,t){t===void 0&&(t={});let n=S.useContext(tg);n==null&&xe(!1);let{basename:r}=ig(Ro.useViewTransitionState),s=Ai(e,{relative:t.relative});if(!n.isTransitioning)return!1;let a=qr(n.currentLocation.pathname,r)||n.currentLocation.pathname,l=qr(n.nextLocation.pathname,r)||n.nextLocation.pathname;return Oo(s.pathname,l)!=null||Oo(s.pathname,a)!=null}/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */var ug={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"};/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const cg=e=>e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase().trim(),Y=(e,t)=>{const n=S.forwardRef(({color:r="currentColor",size:s=24,strokeWidth:a=2,absoluteStrokeWidth:l,className:o="",children:u,...c},h)=>S.createElement("svg",{ref:h,...ug,width:s,height:s,stroke:r,strokeWidth:l?Number(a)*24/Number(s):a,className:["lucide",`lucide-${cg(e)}`,o].join(" "),...c},[...t.map(([d,m])=>S.createElement(d,m)),...Array.isArray(u)?u:[u]]));return n.displayName=`${e}`,n};/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const _m=Y("AlertCircle",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["line",{x1:"12",x2:"12",y1:"8",y2:"12",key:"1pkeuh"}],["line",{x1:"12",x2:"12.01",y1:"16",y2:"16",key:"4dfq90"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const dg=Y("ArrowUpDown",[["path",{d:"m21 16-4 4-4-4",key:"f6ql7i"}],["path",{d:"M17 20V4",key:"1ejh1v"}],["path",{d:"m3 8 4-4 4 4",key:"11wl7u"}],["path",{d:"M7 4v16",key:"1glfcx"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const fg=Y("BarChart3",[["path",{d:"M3 3v18h18",key:"1s2lah"}],["path",{d:"M18 17V9",key:"2bz60n"}],["path",{d:"M13 17V5",key:"1frdt8"}],["path",{d:"M8 17v-3",key:"17ska0"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const hg=Y("Bot",[["path",{d:"M12 8V4H8",key:"hb8ula"}],["rect",{width:"16",height:"12",x:"4",y:"8",rx:"2",key:"enze0r"}],["path",{d:"M2 14h2",key:"vft8re"}],["path",{d:"M20 14h2",key:"4cs60a"}],["path",{d:"M15 13v2",key:"1xurst"}],["path",{d:"M9 13v2",key:"rq6x2g"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Em=Y("CheckCircle",[["path",{d:"M22 11.08V12a10 10 0 1 1-5.93-9.14",key:"g774vq"}],["path",{d:"m9 11 3 3L22 4",key:"1pflzl"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const mg=Y("Check",[["path",{d:"M20 6 9 17l-5-5",key:"1gmf2c"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const pg=Y("ChevronDown",[["path",{d:"m6 9 6 6 6-6",key:"qrunsl"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const gi=Y("ChevronRight",[["path",{d:"m9 18 6-6-6-6",key:"mthhwq"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const vg=Y("Clock",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["polyline",{points:"12 6 12 12 16 14",key:"68esgv"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const xg=Y("Coins",[["circle",{cx:"8",cy:"8",r:"6",key:"3yglwk"}],["path",{d:"M18.09 10.37A6 6 0 1 1 10.34 18",key:"t5s6rm"}],["path",{d:"M7 6h1v4",key:"1obek4"}],["path",{d:"m16.71 13.88.7.71-2.82 2.82",key:"1rbuyh"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const yg=Y("Copy",[["rect",{width:"14",height:"14",x:"8",y:"8",rx:"2",ry:"2",key:"17jyea"}],["path",{d:"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2",key:"zix9uf"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const gg=Y("Database",[["ellipse",{cx:"12",cy:"5",rx:"9",ry:"3",key:"msslwz"}],["path",{d:"M3 5V19A9 3 0 0 0 21 19V5",key:"1wlel7"}],["path",{d:"M3 12A9 3 0 0 0 21 12",key:"mv7ke4"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Nd=Y("Download",[["path",{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4",key:"ih7n3h"}],["polyline",{points:"7 10 12 15 17 10",key:"2ggqvy"}],["line",{x1:"12",x2:"12",y1:"15",y2:"3",key:"1vk2je"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const jg=Y("ExternalLink",[["path",{d:"M15 3h6v6",key:"1q9fwt"}],["path",{d:"M10 14 21 3",key:"gplh6r"}],["path",{d:"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6",key:"a6xqqp"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const wg=Y("FlaskConical",[["path",{d:"M10 2v7.527a2 2 0 0 1-.211.896L4.72 20.55a1 1 0 0 0 .9 1.45h12.76a1 1 0 0 0 .9-1.45l-5.069-10.127A2 2 0 0 1 14 9.527V2",key:"pzvekw"}],["path",{d:"M8.5 2h7",key:"csnxdl"}],["path",{d:"M7 16h10",key:"wp8him"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const kg=Y("GitCompare",[["circle",{cx:"18",cy:"18",r:"3",key:"1xkwt0"}],["circle",{cx:"6",cy:"6",r:"3",key:"1lh9wr"}],["path",{d:"M13 6h3a2 2 0 0 1 2 2v7",key:"1yeb86"}],["path",{d:"M11 18H8a2 2 0 0 1-2-2V9",key:"19pyzm"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Sg=Y("Github",[["path",{d:"M15 22v-4a4.8 4.8 0 0 0-1-3.5c3 0 6-2 6-5.5.08-1.25-.27-2.48-1-3.5.28-1.15.28-2.35 0-3.5 0 0-1 0-3 1.5-2.64-.5-5.36-.5-8 0C6 2 5 2 5 2c-.3 1.15-.3 2.35 0 3.5A5.403 5.403 0 0 0 4 9c0 3.5 3 5.5 6 5.5-.39.49-.68 1.05-.85 1.65-.17.6-.22 1.23-.15 1.85v4",key:"tonef"}],["path",{d:"M9 18c-4.51 2-5-2-7-2",key:"9comsn"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const $i=Y("Globe",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20",key:"13o1zl"}],["path",{d:"M2 12h20",key:"9i4pu4"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Ng=Y("History",[["path",{d:"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8",key:"1357e3"}],["path",{d:"M3 3v5h5",key:"1xhq8a"}],["path",{d:"M12 7v5l4 2",key:"1fdv2h"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const bg=Y("List",[["line",{x1:"8",x2:"21",y1:"6",y2:"6",key:"7ey8pc"}],["line",{x1:"8",x2:"21",y1:"12",y2:"12",key:"rjfblc"}],["line",{x1:"8",x2:"21",y1:"18",y2:"18",key:"c3b1m8"}],["line",{x1:"3",x2:"3.01",y1:"6",y2:"6",key:"1g7gq3"}],["line",{x1:"3",x2:"3.01",y1:"12",y2:"12",key:"1pjlvk"}],["line",{x1:"3",x2:"3.01",y1:"18",y2:"18",key:"28t2mc"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const ca=Y("Loader2",[["path",{d:"M21 12a9 9 0 1 1-6.219-8.56",key:"13zald"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Pm=Y("Lock",[["rect",{width:"18",height:"11",x:"3",y:"11",rx:"2",ry:"2",key:"1w4ew1"}],["path",{d:"M7 11V7a5 5 0 0 1 10 0v4",key:"fwvmzm"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Cg=Y("LogOut",[["path",{d:"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4",key:"1uf3rs"}],["polyline",{points:"16 17 21 12 16 7",key:"1gabdz"}],["line",{x1:"21",x2:"9",y1:"12",y2:"12",key:"1uyos4"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const _g=Y("Moon",[["path",{d:"M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z",key:"a7tn18"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Gs=Y("Play",[["polygon",{points:"5 3 19 12 5 21 5 3",key:"191637"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Ui=Y("Plus",[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"M12 5v14",key:"s699le"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Tm=Y("Settings",[["path",{d:"M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z",key:"1qme2f"}],["circle",{cx:"12",cy:"12",r:"3",key:"1v7zrd"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Eg=Y("Share2",[["circle",{cx:"18",cy:"5",r:"3",key:"gq8acd"}],["circle",{cx:"6",cy:"12",r:"3",key:"w7nqdw"}],["circle",{cx:"18",cy:"19",r:"3",key:"1xt0gg"}],["line",{x1:"8.59",x2:"15.42",y1:"13.51",y2:"17.49",key:"47mynk"}],["line",{x1:"15.41",x2:"8.59",y1:"6.51",y2:"10.49",key:"1n3mei"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Pg=Y("Square",[["rect",{width:"18",height:"18",x:"3",y:"3",rx:"2",key:"afitv7"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Tg=Y("Sun",[["circle",{cx:"12",cy:"12",r:"4",key:"4exip2"}],["path",{d:"M12 2v2",key:"tus03m"}],["path",{d:"M12 20v2",key:"1lh1kg"}],["path",{d:"m4.93 4.93 1.41 1.41",key:"149t6j"}],["path",{d:"m17.66 17.66 1.41 1.41",key:"ptbguv"}],["path",{d:"M2 12h2",key:"1t8f8n"}],["path",{d:"M20 12h2",key:"1q8mjw"}],["path",{d:"m6.34 17.66-1.41 1.41",key:"1m8zz5"}],["path",{d:"m19.07 4.93-1.41 1.41",key:"1shlcs"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Om=Y("Trash2",[["path",{d:"M3 6h18",key:"d0wm0j"}],["path",{d:"M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6",key:"4alrt4"}],["path",{d:"M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2",key:"v07s0e"}],["line",{x1:"10",x2:"10",y1:"11",y2:"17",key:"1uufr5"}],["line",{x1:"14",x2:"14",y1:"11",y2:"17",key:"xtxkd"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Lm=Y("User",[["path",{d:"M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2",key:"975kel"}],["circle",{cx:"12",cy:"7",r:"4",key:"17ys0d"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Og=Y("XCircle",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"m15 9-6 6",key:"1uzhvr"}],["path",{d:"m9 9 6 6",key:"z0biqf"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Rm=Y("X",[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Bi=Y("Zap",[["polygon",{points:"13 2 3 14 12 14 11 22 21 10 12 10 13 2",key:"45s27k"}]]),Lg={},bd=e=>{let t;const n=new Set,r=(h,d)=>{const m=typeof h=="function"?h(t):h;if(!Object.is(m,t)){const x=t;t=d??(typeof m!="object"||m===null)?m:Object.assign({},t,m),n.forEach(k=>k(t,x))}},s=()=>t,u={setState:r,getState:s,getInitialState:()=>c,subscribe:h=>(n.add(h),()=>n.delete(h)),destroy:()=>{(Lg?"production":void 0)!=="production"&&console.warn("[DEPRECATED] The `destroy` method will be unsupported in a future version. Instead use unsubscribe function returned by subscribe. Everything will be garbage-collected if store is garbage-collected."),n.clear()}},c=t=e(r,s,u);return u},Rg=e=>e?bd(e):bd;var Mm={exports:{}},zm={},Fm={exports:{}},Im={};/** + * @license React + * use-sync-external-store-shim.production.js + * + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var Jr=S;function Mg(e,t){return e===t&&(e!==0||1/e===1/t)||e!==e&&t!==t}var zg=typeof Object.is=="function"?Object.is:Mg,Fg=Jr.useState,Ig=Jr.useEffect,Dg=Jr.useLayoutEffect,Ag=Jr.useDebugValue;function $g(e,t){var n=t(),r=Fg({inst:{value:n,getSnapshot:t}}),s=r[0].inst,a=r[1];return Dg(function(){s.value=n,s.getSnapshot=t,gl(s)&&a({inst:s})},[e,n,t]),Ig(function(){return gl(s)&&a({inst:s}),e(function(){gl(s)&&a({inst:s})})},[e]),Ag(n),n}function gl(e){var t=e.getSnapshot;e=e.value;try{var n=t();return!zg(e,n)}catch{return!0}}function Ug(e,t){return t()}var Bg=typeof window>"u"||typeof window.document>"u"||typeof window.document.createElement>"u"?Ug:$g;Im.useSyncExternalStore=Jr.useSyncExternalStore!==void 0?Jr.useSyncExternalStore:Bg;Fm.exports=Im;var Qg=Fm.exports;/** + * @license React + * use-sync-external-store-shim/with-selector.production.js + * + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var Qi=S,Vg=Qg;function Kg(e,t){return e===t&&(e!==0||1/e===1/t)||e!==e&&t!==t}var Hg=typeof Object.is=="function"?Object.is:Kg,Wg=Vg.useSyncExternalStore,qg=Qi.useRef,Jg=Qi.useEffect,Gg=Qi.useMemo,Yg=Qi.useDebugValue;zm.useSyncExternalStoreWithSelector=function(e,t,n,r,s){var a=qg(null);if(a.current===null){var l={hasValue:!1,value:null};a.current=l}else l=a.current;a=Gg(function(){function u(x){if(!c){if(c=!0,h=x,x=r(x),s!==void 0&&l.hasValue){var k=l.value;if(s(k,x))return d=k}return d=x}if(k=d,Hg(h,x))return k;var g=r(x);return s!==void 0&&s(k,g)?(h=x,k):(h=x,d=g)}var c=!1,h,d,m=n===void 0?null:n;return[function(){return u(t())},m===null?void 0:function(){return u(m())}]},[t,n,r,s]);var o=Wg(e,a[0],a[1]);return Jg(function(){l.hasValue=!0,l.value=o},[o]),Yg(o),o};Mm.exports=zm;var Xg=Mm.exports;const Zg=Vd(Xg),Dm={},{useDebugValue:e0}=Qo,{useSyncExternalStoreWithSelector:t0}=Zg;let Cd=!1;const n0=e=>e;function r0(e,t=n0,n){(Dm?"production":void 0)!=="production"&&n&&!Cd&&(console.warn("[DEPRECATED] Use `createWithEqualityFn` instead of `create` or use `useStoreWithEqualityFn` instead of `useStore`. They can be imported from 'zustand/traditional'. https://github.com/pmndrs/zustand/discussions/1937"),Cd=!0);const r=t0(e.subscribe,e.getState,e.getServerState||e.getInitialState,t,n);return e0(r),r}const _d=e=>{(Dm?"production":void 0)!=="production"&&typeof e!="function"&&console.warn("[DEPRECATED] Passing a vanilla store will be unsupported in a future version. Instead use `import { useStore } from 'zustand'`.");const t=typeof e=="function"?Rg(e):e,n=(r,s)=>r0(t,r,s);return Object.assign(n,t),n},$u=e=>e?_d(e):_d,Vi="/api",Uu="flow_auth_token",Bu="flow_auth_expires",Qu="flow_auth_username";function Ys(){const e=localStorage.getItem(Uu),t=localStorage.getItem(Bu);return!e||!t?null:new Date(t)<=new Date?(Yn(),null):e}function Ed(e,t,n){localStorage.setItem(Uu,e),localStorage.setItem(Bu,t),localStorage.setItem(Qu,n)}function Yn(){localStorage.removeItem(Uu),localStorage.removeItem(Bu),localStorage.removeItem(Qu)}function Vu(){return localStorage.getItem(Qu)}let ar=null;function s0(e){ar=e}async function Q(e,t,n=!1){const r={"Content-Type":"application/json",...t==null?void 0:t.headers};if(!n){const a=Ys();a&&(r.Authorization=`Bearer ${a}`)}const s=await fetch(`${Vi}${e}`,{...t,headers:r});if(s.status===401){Yn(),ar&&ar();const a=await s.json().catch(()=>({detail:"Not authenticated"}));throw new Error(a.detail||"Not authenticated")}if(!s.ok){const a=await s.json().catch(()=>({detail:s.statusText}));throw new Error(a.detail||"API request failed")}if(s.status!==204)return s.json()}const ur={getConfig:()=>Q("/auth/config",void 0,!0),login:e=>Q("/auth/login",{method:"POST",body:JSON.stringify(e)},!0),getGitHubAuthUrl:()=>`${Vi}/auth/github`,getCurrentUser:()=>Q("/auth/me"),logout:()=>Q("/auth/logout",{method:"POST"})},Er={list:e=>{const t=new URLSearchParams;e!=null&&e.include_auto_generated&&t.set("include_auto_generated","true"),e!=null&&e.include_public&&t.set("include_public","true");const n=t.toString();return Q(`/configs${n?`?${n}`:""}`)},get:e=>Q(`/configs/${e}`),create:e=>Q("/configs",{method:"POST",body:JSON.stringify(e)}),update:(e,t)=>Q(`/configs/${e}`,{method:"PUT",body:JSON.stringify(t)}),delete:e=>Q(`/configs/${e}`,{method:"DELETE"})},Et={list:e=>{const t=new URLSearchParams;e!=null&&e.category&&t.set("category",e.category),e!=null&&e.suite&&t.set("suite",e.suite);const n=t.toString();return Q(`/tasks${n?`?${n}`:""}`)},get:e=>Q(`/tasks/${e}`),create:e=>Q("/tasks",{method:"POST",body:JSON.stringify(e)}),update:(e,t)=>Q(`/tasks/${e}`,{method:"PUT",body:JSON.stringify(t)}),delete:e=>Q(`/tasks/${e}`,{method:"DELETE"}),listSuites:()=>Q("/tasks/suites"),importSuite:e=>Q(`/tasks/import-suite?suite_name=${encodeURIComponent(e)}`,{method:"POST"})},Ot={list:e=>{const t=new URLSearchParams;e!=null&&e.status&&t.set("status",e.status),e!=null&&e.include_public&&t.set("include_public","true");const n=t.toString();return Q(`/jobs${n?`?${n}`:""}`)},get:e=>Q(`/jobs/${e}`),create:e=>Q("/jobs",{method:"POST",body:JSON.stringify(e)}),update:(e,t)=>Q(`/jobs/${e}`,{method:"PUT",body:JSON.stringify(t)}),start:async function*(e){var o;const t={},n=Ys();n&&(t.Authorization=`Bearer ${n}`);const r=await fetch(`${Vi}/jobs/${e}/start`,{method:"POST",headers:t});if(r.status===401)throw Yn(),ar&&ar(),new Error("Not authenticated");if(!r.ok)throw new Error("Failed to start job");const s=(o=r.body)==null?void 0:o.getReader();if(!s)throw new Error("No response body");const a=new TextDecoder;let l="";for(;;){const{done:u,value:c}=await s.read();if(u)break;l+=a.decode(c,{stream:!0});const h=l.split(` +`);l=h.pop()||"";for(const d of h)d.startsWith("data: ")&&(yield JSON.parse(d.slice(6)))}},cancel:e=>Q(`/jobs/${e}/cancel`,{method:"POST"}),delete:e=>Q(`/jobs/${e}`,{method:"DELETE"})},Mo={list:e=>{const t=new URLSearchParams;e!=null&&e.job_id&&t.set("job_id",e.job_id),e!=null&&e.candidate_name&&t.set("candidate_name",e.candidate_name),e!=null&&e.task_name&&t.set("task_name",e.task_name),(e==null?void 0:e.is_pareto)!==void 0&&t.set("is_pareto",String(e.is_pareto));const n=t.toString();return Q(`/runs${n?`?${n}`:""}`)},get:e=>Q(`/runs/${e}`),getJobSummary:e=>Q(`/runs/job/${e}/summary`)},Es={list:e=>{const t=new URLSearchParams;e!=null&&e.agent_id&&t.set("agent_id",e.agent_id),e!=null&&e.limit&&t.set("limit",String(e.limit));const n=t.toString();return Q(`/tests${n?`?${n}`:""}`)},get:e=>Q(`/tests/${e}`),create:e=>Q("/tests",{method:"POST",body:JSON.stringify(e)}),start:async function*(e){var o;const t={},n=Ys();n&&(t.Authorization=`Bearer ${n}`);const r=await fetch(`${Vi}/tests/${e}/start`,{method:"POST",headers:t});if(r.status===401)throw Yn(),ar&&ar(),new Error("Not authenticated");if(!r.ok){const u=await r.json().catch(()=>({detail:"Failed to start test"}));throw new Error(u.detail||"Failed to start test")}const s=(o=r.body)==null?void 0:o.getReader();if(!s)throw new Error("No response body");const a=new TextDecoder;let l="";for(;;){const{done:u,value:c}=await s.read();if(u)break;l+=a.decode(c,{stream:!0});const h=l.split(` +`);l=h.pop()||"";for(const d of h)d.startsWith("data: ")&&(yield JSON.parse(d.slice(6)))}},cancel:e=>Q(`/tests/${e}/cancel`,{method:"POST"}),delete:e=>Q(`/tests/${e}`,{method:"DELETE"})},a0={list:()=>Q("/llm-configs"),get:e=>Q(`/llm-configs/${e}`),getDefault:()=>Q("/llm-configs/default"),create:e=>Q("/llm-configs",{method:"POST",body:JSON.stringify(e)}),update:(e,t)=>Q(`/llm-configs/${e}`,{method:"PUT",body:JSON.stringify(t)}),delete:e=>Q(`/llm-configs/${e}`,{method:"DELETE"}),setDefault:e=>Q(`/llm-configs/${e}/set-default`,{method:"POST"}),test:e=>Q(`/llm-configs/${e}/test`,{method:"POST"})},i0={list:()=>Q("/tools"),get:e=>Q(`/tools/${e}`)},Am={getAgentSchema:()=>Q("/schema/agent")},l0={start:e=>Q("/evaluate",{method:"POST",body:JSON.stringify(e)})},zo={design:e=>Q("/experiment/design",{method:"POST",body:JSON.stringify(e)}),importYaml:e=>Q("/experiment/import-yaml",{method:"POST",body:JSON.stringify(e)}),validate:e=>Q("/experiment/validate",{method:"POST",body:JSON.stringify(e)}),generateCandidates:e=>Q("/experiment/generate-candidates",{method:"POST",body:JSON.stringify(e)})},Ku=$u((e,t)=>(s0(()=>{e({isAuthenticated:!1,user:null,error:"Session expired. Please log in again."})}),{authConfig:null,isLoadingConfig:!0,isAuthenticated:!1,isLoading:!1,user:null,error:null,loadAuthConfig:async()=>{e({isLoadingConfig:!0});try{const n=await ur.getConfig();if(e({authConfig:n,isLoadingConfig:!1}),n.enabled){const r=Ys(),s=Vu();if(r&&s)try{const a=await ur.getCurrentUser();e({isAuthenticated:!0,user:a})}catch{Yn(),e({isAuthenticated:!1,user:null})}}else e({isAuthenticated:!0,user:{username:"anonymous",auth_mode:"none"}})}catch(n){console.error("Failed to load auth config:",n),e({isLoadingConfig:!1,error:"Failed to connect to server"})}},login:async(n,r)=>{e({isLoading:!0,error:null});try{const s=await ur.login({username:n,password:r});return Ed(s.access_token,s.expires_at,s.username),e({isAuthenticated:!0,isLoading:!1,user:{username:s.username,auth_mode:"basic"}}),!0}catch(s){return e({isLoading:!1,error:s instanceof Error?s.message:"Login failed"}),!1}},loginWithGitHub:()=>{window.location.href=ur.getGitHubAuthUrl()},handleOAuthCallback:()=>{const n=new URLSearchParams(window.location.search),r=n.get("auth_error");if(r)return e({error:r}),window.history.replaceState({},"",window.location.pathname),!0;if(n.get("auth_callback")==="true"){const s=n.get("token"),a=n.get("expires_at"),l=n.get("username");return s&&a&&l&&(Ed(s,a,l),e({isAuthenticated:!0,user:{username:l,auth_mode:"github"}})),window.history.replaceState({},"",window.location.pathname),!0}return!1},logout:async()=>{try{await ur.logout()}catch{}Yn(),e({isAuthenticated:!1,user:null,error:null})},checkAuth:async()=>{const{authConfig:n}=t();if(!(n!=null&&n.enabled)){e({isAuthenticated:!0});return}if(!Ys()){e({isAuthenticated:!1,user:null});return}try{const s=await ur.getCurrentUser();e({isAuthenticated:!0,user:s})}catch{Yn(),e({isAuthenticated:!1,user:null})}},clearError:()=>e({error:null})}));function V({variant:e="secondary",size:t="md",className:n="",icon:r,iconRight:s,loading:a=!1,children:l,disabled:o,...u}){const c="font-medium transition-colors disabled:opacity-50 disabled:cursor-not-allowed inline-flex items-center gap-1.5",h={primary:"bg-[var(--accent)] text-black hover:bg-[#16a34a]",secondary:"bg-[var(--bg-tertiary)] text-[var(--text-primary)] border border-[var(--border)] hover:bg-[var(--border)]",danger:"bg-[var(--error)] text-white hover:bg-red-600",ghost:"text-[var(--text-secondary)] hover:text-[var(--text-primary)] hover:bg-[var(--bg-tertiary)]"},d={sm:"px-2 py-1 text-xs",md:"px-3 py-1.5 text-sm"},m=t==="sm"?14:16;return i.jsxs("button",{className:`${c} ${h[e]} ${d[t]} ${n}`,disabled:o||a,...u,children:[a?i.jsx(ca,{size:m,className:"animate-spin"}):r?i.jsx(r,{size:m}):null,l,s&&!a&&i.jsx(s,{size:m})]})}const o0={};function u0(e,t){let n;try{n=e()}catch{return}return{getItem:s=>{var a;const l=u=>u===null?null:JSON.parse(u,void 0),o=(a=n.getItem(s))!=null?a:null;return o instanceof Promise?o.then(l):l(o)},setItem:(s,a)=>n.setItem(s,JSON.stringify(a,void 0)),removeItem:s=>n.removeItem(s)}}const Xs=e=>t=>{try{const n=e(t);return n instanceof Promise?n:{then(r){return Xs(r)(n)},catch(r){return this}}}catch(n){return{then(r){return this},catch(r){return Xs(r)(n)}}}},c0=(e,t)=>(n,r,s)=>{let a={getStorage:()=>localStorage,serialize:JSON.stringify,deserialize:JSON.parse,partialize:j=>j,version:0,merge:(j,p)=>({...p,...j}),...t},l=!1;const o=new Set,u=new Set;let c;try{c=a.getStorage()}catch{}if(!c)return e((...j)=>{console.warn(`[zustand persist middleware] Unable to update item '${a.name}', the given storage is currently unavailable.`),n(...j)},r,s);const h=Xs(a.serialize),d=()=>{const j=a.partialize({...r()});let p;const f=h({state:j,version:a.version}).then(v=>c.setItem(a.name,v)).catch(v=>{p=v});if(p)throw p;return f},m=s.setState;s.setState=(j,p)=>{m(j,p),d()};const x=e((...j)=>{n(...j),d()},r,s);let k;const g=()=>{var j;if(!c)return;l=!1,o.forEach(f=>f(r()));const p=((j=a.onRehydrateStorage)==null?void 0:j.call(a,r()))||void 0;return Xs(c.getItem.bind(c))(a.name).then(f=>{if(f)return a.deserialize(f)}).then(f=>{if(f)if(typeof f.version=="number"&&f.version!==a.version){if(a.migrate)return a.migrate(f.state,f.version);console.error("State loaded from storage couldn't be migrated since no migrate function was provided")}else return f.state}).then(f=>{var v;return k=a.merge(f,(v=r())!=null?v:x),n(k,!0),d()}).then(()=>{p==null||p(k,void 0),l=!0,u.forEach(f=>f(k))}).catch(f=>{p==null||p(void 0,f)})};return s.persist={setOptions:j=>{a={...a,...j},j.getStorage&&(c=j.getStorage())},clearStorage:()=>{c==null||c.removeItem(a.name)},getOptions:()=>a,rehydrate:()=>g(),hasHydrated:()=>l,onHydrate:j=>(o.add(j),()=>{o.delete(j)}),onFinishHydration:j=>(u.add(j),()=>{u.delete(j)})},g(),k||x},d0=(e,t)=>(n,r,s)=>{let a={storage:u0(()=>localStorage),partialize:g=>g,version:0,merge:(g,j)=>({...j,...g}),...t},l=!1;const o=new Set,u=new Set;let c=a.storage;if(!c)return e((...g)=>{console.warn(`[zustand persist middleware] Unable to update item '${a.name}', the given storage is currently unavailable.`),n(...g)},r,s);const h=()=>{const g=a.partialize({...r()});return c.setItem(a.name,{state:g,version:a.version})},d=s.setState;s.setState=(g,j)=>{d(g,j),h()};const m=e((...g)=>{n(...g),h()},r,s);s.getInitialState=()=>m;let x;const k=()=>{var g,j;if(!c)return;l=!1,o.forEach(f=>{var v;return f((v=r())!=null?v:m)});const p=((j=a.onRehydrateStorage)==null?void 0:j.call(a,(g=r())!=null?g:m))||void 0;return Xs(c.getItem.bind(c))(a.name).then(f=>{if(f)if(typeof f.version=="number"&&f.version!==a.version){if(a.migrate)return[!0,a.migrate(f.state,f.version)];console.error("State loaded from storage couldn't be migrated since no migrate function was provided")}else return[!1,f.state];return[!1,void 0]}).then(f=>{var v;const[w,C]=f;if(x=a.merge(C,(v=r())!=null?v:m),n(x,!0),w)return h()}).then(()=>{p==null||p(x,void 0),x=r(),l=!0,u.forEach(f=>f(x))}).catch(f=>{p==null||p(void 0,f)})};return s.persist={setOptions:g=>{a={...a,...g},g.storage&&(c=g.storage)},clearStorage:()=>{c==null||c.removeItem(a.name)},getOptions:()=>a,rehydrate:()=>k(),hasHydrated:()=>l,onHydrate:g=>(o.add(g),()=>{o.delete(g)}),onFinishHydration:g=>(u.add(g),()=>{u.delete(g)})},a.skipHydration||k(),x||m},f0=(e,t)=>"getStorage"in t||"serialize"in t||"deserialize"in t?((o0?"production":void 0)!=="production"&&console.warn("[DEPRECATED] `getStorage`, `serialize` and `deserialize` options are deprecated. Use `storage` option instead."),c0(e,t)):d0(e,t),h0=f0,m0=$u()(h0((e,t)=>({theme:"dark",setTheme:n=>{document.documentElement.setAttribute("data-theme",n),e({theme:n})},toggleTheme:()=>{const n=t().theme==="dark"?"light":"dark";document.documentElement.setAttribute("data-theme",n),e({theme:n})}}),{name:"flow-theme",onRehydrateStorage:()=>e=>{e!=null&&e.theme&&document.documentElement.setAttribute("data-theme",e.theme)}}));function p0(){const{theme:e,toggleTheme:t}=m0();return i.jsx("button",{onClick:t,className:"p-2 rounded-md text-[var(--text-secondary)] hover:text-[var(--text-primary)] hover:bg-[var(--bg-tertiary)] transition-colors focus:outline-none focus:ring-2 focus:ring-[var(--accent)]","aria-label":`Switch to ${e==="dark"?"light":"dark"} mode`,title:`Switch to ${e==="dark"?"light":"dark"} mode`,children:e==="dark"?i.jsx(Tg,{size:16}):i.jsx(_g,{size:16})})}const v0=[{path:"/agents",label:"Agents",icon:hg},{path:"/jobs",label:"Experiments",icon:wg},{path:"/tasks",label:"Datasets",icon:gg}];function x0(){const e=ts(),{authConfig:t,user:n,logout:r}=Ku(),s=l=>l==="/agents"?e.pathname==="/"||e.pathname==="/agents":e.pathname.startsWith(l),a=async()=>{await r()};return i.jsxs("div",{className:"min-h-screen flex flex-col",children:[i.jsx("header",{className:"border-b border-[var(--border)] bg-[var(--bg-secondary)]",children:i.jsxs("div",{className:"max-w-7xl mx-auto px-4 py-3 flex items-center justify-between",children:[i.jsxs("div",{className:"flex items-center gap-8",children:[i.jsxs(kd,{to:"/",className:"text-lg font-bold text-[var(--accent)] flex items-center gap-2 hover:opacity-80",children:[i.jsx(Bi,{size:20}),"flow",i.jsx("span",{className:"text-[var(--text-secondary)]",children:"/optimize"})]}),i.jsx("nav",{className:"flex gap-1",children:v0.map(l=>i.jsxs(kd,{to:l.path,className:`px-3 py-1.5 rounded text-sm transition-colors flex items-center gap-2 ${s(l.path)?"bg-[var(--accent)] text-black font-medium":"text-[var(--text-secondary)] hover:text-[var(--text-primary)] hover:bg-[var(--bg-tertiary)]"}`,children:[i.jsx(l.icon,{size:16}),l.label]},l.path))})]}),i.jsxs("div",{className:"flex items-center gap-4",children:[i.jsx(p0,{}),(t==null?void 0:t.enabled)&&n&&i.jsxs("div",{className:"flex items-center gap-3",children:[i.jsxs("div",{className:"flex items-center gap-2 text-sm text-[var(--text-secondary)]",children:[i.jsx(Lm,{size:14}),i.jsx("span",{children:n.username})]}),i.jsx(V,{variant:"ghost",size:"sm",icon:Cg,onClick:a,title:"Sign out",children:"Sign out"})]})]})]})}),i.jsx("main",{className:"flex-1 bg-[var(--bg-primary)]",children:i.jsx("div",{className:"max-w-7xl mx-auto p-4",children:i.jsx(Wy,{})})})]})}const y0=["maf","miniagent","langgraph"],g0={maf:"Microsoft Agent Framework",miniagent:"MiniAgent",langgraph:"LangGraph"},j0={openai:"OpenAI",azure_openai:"Azure OpenAI",anthropic:"Anthropic",ollama:"Ollama",custom:"Custom (OpenAI-compatible)"};function se({children:e,className:t="",onClick:n,selected:r=!1,selectable:s=!1}){const a="bg-[var(--bg-secondary)] border border-[var(--border)] p-4",l=s?"cursor-pointer hover:border-[var(--accent-dim)] transition-colors":"",o=r?"border-[var(--accent)]":"";return i.jsx("div",{className:`${a} ${l} ${o} ${t}`,onClick:n,children:e})}function J({children:e,variant:t="default"}){const n={default:"bg-[var(--bg-tertiary)] text-[var(--text-primary)] border border-[var(--border)]",success:"bg-green-600 text-white",warning:"bg-yellow-500 text-black",error:"bg-red-600 text-white",info:"bg-blue-600 text-white"};return i.jsx("span",{className:`inline-block px-2 py-0.5 text-xs font-medium rounded ${n[t]}`,children:e})}const w0={pending:"default",running:"info",completed:"success",failed:"error",cancelled:"warning"};function $m({job:e,onDelete:t}){const n=Lt(),r=e.total_experiments>0?e.completed_experiments/e.total_experiments*100:0;return i.jsxs(se,{className:"cursor-pointer hover:border-[var(--accent-dim)] flex flex-col",onClick:()=>n(`/jobs/${e.id}`),children:[i.jsxs("div",{className:"flex items-start justify-between mb-3",children:[i.jsxs("div",{className:"flex-1 min-w-0",children:[i.jsxs("div",{className:"flex items-center gap-2 flex-wrap",children:[i.jsx(J,{variant:w0[e.status]||"default",children:e.status}),e.is_public&&i.jsxs(J,{variant:"info",children:[i.jsx($i,{className:"w-3 h-3 mr-1 inline"}),"Public"]}),e.pareto_frontier.length>0&&i.jsxs(J,{variant:"success",children:[e.pareto_frontier.length," Optimal"]}),e.use_llm_eval&&i.jsx(J,{children:"LLM"})]}),i.jsx("h3",{className:"font-medium mt-2 truncate",title:e.name||`Job ${e.id.slice(0,8)}`,children:e.name||`Job ${e.id.slice(0,8)}`}),i.jsxs("code",{className:"text-xs text-[var(--text-secondary)] font-mono",children:[e.id.slice(0,8),"..."]})]}),t&&i.jsx(V,{variant:"ghost",size:"sm",onClick:s=>{s.stopPropagation(),confirm("Delete this job?")&&t(e.id)},disabled:e.status==="running",children:"×"})]}),(e.status==="running"||e.status==="completed")&&i.jsxs("div",{className:"mb-3",children:[i.jsxs("div",{className:"flex justify-between text-xs text-[var(--text-secondary)] mb-1",children:[i.jsx("span",{children:"Progress"}),i.jsxs("span",{children:[e.completed_experiments,"/",e.total_experiments]})]}),i.jsx("div",{className:"w-full bg-[var(--bg-primary)] h-1.5 rounded-full overflow-hidden",children:i.jsx("div",{className:`h-full transition-all ${e.status==="completed"?"bg-green-500":"bg-[var(--accent)]"}`,style:{width:`${r}%`}})})]}),e.status==="failed"&&e.error&&i.jsx("div",{className:"mb-3 px-2 py-1.5 bg-red-500/10 border border-red-500/30 rounded text-xs text-red-400 line-clamp-2",children:e.error}),i.jsxs("div",{className:"grid grid-cols-3 gap-2 text-center py-2 border-t border-[var(--border)] mt-auto",children:[i.jsxs("div",{children:[i.jsx("div",{className:"text-lg font-bold",children:e.candidate_ids.length}),i.jsx("div",{className:"text-xs text-[var(--text-secondary)]",children:"candidates"})]}),i.jsxs("div",{children:[i.jsx("div",{className:"text-lg font-bold",children:e.task_ids.length}),i.jsx("div",{className:"text-xs text-[var(--text-secondary)]",children:"tasks"})]}),i.jsxs("div",{children:[i.jsx("div",{className:"text-lg font-bold",children:e.total_experiments}),i.jsx("div",{className:"text-xs text-[var(--text-secondary)]",children:"runs"})]})]}),i.jsxs("div",{className:"text-xs text-[var(--text-secondary)] pt-2 border-t border-[var(--border)] flex justify-between items-center",children:[i.jsxs("span",{children:[new Date(e.created_at).toLocaleDateString()," ",new Date(e.created_at).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})]}),e.is_public&&e.created_by_name&&i.jsxs("span",{className:"text-[var(--text-secondary)]",children:["by ",e.created_by_name]})]})]})}const k0={sm:"max-w-sm",md:"max-w-lg",lg:"max-w-2xl",xl:"max-w-4xl"};function ns({isOpen:e,onClose:t,title:n,children:r,footer:s,size:a="md"}){return S.useEffect(()=>{const l=o=>{o.key==="Escape"&&t()};return e&&(document.addEventListener("keydown",l),document.body.style.overflow="hidden"),()=>{document.removeEventListener("keydown",l),document.body.style.overflow=""}},[e,t]),e?i.jsxs("div",{className:"fixed inset-0 z-50 flex items-center justify-center",children:[i.jsx("div",{className:"absolute inset-0 bg-black/80",onClick:t}),i.jsxs("div",{className:`relative bg-[var(--bg-secondary)] border border-[var(--border)] ${k0[a]} w-full mx-4 max-h-[80vh] flex flex-col`,children:[i.jsxs("div",{className:"flex-shrink-0 bg-[var(--bg-secondary)] border-b border-[var(--border)] px-4 py-3 flex items-center justify-between",children:[i.jsx("h2",{className:"font-semibold",children:n}),i.jsx("button",{onClick:t,className:"text-[var(--text-secondary)] hover:text-[var(--text-primary)]",children:"×"})]}),i.jsx("div",{className:"flex-1 overflow-y-auto p-4",children:r}),s&&i.jsx("div",{className:"flex-shrink-0 bg-[var(--bg-secondary)] border-t border-[var(--border)] px-4 py-3",children:s})]})]}):null}function vn({label:e,className:t="",...n}){return i.jsxs("div",{className:"space-y-1",children:[e&&i.jsx("label",{className:"block text-sm text-[var(--text-secondary)]",children:e}),i.jsx("input",{className:`w-full bg-[var(--bg-primary)] border border-[var(--border)] px-3 py-2 text-sm focus:outline-none focus:border-[var(--accent)] ${t}`,...n})]})}function S0({label:e,className:t="",...n}){return i.jsxs("div",{className:"space-y-1",children:[e&&i.jsx("label",{className:"block text-sm text-[var(--text-secondary)]",children:e}),i.jsx("textarea",{className:`w-full bg-[var(--bg-primary)] border border-[var(--border)] px-3 py-2 text-sm focus:outline-none focus:border-[var(--accent)] resize-y min-h-[100px] ${t}`,...n})]})}function Fo({label:e,className:t="",...n}){return i.jsxs("label",{className:`flex items-center gap-2 cursor-pointer ${t}`,children:[i.jsx("input",{type:"checkbox",className:"w-4 h-4 bg-[var(--bg-primary)] border border-[var(--border)] accent-[var(--accent)]",...n}),i.jsx("span",{className:"text-sm",children:e})]})}function N0({variations:e,onChange:t,strategies:n,availableStrategies:r}){const s=r??Object.keys(n),a=()=>{const c=e.map(x=>x.strategy),h=s.find(x=>!c.includes(x))||"none",d=n[h],m={strategy:h};if(d!=null&&d.params)for(const[x,k]of Object.entries(d.params))k.default!==void 0&&(m[x]=k.default);t([...e,m])},l=c=>{t(e.filter((h,d)=>d!==c))},o=(c,h)=>{t(e.map((d,m)=>m===c?{...d,...h}:d))},u=(c,h)=>{const d=n[h],m={strategy:h};if(d!=null&&d.params)for(const[x,k]of Object.entries(d.params))k.default!==void 0&&(m[x]=k.default);o(c,m)};return i.jsxs("div",{className:"space-y-3",children:[i.jsxs("div",{className:"flex items-center justify-between",children:[i.jsx("label",{className:"text-sm font-medium",children:"Compaction Strategies"}),i.jsx(V,{type:"button",variant:"ghost",size:"sm",icon:Ui,onClick:a,disabled:e.length>=s.length,children:"Add"})]}),e.length===0?i.jsx("p",{className:"text-sm text-[var(--text-secondary)] italic",children:'No compaction variations. Click "Add" to test different strategies.'}):i.jsx("div",{className:"space-y-2",children:e.map((c,h)=>{const d=n[c.strategy];return i.jsx("div",{className:"p-3 border border-[var(--border)] rounded bg-[var(--bg-secondary)]",children:i.jsxs("div",{className:"flex items-start justify-between gap-2",children:[i.jsxs("div",{className:"flex-1 space-y-2",children:[i.jsx("select",{className:"w-full px-2 py-1.5 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm",value:c.strategy,onChange:m=>u(h,m.target.value),children:s.map(m=>{var x;return i.jsx("option",{value:m,children:((x=n[m])==null?void 0:x.label)||m},m)})}),(d==null?void 0:d.description)&&i.jsx("p",{className:"text-xs text-[var(--text-secondary)]",children:d.description}),(d==null?void 0:d.params)&&Object.keys(d.params).length>0&&i.jsx("div",{className:"grid grid-cols-2 gap-2 mt-2",children:Object.entries(d.params).map(([m,x])=>i.jsx(b0,{name:m,schema:x,value:c[m],onChange:k=>o(h,{[m]:k})},m))})]}),i.jsx("button",{type:"button",onClick:()=>l(h),className:"p-1 text-[var(--text-secondary)] hover:text-[var(--error)] transition-colors",children:i.jsx(Rm,{size:16})})]})},h)})})]})}function b0({name:e,schema:t,value:n,onChange:r}){const s=e.replace(/_/g," ");return t.type==="boolean"?i.jsxs("label",{className:"flex items-center gap-2 text-xs",children:[i.jsx("input",{type:"checkbox",checked:!!(n??t.default),onChange:a=>r(a.target.checked),className:"accent-[var(--accent)]"}),i.jsx("span",{className:"capitalize",children:s})]}):i.jsxs("div",{children:[i.jsx("label",{className:"text-xs font-medium block mb-1 capitalize",children:s}),i.jsx("input",{type:t.type==="number"?"number":"text",className:"w-full px-2 py-1 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-xs",value:String(n!==void 0?n:t.default??""),onChange:a=>{if(t.type==="number"){const l=parseFloat(a.target.value);r(isNaN(l)?t.default:l)}else r(a.target.value)},min:t.min,max:t.max,step:t.max&&t.max<=1?.1:1})]})}function C0({variations:e,onChange:t,providers:n}){const r=()=>{const o=n[0],u={provider:(o==null?void 0:o.name)||"azure_openai",model:(o==null?void 0:o.models[0])||"gpt-4o"};t([...e,u])},s=o=>{t(e.filter((u,c)=>c!==o))},a=(o,u)=>{t(e.map((c,h)=>h===o?{...c,...u}:c))},l=(o,u)=>{const c=n.find(h=>h.name===u);a(o,{provider:u,model:(c==null?void 0:c.models[0])||""})};return i.jsxs("div",{className:"space-y-3",children:[i.jsxs("div",{className:"flex items-center justify-between",children:[i.jsx("label",{className:"text-sm font-medium",children:"LLM Configurations"}),i.jsx(V,{type:"button",variant:"ghost",size:"sm",icon:Ui,onClick:r,children:"Add"})]}),e.length===0?i.jsx("p",{className:"text-sm text-[var(--text-secondary)] italic",children:`Uses agent's default LLM. Click "Add" to test different models.`}):i.jsx("div",{className:"space-y-2",children:e.map((o,u)=>{const c=n.find(h=>h.name===o.provider);return i.jsxs("div",{className:"flex items-center gap-2 p-2 border border-[var(--border)] rounded bg-[var(--bg-secondary)]",children:[i.jsx("select",{className:"flex-1 px-2 py-1.5 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm",value:o.provider,onChange:h=>l(u,h.target.value),children:n.map(h=>i.jsx("option",{value:h.name,children:h.label},h.name))}),c&&c.models.length>0?i.jsxs("select",{className:"flex-1 px-2 py-1.5 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm",value:o.model,onChange:h=>a(u,{model:h.target.value}),children:[c.models.map(h=>i.jsx("option",{value:h,children:h},h)),!c.models.includes(o.model)&&o.model&&i.jsx("option",{value:o.model,children:o.model})]}):i.jsx("input",{type:"text",className:"flex-1 px-2 py-1.5 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm",value:o.model,onChange:h=>a(u,{model:h.target.value}),placeholder:"Model ID"}),i.jsx("button",{type:"button",onClick:()=>s(u),className:"p-1 text-[var(--text-secondary)] hover:text-[var(--error)] transition-colors",children:i.jsx(Rm,{size:16})})]},u)})})]})}const Io={compaction:[],tools:[],llm_config:[],instructions:[],instruction_strategies:[]};function _0({agentId:e,agentName:t,agentFramework:n="maf",taskSuite:r,taskCount:s,schema:a,onVariationsChange:l,parallel:o,onParallelChange:u,budget:c,onBudgetChange:h,useLlmEval:d,onUseLlmEvalChange:m}){const[x,k]=S.useState(Io),[g,j]=S.useState(!1),[p,f]=S.useState(""),[v,w]=S.useState(null),C=a.frameworks[n],b=(C==null?void 0:C.compaction_strategies)||Object.keys(a.compaction_strategies),N=a.tool_presets||[],_=a.llm_providers||[],P=(()=>{let L=1;x.compaction.length>0&&(L*=x.compaction.length),x.tools.length>0&&(L*=x.tools.length),x.llm_config.length>0&&(L*=x.llm_config.length);const K=x.instructions.length+x.instruction_strategies.reduce((X,R)=>X+R.max_candidates,0);return K>0&&(L*=K),Math.min(L,c)})(),B=P*s,D=L=>{k(L),l==null||l(L)},U=Je({mutationFn:L=>zo.design(L),onSuccess:L=>{f(L.yaml_content),j(!0)}}),ne=Je({mutationFn:L=>zo.validate(L),onSuccess:L=>{w({valid:L.valid,errors:L.errors,warnings:L.warnings})}}),je=()=>({base_agent_id:e,task_suite:r,variations:x,parallel:o,budget:c,use_llm_eval:d}),Ge=()=>{U.mutate(je())},ie=()=>{ne.mutate(je())},T=()=>{const L=new Blob([p],{type:"text/yaml"}),K=URL.createObjectURL(L),X=document.createElement("a");X.href=K,X.download=`${t}_experiment.yaml`,X.click(),URL.revokeObjectURL(K)},A=x.compaction.length>0||x.tools.length>0||x.llm_config.length>0||x.instructions.length>0||x.instruction_strategies.length>0;return i.jsxs("div",{className:"space-y-6",children:[i.jsxs("div",{className:"flex flex-wrap gap-2",children:[i.jsxs(J,{variant:"info",children:[P," candidates"]}),i.jsxs(J,{children:[s," tasks"]}),i.jsxs(J,{variant:B>100?"warning":"success",children:[B," total runs"]})]}),i.jsx(N0,{variations:x.compaction,onChange:L=>D({...x,compaction:L}),strategies:a.compaction_strategies,availableStrategies:b}),i.jsxs("div",{className:"space-y-3",children:[i.jsx("label",{className:"text-sm font-medium",children:"Tool Presets"}),i.jsx("div",{className:"flex flex-wrap gap-2",children:N.map(L=>i.jsxs("label",{className:`flex items-center gap-2 px-3 py-1.5 border rounded cursor-pointer transition-colors ${x.tools.includes(L.name)?"border-[var(--accent)] bg-[var(--accent)]/10":"border-[var(--border)] hover:border-[var(--accent-dim)]"}`,children:[i.jsx("input",{type:"checkbox",checked:x.tools.includes(L.name),onChange:K=>{const X=K.target.checked?[...x.tools,L.name]:x.tools.filter(R=>R!==L.name);D({...x,tools:X})},className:"accent-[var(--accent)]"}),i.jsx("span",{className:"text-sm",children:L.name}),i.jsxs("span",{className:"text-xs text-[var(--text-secondary)]",children:["(",L.tools.length,")"]})]},L.name))}),x.tools.length>0&&i.jsxs("p",{className:"text-xs text-[var(--text-secondary)]",children:["Selected: ",x.tools.join(", ")]})]}),i.jsx(C0,{variations:x.llm_config,onChange:L=>D({...x,llm_config:L}),providers:_}),i.jsxs("div",{className:"border-t border-[var(--border)] pt-4 space-y-4",children:[i.jsx("h4",{className:"text-sm font-medium",children:"Execution Settings"}),i.jsxs("div",{className:"grid grid-cols-2 gap-4",children:[i.jsx(vn,{label:"Parallel Workers",type:"number",value:o,onChange:L=>u(parseInt(L.target.value)||1),min:1,max:16}),i.jsx(vn,{label:"Budget (max candidates)",type:"number",value:c,onChange:L=>h(parseInt(L.target.value)||100),min:1,max:1e3})]}),i.jsx(Fo,{label:"Use LLM evaluation",checked:d,onChange:L=>m(L.target.checked)}),i.jsx("p",{className:"text-xs text-[var(--text-secondary)] ml-6 -mt-2",children:d?"LLM-as-Judge scores task completion (0-1)":"Simple pass/fail based on task success"})]}),i.jsxs("div",{className:"flex items-center gap-2 border-t border-[var(--border)] pt-4",children:[i.jsx(V,{variant:"secondary",size:"sm",onClick:ie,loading:ne.isPending,children:"Validate"}),i.jsx(V,{variant:"secondary",size:"sm",icon:Nd,onClick:Ge,loading:U.isPending,children:"Export YAML"})]}),v&&i.jsxs("div",{className:`p-3 rounded border ${v.valid?"border-green-500/50 bg-green-500/10":"border-red-500/50 bg-red-500/10"}`,children:[i.jsxs("div",{className:"flex items-center gap-2 mb-2",children:[v.valid?i.jsx(Em,{size:16,className:"text-green-500"}):i.jsx(_m,{size:16,className:"text-red-500"}),i.jsx("span",{className:"font-medium text-sm",children:v.valid?"Configuration valid":"Configuration has issues"})]}),v.errors.length>0&&i.jsx("ul",{className:"text-sm text-red-500 list-disc ml-6",children:v.errors.map((L,K)=>i.jsx("li",{children:L},K))}),v.warnings.length>0&&i.jsx("ul",{className:"text-sm text-yellow-500 list-disc ml-6 mt-1",children:v.warnings.map((L,K)=>i.jsx("li",{children:L},K))})]}),g&&i.jsx("div",{className:"fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4",children:i.jsxs("div",{className:"bg-[var(--bg-primary)] rounded-lg shadow-xl max-w-2xl w-full max-h-[80vh] flex flex-col",children:[i.jsxs("div",{className:"flex items-center justify-between p-4 border-b border-[var(--border)]",children:[i.jsx("h3",{className:"font-medium",children:"Experiment YAML"}),i.jsxs("div",{className:"flex items-center gap-2",children:[i.jsx(V,{variant:"secondary",size:"sm",icon:Nd,onClick:T,children:"Download"}),i.jsx(V,{variant:"ghost",size:"sm",onClick:()=>j(!1),children:"Close"})]})]}),i.jsx("pre",{className:"flex-1 overflow-auto p-4 text-xs font-mono bg-[var(--bg-secondary)]",children:p})]})}),!A&&i.jsx("p",{className:"text-sm text-[var(--text-secondary)] italic",children:"No variations selected. Only the baseline agent will be tested. Add compaction strategies, tool presets, or LLM configs to generate candidates."})]})}function Pd(){const e=Lt(),t=Jt(),[n,r]=S.useState(!1),[s,a]=S.useState(null),{data:l=[],isLoading:o}=ve({queryKey:["configs"],queryFn:()=>Er.list()}),{data:u=[]}=ve({queryKey:["jobs"],queryFn:()=>Ot.list()}),c=Je({mutationFn:Er.create,onSuccess:()=>{t.invalidateQueries({queryKey:["configs"]}),r(!1)}}),h=Je({mutationFn:Er.delete,onSuccess:()=>t.invalidateQueries({queryKey:["configs"]})}),d=m=>{const x=u.filter(j=>j.candidate_ids.includes(m)),k=x.filter(j=>j.status==="running").length,g=x.filter(j=>j.status==="completed").length;return{running:k,completed:g,total:x.length}};return i.jsxs("div",{children:[i.jsxs("div",{className:"flex items-center justify-between mb-6",children:[i.jsxs("div",{children:[i.jsx("h2",{className:"text-xl font-bold",children:"Agents"}),i.jsx("p",{className:"text-sm text-[var(--text-secondary)] mt-1",children:"Define and optimize your agent configurations."})]}),i.jsx(V,{variant:"primary",icon:Ui,onClick:()=>r(!0),children:"New Agent"})]}),o?i.jsxs("div",{className:"flex items-center gap-2 text-[var(--text-secondary)]",children:[i.jsx(ca,{size:16,className:"animate-spin"}),"Loading agents..."]}):l.length===0?i.jsx(E0,{onCreateClick:()=>r(!0)}):i.jsx("div",{className:"grid gap-4 md:grid-cols-2 lg:grid-cols-3",children:l.map(m=>{const x=d(m.id);return i.jsx(T0,{agent:m,stats:x,onClick:()=>e(`/agents/${m.id}`),onOptimize:()=>a(m),onDelete:()=>{confirm(`Delete agent "${m.name}"?`)&&h.mutate(m.id)}},m.id)})}),u.length>0&&i.jsxs("div",{className:"mt-8",children:[i.jsx("h3",{className:"text-lg font-medium mb-4",children:"Recent Optimization Jobs"}),i.jsx("div",{className:"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4",children:u.slice(0,6).map(m=>i.jsx($m,{job:m},m.id))}),u.length>6&&i.jsxs(V,{variant:"ghost",className:"mt-4",onClick:()=>e("/jobs"),children:["View all ",u.length," jobs →"]})]}),i.jsx(O0,{isOpen:n,onClose:()=>r(!1),onSubmit:m=>c.mutate(m),isLoading:c.isPending}),s&&i.jsx(L0,{agent:s,isOpen:!!s,onClose:()=>a(null)})]})}function E0({onCreateClick:e}){return i.jsxs("div",{className:"text-center py-16 border border-dashed border-[var(--border)] rounded-lg",children:[i.jsx("div",{className:"inline-flex items-center justify-center w-12 h-12 rounded-full bg-[var(--bg-tertiary)] mb-4",children:i.jsx(Tm,{size:24,className:"text-[var(--text-secondary)]"})}),i.jsx("h3",{className:"text-lg font-medium mb-2",children:"No agents yet"}),i.jsx("p",{className:"text-[var(--text-secondary)] mb-4 max-w-md mx-auto",children:"Create your first agent to start optimizing. Each agent defines instructions, model, compaction strategy, and tool settings."}),i.jsx(V,{variant:"primary",icon:Ui,onClick:e,children:"Create Your First Agent"})]})}function P0(e){return typeof e=="string"?`tools: ${e}`:Array.isArray(e)?`tools: [${e.length}]`:e&&typeof e=="object"?`tools: [${Object.keys(e).length}]`:"tools: standard"}function T0({agent:e,stats:t,onClick:n,onOptimize:r,onDelete:s}){const a=e.config.compaction,l=(a==null?void 0:a.strategy)==="head_tail"?`compaction ${a.params.head_size}/${a.params.tail_size}`:(a==null?void 0:a.strategy)==="none"?null:(a==null?void 0:a.strategy)||null,o=P0(e.config.tools),u=e.config.framework||"maf";return i.jsxs(se,{className:"flex flex-col cursor-pointer hover:border-[var(--accent-dim)] transition-colors",onClick:n,children:[i.jsxs("div",{className:"flex-1",children:[i.jsxs("div",{className:"flex items-start justify-between mb-3",children:[i.jsxs("div",{children:[i.jsx("h3",{className:"font-medium text-lg",children:e.name}),e.description&&i.jsx("p",{className:"text-sm text-[var(--text-secondary)] mt-1",children:e.description})]}),i.jsx(V,{variant:"ghost",size:"sm",icon:Om,onClick:c=>{c.stopPropagation(),s()}})]}),i.jsxs("div",{className:"flex flex-wrap gap-1.5 mb-4",children:[i.jsx(J,{variant:u==="miniagent"?"success":"default",children:u}),l&&i.jsx(J,{children:l}),i.jsx(J,{children:o})]}),t.total>0&&i.jsxs("div",{className:"text-xs text-[var(--text-secondary)] mb-3",children:[t.running>0&&i.jsxs("span",{className:"text-[var(--accent)]",children:[t.running," running "]}),t.completed>0&&i.jsxs("span",{children:[t.completed," completed"]})]})]}),i.jsx("div",{className:"flex gap-2",children:i.jsx(V,{variant:"primary",icon:Bi,onClick:c=>{c.stopPropagation(),r()},className:"flex-1",children:"Optimize"})})]})}function O0({isOpen:e,onClose:t,onSubmit:n,isLoading:r}){var K,X,R,O,Z,he,Ne;const s=["read_file","write_file","edit_file","bash","grep","think"],[a,l]=S.useState("preset"),[o,u]=S.useState({name:"",description:"",instructions:null,model:null,compaction:{strategy:"none",params:{}},tools:s,framework:"miniagent",llm_config_id:null}),[c,h]=S.useState(!1),[d,m]=S.useState("preset"),[x,k]=S.useState([...s]),[g,j]=S.useState(!1),{data:p}=ve({queryKey:["agent-schema"],queryFn:()=>Am.getAgentSchema()}),{data:f=[]}=ve({queryKey:["llm-configs"],queryFn:()=>a0.list()}),{data:v}=ve({queryKey:["tools"],queryFn:()=>i0.list()}),w=((K=v==null?void 0:v.tools)==null?void 0:K.map(M=>M.name))??s,C=(v==null?void 0:v.presets)??{},b=Object.keys(C),N=(p==null?void 0:p.frameworks)??{},_=Object.keys(N).length>0?Object.keys(N):y0,F=o.framework||"miniagent",P=((R=(X=p==null?void 0:p.frameworks)==null?void 0:X[F])==null?void 0:R.compaction_strategies)??["none","head_tail"],B=(p==null?void 0:p.compaction_strategies)??{},D=(p==null?void 0:p.agent_presets)??[],U=M=>{const H=M.config,dt=H.compaction;n({name:M.name+"-agent",description:M.description,framework:H.framework||"miniagent",tools:H.tools||"standard",compaction:dt||{strategy:"none",params:{}},instructions:H.instructions||null})},ne=M=>{if(M.preventDefault(),!o.name.trim())return;const H={...o};d==="custom"&&(H.tools=x),n(H)},je=((O=o.compaction)==null?void 0:O.strategy)!=="none",Ge=((Z=o.compaction)==null?void 0:Z.strategy)||"none",ie=B[Ge],T=M=>{k(H=>H.includes(M)?H.filter(dt=>dt!==M):[...H,M])},A=M=>{const H=B[M],dt={};if(H!=null&&H.params)for(const[rs,ss]of Object.entries(H.params))ss.default!==void 0&&(dt[rs]=ss.default);u({...o,compaction:{strategy:M,params:dt}})},L=a==="custom"?i.jsxs("div",{className:"flex justify-end gap-2",children:[i.jsx(V,{type:"button",variant:"secondary",onClick:t,children:"Cancel"}),i.jsx(V,{type:"submit",form:"create-agent-form",variant:"primary",disabled:!o.name.trim(),loading:r,children:"Create Agent"})]}):i.jsx("div",{className:"flex justify-end gap-2",children:i.jsx(V,{type:"button",variant:"secondary",onClick:t,children:"Cancel"})});return i.jsxs(ns,{isOpen:e,onClose:t,title:"Create Agent",footer:L,children:[i.jsxs("div",{className:"flex items-center gap-3 mb-4 pb-3 border-b border-[var(--border)]",children:[i.jsx("button",{type:"button",className:`text-sm px-3 py-1.5 rounded transition-colors ${a==="preset"?"bg-[var(--accent)] text-white":"text-[var(--text-secondary)] hover:text-[var(--text-primary)]"}`,onClick:()=>l("preset"),children:"From Preset"}),i.jsx("button",{type:"button",className:`text-sm px-3 py-1.5 rounded transition-colors ${a==="custom"?"bg-[var(--accent)] text-white":"text-[var(--text-secondary)] hover:text-[var(--text-primary)]"}`,onClick:()=>l("custom"),children:"Custom"})]}),a==="preset"?i.jsx("div",{className:"space-y-3",children:D.length===0?i.jsx("p",{className:"text-sm text-[var(--text-secondary)] text-center py-4",children:"Loading presets..."}):D.map(M=>i.jsx("button",{type:"button",className:"w-full text-left p-4 border border-[var(--border)] rounded-lg hover:border-[var(--accent)] hover:bg-[var(--accent)]/5 transition-colors",onClick:()=>U(M),disabled:r,children:i.jsxs("div",{className:"flex items-start justify-between",children:[i.jsxs("div",{className:"flex-1",children:[i.jsx("h4",{className:"font-medium",children:M.label}),i.jsx("p",{className:"text-sm text-[var(--text-secondary)] mt-1",children:M.description}),i.jsxs("div",{className:"flex flex-wrap gap-1.5 mt-2",children:[M.tags.map(H=>i.jsx(J,{variant:"default",children:H},H)),M.suggested_datasets.length>0&&i.jsxs(J,{variant:"success",children:["datasets: ",M.suggested_datasets.join(", ")]})]})]}),i.jsx(gi,{size:16,className:"text-[var(--text-secondary)] mt-1 flex-shrink-0"})]})},M.name))}):i.jsxs("form",{id:"create-agent-form",onSubmit:ne,className:"space-y-4",children:[i.jsx(vn,{label:"Name",value:o.name,onChange:M=>u({...o,name:M.target.value}),placeholder:"e.g., my-coding-agent",required:!0}),i.jsxs("div",{children:[i.jsx("label",{className:"text-sm font-medium block mb-1.5",children:"LLM Configuration"}),i.jsxs("select",{className:"w-full px-3 py-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm",value:o.llm_config_id||"",onChange:M=>u({...o,llm_config_id:M.target.value||null}),children:[i.jsx("option",{value:"",children:"Use environment variables"}),f.map(M=>i.jsxs("option",{value:M.id,children:[M.name," (",j0[M.provider],M.model_id?` - ${M.model_id}`:"",")",M.is_default?" (default)":""]},M.id))]}),i.jsx("p",{className:"text-xs text-[var(--text-secondary)] mt-1",children:f.length===0?"No LLM configs found. Uses environment variables (AZURE_OPENAI_ENDPOINT, OPENAI_API_KEY, etc.)":o.llm_config_id?"Uses the selected LLM configuration.":"Uses environment variables (AZURE_OPENAI_ENDPOINT, OPENAI_API_KEY, etc.)"})]}),i.jsxs("div",{children:[i.jsx("label",{className:"text-sm font-medium block mb-1.5",children:"Framework"}),i.jsx("select",{className:"w-full px-3 py-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm",value:o.framework||"miniagent",onChange:M=>{const H=M.target.value;u({...o,framework:H,compaction:{strategy:"none",params:{}}})},children:_.map(M=>{var H;return i.jsx("option",{value:M,children:((H=N[M])==null?void 0:H.label)||g0[M]||M},M)})}),i.jsx("p",{className:"text-xs text-[var(--text-secondary)] mt-1",children:((he=N[F])==null?void 0:he.description)||(F==="miniagent"?"Lightweight agent with token-aware context management.":F==="langgraph"?"Graph-based workflows with state management.":"Default agent implementation.")})]}),i.jsxs("div",{className:"grid grid-cols-2 gap-4",children:[i.jsx(Fo,{label:"Custom instructions",checked:c,onChange:M=>{h(M.target.checked),M.target.checked||u({...o,instructions:null})}}),i.jsx(Fo,{label:"Enable compaction",checked:je,onChange:M=>{if(M.target.checked){const H=P.find(dt=>dt!=="none")||"head_tail";A(H)}else u({...o,compaction:{strategy:"none",params:{}}})}})]}),c&&i.jsx("textarea",{className:"w-full h-32 px-3 py-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm font-mono resize-y",value:o.instructions||"",onChange:M=>u({...o,instructions:M.target.value||null}),placeholder:"System prompt / instructions for the agent..."}),je&&i.jsxs("div",{className:"space-y-3 p-3 border border-[var(--border)] rounded bg-[var(--bg-secondary)]",children:[i.jsxs("div",{children:[i.jsx("label",{className:"text-sm font-medium block mb-1.5",children:"Compaction Strategy"}),i.jsx("select",{className:"w-full px-3 py-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm",value:Ge,onChange:M=>A(M.target.value),children:P.filter(M=>M!=="none").map(M=>{var H;return i.jsx("option",{value:M,children:((H=B[M])==null?void 0:H.label)||M},M)})}),(ie==null?void 0:ie.description)&&i.jsx("p",{className:"text-xs text-[var(--text-secondary)] mt-1",children:ie.description})]}),(ie==null?void 0:ie.params)&&Object.keys(ie.params).length>0&&i.jsx("div",{className:"grid grid-cols-2 gap-3",children:Object.entries(ie.params).map(([M,H])=>{var ss;const dt=(ss=o.compaction)==null?void 0:ss.params[M],rs=dt!==void 0?dt:H.default;return i.jsxs("div",{children:[i.jsx("label",{className:"text-xs font-medium block mb-1 capitalize",children:M.replace(/_/g," ")}),i.jsx("input",{type:"number",className:"w-full px-3 py-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm",value:typeof rs=="number"?rs:Number(rs)||0,onChange:Hm=>{const Wu=parseFloat(Hm.target.value);u({...o,compaction:{...o.compaction,params:{...o.compaction.params,[M]:isNaN(Wu)?typeof H.default=="number"?H.default:0:Wu}}})},min:H.min,max:H.max,step:H.max&&H.max<=1?.1:1}),i.jsx("p",{className:"text-xs text-[var(--text-secondary)] mt-0.5",children:H.description})]},M)})})]}),i.jsxs("div",{className:"space-y-2",children:[i.jsx("label",{className:"text-sm font-medium",children:"Tools"}),i.jsxs("div",{className:"flex gap-4",children:[i.jsxs("label",{className:"flex items-center gap-2",children:[i.jsx("input",{type:"radio",checked:d==="preset",onChange:()=>m("preset"),className:"accent-[var(--accent)]"}),i.jsx("span",{className:"text-sm",children:"Preset"})]}),i.jsxs("label",{className:"flex items-center gap-2",children:[i.jsx("input",{type:"radio",checked:d==="custom",onChange:()=>m("custom"),className:"accent-[var(--accent)]"}),i.jsx("span",{className:"text-sm",children:"Custom"})]})]}),d==="preset"?i.jsxs(i.Fragment,{children:[i.jsx("select",{className:"w-full px-3 py-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm",value:typeof o.tools=="string"?o.tools:"standard",onChange:M=>u({...o,tools:M.target.value}),children:b.map(M=>i.jsx("option",{value:M,children:M},M))}),i.jsx("p",{className:"text-xs text-[var(--text-secondary)] mt-1",children:((Ne=C[typeof o.tools=="string"?o.tools:"standard"])==null?void 0:Ne.join(", "))??""})]}):i.jsx("div",{className:"grid grid-cols-2 gap-1 p-2 border border-[var(--border)] rounded bg-[var(--bg-secondary)]",children:w.map(M=>i.jsxs("label",{className:"flex items-center gap-2 p-1 text-sm cursor-pointer hover:bg-[var(--bg-tertiary)]",children:[i.jsx("input",{type:"checkbox",checked:x.includes(M),onChange:()=>T(M),className:"accent-[var(--accent)]"}),i.jsx("span",{className:"font-mono text-xs",children:M})]},M))})]}),i.jsxs("div",{className:"border-t border-[var(--border)] pt-3",children:[i.jsxs("button",{type:"button",className:"flex items-center gap-2 text-sm text-[var(--text-secondary)] hover:text-[var(--text-primary)] transition-colors",onClick:()=>j(!g),children:[i.jsx(gi,{size:14,className:`transition-transform ${g?"rotate-90":""}`}),"More options"]}),g&&i.jsx("div",{className:"mt-3",children:i.jsx(vn,{label:"Description (optional)",value:o.description,onChange:M=>u({...o,description:M.target.value}),placeholder:"Brief description of this agent"})})]})]})]})}function L0({agent:e,isOpen:t,onClose:n}){var R;const r=Lt(),s=Jt(),[a,l]=S.useState("ready"),[o,u]=S.useState("quick"),[c,h]=S.useState(!1),[d,m]=S.useState([]),[x,k]=S.useState(!1),[g,j]=S.useState(Io),[p,f]=S.useState(4),[v,w]=S.useState(100),[C,b]=S.useState(!1),[N,_]=S.useState(null),{data:F=[]}=ve({queryKey:["tasks"],queryFn:()=>Et.list()}),{data:P=[]}=ve({queryKey:["suites"],queryFn:()=>Et.listSuites()}),{data:B}=ve({queryKey:["agent-schema"],queryFn:()=>Am.getAgentSchema()}),D=P.map(O=>({value:O.name,label:O.name.charAt(0).toUpperCase()+O.name.slice(1),description:O.description,tasks:O.task_count})),U=Je({mutationFn:Et.importSuite,onSuccess:O=>{s.invalidateQueries({queryKey:["tasks"]}),m(O.map(Z=>Z.id))}}),ne=Je({mutationFn:async O=>{const Z=await Ot.create(O);return Ot.start(Z.id).next(),Z},onSuccess:O=>{s.invalidateQueries({queryKey:["jobs"]}),_(O.id),l("success")}}),Ge=x?(()=>{let O=1;g.compaction.length>0&&(O*=g.compaction.length),g.tools.length>0&&(O*=g.tools.length),g.llm_config.length>0&&(O*=g.llm_config.length);const Z=g.instructions.length+g.instruction_strategies.reduce((he,Ne)=>he+Ne.max_candidates,0);return Z>0&&(O*=Z),Math.min(O,v)})():1,ie=c?d.length:((R=D.find(O=>O.value===o))==null?void 0:R.tasks)||3,T=Ge*ie,A=async()=>{l("starting");let O=d;if(!c)try{O=(await U.mutateAsync(o)).map(H=>H.id)}catch(M){console.error("Failed to import suite:",M),alert(`Failed to import task suite: ${o}`),l("ready");return}if(O.length===0){alert("No tasks selected. Please select tasks or choose a task suite."),l("ready");return}let Z;if(x&&(g.compaction.length>0||g.tools.length>0||g.llm_config.length>0||g.instructions.length>0||g.instruction_strategies.length>0))try{Z=(await zo.generateCandidates({base_agent_id:e.id,variations:g,budget:v})).candidate_ids}catch(M){console.error("Failed to generate candidates:",M),alert(`Failed to generate candidates: ${M instanceof Error?M.message:"Unknown error"}`),l("ready");return}else Z=[e.id];const Ne={name:`${e.name} optimization (${Z.length} candidates × ${O.length} tasks)`,candidate_ids:Z,task_ids:O,parallel:p,use_llm_eval:C};ne.mutate(Ne)},L=O=>{m(Z=>Z.includes(O)?Z.filter(he=>he!==O):[...Z,O])},K=()=>{l("ready"),_(null),k(!1),j(Io),n()},X=()=>a==="success"&&N?i.jsxs("div",{className:"flex justify-end gap-3",children:[i.jsx(V,{variant:"secondary",onClick:K,children:"Close"}),i.jsx(V,{variant:"primary",icon:Gs,onClick:()=>{K(),r(`/jobs/${N}`)},children:"View Job"})]}):a==="starting"?null:i.jsxs("div",{className:"flex justify-end gap-2",children:[i.jsx(V,{variant:"secondary",onClick:n,children:"Cancel"}),i.jsxs(V,{variant:"primary",icon:Gs,onClick:A,disabled:c&&d.length===0,children:["Start Optimization (",T," runs)"]})]});return i.jsx(ns,{isOpen:t,onClose:K,title:`Optimize: ${e.name}`,footer:X(),size:"lg",children:a==="success"&&N?i.jsxs("div",{className:"flex flex-col items-center py-8",children:[i.jsx("div",{className:"w-12 h-12 rounded-full bg-green-500/20 flex items-center justify-center mb-4",children:i.jsx(Bi,{size:24,className:"text-green-500"})}),i.jsx("h3",{className:"text-lg font-medium mb-2",children:"Job Started!"}),i.jsx("p",{className:"text-[var(--text-secondary)] text-center mb-2",children:"Optimization job is now running"}),i.jsxs("code",{className:"text-xs bg-[var(--bg-primary)] px-3 py-1.5 rounded font-mono",children:["ID: ",N.slice(0,8),"..."]})]}):a==="starting"?i.jsxs("div",{className:"flex flex-col items-center py-8",children:[i.jsx(ca,{size:32,className:"animate-spin text-[var(--accent)] mb-4"}),i.jsx("p",{className:"text-[var(--text-secondary)]",children:U.isPending?"Importing tasks...":"Creating optimization job..."})]}):i.jsxs("div",{className:"space-y-5",children:[i.jsxs("div",{children:[i.jsx("label",{className:"text-sm font-medium mb-2 block",children:"Task Suite"}),i.jsxs("select",{className:"w-full px-3 py-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm",value:c?"__custom__":o,onChange:O=>{O.target.value==="__custom__"?h(!0):(h(!1),u(O.target.value))},children:[D.map(O=>i.jsxs("option",{value:O.value,children:[O.label," (",O.tasks," tasks) — ",O.description]},O.value)),F.length>0&&i.jsx("option",{value:"__custom__",children:"Custom Selection"})]})]}),c&&F.length>0&&i.jsx("div",{className:"max-h-48 overflow-y-auto border border-[var(--border)] rounded p-2 space-y-1",children:F.map(O=>i.jsxs("label",{className:"flex items-center gap-2 p-2 hover:bg-[var(--bg-tertiary)] cursor-pointer rounded",children:[i.jsx("input",{type:"checkbox",checked:d.includes(O.id),onChange:()=>L(O.id),className:"accent-[var(--accent)]"}),i.jsx("span",{className:"text-sm",children:O.name}),O.suite&&i.jsx(J,{children:O.suite})]},O.id))}),i.jsxs("div",{className:"border-t border-[var(--border)] pt-3",children:[i.jsxs("button",{type:"button",className:"flex items-center gap-2 text-sm text-[var(--text-secondary)] hover:text-[var(--text-primary)] transition-colors",onClick:()=>k(!x),children:[i.jsx(gi,{size:14,className:`transition-transform ${x?"rotate-90":""}`}),"Advanced Settings",x&&i.jsx("span",{className:"text-xs text-[var(--text-secondary)]",children:"(experiment design, variations, execution)"})]}),x&&B&&i.jsx("div",{className:"mt-4",children:i.jsx(_0,{agentId:e.id,agentName:e.name,agentFramework:e.config.framework,taskSuite:c?void 0:o,taskCount:ie,schema:B,onVariationsChange:j,parallel:p,onParallelChange:f,budget:v,onBudgetChange:w,useLlmEval:C,onUseLlmEvalChange:b})})]})]})})}function R0(e){const t=[],n=r=>r.type==="trace_span"&&typeof r.data=="object"&&r.data!==null?r.data:"span_id"in r?r:null;if(Array.isArray(e.spans)){for(const r of e.spans)if(typeof r=="object"&&r!==null){const s=n(r);s&&t.push(s)}}else if(e.span_id)t.push(e);else for(const r in e){const s=e[r];if(typeof s=="object"&&s!==null){const a=n(s);if(a)t.push(a);else if(Array.isArray(s)){for(const l of s)if(typeof l=="object"&&l!==null){const o=n(l);o&&t.push(o)}}}}return t}function Um(e){const t=new Map,n=[];for(const s of e)t.set(s.span_id,{span:s,children:[]});for(const s of e){const a=t.get(s.span_id);s.parent_span_id&&t.has(s.parent_span_id)?t.get(s.parent_span_id).children.push(a):n.push(a)}const r=s=>{s.sort((a,l)=>(a.span.start_time||0)-(l.span.start_time||0)),s.forEach(a=>r(a.children))};return r(n),n}function M0(e){return e.includes("Agent")||e.includes("agent")?"bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-200":e.includes("chat")||e.includes("Chat")||e.includes("llm")?"bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200":e.includes("tool")||e.includes("execute")||e.includes("bash")?"bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200":"bg-orange-100 text-orange-800 dark:bg-orange-900 dark:text-orange-200"}function z0(e){return e>=1e3?`${(e/1e3).toFixed(2)}s`:`${e.toFixed(0)}ms`}function Hu({node:e,depth:t=0}){var d,m;const[n,r]=S.useState(t<2),[s,a]=S.useState(!1),{span:l}=e,o=e.children.length>0,u=(d=l.attributes)==null?void 0:d["gen_ai.usage.input_tokens"],c=(m=l.attributes)==null?void 0:m["gen_ai.usage.output_tokens"],h=u!==void 0||c!==void 0;return i.jsxs("div",{className:"relative",children:[t>0&&i.jsx("div",{className:"absolute left-0 top-0 bottom-0 border-l-2 border-[var(--border)]",style:{marginLeft:`${(t-1)*16+8}px`}}),i.jsxs("div",{className:"flex items-center gap-2 py-1.5 px-1 hover:bg-[var(--bg-primary)] rounded transition-colors cursor-pointer",style:{paddingLeft:`${t*16}px`},onClick:()=>o?r(!n):a(!s),children:[i.jsx("div",{className:"w-4 h-4 flex items-center justify-center text-[var(--text-secondary)]",children:o?n?"▼":"▶":s?"▼":"▶"}),i.jsx("span",{className:`text-xs px-1.5 py-0.5 rounded font-medium ${M0(l.operation_name)}`,children:l.operation_name.replace("ChatAgent.","").replace("invoke_agent ","")}),l.duration_ms!==void 0&&i.jsx("span",{className:"text-xs text-[var(--text-secondary)] font-mono",children:z0(l.duration_ms)}),h&&i.jsxs("span",{className:"text-xs text-[var(--text-secondary)] font-mono",children:[u!==void 0&&i.jsxs("span",{className:"text-blue-400",children:["↑",String(u)]}),u!==void 0&&c!==void 0&&i.jsx("span",{className:"mx-0.5",children:"/"}),c!==void 0&&i.jsxs("span",{className:"text-green-400",children:["↓",String(c)]})]})]}),s&&!o&&i.jsx("div",{className:"ml-4 mt-1 mb-2 p-2 bg-[var(--bg-primary)] rounded border border-[var(--border)] text-xs",style:{marginLeft:`${t*16+20}px`},children:i.jsxs("div",{className:"space-y-1",children:[l.span_id&&i.jsxs("div",{className:"flex gap-2",children:[i.jsx("span",{className:"text-[var(--text-secondary)] w-20",children:"Span ID:"}),i.jsx("span",{className:"font-mono text-xs break-all",children:l.span_id})]}),l.trace_id&&i.jsxs("div",{className:"flex gap-2",children:[i.jsx("span",{className:"text-[var(--text-secondary)] w-20",children:"Trace ID:"}),i.jsx("span",{className:"font-mono text-xs break-all",children:l.trace_id})]}),l.status&&i.jsxs("div",{className:"flex gap-2",children:[i.jsx("span",{className:"text-[var(--text-secondary)] w-20",children:"Status:"}),i.jsx("span",{className:`px-1.5 py-0.5 rounded text-xs ${l.status==="OK"||l.status==="StatusCode.UNSET"?"bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200":"bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200"}`,children:l.status})]}),Object.keys(l.attributes||{}).length>0&&i.jsxs("div",{className:"mt-2",children:[i.jsx("span",{className:"text-[var(--text-secondary)] block mb-1",children:"Attributes:"}),i.jsx("pre",{className:"text-xs bg-[var(--bg-secondary)] border border-[var(--border)] rounded p-2 overflow-auto max-h-32 whitespace-pre-wrap break-all",children:JSON.stringify(l.attributes,null,2)})]})]})}),o&&n&&i.jsx("div",{children:e.children.map((x,k)=>i.jsx(Hu,{node:x,depth:t+1},x.span.span_id||k))})]})}function Bm({trace:e}){const[t,n]=S.useState("tree"),r=S.useMemo(()=>R0(e),[e]),s=S.useMemo(()=>Um(r),[r]);return Object.keys(e).length===0?null:i.jsxs(se,{className:"mb-6",children:[i.jsxs("div",{className:"flex items-center justify-between mb-3",children:[i.jsx("h3",{className:"font-medium",children:"Trace Data"}),i.jsxs("div",{className:"flex gap-1",children:[i.jsx("button",{onClick:()=>n("tree"),className:`px-2 py-1 text-xs rounded ${t==="tree"?"bg-[var(--accent)] text-white":"bg-[var(--bg-primary)] text-[var(--text-secondary)] hover:text-[var(--text-primary)]"}`,children:"Tree"}),i.jsx("button",{onClick:()=>n("raw"),className:`px-2 py-1 text-xs rounded ${t==="raw"?"bg-[var(--accent)] text-white":"bg-[var(--bg-primary)] text-[var(--text-secondary)] hover:text-[var(--text-primary)]"}`,children:"Raw"})]})]}),t==="tree"?r.length>0?i.jsx("div",{className:"border border-[var(--border)] rounded overflow-hidden",children:i.jsxs("div",{className:"p-2",children:[i.jsxs("div",{className:"flex items-center gap-2 mb-2 text-xs text-[var(--text-secondary)]",children:[i.jsxs(J,{variant:"default",children:[r.length," spans"]}),i.jsx("span",{children:"•"}),i.jsx("span",{children:"Click to expand details"})]}),s.map((a,l)=>i.jsx(Hu,{node:a,depth:0},a.span.span_id||l))]})}):i.jsx("div",{className:"text-sm text-[var(--text-secondary)] text-center py-4",children:"No structured spans found. View raw data below."}):i.jsx("pre",{className:"text-xs bg-[var(--bg-primary)] p-3 overflow-x-auto border border-[var(--border)] max-h-96 whitespace-pre-wrap",children:JSON.stringify(e,null,2)})]})}function F0({spans:e,isLive:t=!1}){const n=S.useRef(null),r=S.useMemo(()=>Um(e),[e]);return S.useEffect(()=>{n.current&&t&&n.current.scrollTo({top:n.current.scrollHeight,behavior:"smooth"})},[e.length,t]),i.jsxs("div",{className:"border border-[var(--border)] rounded overflow-hidden h-full flex flex-col",children:[i.jsxs("div",{className:"flex items-center gap-2 p-2 border-b border-[var(--border)] bg-[var(--bg-secondary)]",children:[i.jsxs(J,{variant:"default",children:[e.length," spans"]}),t&&i.jsx("span",{className:"animate-pulse",children:i.jsx(J,{variant:"info",children:"Live"})})]}),i.jsx("div",{ref:n,className:"flex-1 overflow-auto p-2",children:r.length>0?r.map((s,a)=>i.jsx(Hu,{node:s,depth:0},s.span.span_id||a)):i.jsx("div",{className:"text-sm text-[var(--text-secondary)] text-center py-4",children:t?"Waiting for spans...":"No spans recorded"})})]})}function I0({agent:e}){const[t,n]=S.useState(""),[r,s]=S.useState(null),[a,l]=S.useState("idle"),[o,u]=S.useState(null),[c,h]=S.useState(""),[d,m]=S.useState([]),[x,k]=S.useState(null),[g,j]=S.useState(null),[p,f]=S.useState([]),v=S.useRef(null),{data:w=[]}=ve({queryKey:["tasks"],queryFn:()=>Et.list()});S.useEffect(()=>{v.current&&a==="running"&&(v.current.scrollTop=v.current.scrollHeight)},[c,a]);const C=D=>{if(s(D),D){const U=w.find(ne=>ne.id===D);U&&n(U.prompt)}},b=async()=>{if(t.trim()){l("running"),h(""),m([]),k(null),j(null),f([]);try{const D=await Es.create({agent_id:e.id,prompt:t.trim(),task_id:r||void 0});u(D.id);for await(const U of Es.start(D.id))N(U)}catch(D){j(D instanceof Error?D.message:"Test failed"),l("failed")}}},N=D=>{switch(D.event){case"started":break;case"execution":D.execution_event==="text_delta"&&D.content?h(U=>U+D.content):D.execution_event==="tool_call_start"&&D.tool_name?f(U=>[...U,{name:D.tool_name}]):D.execution_event==="tool_result"&&D.content&&f(U=>{if(U.length>0){const ne=[...U];return ne[ne.length-1]={...ne[ne.length-1],content:D.content},ne}return U});break;case"span":if(D.span){const U=D.span;if(U.data){const ne={span_id:U.data.span_id||"",trace_id:U.data.trace_id||"",parent_span_id:U.data.parent_span_id||null,operation_name:U.data.operation_name||"",start_time:U.timestamp?new Date(U.timestamp).getTime():Date.now(),end_time:Date.now(),duration_ms:U.data.duration_ms||0,status:U.data.status||"OK",attributes:U.data.attributes||{}};m(je=>[...je,ne])}}break;case"complete":l("completed"),D.result&&k(D.result);break;case"error":j(D.message),l("failed");break}},_=async()=>{if(o)try{await Es.cancel(o)}catch{}l("idle")},F=()=>{l("idle"),u(null),h(""),m([]),k(null),j(null),f([])},P=a==="running",B=a==="completed"||a==="failed";return i.jsxs("div",{className:"h-full flex flex-col",children:[!P&&!B&&i.jsxs("div",{className:"mb-4 space-y-3",children:[i.jsxs("div",{className:"flex gap-3",children:[i.jsxs("div",{className:"flex-1",children:[i.jsx("label",{className:"block text-sm font-medium mb-1",children:"Select Task (optional)"}),i.jsxs("select",{value:r||"",onChange:D=>C(D.target.value||null),className:"w-full px-3 py-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm",children:[i.jsx("option",{value:"",children:"Custom prompt..."}),w.map(D=>i.jsx("option",{value:D.id,children:D.name},D.id))]})]}),i.jsx("div",{className:"flex items-end",children:i.jsx(V,{variant:"primary",icon:Gs,onClick:b,disabled:!t.trim(),children:"Run Test"})})]}),i.jsxs("div",{children:[i.jsx("label",{className:"block text-sm font-medium mb-1",children:"Prompt"}),i.jsx("textarea",{value:t,onChange:D=>n(D.target.value),placeholder:"Enter a test prompt for the agent...",className:"w-full h-32 px-3 py-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm font-mono resize-none"})]})]}),(P||B)&&i.jsxs("div",{className:"flex-1 flex flex-col min-h-0",children:[i.jsxs("div",{className:"flex items-center justify-between mb-3",children:[i.jsxs("div",{className:"flex items-center gap-2",children:[P&&i.jsxs(i.Fragment,{children:[i.jsx("span",{className:"animate-pulse",children:i.jsx(J,{variant:"info",children:"Running"})}),i.jsx(V,{variant:"ghost",size:"sm",icon:Pg,onClick:_,children:"Cancel"})]}),a==="completed"&&i.jsx(J,{variant:"success",children:"Completed"}),a==="failed"&&i.jsx(J,{variant:"error",children:"Failed"})]}),i.jsxs("div",{className:"flex items-center gap-3",children:[x&&i.jsxs("div",{className:"flex items-center gap-3 text-xs text-[var(--text-secondary)]",children:[i.jsxs("span",{className:"flex items-center gap-1",children:[i.jsx(vg,{size:12}),x.duration_seconds.toFixed(2),"s"]}),i.jsxs("span",{className:"flex items-center gap-1",children:[i.jsx(xg,{size:12}),x.tokens_total," tokens"]}),x.passed!==null&&(x.passed?i.jsx(Em,{size:14,className:"text-green-500"}):i.jsx(Og,{size:14,className:"text-red-500"}))]}),B&&i.jsx(V,{variant:"secondary",size:"sm",onClick:F,children:"New Test"})]})]}),i.jsxs("div",{className:"flex-1 grid grid-cols-2 gap-4 min-h-0",children:[i.jsxs("div",{className:"flex flex-col border border-[var(--border)] rounded overflow-hidden",children:[i.jsx("div",{className:"px-3 py-2 border-b border-[var(--border)] bg-[var(--bg-secondary)] text-sm font-medium",children:"Output"}),i.jsxs("div",{ref:v,className:"flex-1 overflow-auto p-3 font-mono text-sm whitespace-pre-wrap bg-[var(--bg-primary)]",children:[c||(P?"Waiting for response...":"No output"),p.length>0&&i.jsxs("div",{className:"mt-3 space-y-2 border-t border-[var(--border)] pt-3",children:[i.jsx("div",{className:"text-xs text-[var(--text-secondary)] uppercase tracking-wider",children:"Tool Calls"}),p.map((D,U)=>i.jsxs("div",{className:"p-2 bg-green-500/10 border border-green-500/20 rounded text-xs",children:[i.jsx(J,{variant:"success",children:D.name}),D.content&&i.jsxs("div",{className:"mt-1 text-[var(--text-secondary)] truncate max-w-full",children:[D.content.substring(0,200),D.content.length>200&&"..."]})]},U))]})]})]}),i.jsx(F0,{spans:d,isLive:P})]}),g&&i.jsx("div",{className:"mt-3 p-3 bg-red-500/10 border border-red-500/20 rounded text-sm text-red-400",children:g}),B&&o&&i.jsx("div",{className:"mt-3 flex items-center justify-end pt-3 border-t border-[var(--border)]",children:i.jsx(Js,{to:`/tests/${o}`,children:i.jsx(V,{variant:"primary",iconRight:jg,children:"View Full Details"})})})]})]})}function D0(){const{agentId:e}=Di(),t=Lt(),n=Jt(),[r,s]=S.useState("overview"),{data:a,isLoading:l}=ve({queryKey:["configs",e],queryFn:()=>Er.get(e),enabled:!!e}),{data:o=[]}=ve({queryKey:["tests",{agent_id:e}],queryFn:()=>Es.list({agent_id:e}),enabled:!!e}),{data:u=[]}=ve({queryKey:["jobs"],queryFn:()=>Ot.list()}),c=Je({mutationFn:d=>Er.delete(d),onSuccess:()=>{n.invalidateQueries({queryKey:["configs"]}),t("/agents")}}),h=u.filter(d=>d.candidate_ids.includes(e||""));return l?i.jsx("div",{className:"text-[var(--text-secondary)]",children:"Loading..."}):a?i.jsxs("div",{className:"h-full flex flex-col",children:[i.jsxs("div",{className:"mb-6",children:[i.jsx("div",{className:"flex items-center gap-3 mb-2",children:i.jsx("button",{onClick:()=>t("/agents"),className:"text-[var(--text-secondary)] hover:text-[var(--text-primary)]",children:"← Back to Agents"})}),i.jsxs("div",{className:"flex items-center justify-between",children:[i.jsxs("div",{className:"flex items-center gap-3",children:[i.jsx("h2",{className:"text-xl font-bold",children:a.name}),a.is_auto_generated&&i.jsx(J,{variant:"info",children:"Auto-generated"})]}),i.jsx("div",{className:"flex gap-2",children:i.jsx(V,{variant:"secondary",icon:Om,onClick:()=>{confirm(`Delete agent "${a.name}"?`)&&c.mutate(a.id)},children:"Delete"})})]}),a.description&&i.jsx("p",{className:"text-sm text-[var(--text-secondary)] mt-1",children:a.description})]}),i.jsxs("div",{className:"flex gap-1 mb-6 border-b border-[var(--border)]",children:[i.jsx(jl,{active:r==="overview",onClick:()=>s("overview"),icon:i.jsx(Tm,{size:16}),children:"Overview"}),i.jsx(jl,{active:r==="test",onClick:()=>s("test"),icon:i.jsx(Gs,{size:16}),children:"Test"}),i.jsx(jl,{active:r==="history",onClick:()=>s("history"),icon:i.jsx(Ng,{size:16}),badge:o.length,children:"History"})]}),i.jsxs("div",{className:"flex-1 min-h-0",children:[r==="overview"&&i.jsx(A0,{agent:a,recentTests:o,jobs:h}),r==="test"&&i.jsx(I0,{agent:a}),r==="history"&&i.jsx($0,{tests:o})]})]}):i.jsx("div",{className:"text-[var(--text-secondary)]",children:"Agent not found"})}function jl({active:e,onClick:t,icon:n,badge:r,children:s}){return i.jsxs("button",{onClick:t,className:`flex items-center gap-2 px-4 py-2 text-sm font-medium border-b-2 transition-colors ${e?"border-[var(--accent)] text-[var(--text-primary)]":"border-transparent text-[var(--text-secondary)] hover:text-[var(--text-primary)]"}`,children:[n,s,r!==void 0&&r>0&&i.jsx("span",{className:"ml-1 px-1.5 py-0.5 text-xs bg-[var(--bg-tertiary)] rounded",children:r})]})}function A0({agent:e,recentTests:t,jobs:n}){var k,g;const r=Lt(),s=Jt(),a=e.config,[l,o]=S.useState("quick"),[u,c]=S.useState(!1),{data:h=[]}=ve({queryKey:["suites"],queryFn:()=>Et.listSuites()}),d=Je({mutationFn:l0.start,onSuccess:j=>{s.invalidateQueries({queryKey:["jobs"]}),c(!1),r(`/jobs/${j.id}`)},onError:()=>{c(!1)}}),m=()=>{c(!0),d.mutate({agent_id:e.id,suite_name:l,use_llm_eval:!0,parallel:4})},x=()=>{const j=a.tools;return typeof j=="string"?j:Array.isArray(j)?j.join(", "):j&&typeof j=="object"?Object.keys(j).join(", "):"standard"};return i.jsxs("div",{className:"space-y-6",children:[i.jsxs(se,{children:[i.jsx("h3",{className:"font-medium mb-4",children:"Configuration"}),i.jsxs("div",{className:"grid grid-cols-2 gap-4 text-sm",children:[i.jsxs("div",{children:[i.jsx("span",{className:"text-[var(--text-secondary)]",children:"Model:"}),i.jsx("div",{className:"font-mono",children:a.model||"default"})]}),i.jsxs("div",{children:[i.jsx("span",{className:"text-[var(--text-secondary)]",children:"Compaction:"}),i.jsx("div",{className:"font-mono",children:!a.compaction||a.compaction.strategy==="none"?"disabled":`${a.compaction.strategy} (${((k=a.compaction.params)==null?void 0:k.head_size)||0}/${((g=a.compaction.params)==null?void 0:g.tail_size)||0})`})]}),i.jsxs("div",{className:"col-span-2",children:[i.jsx("span",{className:"text-[var(--text-secondary)]",children:"Tools:"}),i.jsx("div",{className:"font-mono",children:x()})]}),a.instructions&&i.jsxs("div",{className:"col-span-2",children:[i.jsx("span",{className:"text-[var(--text-secondary)]",children:"Instructions:"}),i.jsx("pre",{className:"mt-1 p-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-xs whitespace-pre-wrap max-h-32 overflow-auto",children:a.instructions})]})]})]}),i.jsxs(se,{children:[i.jsx("h3",{className:"font-medium mb-3",children:"Evaluate"}),i.jsx("p",{className:"text-sm text-[var(--text-secondary)] mb-3",children:"Run this agent on a task suite to measure quality and cost."}),i.jsxs("div",{className:"flex items-center gap-3",children:[i.jsx("select",{className:"flex-1 px-3 py-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm",value:l,onChange:j=>o(j.target.value),disabled:u,children:h.map(j=>i.jsxs("option",{value:j.name,children:[j.name.charAt(0).toUpperCase()+j.name.slice(1)," (",j.task_count," tasks)"]},j.name))}),i.jsx(V,{variant:"primary",icon:u?ca:Gs,onClick:m,disabled:u,loading:u,children:"Evaluate"})]})]}),i.jsxs(se,{children:[i.jsxs("div",{className:"flex items-center justify-between mb-4",children:[i.jsx("h3",{className:"font-medium",children:"Recent Tests"}),t.length>0&&i.jsxs("span",{className:"text-xs text-[var(--text-secondary)]",children:[t.length," total"]})]}),t.length===0?i.jsx("div",{className:"text-sm text-[var(--text-secondary)] text-center py-4",children:'No tests yet. Click the "Test" tab to run one.'}):i.jsx("div",{className:"space-y-2",children:t.slice(0,5).map(j=>i.jsxs(Js,{to:`/tests/${j.id}`,className:"flex items-center justify-between p-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded hover:border-[var(--accent-dim)] transition-colors",children:[i.jsxs("div",{className:"flex items-center gap-2",children:[i.jsx(Qm,{status:j.status}),i.jsxs("span",{className:"text-sm truncate max-w-[200px]",children:[j.prompt.slice(0,50),"..."]})]}),i.jsxs("div",{className:"flex items-center gap-3 text-xs text-[var(--text-secondary)]",children:[i.jsxs("span",{children:[j.duration_seconds.toFixed(1),"s"]}),i.jsxs("span",{children:[j.tokens_total," tok"]})]})]},j.id))})]}),i.jsxs(se,{children:[i.jsxs("div",{className:"flex items-center justify-between mb-4",children:[i.jsx("h3",{className:"font-medium",children:"Optimization Jobs"}),i.jsx(V,{variant:"secondary",size:"sm",icon:Bi,onClick:()=>r("/agents",{state:{optimizeAgent:e}}),children:"New Job"})]}),n.length===0?i.jsx("div",{className:"text-sm text-[var(--text-secondary)] text-center py-4",children:"No optimization jobs yet."}):i.jsx("div",{className:"space-y-2",children:n.slice(0,5).map(j=>i.jsxs(Js,{to:`/jobs/${j.id}`,className:"flex items-center justify-between p-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded hover:border-[var(--accent-dim)] transition-colors",children:[i.jsxs("div",{className:"flex items-center gap-2",children:[i.jsx(J,{variant:j.status==="completed"?"success":j.status==="running"?"info":"default",children:j.status}),i.jsx("span",{className:"text-sm",children:j.name})]}),i.jsx("span",{className:"text-xs text-[var(--text-secondary)]",children:new Date(j.created_at).toLocaleDateString()})]},j.id))})]})]})}function $0({tests:e}){return e.length===0?i.jsx("div",{className:"text-center py-8 text-[var(--text-secondary)]",children:"No test history yet. Run a test to see results here."}):i.jsx("div",{className:"space-y-2",children:e.map(t=>i.jsxs(Js,{to:`/tests/${t.id}`,className:"flex items-center justify-between p-3 bg-[var(--bg-secondary)] border border-[var(--border)] rounded hover:border-[var(--accent-dim)] transition-colors",children:[i.jsxs("div",{className:"flex-1 min-w-0",children:[i.jsxs("div",{className:"flex items-center gap-2 mb-1",children:[i.jsx(Qm,{status:t.status}),t.score!==null&&i.jsxs("span",{className:`text-sm font-medium ${t.passed?"text-green-400":"text-red-400"}`,children:[(t.score*100).toFixed(0),"%"]})]}),i.jsx("p",{className:"text-sm truncate",children:t.prompt})]}),i.jsxs("div",{className:"flex flex-col items-end gap-1 ml-4",children:[i.jsx("span",{className:"text-xs text-[var(--text-secondary)]",children:new Date(t.created_at).toLocaleString()}),i.jsxs("div",{className:"flex items-center gap-2 text-xs text-[var(--text-secondary)]",children:[i.jsxs("span",{children:[t.duration_seconds.toFixed(1),"s"]}),i.jsx("span",{children:"•"}),i.jsxs("span",{children:[t.tokens_total," tokens"]})]})]})]},t.id))})}function Qm({status:e}){const t={completed:"success",failed:"error",running:"info",cancelled:"warning",pending:"default"};return i.jsx(J,{variant:t[e]||"default",children:e})}function U0(){const e=Jt(),[t,n]=S.useState(!1),[r,s]=S.useState(!1),[a,l]=S.useState(null),[o,u]=S.useState(new Set),c=p=>{u(f=>{const v=new Set(f);return v.has(p)?v.delete(p):v.add(p),v})},{data:h=[],isLoading:d}=ve({queryKey:["tasks"],queryFn:()=>Et.list()}),m=Je({mutationFn:Et.create,onSuccess:()=>{e.invalidateQueries({queryKey:["tasks"]}),n(!1)}}),x=Je({mutationFn:Et.importSuite,onSuccess:()=>{e.invalidateQueries({queryKey:["tasks"]}),s(!1)}}),k=Je({mutationFn:Et.delete,onSuccess:()=>{e.invalidateQueries({queryKey:["tasks"]}),l(null)}}),g=h.reduce((p,f)=>{const v=f.suite||"custom";return p[v]||(p[v]=[]),p[v].push(f),p},{}),j=Object.keys(g).sort((p,f)=>p==="custom"?-1:f==="custom"?1:p.localeCompare(f));return i.jsxs("div",{children:[i.jsxs("div",{className:"flex items-center justify-between mb-6",children:[i.jsxs("div",{children:[i.jsx("h2",{className:"text-xl font-bold",children:"Datasets"}),i.jsx("p",{className:"text-sm text-[var(--text-secondary)] mt-1",children:"Task datasets for evaluating agent configurations."})]}),i.jsxs("div",{className:"flex gap-2",children:[i.jsx(V,{variant:"secondary",onClick:()=>s(!0),children:"Import Suite"}),i.jsx(V,{variant:"primary",onClick:()=>n(!0),children:"+ New Task"})]})]}),d?i.jsx("div",{className:"text-[var(--text-secondary)]",children:"Loading..."}):h.length===0?i.jsx("div",{className:"text-center py-12 text-[var(--text-secondary)]",children:"No tasks yet. Create one or import a built-in suite."}):i.jsx("div",{className:"space-y-4",children:j.map(p=>{const f=g[p],v=!o.has(p);return i.jsxs("div",{children:[i.jsxs("button",{onClick:()=>c(p),className:"flex items-center gap-2 py-2 hover:text-[var(--accent)] transition-colors",children:[v?i.jsx(pg,{size:16,className:"text-[var(--text-secondary)]"}):i.jsx(gi,{size:16,className:"text-[var(--text-secondary)]"}),i.jsx("h3",{className:"text-sm font-medium uppercase tracking-wide",children:p==="custom"?"Custom Tasks":`${p} Suite`}),i.jsx(J,{variant:p==="custom"?"default":"info",children:f.length})]}),v&&i.jsx("div",{className:"grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-3 mt-2",children:f.map(w=>i.jsx(se,{selectable:!0,onClick:()=>l(w),children:i.jsxs("div",{className:"h-32 flex flex-col",children:[i.jsxs("div",{className:"flex items-center gap-2 flex-wrap",children:[i.jsx("span",{className:"font-medium",children:w.name}),w.category&&w.category!=="default"&&i.jsx(J,{variant:"default",children:w.category})]}),i.jsx("p",{className:"text-sm text-[var(--text-secondary)] mt-1 line-clamp-2 flex-1",children:w.prompt}),i.jsx("div",{className:"text-xs text-[var(--text-tertiary)] mt-auto pt-1",children:w.criteria.length>0?i.jsxs("span",{children:[w.criteria.length," eval criteria"]}):i.jsx("span",{className:"text-[var(--text-tertiary)]",children:"No eval criteria"})})]})},w.id))})]},p)})}),i.jsx(B0,{task:a,onClose:()=>l(null),onDelete:p=>{confirm("Delete this task?")&&k.mutate(p)}}),i.jsx(Q0,{isOpen:t,onClose:()=>n(!1),onSubmit:p=>m.mutate(p),isLoading:m.isPending}),i.jsx(V0,{isOpen:r,onClose:()=>s(!1),onSubmit:p=>x.mutate(p),isLoading:x.isPending})]})}function B0({task:e,onClose:t,onDelete:n}){const[r,s]=S.useState("prompt");if(!e)return null;const a=i.jsxs("div",{className:"flex justify-between",children:[i.jsx(V,{variant:"ghost",onClick:()=>n(e.id),className:"text-red-500 hover:text-red-600",children:"Delete Task"}),i.jsx(V,{variant:"secondary",onClick:t,children:"Close"})]});return i.jsx(ns,{isOpen:!!e,onClose:t,title:e.name,size:"lg",footer:a,children:i.jsxs("div",{className:"space-y-4",children:[e.category&&e.category!=="default"&&i.jsx("div",{children:i.jsx(J,{variant:"default",children:e.category})}),i.jsxs("div",{className:"flex gap-1 border-b border-[var(--border)]",children:[i.jsx("button",{onClick:()=>s("prompt"),className:`px-4 py-2 text-sm font-medium border-b-2 -mb-px transition-colors ${r==="prompt"?"border-[var(--accent)] text-[var(--accent)]":"border-transparent text-[var(--text-secondary)] hover:text-[var(--text-primary)]"}`,children:"Prompt"}),i.jsxs("button",{onClick:()=>s("criteria"),className:`px-4 py-2 text-sm font-medium border-b-2 -mb-px transition-colors ${r==="criteria"?"border-[var(--accent)] text-[var(--accent)]":"border-transparent text-[var(--text-secondary)] hover:text-[var(--text-primary)]"}`,children:["Eval Criteria (",e.criteria.length,")"]})]}),r==="prompt"&&i.jsx("div",{className:"p-4 bg-[var(--bg-tertiary)] rounded text-sm whitespace-pre-wrap min-h-[200px]",children:e.prompt}),r==="criteria"&&i.jsx("div",{className:"space-y-2 min-h-[200px]",children:e.criteria.length===0?i.jsx("div",{className:"text-[var(--text-secondary)] text-sm p-4",children:"No evaluation criteria defined for this task."}):e.criteria.map(l=>i.jsxs("div",{className:"p-3 bg-[var(--bg-tertiary)] rounded",children:[i.jsx("div",{className:"font-medium text-sm",children:l.name}),l.instruction&&i.jsx("div",{className:"text-sm text-[var(--text-secondary)] mt-1",children:l.instruction})]},l.name))})]})})}function Q0({isOpen:e,onClose:t,onSubmit:n,isLoading:r}){const[s,a]=S.useState({name:"",prompt:"",criteria:[],category:"default"}),l=()=>{a({...s,criteria:[...s.criteria,{name:"",instruction:"",weight:1}]})},o=(h,d)=>{const m=[...s.criteria];m[h]={...m[h],...d},a({...s,criteria:m})},u=h=>{a({...s,criteria:s.criteria.filter((d,m)=>m!==h)})},c=h=>{h.preventDefault(),!(!s.name.trim()||!s.prompt.trim())&&n({...s,criteria:s.criteria.filter(d=>d.name.trim()&&d.instruction.trim())})};return i.jsx(ns,{isOpen:e,onClose:t,title:"Create Task",children:i.jsxs("form",{onSubmit:c,className:"space-y-4",children:[i.jsx(vn,{label:"Name",value:s.name,onChange:h=>a({...s,name:h.target.value}),placeholder:"e.g., fizzbuzz",required:!0}),i.jsx(S0,{label:"Prompt",value:s.prompt,onChange:h=>a({...s,prompt:h.target.value}),placeholder:"The task description for the agent...",required:!0}),i.jsx(vn,{label:"Category",value:s.category,onChange:h=>a({...s,category:h.target.value}),placeholder:"e.g., coding, research"}),i.jsxs("div",{children:[i.jsxs("div",{className:"flex items-center justify-between mb-2",children:[i.jsx("label",{className:"text-sm text-[var(--text-secondary)]",children:"Evaluation Criteria"}),i.jsx(V,{type:"button",variant:"ghost",size:"sm",onClick:l,children:"+ Add"})]}),i.jsx("div",{className:"space-y-2",children:s.criteria.map((h,d)=>i.jsxs("div",{className:"flex gap-2 items-start",children:[i.jsx(vn,{value:h.name,onChange:m=>o(d,{name:m.target.value}),placeholder:"Name",className:"w-32"}),i.jsx(vn,{value:h.instruction,onChange:m=>o(d,{instruction:m.target.value}),placeholder:"Instruction",className:"flex-1"}),i.jsx(V,{type:"button",variant:"ghost",size:"sm",onClick:()=>u(d),children:"×"})]},d))})]}),i.jsxs("div",{className:"flex justify-end gap-2 pt-4",children:[i.jsx(V,{type:"button",variant:"secondary",onClick:t,children:"Cancel"}),i.jsx(V,{type:"submit",variant:"primary",disabled:r||!s.name.trim()||!s.prompt.trim(),children:r?"Creating...":"Create"})]})]})})}function V0({isOpen:e,onClose:t,onSubmit:n,isLoading:r}){const[s,a]=S.useState(""),{data:l=[],isLoading:o}=ve({queryKey:["suites"],queryFn:()=>Et.listSuites(),enabled:e});return S.useEffect(()=>{l.length>0&&!s&&a(l[0].name)},[l,s]),i.jsx(ns,{isOpen:e,onClose:t,title:"Import Task Suite",children:i.jsxs("div",{className:"space-y-4",children:[i.jsx("p",{className:"text-sm text-[var(--text-secondary)]",children:"Import a built-in task suite for evaluation."}),o?i.jsx("div",{className:"text-[var(--text-secondary)]",children:"Loading suites..."}):l.length===0?i.jsx("div",{className:"text-[var(--text-secondary)]",children:"No suites available."}):i.jsx("div",{className:"space-y-2 max-h-80 overflow-y-auto",children:l.map(u=>i.jsxs("label",{className:`flex items-center gap-3 p-3 border cursor-pointer ${s===u.name?"border-[var(--accent)] bg-[var(--accent)]/10":"border-[var(--border)] hover:border-[var(--accent-dim)]"}`,children:[i.jsx("input",{type:"radio",name:"suite",value:u.name,checked:s===u.name,onChange:()=>a(u.name),className:"accent-[var(--accent)]"}),i.jsxs("span",{className:"capitalize",children:[u.name.replace(/_/g," ")," (",u.task_count," tasks) - ",u.description]})]},u.name))}),i.jsxs("div",{className:"flex justify-end gap-2 pt-4",children:[i.jsx(V,{type:"button",variant:"secondary",onClick:t,children:"Cancel"}),i.jsx(V,{variant:"primary",onClick:()=>n(s),disabled:r||!s,children:r?"Importing...":"Import"})]})]})})}const K0=$u(e=>({jobs:[],setJobs:t=>e({jobs:t})}));function H0(){const e=Lt(),t=Jt(),[n,r]=S.useState(!1),{setJobs:s}=K0(),a=Vu(),{data:l=[],isLoading:o}=ve({queryKey:["jobs",n],queryFn:()=>Ot.list({include_public:n}),refetchInterval:5e3});S.useEffect(()=>{l.length>0&&s(l)},[l,s]);const u=Je({mutationFn:Ot.delete,onSuccess:()=>t.invalidateQueries({queryKey:["jobs"]})});return i.jsxs("div",{children:[i.jsxs("div",{className:"flex items-center justify-between mb-6",children:[i.jsxs("div",{children:[i.jsx("h2",{className:"text-xl font-bold",children:"Experiments"}),i.jsx("p",{className:"text-sm text-[var(--text-secondary)] mt-1",children:"View and manage optimization experiments. Start new experiments from the Agents page."})]}),i.jsxs("div",{className:"flex items-center gap-3",children:[i.jsxs("label",{className:"flex items-center gap-2 text-sm text-[var(--text-secondary)] cursor-pointer",children:[i.jsx("input",{type:"checkbox",checked:n,onChange:c=>r(c.target.checked),className:"rounded border-[var(--border)]"}),i.jsx($i,{className:"w-4 h-4"}),"Show public"]}),i.jsx(V,{variant:"secondary",onClick:()=>e("/agents"),children:"Go to Agents"})]})]}),o?i.jsx("div",{className:"text-[var(--text-secondary)]",children:"Loading..."}):l.length===0?i.jsx("div",{className:"text-center py-12 text-[var(--text-secondary)]",children:"No jobs yet. Go to Agents page to start an optimization."}):i.jsx("div",{className:"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4",children:l.map(c=>{const h=!c.user_id||c.user_id==="anonymous"||a&&c.created_by_name===a;return i.jsx($m,{job:c,onDelete:h?d=>u.mutate(d):void 0},c.id)})})]})}function W0(e,t=!0){return Math.abs(e)<10?"text-[var(--text-secondary)]":(t?e<0:e>0)?"text-green-400":"text-red-400"}function q0(e){return`${e>0?"+":""}${e.toFixed(1)}%`}function Vm(e,t){return t===0?0:(e-t)/t*100}function hs({label:e,values:t,baselineIndex:n,formatter:r,isLowerBetter:s=!0}){const a=t[n];return i.jsxs("tr",{className:"border-b border-[var(--border)] last:border-0",children:[i.jsx("td",{className:"py-2 pr-4 text-[var(--text-secondary)] text-sm",children:e}),t.map((l,o)=>{const u=Vm(l,a),c=o===n;return i.jsxs("td",{className:"py-2 px-4 text-right",children:[i.jsx("div",{className:"font-mono",children:r(l)}),!c&&i.jsx("div",{className:`text-xs ${W0(u,s)}`,children:q0(u)}),c&&i.jsx("div",{className:"text-xs text-[var(--text-secondary)]",children:"(baseline)"})]},o)})]})}function J0({runs:e,baselineRunId:t}){const n=S.useMemo(()=>{if(t){const a=e.findIndex(l=>l.id===t);if(a>=0)return a}return 0},[e,t]);if(e.length<2)return null;const r=Math.min(...e.map(a=>a.tokens_total)),s=Math.max(...e.map(a=>a.score));return i.jsxs(se,{className:"mb-6",children:[i.jsx("h3",{className:"font-medium mb-4",children:"Candidate Comparison"}),i.jsx("div",{className:"overflow-x-auto",children:i.jsxs("table",{className:"w-full text-sm",children:[i.jsx("thead",{children:i.jsxs("tr",{className:"border-b border-[var(--border)]",children:[i.jsx("th",{className:"pb-2 pr-4 text-left text-[var(--text-secondary)] font-medium",children:"Metric"}),e.map((a,l)=>i.jsx("th",{className:"pb-2 px-4 text-right",children:i.jsxs("div",{className:"flex items-center justify-end gap-2",children:[i.jsx("span",{className:"font-medium",children:a.candidate_name}),a.is_pareto&&i.jsx(J,{variant:"success",children:"Optimal"}),l===n&&i.jsx(J,{variant:"info",children:"Base"})]})},a.id))]})}),i.jsxs("tbody",{children:[i.jsx(hs,{label:"Total Tokens",values:e.map(a=>a.tokens_total),baselineIndex:n,formatter:a=>a.toLocaleString(),isLowerBetter:!0}),i.jsx(hs,{label:"Input Tokens",values:e.map(a=>a.tokens_input),baselineIndex:n,formatter:a=>a.toLocaleString(),isLowerBetter:!0}),i.jsx(hs,{label:"Output Tokens",values:e.map(a=>a.tokens_output),baselineIndex:n,formatter:a=>a.toLocaleString(),isLowerBetter:!0}),i.jsx(hs,{label:"Duration",values:e.map(a=>a.duration_seconds),baselineIndex:n,formatter:a=>`${a.toFixed(1)}s`,isLowerBetter:!0}),i.jsx(hs,{label:"Score",values:e.map(a=>a.score*100),baselineIndex:n,formatter:a=>`${a.toFixed(1)}%`,isLowerBetter:!1})]})]})}),i.jsxs("div",{className:"mt-4 pt-4 border-t border-[var(--border)]",children:[i.jsx("h4",{className:"text-sm font-medium mb-2 text-[var(--text-secondary)]",children:"Key Insights"}),i.jsxs("ul",{className:"text-sm space-y-1 text-[var(--text-secondary)]",children:[e.map(a=>{const l=Vm(a.tokens_total,e[n].tokens_total);return a.tokens_total===r&&l<-5?i.jsxs("li",{className:"flex items-center gap-2",children:[i.jsx("span",{className:"text-green-400",children:"✓"}),i.jsxs("span",{children:[i.jsx("strong",{children:a.candidate_name})," uses ",Math.abs(l).toFixed(0),"% fewer tokens"]})]},`token-${a.id}`):null}),e.map(a=>a.score===s&&a.passed?i.jsxs("li",{className:"flex items-center gap-2",children:[i.jsx("span",{className:"text-green-400",children:"✓"}),i.jsxs("span",{children:[i.jsx("strong",{children:a.candidate_name})," achieved highest score (",(a.score*100).toFixed(0),"%)"]})]},`score-${a.id}`):null),e.filter(a=>a.is_pareto).length>0&&i.jsxs("li",{className:"flex items-center gap-2",children:[i.jsx("span",{className:"text-purple-400",children:"★"}),i.jsxs("span",{children:["Optimal candidates (best tradeoff):"," ",e.filter(a=>a.is_pareto).map(a=>a.candidate_name).join(", ")]})]})]})]}),i.jsxs("div",{className:"mt-4 pt-4 border-t border-[var(--border)]",children:[i.jsx("h4",{className:"text-sm font-medium mb-3 text-[var(--text-secondary)]",children:"Token Efficiency"}),i.jsx("div",{className:"space-y-2",children:e.map(a=>{const l=a.tokens_total/e[n].tokens_total*100,o=a.tokens_total<=r;return i.jsxs("div",{className:"flex items-center gap-3",children:[i.jsx("div",{className:"w-24 text-sm truncate",title:a.candidate_name,children:a.candidate_name}),i.jsx("div",{className:"flex-1 h-6 bg-[var(--bg-primary)] rounded overflow-hidden",children:i.jsx("div",{className:`h-full transition-all duration-300 ${o?"bg-green-500":"bg-blue-500"}`,style:{width:`${Math.min(l,100)}%`}})}),i.jsx("div",{className:"w-20 text-right font-mono text-sm",children:a.tokens_total.toLocaleString()})]},a.id)})})]})]})}function G0({summaries:e,height:t=350}){const n=S.useRef(null),[r,s]=S.useState(600),[a,l]=S.useState("tokens"),[o,u]=S.useState(null),[c,h]=S.useState({x:0,y:0});S.useEffect(()=>{const b=()=>{n.current&&s(n.current.clientWidth)};return b(),window.addEventListener("resize",b),()=>window.removeEventListener("resize",b)},[]);const d={top:30,right:30,bottom:50,left:60},m=r-d.left-d.right,x=t-d.top-d.bottom,k=b=>a==="tokens"?b.avg_tokens:b.avg_duration,{xScale:g,yScale:j,xTicks:p,yTicks:f,paretoLine:v}=S.useMemo(()=>{if(e.length===0||m<=0)return{xScale:()=>0,yScale:()=>0,xTicks:[],yTicks:[],paretoLine:[]};const b=e.map(k),N=e.map(T=>T.avg_score),_=Math.min(...b)*.9,F=Math.max(...b)*1.1,P=Math.min(...N,.5),B=Math.min(Math.max(...N)*1.05,1),D=T=>(T-_)/(F-_)*m,U=T=>x-(T-P)/(B-P)*x,ne=Array.from({length:5},(T,A)=>_+A/4*(F-_)),je=Array.from({length:5},(T,A)=>P+A/4*(B-P)),ie=e.filter(T=>T.is_pareto).sort((T,A)=>k(T)-k(A)).map(T=>({x:D(k(T)),y:U(T.avg_score)}));return{xScale:D,yScale:U,xTicks:ne,yTicks:je,paretoLine:ie}},[e,m,x,a]);if(e.length===0)return i.jsx("div",{className:"text-center py-8 text-[var(--text-secondary)]",children:"No data to display"});const w=b=>a==="tokens"?b>=1e6?`${(b/1e6).toFixed(1)}M`:b>=1e3?`${(b/1e3).toFixed(0)}K`:b.toFixed(0):`${b.toFixed(1)}s`,C=(b,N)=>{var F;const _=(F=n.current)==null?void 0:F.getBoundingClientRect();_&&h({x:N.clientX-_.left,y:N.clientY-_.top}),u(b)};return i.jsxs("div",{ref:n,className:"w-full relative",children:[i.jsx("div",{className:"flex justify-end mb-2",children:i.jsxs("div",{className:"inline-flex rounded border border-[var(--border)] text-xs",children:[i.jsx("button",{className:`px-3 py-1 ${a==="tokens"?"bg-[var(--accent)] text-black":"text-[var(--text-secondary)] hover:text-[var(--text-primary)]"}`,onClick:()=>l("tokens"),children:"Tokens"}),i.jsx("button",{className:`px-3 py-1 ${a==="duration"?"bg-[var(--accent)] text-black":"text-[var(--text-secondary)] hover:text-[var(--text-primary)]"}`,onClick:()=>l("duration"),children:"Latency"})]})}),i.jsx("svg",{width:r,height:t,className:"font-mono text-xs",children:i.jsxs("g",{transform:`translate(${d.left}, ${d.top})`,children:[p.map((b,N)=>i.jsx("line",{x1:g(b),y1:0,x2:g(b),y2:x,stroke:"var(--border)",strokeDasharray:"2,2"},`x-grid-${N}`)),f.map((b,N)=>i.jsx("line",{x1:0,y1:j(b),x2:m,y2:j(b),stroke:"var(--border)",strokeDasharray:"2,2"},`y-grid-${N}`)),v.length>1&&i.jsx("polyline",{points:v.map(b=>`${b.x},${b.y}`).join(" "),fill:"none",stroke:"var(--accent)",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"}),e.slice().sort((b,N)=>(b.is_pareto?1:0)-(N.is_pareto?1:0)).map(b=>{const N=g(k(b)),_=j(b.avg_score),F=b.is_pareto,P=(o==null?void 0:o.candidate_name)===b.candidate_name;return i.jsxs("g",{onMouseEnter:B=>C(b,B),onMouseLeave:()=>u(null),children:[i.jsx("circle",{cx:N,cy:_,r:P?10:F?8:6,fill:F?"var(--accent)":"transparent",stroke:P?"var(--text-primary)":F?"var(--accent)":"var(--text-secondary)",strokeWidth:P?3:2,className:"cursor-pointer transition-all"}),F&&!P&&i.jsx("text",{x:N,y:_-12,textAnchor:"middle",fill:"var(--text-primary)",fontSize:10,className:"pointer-events-none",children:b.candidate_name.replace(/^baseline_/,"").slice(0,15)})]},b.candidate_name)}),i.jsx("line",{x1:0,y1:x,x2:m,y2:x,stroke:"var(--text-secondary)"}),p.map((b,N)=>i.jsxs("g",{transform:`translate(${g(b)}, ${x})`,children:[i.jsx("line",{y2:5,stroke:"var(--text-secondary)"}),i.jsx("text",{y:20,textAnchor:"middle",fill:"var(--text-secondary)",fontSize:10,children:w(b)})]},`x-tick-${N}`)),i.jsx("text",{x:m/2,y:x+40,textAnchor:"middle",fill:"var(--text-secondary)",fontSize:11,children:a==="tokens"?"Tokens (cost)":"Duration (latency)"}),i.jsx("line",{x1:0,y1:0,x2:0,y2:x,stroke:"var(--text-secondary)"}),f.map((b,N)=>i.jsxs("g",{transform:`translate(0, ${j(b)})`,children:[i.jsx("line",{x2:-5,stroke:"var(--text-secondary)"}),i.jsxs("text",{x:-10,textAnchor:"end",dominantBaseline:"middle",fill:"var(--text-secondary)",fontSize:10,children:[(b*100).toFixed(0),"%"]})]},`y-tick-${N}`)),i.jsx("text",{transform:`translate(-45, ${x/2}) rotate(-90)`,textAnchor:"middle",fill:"var(--text-secondary)",fontSize:11,children:"Score (quality)"})]})}),o&&i.jsxs("div",{className:"absolute z-10 bg-[var(--bg-secondary)] border border-[var(--border)] rounded-lg shadow-lg p-3 text-sm pointer-events-none",style:{left:Math.min(c.x+15,r-200),top:c.y-10,maxWidth:220},children:[i.jsx("div",{className:"font-medium text-[var(--text-primary)] truncate mb-2",children:o.candidate_name.replace(/^baseline_/,"")}),i.jsxs("div",{className:"grid grid-cols-2 gap-x-4 gap-y-1 text-xs",children:[i.jsx("span",{className:"text-[var(--text-secondary)]",children:"Score:"}),i.jsxs("span",{className:"text-right font-medium",children:[(o.avg_score*100).toFixed(1),"%"]}),i.jsx("span",{className:"text-[var(--text-secondary)]",children:"Tokens:"}),i.jsxs("span",{className:"text-right",children:[(o.avg_tokens/1e3).toFixed(1),"K"]}),i.jsx("span",{className:"text-[var(--text-secondary)]",children:"Duration:"}),i.jsxs("span",{className:"text-right",children:[o.avg_duration.toFixed(1),"s"]}),i.jsx("span",{className:"text-[var(--text-secondary)]",children:"Pass rate:"}),i.jsxs("span",{className:"text-right",children:[o.passed_runs,"/",o.total_runs]})]}),o.is_pareto&&i.jsx("div",{className:"mt-2 pt-2 border-t border-[var(--border)] text-xs text-[var(--accent)]",children:"Optimal (best tradeoff)"})]})]})}function Y0(e=2e3){const[t,n]=S.useState(!1),[r,s]=S.useState(null),a=S.useCallback(async o=>{try{return await navigator.clipboard.writeText(o),n(!0),s(null),setTimeout(()=>n(!1),e),!0}catch{return s("Failed to copy to clipboard"),n(!1),!1}},[e]),l=S.useCallback(()=>{n(!1),s(null)},[]);return{copy:a,copied:t,error:r,reset:l}}function X0({isOpen:e,onClose:t,title:n,itemId:r,itemType:s,isPublic:a,createdByName:l,onTogglePublic:o}){const[u,c]=S.useState(!1),{copy:h,copied:d}=Y0(),m=`${window.location.origin}/${s}s/${r}`,x=async()=>{c(!0);try{await o(!a)}finally{c(!1)}},k=()=>{h(m)};return i.jsx(ns,{isOpen:e,onClose:t,title:n,children:i.jsxs("div",{className:"space-y-4",children:[i.jsxs("div",{className:"flex items-center justify-between p-3 bg-[var(--bg-tertiary)] rounded",children:[i.jsxs("div",{className:"flex items-center gap-3",children:[a?i.jsx($i,{className:"w-5 h-5 text-[var(--accent)]"}):i.jsx(Pm,{className:"w-5 h-5 text-[var(--text-secondary)]"}),i.jsxs("div",{children:[i.jsx("div",{className:"font-medium",children:a?"Public":"Private"}),i.jsx("div",{className:"text-sm text-[var(--text-secondary)]",children:a?"Anyone with the link can view":"Only you can access"})]})]}),i.jsx("button",{onClick:x,disabled:u,className:`relative inline-flex h-6 w-11 items-center rounded-full transition-colors ${a?"bg-[var(--accent)]":"bg-[var(--border)]"} ${u?"opacity-50 cursor-not-allowed":""}`,children:i.jsx("span",{className:`inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${a?"translate-x-6":"translate-x-1"}`})})]}),a&&i.jsxs("div",{className:"space-y-2",children:[i.jsx("label",{className:"text-sm text-[var(--text-secondary)]",children:"Share link"}),i.jsxs("div",{className:"flex gap-2",children:[i.jsx("input",{type:"text",readOnly:!0,value:m,className:"flex-1 px-3 py-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm font-mono"}),i.jsx(V,{variant:"secondary",onClick:k,children:d?i.jsxs(i.Fragment,{children:[i.jsx(mg,{className:"w-4 h-4 mr-1"}),"Copied"]}):i.jsxs(i.Fragment,{children:[i.jsx(yg,{className:"w-4 h-4 mr-1"}),"Copy"]})})]})]}),l&&i.jsxs("div",{className:"text-sm text-[var(--text-secondary)]",children:["Created by ",i.jsx("span",{className:"text-[var(--text-primary)]",children:l})]}),i.jsx("div",{className:"text-xs text-[var(--text-secondary)] pt-2 border-t border-[var(--border)]",children:a?i.jsxs(i.Fragment,{children:[i.jsxs("p",{children:["Public ",s,"s can be viewed by anyone with the link."]}),i.jsxs("p",{className:"mt-1",children:["Only you can edit or delete this ",s,"."]})]}):i.jsxs("p",{children:["Make this ",s," public to share it with others."]})})]})})}function Z0({job:e,onUpdate:t}){const[n,r]=S.useState(!1),s=async a=>{await Ot.update(e.id,{is_public:a}),t()};return i.jsxs(i.Fragment,{children:[i.jsxs(V,{variant:"secondary",size:"sm",onClick:()=>r(!0),title:e.is_public?"Sharing settings":"Share this job",children:[i.jsx(Eg,{className:"w-4 h-4 mr-1"}),e.is_public?"Shared":"Share"]}),i.jsx(X0,{isOpen:n,onClose:()=>r(!1),title:"Share Job",itemId:e.id,itemType:"job",isPublic:e.is_public,createdByName:e.created_by_name,onTogglePublic:s})]})}function e1(){const{jobId:e}=Di(),t=Lt(),n=Jt(),[r,s]=S.useState(null),[a,l]=S.useState(!1),[o,u]=S.useState(null),[c,h]=S.useState([]),[d,m]=S.useState(null),[x,k]=S.useState(null),[g,j]=S.useState("results"),[p,f]=S.useState("score"),[v,w]=S.useState("desc"),[C,b]=S.useState(!1),{data:N,isLoading:_}=ve({queryKey:["jobs",e],queryFn:()=>Ot.get(e),enabled:!!e,refetchInterval:a?2e3:!1}),{data:F=[]}=ve({queryKey:["runs",e],queryFn:()=>Mo.list({job_id:e}),enabled:!!e,refetchInterval:a?2e3:!1}),{data:P}=ve({queryKey:["job-summary",e],queryFn:()=>Mo.getJobSummary(e),enabled:!!e&&(N==null?void 0:N.status)==="completed"}),B=Je({mutationFn:async()=>{l(!0),h([]),m(null),k(null);for await(const R of Ot.start(e))s(R),R.current_candidate&&R.current_task&&m(O=>(O&&(O.candidate!==R.current_candidate||O.task!==R.current_task)&&h(Z=>[...Z,{candidate_name:O.candidate,task_name:O.task,completed_at:Date.now()}]),{candidate:R.current_candidate,task:R.current_task})),R.event==="error"&&(k(R.message),l(!1),n.invalidateQueries({queryKey:["jobs",e]})),R.event==="complete"&&(m(O=>(O&&h(Z=>[...Z,{candidate_name:O.candidate,task_name:O.task,completed_at:Date.now()}]),null)),l(!1),n.invalidateQueries({queryKey:["jobs",e]}),n.invalidateQueries({queryKey:["runs",e]}),n.invalidateQueries({queryKey:["job-summary",e]}))}}),D=Je({mutationFn:()=>Ot.cancel(e),onSuccess:()=>{l(!1),n.invalidateQueries({queryKey:["jobs",e]})}});S.useEffect(()=>{(N==null?void 0:N.status)==="running"&&l(!0)},[N==null?void 0:N.status]);const U=S.useMemo(()=>{const R=new Map;for(const O of F)R.has(O.task_name)||R.set(O.task_name,[]),R.get(O.task_name).push(O);return R},[F]),ne=S.useMemo(()=>Array.from(U.keys()),[U]),je=S.useMemo(()=>{if(!(P!=null&&P.candidate_summaries))return[];let R=[...P.candidate_summaries];return C&&(R=R.filter(O=>O.is_pareto)),R.sort((O,Z)=>{let he,Ne;switch(p){case"score":he=O.avg_score,Ne=Z.avg_score;break;case"tokens":he=O.avg_tokens,Ne=Z.avg_tokens;break;case"duration":he=O.avg_duration,Ne=Z.avg_duration;break;case"pass_rate":he=O.passed_runs/O.total_runs,Ne=Z.passed_runs/Z.total_runs;break}return v==="desc"?Ne-he:he-Ne}),R},[P,p,v,C]),Ge=R=>{p===R?w(v==="desc"?"asc":"desc"):(f(R),w(R==="tokens"||R==="duration"?"asc":"desc"))},ie=({label:R,sortKeyVal:O})=>i.jsx("th",{className:"pb-2 cursor-pointer hover:text-[var(--text-primary)] select-none",onClick:()=>Ge(O),children:i.jsxs("div",{className:"flex items-center gap-1",children:[R,p===O&&i.jsx(dg,{size:12,className:v==="asc"?"rotate-180":""})]})});if(_)return i.jsx("div",{className:"text-[var(--text-secondary)]",children:"Loading..."});if(!N)return i.jsx("div",{className:"text-[var(--text-secondary)]",children:"Job not found"});const T=Vu(),A=!N.user_id||N.user_id==="anonymous"||T&&N.created_by_name===T,L=N.is_public&&!A,K=()=>{n.invalidateQueries({queryKey:["jobs",e]})},X=R=>{const O={pending:"default",running:"info",completed:"success",failed:"error",cancelled:"warning"};return i.jsx(J,{variant:O[R]||"default",children:R})};return i.jsxs("div",{children:[i.jsxs("div",{className:"flex items-center justify-between mb-6",children:[i.jsxs("div",{children:[i.jsxs("div",{className:"flex items-center gap-3",children:[i.jsx("button",{onClick:()=>t("/jobs"),className:"text-[var(--text-secondary)] hover:text-[var(--text-primary)]",children:"← Jobs"}),i.jsx("h2",{className:"text-xl font-bold",children:N.name||`Job ${N.id.slice(0,8)}`}),X(N.status),N.is_public&&i.jsxs(J,{variant:"info",children:[i.jsx($i,{className:"w-3 h-3 mr-1 inline"}),"Public"]})]}),i.jsxs("div",{className:"flex items-center gap-3 mt-1",children:[i.jsxs("code",{className:"text-xs bg-[var(--bg-primary)] px-2 py-0.5 rounded font-mono text-[var(--text-secondary)]",children:[N.id.slice(0,8),"..."]}),i.jsxs("span",{className:"text-sm text-[var(--text-secondary)]",children:[N.candidate_ids.length," candidates × ",N.task_ids.length," tasks = ",N.total_experiments," experiments"]}),N.is_public&&N.created_by_name&&i.jsxs("span",{className:"text-sm text-[var(--text-secondary)]",children:["Created by ",i.jsx("span",{className:"text-[var(--text-primary)]",children:N.created_by_name})]})]})]}),i.jsxs("div",{className:"flex gap-2",children:[A&&i.jsx(Z0,{job:N,onUpdate:K}),L&&i.jsx(J,{variant:"default",children:"View Only"}),A&&N.status==="pending"&&i.jsx(V,{variant:"primary",onClick:()=>B.mutate(),disabled:B.isPending,children:B.isPending?"Starting...":"Start"}),A&&N.status==="running"&&i.jsx(V,{variant:"danger",onClick:()=>D.mutate(),disabled:D.isPending,children:"Cancel"})]})]}),(x||N.error)&&i.jsx(se,{className:"mb-6 border-red-500/50 bg-red-500/10",children:i.jsxs("div",{className:"flex items-start gap-3",children:[i.jsx("div",{className:"w-5 h-5 rounded-full bg-red-500 flex items-center justify-center text-white text-xs font-bold flex-shrink-0 mt-0.5",children:"!"}),i.jsxs("div",{children:[i.jsx("h3",{className:"font-medium text-red-400",children:"Error"}),i.jsx("p",{className:"text-sm text-[var(--text-secondary)] mt-1",children:x||N.error})]})]})}),(a||r)&&i.jsxs(se,{className:"mb-6",children:[i.jsxs("div",{className:"flex items-center justify-between mb-2",children:[i.jsx("span",{className:"font-medium",children:"Progress"}),i.jsxs("span",{className:"text-[var(--accent)]",children:[(r==null?void 0:r.completed)||N.completed_experiments,"/",(r==null?void 0:r.total)||N.total_experiments]})]}),i.jsx("div",{className:"w-full bg-[var(--bg-primary)] h-2 mb-2",children:i.jsx("div",{className:"h-full bg-[var(--accent)] transition-all",style:{width:`${((r==null?void 0:r.completed)||N.completed_experiments)/((r==null?void 0:r.total)||N.total_experiments)*100}%`}})}),(r==null?void 0:r.message)&&i.jsx("p",{className:"text-sm text-[var(--text-secondary)]",children:r.message}),a&&i.jsxs("div",{className:"mt-4 border-t border-[var(--border)] pt-4",children:[(r==null?void 0:r.current_candidate)&&(r==null?void 0:r.current_task)&&i.jsxs("div",{className:"mb-3",children:[i.jsx("span",{className:"text-xs text-[var(--text-secondary)] uppercase tracking-wider",children:"Currently Running"}),i.jsxs("div",{className:"flex items-center gap-2 mt-1 px-3 py-2 bg-blue-500/10 border border-blue-500/30 rounded",children:[i.jsx("div",{className:"w-2 h-2 bg-blue-400 rounded-full animate-pulse"}),i.jsx("span",{className:"font-medium",children:r.current_candidate}),i.jsx("span",{className:"text-[var(--text-secondary)]",children:"→"}),i.jsx("span",{children:r.current_task})]})]}),c.length>0&&i.jsxs("div",{children:[i.jsxs("span",{className:"text-xs text-[var(--text-secondary)] uppercase tracking-wider",children:["Completed (",c.length,")"]}),i.jsx("div",{className:"mt-1 max-h-40 overflow-y-auto space-y-1",children:c.map((R,O)=>i.jsxs("div",{className:"flex items-center gap-2 px-3 py-1.5 bg-green-500/10 border border-green-500/30 rounded text-sm",children:[i.jsx("div",{className:"w-2 h-2 bg-green-400 rounded-full"}),i.jsx("span",{className:"font-medium",children:R.candidate_name}),i.jsx("span",{className:"text-[var(--text-secondary)]",children:"→"}),i.jsx("span",{children:R.task_name})]},`${R.candidate_name}-${R.task_name}-${O}`))})]})]})]}),(N.status==="completed"||F.length>0)&&i.jsxs("div",{className:"flex gap-1 mb-6 border-b border-[var(--border)]",children:[i.jsxs("button",{onClick:()=>j("results"),className:`flex items-center gap-2 px-4 py-2 text-sm font-medium border-b-2 transition-colors ${g==="results"?"border-[var(--accent)] text-[var(--accent)]":"border-transparent text-[var(--text-secondary)] hover:text-[var(--text-primary)]"}`,children:[i.jsx(fg,{size:16}),"Results"]}),i.jsxs("button",{onClick:()=>j("compare"),className:`flex items-center gap-2 px-4 py-2 text-sm font-medium border-b-2 transition-colors ${g==="compare"?"border-[var(--accent)] text-[var(--accent)]":"border-transparent text-[var(--text-secondary)] hover:text-[var(--text-primary)]"}`,children:[i.jsx(kg,{size:16}),"Compare"]}),i.jsxs("button",{onClick:()=>j("runs"),className:`flex items-center gap-2 px-4 py-2 text-sm font-medium border-b-2 transition-colors ${g==="runs"?"border-[var(--accent)] text-[var(--accent)]":"border-transparent text-[var(--text-secondary)] hover:text-[var(--text-primary)]"}`,children:[i.jsx(bg,{size:16}),"Runs (",F.length,")"]})]}),g==="results"&&i.jsxs(i.Fragment,{children:[P&&P.candidate_summaries.length>1&&i.jsxs(se,{className:"mb-6",children:[i.jsx("div",{className:"flex items-start justify-between mb-4",children:i.jsxs("div",{children:[i.jsx("h3",{className:"font-medium",children:"Quality vs. Cost Tradeoff"}),i.jsxs("p",{className:"text-sm text-[var(--text-secondary)] mt-1",children:["Candidates on the frontier (connected line) are ",i.jsx("strong",{children:"optimal"})," - no other candidate beats them on both score AND cost."]})]})}),i.jsxs("div",{className:"mb-4 p-3 bg-[var(--bg-primary)] rounded border border-[var(--border)] text-xs text-[var(--text-secondary)]",children:[i.jsx("strong",{className:"text-[var(--text-primary)]",children:"How optimal tradeoffs are calculated:"})," A candidate is optimal if there's no other candidate that has both a higher score AND lower cost. For example, if Candidate A has 95% score at 50K tokens and Candidate B has 90% score at 40K tokens, both are optimal - A is better on score, B is better on cost. But if Candidate C has 85% score at 60K tokens, it's ",i.jsx("em",{children:"not"})," optimal because B beats it on both metrics."]}),i.jsx(G0,{summaries:P.candidate_summaries,height:350})]}),P&&i.jsxs(se,{className:"mb-6",children:[i.jsxs("div",{className:"flex items-center justify-between mb-4",children:[i.jsx("h3",{className:"font-medium",children:"Results Summary"}),i.jsxs("label",{className:"flex items-center gap-2 text-sm text-[var(--text-secondary)] cursor-pointer",children:[i.jsx("input",{type:"checkbox",checked:C,onChange:R=>b(R.target.checked),className:"rounded border-[var(--border)]"}),"Optimal only"]})]}),i.jsx("div",{className:"overflow-x-auto",children:i.jsxs("table",{className:"w-full text-sm",children:[i.jsx("thead",{children:i.jsxs("tr",{className:"text-left text-[var(--text-secondary)] border-b border-[var(--border)]",children:[i.jsx("th",{className:"pb-2",children:"Candidate"}),i.jsx(ie,{label:"Score",sortKeyVal:"score"}),i.jsx(ie,{label:"Tokens",sortKeyVal:"tokens"}),i.jsx(ie,{label:"Duration",sortKeyVal:"duration"}),i.jsx(ie,{label:"Pass Rate",sortKeyVal:"pass_rate"}),i.jsx("th",{className:"pb-2",children:"Optimal"})]})}),i.jsx("tbody",{children:je.map((R,O)=>i.jsxs("tr",{className:`border-b border-[var(--border)] ${O===0?"bg-[var(--accent)]/10":""}`,children:[i.jsxs("td",{className:"py-2 font-medium",children:[O===0&&i.jsx("span",{className:"text-[var(--accent)] mr-1",children:"#1"}),R.candidate_name.replace(/^baseline_/,"")]}),i.jsxs("td",{className:"py-2",children:[(R.avg_score*100).toFixed(1),"%"]}),i.jsxs("td",{className:"py-2",children:[(R.avg_tokens/1e3).toFixed(1),"K"]}),i.jsxs("td",{className:"py-2",children:[R.avg_duration.toFixed(1),"s"]}),i.jsxs("td",{className:"py-2",children:[R.passed_runs,"/",R.total_runs]}),i.jsx("td",{className:"py-2",children:R.is_pareto&&i.jsx(J,{variant:"success",children:"Optimal"})})]},R.candidate_name))})]})}),i.jsx("p",{className:"text-xs text-[var(--text-secondary)] mt-3",children:"Click column headers to sort. The #1 ranked candidate is highlighted based on your sort criteria."})]}),!P&&i.jsx(se,{children:i.jsx("div",{className:"text-center py-8 text-[var(--text-secondary)]",children:a?"Results will appear here after the job completes.":"No results yet. Start the job to see results."})})]}),g==="compare"&&i.jsxs(se,{children:[i.jsx("h3",{className:"font-medium mb-4",children:"Compare Candidates by Task"}),ne.length>0?i.jsxs(i.Fragment,{children:[i.jsx("div",{className:"flex flex-wrap gap-2 mb-4",children:ne.map(R=>i.jsx("button",{onClick:()=>u(o===R?null:R),className:`px-3 py-1 text-sm rounded border transition-colors ${o===R?"bg-[var(--accent)] text-white border-[var(--accent)]":"border-[var(--border)] hover:border-[var(--accent-dim)]"}`,children:R},R))}),o&&U.get(o)?i.jsx(J0,{runs:U.get(o).map(R=>({id:R.id,candidate_name:R.candidate_name,tokens_input:0,tokens_output:0,tokens_total:R.tokens_total,duration_seconds:R.duration_seconds,score:R.score,passed:R.passed,is_pareto:R.is_pareto}))}):i.jsx("div",{className:"text-center py-8 text-[var(--text-secondary)]",children:"Select a task above to compare how different candidates performed on it."})]}):i.jsx("div",{className:"text-center py-8 text-[var(--text-secondary)]",children:a?"Comparison data will appear here after runs complete.":"No runs yet. Start the job to compare candidates."})]}),g==="runs"&&i.jsxs(se,{children:[i.jsx("h3",{className:"font-medium mb-4",children:"All Experiment Runs"}),F.length===0?i.jsx("div",{className:"text-center py-8 text-[var(--text-secondary)]",children:a?"Runs will appear here as they complete. See progress above for live status.":"No runs yet. Start the job to see results."}):i.jsx("div",{className:"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-3",children:F.map(R=>i.jsxs("div",{className:"p-3 bg-[var(--bg-primary)] rounded border border-[var(--border)] cursor-pointer hover:border-[var(--accent-dim)] transition-colors",onClick:()=>t(`/runs/${R.id}`),children:[i.jsxs("div",{className:"flex items-center justify-between mb-2",children:[i.jsxs("span",{className:`text-lg font-bold ${R.passed?"text-green-400":"text-red-400"}`,children:[(R.score*100).toFixed(0),"%"]}),R.is_pareto&&i.jsx(J,{variant:"success",children:"Optimal"})]}),i.jsx("div",{className:"text-sm font-medium truncate",title:R.candidate_name,children:R.candidate_name.replace(/^baseline_/,"")}),i.jsx("div",{className:"text-xs text-[var(--text-secondary)] truncate",children:R.task_name}),i.jsxs("div",{className:"flex items-center gap-3 mt-2 text-xs text-[var(--text-secondary)]",children:[i.jsxs("span",{children:[(R.tokens_total/1e3).toFixed(1),"K tokens"]}),i.jsxs("span",{children:[R.duration_seconds.toFixed(1),"s"]})]})]},R.id))})]})]})}const xn={input:"bg-blue-500",output:"bg-emerald-500",inputText:"text-blue-400",outputText:"text-emerald-400"};function Td(e){return e>=1e3?`${(e/1e3).toFixed(1)}k`:String(e)}function Od({input:e,output:t,maxValue:n,height:r=24,showLabels:s=!0}){const a=e+t;if(a===0)return i.jsx("div",{className:"flex items-center gap-2 w-full",children:i.jsx("div",{className:"rounded bg-[var(--bg-primary)] flex-1",style:{height:`${r}px`}})});const l=n>0?a/n*100:100;return i.jsxs("div",{className:"flex items-center gap-3 w-full",children:[i.jsx("div",{className:"relative rounded overflow-hidden bg-[var(--bg-primary)] flex-1",style:{height:`${r}px`},children:i.jsxs("div",{className:"h-full flex transition-all duration-300",style:{width:`${l}%`},children:[i.jsx("div",{className:`h-full ${xn.input} transition-all`,style:{width:`${e/a*100}%`},title:`Input: ${e.toLocaleString()} tokens`}),i.jsx("div",{className:`h-full ${xn.output} transition-all`,style:{width:`${t/a*100}%`},title:`Output: ${t.toLocaleString()} tokens`})]})}),s&&i.jsxs("div",{className:"flex items-center gap-1 text-xs font-mono text-[var(--text-secondary)] min-w-[90px] justify-end",children:[i.jsxs("span",{className:xn.inputText,children:["↑",Td(e)]}),i.jsx("span",{children:"/"}),i.jsxs("span",{className:xn.outputText,children:["↓",Td(t)]})]})]})}function wl({label:e,value:t,color:n="default"}){const r={default:"text-[var(--text-primary)]",input:xn.inputText,output:xn.outputText}[n];return i.jsxs("div",{className:"flex-1 p-3 bg-[var(--bg-primary)] border border-[var(--border)] rounded",children:[i.jsx("div",{className:"text-xs text-[var(--text-secondary)] mb-1",children:e}),i.jsx("div",{className:`font-mono text-lg font-bold ${r}`,children:t})]})}function Km({tokensInput:e,tokensOutput:t,tokensTotal:n,turns:r}){const s=n>0?Math.round(e/n*100):0,a=n>0?Math.round(t/n*100):0,l=S.useMemo(()=>{if(!r||r.length===0)return null;let u=0,c=0;return r.map(h=>(u+=h.input,c+=h.output,{input:u,output:c,total:u+c}))},[r]),o=l?Math.max(...l.map(u=>u.total)):n;return i.jsxs(se,{className:"mb-6",children:[i.jsx("h3",{className:"font-medium mb-4",children:"Token Usage"}),i.jsx("div",{className:"mb-4",children:i.jsx(Od,{input:e,output:t,maxValue:n,height:32})}),i.jsxs("div",{className:"flex items-center gap-6 text-xs mb-4",children:[i.jsxs("div",{className:"flex items-center gap-2",children:[i.jsx("div",{className:`w-3 h-3 rounded ${xn.input}`}),i.jsxs("span",{className:"text-[var(--text-secondary)]",children:["Input (",s,"%)"]})]}),i.jsxs("div",{className:"flex items-center gap-2",children:[i.jsx("div",{className:`w-3 h-3 rounded ${xn.output}`}),i.jsxs("span",{className:"text-[var(--text-secondary)]",children:["Output (",a,"%)"]})]})]}),i.jsxs("div",{className:"flex gap-3 mb-4",children:[i.jsx(wl,{label:"Input Tokens",value:e.toLocaleString(),color:"input"}),i.jsx(wl,{label:"Output Tokens",value:t.toLocaleString(),color:"output"}),i.jsx(wl,{label:"Total Tokens",value:n.toLocaleString()})]}),l&&l.length>1&&i.jsxs("div",{className:"border-t border-[var(--border)] pt-4",children:[i.jsxs("h4",{className:"text-sm font-medium mb-3 text-[var(--text-secondary)]",children:["Token Accumulation (",r.length," turns)"]}),i.jsx("div",{className:"space-y-2",children:r.map((u,c)=>i.jsxs("div",{className:"flex items-center gap-3",children:[i.jsx("div",{className:"w-6 h-6 rounded-full bg-[var(--bg-primary)] border border-[var(--border)] flex items-center justify-center text-xs font-medium",children:c+1}),i.jsx("div",{className:"flex-1",children:i.jsx(Od,{input:l[c].input,output:l[c].output,maxValue:o,height:16})})]},c))})]}),i.jsx("div",{className:"mt-4 text-xs text-[var(--text-secondary)] border-t border-[var(--border)] pt-3",children:"Token usage affects API cost. Input tokens are typically cheaper than output tokens."})]})}function t1(){const{runId:e}=Di(),t=Lt(),{data:n,isLoading:r}=ve({queryKey:["runs",e],queryFn:()=>Mo.get(e),enabled:!!e});return r?i.jsx("div",{className:"text-[var(--text-secondary)]",children:"Loading..."}):n?i.jsxs("div",{children:[i.jsxs("div",{className:"mb-6",children:[i.jsx("div",{className:"flex items-center gap-3 mb-2",children:i.jsx("button",{onClick:()=>t(`/jobs/${n.job_id}`),className:"text-[var(--text-secondary)] hover:text-[var(--text-primary)]",children:"← Back to Job"})}),i.jsxs("div",{className:"flex items-center gap-3",children:[i.jsx("h2",{className:"text-xl font-bold",children:n.candidate_name}),i.jsx("span",{className:"text-[var(--text-secondary)]",children:"→"}),i.jsx("span",{className:"text-lg",children:n.task_name}),n.is_pareto&&i.jsx(J,{variant:"success",children:"Optimal"})]})]}),i.jsxs("div",{className:"grid grid-cols-4 gap-4 mb-6",children:[i.jsx(Ta,{label:"Score",value:`${(n.score*100).toFixed(1)}%`,status:n.passed?"success":"error"}),i.jsx(Ta,{label:"Total Tokens",value:n.tokens_total.toLocaleString()}),i.jsx(Ta,{label:"Duration",value:`${n.duration_seconds.toFixed(1)}s`}),i.jsx(Ta,{label:"Status",value:n.passed?"Passed":"Failed",status:n.passed?"success":"error"})]}),i.jsx(Km,{tokensInput:n.tokens_input,tokensOutput:n.tokens_output,tokensTotal:n.tokens_total}),i.jsxs(se,{className:"mb-6",children:[i.jsx("h3",{className:"font-medium mb-3",children:"Evaluation"}),n.reasoning&&i.jsx("p",{className:"text-sm text-[var(--text-secondary)] mb-4",children:n.reasoning}),n.criteria_results.length>0&&i.jsx("div",{className:"space-y-2",children:n.criteria_results.map(s=>i.jsx("div",{className:"flex items-start justify-between p-3 bg-[var(--bg-primary)] border border-[var(--border)]",children:i.jsxs("div",{className:"flex-1",children:[i.jsxs("div",{className:"flex items-center gap-2",children:[i.jsx("span",{className:"font-medium",children:s.name}),i.jsxs(J,{variant:s.passed?"success":"error",children:[(s.score*100).toFixed(0),"%"]})]}),s.reasoning&&i.jsx("p",{className:"text-sm text-[var(--text-secondary)] mt-1",children:s.reasoning})]})},s.name))})]}),i.jsxs(se,{className:"mb-6",children:[i.jsx("h3",{className:"font-medium mb-3",children:"Agent Output"}),i.jsx("pre",{className:"text-sm bg-[var(--bg-primary)] p-3 overflow-x-auto whitespace-pre-wrap border border-[var(--border)]",children:n.output||"(no output)"})]}),n.files_created.length>0&&i.jsxs(se,{className:"mb-6",children:[i.jsx("h3",{className:"font-medium mb-3",children:"Files Created"}),i.jsx("div",{className:"space-y-1",children:n.files_created.map(s=>i.jsx("div",{className:"text-sm font-mono text-[var(--text-secondary)]",children:s},s))})]}),Object.keys(n.trace).length>0&&i.jsx(Bm,{trace:n.trace})]}):i.jsx("div",{className:"text-[var(--text-secondary)]",children:"Run not found"})}function Ta({label:e,value:t,status:n}){const r={success:"text-green-400",error:"text-red-400"};return i.jsxs(se,{children:[i.jsx("div",{className:"text-sm text-[var(--text-secondary)]",children:e}),i.jsx("div",{className:`text-xl font-bold ${n?r[n]:""}`,children:t})]})}function n1(){const{testId:e}=Di(),t=Lt(),{data:n,isLoading:r}=ve({queryKey:["tests",e],queryFn:()=>Es.get(e),enabled:!!e}),{data:s}=ve({queryKey:["configs",n==null?void 0:n.agent_id],queryFn:()=>Er.get(n.agent_id),enabled:!!(n!=null&&n.agent_id)});if(r)return i.jsx("div",{className:"text-[var(--text-secondary)]",children:"Loading..."});if(!n)return i.jsx("div",{className:"text-[var(--text-secondary)]",children:"Test not found"});const a={completed:"success",failed:"error",running:"info",pending:"default",cancelled:"warning"};return i.jsxs("div",{children:[i.jsxs("div",{className:"mb-6",children:[i.jsx("div",{className:"flex items-center gap-3 mb-2",children:i.jsx("button",{onClick:()=>t("/agents"),className:"text-[var(--text-secondary)] hover:text-[var(--text-primary)]",children:"← Back to Agents"})}),i.jsxs("div",{className:"flex items-center gap-3",children:[i.jsx("h2",{className:"text-xl font-bold",children:"Test Run"}),s&&i.jsxs(i.Fragment,{children:[i.jsx("span",{className:"text-[var(--text-secondary)]",children:"•"}),i.jsx("span",{className:"text-lg",children:s.name})]}),i.jsx(J,{variant:a[n.status]||"default",children:n.status})]}),i.jsxs("p",{className:"text-sm text-[var(--text-secondary)] mt-1 font-mono",children:["ID: ",n.id.slice(0,8),"..."]})]}),i.jsxs("div",{className:"grid grid-cols-4 gap-4 mb-6",children:[i.jsx(Oa,{label:"Duration",value:`${n.duration_seconds.toFixed(2)}s`}),i.jsx(Oa,{label:"Total Tokens",value:n.tokens_total.toLocaleString()}),n.score!==null&&i.jsx(Oa,{label:"Score",value:`${(n.score*100).toFixed(1)}%`,status:n.passed?"success":"error"}),i.jsx(Oa,{label:"Status",value:n.status.charAt(0).toUpperCase()+n.status.slice(1),status:n.status==="completed"?"success":n.status==="failed"?"error":void 0})]}),i.jsx(Km,{tokensInput:n.tokens_input,tokensOutput:n.tokens_output,tokensTotal:n.tokens_total}),i.jsxs(se,{className:"mb-6",children:[i.jsx("h3",{className:"font-medium mb-3",children:"Prompt"}),i.jsx("pre",{className:"text-sm bg-[var(--bg-primary)] p-3 overflow-x-auto whitespace-pre-wrap border border-[var(--border)] font-mono",children:n.prompt})]}),n.error&&i.jsxs(se,{className:"mb-6 border-red-500/30 bg-red-500/5",children:[i.jsx("h3",{className:"font-medium mb-3 text-red-400",children:"Error"}),i.jsx("pre",{className:"text-sm text-red-300 overflow-x-auto whitespace-pre-wrap",children:n.error})]}),n.reasoning&&i.jsxs(se,{className:"mb-6",children:[i.jsx("h3",{className:"font-medium mb-3",children:"Evaluation"}),i.jsx("p",{className:"text-sm text-[var(--text-secondary)]",children:n.reasoning})]}),i.jsxs(se,{className:"mb-6",children:[i.jsx("h3",{className:"font-medium mb-3",children:"Agent Output"}),i.jsx("pre",{className:"text-sm bg-[var(--bg-primary)] p-3 overflow-x-auto whitespace-pre-wrap border border-[var(--border)]",children:n.output||"(no output)"})]}),n.files_created&&n.files_created.length>0&&i.jsxs(se,{className:"mb-6",children:[i.jsx("h3",{className:"font-medium mb-3",children:"Files Created"}),i.jsx("div",{className:"space-y-1",children:n.files_created.map(l=>i.jsx("div",{className:"text-sm font-mono text-[var(--text-secondary)]",children:l},l))})]}),n.trace&&Object.keys(n.trace).length>0&&i.jsx(Bm,{trace:n.trace}),i.jsxs(se,{className:"mb-6",children:[i.jsx("h3",{className:"font-medium mb-3",children:"Timestamps"}),i.jsxs("div",{className:"grid grid-cols-3 gap-4 text-sm",children:[i.jsxs("div",{children:[i.jsx("span",{className:"text-[var(--text-secondary)]",children:"Created:"}),i.jsx("div",{className:"font-mono",children:new Date(n.created_at).toLocaleString()})]}),n.started_at&&i.jsxs("div",{children:[i.jsx("span",{className:"text-[var(--text-secondary)]",children:"Started:"}),i.jsx("div",{className:"font-mono",children:new Date(n.started_at).toLocaleString()})]}),n.completed_at&&i.jsxs("div",{children:[i.jsx("span",{className:"text-[var(--text-secondary)]",children:"Completed:"}),i.jsx("div",{className:"font-mono",children:new Date(n.completed_at).toLocaleString()})]})]})]})]})}function Oa({label:e,value:t,status:n}){const r={success:"text-green-400",error:"text-red-400"};return i.jsxs(se,{children:[i.jsx("div",{className:"text-sm text-[var(--text-secondary)]",children:e}),i.jsx("div",{className:`text-xl font-bold ${n?r[n]:""}`,children:t})]})}function r1(){const{authConfig:e,isLoading:t,error:n,login:r,loginWithGitHub:s,clearError:a}=Ku(),[l,o]=S.useState(""),[u,c]=S.useState("");S.useEffect(()=>{n&&a()},[l,u]);const h=async m=>{m.preventDefault(),!(!l||!u)&&await r(l,u)},d=()=>{s()};return i.jsx("div",{className:"min-h-screen bg-[var(--bg-primary)] flex items-center justify-center p-4",children:i.jsxs("div",{className:"w-full max-w-md",children:[i.jsxs("div",{className:"text-center mb-8",children:[i.jsx("h1",{className:"text-2xl font-bold text-[var(--text-primary)] mb-2",children:"Flow"}),i.jsx("p",{className:"text-[var(--text-secondary)]",children:"Sign in to access the optimization dashboard"})]}),i.jsxs("div",{className:"bg-[var(--bg-secondary)] border border-[var(--border)] p-6 space-y-6",children:[n&&i.jsxs("div",{className:"flex items-start gap-3 p-3 bg-[var(--error)]/10 border border-[var(--error)]/20 text-[var(--error)]",children:[i.jsx(_m,{size:18,className:"mt-0.5 flex-shrink-0"}),i.jsx("p",{className:"text-sm",children:n})]}),(e==null?void 0:e.mode)==="basic"&&i.jsxs("form",{onSubmit:h,className:"space-y-4",children:[i.jsxs("div",{className:"space-y-1",children:[i.jsx("label",{className:"block text-sm text-[var(--text-secondary)]",children:"Username"}),i.jsxs("div",{className:"relative",children:[i.jsx(Lm,{size:16,className:"absolute left-3 top-1/2 -translate-y-1/2 text-[var(--text-tertiary)]"}),i.jsx("input",{type:"text",value:l,onChange:m=>o(m.target.value),className:"w-full bg-[var(--bg-primary)] border border-[var(--border)] pl-10 pr-3 py-2 text-sm focus:outline-none focus:border-[var(--accent)]",placeholder:"Enter username",autoComplete:"username",autoFocus:!0})]})]}),i.jsxs("div",{className:"space-y-1",children:[i.jsx("label",{className:"block text-sm text-[var(--text-secondary)]",children:"Password"}),i.jsxs("div",{className:"relative",children:[i.jsx(Pm,{size:16,className:"absolute left-3 top-1/2 -translate-y-1/2 text-[var(--text-tertiary)]"}),i.jsx("input",{type:"password",value:u,onChange:m=>c(m.target.value),className:"w-full bg-[var(--bg-primary)] border border-[var(--border)] pl-10 pr-3 py-2 text-sm focus:outline-none focus:border-[var(--accent)]",placeholder:"Enter password",autoComplete:"current-password"})]})]}),i.jsx(V,{type:"submit",variant:"primary",className:"w-full justify-center",loading:t,disabled:!l||!u,children:"Sign In"})]}),(e==null?void 0:e.mode)==="github"&&i.jsxs("div",{className:"space-y-4",children:[i.jsx("p",{className:"text-sm text-[var(--text-secondary)] text-center",children:"Sign in with your GitHub account to continue"}),i.jsx(V,{onClick:d,variant:"secondary",className:"w-full justify-center",icon:Sg,children:"Continue with GitHub"})]})]})]})})}function s1({children:e}){const{authConfig:t,isLoadingConfig:n,isAuthenticated:r,loadAuthConfig:s,handleOAuthCallback:a}=Ku();return S.useEffect(()=>{s()},[s]),S.useEffect(()=>{n||a()},[n,a]),n?i.jsx("div",{className:"min-h-screen bg-[var(--bg-primary)] flex items-center justify-center",children:i.jsxs("div",{className:"text-center",children:[i.jsx(ca,{className:"w-8 h-8 animate-spin text-[var(--accent)] mx-auto mb-4"}),i.jsx("p",{className:"text-[var(--text-secondary)]",children:"Loading..."})]})}):t!=null&&t.enabled&&!r?i.jsx(r1,{}):i.jsx(i.Fragment,{children:e})}function a1(){return i.jsx(rg,{children:i.jsx(s1,{children:i.jsx(Jy,{children:i.jsxs(kt,{path:"/",element:i.jsx(x0,{}),children:[i.jsx(kt,{index:!0,element:i.jsx(Pd,{})}),i.jsx(kt,{path:"agents",element:i.jsx(Pd,{})}),i.jsx(kt,{path:"agents/:agentId",element:i.jsx(D0,{})}),i.jsx(kt,{path:"tasks",element:i.jsx(U0,{})}),i.jsx(kt,{path:"jobs",element:i.jsx(H0,{})}),i.jsx(kt,{path:"jobs/:jobId",element:i.jsx(e1,{})}),i.jsx(kt,{path:"runs/:runId",element:i.jsx(t1,{})}),i.jsx(kt,{path:"tests/:testId",element:i.jsx(n1,{})})]})})})})}const Ld=localStorage.getItem("flow-theme");if(Ld)try{const{state:e}=JSON.parse(Ld);e!=null&&e.theme&&document.documentElement.setAttribute("data-theme",e.theme)}catch{}const i1=new Vx({defaultOptions:{queries:{staleTime:5e3,refetchOnWindowFocus:!1}}});kl.createRoot(document.getElementById("root")).render(i.jsx(Qo.StrictMode,{children:i.jsx(Kx,{client:i1,children:i.jsx(a1,{})})})); diff --git a/src/flow/ui/ui/assets/index-C0IOOQ4X.css b/src/flow/ui/ui/assets/index-C0IOOQ4X.css new file mode 100644 index 0000000000000000000000000000000000000000..d31d5c28e6d34dbf28f6f2e95915d2cf48e4d506 --- /dev/null +++ b/src/flow/ui/ui/assets/index-C0IOOQ4X.css @@ -0,0 +1 @@ +*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:JetBrains Mono,ui-monospace,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.pointer-events-none{pointer-events:none}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{top:0;right:0;bottom:0;left:0}.bottom-0{bottom:0}.left-0{left:0}.left-3{left:.75rem}.top-0{top:0}.top-1\/2{top:50%}.z-10{z-index:10}.z-50{z-index:50}.col-span-2{grid-column:span 2 / span 2}.mx-0\.5{margin-left:.125rem;margin-right:.125rem}.mx-4{margin-left:1rem;margin-right:1rem}.mx-auto{margin-left:auto;margin-right:auto}.-mt-2{margin-top:-.5rem}.mb-1{margin-bottom:.25rem}.mb-1\.5{margin-bottom:.375rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.mb-8{margin-bottom:2rem}.ml-1{margin-left:.25rem}.ml-2{margin-left:.5rem}.ml-4{margin-left:1rem}.ml-6{margin-left:1.5rem}.mr-1{margin-right:.25rem}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-8{margin-top:2rem}.mt-auto{margin-top:auto}.line-clamp-2{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2}.line-clamp-3{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.h-1\.5{height:.375rem}.h-12{height:3rem}.h-2{height:.5rem}.h-3{height:.75rem}.h-32{height:8rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-8{height:2rem}.h-full{height:100%}.max-h-32{max-height:8rem}.max-h-40{max-height:10rem}.max-h-48{max-height:12rem}.max-h-80{max-height:20rem}.max-h-96{max-height:24rem}.max-h-\[80vh\]{max-height:80vh}.min-h-0{min-height:0px}.min-h-\[100px\]{min-height:100px}.min-h-screen{min-height:100vh}.w-11{width:2.75rem}.w-12{width:3rem}.w-2{width:.5rem}.w-20{width:5rem}.w-24{width:6rem}.w-3{width:.75rem}.w-32{width:8rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-8{width:2rem}.w-full{width:100%}.min-w-0{min-width:0px}.min-w-\[90px\]{min-width:90px}.max-w-2xl{max-width:42rem}.max-w-7xl{max-width:80rem}.max-w-\[200px\]{max-width:200px}.max-w-full{max-width:100%}.max-w-lg{max-width:32rem}.max-w-md{max-width:28rem}.flex-1{flex:1 1 0%}.flex-shrink-0{flex-shrink:0}.-translate-y-1\/2{--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-1{--tw-translate-x: .25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-6{--tw-translate-x: 1.5rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-180{--tw-rotate: 180deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-90{--tw-rotate: 90deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.resize-none{resize:none}.resize-y{resize:vertical}.resize{resize:both}.list-disc{list-style-type:disc}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-6{gap:1.5rem}.gap-8{gap:2rem}.gap-x-4{-moz-column-gap:1rem;column-gap:1rem}.gap-y-1{row-gap:.25rem}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem * var(--tw-space-y-reverse))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.break-all{word-break:break-all}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.border{border-width:1px}.border-b{border-bottom-width:1px}.border-b-2{border-bottom-width:2px}.border-l-2{border-left-width:2px}.border-t{border-top-width:1px}.border-dashed{border-style:dashed}.border-\[var\(--accent\)\]{border-color:var(--accent)}.border-\[var\(--border\)\]{border-color:var(--border)}.border-blue-500\/30{border-color:#3b82f64d}.border-green-500\/20{border-color:#22c55e33}.border-green-500\/30{border-color:#22c55e4d}.border-green-500\/50{border-color:#22c55e80}.border-red-500\/20{border-color:#ef444433}.border-red-500\/30{border-color:#ef44444d}.border-red-500\/50{border-color:#ef444480}.border-transparent{border-color:transparent}.bg-\[var\(--accent\)\]{background-color:var(--accent)}.bg-\[var\(--bg-primary\)\]{background-color:var(--bg-primary)}.bg-\[var\(--bg-secondary\)\]{background-color:var(--bg-secondary)}.bg-\[var\(--bg-tertiary\)\]{background-color:var(--bg-tertiary)}.bg-\[var\(--border\)\]{background-color:var(--border)}.bg-\[var\(--error\)\]{background-color:var(--error)}.bg-black\/50{background-color:#00000080}.bg-black\/80{background-color:#000c}.bg-blue-100{--tw-bg-opacity: 1;background-color:rgb(219 234 254 / var(--tw-bg-opacity, 1))}.bg-blue-400{--tw-bg-opacity: 1;background-color:rgb(96 165 250 / var(--tw-bg-opacity, 1))}.bg-blue-500{--tw-bg-opacity: 1;background-color:rgb(59 130 246 / var(--tw-bg-opacity, 1))}.bg-blue-500\/10{background-color:#3b82f61a}.bg-blue-600{--tw-bg-opacity: 1;background-color:rgb(37 99 235 / var(--tw-bg-opacity, 1))}.bg-emerald-500{--tw-bg-opacity: 1;background-color:rgb(16 185 129 / var(--tw-bg-opacity, 1))}.bg-green-100{--tw-bg-opacity: 1;background-color:rgb(220 252 231 / var(--tw-bg-opacity, 1))}.bg-green-400{--tw-bg-opacity: 1;background-color:rgb(74 222 128 / var(--tw-bg-opacity, 1))}.bg-green-500{--tw-bg-opacity: 1;background-color:rgb(34 197 94 / var(--tw-bg-opacity, 1))}.bg-green-500\/10{background-color:#22c55e1a}.bg-green-500\/20{background-color:#22c55e33}.bg-green-600{--tw-bg-opacity: 1;background-color:rgb(22 163 74 / var(--tw-bg-opacity, 1))}.bg-orange-100{--tw-bg-opacity: 1;background-color:rgb(255 237 213 / var(--tw-bg-opacity, 1))}.bg-purple-100{--tw-bg-opacity: 1;background-color:rgb(243 232 255 / var(--tw-bg-opacity, 1))}.bg-red-100{--tw-bg-opacity: 1;background-color:rgb(254 226 226 / var(--tw-bg-opacity, 1))}.bg-red-500{--tw-bg-opacity: 1;background-color:rgb(239 68 68 / var(--tw-bg-opacity, 1))}.bg-red-500\/10{background-color:#ef44441a}.bg-red-500\/5{background-color:#ef44440d}.bg-red-600{--tw-bg-opacity: 1;background-color:rgb(220 38 38 / var(--tw-bg-opacity, 1))}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.bg-yellow-500{--tw-bg-opacity: 1;background-color:rgb(234 179 8 / var(--tw-bg-opacity, 1))}.p-1{padding:.25rem}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-6{padding:1.5rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-12{padding-top:3rem;padding-bottom:3rem}.py-16{padding-top:4rem;padding-bottom:4rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-8{padding-top:2rem;padding-bottom:2rem}.pb-2{padding-bottom:.5rem}.pl-10{padding-left:2.5rem}.pr-3{padding-right:.75rem}.pr-4{padding-right:1rem}.pt-2{padding-top:.5rem}.pt-3{padding-top:.75rem}.pt-4{padding-top:1rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.font-mono{font-family:JetBrains Mono,ui-monospace,monospace}.text-2xl{font-size:1.5rem;line-height:2rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.capitalize{text-transform:capitalize}.italic{font-style:italic}.tracking-wide{letter-spacing:.025em}.tracking-wider{letter-spacing:.05em}.text-\[var\(--accent\)\]{color:var(--accent)}.text-\[var\(--error\)\]{color:var(--error)}.text-\[var\(--text-primary\)\]{color:var(--text-primary)}.text-\[var\(--text-secondary\)\]{color:var(--text-secondary)}.text-\[var\(--text-tertiary\)\]{color:var(--text-tertiary)}.text-black{--tw-text-opacity: 1;color:rgb(0 0 0 / var(--tw-text-opacity, 1))}.text-blue-400{--tw-text-opacity: 1;color:rgb(96 165 250 / var(--tw-text-opacity, 1))}.text-blue-800{--tw-text-opacity: 1;color:rgb(30 64 175 / var(--tw-text-opacity, 1))}.text-emerald-400{--tw-text-opacity: 1;color:rgb(52 211 153 / var(--tw-text-opacity, 1))}.text-green-400{--tw-text-opacity: 1;color:rgb(74 222 128 / var(--tw-text-opacity, 1))}.text-green-500{--tw-text-opacity: 1;color:rgb(34 197 94 / var(--tw-text-opacity, 1))}.text-green-800{--tw-text-opacity: 1;color:rgb(22 101 52 / var(--tw-text-opacity, 1))}.text-orange-800{--tw-text-opacity: 1;color:rgb(154 52 18 / var(--tw-text-opacity, 1))}.text-purple-400{--tw-text-opacity: 1;color:rgb(192 132 252 / var(--tw-text-opacity, 1))}.text-purple-800{--tw-text-opacity: 1;color:rgb(107 33 168 / var(--tw-text-opacity, 1))}.text-red-300{--tw-text-opacity: 1;color:rgb(252 165 165 / var(--tw-text-opacity, 1))}.text-red-400{--tw-text-opacity: 1;color:rgb(248 113 113 / var(--tw-text-opacity, 1))}.text-red-500{--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity, 1))}.text-red-800{--tw-text-opacity: 1;color:rgb(153 27 27 / var(--tw-text-opacity, 1))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.text-yellow-500{--tw-text-opacity: 1;color:rgb(234 179 8 / var(--tw-text-opacity, 1))}.accent-\[var\(--accent\)\]{accent-color:var(--accent)}.opacity-50{opacity:.5}.shadow-lg{--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-xl{--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-300{transition-duration:.3s}:root{--bg-primary: #0a0a0a;--bg-secondary: #141414;--bg-tertiary: #1a1a1a;--text-primary: #f5f5f5;--text-secondary: #a3a3a3;--accent: #22c55e;--accent-dim: #166534;--border: #262626;--error: #ef4444}[data-theme=light]{--bg-primary: #ffffff;--bg-secondary: #f7f8f9;--bg-tertiary: #eef0f2;--text-primary: #1a1a1a;--text-secondary: #4a4a4a;--accent: #16a34a;--accent-dim: #dcfce7;--border: #d1d5db;--error: #dc2626}*{box-sizing:border-box}body{margin:0;background-color:var(--bg-primary);color:var(--text-primary);font-family:JetBrains Mono,ui-monospace,monospace;font-size:14px;line-height:1.6}::-webkit-scrollbar{width:8px;height:8px}::-webkit-scrollbar-track{background:var(--bg-secondary)}::-webkit-scrollbar-thumb{background:var(--border);border-radius:4px}::-webkit-scrollbar-thumb:hover{background:#404040}[data-theme=light] ::-webkit-scrollbar-thumb:hover{background:silver}.last\:border-0:last-child{border-width:0px}.hover\:border-\[var\(--accent-dim\)\]:hover{border-color:var(--accent-dim)}.hover\:bg-\[\#16a34a\]:hover{--tw-bg-opacity: 1;background-color:rgb(22 163 74 / var(--tw-bg-opacity, 1))}.hover\:bg-\[var\(--bg-primary\)\]:hover{background-color:var(--bg-primary)}.hover\:bg-\[var\(--bg-tertiary\)\]:hover{background-color:var(--bg-tertiary)}.hover\:bg-\[var\(--border\)\]:hover{background-color:var(--border)}.hover\:bg-red-600:hover{--tw-bg-opacity: 1;background-color:rgb(220 38 38 / var(--tw-bg-opacity, 1))}.hover\:text-\[var\(--accent\)\]:hover{color:var(--accent)}.hover\:text-\[var\(--error\)\]:hover{color:var(--error)}.hover\:text-\[var\(--text-primary\)\]:hover{color:var(--text-primary)}.hover\:opacity-80:hover{opacity:.8}.focus\:border-\[var\(--accent\)\]:focus{border-color:var(--accent)}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-2:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-\[var\(--accent\)\]:focus{--tw-ring-color: var(--accent)}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}@media (min-width: 768px){.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (min-width: 1024px){.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}@media (min-width: 1280px){.xl\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}@media (prefers-color-scheme: dark){.dark\:bg-blue-900{--tw-bg-opacity: 1;background-color:rgb(30 58 138 / var(--tw-bg-opacity, 1))}.dark\:bg-green-900{--tw-bg-opacity: 1;background-color:rgb(20 83 45 / var(--tw-bg-opacity, 1))}.dark\:bg-orange-900{--tw-bg-opacity: 1;background-color:rgb(124 45 18 / var(--tw-bg-opacity, 1))}.dark\:bg-purple-900{--tw-bg-opacity: 1;background-color:rgb(88 28 135 / var(--tw-bg-opacity, 1))}.dark\:bg-red-900{--tw-bg-opacity: 1;background-color:rgb(127 29 29 / var(--tw-bg-opacity, 1))}.dark\:text-blue-200{--tw-text-opacity: 1;color:rgb(191 219 254 / var(--tw-text-opacity, 1))}.dark\:text-green-200{--tw-text-opacity: 1;color:rgb(187 247 208 / var(--tw-text-opacity, 1))}.dark\:text-orange-200{--tw-text-opacity: 1;color:rgb(254 215 170 / var(--tw-text-opacity, 1))}.dark\:text-purple-200{--tw-text-opacity: 1;color:rgb(233 213 255 / var(--tw-text-opacity, 1))}.dark\:text-red-200{--tw-text-opacity: 1;color:rgb(254 202 202 / var(--tw-text-opacity, 1))}} diff --git a/src/flow/ui/ui/assets/index-Cma0lWjl.js b/src/flow/ui/ui/assets/index-Cma0lWjl.js new file mode 100644 index 0000000000000000000000000000000000000000..3e8d033a6f399b97c13c73d7c56986f389a4fe32 --- /dev/null +++ b/src/flow/ui/ui/assets/index-Cma0lWjl.js @@ -0,0 +1,270 @@ +var qu=e=>{throw TypeError(e)};var Ki=(e,t,n)=>t.has(e)||qu("Cannot "+n);var y=(e,t,n)=>(Ki(e,t,"read from private field"),n?n.call(e):t.get(e)),$=(e,t,n)=>t.has(e)?qu("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(e):t.set(e,n),z=(e,t,n,r)=>(Ki(e,t,"write to private field"),r?r.call(e,n):t.set(e,n),n),W=(e,t,n)=>(Ki(e,t,"access private method"),n);var da=(e,t,n,r)=>({set _(s){z(e,t,s,n)},get _(){return y(e,t,r)}});function Wm(e,t){for(var n=0;nr[s]})}}}return Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const s of document.querySelectorAll('link[rel="modulepreload"]'))r(s);new MutationObserver(s=>{for(const a of s)if(a.type==="childList")for(const l of a.addedNodes)l.tagName==="LINK"&&l.rel==="modulepreload"&&r(l)}).observe(document,{childList:!0,subtree:!0});function n(s){const a={};return s.integrity&&(a.integrity=s.integrity),s.referrerPolicy&&(a.referrerPolicy=s.referrerPolicy),s.crossOrigin==="use-credentials"?a.credentials="include":s.crossOrigin==="anonymous"?a.credentials="omit":a.credentials="same-origin",a}function r(s){if(s.ep)return;s.ep=!0;const a=n(s);fetch(s.href,a)}})();function Vd(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var Kd={exports:{}},ji={},Hd={exports:{}},q={};/** + * @license React + * react.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var sa=Symbol.for("react.element"),qm=Symbol.for("react.portal"),Jm=Symbol.for("react.fragment"),Gm=Symbol.for("react.strict_mode"),Ym=Symbol.for("react.profiler"),Xm=Symbol.for("react.provider"),Zm=Symbol.for("react.context"),ep=Symbol.for("react.forward_ref"),tp=Symbol.for("react.suspense"),np=Symbol.for("react.memo"),rp=Symbol.for("react.lazy"),Ju=Symbol.iterator;function sp(e){return e===null||typeof e!="object"?null:(e=Ju&&e[Ju]||e["@@iterator"],typeof e=="function"?e:null)}var Wd={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},qd=Object.assign,Jd={};function Gr(e,t,n){this.props=e,this.context=t,this.refs=Jd,this.updater=n||Wd}Gr.prototype.isReactComponent={};Gr.prototype.setState=function(e,t){if(typeof e!="object"&&typeof e!="function"&&e!=null)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")};Gr.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")};function Gd(){}Gd.prototype=Gr.prototype;function Ao(e,t,n){this.props=e,this.context=t,this.refs=Jd,this.updater=n||Wd}var $o=Ao.prototype=new Gd;$o.constructor=Ao;qd($o,Gr.prototype);$o.isPureReactComponent=!0;var Gu=Array.isArray,Yd=Object.prototype.hasOwnProperty,Uo={current:null},Xd={key:!0,ref:!0,__self:!0,__source:!0};function Zd(e,t,n){var r,s={},a=null,l=null;if(t!=null)for(r in t.ref!==void 0&&(l=t.ref),t.key!==void 0&&(a=""+t.key),t)Yd.call(t,r)&&!Xd.hasOwnProperty(r)&&(s[r]=t[r]);var o=arguments.length-2;if(o===1)s.children=n;else if(1>>1,X=T[K];if(0>>1;Ks(Z,L))hes(Ne,Z)?(T[K]=Ne,T[he]=L,K=he):(T[K]=Z,T[O]=L,K=O);else if(hes(Ne,L))T[K]=Ne,T[he]=L,K=he;else break e}}return A}function s(T,A){var L=T.sortIndex-A.sortIndex;return L!==0?L:T.id-A.id}if(typeof performance=="object"&&typeof performance.now=="function"){var a=performance;e.unstable_now=function(){return a.now()}}else{var l=Date,o=l.now();e.unstable_now=function(){return l.now()-o}}var u=[],c=[],h=1,d=null,m=3,x=!1,w=!1,j=!1,S=typeof setTimeout=="function"?setTimeout:null,p=typeof clearTimeout=="function"?clearTimeout:null,f=typeof setImmediate<"u"?setImmediate:null;typeof navigator<"u"&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function v(T){for(var A=n(c);A!==null;){if(A.callback===null)r(c);else if(A.startTime<=T)r(c),A.sortIndex=A.expirationTime,t(u,A);else break;A=n(c)}}function g(T){if(j=!1,v(T),!w)if(n(u)!==null)w=!0,Ge(C);else{var A=n(c);A!==null&&ie(g,A.startTime-T)}}function C(T,A){w=!1,j&&(j=!1,p(_),_=-1),x=!0;var L=m;try{for(v(A),d=n(u);d!==null&&(!(d.expirationTime>A)||T&&!B());){var K=d.callback;if(typeof K=="function"){d.callback=null,m=d.priorityLevel;var X=K(d.expirationTime<=A);A=e.unstable_now(),typeof X=="function"?d.callback=X:d===n(u)&&r(u),v(A)}else r(u);d=n(u)}if(d!==null)var R=!0;else{var O=n(c);O!==null&&ie(g,O.startTime-A),R=!1}return R}finally{d=null,m=L,x=!1}}var b=!1,N=null,_=-1,F=5,P=-1;function B(){return!(e.unstable_now()-PT||125K?(T.sortIndex=L,t(c,T),n(u)===null&&T===n(c)&&(j?(p(_),_=-1):j=!0,ie(g,L-K))):(T.sortIndex=X,t(u,T),w||x||(w=!0,Ge(C))),T},e.unstable_shouldYield=B,e.unstable_wrapCallback=function(T){var A=m;return function(){var L=m;m=A;try{return T.apply(this,arguments)}finally{m=L}}}})(sf);rf.exports=sf;var vp=rf.exports;/** + * @license React + * react-dom.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var xp=k,et=vp;function E(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),Sl=Object.prototype.hasOwnProperty,yp=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,Xu={},Zu={};function gp(e){return Sl.call(Zu,e)?!0:Sl.call(Xu,e)?!1:yp.test(e)?Zu[e]=!0:(Xu[e]=!0,!1)}function jp(e,t,n,r){if(n!==null&&n.type===0)return!1;switch(typeof t){case"function":case"symbol":return!0;case"boolean":return r?!1:n!==null?!n.acceptsBooleans:(e=e.toLowerCase().slice(0,5),e!=="data-"&&e!=="aria-");default:return!1}}function wp(e,t,n,r){if(t===null||typeof t>"u"||jp(e,t,n,r))return!0;if(r)return!1;if(n!==null)switch(n.type){case 3:return!t;case 4:return t===!1;case 5:return isNaN(t);case 6:return isNaN(t)||1>t}return!1}function Ue(e,t,n,r,s,a,l){this.acceptsBooleans=t===2||t===3||t===4,this.attributeName=r,this.attributeNamespace=s,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=a,this.removeEmptyString=l}var Te={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(e){Te[e]=new Ue(e,0,!1,e,null,!1,!1)});[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(e){var t=e[0];Te[t]=new Ue(t,1,!1,e[1],null,!1,!1)});["contentEditable","draggable","spellCheck","value"].forEach(function(e){Te[e]=new Ue(e,2,!1,e.toLowerCase(),null,!1,!1)});["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(e){Te[e]=new Ue(e,2,!1,e,null,!1,!1)});"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(e){Te[e]=new Ue(e,3,!1,e.toLowerCase(),null,!1,!1)});["checked","multiple","muted","selected"].forEach(function(e){Te[e]=new Ue(e,3,!0,e,null,!1,!1)});["capture","download"].forEach(function(e){Te[e]=new Ue(e,4,!1,e,null,!1,!1)});["cols","rows","size","span"].forEach(function(e){Te[e]=new Ue(e,6,!1,e,null,!1,!1)});["rowSpan","start"].forEach(function(e){Te[e]=new Ue(e,5,!1,e.toLowerCase(),null,!1,!1)});var Vo=/[\-:]([a-z])/g;function Ko(e){return e[1].toUpperCase()}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(e){var t=e.replace(Vo,Ko);Te[t]=new Ue(t,1,!1,e,null,!1,!1)});"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(e){var t=e.replace(Vo,Ko);Te[t]=new Ue(t,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)});["xml:base","xml:lang","xml:space"].forEach(function(e){var t=e.replace(Vo,Ko);Te[t]=new Ue(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)});["tabIndex","crossOrigin"].forEach(function(e){Te[e]=new Ue(e,1,!1,e.toLowerCase(),null,!1,!1)});Te.xlinkHref=new Ue("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1);["src","href","action","formAction"].forEach(function(e){Te[e]=new Ue(e,1,!1,e.toLowerCase(),null,!0,!0)});function Ho(e,t,n,r){var s=Te.hasOwnProperty(t)?Te[t]:null;(s!==null?s.type!==0:r||!(2o||s[l]!==a[o]){var u=` +`+s[l].replace(" at new "," at ");return e.displayName&&u.includes("")&&(u=u.replace("",e.displayName)),u}while(1<=l&&0<=o);break}}}finally{qi=!1,Error.prepareStackTrace=n}return(e=e?e.displayName||e.name:"")?ms(e):""}function kp(e){switch(e.tag){case 5:return ms(e.type);case 16:return ms("Lazy");case 13:return ms("Suspense");case 19:return ms("SuspenseList");case 0:case 2:case 15:return e=Ji(e.type,!1),e;case 11:return e=Ji(e.type.render,!1),e;case 1:return e=Ji(e.type,!0),e;default:return""}}function _l(e){if(e==null)return null;if(typeof e=="function")return e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case dr:return"Fragment";case cr:return"Portal";case Nl:return"Profiler";case Wo:return"StrictMode";case bl:return"Suspense";case Cl:return"SuspenseList"}if(typeof e=="object")switch(e.$$typeof){case of:return(e.displayName||"Context")+".Consumer";case lf:return(e._context.displayName||"Context")+".Provider";case qo:var t=e.render;return e=e.displayName,e||(e=t.displayName||t.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case Jo:return t=e.displayName||null,t!==null?t:_l(e.type)||"Memo";case Zt:t=e._payload,e=e._init;try{return _l(e(t))}catch{}}return null}function Sp(e){var t=e.type;switch(e.tag){case 24:return"Cache";case 9:return(t.displayName||"Context")+".Consumer";case 10:return(t._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return e=t.render,e=e.displayName||e.name||"",t.displayName||(e!==""?"ForwardRef("+e+")":"ForwardRef");case 7:return"Fragment";case 5:return t;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return _l(t);case 8:return t===Wo?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if(typeof t=="function")return t.displayName||t.name||null;if(typeof t=="string")return t}return null}function En(e){switch(typeof e){case"boolean":case"number":case"string":case"undefined":return e;case"object":return e;default:return""}}function cf(e){var t=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(t==="checkbox"||t==="radio")}function Np(e){var t=cf(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),r=""+e[t];if(!e.hasOwnProperty(t)&&typeof n<"u"&&typeof n.get=="function"&&typeof n.set=="function"){var s=n.get,a=n.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return s.call(this)},set:function(l){r=""+l,a.call(this,l)}}),Object.defineProperty(e,t,{enumerable:n.enumerable}),{getValue:function(){return r},setValue:function(l){r=""+l},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}function ma(e){e._valueTracker||(e._valueTracker=Np(e))}function df(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),r="";return e&&(r=cf(e)?e.checked?"true":"false":e.value),e=r,e!==n?(t.setValue(e),!0):!1}function Ka(e){if(e=e||(typeof document<"u"?document:void 0),typeof e>"u")return null;try{return e.activeElement||e.body}catch{return e.body}}function El(e,t){var n=t.checked;return fe({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:n??e._wrapperState.initialChecked})}function tc(e,t){var n=t.defaultValue==null?"":t.defaultValue,r=t.checked!=null?t.checked:t.defaultChecked;n=En(t.value!=null?t.value:n),e._wrapperState={initialChecked:r,initialValue:n,controlled:t.type==="checkbox"||t.type==="radio"?t.checked!=null:t.value!=null}}function ff(e,t){t=t.checked,t!=null&&Ho(e,"checked",t,!1)}function Pl(e,t){ff(e,t);var n=En(t.value),r=t.type;if(n!=null)r==="number"?(n===0&&e.value===""||e.value!=n)&&(e.value=""+n):e.value!==""+n&&(e.value=""+n);else if(r==="submit"||r==="reset"){e.removeAttribute("value");return}t.hasOwnProperty("value")?Tl(e,t.type,n):t.hasOwnProperty("defaultValue")&&Tl(e,t.type,En(t.defaultValue)),t.checked==null&&t.defaultChecked!=null&&(e.defaultChecked=!!t.defaultChecked)}function nc(e,t,n){if(t.hasOwnProperty("value")||t.hasOwnProperty("defaultValue")){var r=t.type;if(!(r!=="submit"&&r!=="reset"||t.value!==void 0&&t.value!==null))return;t=""+e._wrapperState.initialValue,n||t===e.value||(e.value=t),e.defaultValue=t}n=e.name,n!==""&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,n!==""&&(e.name=n)}function Tl(e,t,n){(t!=="number"||Ka(e.ownerDocument)!==e)&&(n==null?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+n&&(e.defaultValue=""+n))}var ps=Array.isArray;function kr(e,t,n,r){if(e=e.options,t){t={};for(var s=0;s"+t.valueOf().toString()+"",t=pa.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}});function Ts(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&n.nodeType===3){n.nodeValue=t;return}}e.textContent=t}var gs={animationIterationCount:!0,aspectRatio:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},bp=["Webkit","ms","Moz","O"];Object.keys(gs).forEach(function(e){bp.forEach(function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),gs[t]=gs[e]})});function vf(e,t,n){return t==null||typeof t=="boolean"||t===""?"":n||typeof t!="number"||t===0||gs.hasOwnProperty(e)&&gs[e]?(""+t).trim():t+"px"}function xf(e,t){e=e.style;for(var n in t)if(t.hasOwnProperty(n)){var r=n.indexOf("--")===0,s=vf(n,t[n],r);n==="float"&&(n="cssFloat"),r?e.setProperty(n,s):e[n]=s}}var Cp=fe({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function Rl(e,t){if(t){if(Cp[e]&&(t.children!=null||t.dangerouslySetInnerHTML!=null))throw Error(E(137,e));if(t.dangerouslySetInnerHTML!=null){if(t.children!=null)throw Error(E(60));if(typeof t.dangerouslySetInnerHTML!="object"||!("__html"in t.dangerouslySetInnerHTML))throw Error(E(61))}if(t.style!=null&&typeof t.style!="object")throw Error(E(62))}}function Ml(e,t){if(e.indexOf("-")===-1)return typeof t.is=="string";switch(e){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}var zl=null;function Go(e){return e=e.target||e.srcElement||window,e.correspondingUseElement&&(e=e.correspondingUseElement),e.nodeType===3?e.parentNode:e}var Fl=null,Sr=null,Nr=null;function ac(e){if(e=la(e)){if(typeof Fl!="function")throw Error(E(280));var t=e.stateNode;t&&(t=bi(t),Fl(e.stateNode,e.type,t))}}function yf(e){Sr?Nr?Nr.push(e):Nr=[e]:Sr=e}function gf(){if(Sr){var e=Sr,t=Nr;if(Nr=Sr=null,ac(e),t)for(e=0;e>>=0,e===0?32:31-(Ip(e)/Dp|0)|0}var va=64,xa=4194304;function vs(e){switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return e&4194240;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return e&130023424;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 1073741824;default:return e}}function Ja(e,t){var n=e.pendingLanes;if(n===0)return 0;var r=0,s=e.suspendedLanes,a=e.pingedLanes,l=n&268435455;if(l!==0){var o=l&~s;o!==0?r=vs(o):(a&=l,a!==0&&(r=vs(a)))}else l=n&~s,l!==0?r=vs(l):a!==0&&(r=vs(a));if(r===0)return 0;if(t!==0&&t!==r&&!(t&s)&&(s=r&-r,a=t&-t,s>=a||s===16&&(a&4194240)!==0))return t;if(r&4&&(r|=n&16),t=e.entangledLanes,t!==0)for(e=e.entanglements,t&=r;0n;n++)t.push(e);return t}function aa(e,t,n){e.pendingLanes|=t,t!==536870912&&(e.suspendedLanes=0,e.pingedLanes=0),e=e.eventTimes,t=31-yt(t),e[t]=n}function Bp(e,t){var n=e.pendingLanes&~t;e.pendingLanes=t,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=t,e.mutableReadLanes&=t,e.entangledLanes&=t,t=e.entanglements;var r=e.eventTimes;for(e=e.expirationTimes;0=ws),mc=" ",pc=!1;function Af(e,t){switch(e){case"keyup":return vv.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function $f(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var fr=!1;function yv(e,t){switch(e){case"compositionend":return $f(t);case"keypress":return t.which!==32?null:(pc=!0,mc);case"textInput":return e=t.data,e===mc&&pc?null:e;default:return null}}function gv(e,t){if(fr)return e==="compositionend"||!su&&Af(e,t)?(e=If(),za=tu=hn=null,fr=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:n,offset:t-e};e=r}e:{for(;n;){if(n.nextSibling){n=n.nextSibling;break e}n=n.parentNode}n=void 0}n=gc(n)}}function Vf(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?Vf(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function Kf(){for(var e=window,t=Ka();t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href=="string"}catch{n=!1}if(n)e=t.contentWindow;else break;t=Ka(e.document)}return t}function au(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}function Ev(e){var t=Kf(),n=e.focusedElem,r=e.selectionRange;if(t!==n&&n&&n.ownerDocument&&Vf(n.ownerDocument.documentElement,n)){if(r!==null&&au(n)){if(t=r.start,e=r.end,e===void 0&&(e=t),"selectionStart"in n)n.selectionStart=t,n.selectionEnd=Math.min(e,n.value.length);else if(e=(t=n.ownerDocument||document)&&t.defaultView||window,e.getSelection){e=e.getSelection();var s=n.textContent.length,a=Math.min(r.start,s);r=r.end===void 0?a:Math.min(r.end,s),!e.extend&&a>r&&(s=r,r=a,a=s),s=jc(n,a);var l=jc(n,r);s&&l&&(e.rangeCount!==1||e.anchorNode!==s.node||e.anchorOffset!==s.offset||e.focusNode!==l.node||e.focusOffset!==l.offset)&&(t=t.createRange(),t.setStart(s.node,s.offset),e.removeAllRanges(),a>r?(e.addRange(t),e.extend(l.node,l.offset)):(t.setEnd(l.node,l.offset),e.addRange(t)))}}for(t=[],e=n;e=e.parentNode;)e.nodeType===1&&t.push({element:e,left:e.scrollLeft,top:e.scrollTop});for(typeof n.focus=="function"&&n.focus(),n=0;n=document.documentMode,hr=null,Bl=null,Ss=null,Ql=!1;function wc(e,t,n){var r=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;Ql||hr==null||hr!==Ka(r)||(r=hr,"selectionStart"in r&&au(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),Ss&&Fs(Ss,r)||(Ss=r,r=Xa(Bl,"onSelect"),0vr||(e.current=Jl[vr],Jl[vr]=null,vr--)}function ae(e,t){vr++,Jl[vr]=e.current,e.current=t}var Pn={},ze=On(Pn),He=On(!1),Xn=Pn;function Br(e,t){var n=e.type.contextTypes;if(!n)return Pn;var r=e.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===t)return r.__reactInternalMemoizedMaskedChildContext;var s={},a;for(a in n)s[a]=t[a];return r&&(e=e.stateNode,e.__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=s),s}function We(e){return e=e.childContextTypes,e!=null}function ei(){oe(He),oe(ze)}function Ec(e,t,n){if(ze.current!==Pn)throw Error(E(168));ae(ze,t),ae(He,n)}function eh(e,t,n){var r=e.stateNode;if(t=t.childContextTypes,typeof r.getChildContext!="function")return n;r=r.getChildContext();for(var s in r)if(!(s in t))throw Error(E(108,Sp(e)||"Unknown",s));return fe({},n,r)}function ti(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||Pn,Xn=ze.current,ae(ze,e),ae(He,He.current),!0}function Pc(e,t,n){var r=e.stateNode;if(!r)throw Error(E(169));n?(e=eh(e,t,Xn),r.__reactInternalMemoizedMergedChildContext=e,oe(He),oe(ze),ae(ze,e)):oe(He),ae(He,n)}var zt=null,Ci=!1,ul=!1;function th(e){zt===null?zt=[e]:zt.push(e)}function $v(e){Ci=!0,th(e)}function Ln(){if(!ul&&zt!==null){ul=!0;var e=0,t=re;try{var n=zt;for(re=1;e>=l,s-=l,$t=1<<32-yt(t)+s|n<_?(F=N,N=null):F=N.sibling;var P=m(p,N,v[_],g);if(P===null){N===null&&(N=F);break}e&&N&&P.alternate===null&&t(p,N),f=a(P,f,_),b===null?C=P:b.sibling=P,b=P,N=F}if(_===v.length)return n(p,N),ue&&Mn(p,_),C;if(N===null){for(;__?(F=N,N=null):F=N.sibling;var B=m(p,N,P.value,g);if(B===null){N===null&&(N=F);break}e&&N&&B.alternate===null&&t(p,N),f=a(B,f,_),b===null?C=B:b.sibling=B,b=B,N=F}if(P.done)return n(p,N),ue&&Mn(p,_),C;if(N===null){for(;!P.done;_++,P=v.next())P=d(p,P.value,g),P!==null&&(f=a(P,f,_),b===null?C=P:b.sibling=P,b=P);return ue&&Mn(p,_),C}for(N=r(p,N);!P.done;_++,P=v.next())P=x(N,p,_,P.value,g),P!==null&&(e&&P.alternate!==null&&N.delete(P.key===null?_:P.key),f=a(P,f,_),b===null?C=P:b.sibling=P,b=P);return e&&N.forEach(function(D){return t(p,D)}),ue&&Mn(p,_),C}function S(p,f,v,g){if(typeof v=="object"&&v!==null&&v.type===dr&&v.key===null&&(v=v.props.children),typeof v=="object"&&v!==null){switch(v.$$typeof){case ha:e:{for(var C=v.key,b=f;b!==null;){if(b.key===C){if(C=v.type,C===dr){if(b.tag===7){n(p,b.sibling),f=s(b,v.props.children),f.return=p,p=f;break e}}else if(b.elementType===C||typeof C=="object"&&C!==null&&C.$$typeof===Zt&&Lc(C)===b.type){n(p,b.sibling),f=s(b,v.props),f.ref=cs(p,b,v),f.return=p,p=f;break e}n(p,b);break}else t(p,b);b=b.sibling}v.type===dr?(f=Gn(v.props.children,p.mode,g,v.key),f.return=p,p=f):(g=Qa(v.type,v.key,v.props,null,p.mode,g),g.ref=cs(p,f,v),g.return=p,p=g)}return l(p);case cr:e:{for(b=v.key;f!==null;){if(f.key===b)if(f.tag===4&&f.stateNode.containerInfo===v.containerInfo&&f.stateNode.implementation===v.implementation){n(p,f.sibling),f=s(f,v.children||[]),f.return=p,p=f;break e}else{n(p,f);break}else t(p,f);f=f.sibling}f=xl(v,p.mode,g),f.return=p,p=f}return l(p);case Zt:return b=v._init,S(p,f,b(v._payload),g)}if(ps(v))return w(p,f,v,g);if(as(v))return j(p,f,v,g);Na(p,v)}return typeof v=="string"&&v!==""||typeof v=="number"?(v=""+v,f!==null&&f.tag===6?(n(p,f.sibling),f=s(f,v),f.return=p,p=f):(n(p,f),f=vl(v,p.mode,g),f.return=p,p=f),l(p)):n(p,f)}return S}var Vr=ah(!0),ih=ah(!1),si=On(null),ai=null,gr=null,uu=null;function cu(){uu=gr=ai=null}function du(e){var t=si.current;oe(si),e._currentValue=t}function Xl(e,t,n){for(;e!==null;){var r=e.alternate;if((e.childLanes&t)!==t?(e.childLanes|=t,r!==null&&(r.childLanes|=t)):r!==null&&(r.childLanes&t)!==t&&(r.childLanes|=t),e===n)break;e=e.return}}function Cr(e,t){ai=e,uu=gr=null,e=e.dependencies,e!==null&&e.firstContext!==null&&(e.lanes&t&&(Ke=!0),e.firstContext=null)}function ut(e){var t=e._currentValue;if(uu!==e)if(e={context:e,memoizedValue:t,next:null},gr===null){if(ai===null)throw Error(E(308));gr=e,ai.dependencies={lanes:0,firstContext:e}}else gr=gr.next=e;return t}var In=null;function fu(e){In===null?In=[e]:In.push(e)}function lh(e,t,n,r){var s=t.interleaved;return s===null?(n.next=n,fu(t)):(n.next=s.next,s.next=n),t.interleaved=n,Ht(e,r)}function Ht(e,t){e.lanes|=t;var n=e.alternate;for(n!==null&&(n.lanes|=t),n=e,e=e.return;e!==null;)e.childLanes|=t,n=e.alternate,n!==null&&(n.childLanes|=t),n=e,e=e.return;return n.tag===3?n.stateNode:null}var en=!1;function hu(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,interleaved:null,lanes:0},effects:null}}function oh(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,effects:e.effects})}function Bt(e,t){return{eventTime:e,lane:t,tag:0,payload:null,callback:null,next:null}}function kn(e,t,n){var r=e.updateQueue;if(r===null)return null;if(r=r.shared,ee&2){var s=r.pending;return s===null?t.next=t:(t.next=s.next,s.next=t),r.pending=t,Ht(e,n)}return s=r.interleaved,s===null?(t.next=t,fu(r)):(t.next=s.next,s.next=t),r.interleaved=t,Ht(e,n)}function Ia(e,t,n){if(t=t.updateQueue,t!==null&&(t=t.shared,(n&4194240)!==0)){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,Xo(e,n)}}function Rc(e,t){var n=e.updateQueue,r=e.alternate;if(r!==null&&(r=r.updateQueue,n===r)){var s=null,a=null;if(n=n.firstBaseUpdate,n!==null){do{var l={eventTime:n.eventTime,lane:n.lane,tag:n.tag,payload:n.payload,callback:n.callback,next:null};a===null?s=a=l:a=a.next=l,n=n.next}while(n!==null);a===null?s=a=t:a=a.next=t}else s=a=t;n={baseState:r.baseState,firstBaseUpdate:s,lastBaseUpdate:a,shared:r.shared,effects:r.effects},e.updateQueue=n;return}e=n.lastBaseUpdate,e===null?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}function ii(e,t,n,r){var s=e.updateQueue;en=!1;var a=s.firstBaseUpdate,l=s.lastBaseUpdate,o=s.shared.pending;if(o!==null){s.shared.pending=null;var u=o,c=u.next;u.next=null,l===null?a=c:l.next=c,l=u;var h=e.alternate;h!==null&&(h=h.updateQueue,o=h.lastBaseUpdate,o!==l&&(o===null?h.firstBaseUpdate=c:o.next=c,h.lastBaseUpdate=u))}if(a!==null){var d=s.baseState;l=0,h=c=u=null,o=a;do{var m=o.lane,x=o.eventTime;if((r&m)===m){h!==null&&(h=h.next={eventTime:x,lane:0,tag:o.tag,payload:o.payload,callback:o.callback,next:null});e:{var w=e,j=o;switch(m=t,x=n,j.tag){case 1:if(w=j.payload,typeof w=="function"){d=w.call(x,d,m);break e}d=w;break e;case 3:w.flags=w.flags&-65537|128;case 0:if(w=j.payload,m=typeof w=="function"?w.call(x,d,m):w,m==null)break e;d=fe({},d,m);break e;case 2:en=!0}}o.callback!==null&&o.lane!==0&&(e.flags|=64,m=s.effects,m===null?s.effects=[o]:m.push(o))}else x={eventTime:x,lane:m,tag:o.tag,payload:o.payload,callback:o.callback,next:null},h===null?(c=h=x,u=d):h=h.next=x,l|=m;if(o=o.next,o===null){if(o=s.shared.pending,o===null)break;m=o,o=m.next,m.next=null,s.lastBaseUpdate=m,s.shared.pending=null}}while(!0);if(h===null&&(u=d),s.baseState=u,s.firstBaseUpdate=c,s.lastBaseUpdate=h,t=s.shared.interleaved,t!==null){s=t;do l|=s.lane,s=s.next;while(s!==t)}else a===null&&(s.shared.lanes=0);tr|=l,e.lanes=l,e.memoizedState=d}}function Mc(e,t,n){if(e=t.effects,t.effects=null,e!==null)for(t=0;tn?n:4,e(!0);var r=dl.transition;dl.transition={};try{e(!1),t()}finally{re=n,dl.transition=r}}function bh(){return ct().memoizedState}function Vv(e,t,n){var r=Nn(e);if(n={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null},Ch(e))_h(t,n);else if(n=lh(e,t,n,r),n!==null){var s=Ae();gt(n,e,r,s),Eh(n,t,r)}}function Kv(e,t,n){var r=Nn(e),s={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null};if(Ch(e))_h(t,s);else{var a=e.alternate;if(e.lanes===0&&(a===null||a.lanes===0)&&(a=t.lastRenderedReducer,a!==null))try{var l=t.lastRenderedState,o=a(l,n);if(s.hasEagerState=!0,s.eagerState=o,jt(o,l)){var u=t.interleaved;u===null?(s.next=s,fu(t)):(s.next=u.next,u.next=s),t.interleaved=s;return}}catch{}finally{}n=lh(e,t,s,r),n!==null&&(s=Ae(),gt(n,e,r,s),Eh(n,t,r))}}function Ch(e){var t=e.alternate;return e===de||t!==null&&t===de}function _h(e,t){Ns=oi=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function Eh(e,t,n){if(n&4194240){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,Xo(e,n)}}var ui={readContext:ut,useCallback:Oe,useContext:Oe,useEffect:Oe,useImperativeHandle:Oe,useInsertionEffect:Oe,useLayoutEffect:Oe,useMemo:Oe,useReducer:Oe,useRef:Oe,useState:Oe,useDebugValue:Oe,useDeferredValue:Oe,useTransition:Oe,useMutableSource:Oe,useSyncExternalStore:Oe,useId:Oe,unstable_isNewReconciler:!1},Hv={readContext:ut,useCallback:function(e,t){return St().memoizedState=[e,t===void 0?null:t],e},useContext:ut,useEffect:Fc,useImperativeHandle:function(e,t,n){return n=n!=null?n.concat([e]):null,Aa(4194308,4,jh.bind(null,t,e),n)},useLayoutEffect:function(e,t){return Aa(4194308,4,e,t)},useInsertionEffect:function(e,t){return Aa(4,2,e,t)},useMemo:function(e,t){var n=St();return t=t===void 0?null:t,e=e(),n.memoizedState=[e,t],e},useReducer:function(e,t,n){var r=St();return t=n!==void 0?n(t):t,r.memoizedState=r.baseState=t,e={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:t},r.queue=e,e=e.dispatch=Vv.bind(null,de,e),[r.memoizedState,e]},useRef:function(e){var t=St();return e={current:e},t.memoizedState=e},useState:zc,useDebugValue:wu,useDeferredValue:function(e){return St().memoizedState=e},useTransition:function(){var e=zc(!1),t=e[0];return e=Qv.bind(null,e[1]),St().memoizedState=e,[t,e]},useMutableSource:function(){},useSyncExternalStore:function(e,t,n){var r=de,s=St();if(ue){if(n===void 0)throw Error(E(407));n=n()}else{if(n=t(),_e===null)throw Error(E(349));er&30||fh(r,t,n)}s.memoizedState=n;var a={value:n,getSnapshot:t};return s.queue=a,Fc(mh.bind(null,r,a,e),[e]),r.flags|=2048,Vs(9,hh.bind(null,r,a,n,t),void 0,null),n},useId:function(){var e=St(),t=_e.identifierPrefix;if(ue){var n=Ut,r=$t;n=(r&~(1<<32-yt(r)-1)).toString(32)+n,t=":"+t+"R"+n,n=Bs++,0<\/script>",e=e.removeChild(e.firstChild)):typeof r.is=="string"?e=l.createElement(n,{is:r.is}):(e=l.createElement(n),n==="select"&&(l=e,r.multiple?l.multiple=!0:r.size&&(l.size=r.size))):e=l.createElementNS(e,n),e[_t]=t,e[As]=r,Dh(e,t,!1,!1),t.stateNode=e;e:{switch(l=Ml(n,r),n){case"dialog":le("cancel",e),le("close",e),s=r;break;case"iframe":case"object":case"embed":le("load",e),s=r;break;case"video":case"audio":for(s=0;sWr&&(t.flags|=128,r=!0,ds(a,!1),t.lanes=4194304)}else{if(!r)if(e=li(l),e!==null){if(t.flags|=128,r=!0,n=e.updateQueue,n!==null&&(t.updateQueue=n,t.flags|=4),ds(a,!0),a.tail===null&&a.tailMode==="hidden"&&!l.alternate&&!ue)return Le(t),null}else 2*ye()-a.renderingStartTime>Wr&&n!==1073741824&&(t.flags|=128,r=!0,ds(a,!1),t.lanes=4194304);a.isBackwards?(l.sibling=t.child,t.child=l):(n=a.last,n!==null?n.sibling=l:t.child=l,a.last=l)}return a.tail!==null?(t=a.tail,a.rendering=t,a.tail=t.sibling,a.renderingStartTime=ye(),t.sibling=null,n=ce.current,ae(ce,r?n&1|2:n&1),t):(Le(t),null);case 22:case 23:return _u(),r=t.memoizedState!==null,e!==null&&e.memoizedState!==null!==r&&(t.flags|=8192),r&&t.mode&1?Ye&1073741824&&(Le(t),t.subtreeFlags&6&&(t.flags|=8192)):Le(t),null;case 24:return null;case 25:return null}throw Error(E(156,t.tag))}function ex(e,t){switch(lu(t),t.tag){case 1:return We(t.type)&&ei(),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return Kr(),oe(He),oe(ze),vu(),e=t.flags,e&65536&&!(e&128)?(t.flags=e&-65537|128,t):null;case 5:return pu(t),null;case 13:if(oe(ce),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(E(340));Qr()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return oe(ce),null;case 4:return Kr(),null;case 10:return du(t.type._context),null;case 22:case 23:return _u(),null;case 24:return null;default:return null}}var Ca=!1,Me=!1,tx=typeof WeakSet=="function"?WeakSet:Set,I=null;function jr(e,t){var n=e.ref;if(n!==null)if(typeof n=="function")try{n(null)}catch(r){pe(e,t,r)}else n.current=null}function lo(e,t,n){try{n()}catch(r){pe(e,t,r)}}var Wc=!1;function nx(e,t){if(Vl=Ga,e=Kf(),au(e)){if("selectionStart"in e)var n={start:e.selectionStart,end:e.selectionEnd};else e:{n=(n=e.ownerDocument)&&n.defaultView||window;var r=n.getSelection&&n.getSelection();if(r&&r.rangeCount!==0){n=r.anchorNode;var s=r.anchorOffset,a=r.focusNode;r=r.focusOffset;try{n.nodeType,a.nodeType}catch{n=null;break e}var l=0,o=-1,u=-1,c=0,h=0,d=e,m=null;t:for(;;){for(var x;d!==n||s!==0&&d.nodeType!==3||(o=l+s),d!==a||r!==0&&d.nodeType!==3||(u=l+r),d.nodeType===3&&(l+=d.nodeValue.length),(x=d.firstChild)!==null;)m=d,d=x;for(;;){if(d===e)break t;if(m===n&&++c===s&&(o=l),m===a&&++h===r&&(u=l),(x=d.nextSibling)!==null)break;d=m,m=d.parentNode}d=x}n=o===-1||u===-1?null:{start:o,end:u}}else n=null}n=n||{start:0,end:0}}else n=null;for(Kl={focusedElem:e,selectionRange:n},Ga=!1,I=t;I!==null;)if(t=I,e=t.child,(t.subtreeFlags&1028)!==0&&e!==null)e.return=t,I=e;else for(;I!==null;){t=I;try{var w=t.alternate;if(t.flags&1024)switch(t.tag){case 0:case 11:case 15:break;case 1:if(w!==null){var j=w.memoizedProps,S=w.memoizedState,p=t.stateNode,f=p.getSnapshotBeforeUpdate(t.elementType===t.type?j:ht(t.type,j),S);p.__reactInternalSnapshotBeforeUpdate=f}break;case 3:var v=t.stateNode.containerInfo;v.nodeType===1?v.textContent="":v.nodeType===9&&v.documentElement&&v.removeChild(v.documentElement);break;case 5:case 6:case 4:case 17:break;default:throw Error(E(163))}}catch(g){pe(t,t.return,g)}if(e=t.sibling,e!==null){e.return=t.return,I=e;break}I=t.return}return w=Wc,Wc=!1,w}function bs(e,t,n){var r=t.updateQueue;if(r=r!==null?r.lastEffect:null,r!==null){var s=r=r.next;do{if((s.tag&e)===e){var a=s.destroy;s.destroy=void 0,a!==void 0&&lo(t,n,a)}s=s.next}while(s!==r)}}function Pi(e,t){if(t=t.updateQueue,t=t!==null?t.lastEffect:null,t!==null){var n=t=t.next;do{if((n.tag&e)===e){var r=n.create;n.destroy=r()}n=n.next}while(n!==t)}}function oo(e){var t=e.ref;if(t!==null){var n=e.stateNode;switch(e.tag){case 5:e=n;break;default:e=n}typeof t=="function"?t(e):t.current=e}}function Uh(e){var t=e.alternate;t!==null&&(e.alternate=null,Uh(t)),e.child=null,e.deletions=null,e.sibling=null,e.tag===5&&(t=e.stateNode,t!==null&&(delete t[_t],delete t[As],delete t[ql],delete t[Dv],delete t[Av])),e.stateNode=null,e.return=null,e.dependencies=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.stateNode=null,e.updateQueue=null}function Bh(e){return e.tag===5||e.tag===3||e.tag===4}function qc(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||Bh(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.flags&2||e.child===null||e.tag===4)continue e;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function uo(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.nodeType===8?n.parentNode.insertBefore(e,t):n.insertBefore(e,t):(n.nodeType===8?(t=n.parentNode,t.insertBefore(e,n)):(t=n,t.appendChild(e)),n=n._reactRootContainer,n!=null||t.onclick!==null||(t.onclick=Za));else if(r!==4&&(e=e.child,e!==null))for(uo(e,t,n),e=e.sibling;e!==null;)uo(e,t,n),e=e.sibling}function co(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(r!==4&&(e=e.child,e!==null))for(co(e,t,n),e=e.sibling;e!==null;)co(e,t,n),e=e.sibling}var Ee=null,vt=!1;function Yt(e,t,n){for(n=n.child;n!==null;)Qh(e,t,n),n=n.sibling}function Qh(e,t,n){if(Pt&&typeof Pt.onCommitFiberUnmount=="function")try{Pt.onCommitFiberUnmount(wi,n)}catch{}switch(n.tag){case 5:Me||jr(n,t);case 6:var r=Ee,s=vt;Ee=null,Yt(e,t,n),Ee=r,vt=s,Ee!==null&&(vt?(e=Ee,n=n.stateNode,e.nodeType===8?e.parentNode.removeChild(n):e.removeChild(n)):Ee.removeChild(n.stateNode));break;case 18:Ee!==null&&(vt?(e=Ee,n=n.stateNode,e.nodeType===8?ol(e.parentNode,n):e.nodeType===1&&ol(e,n),Ms(e)):ol(Ee,n.stateNode));break;case 4:r=Ee,s=vt,Ee=n.stateNode.containerInfo,vt=!0,Yt(e,t,n),Ee=r,vt=s;break;case 0:case 11:case 14:case 15:if(!Me&&(r=n.updateQueue,r!==null&&(r=r.lastEffect,r!==null))){s=r=r.next;do{var a=s,l=a.destroy;a=a.tag,l!==void 0&&(a&2||a&4)&&lo(n,t,l),s=s.next}while(s!==r)}Yt(e,t,n);break;case 1:if(!Me&&(jr(n,t),r=n.stateNode,typeof r.componentWillUnmount=="function"))try{r.props=n.memoizedProps,r.state=n.memoizedState,r.componentWillUnmount()}catch(o){pe(n,t,o)}Yt(e,t,n);break;case 21:Yt(e,t,n);break;case 22:n.mode&1?(Me=(r=Me)||n.memoizedState!==null,Yt(e,t,n),Me=r):Yt(e,t,n);break;default:Yt(e,t,n)}}function Jc(e){var t=e.updateQueue;if(t!==null){e.updateQueue=null;var n=e.stateNode;n===null&&(n=e.stateNode=new tx),t.forEach(function(r){var s=dx.bind(null,e,r);n.has(r)||(n.add(r),r.then(s,s))})}}function ft(e,t){var n=t.deletions;if(n!==null)for(var r=0;rs&&(s=l),r&=~a}if(r=s,r=ye()-r,r=(120>r?120:480>r?480:1080>r?1080:1920>r?1920:3e3>r?3e3:4320>r?4320:1960*sx(r/1960))-r,10e?16:e,mn===null)var r=!1;else{if(e=mn,mn=null,fi=0,ee&6)throw Error(E(331));var s=ee;for(ee|=4,I=e.current;I!==null;){var a=I,l=a.child;if(I.flags&16){var o=a.deletions;if(o!==null){for(var u=0;uye()-bu?Jn(e,0):Nu|=n),qe(e,t)}function Yh(e,t){t===0&&(e.mode&1?(t=xa,xa<<=1,!(xa&130023424)&&(xa=4194304)):t=1);var n=Ae();e=Ht(e,t),e!==null&&(aa(e,t,n),qe(e,n))}function cx(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),Yh(e,n)}function dx(e,t){var n=0;switch(e.tag){case 13:var r=e.stateNode,s=e.memoizedState;s!==null&&(n=s.retryLane);break;case 19:r=e.stateNode;break;default:throw Error(E(314))}r!==null&&r.delete(t),Yh(e,n)}var Xh;Xh=function(e,t,n){if(e!==null)if(e.memoizedProps!==t.pendingProps||He.current)Ke=!0;else{if(!(e.lanes&n)&&!(t.flags&128))return Ke=!1,Xv(e,t,n);Ke=!!(e.flags&131072)}else Ke=!1,ue&&t.flags&1048576&&nh(t,ri,t.index);switch(t.lanes=0,t.tag){case 2:var r=t.type;$a(e,t),e=t.pendingProps;var s=Br(t,ze.current);Cr(t,n),s=yu(null,t,r,e,s,n);var a=gu();return t.flags|=1,typeof s=="object"&&s!==null&&typeof s.render=="function"&&s.$$typeof===void 0?(t.tag=1,t.memoizedState=null,t.updateQueue=null,We(r)?(a=!0,ti(t)):a=!1,t.memoizedState=s.state!==null&&s.state!==void 0?s.state:null,hu(t),s.updater=Ei,t.stateNode=s,s._reactInternals=t,eo(t,r,e,n),t=ro(null,t,r,!0,a,n)):(t.tag=0,ue&&a&&iu(t),Ie(null,t,s,n),t=t.child),t;case 16:r=t.elementType;e:{switch($a(e,t),e=t.pendingProps,s=r._init,r=s(r._payload),t.type=r,s=t.tag=hx(r),e=ht(r,e),s){case 0:t=no(null,t,r,e,n);break e;case 1:t=Vc(null,t,r,e,n);break e;case 11:t=Bc(null,t,r,e,n);break e;case 14:t=Qc(null,t,r,ht(r.type,e),n);break e}throw Error(E(306,r,""))}return t;case 0:return r=t.type,s=t.pendingProps,s=t.elementType===r?s:ht(r,s),no(e,t,r,s,n);case 1:return r=t.type,s=t.pendingProps,s=t.elementType===r?s:ht(r,s),Vc(e,t,r,s,n);case 3:e:{if(zh(t),e===null)throw Error(E(387));r=t.pendingProps,a=t.memoizedState,s=a.element,oh(e,t),ii(t,r,null,n);var l=t.memoizedState;if(r=l.element,a.isDehydrated)if(a={element:r,isDehydrated:!1,cache:l.cache,pendingSuspenseBoundaries:l.pendingSuspenseBoundaries,transitions:l.transitions},t.updateQueue.baseState=a,t.memoizedState=a,t.flags&256){s=Hr(Error(E(423)),t),t=Kc(e,t,r,n,s);break e}else if(r!==s){s=Hr(Error(E(424)),t),t=Kc(e,t,r,n,s);break e}else for(Xe=wn(t.stateNode.containerInfo.firstChild),Ze=t,ue=!0,xt=null,n=ih(t,null,r,n),t.child=n;n;)n.flags=n.flags&-3|4096,n=n.sibling;else{if(Qr(),r===s){t=Wt(e,t,n);break e}Ie(e,t,r,n)}t=t.child}return t;case 5:return uh(t),e===null&&Yl(t),r=t.type,s=t.pendingProps,a=e!==null?e.memoizedProps:null,l=s.children,Hl(r,s)?l=null:a!==null&&Hl(r,a)&&(t.flags|=32),Mh(e,t),Ie(e,t,l,n),t.child;case 6:return e===null&&Yl(t),null;case 13:return Fh(e,t,n);case 4:return mu(t,t.stateNode.containerInfo),r=t.pendingProps,e===null?t.child=Vr(t,null,r,n):Ie(e,t,r,n),t.child;case 11:return r=t.type,s=t.pendingProps,s=t.elementType===r?s:ht(r,s),Bc(e,t,r,s,n);case 7:return Ie(e,t,t.pendingProps,n),t.child;case 8:return Ie(e,t,t.pendingProps.children,n),t.child;case 12:return Ie(e,t,t.pendingProps.children,n),t.child;case 10:e:{if(r=t.type._context,s=t.pendingProps,a=t.memoizedProps,l=s.value,ae(si,r._currentValue),r._currentValue=l,a!==null)if(jt(a.value,l)){if(a.children===s.children&&!He.current){t=Wt(e,t,n);break e}}else for(a=t.child,a!==null&&(a.return=t);a!==null;){var o=a.dependencies;if(o!==null){l=a.child;for(var u=o.firstContext;u!==null;){if(u.context===r){if(a.tag===1){u=Bt(-1,n&-n),u.tag=2;var c=a.updateQueue;if(c!==null){c=c.shared;var h=c.pending;h===null?u.next=u:(u.next=h.next,h.next=u),c.pending=u}}a.lanes|=n,u=a.alternate,u!==null&&(u.lanes|=n),Xl(a.return,n,t),o.lanes|=n;break}u=u.next}}else if(a.tag===10)l=a.type===t.type?null:a.child;else if(a.tag===18){if(l=a.return,l===null)throw Error(E(341));l.lanes|=n,o=l.alternate,o!==null&&(o.lanes|=n),Xl(l,n,t),l=a.sibling}else l=a.child;if(l!==null)l.return=a;else for(l=a;l!==null;){if(l===t){l=null;break}if(a=l.sibling,a!==null){a.return=l.return,l=a;break}l=l.return}a=l}Ie(e,t,s.children,n),t=t.child}return t;case 9:return s=t.type,r=t.pendingProps.children,Cr(t,n),s=ut(s),r=r(s),t.flags|=1,Ie(e,t,r,n),t.child;case 14:return r=t.type,s=ht(r,t.pendingProps),s=ht(r.type,s),Qc(e,t,r,s,n);case 15:return Lh(e,t,t.type,t.pendingProps,n);case 17:return r=t.type,s=t.pendingProps,s=t.elementType===r?s:ht(r,s),$a(e,t),t.tag=1,We(r)?(e=!0,ti(t)):e=!1,Cr(t,n),Ph(t,r,s),eo(t,r,s,n),ro(null,t,r,!0,e,n);case 19:return Ih(e,t,n);case 22:return Rh(e,t,n)}throw Error(E(156,t.tag))};function Zh(e,t){return Cf(e,t)}function fx(e,t,n,r){this.tag=e,this.key=n,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=t,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function lt(e,t,n,r){return new fx(e,t,n,r)}function Pu(e){return e=e.prototype,!(!e||!e.isReactComponent)}function hx(e){if(typeof e=="function")return Pu(e)?1:0;if(e!=null){if(e=e.$$typeof,e===qo)return 11;if(e===Jo)return 14}return 2}function bn(e,t){var n=e.alternate;return n===null?(n=lt(e.tag,t,e.key,e.mode),n.elementType=e.elementType,n.type=e.type,n.stateNode=e.stateNode,n.alternate=e,e.alternate=n):(n.pendingProps=t,n.type=e.type,n.flags=0,n.subtreeFlags=0,n.deletions=null),n.flags=e.flags&14680064,n.childLanes=e.childLanes,n.lanes=e.lanes,n.child=e.child,n.memoizedProps=e.memoizedProps,n.memoizedState=e.memoizedState,n.updateQueue=e.updateQueue,t=e.dependencies,n.dependencies=t===null?null:{lanes:t.lanes,firstContext:t.firstContext},n.sibling=e.sibling,n.index=e.index,n.ref=e.ref,n}function Qa(e,t,n,r,s,a){var l=2;if(r=e,typeof e=="function")Pu(e)&&(l=1);else if(typeof e=="string")l=5;else e:switch(e){case dr:return Gn(n.children,s,a,t);case Wo:l=8,s|=8;break;case Nl:return e=lt(12,n,t,s|2),e.elementType=Nl,e.lanes=a,e;case bl:return e=lt(13,n,t,s),e.elementType=bl,e.lanes=a,e;case Cl:return e=lt(19,n,t,s),e.elementType=Cl,e.lanes=a,e;case uf:return Oi(n,s,a,t);default:if(typeof e=="object"&&e!==null)switch(e.$$typeof){case lf:l=10;break e;case of:l=9;break e;case qo:l=11;break e;case Jo:l=14;break e;case Zt:l=16,r=null;break e}throw Error(E(130,e==null?e:typeof e,""))}return t=lt(l,n,t,s),t.elementType=e,t.type=r,t.lanes=a,t}function Gn(e,t,n,r){return e=lt(7,e,r,t),e.lanes=n,e}function Oi(e,t,n,r){return e=lt(22,e,r,t),e.elementType=uf,e.lanes=n,e.stateNode={isHidden:!1},e}function vl(e,t,n){return e=lt(6,e,null,t),e.lanes=n,e}function xl(e,t,n){return t=lt(4,e.children!==null?e.children:[],e.key,t),t.lanes=n,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}function mx(e,t,n,r,s){this.tag=t,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.pendingContext=this.context=null,this.callbackPriority=0,this.eventTimes=Yi(0),this.expirationTimes=Yi(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=Yi(0),this.identifierPrefix=r,this.onRecoverableError=s,this.mutableSourceEagerHydrationData=null}function Tu(e,t,n,r,s,a,l,o,u){return e=new mx(e,t,n,o,u),t===1?(t=1,a===!0&&(t|=8)):t=0,a=lt(3,null,null,t),e.current=a,a.stateNode=e,a.memoizedState={element:r,isDehydrated:n,cache:null,transitions:null,pendingSuspenseBoundaries:null},hu(a),e}function px(e,t,n){var r=3"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(rm)}catch(e){console.error(e)}}rm(),nf.exports=tt;var jx=nf.exports,rd=jx;kl.createRoot=rd.createRoot,kl.hydrateRoot=rd.hydrateRoot;var Zr=class{constructor(){this.listeners=new Set,this.subscribe=this.subscribe.bind(this)}subscribe(e){return this.listeners.add(e),this.onSubscribe(),()=>{this.listeners.delete(e),this.onUnsubscribe()}}hasListeners(){return this.listeners.size>0}onSubscribe(){}onUnsubscribe(){}},wx={setTimeout:(e,t)=>setTimeout(e,t),clearTimeout:e=>clearTimeout(e),setInterval:(e,t)=>setInterval(e,t),clearInterval:e=>clearInterval(e)},rn,Do,Rd,kx=(Rd=class{constructor(){$(this,rn,wx);$(this,Do,!1)}setTimeoutProvider(e){z(this,rn,e)}setTimeout(e,t){return y(this,rn).setTimeout(e,t)}clearTimeout(e){y(this,rn).clearTimeout(e)}setInterval(e,t){return y(this,rn).setInterval(e,t)}clearInterval(e){y(this,rn).clearInterval(e)}},rn=new WeakMap,Do=new WeakMap,Rd),An=new kx;function Sx(e){setTimeout(e,0)}var rr=typeof window>"u"||"Deno"in globalThis;function De(){}function Nx(e,t){return typeof e=="function"?e(t):e}function vo(e){return typeof e=="number"&&e>=0&&e!==1/0}function sm(e,t){return Math.max(e+(t||0)-Date.now(),0)}function Cn(e,t){return typeof e=="function"?e(t):e}function st(e,t){return typeof e=="function"?e(t):e}function sd(e,t){const{type:n="all",exact:r,fetchStatus:s,predicate:a,queryKey:l,stale:o}=e;if(l){if(r){if(t.queryHash!==Mu(l,t.options))return!1}else if(!Hs(t.queryKey,l))return!1}if(n!=="all"){const u=t.isActive();if(n==="active"&&!u||n==="inactive"&&u)return!1}return!(typeof o=="boolean"&&t.isStale()!==o||s&&s!==t.state.fetchStatus||a&&!a(t))}function ad(e,t){const{exact:n,status:r,predicate:s,mutationKey:a}=e;if(a){if(!t.options.mutationKey)return!1;if(n){if(sr(t.options.mutationKey)!==sr(a))return!1}else if(!Hs(t.options.mutationKey,a))return!1}return!(r&&t.state.status!==r||s&&!s(t))}function Mu(e,t){return((t==null?void 0:t.queryKeyHashFn)||sr)(e)}function sr(e){return JSON.stringify(e,(t,n)=>xo(n)?Object.keys(n).sort().reduce((r,s)=>(r[s]=n[s],r),{}):n)}function Hs(e,t){return e===t?!0:typeof e!=typeof t?!1:e&&t&&typeof e=="object"&&typeof t=="object"?Object.keys(t).every(n=>Hs(e[n],t[n])):!1}var bx=Object.prototype.hasOwnProperty;function am(e,t,n=0){if(e===t)return e;if(n>500)return t;const r=id(e)&&id(t);if(!r&&!(xo(e)&&xo(t)))return t;const a=(r?e:Object.keys(e)).length,l=r?t:Object.keys(t),o=l.length,u=r?new Array(o):{};let c=0;for(let h=0;h{An.setTimeout(t,e)})}function yo(e,t,n){return typeof n.structuralSharing=="function"?n.structuralSharing(e,t):n.structuralSharing!==!1?am(e,t):t}function _x(e,t,n=0){const r=[...e,t];return n&&r.length>n?r.slice(1):r}function Ex(e,t,n=0){const r=[t,...e];return n&&r.length>n?r.slice(0,-1):r}var zu=Symbol();function im(e,t){return!e.queryFn&&(t!=null&&t.initialPromise)?()=>t.initialPromise:!e.queryFn||e.queryFn===zu?()=>Promise.reject(new Error(`Missing queryFn: '${e.queryHash}'`)):e.queryFn}function Fu(e,t){return typeof e=="function"?e(...t):!!e}function Px(e,t,n){let r=!1,s;return Object.defineProperty(e,"signal",{enumerable:!0,get:()=>(s??(s=t()),r||(r=!0,s.aborted?n():s.addEventListener("abort",n,{once:!0})),s)}),e}var $n,sn,Pr,Md,Tx=(Md=class extends Zr{constructor(){super();$(this,$n);$(this,sn);$(this,Pr);z(this,Pr,t=>{if(!rr&&window.addEventListener){const n=()=>t();return window.addEventListener("visibilitychange",n,!1),()=>{window.removeEventListener("visibilitychange",n)}}})}onSubscribe(){y(this,sn)||this.setEventListener(y(this,Pr))}onUnsubscribe(){var t;this.hasListeners()||((t=y(this,sn))==null||t.call(this),z(this,sn,void 0))}setEventListener(t){var n;z(this,Pr,t),(n=y(this,sn))==null||n.call(this),z(this,sn,t(r=>{typeof r=="boolean"?this.setFocused(r):this.onFocus()}))}setFocused(t){y(this,$n)!==t&&(z(this,$n,t),this.onFocus())}onFocus(){const t=this.isFocused();this.listeners.forEach(n=>{n(t)})}isFocused(){var t;return typeof y(this,$n)=="boolean"?y(this,$n):((t=globalThis.document)==null?void 0:t.visibilityState)!=="hidden"}},$n=new WeakMap,sn=new WeakMap,Pr=new WeakMap,Md),Iu=new Tx;function go(){let e,t;const n=new Promise((s,a)=>{e=s,t=a});n.status="pending",n.catch(()=>{});function r(s){Object.assign(n,s),delete n.resolve,delete n.reject}return n.resolve=s=>{r({status:"fulfilled",value:s}),e(s)},n.reject=s=>{r({status:"rejected",reason:s}),t(s)},n}var Ox=Sx;function Lx(){let e=[],t=0,n=o=>{o()},r=o=>{o()},s=Ox;const a=o=>{t?e.push(o):s(()=>{n(o)})},l=()=>{const o=e;e=[],o.length&&s(()=>{r(()=>{o.forEach(u=>{n(u)})})})};return{batch:o=>{let u;t++;try{u=o()}finally{t--,t||l()}return u},batchCalls:o=>(...u)=>{a(()=>{o(...u)})},schedule:a,setNotifyFunction:o=>{n=o},setBatchNotifyFunction:o=>{r=o},setScheduler:o=>{s=o}}}var ke=Lx(),Tr,an,Or,zd,Rx=(zd=class extends Zr{constructor(){super();$(this,Tr,!0);$(this,an);$(this,Or);z(this,Or,t=>{if(!rr&&window.addEventListener){const n=()=>t(!0),r=()=>t(!1);return window.addEventListener("online",n,!1),window.addEventListener("offline",r,!1),()=>{window.removeEventListener("online",n),window.removeEventListener("offline",r)}}})}onSubscribe(){y(this,an)||this.setEventListener(y(this,Or))}onUnsubscribe(){var t;this.hasListeners()||((t=y(this,an))==null||t.call(this),z(this,an,void 0))}setEventListener(t){var n;z(this,Or,t),(n=y(this,an))==null||n.call(this),z(this,an,t(this.setOnline.bind(this)))}setOnline(t){y(this,Tr)!==t&&(z(this,Tr,t),this.listeners.forEach(r=>{r(t)}))}isOnline(){return y(this,Tr)}},Tr=new WeakMap,an=new WeakMap,Or=new WeakMap,zd),vi=new Rx;function Mx(e){return Math.min(1e3*2**e,3e4)}function lm(e){return(e??"online")==="online"?vi.isOnline():!0}var jo=class extends Error{constructor(e){super("CancelledError"),this.revert=e==null?void 0:e.revert,this.silent=e==null?void 0:e.silent}};function om(e){let t=!1,n=0,r;const s=go(),a=()=>s.status!=="pending",l=j=>{var S;if(!a()){const p=new jo(j);m(p),(S=e.onCancel)==null||S.call(e,p)}},o=()=>{t=!0},u=()=>{t=!1},c=()=>Iu.isFocused()&&(e.networkMode==="always"||vi.isOnline())&&e.canRun(),h=()=>lm(e.networkMode)&&e.canRun(),d=j=>{a()||(r==null||r(),s.resolve(j))},m=j=>{a()||(r==null||r(),s.reject(j))},x=()=>new Promise(j=>{var S;r=p=>{(a()||c())&&j(p)},(S=e.onPause)==null||S.call(e)}).then(()=>{var j;r=void 0,a()||(j=e.onContinue)==null||j.call(e)}),w=()=>{if(a())return;let j;const S=n===0?e.initialPromise:void 0;try{j=S??e.fn()}catch(p){j=Promise.reject(p)}Promise.resolve(j).then(d).catch(p=>{var b;if(a())return;const f=e.retry??(rr?0:3),v=e.retryDelay??Mx,g=typeof v=="function"?v(n,p):v,C=f===!0||typeof f=="number"&&nc()?void 0:x()).then(()=>{t?m(p):w()})})};return{promise:s,status:()=>s.status,cancel:l,continue:()=>(r==null||r(),s),cancelRetry:o,continueRetry:u,canStart:h,start:()=>(h()?w():x().then(w),s)}}var Un,Fd,um=(Fd=class{constructor(){$(this,Un)}destroy(){this.clearGcTimeout()}scheduleGc(){this.clearGcTimeout(),vo(this.gcTime)&&z(this,Un,An.setTimeout(()=>{this.optionalRemove()},this.gcTime))}updateGcTime(e){this.gcTime=Math.max(this.gcTime||0,e??(rr?1/0:5*60*1e3))}clearGcTimeout(){y(this,Un)&&(An.clearTimeout(y(this,Un)),z(this,Un,void 0))}},Un=new WeakMap,Fd),Bn,Lr,rt,Qn,be,Zs,Vn,mt,Rt,Id,zx=(Id=class extends um{constructor(t){super();$(this,mt);$(this,Bn);$(this,Lr);$(this,rt);$(this,Qn);$(this,be);$(this,Zs);$(this,Vn);z(this,Vn,!1),z(this,Zs,t.defaultOptions),this.setOptions(t.options),this.observers=[],z(this,Qn,t.client),z(this,rt,y(this,Qn).getQueryCache()),this.queryKey=t.queryKey,this.queryHash=t.queryHash,z(this,Bn,ud(this.options)),this.state=t.state??y(this,Bn),this.scheduleGc()}get meta(){return this.options.meta}get promise(){var t;return(t=y(this,be))==null?void 0:t.promise}setOptions(t){if(this.options={...y(this,Zs),...t},this.updateGcTime(this.options.gcTime),this.state&&this.state.data===void 0){const n=ud(this.options);n.data!==void 0&&(this.setState(od(n.data,n.dataUpdatedAt)),z(this,Bn,n))}}optionalRemove(){!this.observers.length&&this.state.fetchStatus==="idle"&&y(this,rt).remove(this)}setData(t,n){const r=yo(this.state.data,t,this.options);return W(this,mt,Rt).call(this,{data:r,type:"success",dataUpdatedAt:n==null?void 0:n.updatedAt,manual:n==null?void 0:n.manual}),r}setState(t,n){W(this,mt,Rt).call(this,{type:"setState",state:t,setStateOptions:n})}cancel(t){var r,s;const n=(r=y(this,be))==null?void 0:r.promise;return(s=y(this,be))==null||s.cancel(t),n?n.then(De).catch(De):Promise.resolve()}destroy(){super.destroy(),this.cancel({silent:!0})}reset(){this.destroy(),this.setState(y(this,Bn))}isActive(){return this.observers.some(t=>st(t.options.enabled,this)!==!1)}isDisabled(){return this.getObserversCount()>0?!this.isActive():this.options.queryFn===zu||this.state.dataUpdateCount+this.state.errorUpdateCount===0}isStatic(){return this.getObserversCount()>0?this.observers.some(t=>Cn(t.options.staleTime,this)==="static"):!1}isStale(){return this.getObserversCount()>0?this.observers.some(t=>t.getCurrentResult().isStale):this.state.data===void 0||this.state.isInvalidated}isStaleByTime(t=0){return this.state.data===void 0?!0:t==="static"?!1:this.state.isInvalidated?!0:!sm(this.state.dataUpdatedAt,t)}onFocus(){var n;const t=this.observers.find(r=>r.shouldFetchOnWindowFocus());t==null||t.refetch({cancelRefetch:!1}),(n=y(this,be))==null||n.continue()}onOnline(){var n;const t=this.observers.find(r=>r.shouldFetchOnReconnect());t==null||t.refetch({cancelRefetch:!1}),(n=y(this,be))==null||n.continue()}addObserver(t){this.observers.includes(t)||(this.observers.push(t),this.clearGcTimeout(),y(this,rt).notify({type:"observerAdded",query:this,observer:t}))}removeObserver(t){this.observers.includes(t)&&(this.observers=this.observers.filter(n=>n!==t),this.observers.length||(y(this,be)&&(y(this,Vn)?y(this,be).cancel({revert:!0}):y(this,be).cancelRetry()),this.scheduleGc()),y(this,rt).notify({type:"observerRemoved",query:this,observer:t}))}getObserversCount(){return this.observers.length}invalidate(){this.state.isInvalidated||W(this,mt,Rt).call(this,{type:"invalidate"})}async fetch(t,n){var u,c,h,d,m,x,w,j,S,p,f,v;if(this.state.fetchStatus!=="idle"&&((u=y(this,be))==null?void 0:u.status())!=="rejected"){if(this.state.data!==void 0&&(n!=null&&n.cancelRefetch))this.cancel({silent:!0});else if(y(this,be))return y(this,be).continueRetry(),y(this,be).promise}if(t&&this.setOptions(t),!this.options.queryFn){const g=this.observers.find(C=>C.options.queryFn);g&&this.setOptions(g.options)}const r=new AbortController,s=g=>{Object.defineProperty(g,"signal",{enumerable:!0,get:()=>(z(this,Vn,!0),r.signal)})},a=()=>{const g=im(this.options,n),b=(()=>{const N={client:y(this,Qn),queryKey:this.queryKey,meta:this.meta};return s(N),N})();return z(this,Vn,!1),this.options.persister?this.options.persister(g,b,this):g(b)},o=(()=>{const g={fetchOptions:n,options:this.options,queryKey:this.queryKey,client:y(this,Qn),state:this.state,fetchFn:a};return s(g),g})();(c=this.options.behavior)==null||c.onFetch(o,this),z(this,Lr,this.state),(this.state.fetchStatus==="idle"||this.state.fetchMeta!==((h=o.fetchOptions)==null?void 0:h.meta))&&W(this,mt,Rt).call(this,{type:"fetch",meta:(d=o.fetchOptions)==null?void 0:d.meta}),z(this,be,om({initialPromise:n==null?void 0:n.initialPromise,fn:o.fetchFn,onCancel:g=>{g instanceof jo&&g.revert&&this.setState({...y(this,Lr),fetchStatus:"idle"}),r.abort()},onFail:(g,C)=>{W(this,mt,Rt).call(this,{type:"failed",failureCount:g,error:C})},onPause:()=>{W(this,mt,Rt).call(this,{type:"pause"})},onContinue:()=>{W(this,mt,Rt).call(this,{type:"continue"})},retry:o.options.retry,retryDelay:o.options.retryDelay,networkMode:o.options.networkMode,canRun:()=>!0}));try{const g=await y(this,be).start();if(g===void 0)throw new Error(`${this.queryHash} data is undefined`);return this.setData(g),(x=(m=y(this,rt).config).onSuccess)==null||x.call(m,g,this),(j=(w=y(this,rt).config).onSettled)==null||j.call(w,g,this.state.error,this),g}catch(g){if(g instanceof jo){if(g.silent)return y(this,be).promise;if(g.revert){if(this.state.data===void 0)throw g;return this.state.data}}throw W(this,mt,Rt).call(this,{type:"error",error:g}),(p=(S=y(this,rt).config).onError)==null||p.call(S,g,this),(v=(f=y(this,rt).config).onSettled)==null||v.call(f,this.state.data,g,this),g}finally{this.scheduleGc()}}},Bn=new WeakMap,Lr=new WeakMap,rt=new WeakMap,Qn=new WeakMap,be=new WeakMap,Zs=new WeakMap,Vn=new WeakMap,mt=new WeakSet,Rt=function(t){const n=r=>{switch(t.type){case"failed":return{...r,fetchFailureCount:t.failureCount,fetchFailureReason:t.error};case"pause":return{...r,fetchStatus:"paused"};case"continue":return{...r,fetchStatus:"fetching"};case"fetch":return{...r,...cm(r.data,this.options),fetchMeta:t.meta??null};case"success":const s={...r,...od(t.data,t.dataUpdatedAt),dataUpdateCount:r.dataUpdateCount+1,...!t.manual&&{fetchStatus:"idle",fetchFailureCount:0,fetchFailureReason:null}};return z(this,Lr,t.manual?s:void 0),s;case"error":const a=t.error;return{...r,error:a,errorUpdateCount:r.errorUpdateCount+1,errorUpdatedAt:Date.now(),fetchFailureCount:r.fetchFailureCount+1,fetchFailureReason:a,fetchStatus:"idle",status:"error",isInvalidated:!0};case"invalidate":return{...r,isInvalidated:!0};case"setState":return{...r,...t.state}}};this.state=n(this.state),ke.batch(()=>{this.observers.forEach(r=>{r.onQueryUpdate()}),y(this,rt).notify({query:this,type:"updated",action:t})})},Id);function cm(e,t){return{fetchFailureCount:0,fetchFailureReason:null,fetchStatus:lm(t.networkMode)?"fetching":"paused",...e===void 0&&{error:null,status:"pending"}}}function od(e,t){return{data:e,dataUpdatedAt:t??Date.now(),error:null,isInvalidated:!1,status:"success"}}function ud(e){const t=typeof e.initialData=="function"?e.initialData():e.initialData,n=t!==void 0,r=n?typeof e.initialDataUpdatedAt=="function"?e.initialDataUpdatedAt():e.initialDataUpdatedAt:0;return{data:t,dataUpdateCount:0,dataUpdatedAt:n?r??Date.now():0,error:null,errorUpdateCount:0,errorUpdatedAt:0,fetchFailureCount:0,fetchFailureReason:null,fetchMeta:null,isInvalidated:!1,status:n?"success":"pending",fetchStatus:"idle"}}var Be,G,ea,Fe,Kn,Rr,Ft,ln,ta,Mr,zr,Hn,Wn,on,Fr,te,ys,wo,ko,So,No,bo,Co,_o,dm,Dd,Fx=(Dd=class extends Zr{constructor(t,n){super();$(this,te);$(this,Be);$(this,G);$(this,ea);$(this,Fe);$(this,Kn);$(this,Rr);$(this,Ft);$(this,ln);$(this,ta);$(this,Mr);$(this,zr);$(this,Hn);$(this,Wn);$(this,on);$(this,Fr,new Set);this.options=n,z(this,Be,t),z(this,ln,null),z(this,Ft,go()),this.bindMethods(),this.setOptions(n)}bindMethods(){this.refetch=this.refetch.bind(this)}onSubscribe(){this.listeners.size===1&&(y(this,G).addObserver(this),cd(y(this,G),this.options)?W(this,te,ys).call(this):this.updateResult(),W(this,te,No).call(this))}onUnsubscribe(){this.hasListeners()||this.destroy()}shouldFetchOnReconnect(){return Eo(y(this,G),this.options,this.options.refetchOnReconnect)}shouldFetchOnWindowFocus(){return Eo(y(this,G),this.options,this.options.refetchOnWindowFocus)}destroy(){this.listeners=new Set,W(this,te,bo).call(this),W(this,te,Co).call(this),y(this,G).removeObserver(this)}setOptions(t){const n=this.options,r=y(this,G);if(this.options=y(this,Be).defaultQueryOptions(t),this.options.enabled!==void 0&&typeof this.options.enabled!="boolean"&&typeof this.options.enabled!="function"&&typeof st(this.options.enabled,y(this,G))!="boolean")throw new Error("Expected enabled to be a boolean or a callback that returns a boolean");W(this,te,_o).call(this),y(this,G).setOptions(this.options),n._defaulted&&!pi(this.options,n)&&y(this,Be).getQueryCache().notify({type:"observerOptionsUpdated",query:y(this,G),observer:this});const s=this.hasListeners();s&&dd(y(this,G),r,this.options,n)&&W(this,te,ys).call(this),this.updateResult(),s&&(y(this,G)!==r||st(this.options.enabled,y(this,G))!==st(n.enabled,y(this,G))||Cn(this.options.staleTime,y(this,G))!==Cn(n.staleTime,y(this,G)))&&W(this,te,wo).call(this);const a=W(this,te,ko).call(this);s&&(y(this,G)!==r||st(this.options.enabled,y(this,G))!==st(n.enabled,y(this,G))||a!==y(this,on))&&W(this,te,So).call(this,a)}getOptimisticResult(t){const n=y(this,Be).getQueryCache().build(y(this,Be),t),r=this.createResult(n,t);return Dx(this,r)&&(z(this,Fe,r),z(this,Rr,this.options),z(this,Kn,y(this,G).state)),r}getCurrentResult(){return y(this,Fe)}trackResult(t,n){return new Proxy(t,{get:(r,s)=>(this.trackProp(s),n==null||n(s),s==="promise"&&(this.trackProp("data"),!this.options.experimental_prefetchInRender&&y(this,Ft).status==="pending"&&y(this,Ft).reject(new Error("experimental_prefetchInRender feature flag is not enabled"))),Reflect.get(r,s))})}trackProp(t){y(this,Fr).add(t)}getCurrentQuery(){return y(this,G)}refetch({...t}={}){return this.fetch({...t})}fetchOptimistic(t){const n=y(this,Be).defaultQueryOptions(t),r=y(this,Be).getQueryCache().build(y(this,Be),n);return r.fetch().then(()=>this.createResult(r,n))}fetch(t){return W(this,te,ys).call(this,{...t,cancelRefetch:t.cancelRefetch??!0}).then(()=>(this.updateResult(),y(this,Fe)))}createResult(t,n){var F;const r=y(this,G),s=this.options,a=y(this,Fe),l=y(this,Kn),o=y(this,Rr),c=t!==r?t.state:y(this,ea),{state:h}=t;let d={...h},m=!1,x;if(n._optimisticResults){const P=this.hasListeners(),B=!P&&cd(t,n),D=P&&dd(t,r,n,s);(B||D)&&(d={...d,...cm(h.data,t.options)}),n._optimisticResults==="isRestoring"&&(d.fetchStatus="idle")}let{error:w,errorUpdatedAt:j,status:S}=d;x=d.data;let p=!1;if(n.placeholderData!==void 0&&x===void 0&&S==="pending"){let P;a!=null&&a.isPlaceholderData&&n.placeholderData===(o==null?void 0:o.placeholderData)?(P=a.data,p=!0):P=typeof n.placeholderData=="function"?n.placeholderData((F=y(this,zr))==null?void 0:F.state.data,y(this,zr)):n.placeholderData,P!==void 0&&(S="success",x=yo(a==null?void 0:a.data,P,n),m=!0)}if(n.select&&x!==void 0&&!p)if(a&&x===(l==null?void 0:l.data)&&n.select===y(this,ta))x=y(this,Mr);else try{z(this,ta,n.select),x=n.select(x),x=yo(a==null?void 0:a.data,x,n),z(this,Mr,x),z(this,ln,null)}catch(P){z(this,ln,P)}y(this,ln)&&(w=y(this,ln),x=y(this,Mr),j=Date.now(),S="error");const f=d.fetchStatus==="fetching",v=S==="pending",g=S==="error",C=v&&f,b=x!==void 0,_={status:S,fetchStatus:d.fetchStatus,isPending:v,isSuccess:S==="success",isError:g,isInitialLoading:C,isLoading:C,data:x,dataUpdatedAt:d.dataUpdatedAt,error:w,errorUpdatedAt:j,failureCount:d.fetchFailureCount,failureReason:d.fetchFailureReason,errorUpdateCount:d.errorUpdateCount,isFetched:d.dataUpdateCount>0||d.errorUpdateCount>0,isFetchedAfterMount:d.dataUpdateCount>c.dataUpdateCount||d.errorUpdateCount>c.errorUpdateCount,isFetching:f,isRefetching:f&&!v,isLoadingError:g&&!b,isPaused:d.fetchStatus==="paused",isPlaceholderData:m,isRefetchError:g&&b,isStale:Du(t,n),refetch:this.refetch,promise:y(this,Ft),isEnabled:st(n.enabled,t)!==!1};if(this.options.experimental_prefetchInRender){const P=_.data!==void 0,B=_.status==="error"&&!P,D=je=>{B?je.reject(_.error):P&&je.resolve(_.data)},U=()=>{const je=z(this,Ft,_.promise=go());D(je)},ne=y(this,Ft);switch(ne.status){case"pending":t.queryHash===r.queryHash&&D(ne);break;case"fulfilled":(B||_.data!==ne.value)&&U();break;case"rejected":(!B||_.error!==ne.reason)&&U();break}}return _}updateResult(){const t=y(this,Fe),n=this.createResult(y(this,G),this.options);if(z(this,Kn,y(this,G).state),z(this,Rr,this.options),y(this,Kn).data!==void 0&&z(this,zr,y(this,G)),pi(n,t))return;z(this,Fe,n);const r=()=>{if(!t)return!0;const{notifyOnChangeProps:s}=this.options,a=typeof s=="function"?s():s;if(a==="all"||!a&&!y(this,Fr).size)return!0;const l=new Set(a??y(this,Fr));return this.options.throwOnError&&l.add("error"),Object.keys(y(this,Fe)).some(o=>{const u=o;return y(this,Fe)[u]!==t[u]&&l.has(u)})};W(this,te,dm).call(this,{listeners:r()})}onQueryUpdate(){this.updateResult(),this.hasListeners()&&W(this,te,No).call(this)}},Be=new WeakMap,G=new WeakMap,ea=new WeakMap,Fe=new WeakMap,Kn=new WeakMap,Rr=new WeakMap,Ft=new WeakMap,ln=new WeakMap,ta=new WeakMap,Mr=new WeakMap,zr=new WeakMap,Hn=new WeakMap,Wn=new WeakMap,on=new WeakMap,Fr=new WeakMap,te=new WeakSet,ys=function(t){W(this,te,_o).call(this);let n=y(this,G).fetch(this.options,t);return t!=null&&t.throwOnError||(n=n.catch(De)),n},wo=function(){W(this,te,bo).call(this);const t=Cn(this.options.staleTime,y(this,G));if(rr||y(this,Fe).isStale||!vo(t))return;const r=sm(y(this,Fe).dataUpdatedAt,t)+1;z(this,Hn,An.setTimeout(()=>{y(this,Fe).isStale||this.updateResult()},r))},ko=function(){return(typeof this.options.refetchInterval=="function"?this.options.refetchInterval(y(this,G)):this.options.refetchInterval)??!1},So=function(t){W(this,te,Co).call(this),z(this,on,t),!(rr||st(this.options.enabled,y(this,G))===!1||!vo(y(this,on))||y(this,on)===0)&&z(this,Wn,An.setInterval(()=>{(this.options.refetchIntervalInBackground||Iu.isFocused())&&W(this,te,ys).call(this)},y(this,on)))},No=function(){W(this,te,wo).call(this),W(this,te,So).call(this,W(this,te,ko).call(this))},bo=function(){y(this,Hn)&&(An.clearTimeout(y(this,Hn)),z(this,Hn,void 0))},Co=function(){y(this,Wn)&&(An.clearInterval(y(this,Wn)),z(this,Wn,void 0))},_o=function(){const t=y(this,Be).getQueryCache().build(y(this,Be),this.options);if(t===y(this,G))return;const n=y(this,G);z(this,G,t),z(this,ea,t.state),this.hasListeners()&&(n==null||n.removeObserver(this),t.addObserver(this))},dm=function(t){ke.batch(()=>{t.listeners&&this.listeners.forEach(n=>{n(y(this,Fe))}),y(this,Be).getQueryCache().notify({query:y(this,G),type:"observerResultsUpdated"})})},Dd);function Ix(e,t){return st(t.enabled,e)!==!1&&e.state.data===void 0&&!(e.state.status==="error"&&t.retryOnMount===!1)}function cd(e,t){return Ix(e,t)||e.state.data!==void 0&&Eo(e,t,t.refetchOnMount)}function Eo(e,t,n){if(st(t.enabled,e)!==!1&&Cn(t.staleTime,e)!=="static"){const r=typeof n=="function"?n(e):n;return r==="always"||r!==!1&&Du(e,t)}return!1}function dd(e,t,n,r){return(e!==t||st(r.enabled,e)===!1)&&(!n.suspense||e.state.status!=="error")&&Du(e,n)}function Du(e,t){return st(t.enabled,e)!==!1&&e.isStaleByTime(Cn(t.staleTime,e))}function Dx(e,t){return!pi(e.getCurrentResult(),t)}function fd(e){return{onFetch:(t,n)=>{var h,d,m,x,w;const r=t.options,s=(m=(d=(h=t.fetchOptions)==null?void 0:h.meta)==null?void 0:d.fetchMore)==null?void 0:m.direction,a=((x=t.state.data)==null?void 0:x.pages)||[],l=((w=t.state.data)==null?void 0:w.pageParams)||[];let o={pages:[],pageParams:[]},u=0;const c=async()=>{let j=!1;const S=v=>{Px(v,()=>t.signal,()=>j=!0)},p=im(t.options,t.fetchOptions),f=async(v,g,C)=>{if(j)return Promise.reject();if(g==null&&v.pages.length)return Promise.resolve(v);const N=(()=>{const B={client:t.client,queryKey:t.queryKey,pageParam:g,direction:C?"backward":"forward",meta:t.options.meta};return S(B),B})(),_=await p(N),{maxPages:F}=t.options,P=C?Ex:_x;return{pages:P(v.pages,_,F),pageParams:P(v.pageParams,g,F)}};if(s&&a.length){const v=s==="backward",g=v?Ax:hd,C={pages:a,pageParams:l},b=g(r,C);o=await f(C,b,v)}else{const v=e??a.length;do{const g=u===0?l[0]??r.initialPageParam:hd(r,o);if(u>0&&g==null)break;o=await f(o,g),u++}while(u{var j,S;return(S=(j=t.options).persister)==null?void 0:S.call(j,c,{client:t.client,queryKey:t.queryKey,meta:t.options.meta,signal:t.signal},n)}:t.fetchFn=c}}}function hd(e,{pages:t,pageParams:n}){const r=t.length-1;return t.length>0?e.getNextPageParam(t[r],t,n[r],n):void 0}function Ax(e,{pages:t,pageParams:n}){var r;return t.length>0?(r=e.getPreviousPageParam)==null?void 0:r.call(e,t[0],t,n[0],n):void 0}var na,Nt,Re,qn,bt,Xt,Ad,$x=(Ad=class extends um{constructor(t){super();$(this,bt);$(this,na);$(this,Nt);$(this,Re);$(this,qn);z(this,na,t.client),this.mutationId=t.mutationId,z(this,Re,t.mutationCache),z(this,Nt,[]),this.state=t.state||fm(),this.setOptions(t.options),this.scheduleGc()}setOptions(t){this.options=t,this.updateGcTime(this.options.gcTime)}get meta(){return this.options.meta}addObserver(t){y(this,Nt).includes(t)||(y(this,Nt).push(t),this.clearGcTimeout(),y(this,Re).notify({type:"observerAdded",mutation:this,observer:t}))}removeObserver(t){z(this,Nt,y(this,Nt).filter(n=>n!==t)),this.scheduleGc(),y(this,Re).notify({type:"observerRemoved",mutation:this,observer:t})}optionalRemove(){y(this,Nt).length||(this.state.status==="pending"?this.scheduleGc():y(this,Re).remove(this))}continue(){var t;return((t=y(this,qn))==null?void 0:t.continue())??this.execute(this.state.variables)}async execute(t){var l,o,u,c,h,d,m,x,w,j,S,p,f,v,g,C,b,N;const n=()=>{W(this,bt,Xt).call(this,{type:"continue"})},r={client:y(this,na),meta:this.options.meta,mutationKey:this.options.mutationKey};z(this,qn,om({fn:()=>this.options.mutationFn?this.options.mutationFn(t,r):Promise.reject(new Error("No mutationFn found")),onFail:(_,F)=>{W(this,bt,Xt).call(this,{type:"failed",failureCount:_,error:F})},onPause:()=>{W(this,bt,Xt).call(this,{type:"pause"})},onContinue:n,retry:this.options.retry??0,retryDelay:this.options.retryDelay,networkMode:this.options.networkMode,canRun:()=>y(this,Re).canRun(this)}));const s=this.state.status==="pending",a=!y(this,qn).canStart();try{if(s)n();else{W(this,bt,Xt).call(this,{type:"pending",variables:t,isPaused:a}),y(this,Re).config.onMutate&&await y(this,Re).config.onMutate(t,this,r);const F=await((o=(l=this.options).onMutate)==null?void 0:o.call(l,t,r));F!==this.state.context&&W(this,bt,Xt).call(this,{type:"pending",context:F,variables:t,isPaused:a})}const _=await y(this,qn).start();return await((c=(u=y(this,Re).config).onSuccess)==null?void 0:c.call(u,_,t,this.state.context,this,r)),await((d=(h=this.options).onSuccess)==null?void 0:d.call(h,_,t,this.state.context,r)),await((x=(m=y(this,Re).config).onSettled)==null?void 0:x.call(m,_,null,this.state.variables,this.state.context,this,r)),await((j=(w=this.options).onSettled)==null?void 0:j.call(w,_,null,t,this.state.context,r)),W(this,bt,Xt).call(this,{type:"success",data:_}),_}catch(_){try{await((p=(S=y(this,Re).config).onError)==null?void 0:p.call(S,_,t,this.state.context,this,r))}catch(F){Promise.reject(F)}try{await((v=(f=this.options).onError)==null?void 0:v.call(f,_,t,this.state.context,r))}catch(F){Promise.reject(F)}try{await((C=(g=y(this,Re).config).onSettled)==null?void 0:C.call(g,void 0,_,this.state.variables,this.state.context,this,r))}catch(F){Promise.reject(F)}try{await((N=(b=this.options).onSettled)==null?void 0:N.call(b,void 0,_,t,this.state.context,r))}catch(F){Promise.reject(F)}throw W(this,bt,Xt).call(this,{type:"error",error:_}),_}finally{y(this,Re).runNext(this)}}},na=new WeakMap,Nt=new WeakMap,Re=new WeakMap,qn=new WeakMap,bt=new WeakSet,Xt=function(t){const n=r=>{switch(t.type){case"failed":return{...r,failureCount:t.failureCount,failureReason:t.error};case"pause":return{...r,isPaused:!0};case"continue":return{...r,isPaused:!1};case"pending":return{...r,context:t.context,data:void 0,failureCount:0,failureReason:null,error:null,isPaused:t.isPaused,status:"pending",variables:t.variables,submittedAt:Date.now()};case"success":return{...r,data:t.data,failureCount:0,failureReason:null,error:null,status:"success",isPaused:!1};case"error":return{...r,data:void 0,error:t.error,failureCount:r.failureCount+1,failureReason:t.error,isPaused:!1,status:"error"}}};this.state=n(this.state),ke.batch(()=>{y(this,Nt).forEach(r=>{r.onMutationUpdate(t)}),y(this,Re).notify({mutation:this,type:"updated",action:t})})},Ad);function fm(){return{context:void 0,data:void 0,error:null,failureCount:0,failureReason:null,isPaused:!1,status:"idle",variables:void 0,submittedAt:0}}var It,pt,ra,$d,Ux=($d=class extends Zr{constructor(t={}){super();$(this,It);$(this,pt);$(this,ra);this.config=t,z(this,It,new Set),z(this,pt,new Map),z(this,ra,0)}build(t,n,r){const s=new $x({client:t,mutationCache:this,mutationId:++da(this,ra)._,options:t.defaultMutationOptions(n),state:r});return this.add(s),s}add(t){y(this,It).add(t);const n=Pa(t);if(typeof n=="string"){const r=y(this,pt).get(n);r?r.push(t):y(this,pt).set(n,[t])}this.notify({type:"added",mutation:t})}remove(t){if(y(this,It).delete(t)){const n=Pa(t);if(typeof n=="string"){const r=y(this,pt).get(n);if(r)if(r.length>1){const s=r.indexOf(t);s!==-1&&r.splice(s,1)}else r[0]===t&&y(this,pt).delete(n)}}this.notify({type:"removed",mutation:t})}canRun(t){const n=Pa(t);if(typeof n=="string"){const r=y(this,pt).get(n),s=r==null?void 0:r.find(a=>a.state.status==="pending");return!s||s===t}else return!0}runNext(t){var r;const n=Pa(t);if(typeof n=="string"){const s=(r=y(this,pt).get(n))==null?void 0:r.find(a=>a!==t&&a.state.isPaused);return(s==null?void 0:s.continue())??Promise.resolve()}else return Promise.resolve()}clear(){ke.batch(()=>{y(this,It).forEach(t=>{this.notify({type:"removed",mutation:t})}),y(this,It).clear(),y(this,pt).clear()})}getAll(){return Array.from(y(this,It))}find(t){const n={exact:!0,...t};return this.getAll().find(r=>ad(n,r))}findAll(t={}){return this.getAll().filter(n=>ad(t,n))}notify(t){ke.batch(()=>{this.listeners.forEach(n=>{n(t)})})}resumePausedMutations(){const t=this.getAll().filter(n=>n.state.isPaused);return ke.batch(()=>Promise.all(t.map(n=>n.continue().catch(De))))}},It=new WeakMap,pt=new WeakMap,ra=new WeakMap,$d);function Pa(e){var t;return(t=e.options.scope)==null?void 0:t.id}var Dt,un,Qe,At,Qt,Va,Po,Ud,Bx=(Ud=class extends Zr{constructor(n,r){super();$(this,Qt);$(this,Dt);$(this,un);$(this,Qe);$(this,At);z(this,Dt,n),this.setOptions(r),this.bindMethods(),W(this,Qt,Va).call(this)}bindMethods(){this.mutate=this.mutate.bind(this),this.reset=this.reset.bind(this)}setOptions(n){var s;const r=this.options;this.options=y(this,Dt).defaultMutationOptions(n),pi(this.options,r)||y(this,Dt).getMutationCache().notify({type:"observerOptionsUpdated",mutation:y(this,Qe),observer:this}),r!=null&&r.mutationKey&&this.options.mutationKey&&sr(r.mutationKey)!==sr(this.options.mutationKey)?this.reset():((s=y(this,Qe))==null?void 0:s.state.status)==="pending"&&y(this,Qe).setOptions(this.options)}onUnsubscribe(){var n;this.hasListeners()||(n=y(this,Qe))==null||n.removeObserver(this)}onMutationUpdate(n){W(this,Qt,Va).call(this),W(this,Qt,Po).call(this,n)}getCurrentResult(){return y(this,un)}reset(){var n;(n=y(this,Qe))==null||n.removeObserver(this),z(this,Qe,void 0),W(this,Qt,Va).call(this),W(this,Qt,Po).call(this)}mutate(n,r){var s;return z(this,At,r),(s=y(this,Qe))==null||s.removeObserver(this),z(this,Qe,y(this,Dt).getMutationCache().build(y(this,Dt),this.options)),y(this,Qe).addObserver(this),y(this,Qe).execute(n)}},Dt=new WeakMap,un=new WeakMap,Qe=new WeakMap,At=new WeakMap,Qt=new WeakSet,Va=function(){var r;const n=((r=y(this,Qe))==null?void 0:r.state)??fm();z(this,un,{...n,isPending:n.status==="pending",isSuccess:n.status==="success",isError:n.status==="error",isIdle:n.status==="idle",mutate:this.mutate,reset:this.reset})},Po=function(n){ke.batch(()=>{var r,s,a,l,o,u,c,h;if(y(this,At)&&this.hasListeners()){const d=y(this,un).variables,m=y(this,un).context,x={client:y(this,Dt),meta:this.options.meta,mutationKey:this.options.mutationKey};if((n==null?void 0:n.type)==="success"){try{(s=(r=y(this,At)).onSuccess)==null||s.call(r,n.data,d,m,x)}catch(w){Promise.reject(w)}try{(l=(a=y(this,At)).onSettled)==null||l.call(a,n.data,null,d,m,x)}catch(w){Promise.reject(w)}}else if((n==null?void 0:n.type)==="error"){try{(u=(o=y(this,At)).onError)==null||u.call(o,n.error,d,m,x)}catch(w){Promise.reject(w)}try{(h=(c=y(this,At)).onSettled)==null||h.call(c,void 0,n.error,d,m,x)}catch(w){Promise.reject(w)}}}this.listeners.forEach(d=>{d(y(this,un))})})},Ud),Ct,Bd,Qx=(Bd=class extends Zr{constructor(t={}){super();$(this,Ct);this.config=t,z(this,Ct,new Map)}build(t,n,r){const s=n.queryKey,a=n.queryHash??Mu(s,n);let l=this.get(a);return l||(l=new zx({client:t,queryKey:s,queryHash:a,options:t.defaultQueryOptions(n),state:r,defaultOptions:t.getQueryDefaults(s)}),this.add(l)),l}add(t){y(this,Ct).has(t.queryHash)||(y(this,Ct).set(t.queryHash,t),this.notify({type:"added",query:t}))}remove(t){const n=y(this,Ct).get(t.queryHash);n&&(t.destroy(),n===t&&y(this,Ct).delete(t.queryHash),this.notify({type:"removed",query:t}))}clear(){ke.batch(()=>{this.getAll().forEach(t=>{this.remove(t)})})}get(t){return y(this,Ct).get(t)}getAll(){return[...y(this,Ct).values()]}find(t){const n={exact:!0,...t};return this.getAll().find(r=>sd(n,r))}findAll(t={}){const n=this.getAll();return Object.keys(t).length>0?n.filter(r=>sd(t,r)):n}notify(t){ke.batch(()=>{this.listeners.forEach(n=>{n(t)})})}onFocus(){ke.batch(()=>{this.getAll().forEach(t=>{t.onFocus()})})}onOnline(){ke.batch(()=>{this.getAll().forEach(t=>{t.onOnline()})})}},Ct=new WeakMap,Bd),me,cn,dn,Ir,Dr,fn,Ar,$r,Qd,Vx=(Qd=class{constructor(e={}){$(this,me);$(this,cn);$(this,dn);$(this,Ir);$(this,Dr);$(this,fn);$(this,Ar);$(this,$r);z(this,me,e.queryCache||new Qx),z(this,cn,e.mutationCache||new Ux),z(this,dn,e.defaultOptions||{}),z(this,Ir,new Map),z(this,Dr,new Map),z(this,fn,0)}mount(){da(this,fn)._++,y(this,fn)===1&&(z(this,Ar,Iu.subscribe(async e=>{e&&(await this.resumePausedMutations(),y(this,me).onFocus())})),z(this,$r,vi.subscribe(async e=>{e&&(await this.resumePausedMutations(),y(this,me).onOnline())})))}unmount(){var e,t;da(this,fn)._--,y(this,fn)===0&&((e=y(this,Ar))==null||e.call(this),z(this,Ar,void 0),(t=y(this,$r))==null||t.call(this),z(this,$r,void 0))}isFetching(e){return y(this,me).findAll({...e,fetchStatus:"fetching"}).length}isMutating(e){return y(this,cn).findAll({...e,status:"pending"}).length}getQueryData(e){var n;const t=this.defaultQueryOptions({queryKey:e});return(n=y(this,me).get(t.queryHash))==null?void 0:n.state.data}ensureQueryData(e){const t=this.defaultQueryOptions(e),n=y(this,me).build(this,t),r=n.state.data;return r===void 0?this.fetchQuery(e):(e.revalidateIfStale&&n.isStaleByTime(Cn(t.staleTime,n))&&this.prefetchQuery(t),Promise.resolve(r))}getQueriesData(e){return y(this,me).findAll(e).map(({queryKey:t,state:n})=>{const r=n.data;return[t,r]})}setQueryData(e,t,n){const r=this.defaultQueryOptions({queryKey:e}),s=y(this,me).get(r.queryHash),a=s==null?void 0:s.state.data,l=Nx(t,a);if(l!==void 0)return y(this,me).build(this,r).setData(l,{...n,manual:!0})}setQueriesData(e,t,n){return ke.batch(()=>y(this,me).findAll(e).map(({queryKey:r})=>[r,this.setQueryData(r,t,n)]))}getQueryState(e){var n;const t=this.defaultQueryOptions({queryKey:e});return(n=y(this,me).get(t.queryHash))==null?void 0:n.state}removeQueries(e){const t=y(this,me);ke.batch(()=>{t.findAll(e).forEach(n=>{t.remove(n)})})}resetQueries(e,t){const n=y(this,me);return ke.batch(()=>(n.findAll(e).forEach(r=>{r.reset()}),this.refetchQueries({type:"active",...e},t)))}cancelQueries(e,t={}){const n={revert:!0,...t},r=ke.batch(()=>y(this,me).findAll(e).map(s=>s.cancel(n)));return Promise.all(r).then(De).catch(De)}invalidateQueries(e,t={}){return ke.batch(()=>(y(this,me).findAll(e).forEach(n=>{n.invalidate()}),(e==null?void 0:e.refetchType)==="none"?Promise.resolve():this.refetchQueries({...e,type:(e==null?void 0:e.refetchType)??(e==null?void 0:e.type)??"active"},t)))}refetchQueries(e,t={}){const n={...t,cancelRefetch:t.cancelRefetch??!0},r=ke.batch(()=>y(this,me).findAll(e).filter(s=>!s.isDisabled()&&!s.isStatic()).map(s=>{let a=s.fetch(void 0,n);return n.throwOnError||(a=a.catch(De)),s.state.fetchStatus==="paused"?Promise.resolve():a}));return Promise.all(r).then(De)}fetchQuery(e){const t=this.defaultQueryOptions(e);t.retry===void 0&&(t.retry=!1);const n=y(this,me).build(this,t);return n.isStaleByTime(Cn(t.staleTime,n))?n.fetch(t):Promise.resolve(n.state.data)}prefetchQuery(e){return this.fetchQuery(e).then(De).catch(De)}fetchInfiniteQuery(e){return e.behavior=fd(e.pages),this.fetchQuery(e)}prefetchInfiniteQuery(e){return this.fetchInfiniteQuery(e).then(De).catch(De)}ensureInfiniteQueryData(e){return e.behavior=fd(e.pages),this.ensureQueryData(e)}resumePausedMutations(){return vi.isOnline()?y(this,cn).resumePausedMutations():Promise.resolve()}getQueryCache(){return y(this,me)}getMutationCache(){return y(this,cn)}getDefaultOptions(){return y(this,dn)}setDefaultOptions(e){z(this,dn,e)}setQueryDefaults(e,t){y(this,Ir).set(sr(e),{queryKey:e,defaultOptions:t})}getQueryDefaults(e){const t=[...y(this,Ir).values()],n={};return t.forEach(r=>{Hs(e,r.queryKey)&&Object.assign(n,r.defaultOptions)}),n}setMutationDefaults(e,t){y(this,Dr).set(sr(e),{mutationKey:e,defaultOptions:t})}getMutationDefaults(e){const t=[...y(this,Dr).values()],n={};return t.forEach(r=>{Hs(e,r.mutationKey)&&Object.assign(n,r.defaultOptions)}),n}defaultQueryOptions(e){if(e._defaulted)return e;const t={...y(this,dn).queries,...this.getQueryDefaults(e.queryKey),...e,_defaulted:!0};return t.queryHash||(t.queryHash=Mu(t.queryKey,t)),t.refetchOnReconnect===void 0&&(t.refetchOnReconnect=t.networkMode!=="always"),t.throwOnError===void 0&&(t.throwOnError=!!t.suspense),!t.networkMode&&t.persister&&(t.networkMode="offlineFirst"),t.queryFn===zu&&(t.enabled=!1),t}defaultMutationOptions(e){return e!=null&&e._defaulted?e:{...y(this,dn).mutations,...(e==null?void 0:e.mutationKey)&&this.getMutationDefaults(e.mutationKey),...e,_defaulted:!0}}clear(){y(this,me).clear(),y(this,cn).clear()}},me=new WeakMap,cn=new WeakMap,dn=new WeakMap,Ir=new WeakMap,Dr=new WeakMap,fn=new WeakMap,Ar=new WeakMap,$r=new WeakMap,Qd),hm=k.createContext(void 0),Jt=e=>{const t=k.useContext(hm);if(!t)throw new Error("No QueryClient set, use QueryClientProvider to set one");return t},Kx=({client:e,children:t})=>(k.useEffect(()=>(e.mount(),()=>{e.unmount()}),[e]),i.jsx(hm.Provider,{value:e,children:t})),mm=k.createContext(!1),Hx=()=>k.useContext(mm);mm.Provider;function Wx(){let e=!1;return{clearReset:()=>{e=!1},reset:()=>{e=!0},isReset:()=>e}}var qx=k.createContext(Wx()),Jx=()=>k.useContext(qx),Gx=(e,t,n)=>{const r=n!=null&&n.state.error&&typeof e.throwOnError=="function"?Fu(e.throwOnError,[n.state.error,n]):e.throwOnError;(e.suspense||e.experimental_prefetchInRender||r)&&(t.isReset()||(e.retryOnMount=!1))},Yx=e=>{k.useEffect(()=>{e.clearReset()},[e])},Xx=({result:e,errorResetBoundary:t,throwOnError:n,query:r,suspense:s})=>e.isError&&!t.isReset()&&!e.isFetching&&r&&(s&&e.data===void 0||Fu(n,[e.error,r])),Zx=e=>{if(e.suspense){const n=s=>s==="static"?s:Math.max(s??1e3,1e3),r=e.staleTime;e.staleTime=typeof r=="function"?(...s)=>n(r(...s)):n(r),typeof e.gcTime=="number"&&(e.gcTime=Math.max(e.gcTime,1e3))}},ey=(e,t)=>e.isLoading&&e.isFetching&&!t,ty=(e,t)=>(e==null?void 0:e.suspense)&&t.isPending,md=(e,t,n)=>t.fetchOptimistic(e).catch(()=>{n.clearReset()});function ny(e,t,n){var m,x,w,j;const r=Hx(),s=Jx(),a=Jt(),l=a.defaultQueryOptions(e);(x=(m=a.getDefaultOptions().queries)==null?void 0:m._experimental_beforeQuery)==null||x.call(m,l);const o=a.getQueryCache().get(l.queryHash);l._optimisticResults=r?"isRestoring":"optimistic",Zx(l),Gx(l,s,o),Yx(s);const u=!a.getQueryCache().get(l.queryHash),[c]=k.useState(()=>new t(a,l)),h=c.getOptimisticResult(l),d=!r&&e.subscribed!==!1;if(k.useSyncExternalStore(k.useCallback(S=>{const p=d?c.subscribe(ke.batchCalls(S)):De;return c.updateResult(),p},[c,d]),()=>c.getCurrentResult(),()=>c.getCurrentResult()),k.useEffect(()=>{c.setOptions(l)},[l,c]),ty(l,h))throw md(l,c,s);if(Xx({result:h,errorResetBoundary:s,throwOnError:l.throwOnError,query:o,suspense:l.suspense}))throw h.error;if((j=(w=a.getDefaultOptions().queries)==null?void 0:w._experimental_afterQuery)==null||j.call(w,l,h),l.experimental_prefetchInRender&&!rr&&ey(h,r)){const S=u?md(l,c,s):o==null?void 0:o.promise;S==null||S.catch(De).finally(()=>{c.updateResult()})}return l.notifyOnChangeProps?h:c.trackResult(h)}function ve(e,t){return ny(e,Fx)}function Je(e,t){const n=Jt(),[r]=k.useState(()=>new Bx(n,e));k.useEffect(()=>{r.setOptions(e)},[r,e]);const s=k.useSyncExternalStore(k.useCallback(l=>r.subscribe(ke.batchCalls(l)),[r]),()=>r.getCurrentResult(),()=>r.getCurrentResult()),a=k.useCallback((l,o)=>{r.mutate(l,o).catch(De)},[r]);if(s.error&&Fu(r.options.throwOnError,[s.error]))throw s.error;return{...s,mutate:a,mutateAsync:s.mutate}}/** + * @remix-run/router v1.23.2 + * + * Copyright (c) Remix Software Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE.md file in the root directory of this source tree. + * + * @license MIT + */function Ws(){return Ws=Object.assign?Object.assign.bind():function(e){for(var t=1;t"u")throw new Error(t)}function Au(e,t){if(!e){typeof console<"u"&&console.warn(t);try{throw new Error(t)}catch{}}}function sy(){return Math.random().toString(36).substr(2,8)}function vd(e,t){return{usr:e.state,key:e.key,idx:t}}function To(e,t,n,r){return n===void 0&&(n=null),Ws({pathname:typeof e=="string"?e:e.pathname,search:"",hash:""},typeof t=="string"?es(t):t,{state:n,key:t&&t.key||r||sy()})}function xi(e){let{pathname:t="/",search:n="",hash:r=""}=e;return n&&n!=="?"&&(t+=n.charAt(0)==="?"?n:"?"+n),r&&r!=="#"&&(t+=r.charAt(0)==="#"?r:"#"+r),t}function es(e){let t={};if(e){let n=e.indexOf("#");n>=0&&(t.hash=e.substr(n),e=e.substr(0,n));let r=e.indexOf("?");r>=0&&(t.search=e.substr(r),e=e.substr(0,r)),e&&(t.pathname=e)}return t}function ay(e,t,n,r){r===void 0&&(r={});let{window:s=document.defaultView,v5Compat:a=!1}=r,l=s.history,o=pn.Pop,u=null,c=h();c==null&&(c=0,l.replaceState(Ws({},l.state,{idx:c}),""));function h(){return(l.state||{idx:null}).idx}function d(){o=pn.Pop;let S=h(),p=S==null?null:S-c;c=S,u&&u({action:o,location:j.location,delta:p})}function m(S,p){o=pn.Push;let f=To(j.location,S,p);c=h()+1;let v=vd(f,c),g=j.createHref(f);try{l.pushState(v,"",g)}catch(C){if(C instanceof DOMException&&C.name==="DataCloneError")throw C;s.location.assign(g)}a&&u&&u({action:o,location:j.location,delta:1})}function x(S,p){o=pn.Replace;let f=To(j.location,S,p);c=h();let v=vd(f,c),g=j.createHref(f);l.replaceState(v,"",g),a&&u&&u({action:o,location:j.location,delta:0})}function w(S){let p=s.location.origin!=="null"?s.location.origin:s.location.href,f=typeof S=="string"?S:xi(S);return f=f.replace(/ $/,"%20"),xe(p,"No window.location.(origin|href) available to create URL for href: "+f),new URL(f,p)}let j={get action(){return o},get location(){return e(s,l)},listen(S){if(u)throw new Error("A history only accepts one active listener");return s.addEventListener(pd,d),u=S,()=>{s.removeEventListener(pd,d),u=null}},createHref(S){return t(s,S)},createURL:w,encodeLocation(S){let p=w(S);return{pathname:p.pathname,search:p.search,hash:p.hash}},push:m,replace:x,go(S){return l.go(S)}};return j}var xd;(function(e){e.data="data",e.deferred="deferred",e.redirect="redirect",e.error="error"})(xd||(xd={}));function iy(e,t,n){return n===void 0&&(n="/"),ly(e,t,n)}function ly(e,t,n,r){let s=typeof t=="string"?es(t):t,a=qr(s.pathname||"/",n);if(a==null)return null;let l=pm(e);oy(l);let o=null;for(let u=0;o==null&&u{let u={relativePath:o===void 0?a.path||"":o,caseSensitive:a.caseSensitive===!0,childrenIndex:l,route:a};u.relativePath.startsWith("/")&&(xe(u.relativePath.startsWith(r),'Absolute route path "'+u.relativePath+'" nested under path '+('"'+r+'" is not valid. An absolute child route path ')+"must start with the combined path of all its parent routes."),u.relativePath=u.relativePath.slice(r.length));let c=_n([r,u.relativePath]),h=n.concat(u);a.children&&a.children.length>0&&(xe(a.index!==!0,"Index routes must not have child routes. Please remove "+('all child routes from route path "'+c+'".')),pm(a.children,t,h,c)),!(a.path==null&&!a.index)&&t.push({path:c,score:py(c,a.index),routesMeta:h})};return e.forEach((a,l)=>{var o;if(a.path===""||!((o=a.path)!=null&&o.includes("?")))s(a,l);else for(let u of vm(a.path))s(a,l,u)}),t}function vm(e){let t=e.split("/");if(t.length===0)return[];let[n,...r]=t,s=n.endsWith("?"),a=n.replace(/\?$/,"");if(r.length===0)return s?[a,""]:[a];let l=vm(r.join("/")),o=[];return o.push(...l.map(u=>u===""?a:[a,u].join("/"))),s&&o.push(...l),o.map(u=>e.startsWith("/")&&u===""?"/":u)}function oy(e){e.sort((t,n)=>t.score!==n.score?n.score-t.score:vy(t.routesMeta.map(r=>r.childrenIndex),n.routesMeta.map(r=>r.childrenIndex)))}const uy=/^:[\w-]+$/,cy=3,dy=2,fy=1,hy=10,my=-2,yd=e=>e==="*";function py(e,t){let n=e.split("/"),r=n.length;return n.some(yd)&&(r+=my),t&&(r+=dy),n.filter(s=>!yd(s)).reduce((s,a)=>s+(uy.test(a)?cy:a===""?fy:hy),r)}function vy(e,t){return e.length===t.length&&e.slice(0,-1).every((r,s)=>r===t[s])?e[e.length-1]-t[t.length-1]:0}function xy(e,t,n){let{routesMeta:r}=e,s={},a="/",l=[];for(let o=0;o{let{paramName:m,isOptional:x}=h;if(m==="*"){let j=o[d]||"";l=a.slice(0,a.length-j.length).replace(/(.)\/+$/,"$1")}const w=o[d];return x&&!w?c[m]=void 0:c[m]=(w||"").replace(/%2F/g,"/"),c},{}),pathname:a,pathnameBase:l,pattern:e}}function yy(e,t,n){t===void 0&&(t=!1),n===void 0&&(n=!0),Au(e==="*"||!e.endsWith("*")||e.endsWith("/*"),'Route path "'+e+'" will be treated as if it were '+('"'+e.replace(/\*$/,"/*")+'" because the `*` character must ')+"always follow a `/` in the pattern. To get rid of this warning, "+('please change the route path to "'+e.replace(/\*$/,"/*")+'".'));let r=[],s="^"+e.replace(/\/*\*?$/,"").replace(/^\/*/,"/").replace(/[\\.*+^${}|()[\]]/g,"\\$&").replace(/\/:([\w-]+)(\?)?/g,(l,o,u)=>(r.push({paramName:o,isOptional:u!=null}),u?"/?([^\\/]+)?":"/([^\\/]+)"));return e.endsWith("*")?(r.push({paramName:"*"}),s+=e==="*"||e==="/*"?"(.*)$":"(?:\\/(.+)|\\/*)$"):n?s+="\\/*$":e!==""&&e!=="/"&&(s+="(?:(?=\\/|$))"),[new RegExp(s,t?void 0:"i"),r]}function gy(e){try{return e.split("/").map(t=>decodeURIComponent(t).replace(/\//g,"%2F")).join("/")}catch(t){return Au(!1,'The URL path "'+e+'" could not be decoded because it is is a malformed URL segment. This is probably due to a bad percent '+("encoding ("+t+").")),e}}function qr(e,t){if(t==="/")return e;if(!e.toLowerCase().startsWith(t.toLowerCase()))return null;let n=t.endsWith("/")?t.length-1:t.length,r=e.charAt(n);return r&&r!=="/"?null:e.slice(n)||"/"}const jy=/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i,wy=e=>jy.test(e);function ky(e,t){t===void 0&&(t="/");let{pathname:n,search:r="",hash:s=""}=typeof e=="string"?es(e):e,a;if(n)if(wy(n))a=n;else{if(n.includes("//")){let l=n;n=n.replace(/\/\/+/g,"/"),Au(!1,"Pathnames cannot have embedded double slashes - normalizing "+(l+" -> "+n))}n.startsWith("/")?a=gd(n.substring(1),"/"):a=gd(n,t)}else a=t;return{pathname:a,search:by(r),hash:Cy(s)}}function gd(e,t){let n=t.replace(/\/+$/,"").split("/");return e.split("/").forEach(s=>{s===".."?n.length>1&&n.pop():s!=="."&&n.push(s)}),n.length>1?n.join("/"):"/"}function yl(e,t,n,r){return"Cannot include a '"+e+"' character in a manually specified "+("`to."+t+"` field ["+JSON.stringify(r)+"]. Please separate it out to the ")+("`to."+n+"` field. Alternatively you may provide the full path as ")+'a string in and the router will parse it for you.'}function Sy(e){return e.filter((t,n)=>n===0||t.route.path&&t.route.path.length>0)}function xm(e,t){let n=Sy(e);return t?n.map((r,s)=>s===n.length-1?r.pathname:r.pathnameBase):n.map(r=>r.pathnameBase)}function ym(e,t,n,r){r===void 0&&(r=!1);let s;typeof e=="string"?s=es(e):(s=Ws({},e),xe(!s.pathname||!s.pathname.includes("?"),yl("?","pathname","search",s)),xe(!s.pathname||!s.pathname.includes("#"),yl("#","pathname","hash",s)),xe(!s.search||!s.search.includes("#"),yl("#","search","hash",s)));let a=e===""||s.pathname==="",l=a?"/":s.pathname,o;if(l==null)o=n;else{let d=t.length-1;if(!r&&l.startsWith("..")){let m=l.split("/");for(;m[0]==="..";)m.shift(),d-=1;s.pathname=m.join("/")}o=d>=0?t[d]:"/"}let u=ky(s,o),c=l&&l!=="/"&&l.endsWith("/"),h=(a||l===".")&&n.endsWith("/");return!u.pathname.endsWith("/")&&(c||h)&&(u.pathname+="/"),u}const _n=e=>e.join("/").replace(/\/\/+/g,"/"),Ny=e=>e.replace(/\/+$/,"").replace(/^\/*/,"/"),by=e=>!e||e==="?"?"":e.startsWith("?")?e:"?"+e,Cy=e=>!e||e==="#"?"":e.startsWith("#")?e:"#"+e;function _y(e){return e!=null&&typeof e.status=="number"&&typeof e.statusText=="string"&&typeof e.internal=="boolean"&&"data"in e}const gm=["post","put","patch","delete"];new Set(gm);const Ey=["get",...gm];new Set(Ey);/** + * React Router v6.30.3 + * + * Copyright (c) Remix Software Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE.md file in the root directory of this source tree. + * + * @license MIT + */function qs(){return qs=Object.assign?Object.assign.bind():function(e){for(var t=1;t{o.current=!0}),k.useCallback(function(c,h){if(h===void 0&&(h={}),!o.current)return;if(typeof c=="number"){r.go(c);return}let d=ym(c,JSON.parse(l),a,h.relative==="path");e==null&&t!=="/"&&(d.pathname=d.pathname==="/"?t:_n([t,d.pathname])),(h.replace?r.replace:r.push)(d,h.state,h)},[t,r,l,a,e])}const Oy=k.createContext(null);function Ly(e){let t=k.useContext(Gt).outlet;return t&&k.createElement(Oy.Provider,{value:e},t)}function Di(){let{matches:e}=k.useContext(Gt),t=e[e.length-1];return t?t.params:{}}function Ai(e,t){let{relative:n}=t===void 0?{}:t,{future:r}=k.useContext(Rn),{matches:s}=k.useContext(Gt),{pathname:a}=ts(),l=JSON.stringify(xm(s,r.v7_relativeSplatPath));return k.useMemo(()=>ym(e,JSON.parse(l),a,n==="path"),[e,l,a,n])}function Ry(e,t){return My(e,t)}function My(e,t,n,r){ua()||xe(!1);let{navigator:s}=k.useContext(Rn),{matches:a}=k.useContext(Gt),l=a[a.length-1],o=l?l.params:{};l&&l.pathname;let u=l?l.pathnameBase:"/";l&&l.route;let c=ts(),h;if(t){var d;let S=typeof t=="string"?es(t):t;u==="/"||(d=S.pathname)!=null&&d.startsWith(u)||xe(!1),h=S}else h=c;let m=h.pathname||"/",x=m;if(u!=="/"){let S=u.replace(/^\//,"").split("/");x="/"+m.replace(/^\//,"").split("/").slice(S.length).join("/")}let w=iy(e,{pathname:x}),j=Ay(w&&w.map(S=>Object.assign({},S,{params:Object.assign({},o,S.params),pathname:_n([u,s.encodeLocation?s.encodeLocation(S.pathname).pathname:S.pathname]),pathnameBase:S.pathnameBase==="/"?u:_n([u,s.encodeLocation?s.encodeLocation(S.pathnameBase).pathname:S.pathnameBase])})),a,n,r);return t&&j?k.createElement(Ii.Provider,{value:{location:qs({pathname:"/",search:"",hash:"",state:null,key:"default"},h),navigationType:pn.Pop}},j):j}function zy(){let e=Qy(),t=_y(e)?e.status+" "+e.statusText:e instanceof Error?e.message:JSON.stringify(e),n=e instanceof Error?e.stack:null,s={padding:"0.5rem",backgroundColor:"rgba(200,200,200, 0.5)"};return k.createElement(k.Fragment,null,k.createElement("h2",null,"Unexpected Application Error!"),k.createElement("h3",{style:{fontStyle:"italic"}},t),n?k.createElement("pre",{style:s},n):null,null)}const Fy=k.createElement(zy,null);class Iy extends k.Component{constructor(t){super(t),this.state={location:t.location,revalidation:t.revalidation,error:t.error}}static getDerivedStateFromError(t){return{error:t}}static getDerivedStateFromProps(t,n){return n.location!==t.location||n.revalidation!=="idle"&&t.revalidation==="idle"?{error:t.error,location:t.location,revalidation:t.revalidation}:{error:t.error!==void 0?t.error:n.error,location:n.location,revalidation:t.revalidation||n.revalidation}}componentDidCatch(t,n){console.error("React Router caught the following error during render",t,n)}render(){return this.state.error!==void 0?k.createElement(Gt.Provider,{value:this.props.routeContext},k.createElement(wm.Provider,{value:this.state.error,children:this.props.component})):this.props.children}}function Dy(e){let{routeContext:t,match:n,children:r}=e,s=k.useContext(Fi);return s&&s.static&&s.staticContext&&(n.route.errorElement||n.route.ErrorBoundary)&&(s.staticContext._deepestRenderedBoundaryId=n.route.id),k.createElement(Gt.Provider,{value:t},r)}function Ay(e,t,n,r){var s;if(t===void 0&&(t=[]),n===void 0&&(n=null),r===void 0&&(r=null),e==null){var a;if(!n)return null;if(n.errors)e=n.matches;else if((a=r)!=null&&a.v7_partialHydration&&t.length===0&&!n.initialized&&n.matches.length>0)e=n.matches;else return null}let l=e,o=(s=n)==null?void 0:s.errors;if(o!=null){let h=l.findIndex(d=>d.route.id&&(o==null?void 0:o[d.route.id])!==void 0);h>=0||xe(!1),l=l.slice(0,Math.min(l.length,h+1))}let u=!1,c=-1;if(n&&r&&r.v7_partialHydration)for(let h=0;h=0?l=l.slice(0,c+1):l=[l[0]];break}}}return l.reduceRight((h,d,m)=>{let x,w=!1,j=null,S=null;n&&(x=o&&d.route.id?o[d.route.id]:void 0,j=d.route.errorElement||Fy,u&&(c<0&&m===0?(Ky("route-fallback"),w=!0,S=null):c===m&&(w=!0,S=d.route.hydrateFallbackElement||null)));let p=t.concat(l.slice(0,m+1)),f=()=>{let v;return x?v=j:w?v=S:d.route.Component?v=k.createElement(d.route.Component,null):d.route.element?v=d.route.element:v=h,k.createElement(Dy,{match:d,routeContext:{outlet:h,matches:p,isDataRoute:n!=null},children:v})};return n&&(d.route.ErrorBoundary||d.route.errorElement||m===0)?k.createElement(Iy,{location:n.location,revalidation:n.revalidation,component:j,error:x,children:f(),routeContext:{outlet:null,matches:p,isDataRoute:!0}}):f()},null)}var Sm=function(e){return e.UseBlocker="useBlocker",e.UseRevalidator="useRevalidator",e.UseNavigateStable="useNavigate",e}(Sm||{}),Nm=function(e){return e.UseBlocker="useBlocker",e.UseLoaderData="useLoaderData",e.UseActionData="useActionData",e.UseRouteError="useRouteError",e.UseNavigation="useNavigation",e.UseRouteLoaderData="useRouteLoaderData",e.UseMatches="useMatches",e.UseRevalidator="useRevalidator",e.UseNavigateStable="useNavigate",e.UseRouteId="useRouteId",e}(Nm||{});function $y(e){let t=k.useContext(Fi);return t||xe(!1),t}function Uy(e){let t=k.useContext(jm);return t||xe(!1),t}function By(e){let t=k.useContext(Gt);return t||xe(!1),t}function bm(e){let t=By(),n=t.matches[t.matches.length-1];return n.route.id||xe(!1),n.route.id}function Qy(){var e;let t=k.useContext(wm),n=Uy(),r=bm();return t!==void 0?t:(e=n.errors)==null?void 0:e[r]}function Vy(){let{router:e}=$y(Sm.UseNavigateStable),t=bm(Nm.UseNavigateStable),n=k.useRef(!1);return km(()=>{n.current=!0}),k.useCallback(function(s,a){a===void 0&&(a={}),n.current&&(typeof s=="number"?e.navigate(s):e.navigate(s,qs({fromRouteId:t},a)))},[e,t])}const jd={};function Ky(e,t,n){jd[e]||(jd[e]=!0)}function Hy(e,t){e==null||e.v7_startTransition,e==null||e.v7_relativeSplatPath}function Wy(e){return Ly(e.context)}function kt(e){xe(!1)}function qy(e){let{basename:t="/",children:n=null,location:r,navigationType:s=pn.Pop,navigator:a,static:l=!1,future:o}=e;ua()&&xe(!1);let u=t.replace(/^\/*/,"/"),c=k.useMemo(()=>({basename:u,navigator:a,static:l,future:qs({v7_relativeSplatPath:!1},o)}),[u,o,a,l]);typeof r=="string"&&(r=es(r));let{pathname:h="/",search:d="",hash:m="",state:x=null,key:w="default"}=r,j=k.useMemo(()=>{let S=qr(h,u);return S==null?null:{location:{pathname:S,search:d,hash:m,state:x,key:w},navigationType:s}},[u,h,d,m,x,w,s]);return j==null?null:k.createElement(Rn.Provider,{value:c},k.createElement(Ii.Provider,{children:n,value:j}))}function Jy(e){let{children:t,location:n}=e;return Ry(Lo(t),n)}new Promise(()=>{});function Lo(e,t){t===void 0&&(t=[]);let n=[];return k.Children.forEach(e,(r,s)=>{if(!k.isValidElement(r))return;let a=[...t,s];if(r.type===k.Fragment){n.push.apply(n,Lo(r.props.children,a));return}r.type!==kt&&xe(!1),!r.props.index||!r.props.children||xe(!1);let l={id:r.props.id||a.join("-"),caseSensitive:r.props.caseSensitive,element:r.props.element,Component:r.props.Component,index:r.props.index,path:r.props.path,loader:r.props.loader,action:r.props.action,errorElement:r.props.errorElement,ErrorBoundary:r.props.ErrorBoundary,hasErrorBoundary:r.props.ErrorBoundary!=null||r.props.errorElement!=null,shouldRevalidate:r.props.shouldRevalidate,handle:r.props.handle,lazy:r.props.lazy};r.props.children&&(l.children=Lo(r.props.children,a)),n.push(l)}),n}/** + * React Router DOM v6.30.3 + * + * Copyright (c) Remix Software Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE.md file in the root directory of this source tree. + * + * @license MIT + */function yi(){return yi=Object.assign?Object.assign.bind():function(e){for(var t=1;t=0)&&(n[s]=e[s]);return n}function Gy(e){return!!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)}function Yy(e,t){return e.button===0&&(!t||t==="_self")&&!Gy(e)}const Xy=["onClick","relative","reloadDocument","replace","state","target","to","preventScrollReset","viewTransition"],Zy=["aria-current","caseSensitive","className","end","style","to","viewTransition","children"],eg="6";try{window.__reactRouterVersion=eg}catch{}const tg=k.createContext({isTransitioning:!1}),ng="startTransition",wd=up[ng];function rg(e){let{basename:t,children:n,future:r,window:s}=e,a=k.useRef();a.current==null&&(a.current=ry({window:s,v5Compat:!0}));let l=a.current,[o,u]=k.useState({action:l.action,location:l.location}),{v7_startTransition:c}=r||{},h=k.useCallback(d=>{c&&wd?wd(()=>u(d)):u(d)},[u,c]);return k.useLayoutEffect(()=>l.listen(h),[l,h]),k.useEffect(()=>Hy(r),[r]),k.createElement(qy,{basename:t,children:n,location:o.location,navigationType:o.action,navigator:l,future:r})}const sg=typeof window<"u"&&typeof window.document<"u"&&typeof window.document.createElement<"u",ag=/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i,Js=k.forwardRef(function(t,n){let{onClick:r,relative:s,reloadDocument:a,replace:l,state:o,target:u,to:c,preventScrollReset:h,viewTransition:d}=t,m=Cm(t,Xy),{basename:x}=k.useContext(Rn),w,j=!1;if(typeof c=="string"&&ag.test(c)&&(w=c,sg))try{let v=new URL(window.location.href),g=c.startsWith("//")?new URL(v.protocol+c):new URL(c),C=qr(g.pathname,x);g.origin===v.origin&&C!=null?c=C+g.search+g.hash:j=!0}catch{}let S=Py(c,{relative:s}),p=lg(c,{replace:l,state:o,target:u,preventScrollReset:h,relative:s,viewTransition:d});function f(v){r&&r(v),v.defaultPrevented||p(v)}return k.createElement("a",yi({},m,{href:w||S,onClick:j||a?r:f,ref:n,target:u}))}),kd=k.forwardRef(function(t,n){let{"aria-current":r="page",caseSensitive:s=!1,className:a="",end:l=!1,style:o,to:u,viewTransition:c,children:h}=t,d=Cm(t,Zy),m=Ai(u,{relative:d.relative}),x=ts(),w=k.useContext(jm),{navigator:j,basename:S}=k.useContext(Rn),p=w!=null&&og(m)&&c===!0,f=j.encodeLocation?j.encodeLocation(m).pathname:m.pathname,v=x.pathname,g=w&&w.navigation&&w.navigation.location?w.navigation.location.pathname:null;s||(v=v.toLowerCase(),g=g?g.toLowerCase():null,f=f.toLowerCase()),g&&S&&(g=qr(g,S)||g);const C=f!=="/"&&f.endsWith("/")?f.length-1:f.length;let b=v===f||!l&&v.startsWith(f)&&v.charAt(C)==="/",N=g!=null&&(g===f||!l&&g.startsWith(f)&&g.charAt(f.length)==="/"),_={isActive:b,isPending:N,isTransitioning:p},F=b?r:void 0,P;typeof a=="function"?P=a(_):P=[a,b?"active":null,N?"pending":null,p?"transitioning":null].filter(Boolean).join(" ");let B=typeof o=="function"?o(_):o;return k.createElement(Js,yi({},d,{"aria-current":F,className:P,ref:n,style:B,to:u,viewTransition:c}),typeof h=="function"?h(_):h)});var Ro;(function(e){e.UseScrollRestoration="useScrollRestoration",e.UseSubmit="useSubmit",e.UseSubmitFetcher="useSubmitFetcher",e.UseFetcher="useFetcher",e.useViewTransitionState="useViewTransitionState"})(Ro||(Ro={}));var Sd;(function(e){e.UseFetcher="useFetcher",e.UseFetchers="useFetchers",e.UseScrollRestoration="useScrollRestoration"})(Sd||(Sd={}));function ig(e){let t=k.useContext(Fi);return t||xe(!1),t}function lg(e,t){let{target:n,replace:r,state:s,preventScrollReset:a,relative:l,viewTransition:o}=t===void 0?{}:t,u=Lt(),c=ts(),h=Ai(e,{relative:l});return k.useCallback(d=>{if(Yy(d,n)){d.preventDefault();let m=r!==void 0?r:xi(c)===xi(h);u(e,{replace:m,state:s,preventScrollReset:a,relative:l,viewTransition:o})}},[c,u,h,r,s,n,e,a,l,o])}function og(e,t){t===void 0&&(t={});let n=k.useContext(tg);n==null&&xe(!1);let{basename:r}=ig(Ro.useViewTransitionState),s=Ai(e,{relative:t.relative});if(!n.isTransitioning)return!1;let a=qr(n.currentLocation.pathname,r)||n.currentLocation.pathname,l=qr(n.nextLocation.pathname,r)||n.nextLocation.pathname;return Oo(s.pathname,l)!=null||Oo(s.pathname,a)!=null}/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */var ug={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"};/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const cg=e=>e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase().trim(),Y=(e,t)=>{const n=k.forwardRef(({color:r="currentColor",size:s=24,strokeWidth:a=2,absoluteStrokeWidth:l,className:o="",children:u,...c},h)=>k.createElement("svg",{ref:h,...ug,width:s,height:s,stroke:r,strokeWidth:l?Number(a)*24/Number(s):a,className:["lucide",`lucide-${cg(e)}`,o].join(" "),...c},[...t.map(([d,m])=>k.createElement(d,m)),...Array.isArray(u)?u:[u]]));return n.displayName=`${e}`,n};/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const _m=Y("AlertCircle",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["line",{x1:"12",x2:"12",y1:"8",y2:"12",key:"1pkeuh"}],["line",{x1:"12",x2:"12.01",y1:"16",y2:"16",key:"4dfq90"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const dg=Y("ArrowUpDown",[["path",{d:"m21 16-4 4-4-4",key:"f6ql7i"}],["path",{d:"M17 20V4",key:"1ejh1v"}],["path",{d:"m3 8 4-4 4 4",key:"11wl7u"}],["path",{d:"M7 4v16",key:"1glfcx"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const fg=Y("BarChart3",[["path",{d:"M3 3v18h18",key:"1s2lah"}],["path",{d:"M18 17V9",key:"2bz60n"}],["path",{d:"M13 17V5",key:"1frdt8"}],["path",{d:"M8 17v-3",key:"17ska0"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const hg=Y("Bot",[["path",{d:"M12 8V4H8",key:"hb8ula"}],["rect",{width:"16",height:"12",x:"4",y:"8",rx:"2",key:"enze0r"}],["path",{d:"M2 14h2",key:"vft8re"}],["path",{d:"M20 14h2",key:"4cs60a"}],["path",{d:"M15 13v2",key:"1xurst"}],["path",{d:"M9 13v2",key:"rq6x2g"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Em=Y("CheckCircle",[["path",{d:"M22 11.08V12a10 10 0 1 1-5.93-9.14",key:"g774vq"}],["path",{d:"m9 11 3 3L22 4",key:"1pflzl"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const mg=Y("Check",[["path",{d:"M20 6 9 17l-5-5",key:"1gmf2c"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const pg=Y("ChevronDown",[["path",{d:"m6 9 6 6 6-6",key:"qrunsl"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const gi=Y("ChevronRight",[["path",{d:"m9 18 6-6-6-6",key:"mthhwq"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const vg=Y("Clock",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["polyline",{points:"12 6 12 12 16 14",key:"68esgv"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const xg=Y("Coins",[["circle",{cx:"8",cy:"8",r:"6",key:"3yglwk"}],["path",{d:"M18.09 10.37A6 6 0 1 1 10.34 18",key:"t5s6rm"}],["path",{d:"M7 6h1v4",key:"1obek4"}],["path",{d:"m16.71 13.88.7.71-2.82 2.82",key:"1rbuyh"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const yg=Y("Copy",[["rect",{width:"14",height:"14",x:"8",y:"8",rx:"2",ry:"2",key:"17jyea"}],["path",{d:"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2",key:"zix9uf"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const gg=Y("Database",[["ellipse",{cx:"12",cy:"5",rx:"9",ry:"3",key:"msslwz"}],["path",{d:"M3 5V19A9 3 0 0 0 21 19V5",key:"1wlel7"}],["path",{d:"M3 12A9 3 0 0 0 21 12",key:"mv7ke4"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Nd=Y("Download",[["path",{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4",key:"ih7n3h"}],["polyline",{points:"7 10 12 15 17 10",key:"2ggqvy"}],["line",{x1:"12",x2:"12",y1:"15",y2:"3",key:"1vk2je"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const jg=Y("ExternalLink",[["path",{d:"M15 3h6v6",key:"1q9fwt"}],["path",{d:"M10 14 21 3",key:"gplh6r"}],["path",{d:"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6",key:"a6xqqp"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const wg=Y("FlaskConical",[["path",{d:"M10 2v7.527a2 2 0 0 1-.211.896L4.72 20.55a1 1 0 0 0 .9 1.45h12.76a1 1 0 0 0 .9-1.45l-5.069-10.127A2 2 0 0 1 14 9.527V2",key:"pzvekw"}],["path",{d:"M8.5 2h7",key:"csnxdl"}],["path",{d:"M7 16h10",key:"wp8him"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const kg=Y("GitCompare",[["circle",{cx:"18",cy:"18",r:"3",key:"1xkwt0"}],["circle",{cx:"6",cy:"6",r:"3",key:"1lh9wr"}],["path",{d:"M13 6h3a2 2 0 0 1 2 2v7",key:"1yeb86"}],["path",{d:"M11 18H8a2 2 0 0 1-2-2V9",key:"19pyzm"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Sg=Y("Github",[["path",{d:"M15 22v-4a4.8 4.8 0 0 0-1-3.5c3 0 6-2 6-5.5.08-1.25-.27-2.48-1-3.5.28-1.15.28-2.35 0-3.5 0 0-1 0-3 1.5-2.64-.5-5.36-.5-8 0C6 2 5 2 5 2c-.3 1.15-.3 2.35 0 3.5A5.403 5.403 0 0 0 4 9c0 3.5 3 5.5 6 5.5-.39.49-.68 1.05-.85 1.65-.17.6-.22 1.23-.15 1.85v4",key:"tonef"}],["path",{d:"M9 18c-4.51 2-5-2-7-2",key:"9comsn"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const $i=Y("Globe",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20",key:"13o1zl"}],["path",{d:"M2 12h20",key:"9i4pu4"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Ng=Y("History",[["path",{d:"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8",key:"1357e3"}],["path",{d:"M3 3v5h5",key:"1xhq8a"}],["path",{d:"M12 7v5l4 2",key:"1fdv2h"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const bg=Y("List",[["line",{x1:"8",x2:"21",y1:"6",y2:"6",key:"7ey8pc"}],["line",{x1:"8",x2:"21",y1:"12",y2:"12",key:"rjfblc"}],["line",{x1:"8",x2:"21",y1:"18",y2:"18",key:"c3b1m8"}],["line",{x1:"3",x2:"3.01",y1:"6",y2:"6",key:"1g7gq3"}],["line",{x1:"3",x2:"3.01",y1:"12",y2:"12",key:"1pjlvk"}],["line",{x1:"3",x2:"3.01",y1:"18",y2:"18",key:"28t2mc"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const ca=Y("Loader2",[["path",{d:"M21 12a9 9 0 1 1-6.219-8.56",key:"13zald"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Pm=Y("Lock",[["rect",{width:"18",height:"11",x:"3",y:"11",rx:"2",ry:"2",key:"1w4ew1"}],["path",{d:"M7 11V7a5 5 0 0 1 10 0v4",key:"fwvmzm"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Cg=Y("LogOut",[["path",{d:"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4",key:"1uf3rs"}],["polyline",{points:"16 17 21 12 16 7",key:"1gabdz"}],["line",{x1:"21",x2:"9",y1:"12",y2:"12",key:"1uyos4"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const _g=Y("Moon",[["path",{d:"M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z",key:"a7tn18"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Gs=Y("Play",[["polygon",{points:"5 3 19 12 5 21 5 3",key:"191637"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Ui=Y("Plus",[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"M12 5v14",key:"s699le"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Tm=Y("Settings",[["path",{d:"M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z",key:"1qme2f"}],["circle",{cx:"12",cy:"12",r:"3",key:"1v7zrd"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Eg=Y("Share2",[["circle",{cx:"18",cy:"5",r:"3",key:"gq8acd"}],["circle",{cx:"6",cy:"12",r:"3",key:"w7nqdw"}],["circle",{cx:"18",cy:"19",r:"3",key:"1xt0gg"}],["line",{x1:"8.59",x2:"15.42",y1:"13.51",y2:"17.49",key:"47mynk"}],["line",{x1:"15.41",x2:"8.59",y1:"6.51",y2:"10.49",key:"1n3mei"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Pg=Y("Square",[["rect",{width:"18",height:"18",x:"3",y:"3",rx:"2",key:"afitv7"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Tg=Y("Sun",[["circle",{cx:"12",cy:"12",r:"4",key:"4exip2"}],["path",{d:"M12 2v2",key:"tus03m"}],["path",{d:"M12 20v2",key:"1lh1kg"}],["path",{d:"m4.93 4.93 1.41 1.41",key:"149t6j"}],["path",{d:"m17.66 17.66 1.41 1.41",key:"ptbguv"}],["path",{d:"M2 12h2",key:"1t8f8n"}],["path",{d:"M20 12h2",key:"1q8mjw"}],["path",{d:"m6.34 17.66-1.41 1.41",key:"1m8zz5"}],["path",{d:"m19.07 4.93-1.41 1.41",key:"1shlcs"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Om=Y("Trash2",[["path",{d:"M3 6h18",key:"d0wm0j"}],["path",{d:"M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6",key:"4alrt4"}],["path",{d:"M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2",key:"v07s0e"}],["line",{x1:"10",x2:"10",y1:"11",y2:"17",key:"1uufr5"}],["line",{x1:"14",x2:"14",y1:"11",y2:"17",key:"xtxkd"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Lm=Y("User",[["path",{d:"M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2",key:"975kel"}],["circle",{cx:"12",cy:"7",r:"4",key:"17ys0d"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Og=Y("XCircle",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"m15 9-6 6",key:"1uzhvr"}],["path",{d:"m9 9 6 6",key:"z0biqf"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Rm=Y("X",[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]]);/** + * @license lucide-react v0.330.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Bi=Y("Zap",[["polygon",{points:"13 2 3 14 12 14 11 22 21 10 12 10 13 2",key:"45s27k"}]]),Lg={},bd=e=>{let t;const n=new Set,r=(h,d)=>{const m=typeof h=="function"?h(t):h;if(!Object.is(m,t)){const x=t;t=d??(typeof m!="object"||m===null)?m:Object.assign({},t,m),n.forEach(w=>w(t,x))}},s=()=>t,u={setState:r,getState:s,getInitialState:()=>c,subscribe:h=>(n.add(h),()=>n.delete(h)),destroy:()=>{(Lg?"production":void 0)!=="production"&&console.warn("[DEPRECATED] The `destroy` method will be unsupported in a future version. Instead use unsubscribe function returned by subscribe. Everything will be garbage-collected if store is garbage-collected."),n.clear()}},c=t=e(r,s,u);return u},Rg=e=>e?bd(e):bd;var Mm={exports:{}},zm={},Fm={exports:{}},Im={};/** + * @license React + * use-sync-external-store-shim.production.js + * + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var Jr=k;function Mg(e,t){return e===t&&(e!==0||1/e===1/t)||e!==e&&t!==t}var zg=typeof Object.is=="function"?Object.is:Mg,Fg=Jr.useState,Ig=Jr.useEffect,Dg=Jr.useLayoutEffect,Ag=Jr.useDebugValue;function $g(e,t){var n=t(),r=Fg({inst:{value:n,getSnapshot:t}}),s=r[0].inst,a=r[1];return Dg(function(){s.value=n,s.getSnapshot=t,gl(s)&&a({inst:s})},[e,n,t]),Ig(function(){return gl(s)&&a({inst:s}),e(function(){gl(s)&&a({inst:s})})},[e]),Ag(n),n}function gl(e){var t=e.getSnapshot;e=e.value;try{var n=t();return!zg(e,n)}catch{return!0}}function Ug(e,t){return t()}var Bg=typeof window>"u"||typeof window.document>"u"||typeof window.document.createElement>"u"?Ug:$g;Im.useSyncExternalStore=Jr.useSyncExternalStore!==void 0?Jr.useSyncExternalStore:Bg;Fm.exports=Im;var Qg=Fm.exports;/** + * @license React + * use-sync-external-store-shim/with-selector.production.js + * + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var Qi=k,Vg=Qg;function Kg(e,t){return e===t&&(e!==0||1/e===1/t)||e!==e&&t!==t}var Hg=typeof Object.is=="function"?Object.is:Kg,Wg=Vg.useSyncExternalStore,qg=Qi.useRef,Jg=Qi.useEffect,Gg=Qi.useMemo,Yg=Qi.useDebugValue;zm.useSyncExternalStoreWithSelector=function(e,t,n,r,s){var a=qg(null);if(a.current===null){var l={hasValue:!1,value:null};a.current=l}else l=a.current;a=Gg(function(){function u(x){if(!c){if(c=!0,h=x,x=r(x),s!==void 0&&l.hasValue){var w=l.value;if(s(w,x))return d=w}return d=x}if(w=d,Hg(h,x))return w;var j=r(x);return s!==void 0&&s(w,j)?(h=x,w):(h=x,d=j)}var c=!1,h,d,m=n===void 0?null:n;return[function(){return u(t())},m===null?void 0:function(){return u(m())}]},[t,n,r,s]);var o=Wg(e,a[0],a[1]);return Jg(function(){l.hasValue=!0,l.value=o},[o]),Yg(o),o};Mm.exports=zm;var Xg=Mm.exports;const Zg=Vd(Xg),Dm={},{useDebugValue:e0}=Qo,{useSyncExternalStoreWithSelector:t0}=Zg;let Cd=!1;const n0=e=>e;function r0(e,t=n0,n){(Dm?"production":void 0)!=="production"&&n&&!Cd&&(console.warn("[DEPRECATED] Use `createWithEqualityFn` instead of `create` or use `useStoreWithEqualityFn` instead of `useStore`. They can be imported from 'zustand/traditional'. https://github.com/pmndrs/zustand/discussions/1937"),Cd=!0);const r=t0(e.subscribe,e.getState,e.getServerState||e.getInitialState,t,n);return e0(r),r}const _d=e=>{(Dm?"production":void 0)!=="production"&&typeof e!="function"&&console.warn("[DEPRECATED] Passing a vanilla store will be unsupported in a future version. Instead use `import { useStore } from 'zustand'`.");const t=typeof e=="function"?Rg(e):e,n=(r,s)=>r0(t,r,s);return Object.assign(n,t),n},$u=e=>e?_d(e):_d,Vi="/api",Uu="flow_auth_token",Bu="flow_auth_expires",Qu="flow_auth_username";function Ys(){const e=localStorage.getItem(Uu),t=localStorage.getItem(Bu);return!e||!t?null:new Date(t)<=new Date?(Yn(),null):e}function Ed(e,t,n){localStorage.setItem(Uu,e),localStorage.setItem(Bu,t),localStorage.setItem(Qu,n)}function Yn(){localStorage.removeItem(Uu),localStorage.removeItem(Bu),localStorage.removeItem(Qu)}function Vu(){return localStorage.getItem(Qu)}let ar=null;function s0(e){ar=e}async function Q(e,t,n=!1){const r={"Content-Type":"application/json",...t==null?void 0:t.headers};if(!n){const a=Ys();a&&(r.Authorization=`Bearer ${a}`)}const s=await fetch(`${Vi}${e}`,{...t,headers:r});if(s.status===401){Yn(),ar&&ar();const a=await s.json().catch(()=>({detail:"Not authenticated"}));throw new Error(a.detail||"Not authenticated")}if(!s.ok){const a=await s.json().catch(()=>({detail:s.statusText}));throw new Error(a.detail||"API request failed")}if(s.status!==204)return s.json()}const ur={getConfig:()=>Q("/auth/config",void 0,!0),login:e=>Q("/auth/login",{method:"POST",body:JSON.stringify(e)},!0),getGitHubAuthUrl:()=>`${Vi}/auth/github`,getCurrentUser:()=>Q("/auth/me"),logout:()=>Q("/auth/logout",{method:"POST"})},Er={list:e=>{const t=new URLSearchParams;e!=null&&e.include_auto_generated&&t.set("include_auto_generated","true"),e!=null&&e.include_public&&t.set("include_public","true");const n=t.toString();return Q(`/configs${n?`?${n}`:""}`)},get:e=>Q(`/configs/${e}`),create:e=>Q("/configs",{method:"POST",body:JSON.stringify(e)}),update:(e,t)=>Q(`/configs/${e}`,{method:"PUT",body:JSON.stringify(t)}),delete:e=>Q(`/configs/${e}`,{method:"DELETE"})},Et={list:e=>{const t=new URLSearchParams;e!=null&&e.category&&t.set("category",e.category),e!=null&&e.suite&&t.set("suite",e.suite);const n=t.toString();return Q(`/tasks${n?`?${n}`:""}`)},get:e=>Q(`/tasks/${e}`),create:e=>Q("/tasks",{method:"POST",body:JSON.stringify(e)}),update:(e,t)=>Q(`/tasks/${e}`,{method:"PUT",body:JSON.stringify(t)}),delete:e=>Q(`/tasks/${e}`,{method:"DELETE"}),listSuites:()=>Q("/tasks/suites"),importSuite:e=>Q(`/tasks/import-suite?suite_name=${encodeURIComponent(e)}`,{method:"POST"})},Ot={list:e=>{const t=new URLSearchParams;e!=null&&e.status&&t.set("status",e.status),e!=null&&e.include_public&&t.set("include_public","true");const n=t.toString();return Q(`/jobs${n?`?${n}`:""}`)},get:e=>Q(`/jobs/${e}`),create:e=>Q("/jobs",{method:"POST",body:JSON.stringify(e)}),update:(e,t)=>Q(`/jobs/${e}`,{method:"PUT",body:JSON.stringify(t)}),start:async function*(e){var o;const t={},n=Ys();n&&(t.Authorization=`Bearer ${n}`);const r=await fetch(`${Vi}/jobs/${e}/start`,{method:"POST",headers:t});if(r.status===401)throw Yn(),ar&&ar(),new Error("Not authenticated");if(!r.ok)throw new Error("Failed to start job");const s=(o=r.body)==null?void 0:o.getReader();if(!s)throw new Error("No response body");const a=new TextDecoder;let l="";for(;;){const{done:u,value:c}=await s.read();if(u)break;l+=a.decode(c,{stream:!0});const h=l.split(` +`);l=h.pop()||"";for(const d of h)d.startsWith("data: ")&&(yield JSON.parse(d.slice(6)))}},cancel:e=>Q(`/jobs/${e}/cancel`,{method:"POST"}),delete:e=>Q(`/jobs/${e}`,{method:"DELETE"})},Mo={list:e=>{const t=new URLSearchParams;e!=null&&e.job_id&&t.set("job_id",e.job_id),e!=null&&e.candidate_name&&t.set("candidate_name",e.candidate_name),e!=null&&e.task_name&&t.set("task_name",e.task_name),(e==null?void 0:e.is_pareto)!==void 0&&t.set("is_pareto",String(e.is_pareto));const n=t.toString();return Q(`/runs${n?`?${n}`:""}`)},get:e=>Q(`/runs/${e}`),getJobSummary:e=>Q(`/runs/job/${e}/summary`)},Es={list:e=>{const t=new URLSearchParams;e!=null&&e.agent_id&&t.set("agent_id",e.agent_id),e!=null&&e.limit&&t.set("limit",String(e.limit));const n=t.toString();return Q(`/tests${n?`?${n}`:""}`)},get:e=>Q(`/tests/${e}`),create:e=>Q("/tests",{method:"POST",body:JSON.stringify(e)}),start:async function*(e){var o;const t={},n=Ys();n&&(t.Authorization=`Bearer ${n}`);const r=await fetch(`${Vi}/tests/${e}/start`,{method:"POST",headers:t});if(r.status===401)throw Yn(),ar&&ar(),new Error("Not authenticated");if(!r.ok){const u=await r.json().catch(()=>({detail:"Failed to start test"}));throw new Error(u.detail||"Failed to start test")}const s=(o=r.body)==null?void 0:o.getReader();if(!s)throw new Error("No response body");const a=new TextDecoder;let l="";for(;;){const{done:u,value:c}=await s.read();if(u)break;l+=a.decode(c,{stream:!0});const h=l.split(` +`);l=h.pop()||"";for(const d of h)d.startsWith("data: ")&&(yield JSON.parse(d.slice(6)))}},cancel:e=>Q(`/tests/${e}/cancel`,{method:"POST"}),delete:e=>Q(`/tests/${e}`,{method:"DELETE"})},a0={list:()=>Q("/llm-configs"),get:e=>Q(`/llm-configs/${e}`),getDefault:()=>Q("/llm-configs/default"),create:e=>Q("/llm-configs",{method:"POST",body:JSON.stringify(e)}),update:(e,t)=>Q(`/llm-configs/${e}`,{method:"PUT",body:JSON.stringify(t)}),delete:e=>Q(`/llm-configs/${e}`,{method:"DELETE"}),setDefault:e=>Q(`/llm-configs/${e}/set-default`,{method:"POST"}),test:e=>Q(`/llm-configs/${e}/test`,{method:"POST"})},i0={list:()=>Q("/tools"),get:e=>Q(`/tools/${e}`)},Am={getAgentSchema:()=>Q("/schema/agent")},l0={start:e=>Q("/evaluate",{method:"POST",body:JSON.stringify(e)})},zo={design:e=>Q("/experiment/design",{method:"POST",body:JSON.stringify(e)}),importYaml:e=>Q("/experiment/import-yaml",{method:"POST",body:JSON.stringify(e)}),validate:e=>Q("/experiment/validate",{method:"POST",body:JSON.stringify(e)}),generateCandidates:e=>Q("/experiment/generate-candidates",{method:"POST",body:JSON.stringify(e)})},Ku=$u((e,t)=>(s0(()=>{e({isAuthenticated:!1,user:null,error:"Session expired. Please log in again."})}),{authConfig:null,isLoadingConfig:!0,isAuthenticated:!1,isLoading:!1,user:null,error:null,loadAuthConfig:async()=>{e({isLoadingConfig:!0});try{const n=await ur.getConfig();if(e({authConfig:n,isLoadingConfig:!1}),n.enabled){const r=Ys(),s=Vu();if(r&&s)try{const a=await ur.getCurrentUser();e({isAuthenticated:!0,user:a})}catch{Yn(),e({isAuthenticated:!1,user:null})}}else e({isAuthenticated:!0,user:{username:"anonymous",auth_mode:"none"}})}catch(n){console.error("Failed to load auth config:",n),e({isLoadingConfig:!1,error:"Failed to connect to server"})}},login:async(n,r)=>{e({isLoading:!0,error:null});try{const s=await ur.login({username:n,password:r});return Ed(s.access_token,s.expires_at,s.username),e({isAuthenticated:!0,isLoading:!1,user:{username:s.username,auth_mode:"basic"}}),!0}catch(s){return e({isLoading:!1,error:s instanceof Error?s.message:"Login failed"}),!1}},loginWithGitHub:()=>{window.location.href=ur.getGitHubAuthUrl()},handleOAuthCallback:()=>{const n=new URLSearchParams(window.location.search),r=n.get("auth_error");if(r)return e({error:r}),window.history.replaceState({},"",window.location.pathname),!0;if(n.get("auth_callback")==="true"){const s=n.get("token"),a=n.get("expires_at"),l=n.get("username");return s&&a&&l&&(Ed(s,a,l),e({isAuthenticated:!0,user:{username:l,auth_mode:"github"}})),window.history.replaceState({},"",window.location.pathname),!0}return!1},logout:async()=>{try{await ur.logout()}catch{}Yn(),e({isAuthenticated:!1,user:null,error:null})},checkAuth:async()=>{const{authConfig:n}=t();if(!(n!=null&&n.enabled)){e({isAuthenticated:!0});return}if(!Ys()){e({isAuthenticated:!1,user:null});return}try{const s=await ur.getCurrentUser();e({isAuthenticated:!0,user:s})}catch{Yn(),e({isAuthenticated:!1,user:null})}},clearError:()=>e({error:null})}));function V({variant:e="secondary",size:t="md",className:n="",icon:r,iconRight:s,loading:a=!1,children:l,disabled:o,...u}){const c="font-medium transition-colors disabled:opacity-50 disabled:cursor-not-allowed inline-flex items-center gap-1.5",h={primary:"bg-[var(--accent)] text-black hover:bg-[#16a34a]",secondary:"bg-[var(--bg-tertiary)] text-[var(--text-primary)] border border-[var(--border)] hover:bg-[var(--border)]",danger:"bg-[var(--error)] text-white hover:bg-red-600",ghost:"text-[var(--text-secondary)] hover:text-[var(--text-primary)] hover:bg-[var(--bg-tertiary)]"},d={sm:"px-2 py-1 text-xs",md:"px-3 py-1.5 text-sm"},m=t==="sm"?14:16;return i.jsxs("button",{className:`${c} ${h[e]} ${d[t]} ${n}`,disabled:o||a,...u,children:[a?i.jsx(ca,{size:m,className:"animate-spin"}):r?i.jsx(r,{size:m}):null,l,s&&!a&&i.jsx(s,{size:m})]})}const o0={};function u0(e,t){let n;try{n=e()}catch{return}return{getItem:s=>{var a;const l=u=>u===null?null:JSON.parse(u,void 0),o=(a=n.getItem(s))!=null?a:null;return o instanceof Promise?o.then(l):l(o)},setItem:(s,a)=>n.setItem(s,JSON.stringify(a,void 0)),removeItem:s=>n.removeItem(s)}}const Xs=e=>t=>{try{const n=e(t);return n instanceof Promise?n:{then(r){return Xs(r)(n)},catch(r){return this}}}catch(n){return{then(r){return this},catch(r){return Xs(r)(n)}}}},c0=(e,t)=>(n,r,s)=>{let a={getStorage:()=>localStorage,serialize:JSON.stringify,deserialize:JSON.parse,partialize:S=>S,version:0,merge:(S,p)=>({...p,...S}),...t},l=!1;const o=new Set,u=new Set;let c;try{c=a.getStorage()}catch{}if(!c)return e((...S)=>{console.warn(`[zustand persist middleware] Unable to update item '${a.name}', the given storage is currently unavailable.`),n(...S)},r,s);const h=Xs(a.serialize),d=()=>{const S=a.partialize({...r()});let p;const f=h({state:S,version:a.version}).then(v=>c.setItem(a.name,v)).catch(v=>{p=v});if(p)throw p;return f},m=s.setState;s.setState=(S,p)=>{m(S,p),d()};const x=e((...S)=>{n(...S),d()},r,s);let w;const j=()=>{var S;if(!c)return;l=!1,o.forEach(f=>f(r()));const p=((S=a.onRehydrateStorage)==null?void 0:S.call(a,r()))||void 0;return Xs(c.getItem.bind(c))(a.name).then(f=>{if(f)return a.deserialize(f)}).then(f=>{if(f)if(typeof f.version=="number"&&f.version!==a.version){if(a.migrate)return a.migrate(f.state,f.version);console.error("State loaded from storage couldn't be migrated since no migrate function was provided")}else return f.state}).then(f=>{var v;return w=a.merge(f,(v=r())!=null?v:x),n(w,!0),d()}).then(()=>{p==null||p(w,void 0),l=!0,u.forEach(f=>f(w))}).catch(f=>{p==null||p(void 0,f)})};return s.persist={setOptions:S=>{a={...a,...S},S.getStorage&&(c=S.getStorage())},clearStorage:()=>{c==null||c.removeItem(a.name)},getOptions:()=>a,rehydrate:()=>j(),hasHydrated:()=>l,onHydrate:S=>(o.add(S),()=>{o.delete(S)}),onFinishHydration:S=>(u.add(S),()=>{u.delete(S)})},j(),w||x},d0=(e,t)=>(n,r,s)=>{let a={storage:u0(()=>localStorage),partialize:j=>j,version:0,merge:(j,S)=>({...S,...j}),...t},l=!1;const o=new Set,u=new Set;let c=a.storage;if(!c)return e((...j)=>{console.warn(`[zustand persist middleware] Unable to update item '${a.name}', the given storage is currently unavailable.`),n(...j)},r,s);const h=()=>{const j=a.partialize({...r()});return c.setItem(a.name,{state:j,version:a.version})},d=s.setState;s.setState=(j,S)=>{d(j,S),h()};const m=e((...j)=>{n(...j),h()},r,s);s.getInitialState=()=>m;let x;const w=()=>{var j,S;if(!c)return;l=!1,o.forEach(f=>{var v;return f((v=r())!=null?v:m)});const p=((S=a.onRehydrateStorage)==null?void 0:S.call(a,(j=r())!=null?j:m))||void 0;return Xs(c.getItem.bind(c))(a.name).then(f=>{if(f)if(typeof f.version=="number"&&f.version!==a.version){if(a.migrate)return[!0,a.migrate(f.state,f.version)];console.error("State loaded from storage couldn't be migrated since no migrate function was provided")}else return[!1,f.state];return[!1,void 0]}).then(f=>{var v;const[g,C]=f;if(x=a.merge(C,(v=r())!=null?v:m),n(x,!0),g)return h()}).then(()=>{p==null||p(x,void 0),x=r(),l=!0,u.forEach(f=>f(x))}).catch(f=>{p==null||p(void 0,f)})};return s.persist={setOptions:j=>{a={...a,...j},j.storage&&(c=j.storage)},clearStorage:()=>{c==null||c.removeItem(a.name)},getOptions:()=>a,rehydrate:()=>w(),hasHydrated:()=>l,onHydrate:j=>(o.add(j),()=>{o.delete(j)}),onFinishHydration:j=>(u.add(j),()=>{u.delete(j)})},a.skipHydration||w(),x||m},f0=(e,t)=>"getStorage"in t||"serialize"in t||"deserialize"in t?((o0?"production":void 0)!=="production"&&console.warn("[DEPRECATED] `getStorage`, `serialize` and `deserialize` options are deprecated. Use `storage` option instead."),c0(e,t)):d0(e,t),h0=f0,m0=$u()(h0((e,t)=>({theme:"dark",setTheme:n=>{document.documentElement.setAttribute("data-theme",n),e({theme:n})},toggleTheme:()=>{const n=t().theme==="dark"?"light":"dark";document.documentElement.setAttribute("data-theme",n),e({theme:n})}}),{name:"flow-theme",onRehydrateStorage:()=>e=>{e!=null&&e.theme&&document.documentElement.setAttribute("data-theme",e.theme)}}));function p0(){const{theme:e,toggleTheme:t}=m0();return i.jsx("button",{onClick:t,className:"p-2 rounded-md text-[var(--text-secondary)] hover:text-[var(--text-primary)] hover:bg-[var(--bg-tertiary)] transition-colors focus:outline-none focus:ring-2 focus:ring-[var(--accent)]","aria-label":`Switch to ${e==="dark"?"light":"dark"} mode`,title:`Switch to ${e==="dark"?"light":"dark"} mode`,children:e==="dark"?i.jsx(Tg,{size:16}):i.jsx(_g,{size:16})})}const v0=[{path:"/agents",label:"Agents",icon:hg},{path:"/jobs",label:"Experiments",icon:wg},{path:"/tasks",label:"Datasets",icon:gg}];function x0(){const e=ts(),{authConfig:t,user:n,logout:r}=Ku(),s=l=>l==="/agents"?e.pathname==="/"||e.pathname==="/agents":e.pathname.startsWith(l),a=async()=>{await r()};return i.jsxs("div",{className:"min-h-screen flex flex-col",children:[i.jsx("header",{className:"border-b border-[var(--border)] bg-[var(--bg-secondary)]",children:i.jsxs("div",{className:"max-w-7xl mx-auto px-4 py-3 flex items-center justify-between",children:[i.jsxs("div",{className:"flex items-center gap-8",children:[i.jsxs(kd,{to:"/",className:"text-lg font-bold text-[var(--accent)] flex items-center gap-2 hover:opacity-80",children:[i.jsx(Bi,{size:20}),"flow",i.jsx("span",{className:"text-[var(--text-secondary)]",children:"/optimize"})]}),i.jsx("nav",{className:"flex gap-1",children:v0.map(l=>i.jsxs(kd,{to:l.path,className:`px-3 py-1.5 rounded text-sm transition-colors flex items-center gap-2 ${s(l.path)?"bg-[var(--accent)] text-black font-medium":"text-[var(--text-secondary)] hover:text-[var(--text-primary)] hover:bg-[var(--bg-tertiary)]"}`,children:[i.jsx(l.icon,{size:16}),l.label]},l.path))})]}),i.jsxs("div",{className:"flex items-center gap-4",children:[i.jsx(p0,{}),(t==null?void 0:t.enabled)&&n&&i.jsxs("div",{className:"flex items-center gap-3",children:[i.jsxs("div",{className:"flex items-center gap-2 text-sm text-[var(--text-secondary)]",children:[i.jsx(Lm,{size:14}),i.jsx("span",{children:n.username})]}),i.jsx(V,{variant:"ghost",size:"sm",icon:Cg,onClick:a,title:"Sign out",children:"Sign out"})]})]})]})}),i.jsx("main",{className:"flex-1 bg-[var(--bg-primary)]",children:i.jsx("div",{className:"max-w-7xl mx-auto p-4",children:i.jsx(Wy,{})})})]})}const y0=["maf","miniagent","langgraph"],g0={maf:"Microsoft Agent Framework",miniagent:"MiniAgent",langgraph:"LangGraph"},j0={openai:"OpenAI",azure_openai:"Azure OpenAI",anthropic:"Anthropic",ollama:"Ollama",custom:"Custom (OpenAI-compatible)"};function se({children:e,className:t="",onClick:n,selected:r=!1,selectable:s=!1}){const a="bg-[var(--bg-secondary)] border border-[var(--border)] p-4",l=s?"cursor-pointer hover:border-[var(--accent-dim)] transition-colors":"",o=r?"border-[var(--accent)]":"";return i.jsx("div",{className:`${a} ${l} ${o} ${t}`,onClick:n,children:e})}function J({children:e,variant:t="default"}){const n={default:"bg-[var(--bg-tertiary)] text-[var(--text-primary)] border border-[var(--border)]",success:"bg-green-600 text-white",warning:"bg-yellow-500 text-black",error:"bg-red-600 text-white",info:"bg-blue-600 text-white"};return i.jsx("span",{className:`inline-block px-2 py-0.5 text-xs font-medium rounded ${n[t]}`,children:e})}const w0={pending:"default",running:"info",completed:"success",failed:"error",cancelled:"warning"};function $m({job:e,onDelete:t}){const n=Lt(),r=e.total_experiments>0?e.completed_experiments/e.total_experiments*100:0;return i.jsxs(se,{className:"cursor-pointer hover:border-[var(--accent-dim)] flex flex-col",onClick:()=>n(`/jobs/${e.id}`),children:[i.jsxs("div",{className:"flex items-start justify-between mb-3",children:[i.jsxs("div",{className:"flex-1 min-w-0",children:[i.jsxs("div",{className:"flex items-center gap-2 flex-wrap",children:[i.jsx(J,{variant:w0[e.status]||"default",children:e.status}),e.is_public&&i.jsxs(J,{variant:"info",children:[i.jsx($i,{className:"w-3 h-3 mr-1 inline"}),"Public"]}),e.pareto_frontier.length>0&&i.jsxs(J,{variant:"success",children:[e.pareto_frontier.length," Optimal"]}),e.use_llm_eval&&i.jsx(J,{children:"LLM"})]}),i.jsx("h3",{className:"font-medium mt-2 truncate",title:e.name||`Job ${e.id.slice(0,8)}`,children:e.name||`Job ${e.id.slice(0,8)}`}),i.jsxs("code",{className:"text-xs text-[var(--text-secondary)] font-mono",children:[e.id.slice(0,8),"..."]})]}),t&&i.jsx(V,{variant:"ghost",size:"sm",onClick:s=>{s.stopPropagation(),confirm("Delete this job?")&&t(e.id)},disabled:e.status==="running",children:"×"})]}),(e.status==="running"||e.status==="completed")&&i.jsxs("div",{className:"mb-3",children:[i.jsxs("div",{className:"flex justify-between text-xs text-[var(--text-secondary)] mb-1",children:[i.jsx("span",{children:"Progress"}),i.jsxs("span",{children:[e.completed_experiments,"/",e.total_experiments]})]}),i.jsx("div",{className:"w-full bg-[var(--bg-primary)] h-1.5 rounded-full overflow-hidden",children:i.jsx("div",{className:`h-full transition-all ${e.status==="completed"?"bg-green-500":"bg-[var(--accent)]"}`,style:{width:`${r}%`}})})]}),e.status==="failed"&&e.error&&i.jsx("div",{className:"mb-3 px-2 py-1.5 bg-red-500/10 border border-red-500/30 rounded text-xs text-red-400 line-clamp-2",children:e.error}),i.jsxs("div",{className:"grid grid-cols-3 gap-2 text-center py-2 border-t border-[var(--border)] mt-auto",children:[i.jsxs("div",{children:[i.jsx("div",{className:"text-lg font-bold",children:e.candidate_ids.length}),i.jsx("div",{className:"text-xs text-[var(--text-secondary)]",children:"candidates"})]}),i.jsxs("div",{children:[i.jsx("div",{className:"text-lg font-bold",children:e.task_ids.length}),i.jsx("div",{className:"text-xs text-[var(--text-secondary)]",children:"tasks"})]}),i.jsxs("div",{children:[i.jsx("div",{className:"text-lg font-bold",children:e.total_experiments}),i.jsx("div",{className:"text-xs text-[var(--text-secondary)]",children:"runs"})]})]}),i.jsxs("div",{className:"text-xs text-[var(--text-secondary)] pt-2 border-t border-[var(--border)] flex justify-between items-center",children:[i.jsxs("span",{children:[new Date(e.created_at).toLocaleDateString()," ",new Date(e.created_at).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})]}),e.is_public&&e.created_by_name&&i.jsxs("span",{className:"text-[var(--text-secondary)]",children:["by ",e.created_by_name]})]})]})}const k0={sm:"max-w-sm",md:"max-w-lg",lg:"max-w-2xl",xl:"max-w-4xl"};function ns({isOpen:e,onClose:t,title:n,children:r,footer:s,size:a="md"}){return k.useEffect(()=>{const l=o=>{o.key==="Escape"&&t()};return e&&(document.addEventListener("keydown",l),document.body.style.overflow="hidden"),()=>{document.removeEventListener("keydown",l),document.body.style.overflow=""}},[e,t]),e?i.jsxs("div",{className:"fixed inset-0 z-50 flex items-center justify-center",children:[i.jsx("div",{className:"absolute inset-0 bg-black/80",onClick:t}),i.jsxs("div",{className:`relative bg-[var(--bg-secondary)] border border-[var(--border)] ${k0[a]} w-full mx-4 max-h-[80vh] flex flex-col`,children:[i.jsxs("div",{className:"flex-shrink-0 bg-[var(--bg-secondary)] border-b border-[var(--border)] px-4 py-3 flex items-center justify-between",children:[i.jsx("h2",{className:"font-semibold",children:n}),i.jsx("button",{onClick:t,className:"text-[var(--text-secondary)] hover:text-[var(--text-primary)]",children:"×"})]}),i.jsx("div",{className:"flex-1 overflow-y-auto p-4",children:r}),s&&i.jsx("div",{className:"flex-shrink-0 bg-[var(--bg-secondary)] border-t border-[var(--border)] px-4 py-3",children:s})]})]}):null}function vn({label:e,className:t="",...n}){return i.jsxs("div",{className:"space-y-1",children:[e&&i.jsx("label",{className:"block text-sm text-[var(--text-secondary)]",children:e}),i.jsx("input",{className:`w-full bg-[var(--bg-primary)] border border-[var(--border)] px-3 py-2 text-sm focus:outline-none focus:border-[var(--accent)] ${t}`,...n})]})}function S0({label:e,className:t="",...n}){return i.jsxs("div",{className:"space-y-1",children:[e&&i.jsx("label",{className:"block text-sm text-[var(--text-secondary)]",children:e}),i.jsx("textarea",{className:`w-full bg-[var(--bg-primary)] border border-[var(--border)] px-3 py-2 text-sm focus:outline-none focus:border-[var(--accent)] resize-y min-h-[100px] ${t}`,...n})]})}function Fo({label:e,className:t="",...n}){return i.jsxs("label",{className:`flex items-center gap-2 cursor-pointer ${t}`,children:[i.jsx("input",{type:"checkbox",className:"w-4 h-4 bg-[var(--bg-primary)] border border-[var(--border)] accent-[var(--accent)]",...n}),i.jsx("span",{className:"text-sm",children:e})]})}function N0({variations:e,onChange:t,strategies:n,availableStrategies:r}){const s=r??Object.keys(n),a=()=>{const c=e.map(x=>x.strategy),h=s.find(x=>!c.includes(x))||"none",d=n[h],m={strategy:h};if(d!=null&&d.params)for(const[x,w]of Object.entries(d.params))w.default!==void 0&&(m[x]=w.default);t([...e,m])},l=c=>{t(e.filter((h,d)=>d!==c))},o=(c,h)=>{t(e.map((d,m)=>m===c?{...d,...h}:d))},u=(c,h)=>{const d=n[h],m={strategy:h};if(d!=null&&d.params)for(const[x,w]of Object.entries(d.params))w.default!==void 0&&(m[x]=w.default);o(c,m)};return i.jsxs("div",{className:"space-y-3",children:[i.jsxs("div",{className:"flex items-center justify-between",children:[i.jsx("label",{className:"text-sm font-medium",children:"Compaction Strategies"}),i.jsx(V,{type:"button",variant:"ghost",size:"sm",icon:Ui,onClick:a,disabled:e.length>=s.length,children:"Add"})]}),e.length===0?i.jsx("p",{className:"text-sm text-[var(--text-secondary)] italic",children:'No compaction variations. Click "Add" to test different strategies.'}):i.jsx("div",{className:"space-y-2",children:e.map((c,h)=>{const d=n[c.strategy];return i.jsx("div",{className:"p-3 border border-[var(--border)] rounded bg-[var(--bg-secondary)]",children:i.jsxs("div",{className:"flex items-start justify-between gap-2",children:[i.jsxs("div",{className:"flex-1 space-y-2",children:[i.jsx("select",{className:"w-full px-2 py-1.5 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm",value:c.strategy,onChange:m=>u(h,m.target.value),children:s.map(m=>{var x;return i.jsx("option",{value:m,children:((x=n[m])==null?void 0:x.label)||m},m)})}),(d==null?void 0:d.description)&&i.jsx("p",{className:"text-xs text-[var(--text-secondary)]",children:d.description}),(d==null?void 0:d.params)&&Object.keys(d.params).length>0&&i.jsx("div",{className:"grid grid-cols-2 gap-2 mt-2",children:Object.entries(d.params).map(([m,x])=>i.jsx(b0,{name:m,schema:x,value:c[m],onChange:w=>o(h,{[m]:w})},m))})]}),i.jsx("button",{type:"button",onClick:()=>l(h),className:"p-1 text-[var(--text-secondary)] hover:text-[var(--error)] transition-colors",children:i.jsx(Rm,{size:16})})]})},h)})})]})}function b0({name:e,schema:t,value:n,onChange:r}){const s=e.replace(/_/g," ");return t.type==="boolean"?i.jsxs("label",{className:"flex items-center gap-2 text-xs",children:[i.jsx("input",{type:"checkbox",checked:!!(n??t.default),onChange:a=>r(a.target.checked),className:"accent-[var(--accent)]"}),i.jsx("span",{className:"capitalize",children:s})]}):i.jsxs("div",{children:[i.jsx("label",{className:"text-xs font-medium block mb-1 capitalize",children:s}),i.jsx("input",{type:t.type==="number"?"number":"text",className:"w-full px-2 py-1 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-xs",value:String(n!==void 0?n:t.default??""),onChange:a=>{if(t.type==="number"){const l=parseFloat(a.target.value);r(isNaN(l)?t.default:l)}else r(a.target.value)},min:t.min,max:t.max,step:t.max&&t.max<=1?.1:1})]})}function C0({variations:e,onChange:t,providers:n}){const r=()=>{const o=n[0],u={provider:(o==null?void 0:o.name)||"azure_openai",model:(o==null?void 0:o.models[0])||"gpt-4o"};t([...e,u])},s=o=>{t(e.filter((u,c)=>c!==o))},a=(o,u)=>{t(e.map((c,h)=>h===o?{...c,...u}:c))},l=(o,u)=>{const c=n.find(h=>h.name===u);a(o,{provider:u,model:(c==null?void 0:c.models[0])||""})};return i.jsxs("div",{className:"space-y-3",children:[i.jsxs("div",{className:"flex items-center justify-between",children:[i.jsx("label",{className:"text-sm font-medium",children:"LLM Configurations"}),i.jsx(V,{type:"button",variant:"ghost",size:"sm",icon:Ui,onClick:r,children:"Add"})]}),e.length===0?i.jsx("p",{className:"text-sm text-[var(--text-secondary)] italic",children:`Uses agent's default LLM. Click "Add" to test different models.`}):i.jsx("div",{className:"space-y-2",children:e.map((o,u)=>{const c=n.find(h=>h.name===o.provider);return i.jsxs("div",{className:"flex items-center gap-2 p-2 border border-[var(--border)] rounded bg-[var(--bg-secondary)]",children:[i.jsx("select",{className:"flex-1 px-2 py-1.5 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm",value:o.provider,onChange:h=>l(u,h.target.value),children:n.map(h=>i.jsx("option",{value:h.name,children:h.label},h.name))}),c&&c.models.length>0?i.jsxs("select",{className:"flex-1 px-2 py-1.5 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm",value:o.model,onChange:h=>a(u,{model:h.target.value}),children:[c.models.map(h=>i.jsx("option",{value:h,children:h},h)),!c.models.includes(o.model)&&o.model&&i.jsx("option",{value:o.model,children:o.model})]}):i.jsx("input",{type:"text",className:"flex-1 px-2 py-1.5 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm",value:o.model,onChange:h=>a(u,{model:h.target.value}),placeholder:"Model ID"}),i.jsx("button",{type:"button",onClick:()=>s(u),className:"p-1 text-[var(--text-secondary)] hover:text-[var(--error)] transition-colors",children:i.jsx(Rm,{size:16})})]},u)})})]})}const Io={compaction:[],tools:[],llm_config:[],instructions:[],instruction_strategies:[]};function _0({agentId:e,agentName:t,agentFramework:n="maf",taskSuite:r,taskCount:s,schema:a,onVariationsChange:l,parallel:o,onParallelChange:u,budget:c,onBudgetChange:h,useLlmEval:d,onUseLlmEvalChange:m}){const[x,w]=k.useState(Io),[j,S]=k.useState(!1),[p,f]=k.useState(""),[v,g]=k.useState(null),C=a.frameworks[n],b=(C==null?void 0:C.compaction_strategies)||Object.keys(a.compaction_strategies),N=a.tool_presets||[],_=a.llm_providers||[],P=(()=>{let L=1;x.compaction.length>0&&(L*=x.compaction.length),x.tools.length>0&&(L*=x.tools.length),x.llm_config.length>0&&(L*=x.llm_config.length);const K=x.instructions.length+x.instruction_strategies.reduce((X,R)=>X+R.max_candidates,0);return K>0&&(L*=K),Math.min(L,c)})(),B=P*s,D=L=>{w(L),l==null||l(L)},U=Je({mutationFn:L=>zo.design(L),onSuccess:L=>{f(L.yaml_content),S(!0)}}),ne=Je({mutationFn:L=>zo.validate(L),onSuccess:L=>{g({valid:L.valid,errors:L.errors,warnings:L.warnings})}}),je=()=>({base_agent_id:e,task_suite:r,variations:x,parallel:o,budget:c,use_llm_eval:d}),Ge=()=>{U.mutate(je())},ie=()=>{ne.mutate(je())},T=()=>{const L=new Blob([p],{type:"text/yaml"}),K=URL.createObjectURL(L),X=document.createElement("a");X.href=K,X.download=`${t}_experiment.yaml`,X.click(),URL.revokeObjectURL(K)},A=x.compaction.length>0||x.tools.length>0||x.llm_config.length>0||x.instructions.length>0||x.instruction_strategies.length>0;return i.jsxs("div",{className:"space-y-6",children:[i.jsxs("div",{className:"flex flex-wrap gap-2",children:[i.jsxs(J,{variant:"info",children:[P," candidates"]}),i.jsxs(J,{children:[s," tasks"]}),i.jsxs(J,{variant:B>100?"warning":"success",children:[B," total runs"]})]}),i.jsx(N0,{variations:x.compaction,onChange:L=>D({...x,compaction:L}),strategies:a.compaction_strategies,availableStrategies:b}),i.jsxs("div",{className:"space-y-3",children:[i.jsx("label",{className:"text-sm font-medium",children:"Tool Presets"}),i.jsx("div",{className:"flex flex-wrap gap-2",children:N.map(L=>i.jsxs("label",{className:`flex items-center gap-2 px-3 py-1.5 border rounded cursor-pointer transition-colors ${x.tools.includes(L.name)?"border-[var(--accent)] bg-[var(--accent)]/10":"border-[var(--border)] hover:border-[var(--accent-dim)]"}`,children:[i.jsx("input",{type:"checkbox",checked:x.tools.includes(L.name),onChange:K=>{const X=K.target.checked?[...x.tools,L.name]:x.tools.filter(R=>R!==L.name);D({...x,tools:X})},className:"accent-[var(--accent)]"}),i.jsx("span",{className:"text-sm",children:L.name}),i.jsxs("span",{className:"text-xs text-[var(--text-secondary)]",children:["(",L.tools.length,")"]})]},L.name))}),x.tools.length>0&&i.jsxs("p",{className:"text-xs text-[var(--text-secondary)]",children:["Selected: ",x.tools.join(", ")]})]}),i.jsx(C0,{variations:x.llm_config,onChange:L=>D({...x,llm_config:L}),providers:_}),i.jsxs("div",{className:"border-t border-[var(--border)] pt-4 space-y-4",children:[i.jsx("h4",{className:"text-sm font-medium",children:"Execution Settings"}),i.jsxs("div",{className:"grid grid-cols-2 gap-4",children:[i.jsx(vn,{label:"Parallel Workers",type:"number",value:o,onChange:L=>u(parseInt(L.target.value)||1),min:1,max:16}),i.jsx(vn,{label:"Budget (max candidates)",type:"number",value:c,onChange:L=>h(parseInt(L.target.value)||100),min:1,max:1e3})]}),i.jsx(Fo,{label:"Use LLM evaluation",checked:d,onChange:L=>m(L.target.checked)}),i.jsx("p",{className:"text-xs text-[var(--text-secondary)] ml-6 -mt-2",children:d?"LLM-as-Judge scores task completion (0-1)":"Simple pass/fail based on task success"})]}),i.jsxs("div",{className:"flex items-center gap-2 border-t border-[var(--border)] pt-4",children:[i.jsx(V,{variant:"secondary",size:"sm",onClick:ie,loading:ne.isPending,children:"Validate"}),i.jsx(V,{variant:"secondary",size:"sm",icon:Nd,onClick:Ge,loading:U.isPending,children:"Export YAML"})]}),v&&i.jsxs("div",{className:`p-3 rounded border ${v.valid?"border-green-500/50 bg-green-500/10":"border-red-500/50 bg-red-500/10"}`,children:[i.jsxs("div",{className:"flex items-center gap-2 mb-2",children:[v.valid?i.jsx(Em,{size:16,className:"text-green-500"}):i.jsx(_m,{size:16,className:"text-red-500"}),i.jsx("span",{className:"font-medium text-sm",children:v.valid?"Configuration valid":"Configuration has issues"})]}),v.errors.length>0&&i.jsx("ul",{className:"text-sm text-red-500 list-disc ml-6",children:v.errors.map((L,K)=>i.jsx("li",{children:L},K))}),v.warnings.length>0&&i.jsx("ul",{className:"text-sm text-yellow-500 list-disc ml-6 mt-1",children:v.warnings.map((L,K)=>i.jsx("li",{children:L},K))})]}),j&&i.jsx("div",{className:"fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4",children:i.jsxs("div",{className:"bg-[var(--bg-primary)] rounded-lg shadow-xl max-w-2xl w-full max-h-[80vh] flex flex-col",children:[i.jsxs("div",{className:"flex items-center justify-between p-4 border-b border-[var(--border)]",children:[i.jsx("h3",{className:"font-medium",children:"Experiment YAML"}),i.jsxs("div",{className:"flex items-center gap-2",children:[i.jsx(V,{variant:"secondary",size:"sm",icon:Nd,onClick:T,children:"Download"}),i.jsx(V,{variant:"ghost",size:"sm",onClick:()=>S(!1),children:"Close"})]})]}),i.jsx("pre",{className:"flex-1 overflow-auto p-4 text-xs font-mono bg-[var(--bg-secondary)]",children:p})]})}),!A&&i.jsx("p",{className:"text-sm text-[var(--text-secondary)] italic",children:"No variations selected. Only the baseline agent will be tested. Add compaction strategies, tool presets, or LLM configs to generate candidates."})]})}function Pd(){const e=Lt(),t=Jt(),[n,r]=k.useState(!1),[s,a]=k.useState(null),{data:l=[],isLoading:o}=ve({queryKey:["configs"],queryFn:()=>Er.list()}),{data:u=[]}=ve({queryKey:["jobs"],queryFn:()=>Ot.list()}),c=Je({mutationFn:Er.create,onSuccess:()=>{t.invalidateQueries({queryKey:["configs"]}),r(!1)}}),h=Je({mutationFn:Er.delete,onSuccess:()=>t.invalidateQueries({queryKey:["configs"]})}),d=m=>{const x=u.filter(S=>S.candidate_ids.includes(m)),w=x.filter(S=>S.status==="running").length,j=x.filter(S=>S.status==="completed").length;return{running:w,completed:j,total:x.length}};return i.jsxs("div",{children:[i.jsxs("div",{className:"flex items-center justify-between mb-6",children:[i.jsxs("div",{children:[i.jsx("h2",{className:"text-xl font-bold",children:"Agents"}),i.jsx("p",{className:"text-sm text-[var(--text-secondary)] mt-1",children:"Define and optimize your agent configurations."})]}),i.jsx(V,{variant:"primary",icon:Ui,onClick:()=>r(!0),children:"New Agent"})]}),o?i.jsxs("div",{className:"flex items-center gap-2 text-[var(--text-secondary)]",children:[i.jsx(ca,{size:16,className:"animate-spin"}),"Loading agents..."]}):l.length===0?i.jsx(E0,{onCreateClick:()=>r(!0)}):i.jsx("div",{className:"grid gap-4 md:grid-cols-2 lg:grid-cols-3",children:l.map(m=>{const x=d(m.id);return i.jsx(T0,{agent:m,stats:x,onClick:()=>e(`/agents/${m.id}`),onOptimize:()=>a(m),onDelete:()=>{confirm(`Delete agent "${m.name}"?`)&&h.mutate(m.id)}},m.id)})}),u.length>0&&i.jsxs("div",{className:"mt-8",children:[i.jsx("h3",{className:"text-lg font-medium mb-4",children:"Recent Optimization Jobs"}),i.jsx("div",{className:"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4",children:u.slice(0,6).map(m=>i.jsx($m,{job:m},m.id))}),u.length>6&&i.jsxs(V,{variant:"ghost",className:"mt-4",onClick:()=>e("/jobs"),children:["View all ",u.length," jobs →"]})]}),i.jsx(O0,{isOpen:n,onClose:()=>r(!1),onSubmit:m=>c.mutate(m),isLoading:c.isPending}),s&&i.jsx(L0,{agent:s,isOpen:!!s,onClose:()=>a(null)})]})}function E0({onCreateClick:e}){return i.jsxs("div",{className:"text-center py-16 border border-dashed border-[var(--border)] rounded-lg",children:[i.jsx("div",{className:"inline-flex items-center justify-center w-12 h-12 rounded-full bg-[var(--bg-tertiary)] mb-4",children:i.jsx(Tm,{size:24,className:"text-[var(--text-secondary)]"})}),i.jsx("h3",{className:"text-lg font-medium mb-2",children:"No agents yet"}),i.jsx("p",{className:"text-[var(--text-secondary)] mb-4 max-w-md mx-auto",children:"Create your first agent to start optimizing. Each agent defines instructions, model, compaction strategy, and tool settings."}),i.jsx(V,{variant:"primary",icon:Ui,onClick:e,children:"Create Your First Agent"})]})}function P0(e){return typeof e=="string"?`tools: ${e}`:Array.isArray(e)?`tools: [${e.length}]`:typeof e=="object"?`tools: [${Object.keys(e).length}]`:"tools: standard"}function T0({agent:e,stats:t,onClick:n,onOptimize:r,onDelete:s}){const a=e.config.compaction,l=(a==null?void 0:a.strategy)==="head_tail"?`compaction ${a.params.head_size}/${a.params.tail_size}`:(a==null?void 0:a.strategy)==="none"?null:(a==null?void 0:a.strategy)||null,o=P0(e.config.tools),u=e.config.framework||"maf";return i.jsxs(se,{className:"flex flex-col cursor-pointer hover:border-[var(--accent-dim)] transition-colors",onClick:n,children:[i.jsxs("div",{className:"flex-1",children:[i.jsxs("div",{className:"flex items-start justify-between mb-3",children:[i.jsxs("div",{children:[i.jsx("h3",{className:"font-medium text-lg",children:e.name}),e.description&&i.jsx("p",{className:"text-sm text-[var(--text-secondary)] mt-1",children:e.description})]}),i.jsx(V,{variant:"ghost",size:"sm",icon:Om,onClick:c=>{c.stopPropagation(),s()}})]}),i.jsxs("div",{className:"flex flex-wrap gap-1.5 mb-4",children:[i.jsx(J,{variant:u==="miniagent"?"success":"default",children:u}),l&&i.jsx(J,{children:l}),i.jsx(J,{children:o})]}),t.total>0&&i.jsxs("div",{className:"text-xs text-[var(--text-secondary)] mb-3",children:[t.running>0&&i.jsxs("span",{className:"text-[var(--accent)]",children:[t.running," running "]}),t.completed>0&&i.jsxs("span",{children:[t.completed," completed"]})]})]}),i.jsx("div",{className:"flex gap-2",children:i.jsx(V,{variant:"primary",icon:Bi,onClick:c=>{c.stopPropagation(),r()},className:"flex-1",children:"Optimize"})})]})}function O0({isOpen:e,onClose:t,onSubmit:n,isLoading:r}){var K,X,R,O,Z,he,Ne;const s=["read_file","write_file","edit_file","bash","grep","think"],[a,l]=k.useState("preset"),[o,u]=k.useState({name:"",description:"",instructions:null,model:null,compaction:{strategy:"none",params:{}},tools:s,framework:"miniagent",llm_config_id:null}),[c,h]=k.useState(!1),[d,m]=k.useState("preset"),[x,w]=k.useState([...s]),[j,S]=k.useState(!1),{data:p}=ve({queryKey:["agent-schema"],queryFn:()=>Am.getAgentSchema()}),{data:f=[]}=ve({queryKey:["llm-configs"],queryFn:()=>a0.list()}),{data:v}=ve({queryKey:["tools"],queryFn:()=>i0.list()}),g=((K=v==null?void 0:v.tools)==null?void 0:K.map(M=>M.name))??s,C=(v==null?void 0:v.presets)??{},b=Object.keys(C),N=(p==null?void 0:p.frameworks)??{},_=Object.keys(N).length>0?Object.keys(N):y0,F=o.framework||"miniagent",P=((R=(X=p==null?void 0:p.frameworks)==null?void 0:X[F])==null?void 0:R.compaction_strategies)??["none","head_tail"],B=(p==null?void 0:p.compaction_strategies)??{},D=(p==null?void 0:p.agent_presets)??[],U=M=>{const H=M.config,dt=H.compaction;n({name:M.name+"-agent",description:M.description,framework:H.framework||"miniagent",tools:H.tools||"standard",compaction:dt||{strategy:"none",params:{}},instructions:H.instructions||null})},ne=M=>{if(M.preventDefault(),!o.name.trim())return;const H={...o};d==="custom"&&(H.tools=x),n(H)},je=((O=o.compaction)==null?void 0:O.strategy)!=="none",Ge=((Z=o.compaction)==null?void 0:Z.strategy)||"none",ie=B[Ge],T=M=>{w(H=>H.includes(M)?H.filter(dt=>dt!==M):[...H,M])},A=M=>{const H=B[M],dt={};if(H!=null&&H.params)for(const[rs,ss]of Object.entries(H.params))ss.default!==void 0&&(dt[rs]=ss.default);u({...o,compaction:{strategy:M,params:dt}})},L=a==="custom"?i.jsxs("div",{className:"flex justify-end gap-2",children:[i.jsx(V,{type:"button",variant:"secondary",onClick:t,children:"Cancel"}),i.jsx(V,{type:"submit",form:"create-agent-form",variant:"primary",disabled:!o.name.trim(),loading:r,children:"Create Agent"})]}):i.jsx("div",{className:"flex justify-end gap-2",children:i.jsx(V,{type:"button",variant:"secondary",onClick:t,children:"Cancel"})});return i.jsxs(ns,{isOpen:e,onClose:t,title:"Create Agent",footer:L,children:[i.jsxs("div",{className:"flex items-center gap-3 mb-4 pb-3 border-b border-[var(--border)]",children:[i.jsx("button",{type:"button",className:`text-sm px-3 py-1.5 rounded transition-colors ${a==="preset"?"bg-[var(--accent)] text-white":"text-[var(--text-secondary)] hover:text-[var(--text-primary)]"}`,onClick:()=>l("preset"),children:"From Preset"}),i.jsx("button",{type:"button",className:`text-sm px-3 py-1.5 rounded transition-colors ${a==="custom"?"bg-[var(--accent)] text-white":"text-[var(--text-secondary)] hover:text-[var(--text-primary)]"}`,onClick:()=>l("custom"),children:"Custom"})]}),a==="preset"?i.jsx("div",{className:"space-y-3",children:D.length===0?i.jsx("p",{className:"text-sm text-[var(--text-secondary)] text-center py-4",children:"Loading presets..."}):D.map(M=>i.jsx("button",{type:"button",className:"w-full text-left p-4 border border-[var(--border)] rounded-lg hover:border-[var(--accent)] hover:bg-[var(--accent)]/5 transition-colors",onClick:()=>U(M),disabled:r,children:i.jsxs("div",{className:"flex items-start justify-between",children:[i.jsxs("div",{className:"flex-1",children:[i.jsx("h4",{className:"font-medium",children:M.label}),i.jsx("p",{className:"text-sm text-[var(--text-secondary)] mt-1",children:M.description}),i.jsxs("div",{className:"flex flex-wrap gap-1.5 mt-2",children:[M.tags.map(H=>i.jsx(J,{variant:"default",children:H},H)),M.suggested_datasets.length>0&&i.jsxs(J,{variant:"success",children:["datasets: ",M.suggested_datasets.join(", ")]})]})]}),i.jsx(gi,{size:16,className:"text-[var(--text-secondary)] mt-1 flex-shrink-0"})]})},M.name))}):i.jsxs("form",{id:"create-agent-form",onSubmit:ne,className:"space-y-4",children:[i.jsx(vn,{label:"Name",value:o.name,onChange:M=>u({...o,name:M.target.value}),placeholder:"e.g., my-coding-agent",required:!0}),i.jsxs("div",{children:[i.jsx("label",{className:"text-sm font-medium block mb-1.5",children:"LLM Configuration"}),i.jsxs("select",{className:"w-full px-3 py-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm",value:o.llm_config_id||"",onChange:M=>u({...o,llm_config_id:M.target.value||null}),children:[i.jsx("option",{value:"",children:"Use environment variables"}),f.map(M=>i.jsxs("option",{value:M.id,children:[M.name," (",j0[M.provider],M.model_id?` - ${M.model_id}`:"",")",M.is_default?" (default)":""]},M.id))]}),i.jsx("p",{className:"text-xs text-[var(--text-secondary)] mt-1",children:f.length===0?"No LLM configs found. Uses environment variables (AZURE_OPENAI_ENDPOINT, OPENAI_API_KEY, etc.)":o.llm_config_id?"Uses the selected LLM configuration.":"Uses environment variables (AZURE_OPENAI_ENDPOINT, OPENAI_API_KEY, etc.)"})]}),i.jsxs("div",{children:[i.jsx("label",{className:"text-sm font-medium block mb-1.5",children:"Framework"}),i.jsx("select",{className:"w-full px-3 py-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm",value:o.framework||"miniagent",onChange:M=>{const H=M.target.value;u({...o,framework:H,compaction:{strategy:"none",params:{}}})},children:_.map(M=>{var H;return i.jsx("option",{value:M,children:((H=N[M])==null?void 0:H.label)||g0[M]||M},M)})}),i.jsx("p",{className:"text-xs text-[var(--text-secondary)] mt-1",children:((he=N[F])==null?void 0:he.description)||(F==="miniagent"?"Lightweight agent with token-aware context management.":F==="langgraph"?"Graph-based workflows with state management.":"Default agent implementation.")})]}),i.jsxs("div",{className:"grid grid-cols-2 gap-4",children:[i.jsx(Fo,{label:"Custom instructions",checked:c,onChange:M=>{h(M.target.checked),M.target.checked||u({...o,instructions:null})}}),i.jsx(Fo,{label:"Enable compaction",checked:je,onChange:M=>{if(M.target.checked){const H=P.find(dt=>dt!=="none")||"head_tail";A(H)}else u({...o,compaction:{strategy:"none",params:{}}})}})]}),c&&i.jsx("textarea",{className:"w-full h-32 px-3 py-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm font-mono resize-y",value:o.instructions||"",onChange:M=>u({...o,instructions:M.target.value||null}),placeholder:"System prompt / instructions for the agent..."}),je&&i.jsxs("div",{className:"space-y-3 p-3 border border-[var(--border)] rounded bg-[var(--bg-secondary)]",children:[i.jsxs("div",{children:[i.jsx("label",{className:"text-sm font-medium block mb-1.5",children:"Compaction Strategy"}),i.jsx("select",{className:"w-full px-3 py-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm",value:Ge,onChange:M=>A(M.target.value),children:P.filter(M=>M!=="none").map(M=>{var H;return i.jsx("option",{value:M,children:((H=B[M])==null?void 0:H.label)||M},M)})}),(ie==null?void 0:ie.description)&&i.jsx("p",{className:"text-xs text-[var(--text-secondary)] mt-1",children:ie.description})]}),(ie==null?void 0:ie.params)&&Object.keys(ie.params).length>0&&i.jsx("div",{className:"grid grid-cols-2 gap-3",children:Object.entries(ie.params).map(([M,H])=>{var ss;const dt=(ss=o.compaction)==null?void 0:ss.params[M],rs=dt!==void 0?dt:H.default;return i.jsxs("div",{children:[i.jsx("label",{className:"text-xs font-medium block mb-1 capitalize",children:M.replace(/_/g," ")}),i.jsx("input",{type:"number",className:"w-full px-3 py-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm",value:typeof rs=="number"?rs:Number(rs)||0,onChange:Hm=>{const Wu=parseFloat(Hm.target.value);u({...o,compaction:{...o.compaction,params:{...o.compaction.params,[M]:isNaN(Wu)?typeof H.default=="number"?H.default:0:Wu}}})},min:H.min,max:H.max,step:H.max&&H.max<=1?.1:1}),i.jsx("p",{className:"text-xs text-[var(--text-secondary)] mt-0.5",children:H.description})]},M)})})]}),i.jsxs("div",{className:"space-y-2",children:[i.jsx("label",{className:"text-sm font-medium",children:"Tools"}),i.jsxs("div",{className:"flex gap-4",children:[i.jsxs("label",{className:"flex items-center gap-2",children:[i.jsx("input",{type:"radio",checked:d==="preset",onChange:()=>m("preset"),className:"accent-[var(--accent)]"}),i.jsx("span",{className:"text-sm",children:"Preset"})]}),i.jsxs("label",{className:"flex items-center gap-2",children:[i.jsx("input",{type:"radio",checked:d==="custom",onChange:()=>m("custom"),className:"accent-[var(--accent)]"}),i.jsx("span",{className:"text-sm",children:"Custom"})]})]}),d==="preset"?i.jsxs(i.Fragment,{children:[i.jsx("select",{className:"w-full px-3 py-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm",value:typeof o.tools=="string"?o.tools:"standard",onChange:M=>u({...o,tools:M.target.value}),children:b.map(M=>i.jsx("option",{value:M,children:M},M))}),i.jsx("p",{className:"text-xs text-[var(--text-secondary)] mt-1",children:((Ne=C[typeof o.tools=="string"?o.tools:"standard"])==null?void 0:Ne.join(", "))??""})]}):i.jsx("div",{className:"grid grid-cols-2 gap-1 p-2 border border-[var(--border)] rounded bg-[var(--bg-secondary)]",children:g.map(M=>i.jsxs("label",{className:"flex items-center gap-2 p-1 text-sm cursor-pointer hover:bg-[var(--bg-tertiary)]",children:[i.jsx("input",{type:"checkbox",checked:x.includes(M),onChange:()=>T(M),className:"accent-[var(--accent)]"}),i.jsx("span",{className:"font-mono text-xs",children:M})]},M))})]}),i.jsxs("div",{className:"border-t border-[var(--border)] pt-3",children:[i.jsxs("button",{type:"button",className:"flex items-center gap-2 text-sm text-[var(--text-secondary)] hover:text-[var(--text-primary)] transition-colors",onClick:()=>S(!j),children:[i.jsx(gi,{size:14,className:`transition-transform ${j?"rotate-90":""}`}),"More options"]}),j&&i.jsx("div",{className:"mt-3",children:i.jsx(vn,{label:"Description (optional)",value:o.description,onChange:M=>u({...o,description:M.target.value}),placeholder:"Brief description of this agent"})})]})]})]})}function L0({agent:e,isOpen:t,onClose:n}){var R;const r=Lt(),s=Jt(),[a,l]=k.useState("ready"),[o,u]=k.useState("quick"),[c,h]=k.useState(!1),[d,m]=k.useState([]),[x,w]=k.useState(!1),[j,S]=k.useState(Io),[p,f]=k.useState(4),[v,g]=k.useState(100),[C,b]=k.useState(!1),[N,_]=k.useState(null),{data:F=[]}=ve({queryKey:["tasks"],queryFn:()=>Et.list()}),{data:P=[]}=ve({queryKey:["suites"],queryFn:()=>Et.listSuites()}),{data:B}=ve({queryKey:["agent-schema"],queryFn:()=>Am.getAgentSchema()}),D=P.map(O=>({value:O.name,label:O.name.charAt(0).toUpperCase()+O.name.slice(1),description:O.description,tasks:O.task_count})),U=Je({mutationFn:Et.importSuite,onSuccess:O=>{s.invalidateQueries({queryKey:["tasks"]}),m(O.map(Z=>Z.id))}}),ne=Je({mutationFn:async O=>{const Z=await Ot.create(O);return Ot.start(Z.id).next(),Z},onSuccess:O=>{s.invalidateQueries({queryKey:["jobs"]}),_(O.id),l("success")}}),Ge=x?(()=>{let O=1;j.compaction.length>0&&(O*=j.compaction.length),j.tools.length>0&&(O*=j.tools.length),j.llm_config.length>0&&(O*=j.llm_config.length);const Z=j.instructions.length+j.instruction_strategies.reduce((he,Ne)=>he+Ne.max_candidates,0);return Z>0&&(O*=Z),Math.min(O,v)})():1,ie=c?d.length:((R=D.find(O=>O.value===o))==null?void 0:R.tasks)||3,T=Ge*ie,A=async()=>{l("starting");let O=d;if(!c)try{O=(await U.mutateAsync(o)).map(H=>H.id)}catch(M){console.error("Failed to import suite:",M),alert(`Failed to import task suite: ${o}`),l("ready");return}if(O.length===0){alert("No tasks selected. Please select tasks or choose a task suite."),l("ready");return}let Z;if(x&&(j.compaction.length>0||j.tools.length>0||j.llm_config.length>0||j.instructions.length>0||j.instruction_strategies.length>0))try{Z=(await zo.generateCandidates({base_agent_id:e.id,variations:j,budget:v})).candidate_ids}catch(M){console.error("Failed to generate candidates:",M),alert(`Failed to generate candidates: ${M instanceof Error?M.message:"Unknown error"}`),l("ready");return}else Z=[e.id];const Ne={name:`${e.name} optimization (${Z.length} candidates × ${O.length} tasks)`,candidate_ids:Z,task_ids:O,parallel:p,use_llm_eval:C};ne.mutate(Ne)},L=O=>{m(Z=>Z.includes(O)?Z.filter(he=>he!==O):[...Z,O])},K=()=>{l("ready"),_(null),w(!1),S(Io),n()},X=()=>a==="success"&&N?i.jsxs("div",{className:"flex justify-end gap-3",children:[i.jsx(V,{variant:"secondary",onClick:K,children:"Close"}),i.jsx(V,{variant:"primary",icon:Gs,onClick:()=>{K(),r(`/jobs/${N}`)},children:"View Job"})]}):a==="starting"?null:i.jsxs("div",{className:"flex justify-end gap-2",children:[i.jsx(V,{variant:"secondary",onClick:n,children:"Cancel"}),i.jsxs(V,{variant:"primary",icon:Gs,onClick:A,disabled:c&&d.length===0,children:["Start Optimization (",T," runs)"]})]});return i.jsx(ns,{isOpen:t,onClose:K,title:`Optimize: ${e.name}`,footer:X(),size:"lg",children:a==="success"&&N?i.jsxs("div",{className:"flex flex-col items-center py-8",children:[i.jsx("div",{className:"w-12 h-12 rounded-full bg-green-500/20 flex items-center justify-center mb-4",children:i.jsx(Bi,{size:24,className:"text-green-500"})}),i.jsx("h3",{className:"text-lg font-medium mb-2",children:"Job Started!"}),i.jsx("p",{className:"text-[var(--text-secondary)] text-center mb-2",children:"Optimization job is now running"}),i.jsxs("code",{className:"text-xs bg-[var(--bg-primary)] px-3 py-1.5 rounded font-mono",children:["ID: ",N.slice(0,8),"..."]})]}):a==="starting"?i.jsxs("div",{className:"flex flex-col items-center py-8",children:[i.jsx(ca,{size:32,className:"animate-spin text-[var(--accent)] mb-4"}),i.jsx("p",{className:"text-[var(--text-secondary)]",children:U.isPending?"Importing tasks...":"Creating optimization job..."})]}):i.jsxs("div",{className:"space-y-5",children:[i.jsxs("div",{children:[i.jsx("label",{className:"text-sm font-medium mb-2 block",children:"Task Suite"}),i.jsxs("select",{className:"w-full px-3 py-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm",value:c?"__custom__":o,onChange:O=>{O.target.value==="__custom__"?h(!0):(h(!1),u(O.target.value))},children:[D.map(O=>i.jsxs("option",{value:O.value,children:[O.label," (",O.tasks," tasks) — ",O.description]},O.value)),F.length>0&&i.jsx("option",{value:"__custom__",children:"Custom Selection"})]})]}),c&&F.length>0&&i.jsx("div",{className:"max-h-48 overflow-y-auto border border-[var(--border)] rounded p-2 space-y-1",children:F.map(O=>i.jsxs("label",{className:"flex items-center gap-2 p-2 hover:bg-[var(--bg-tertiary)] cursor-pointer rounded",children:[i.jsx("input",{type:"checkbox",checked:d.includes(O.id),onChange:()=>L(O.id),className:"accent-[var(--accent)]"}),i.jsx("span",{className:"text-sm",children:O.name}),O.suite&&i.jsx(J,{children:O.suite})]},O.id))}),i.jsxs("div",{className:"border-t border-[var(--border)] pt-3",children:[i.jsxs("button",{type:"button",className:"flex items-center gap-2 text-sm text-[var(--text-secondary)] hover:text-[var(--text-primary)] transition-colors",onClick:()=>w(!x),children:[i.jsx(gi,{size:14,className:`transition-transform ${x?"rotate-90":""}`}),"Advanced Settings",x&&i.jsx("span",{className:"text-xs text-[var(--text-secondary)]",children:"(experiment design, variations, execution)"})]}),x&&B&&i.jsx("div",{className:"mt-4",children:i.jsx(_0,{agentId:e.id,agentName:e.name,agentFramework:e.config.framework,taskSuite:c?void 0:o,taskCount:ie,schema:B,onVariationsChange:S,parallel:p,onParallelChange:f,budget:v,onBudgetChange:g,useLlmEval:C,onUseLlmEvalChange:b})})]})]})})}function R0(e){const t=[],n=r=>r.type==="trace_span"&&typeof r.data=="object"&&r.data!==null?r.data:"span_id"in r?r:null;if(Array.isArray(e.spans)){for(const r of e.spans)if(typeof r=="object"&&r!==null){const s=n(r);s&&t.push(s)}}else if(e.span_id)t.push(e);else for(const r in e){const s=e[r];if(typeof s=="object"&&s!==null){const a=n(s);if(a)t.push(a);else if(Array.isArray(s)){for(const l of s)if(typeof l=="object"&&l!==null){const o=n(l);o&&t.push(o)}}}}return t}function Um(e){const t=new Map,n=[];for(const s of e)t.set(s.span_id,{span:s,children:[]});for(const s of e){const a=t.get(s.span_id);s.parent_span_id&&t.has(s.parent_span_id)?t.get(s.parent_span_id).children.push(a):n.push(a)}const r=s=>{s.sort((a,l)=>(a.span.start_time||0)-(l.span.start_time||0)),s.forEach(a=>r(a.children))};return r(n),n}function M0(e){return e.includes("Agent")||e.includes("agent")?"bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-200":e.includes("chat")||e.includes("Chat")||e.includes("llm")?"bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200":e.includes("tool")||e.includes("execute")||e.includes("bash")?"bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200":"bg-orange-100 text-orange-800 dark:bg-orange-900 dark:text-orange-200"}function z0(e){return e>=1e3?`${(e/1e3).toFixed(2)}s`:`${e.toFixed(0)}ms`}function Hu({node:e,depth:t=0}){var d,m;const[n,r]=k.useState(t<2),[s,a]=k.useState(!1),{span:l}=e,o=e.children.length>0,u=(d=l.attributes)==null?void 0:d["gen_ai.usage.input_tokens"],c=(m=l.attributes)==null?void 0:m["gen_ai.usage.output_tokens"],h=u!==void 0||c!==void 0;return i.jsxs("div",{className:"relative",children:[t>0&&i.jsx("div",{className:"absolute left-0 top-0 bottom-0 border-l-2 border-[var(--border)]",style:{marginLeft:`${(t-1)*16+8}px`}}),i.jsxs("div",{className:"flex items-center gap-2 py-1.5 px-1 hover:bg-[var(--bg-primary)] rounded transition-colors cursor-pointer",style:{paddingLeft:`${t*16}px`},onClick:()=>o?r(!n):a(!s),children:[i.jsx("div",{className:"w-4 h-4 flex items-center justify-center text-[var(--text-secondary)]",children:o?n?"▼":"▶":s?"▼":"▶"}),i.jsx("span",{className:`text-xs px-1.5 py-0.5 rounded font-medium ${M0(l.operation_name)}`,children:l.operation_name.replace("ChatAgent.","").replace("invoke_agent ","")}),l.duration_ms!==void 0&&i.jsx("span",{className:"text-xs text-[var(--text-secondary)] font-mono",children:z0(l.duration_ms)}),h&&i.jsxs("span",{className:"text-xs text-[var(--text-secondary)] font-mono",children:[u!==void 0&&i.jsxs("span",{className:"text-blue-400",children:["↑",String(u)]}),u!==void 0&&c!==void 0&&i.jsx("span",{className:"mx-0.5",children:"/"}),c!==void 0&&i.jsxs("span",{className:"text-green-400",children:["↓",String(c)]})]})]}),s&&!o&&i.jsx("div",{className:"ml-4 mt-1 mb-2 p-2 bg-[var(--bg-primary)] rounded border border-[var(--border)] text-xs",style:{marginLeft:`${t*16+20}px`},children:i.jsxs("div",{className:"space-y-1",children:[l.span_id&&i.jsxs("div",{className:"flex gap-2",children:[i.jsx("span",{className:"text-[var(--text-secondary)] w-20",children:"Span ID:"}),i.jsx("span",{className:"font-mono text-xs break-all",children:l.span_id})]}),l.trace_id&&i.jsxs("div",{className:"flex gap-2",children:[i.jsx("span",{className:"text-[var(--text-secondary)] w-20",children:"Trace ID:"}),i.jsx("span",{className:"font-mono text-xs break-all",children:l.trace_id})]}),l.status&&i.jsxs("div",{className:"flex gap-2",children:[i.jsx("span",{className:"text-[var(--text-secondary)] w-20",children:"Status:"}),i.jsx("span",{className:`px-1.5 py-0.5 rounded text-xs ${l.status==="OK"||l.status==="StatusCode.UNSET"?"bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200":"bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200"}`,children:l.status})]}),Object.keys(l.attributes||{}).length>0&&i.jsxs("div",{className:"mt-2",children:[i.jsx("span",{className:"text-[var(--text-secondary)] block mb-1",children:"Attributes:"}),i.jsx("pre",{className:"text-xs bg-[var(--bg-secondary)] border border-[var(--border)] rounded p-2 overflow-auto max-h-32 whitespace-pre-wrap break-all",children:JSON.stringify(l.attributes,null,2)})]})]})}),o&&n&&i.jsx("div",{children:e.children.map((x,w)=>i.jsx(Hu,{node:x,depth:t+1},x.span.span_id||w))})]})}function Bm({trace:e}){const[t,n]=k.useState("tree"),r=k.useMemo(()=>R0(e),[e]),s=k.useMemo(()=>Um(r),[r]);return Object.keys(e).length===0?null:i.jsxs(se,{className:"mb-6",children:[i.jsxs("div",{className:"flex items-center justify-between mb-3",children:[i.jsx("h3",{className:"font-medium",children:"Trace Data"}),i.jsxs("div",{className:"flex gap-1",children:[i.jsx("button",{onClick:()=>n("tree"),className:`px-2 py-1 text-xs rounded ${t==="tree"?"bg-[var(--accent)] text-white":"bg-[var(--bg-primary)] text-[var(--text-secondary)] hover:text-[var(--text-primary)]"}`,children:"Tree"}),i.jsx("button",{onClick:()=>n("raw"),className:`px-2 py-1 text-xs rounded ${t==="raw"?"bg-[var(--accent)] text-white":"bg-[var(--bg-primary)] text-[var(--text-secondary)] hover:text-[var(--text-primary)]"}`,children:"Raw"})]})]}),t==="tree"?r.length>0?i.jsx("div",{className:"border border-[var(--border)] rounded overflow-hidden",children:i.jsxs("div",{className:"p-2",children:[i.jsxs("div",{className:"flex items-center gap-2 mb-2 text-xs text-[var(--text-secondary)]",children:[i.jsxs(J,{variant:"default",children:[r.length," spans"]}),i.jsx("span",{children:"•"}),i.jsx("span",{children:"Click to expand details"})]}),s.map((a,l)=>i.jsx(Hu,{node:a,depth:0},a.span.span_id||l))]})}):i.jsx("div",{className:"text-sm text-[var(--text-secondary)] text-center py-4",children:"No structured spans found. View raw data below."}):i.jsx("pre",{className:"text-xs bg-[var(--bg-primary)] p-3 overflow-x-auto border border-[var(--border)] max-h-96 whitespace-pre-wrap",children:JSON.stringify(e,null,2)})]})}function F0({spans:e,isLive:t=!1}){const n=k.useRef(null),r=k.useMemo(()=>Um(e),[e]);return k.useEffect(()=>{n.current&&t&&n.current.scrollTo({top:n.current.scrollHeight,behavior:"smooth"})},[e.length,t]),i.jsxs("div",{className:"border border-[var(--border)] rounded overflow-hidden h-full flex flex-col",children:[i.jsxs("div",{className:"flex items-center gap-2 p-2 border-b border-[var(--border)] bg-[var(--bg-secondary)]",children:[i.jsxs(J,{variant:"default",children:[e.length," spans"]}),t&&i.jsx("span",{className:"animate-pulse",children:i.jsx(J,{variant:"info",children:"Live"})})]}),i.jsx("div",{ref:n,className:"flex-1 overflow-auto p-2",children:r.length>0?r.map((s,a)=>i.jsx(Hu,{node:s,depth:0},s.span.span_id||a)):i.jsx("div",{className:"text-sm text-[var(--text-secondary)] text-center py-4",children:t?"Waiting for spans...":"No spans recorded"})})]})}function I0({agent:e}){const[t,n]=k.useState(""),[r,s]=k.useState(null),[a,l]=k.useState("idle"),[o,u]=k.useState(null),[c,h]=k.useState(""),[d,m]=k.useState([]),[x,w]=k.useState(null),[j,S]=k.useState(null),[p,f]=k.useState([]),v=k.useRef(null),{data:g=[]}=ve({queryKey:["tasks"],queryFn:()=>Et.list()});k.useEffect(()=>{v.current&&a==="running"&&(v.current.scrollTop=v.current.scrollHeight)},[c,a]);const C=D=>{if(s(D),D){const U=g.find(ne=>ne.id===D);U&&n(U.prompt)}},b=async()=>{if(t.trim()){l("running"),h(""),m([]),w(null),S(null),f([]);try{const D=await Es.create({agent_id:e.id,prompt:t.trim(),task_id:r||void 0});u(D.id);for await(const U of Es.start(D.id))N(U)}catch(D){S(D instanceof Error?D.message:"Test failed"),l("failed")}}},N=D=>{switch(D.event){case"started":break;case"execution":D.execution_event==="text_delta"&&D.content?h(U=>U+D.content):D.execution_event==="tool_call_start"&&D.tool_name?f(U=>[...U,{name:D.tool_name}]):D.execution_event==="tool_result"&&D.content&&f(U=>{if(U.length>0){const ne=[...U];return ne[ne.length-1]={...ne[ne.length-1],content:D.content},ne}return U});break;case"span":if(D.span){const U=D.span;if(U.data){const ne={span_id:U.data.span_id||"",trace_id:U.data.trace_id||"",parent_span_id:U.data.parent_span_id||null,operation_name:U.data.operation_name||"",start_time:U.timestamp?new Date(U.timestamp).getTime():Date.now(),end_time:Date.now(),duration_ms:U.data.duration_ms||0,status:U.data.status||"OK",attributes:U.data.attributes||{}};m(je=>[...je,ne])}}break;case"complete":l("completed"),D.result&&w(D.result);break;case"error":S(D.message),l("failed");break}},_=async()=>{if(o)try{await Es.cancel(o)}catch{}l("idle")},F=()=>{l("idle"),u(null),h(""),m([]),w(null),S(null),f([])},P=a==="running",B=a==="completed"||a==="failed";return i.jsxs("div",{className:"h-full flex flex-col",children:[!P&&!B&&i.jsxs("div",{className:"mb-4 space-y-3",children:[i.jsxs("div",{className:"flex gap-3",children:[i.jsxs("div",{className:"flex-1",children:[i.jsx("label",{className:"block text-sm font-medium mb-1",children:"Select Task (optional)"}),i.jsxs("select",{value:r||"",onChange:D=>C(D.target.value||null),className:"w-full px-3 py-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm",children:[i.jsx("option",{value:"",children:"Custom prompt..."}),g.map(D=>i.jsx("option",{value:D.id,children:D.name},D.id))]})]}),i.jsx("div",{className:"flex items-end",children:i.jsx(V,{variant:"primary",icon:Gs,onClick:b,disabled:!t.trim(),children:"Run Test"})})]}),i.jsxs("div",{children:[i.jsx("label",{className:"block text-sm font-medium mb-1",children:"Prompt"}),i.jsx("textarea",{value:t,onChange:D=>n(D.target.value),placeholder:"Enter a test prompt for the agent...",className:"w-full h-32 px-3 py-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm font-mono resize-none"})]})]}),(P||B)&&i.jsxs("div",{className:"flex-1 flex flex-col min-h-0",children:[i.jsxs("div",{className:"flex items-center justify-between mb-3",children:[i.jsxs("div",{className:"flex items-center gap-2",children:[P&&i.jsxs(i.Fragment,{children:[i.jsx("span",{className:"animate-pulse",children:i.jsx(J,{variant:"info",children:"Running"})}),i.jsx(V,{variant:"ghost",size:"sm",icon:Pg,onClick:_,children:"Cancel"})]}),a==="completed"&&i.jsx(J,{variant:"success",children:"Completed"}),a==="failed"&&i.jsx(J,{variant:"error",children:"Failed"})]}),i.jsxs("div",{className:"flex items-center gap-3",children:[x&&i.jsxs("div",{className:"flex items-center gap-3 text-xs text-[var(--text-secondary)]",children:[i.jsxs("span",{className:"flex items-center gap-1",children:[i.jsx(vg,{size:12}),x.duration_seconds.toFixed(2),"s"]}),i.jsxs("span",{className:"flex items-center gap-1",children:[i.jsx(xg,{size:12}),x.tokens_total," tokens"]}),x.passed!==null&&(x.passed?i.jsx(Em,{size:14,className:"text-green-500"}):i.jsx(Og,{size:14,className:"text-red-500"}))]}),B&&i.jsx(V,{variant:"secondary",size:"sm",onClick:F,children:"New Test"})]})]}),i.jsxs("div",{className:"flex-1 grid grid-cols-2 gap-4 min-h-0",children:[i.jsxs("div",{className:"flex flex-col border border-[var(--border)] rounded overflow-hidden",children:[i.jsx("div",{className:"px-3 py-2 border-b border-[var(--border)] bg-[var(--bg-secondary)] text-sm font-medium",children:"Output"}),i.jsxs("div",{ref:v,className:"flex-1 overflow-auto p-3 font-mono text-sm whitespace-pre-wrap bg-[var(--bg-primary)]",children:[c||(P?"Waiting for response...":"No output"),p.length>0&&i.jsxs("div",{className:"mt-3 space-y-2 border-t border-[var(--border)] pt-3",children:[i.jsx("div",{className:"text-xs text-[var(--text-secondary)] uppercase tracking-wider",children:"Tool Calls"}),p.map((D,U)=>i.jsxs("div",{className:"p-2 bg-green-500/10 border border-green-500/20 rounded text-xs",children:[i.jsx(J,{variant:"success",children:D.name}),D.content&&i.jsxs("div",{className:"mt-1 text-[var(--text-secondary)] truncate max-w-full",children:[D.content.substring(0,200),D.content.length>200&&"..."]})]},U))]})]})]}),i.jsx(F0,{spans:d,isLive:P})]}),j&&i.jsx("div",{className:"mt-3 p-3 bg-red-500/10 border border-red-500/20 rounded text-sm text-red-400",children:j}),B&&o&&i.jsx("div",{className:"mt-3 flex items-center justify-end pt-3 border-t border-[var(--border)]",children:i.jsx(Js,{to:`/tests/${o}`,children:i.jsx(V,{variant:"primary",iconRight:jg,children:"View Full Details"})})})]})]})}function D0(){const{agentId:e}=Di(),t=Lt(),n=Jt(),[r,s]=k.useState("overview"),{data:a,isLoading:l}=ve({queryKey:["configs",e],queryFn:()=>Er.get(e),enabled:!!e}),{data:o=[]}=ve({queryKey:["tests",{agent_id:e}],queryFn:()=>Es.list({agent_id:e}),enabled:!!e}),{data:u=[]}=ve({queryKey:["jobs"],queryFn:()=>Ot.list()}),c=Je({mutationFn:d=>Er.delete(d),onSuccess:()=>{n.invalidateQueries({queryKey:["configs"]}),t("/agents")}}),h=u.filter(d=>d.candidate_ids.includes(e||""));return l?i.jsx("div",{className:"text-[var(--text-secondary)]",children:"Loading..."}):a?i.jsxs("div",{className:"h-full flex flex-col",children:[i.jsxs("div",{className:"mb-6",children:[i.jsx("div",{className:"flex items-center gap-3 mb-2",children:i.jsx("button",{onClick:()=>t("/agents"),className:"text-[var(--text-secondary)] hover:text-[var(--text-primary)]",children:"← Back to Agents"})}),i.jsxs("div",{className:"flex items-center justify-between",children:[i.jsxs("div",{className:"flex items-center gap-3",children:[i.jsx("h2",{className:"text-xl font-bold",children:a.name}),a.is_auto_generated&&i.jsx(J,{variant:"info",children:"Auto-generated"})]}),i.jsx("div",{className:"flex gap-2",children:i.jsx(V,{variant:"secondary",icon:Om,onClick:()=>{confirm(`Delete agent "${a.name}"?`)&&c.mutate(a.id)},children:"Delete"})})]}),a.description&&i.jsx("p",{className:"text-sm text-[var(--text-secondary)] mt-1",children:a.description})]}),i.jsxs("div",{className:"flex gap-1 mb-6 border-b border-[var(--border)]",children:[i.jsx(jl,{active:r==="overview",onClick:()=>s("overview"),icon:i.jsx(Tm,{size:16}),children:"Overview"}),i.jsx(jl,{active:r==="test",onClick:()=>s("test"),icon:i.jsx(Gs,{size:16}),children:"Test"}),i.jsx(jl,{active:r==="history",onClick:()=>s("history"),icon:i.jsx(Ng,{size:16}),badge:o.length,children:"History"})]}),i.jsxs("div",{className:"flex-1 min-h-0",children:[r==="overview"&&i.jsx(A0,{agent:a,recentTests:o,jobs:h}),r==="test"&&i.jsx(I0,{agent:a}),r==="history"&&i.jsx($0,{tests:o})]})]}):i.jsx("div",{className:"text-[var(--text-secondary)]",children:"Agent not found"})}function jl({active:e,onClick:t,icon:n,badge:r,children:s}){return i.jsxs("button",{onClick:t,className:`flex items-center gap-2 px-4 py-2 text-sm font-medium border-b-2 transition-colors ${e?"border-[var(--accent)] text-[var(--text-primary)]":"border-transparent text-[var(--text-secondary)] hover:text-[var(--text-primary)]"}`,children:[n,s,r!==void 0&&r>0&&i.jsx("span",{className:"ml-1 px-1.5 py-0.5 text-xs bg-[var(--bg-tertiary)] rounded",children:r})]})}function A0({agent:e,recentTests:t,jobs:n}){var w,j,S,p,f,v;const r=Lt(),s=Jt(),a=e.config,[l,o]=k.useState("quick"),[u,c]=k.useState(!1),{data:h=[]}=ve({queryKey:["suites"],queryFn:()=>Et.listSuites()}),d=Je({mutationFn:l0.start,onSuccess:g=>{s.invalidateQueries({queryKey:["jobs"]}),c(!1),r(`/jobs/${g.id}`)},onError:()=>{c(!1)}}),m=()=>{c(!0),d.mutate({agent_id:e.id,suite_name:l,use_llm_eval:!0,parallel:4})},x=()=>{const g=a.tools;return typeof g=="string"?g:Array.isArray(g)?g.join(", "):typeof g=="object"?Object.keys(g).join(", "):"standard"};return i.jsxs("div",{className:"space-y-6",children:[i.jsxs(se,{children:[i.jsx("h3",{className:"font-medium mb-4",children:"Configuration"}),i.jsxs("div",{className:"grid grid-cols-2 gap-4 text-sm",children:[i.jsxs("div",{children:[i.jsx("span",{className:"text-[var(--text-secondary)]",children:"Model:"}),i.jsx("div",{className:"font-mono",children:a.model||"default"})]}),i.jsxs("div",{children:[i.jsx("span",{className:"text-[var(--text-secondary)]",children:"Compaction:"}),i.jsx("div",{className:"font-mono",children:((w=a.compaction)==null?void 0:w.strategy)==="none"?"disabled":`${(j=a.compaction)==null?void 0:j.strategy} (${((p=(S=a.compaction)==null?void 0:S.params)==null?void 0:p.head_size)||0}/${((v=(f=a.compaction)==null?void 0:f.params)==null?void 0:v.tail_size)||0})`})]}),i.jsxs("div",{className:"col-span-2",children:[i.jsx("span",{className:"text-[var(--text-secondary)]",children:"Tools:"}),i.jsx("div",{className:"font-mono",children:x()})]}),a.instructions&&i.jsxs("div",{className:"col-span-2",children:[i.jsx("span",{className:"text-[var(--text-secondary)]",children:"Instructions:"}),i.jsx("pre",{className:"mt-1 p-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-xs whitespace-pre-wrap max-h-32 overflow-auto",children:a.instructions})]})]})]}),i.jsxs(se,{children:[i.jsx("h3",{className:"font-medium mb-3",children:"Evaluate"}),i.jsx("p",{className:"text-sm text-[var(--text-secondary)] mb-3",children:"Run this agent on a task suite to measure quality and cost."}),i.jsxs("div",{className:"flex items-center gap-3",children:[i.jsx("select",{className:"flex-1 px-3 py-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm",value:l,onChange:g=>o(g.target.value),disabled:u,children:h.map(g=>i.jsxs("option",{value:g.name,children:[g.name.charAt(0).toUpperCase()+g.name.slice(1)," (",g.task_count," tasks)"]},g.name))}),i.jsx(V,{variant:"primary",icon:u?ca:Gs,onClick:m,disabled:u,loading:u,children:"Evaluate"})]})]}),i.jsxs(se,{children:[i.jsxs("div",{className:"flex items-center justify-between mb-4",children:[i.jsx("h3",{className:"font-medium",children:"Recent Tests"}),t.length>0&&i.jsxs("span",{className:"text-xs text-[var(--text-secondary)]",children:[t.length," total"]})]}),t.length===0?i.jsx("div",{className:"text-sm text-[var(--text-secondary)] text-center py-4",children:'No tests yet. Click the "Test" tab to run one.'}):i.jsx("div",{className:"space-y-2",children:t.slice(0,5).map(g=>i.jsxs(Js,{to:`/tests/${g.id}`,className:"flex items-center justify-between p-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded hover:border-[var(--accent-dim)] transition-colors",children:[i.jsxs("div",{className:"flex items-center gap-2",children:[i.jsx(Qm,{status:g.status}),i.jsxs("span",{className:"text-sm truncate max-w-[200px]",children:[g.prompt.slice(0,50),"..."]})]}),i.jsxs("div",{className:"flex items-center gap-3 text-xs text-[var(--text-secondary)]",children:[i.jsxs("span",{children:[g.duration_seconds.toFixed(1),"s"]}),i.jsxs("span",{children:[g.tokens_total," tok"]})]})]},g.id))})]}),i.jsxs(se,{children:[i.jsxs("div",{className:"flex items-center justify-between mb-4",children:[i.jsx("h3",{className:"font-medium",children:"Optimization Jobs"}),i.jsx(V,{variant:"secondary",size:"sm",icon:Bi,onClick:()=>r("/agents",{state:{optimizeAgent:e}}),children:"New Job"})]}),n.length===0?i.jsx("div",{className:"text-sm text-[var(--text-secondary)] text-center py-4",children:"No optimization jobs yet."}):i.jsx("div",{className:"space-y-2",children:n.slice(0,5).map(g=>i.jsxs(Js,{to:`/jobs/${g.id}`,className:"flex items-center justify-between p-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded hover:border-[var(--accent-dim)] transition-colors",children:[i.jsxs("div",{className:"flex items-center gap-2",children:[i.jsx(J,{variant:g.status==="completed"?"success":g.status==="running"?"info":"default",children:g.status}),i.jsx("span",{className:"text-sm",children:g.name})]}),i.jsx("span",{className:"text-xs text-[var(--text-secondary)]",children:new Date(g.created_at).toLocaleDateString()})]},g.id))})]})]})}function $0({tests:e}){return e.length===0?i.jsx("div",{className:"text-center py-8 text-[var(--text-secondary)]",children:"No test history yet. Run a test to see results here."}):i.jsx("div",{className:"space-y-2",children:e.map(t=>i.jsxs(Js,{to:`/tests/${t.id}`,className:"flex items-center justify-between p-3 bg-[var(--bg-secondary)] border border-[var(--border)] rounded hover:border-[var(--accent-dim)] transition-colors",children:[i.jsxs("div",{className:"flex-1 min-w-0",children:[i.jsxs("div",{className:"flex items-center gap-2 mb-1",children:[i.jsx(Qm,{status:t.status}),t.score!==null&&i.jsxs("span",{className:`text-sm font-medium ${t.passed?"text-green-400":"text-red-400"}`,children:[(t.score*100).toFixed(0),"%"]})]}),i.jsx("p",{className:"text-sm truncate",children:t.prompt})]}),i.jsxs("div",{className:"flex flex-col items-end gap-1 ml-4",children:[i.jsx("span",{className:"text-xs text-[var(--text-secondary)]",children:new Date(t.created_at).toLocaleString()}),i.jsxs("div",{className:"flex items-center gap-2 text-xs text-[var(--text-secondary)]",children:[i.jsxs("span",{children:[t.duration_seconds.toFixed(1),"s"]}),i.jsx("span",{children:"•"}),i.jsxs("span",{children:[t.tokens_total," tokens"]})]})]})]},t.id))})}function Qm({status:e}){const t={completed:"success",failed:"error",running:"info",cancelled:"warning",pending:"default"};return i.jsx(J,{variant:t[e]||"default",children:e})}function U0(){const e=Jt(),[t,n]=k.useState(!1),[r,s]=k.useState(!1),[a,l]=k.useState(null),[o,u]=k.useState(new Set),c=p=>{u(f=>{const v=new Set(f);return v.has(p)?v.delete(p):v.add(p),v})},{data:h=[],isLoading:d}=ve({queryKey:["tasks"],queryFn:()=>Et.list()}),m=Je({mutationFn:Et.create,onSuccess:()=>{e.invalidateQueries({queryKey:["tasks"]}),n(!1)}}),x=Je({mutationFn:Et.importSuite,onSuccess:()=>{e.invalidateQueries({queryKey:["tasks"]}),s(!1)}}),w=Je({mutationFn:Et.delete,onSuccess:()=>{e.invalidateQueries({queryKey:["tasks"]}),l(null)}}),j=h.reduce((p,f)=>{const v=f.suite||"custom";return p[v]||(p[v]=[]),p[v].push(f),p},{}),S=Object.keys(j).sort((p,f)=>p==="custom"?-1:f==="custom"?1:p.localeCompare(f));return i.jsxs("div",{children:[i.jsxs("div",{className:"flex items-center justify-between mb-6",children:[i.jsxs("div",{children:[i.jsx("h2",{className:"text-xl font-bold",children:"Datasets"}),i.jsx("p",{className:"text-sm text-[var(--text-secondary)] mt-1",children:"Task datasets for evaluating agent configurations."})]}),i.jsxs("div",{className:"flex gap-2",children:[i.jsx(V,{variant:"secondary",onClick:()=>s(!0),children:"Import Suite"}),i.jsx(V,{variant:"primary",onClick:()=>n(!0),children:"+ New Task"})]})]}),d?i.jsx("div",{className:"text-[var(--text-secondary)]",children:"Loading..."}):h.length===0?i.jsx("div",{className:"text-center py-12 text-[var(--text-secondary)]",children:"No tasks yet. Create one or import a built-in suite."}):i.jsx("div",{className:"space-y-4",children:S.map(p=>{const f=j[p],v=!o.has(p);return i.jsxs("div",{children:[i.jsxs("button",{onClick:()=>c(p),className:"flex items-center gap-2 py-2 hover:text-[var(--accent)] transition-colors",children:[v?i.jsx(pg,{size:16,className:"text-[var(--text-secondary)]"}):i.jsx(gi,{size:16,className:"text-[var(--text-secondary)]"}),i.jsx("h3",{className:"text-sm font-medium uppercase tracking-wide",children:p==="custom"?"Custom Tasks":`${p} Suite`}),i.jsx(J,{variant:p==="custom"?"default":"info",children:f.length})]}),v&&i.jsx("div",{className:"grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-3 mt-2",children:f.map(g=>i.jsx(se,{selectable:!0,onClick:()=>l(g),children:i.jsxs("div",{className:"h-32 flex flex-col",children:[i.jsxs("div",{className:"flex items-center gap-2 flex-wrap",children:[i.jsx("span",{className:"font-medium",children:g.name}),g.category&&g.category!=="default"&&i.jsx(J,{variant:"default",children:g.category})]}),i.jsx("p",{className:"text-sm text-[var(--text-secondary)] mt-1 line-clamp-2 flex-1",children:g.prompt}),i.jsx("div",{className:"text-xs text-[var(--text-tertiary)] mt-auto pt-1",children:g.criteria.length>0?i.jsxs("span",{children:[g.criteria.length," eval criteria"]}):i.jsx("span",{className:"text-[var(--text-tertiary)]",children:"No eval criteria"})})]})},g.id))})]},p)})}),i.jsx(B0,{task:a,onClose:()=>l(null),onDelete:p=>{confirm("Delete this task?")&&w.mutate(p)}}),i.jsx(Q0,{isOpen:t,onClose:()=>n(!1),onSubmit:p=>m.mutate(p),isLoading:m.isPending}),i.jsx(V0,{isOpen:r,onClose:()=>s(!1),onSubmit:p=>x.mutate(p),isLoading:x.isPending})]})}function B0({task:e,onClose:t,onDelete:n}){const[r,s]=k.useState("prompt");if(!e)return null;const a=i.jsxs("div",{className:"flex justify-between",children:[i.jsx(V,{variant:"ghost",onClick:()=>n(e.id),className:"text-red-500 hover:text-red-600",children:"Delete Task"}),i.jsx(V,{variant:"secondary",onClick:t,children:"Close"})]});return i.jsx(ns,{isOpen:!!e,onClose:t,title:e.name,size:"lg",footer:a,children:i.jsxs("div",{className:"space-y-4",children:[e.category&&e.category!=="default"&&i.jsx("div",{children:i.jsx(J,{variant:"default",children:e.category})}),i.jsxs("div",{className:"flex gap-1 border-b border-[var(--border)]",children:[i.jsx("button",{onClick:()=>s("prompt"),className:`px-4 py-2 text-sm font-medium border-b-2 -mb-px transition-colors ${r==="prompt"?"border-[var(--accent)] text-[var(--accent)]":"border-transparent text-[var(--text-secondary)] hover:text-[var(--text-primary)]"}`,children:"Prompt"}),i.jsxs("button",{onClick:()=>s("criteria"),className:`px-4 py-2 text-sm font-medium border-b-2 -mb-px transition-colors ${r==="criteria"?"border-[var(--accent)] text-[var(--accent)]":"border-transparent text-[var(--text-secondary)] hover:text-[var(--text-primary)]"}`,children:["Eval Criteria (",e.criteria.length,")"]})]}),r==="prompt"&&i.jsx("div",{className:"p-4 bg-[var(--bg-tertiary)] rounded text-sm whitespace-pre-wrap min-h-[200px]",children:e.prompt}),r==="criteria"&&i.jsx("div",{className:"space-y-2 min-h-[200px]",children:e.criteria.length===0?i.jsx("div",{className:"text-[var(--text-secondary)] text-sm p-4",children:"No evaluation criteria defined for this task."}):e.criteria.map(l=>i.jsxs("div",{className:"p-3 bg-[var(--bg-tertiary)] rounded",children:[i.jsx("div",{className:"font-medium text-sm",children:l.name}),l.instruction&&i.jsx("div",{className:"text-sm text-[var(--text-secondary)] mt-1",children:l.instruction})]},l.name))})]})})}function Q0({isOpen:e,onClose:t,onSubmit:n,isLoading:r}){const[s,a]=k.useState({name:"",prompt:"",criteria:[],category:"default"}),l=()=>{a({...s,criteria:[...s.criteria,{name:"",instruction:"",weight:1}]})},o=(h,d)=>{const m=[...s.criteria];m[h]={...m[h],...d},a({...s,criteria:m})},u=h=>{a({...s,criteria:s.criteria.filter((d,m)=>m!==h)})},c=h=>{h.preventDefault(),!(!s.name.trim()||!s.prompt.trim())&&n({...s,criteria:s.criteria.filter(d=>d.name.trim()&&d.instruction.trim())})};return i.jsx(ns,{isOpen:e,onClose:t,title:"Create Task",children:i.jsxs("form",{onSubmit:c,className:"space-y-4",children:[i.jsx(vn,{label:"Name",value:s.name,onChange:h=>a({...s,name:h.target.value}),placeholder:"e.g., fizzbuzz",required:!0}),i.jsx(S0,{label:"Prompt",value:s.prompt,onChange:h=>a({...s,prompt:h.target.value}),placeholder:"The task description for the agent...",required:!0}),i.jsx(vn,{label:"Category",value:s.category,onChange:h=>a({...s,category:h.target.value}),placeholder:"e.g., coding, research"}),i.jsxs("div",{children:[i.jsxs("div",{className:"flex items-center justify-between mb-2",children:[i.jsx("label",{className:"text-sm text-[var(--text-secondary)]",children:"Evaluation Criteria"}),i.jsx(V,{type:"button",variant:"ghost",size:"sm",onClick:l,children:"+ Add"})]}),i.jsx("div",{className:"space-y-2",children:s.criteria.map((h,d)=>i.jsxs("div",{className:"flex gap-2 items-start",children:[i.jsx(vn,{value:h.name,onChange:m=>o(d,{name:m.target.value}),placeholder:"Name",className:"w-32"}),i.jsx(vn,{value:h.instruction,onChange:m=>o(d,{instruction:m.target.value}),placeholder:"Instruction",className:"flex-1"}),i.jsx(V,{type:"button",variant:"ghost",size:"sm",onClick:()=>u(d),children:"×"})]},d))})]}),i.jsxs("div",{className:"flex justify-end gap-2 pt-4",children:[i.jsx(V,{type:"button",variant:"secondary",onClick:t,children:"Cancel"}),i.jsx(V,{type:"submit",variant:"primary",disabled:r||!s.name.trim()||!s.prompt.trim(),children:r?"Creating...":"Create"})]})]})})}function V0({isOpen:e,onClose:t,onSubmit:n,isLoading:r}){const[s,a]=k.useState(""),{data:l=[],isLoading:o}=ve({queryKey:["suites"],queryFn:()=>Et.listSuites(),enabled:e});return k.useEffect(()=>{l.length>0&&!s&&a(l[0].name)},[l,s]),i.jsx(ns,{isOpen:e,onClose:t,title:"Import Task Suite",children:i.jsxs("div",{className:"space-y-4",children:[i.jsx("p",{className:"text-sm text-[var(--text-secondary)]",children:"Import a built-in task suite for evaluation."}),o?i.jsx("div",{className:"text-[var(--text-secondary)]",children:"Loading suites..."}):l.length===0?i.jsx("div",{className:"text-[var(--text-secondary)]",children:"No suites available."}):i.jsx("div",{className:"space-y-2 max-h-80 overflow-y-auto",children:l.map(u=>i.jsxs("label",{className:`flex items-center gap-3 p-3 border cursor-pointer ${s===u.name?"border-[var(--accent)] bg-[var(--accent)]/10":"border-[var(--border)] hover:border-[var(--accent-dim)]"}`,children:[i.jsx("input",{type:"radio",name:"suite",value:u.name,checked:s===u.name,onChange:()=>a(u.name),className:"accent-[var(--accent)]"}),i.jsxs("span",{className:"capitalize",children:[u.name.replace(/_/g," ")," (",u.task_count," tasks) - ",u.description]})]},u.name))}),i.jsxs("div",{className:"flex justify-end gap-2 pt-4",children:[i.jsx(V,{type:"button",variant:"secondary",onClick:t,children:"Cancel"}),i.jsx(V,{variant:"primary",onClick:()=>n(s),disabled:r||!s,children:r?"Importing...":"Import"})]})]})})}const K0=$u(e=>({jobs:[],setJobs:t=>e({jobs:t})}));function H0(){const e=Lt(),t=Jt(),[n,r]=k.useState(!1),{setJobs:s}=K0(),a=Vu(),{data:l=[],isLoading:o}=ve({queryKey:["jobs",n],queryFn:()=>Ot.list({include_public:n}),refetchInterval:5e3});k.useEffect(()=>{l.length>0&&s(l)},[l,s]);const u=Je({mutationFn:Ot.delete,onSuccess:()=>t.invalidateQueries({queryKey:["jobs"]})});return i.jsxs("div",{children:[i.jsxs("div",{className:"flex items-center justify-between mb-6",children:[i.jsxs("div",{children:[i.jsx("h2",{className:"text-xl font-bold",children:"Experiments"}),i.jsx("p",{className:"text-sm text-[var(--text-secondary)] mt-1",children:"View and manage optimization experiments. Start new experiments from the Agents page."})]}),i.jsxs("div",{className:"flex items-center gap-3",children:[i.jsxs("label",{className:"flex items-center gap-2 text-sm text-[var(--text-secondary)] cursor-pointer",children:[i.jsx("input",{type:"checkbox",checked:n,onChange:c=>r(c.target.checked),className:"rounded border-[var(--border)]"}),i.jsx($i,{className:"w-4 h-4"}),"Show public"]}),i.jsx(V,{variant:"secondary",onClick:()=>e("/agents"),children:"Go to Agents"})]})]}),o?i.jsx("div",{className:"text-[var(--text-secondary)]",children:"Loading..."}):l.length===0?i.jsx("div",{className:"text-center py-12 text-[var(--text-secondary)]",children:"No jobs yet. Go to Agents page to start an optimization."}):i.jsx("div",{className:"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4",children:l.map(c=>{const h=!c.user_id||c.user_id==="anonymous"||a&&c.created_by_name===a;return i.jsx($m,{job:c,onDelete:h?d=>u.mutate(d):void 0},c.id)})})]})}function W0(e,t=!0){return Math.abs(e)<10?"text-[var(--text-secondary)]":(t?e<0:e>0)?"text-green-400":"text-red-400"}function q0(e){return`${e>0?"+":""}${e.toFixed(1)}%`}function Vm(e,t){return t===0?0:(e-t)/t*100}function hs({label:e,values:t,baselineIndex:n,formatter:r,isLowerBetter:s=!0}){const a=t[n];return i.jsxs("tr",{className:"border-b border-[var(--border)] last:border-0",children:[i.jsx("td",{className:"py-2 pr-4 text-[var(--text-secondary)] text-sm",children:e}),t.map((l,o)=>{const u=Vm(l,a),c=o===n;return i.jsxs("td",{className:"py-2 px-4 text-right",children:[i.jsx("div",{className:"font-mono",children:r(l)}),!c&&i.jsx("div",{className:`text-xs ${W0(u,s)}`,children:q0(u)}),c&&i.jsx("div",{className:"text-xs text-[var(--text-secondary)]",children:"(baseline)"})]},o)})]})}function J0({runs:e,baselineRunId:t}){const n=k.useMemo(()=>{if(t){const a=e.findIndex(l=>l.id===t);if(a>=0)return a}return 0},[e,t]);if(e.length<2)return null;const r=Math.min(...e.map(a=>a.tokens_total)),s=Math.max(...e.map(a=>a.score));return i.jsxs(se,{className:"mb-6",children:[i.jsx("h3",{className:"font-medium mb-4",children:"Candidate Comparison"}),i.jsx("div",{className:"overflow-x-auto",children:i.jsxs("table",{className:"w-full text-sm",children:[i.jsx("thead",{children:i.jsxs("tr",{className:"border-b border-[var(--border)]",children:[i.jsx("th",{className:"pb-2 pr-4 text-left text-[var(--text-secondary)] font-medium",children:"Metric"}),e.map((a,l)=>i.jsx("th",{className:"pb-2 px-4 text-right",children:i.jsxs("div",{className:"flex items-center justify-end gap-2",children:[i.jsx("span",{className:"font-medium",children:a.candidate_name}),a.is_pareto&&i.jsx(J,{variant:"success",children:"Optimal"}),l===n&&i.jsx(J,{variant:"info",children:"Base"})]})},a.id))]})}),i.jsxs("tbody",{children:[i.jsx(hs,{label:"Total Tokens",values:e.map(a=>a.tokens_total),baselineIndex:n,formatter:a=>a.toLocaleString(),isLowerBetter:!0}),i.jsx(hs,{label:"Input Tokens",values:e.map(a=>a.tokens_input),baselineIndex:n,formatter:a=>a.toLocaleString(),isLowerBetter:!0}),i.jsx(hs,{label:"Output Tokens",values:e.map(a=>a.tokens_output),baselineIndex:n,formatter:a=>a.toLocaleString(),isLowerBetter:!0}),i.jsx(hs,{label:"Duration",values:e.map(a=>a.duration_seconds),baselineIndex:n,formatter:a=>`${a.toFixed(1)}s`,isLowerBetter:!0}),i.jsx(hs,{label:"Score",values:e.map(a=>a.score*100),baselineIndex:n,formatter:a=>`${a.toFixed(1)}%`,isLowerBetter:!1})]})]})}),i.jsxs("div",{className:"mt-4 pt-4 border-t border-[var(--border)]",children:[i.jsx("h4",{className:"text-sm font-medium mb-2 text-[var(--text-secondary)]",children:"Key Insights"}),i.jsxs("ul",{className:"text-sm space-y-1 text-[var(--text-secondary)]",children:[e.map(a=>{const l=Vm(a.tokens_total,e[n].tokens_total);return a.tokens_total===r&&l<-5?i.jsxs("li",{className:"flex items-center gap-2",children:[i.jsx("span",{className:"text-green-400",children:"✓"}),i.jsxs("span",{children:[i.jsx("strong",{children:a.candidate_name})," uses ",Math.abs(l).toFixed(0),"% fewer tokens"]})]},`token-${a.id}`):null}),e.map(a=>a.score===s&&a.passed?i.jsxs("li",{className:"flex items-center gap-2",children:[i.jsx("span",{className:"text-green-400",children:"✓"}),i.jsxs("span",{children:[i.jsx("strong",{children:a.candidate_name})," achieved highest score (",(a.score*100).toFixed(0),"%)"]})]},`score-${a.id}`):null),e.filter(a=>a.is_pareto).length>0&&i.jsxs("li",{className:"flex items-center gap-2",children:[i.jsx("span",{className:"text-purple-400",children:"★"}),i.jsxs("span",{children:["Optimal candidates (best tradeoff):"," ",e.filter(a=>a.is_pareto).map(a=>a.candidate_name).join(", ")]})]})]})]}),i.jsxs("div",{className:"mt-4 pt-4 border-t border-[var(--border)]",children:[i.jsx("h4",{className:"text-sm font-medium mb-3 text-[var(--text-secondary)]",children:"Token Efficiency"}),i.jsx("div",{className:"space-y-2",children:e.map(a=>{const l=a.tokens_total/e[n].tokens_total*100,o=a.tokens_total<=r;return i.jsxs("div",{className:"flex items-center gap-3",children:[i.jsx("div",{className:"w-24 text-sm truncate",title:a.candidate_name,children:a.candidate_name}),i.jsx("div",{className:"flex-1 h-6 bg-[var(--bg-primary)] rounded overflow-hidden",children:i.jsx("div",{className:`h-full transition-all duration-300 ${o?"bg-green-500":"bg-blue-500"}`,style:{width:`${Math.min(l,100)}%`}})}),i.jsx("div",{className:"w-20 text-right font-mono text-sm",children:a.tokens_total.toLocaleString()})]},a.id)})})]})]})}function G0({summaries:e,height:t=350}){const n=k.useRef(null),[r,s]=k.useState(600),[a,l]=k.useState("tokens"),[o,u]=k.useState(null),[c,h]=k.useState({x:0,y:0});k.useEffect(()=>{const b=()=>{n.current&&s(n.current.clientWidth)};return b(),window.addEventListener("resize",b),()=>window.removeEventListener("resize",b)},[]);const d={top:30,right:30,bottom:50,left:60},m=r-d.left-d.right,x=t-d.top-d.bottom,w=b=>a==="tokens"?b.avg_tokens:b.avg_duration,{xScale:j,yScale:S,xTicks:p,yTicks:f,paretoLine:v}=k.useMemo(()=>{if(e.length===0||m<=0)return{xScale:()=>0,yScale:()=>0,xTicks:[],yTicks:[],paretoLine:[]};const b=e.map(w),N=e.map(T=>T.avg_score),_=Math.min(...b)*.9,F=Math.max(...b)*1.1,P=Math.min(...N,.5),B=Math.min(Math.max(...N)*1.05,1),D=T=>(T-_)/(F-_)*m,U=T=>x-(T-P)/(B-P)*x,ne=Array.from({length:5},(T,A)=>_+A/4*(F-_)),je=Array.from({length:5},(T,A)=>P+A/4*(B-P)),ie=e.filter(T=>T.is_pareto).sort((T,A)=>w(T)-w(A)).map(T=>({x:D(w(T)),y:U(T.avg_score)}));return{xScale:D,yScale:U,xTicks:ne,yTicks:je,paretoLine:ie}},[e,m,x,a]);if(e.length===0)return i.jsx("div",{className:"text-center py-8 text-[var(--text-secondary)]",children:"No data to display"});const g=b=>a==="tokens"?b>=1e6?`${(b/1e6).toFixed(1)}M`:b>=1e3?`${(b/1e3).toFixed(0)}K`:b.toFixed(0):`${b.toFixed(1)}s`,C=(b,N)=>{var F;const _=(F=n.current)==null?void 0:F.getBoundingClientRect();_&&h({x:N.clientX-_.left,y:N.clientY-_.top}),u(b)};return i.jsxs("div",{ref:n,className:"w-full relative",children:[i.jsx("div",{className:"flex justify-end mb-2",children:i.jsxs("div",{className:"inline-flex rounded border border-[var(--border)] text-xs",children:[i.jsx("button",{className:`px-3 py-1 ${a==="tokens"?"bg-[var(--accent)] text-black":"text-[var(--text-secondary)] hover:text-[var(--text-primary)]"}`,onClick:()=>l("tokens"),children:"Tokens"}),i.jsx("button",{className:`px-3 py-1 ${a==="duration"?"bg-[var(--accent)] text-black":"text-[var(--text-secondary)] hover:text-[var(--text-primary)]"}`,onClick:()=>l("duration"),children:"Latency"})]})}),i.jsx("svg",{width:r,height:t,className:"font-mono text-xs",children:i.jsxs("g",{transform:`translate(${d.left}, ${d.top})`,children:[p.map((b,N)=>i.jsx("line",{x1:j(b),y1:0,x2:j(b),y2:x,stroke:"var(--border)",strokeDasharray:"2,2"},`x-grid-${N}`)),f.map((b,N)=>i.jsx("line",{x1:0,y1:S(b),x2:m,y2:S(b),stroke:"var(--border)",strokeDasharray:"2,2"},`y-grid-${N}`)),v.length>1&&i.jsx("polyline",{points:v.map(b=>`${b.x},${b.y}`).join(" "),fill:"none",stroke:"var(--accent)",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"}),e.slice().sort((b,N)=>(b.is_pareto?1:0)-(N.is_pareto?1:0)).map(b=>{const N=j(w(b)),_=S(b.avg_score),F=b.is_pareto,P=(o==null?void 0:o.candidate_name)===b.candidate_name;return i.jsxs("g",{onMouseEnter:B=>C(b,B),onMouseLeave:()=>u(null),children:[i.jsx("circle",{cx:N,cy:_,r:P?10:F?8:6,fill:F?"var(--accent)":"transparent",stroke:P?"var(--text-primary)":F?"var(--accent)":"var(--text-secondary)",strokeWidth:P?3:2,className:"cursor-pointer transition-all"}),F&&!P&&i.jsx("text",{x:N,y:_-12,textAnchor:"middle",fill:"var(--text-primary)",fontSize:10,className:"pointer-events-none",children:b.candidate_name.replace(/^baseline_/,"").slice(0,15)})]},b.candidate_name)}),i.jsx("line",{x1:0,y1:x,x2:m,y2:x,stroke:"var(--text-secondary)"}),p.map((b,N)=>i.jsxs("g",{transform:`translate(${j(b)}, ${x})`,children:[i.jsx("line",{y2:5,stroke:"var(--text-secondary)"}),i.jsx("text",{y:20,textAnchor:"middle",fill:"var(--text-secondary)",fontSize:10,children:g(b)})]},`x-tick-${N}`)),i.jsx("text",{x:m/2,y:x+40,textAnchor:"middle",fill:"var(--text-secondary)",fontSize:11,children:a==="tokens"?"Tokens (cost)":"Duration (latency)"}),i.jsx("line",{x1:0,y1:0,x2:0,y2:x,stroke:"var(--text-secondary)"}),f.map((b,N)=>i.jsxs("g",{transform:`translate(0, ${S(b)})`,children:[i.jsx("line",{x2:-5,stroke:"var(--text-secondary)"}),i.jsxs("text",{x:-10,textAnchor:"end",dominantBaseline:"middle",fill:"var(--text-secondary)",fontSize:10,children:[(b*100).toFixed(0),"%"]})]},`y-tick-${N}`)),i.jsx("text",{transform:`translate(-45, ${x/2}) rotate(-90)`,textAnchor:"middle",fill:"var(--text-secondary)",fontSize:11,children:"Score (quality)"})]})}),o&&i.jsxs("div",{className:"absolute z-10 bg-[var(--bg-secondary)] border border-[var(--border)] rounded-lg shadow-lg p-3 text-sm pointer-events-none",style:{left:Math.min(c.x+15,r-200),top:c.y-10,maxWidth:220},children:[i.jsx("div",{className:"font-medium text-[var(--text-primary)] truncate mb-2",children:o.candidate_name.replace(/^baseline_/,"")}),i.jsxs("div",{className:"grid grid-cols-2 gap-x-4 gap-y-1 text-xs",children:[i.jsx("span",{className:"text-[var(--text-secondary)]",children:"Score:"}),i.jsxs("span",{className:"text-right font-medium",children:[(o.avg_score*100).toFixed(1),"%"]}),i.jsx("span",{className:"text-[var(--text-secondary)]",children:"Tokens:"}),i.jsxs("span",{className:"text-right",children:[(o.avg_tokens/1e3).toFixed(1),"K"]}),i.jsx("span",{className:"text-[var(--text-secondary)]",children:"Duration:"}),i.jsxs("span",{className:"text-right",children:[o.avg_duration.toFixed(1),"s"]}),i.jsx("span",{className:"text-[var(--text-secondary)]",children:"Pass rate:"}),i.jsxs("span",{className:"text-right",children:[o.passed_runs,"/",o.total_runs]})]}),o.is_pareto&&i.jsx("div",{className:"mt-2 pt-2 border-t border-[var(--border)] text-xs text-[var(--accent)]",children:"Optimal (best tradeoff)"})]})]})}function Y0(e=2e3){const[t,n]=k.useState(!1),[r,s]=k.useState(null),a=k.useCallback(async o=>{try{return await navigator.clipboard.writeText(o),n(!0),s(null),setTimeout(()=>n(!1),e),!0}catch{return s("Failed to copy to clipboard"),n(!1),!1}},[e]),l=k.useCallback(()=>{n(!1),s(null)},[]);return{copy:a,copied:t,error:r,reset:l}}function X0({isOpen:e,onClose:t,title:n,itemId:r,itemType:s,isPublic:a,createdByName:l,onTogglePublic:o}){const[u,c]=k.useState(!1),{copy:h,copied:d}=Y0(),m=`${window.location.origin}/${s}s/${r}`,x=async()=>{c(!0);try{await o(!a)}finally{c(!1)}},w=()=>{h(m)};return i.jsx(ns,{isOpen:e,onClose:t,title:n,children:i.jsxs("div",{className:"space-y-4",children:[i.jsxs("div",{className:"flex items-center justify-between p-3 bg-[var(--bg-tertiary)] rounded",children:[i.jsxs("div",{className:"flex items-center gap-3",children:[a?i.jsx($i,{className:"w-5 h-5 text-[var(--accent)]"}):i.jsx(Pm,{className:"w-5 h-5 text-[var(--text-secondary)]"}),i.jsxs("div",{children:[i.jsx("div",{className:"font-medium",children:a?"Public":"Private"}),i.jsx("div",{className:"text-sm text-[var(--text-secondary)]",children:a?"Anyone with the link can view":"Only you can access"})]})]}),i.jsx("button",{onClick:x,disabled:u,className:`relative inline-flex h-6 w-11 items-center rounded-full transition-colors ${a?"bg-[var(--accent)]":"bg-[var(--border)]"} ${u?"opacity-50 cursor-not-allowed":""}`,children:i.jsx("span",{className:`inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${a?"translate-x-6":"translate-x-1"}`})})]}),a&&i.jsxs("div",{className:"space-y-2",children:[i.jsx("label",{className:"text-sm text-[var(--text-secondary)]",children:"Share link"}),i.jsxs("div",{className:"flex gap-2",children:[i.jsx("input",{type:"text",readOnly:!0,value:m,className:"flex-1 px-3 py-2 bg-[var(--bg-primary)] border border-[var(--border)] rounded text-sm font-mono"}),i.jsx(V,{variant:"secondary",onClick:w,children:d?i.jsxs(i.Fragment,{children:[i.jsx(mg,{className:"w-4 h-4 mr-1"}),"Copied"]}):i.jsxs(i.Fragment,{children:[i.jsx(yg,{className:"w-4 h-4 mr-1"}),"Copy"]})})]})]}),l&&i.jsxs("div",{className:"text-sm text-[var(--text-secondary)]",children:["Created by ",i.jsx("span",{className:"text-[var(--text-primary)]",children:l})]}),i.jsx("div",{className:"text-xs text-[var(--text-secondary)] pt-2 border-t border-[var(--border)]",children:a?i.jsxs(i.Fragment,{children:[i.jsxs("p",{children:["Public ",s,"s can be viewed by anyone with the link."]}),i.jsxs("p",{className:"mt-1",children:["Only you can edit or delete this ",s,"."]})]}):i.jsxs("p",{children:["Make this ",s," public to share it with others."]})})]})})}function Z0({job:e,onUpdate:t}){const[n,r]=k.useState(!1),s=async a=>{await Ot.update(e.id,{is_public:a}),t()};return i.jsxs(i.Fragment,{children:[i.jsxs(V,{variant:"secondary",size:"sm",onClick:()=>r(!0),title:e.is_public?"Sharing settings":"Share this job",children:[i.jsx(Eg,{className:"w-4 h-4 mr-1"}),e.is_public?"Shared":"Share"]}),i.jsx(X0,{isOpen:n,onClose:()=>r(!1),title:"Share Job",itemId:e.id,itemType:"job",isPublic:e.is_public,createdByName:e.created_by_name,onTogglePublic:s})]})}function e1(){const{jobId:e}=Di(),t=Lt(),n=Jt(),[r,s]=k.useState(null),[a,l]=k.useState(!1),[o,u]=k.useState(null),[c,h]=k.useState([]),[d,m]=k.useState(null),[x,w]=k.useState(null),[j,S]=k.useState("results"),[p,f]=k.useState("score"),[v,g]=k.useState("desc"),[C,b]=k.useState(!1),{data:N,isLoading:_}=ve({queryKey:["jobs",e],queryFn:()=>Ot.get(e),enabled:!!e,refetchInterval:a?2e3:!1}),{data:F=[]}=ve({queryKey:["runs",e],queryFn:()=>Mo.list({job_id:e}),enabled:!!e,refetchInterval:a?2e3:!1}),{data:P}=ve({queryKey:["job-summary",e],queryFn:()=>Mo.getJobSummary(e),enabled:!!e&&(N==null?void 0:N.status)==="completed"}),B=Je({mutationFn:async()=>{l(!0),h([]),m(null),w(null);for await(const R of Ot.start(e))s(R),R.current_candidate&&R.current_task&&m(O=>(O&&(O.candidate!==R.current_candidate||O.task!==R.current_task)&&h(Z=>[...Z,{candidate_name:O.candidate,task_name:O.task,completed_at:Date.now()}]),{candidate:R.current_candidate,task:R.current_task})),R.event==="error"&&(w(R.message),l(!1),n.invalidateQueries({queryKey:["jobs",e]})),R.event==="complete"&&(m(O=>(O&&h(Z=>[...Z,{candidate_name:O.candidate,task_name:O.task,completed_at:Date.now()}]),null)),l(!1),n.invalidateQueries({queryKey:["jobs",e]}),n.invalidateQueries({queryKey:["runs",e]}),n.invalidateQueries({queryKey:["job-summary",e]}))}}),D=Je({mutationFn:()=>Ot.cancel(e),onSuccess:()=>{l(!1),n.invalidateQueries({queryKey:["jobs",e]})}});k.useEffect(()=>{(N==null?void 0:N.status)==="running"&&l(!0)},[N==null?void 0:N.status]);const U=k.useMemo(()=>{const R=new Map;for(const O of F)R.has(O.task_name)||R.set(O.task_name,[]),R.get(O.task_name).push(O);return R},[F]),ne=k.useMemo(()=>Array.from(U.keys()),[U]),je=k.useMemo(()=>{if(!(P!=null&&P.candidate_summaries))return[];let R=[...P.candidate_summaries];return C&&(R=R.filter(O=>O.is_pareto)),R.sort((O,Z)=>{let he,Ne;switch(p){case"score":he=O.avg_score,Ne=Z.avg_score;break;case"tokens":he=O.avg_tokens,Ne=Z.avg_tokens;break;case"duration":he=O.avg_duration,Ne=Z.avg_duration;break;case"pass_rate":he=O.passed_runs/O.total_runs,Ne=Z.passed_runs/Z.total_runs;break}return v==="desc"?Ne-he:he-Ne}),R},[P,p,v,C]),Ge=R=>{p===R?g(v==="desc"?"asc":"desc"):(f(R),g(R==="tokens"||R==="duration"?"asc":"desc"))},ie=({label:R,sortKeyVal:O})=>i.jsx("th",{className:"pb-2 cursor-pointer hover:text-[var(--text-primary)] select-none",onClick:()=>Ge(O),children:i.jsxs("div",{className:"flex items-center gap-1",children:[R,p===O&&i.jsx(dg,{size:12,className:v==="asc"?"rotate-180":""})]})});if(_)return i.jsx("div",{className:"text-[var(--text-secondary)]",children:"Loading..."});if(!N)return i.jsx("div",{className:"text-[var(--text-secondary)]",children:"Job not found"});const T=Vu(),A=!N.user_id||N.user_id==="anonymous"||T&&N.created_by_name===T,L=N.is_public&&!A,K=()=>{n.invalidateQueries({queryKey:["jobs",e]})},X=R=>{const O={pending:"default",running:"info",completed:"success",failed:"error",cancelled:"warning"};return i.jsx(J,{variant:O[R]||"default",children:R})};return i.jsxs("div",{children:[i.jsxs("div",{className:"flex items-center justify-between mb-6",children:[i.jsxs("div",{children:[i.jsxs("div",{className:"flex items-center gap-3",children:[i.jsx("button",{onClick:()=>t("/jobs"),className:"text-[var(--text-secondary)] hover:text-[var(--text-primary)]",children:"← Jobs"}),i.jsx("h2",{className:"text-xl font-bold",children:N.name||`Job ${N.id.slice(0,8)}`}),X(N.status),N.is_public&&i.jsxs(J,{variant:"info",children:[i.jsx($i,{className:"w-3 h-3 mr-1 inline"}),"Public"]})]}),i.jsxs("div",{className:"flex items-center gap-3 mt-1",children:[i.jsxs("code",{className:"text-xs bg-[var(--bg-primary)] px-2 py-0.5 rounded font-mono text-[var(--text-secondary)]",children:[N.id.slice(0,8),"..."]}),i.jsxs("span",{className:"text-sm text-[var(--text-secondary)]",children:[N.candidate_ids.length," candidates × ",N.task_ids.length," tasks = ",N.total_experiments," experiments"]}),N.is_public&&N.created_by_name&&i.jsxs("span",{className:"text-sm text-[var(--text-secondary)]",children:["Created by ",i.jsx("span",{className:"text-[var(--text-primary)]",children:N.created_by_name})]})]})]}),i.jsxs("div",{className:"flex gap-2",children:[A&&i.jsx(Z0,{job:N,onUpdate:K}),L&&i.jsx(J,{variant:"default",children:"View Only"}),A&&N.status==="pending"&&i.jsx(V,{variant:"primary",onClick:()=>B.mutate(),disabled:B.isPending,children:B.isPending?"Starting...":"Start"}),A&&N.status==="running"&&i.jsx(V,{variant:"danger",onClick:()=>D.mutate(),disabled:D.isPending,children:"Cancel"})]})]}),(x||N.error)&&i.jsx(se,{className:"mb-6 border-red-500/50 bg-red-500/10",children:i.jsxs("div",{className:"flex items-start gap-3",children:[i.jsx("div",{className:"w-5 h-5 rounded-full bg-red-500 flex items-center justify-center text-white text-xs font-bold flex-shrink-0 mt-0.5",children:"!"}),i.jsxs("div",{children:[i.jsx("h3",{className:"font-medium text-red-400",children:"Error"}),i.jsx("p",{className:"text-sm text-[var(--text-secondary)] mt-1",children:x||N.error})]})]})}),(a||r)&&i.jsxs(se,{className:"mb-6",children:[i.jsxs("div",{className:"flex items-center justify-between mb-2",children:[i.jsx("span",{className:"font-medium",children:"Progress"}),i.jsxs("span",{className:"text-[var(--accent)]",children:[(r==null?void 0:r.completed)||N.completed_experiments,"/",(r==null?void 0:r.total)||N.total_experiments]})]}),i.jsx("div",{className:"w-full bg-[var(--bg-primary)] h-2 mb-2",children:i.jsx("div",{className:"h-full bg-[var(--accent)] transition-all",style:{width:`${((r==null?void 0:r.completed)||N.completed_experiments)/((r==null?void 0:r.total)||N.total_experiments)*100}%`}})}),(r==null?void 0:r.message)&&i.jsx("p",{className:"text-sm text-[var(--text-secondary)]",children:r.message}),a&&i.jsxs("div",{className:"mt-4 border-t border-[var(--border)] pt-4",children:[(r==null?void 0:r.current_candidate)&&(r==null?void 0:r.current_task)&&i.jsxs("div",{className:"mb-3",children:[i.jsx("span",{className:"text-xs text-[var(--text-secondary)] uppercase tracking-wider",children:"Currently Running"}),i.jsxs("div",{className:"flex items-center gap-2 mt-1 px-3 py-2 bg-blue-500/10 border border-blue-500/30 rounded",children:[i.jsx("div",{className:"w-2 h-2 bg-blue-400 rounded-full animate-pulse"}),i.jsx("span",{className:"font-medium",children:r.current_candidate}),i.jsx("span",{className:"text-[var(--text-secondary)]",children:"→"}),i.jsx("span",{children:r.current_task})]})]}),c.length>0&&i.jsxs("div",{children:[i.jsxs("span",{className:"text-xs text-[var(--text-secondary)] uppercase tracking-wider",children:["Completed (",c.length,")"]}),i.jsx("div",{className:"mt-1 max-h-40 overflow-y-auto space-y-1",children:c.map((R,O)=>i.jsxs("div",{className:"flex items-center gap-2 px-3 py-1.5 bg-green-500/10 border border-green-500/30 rounded text-sm",children:[i.jsx("div",{className:"w-2 h-2 bg-green-400 rounded-full"}),i.jsx("span",{className:"font-medium",children:R.candidate_name}),i.jsx("span",{className:"text-[var(--text-secondary)]",children:"→"}),i.jsx("span",{children:R.task_name})]},`${R.candidate_name}-${R.task_name}-${O}`))})]})]})]}),(N.status==="completed"||F.length>0)&&i.jsxs("div",{className:"flex gap-1 mb-6 border-b border-[var(--border)]",children:[i.jsxs("button",{onClick:()=>S("results"),className:`flex items-center gap-2 px-4 py-2 text-sm font-medium border-b-2 transition-colors ${j==="results"?"border-[var(--accent)] text-[var(--accent)]":"border-transparent text-[var(--text-secondary)] hover:text-[var(--text-primary)]"}`,children:[i.jsx(fg,{size:16}),"Results"]}),i.jsxs("button",{onClick:()=>S("compare"),className:`flex items-center gap-2 px-4 py-2 text-sm font-medium border-b-2 transition-colors ${j==="compare"?"border-[var(--accent)] text-[var(--accent)]":"border-transparent text-[var(--text-secondary)] hover:text-[var(--text-primary)]"}`,children:[i.jsx(kg,{size:16}),"Compare"]}),i.jsxs("button",{onClick:()=>S("runs"),className:`flex items-center gap-2 px-4 py-2 text-sm font-medium border-b-2 transition-colors ${j==="runs"?"border-[var(--accent)] text-[var(--accent)]":"border-transparent text-[var(--text-secondary)] hover:text-[var(--text-primary)]"}`,children:[i.jsx(bg,{size:16}),"Runs (",F.length,")"]})]}),j==="results"&&i.jsxs(i.Fragment,{children:[P&&P.candidate_summaries.length>1&&i.jsxs(se,{className:"mb-6",children:[i.jsx("div",{className:"flex items-start justify-between mb-4",children:i.jsxs("div",{children:[i.jsx("h3",{className:"font-medium",children:"Quality vs. Cost Tradeoff"}),i.jsxs("p",{className:"text-sm text-[var(--text-secondary)] mt-1",children:["Candidates on the frontier (connected line) are ",i.jsx("strong",{children:"optimal"})," - no other candidate beats them on both score AND cost."]})]})}),i.jsxs("div",{className:"mb-4 p-3 bg-[var(--bg-primary)] rounded border border-[var(--border)] text-xs text-[var(--text-secondary)]",children:[i.jsx("strong",{className:"text-[var(--text-primary)]",children:"How optimal tradeoffs are calculated:"})," A candidate is optimal if there's no other candidate that has both a higher score AND lower cost. For example, if Candidate A has 95% score at 50K tokens and Candidate B has 90% score at 40K tokens, both are optimal - A is better on score, B is better on cost. But if Candidate C has 85% score at 60K tokens, it's ",i.jsx("em",{children:"not"})," optimal because B beats it on both metrics."]}),i.jsx(G0,{summaries:P.candidate_summaries,height:350})]}),P&&i.jsxs(se,{className:"mb-6",children:[i.jsxs("div",{className:"flex items-center justify-between mb-4",children:[i.jsx("h3",{className:"font-medium",children:"Results Summary"}),i.jsxs("label",{className:"flex items-center gap-2 text-sm text-[var(--text-secondary)] cursor-pointer",children:[i.jsx("input",{type:"checkbox",checked:C,onChange:R=>b(R.target.checked),className:"rounded border-[var(--border)]"}),"Optimal only"]})]}),i.jsx("div",{className:"overflow-x-auto",children:i.jsxs("table",{className:"w-full text-sm",children:[i.jsx("thead",{children:i.jsxs("tr",{className:"text-left text-[var(--text-secondary)] border-b border-[var(--border)]",children:[i.jsx("th",{className:"pb-2",children:"Candidate"}),i.jsx(ie,{label:"Score",sortKeyVal:"score"}),i.jsx(ie,{label:"Tokens",sortKeyVal:"tokens"}),i.jsx(ie,{label:"Duration",sortKeyVal:"duration"}),i.jsx(ie,{label:"Pass Rate",sortKeyVal:"pass_rate"}),i.jsx("th",{className:"pb-2",children:"Optimal"})]})}),i.jsx("tbody",{children:je.map((R,O)=>i.jsxs("tr",{className:`border-b border-[var(--border)] ${O===0?"bg-[var(--accent)]/10":""}`,children:[i.jsxs("td",{className:"py-2 font-medium",children:[O===0&&i.jsx("span",{className:"text-[var(--accent)] mr-1",children:"#1"}),R.candidate_name.replace(/^baseline_/,"")]}),i.jsxs("td",{className:"py-2",children:[(R.avg_score*100).toFixed(1),"%"]}),i.jsxs("td",{className:"py-2",children:[(R.avg_tokens/1e3).toFixed(1),"K"]}),i.jsxs("td",{className:"py-2",children:[R.avg_duration.toFixed(1),"s"]}),i.jsxs("td",{className:"py-2",children:[R.passed_runs,"/",R.total_runs]}),i.jsx("td",{className:"py-2",children:R.is_pareto&&i.jsx(J,{variant:"success",children:"Optimal"})})]},R.candidate_name))})]})}),i.jsx("p",{className:"text-xs text-[var(--text-secondary)] mt-3",children:"Click column headers to sort. The #1 ranked candidate is highlighted based on your sort criteria."})]}),!P&&i.jsx(se,{children:i.jsx("div",{className:"text-center py-8 text-[var(--text-secondary)]",children:a?"Results will appear here after the job completes.":"No results yet. Start the job to see results."})})]}),j==="compare"&&i.jsxs(se,{children:[i.jsx("h3",{className:"font-medium mb-4",children:"Compare Candidates by Task"}),ne.length>0?i.jsxs(i.Fragment,{children:[i.jsx("div",{className:"flex flex-wrap gap-2 mb-4",children:ne.map(R=>i.jsx("button",{onClick:()=>u(o===R?null:R),className:`px-3 py-1 text-sm rounded border transition-colors ${o===R?"bg-[var(--accent)] text-white border-[var(--accent)]":"border-[var(--border)] hover:border-[var(--accent-dim)]"}`,children:R},R))}),o&&U.get(o)?i.jsx(J0,{runs:U.get(o).map(R=>({id:R.id,candidate_name:R.candidate_name,tokens_input:0,tokens_output:0,tokens_total:R.tokens_total,duration_seconds:R.duration_seconds,score:R.score,passed:R.passed,is_pareto:R.is_pareto}))}):i.jsx("div",{className:"text-center py-8 text-[var(--text-secondary)]",children:"Select a task above to compare how different candidates performed on it."})]}):i.jsx("div",{className:"text-center py-8 text-[var(--text-secondary)]",children:a?"Comparison data will appear here after runs complete.":"No runs yet. Start the job to compare candidates."})]}),j==="runs"&&i.jsxs(se,{children:[i.jsx("h3",{className:"font-medium mb-4",children:"All Experiment Runs"}),F.length===0?i.jsx("div",{className:"text-center py-8 text-[var(--text-secondary)]",children:a?"Runs will appear here as they complete. See progress above for live status.":"No runs yet. Start the job to see results."}):i.jsx("div",{className:"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-3",children:F.map(R=>i.jsxs("div",{className:"p-3 bg-[var(--bg-primary)] rounded border border-[var(--border)] cursor-pointer hover:border-[var(--accent-dim)] transition-colors",onClick:()=>t(`/runs/${R.id}`),children:[i.jsxs("div",{className:"flex items-center justify-between mb-2",children:[i.jsxs("span",{className:`text-lg font-bold ${R.passed?"text-green-400":"text-red-400"}`,children:[(R.score*100).toFixed(0),"%"]}),R.is_pareto&&i.jsx(J,{variant:"success",children:"Optimal"})]}),i.jsx("div",{className:"text-sm font-medium truncate",title:R.candidate_name,children:R.candidate_name.replace(/^baseline_/,"")}),i.jsx("div",{className:"text-xs text-[var(--text-secondary)] truncate",children:R.task_name}),i.jsxs("div",{className:"flex items-center gap-3 mt-2 text-xs text-[var(--text-secondary)]",children:[i.jsxs("span",{children:[(R.tokens_total/1e3).toFixed(1),"K tokens"]}),i.jsxs("span",{children:[R.duration_seconds.toFixed(1),"s"]})]})]},R.id))})]})]})}const xn={input:"bg-blue-500",output:"bg-emerald-500",inputText:"text-blue-400",outputText:"text-emerald-400"};function Td(e){return e>=1e3?`${(e/1e3).toFixed(1)}k`:String(e)}function Od({input:e,output:t,maxValue:n,height:r=24,showLabels:s=!0}){const a=e+t;if(a===0)return i.jsx("div",{className:"flex items-center gap-2 w-full",children:i.jsx("div",{className:"rounded bg-[var(--bg-primary)] flex-1",style:{height:`${r}px`}})});const l=n>0?a/n*100:100;return i.jsxs("div",{className:"flex items-center gap-3 w-full",children:[i.jsx("div",{className:"relative rounded overflow-hidden bg-[var(--bg-primary)] flex-1",style:{height:`${r}px`},children:i.jsxs("div",{className:"h-full flex transition-all duration-300",style:{width:`${l}%`},children:[i.jsx("div",{className:`h-full ${xn.input} transition-all`,style:{width:`${e/a*100}%`},title:`Input: ${e.toLocaleString()} tokens`}),i.jsx("div",{className:`h-full ${xn.output} transition-all`,style:{width:`${t/a*100}%`},title:`Output: ${t.toLocaleString()} tokens`})]})}),s&&i.jsxs("div",{className:"flex items-center gap-1 text-xs font-mono text-[var(--text-secondary)] min-w-[90px] justify-end",children:[i.jsxs("span",{className:xn.inputText,children:["↑",Td(e)]}),i.jsx("span",{children:"/"}),i.jsxs("span",{className:xn.outputText,children:["↓",Td(t)]})]})]})}function wl({label:e,value:t,color:n="default"}){const r={default:"text-[var(--text-primary)]",input:xn.inputText,output:xn.outputText}[n];return i.jsxs("div",{className:"flex-1 p-3 bg-[var(--bg-primary)] border border-[var(--border)] rounded",children:[i.jsx("div",{className:"text-xs text-[var(--text-secondary)] mb-1",children:e}),i.jsx("div",{className:`font-mono text-lg font-bold ${r}`,children:t})]})}function Km({tokensInput:e,tokensOutput:t,tokensTotal:n,turns:r}){const s=n>0?Math.round(e/n*100):0,a=n>0?Math.round(t/n*100):0,l=k.useMemo(()=>{if(!r||r.length===0)return null;let u=0,c=0;return r.map(h=>(u+=h.input,c+=h.output,{input:u,output:c,total:u+c}))},[r]),o=l?Math.max(...l.map(u=>u.total)):n;return i.jsxs(se,{className:"mb-6",children:[i.jsx("h3",{className:"font-medium mb-4",children:"Token Usage"}),i.jsx("div",{className:"mb-4",children:i.jsx(Od,{input:e,output:t,maxValue:n,height:32})}),i.jsxs("div",{className:"flex items-center gap-6 text-xs mb-4",children:[i.jsxs("div",{className:"flex items-center gap-2",children:[i.jsx("div",{className:`w-3 h-3 rounded ${xn.input}`}),i.jsxs("span",{className:"text-[var(--text-secondary)]",children:["Input (",s,"%)"]})]}),i.jsxs("div",{className:"flex items-center gap-2",children:[i.jsx("div",{className:`w-3 h-3 rounded ${xn.output}`}),i.jsxs("span",{className:"text-[var(--text-secondary)]",children:["Output (",a,"%)"]})]})]}),i.jsxs("div",{className:"flex gap-3 mb-4",children:[i.jsx(wl,{label:"Input Tokens",value:e.toLocaleString(),color:"input"}),i.jsx(wl,{label:"Output Tokens",value:t.toLocaleString(),color:"output"}),i.jsx(wl,{label:"Total Tokens",value:n.toLocaleString()})]}),l&&l.length>1&&i.jsxs("div",{className:"border-t border-[var(--border)] pt-4",children:[i.jsxs("h4",{className:"text-sm font-medium mb-3 text-[var(--text-secondary)]",children:["Token Accumulation (",r.length," turns)"]}),i.jsx("div",{className:"space-y-2",children:r.map((u,c)=>i.jsxs("div",{className:"flex items-center gap-3",children:[i.jsx("div",{className:"w-6 h-6 rounded-full bg-[var(--bg-primary)] border border-[var(--border)] flex items-center justify-center text-xs font-medium",children:c+1}),i.jsx("div",{className:"flex-1",children:i.jsx(Od,{input:l[c].input,output:l[c].output,maxValue:o,height:16})})]},c))})]}),i.jsx("div",{className:"mt-4 text-xs text-[var(--text-secondary)] border-t border-[var(--border)] pt-3",children:"Token usage affects API cost. Input tokens are typically cheaper than output tokens."})]})}function t1(){const{runId:e}=Di(),t=Lt(),{data:n,isLoading:r}=ve({queryKey:["runs",e],queryFn:()=>Mo.get(e),enabled:!!e});return r?i.jsx("div",{className:"text-[var(--text-secondary)]",children:"Loading..."}):n?i.jsxs("div",{children:[i.jsxs("div",{className:"mb-6",children:[i.jsx("div",{className:"flex items-center gap-3 mb-2",children:i.jsx("button",{onClick:()=>t(`/jobs/${n.job_id}`),className:"text-[var(--text-secondary)] hover:text-[var(--text-primary)]",children:"← Back to Job"})}),i.jsxs("div",{className:"flex items-center gap-3",children:[i.jsx("h2",{className:"text-xl font-bold",children:n.candidate_name}),i.jsx("span",{className:"text-[var(--text-secondary)]",children:"→"}),i.jsx("span",{className:"text-lg",children:n.task_name}),n.is_pareto&&i.jsx(J,{variant:"success",children:"Optimal"})]})]}),i.jsxs("div",{className:"grid grid-cols-4 gap-4 mb-6",children:[i.jsx(Ta,{label:"Score",value:`${(n.score*100).toFixed(1)}%`,status:n.passed?"success":"error"}),i.jsx(Ta,{label:"Total Tokens",value:n.tokens_total.toLocaleString()}),i.jsx(Ta,{label:"Duration",value:`${n.duration_seconds.toFixed(1)}s`}),i.jsx(Ta,{label:"Status",value:n.passed?"Passed":"Failed",status:n.passed?"success":"error"})]}),i.jsx(Km,{tokensInput:n.tokens_input,tokensOutput:n.tokens_output,tokensTotal:n.tokens_total}),i.jsxs(se,{className:"mb-6",children:[i.jsx("h3",{className:"font-medium mb-3",children:"Evaluation"}),n.reasoning&&i.jsx("p",{className:"text-sm text-[var(--text-secondary)] mb-4",children:n.reasoning}),n.criteria_results.length>0&&i.jsx("div",{className:"space-y-2",children:n.criteria_results.map(s=>i.jsx("div",{className:"flex items-start justify-between p-3 bg-[var(--bg-primary)] border border-[var(--border)]",children:i.jsxs("div",{className:"flex-1",children:[i.jsxs("div",{className:"flex items-center gap-2",children:[i.jsx("span",{className:"font-medium",children:s.name}),i.jsxs(J,{variant:s.passed?"success":"error",children:[(s.score*100).toFixed(0),"%"]})]}),s.reasoning&&i.jsx("p",{className:"text-sm text-[var(--text-secondary)] mt-1",children:s.reasoning})]})},s.name))})]}),i.jsxs(se,{className:"mb-6",children:[i.jsx("h3",{className:"font-medium mb-3",children:"Agent Output"}),i.jsx("pre",{className:"text-sm bg-[var(--bg-primary)] p-3 overflow-x-auto whitespace-pre-wrap border border-[var(--border)]",children:n.output||"(no output)"})]}),n.files_created.length>0&&i.jsxs(se,{className:"mb-6",children:[i.jsx("h3",{className:"font-medium mb-3",children:"Files Created"}),i.jsx("div",{className:"space-y-1",children:n.files_created.map(s=>i.jsx("div",{className:"text-sm font-mono text-[var(--text-secondary)]",children:s},s))})]}),Object.keys(n.trace).length>0&&i.jsx(Bm,{trace:n.trace})]}):i.jsx("div",{className:"text-[var(--text-secondary)]",children:"Run not found"})}function Ta({label:e,value:t,status:n}){const r={success:"text-green-400",error:"text-red-400"};return i.jsxs(se,{children:[i.jsx("div",{className:"text-sm text-[var(--text-secondary)]",children:e}),i.jsx("div",{className:`text-xl font-bold ${n?r[n]:""}`,children:t})]})}function n1(){const{testId:e}=Di(),t=Lt(),{data:n,isLoading:r}=ve({queryKey:["tests",e],queryFn:()=>Es.get(e),enabled:!!e}),{data:s}=ve({queryKey:["configs",n==null?void 0:n.agent_id],queryFn:()=>Er.get(n.agent_id),enabled:!!(n!=null&&n.agent_id)});if(r)return i.jsx("div",{className:"text-[var(--text-secondary)]",children:"Loading..."});if(!n)return i.jsx("div",{className:"text-[var(--text-secondary)]",children:"Test not found"});const a={completed:"success",failed:"error",running:"info",pending:"default",cancelled:"warning"};return i.jsxs("div",{children:[i.jsxs("div",{className:"mb-6",children:[i.jsx("div",{className:"flex items-center gap-3 mb-2",children:i.jsx("button",{onClick:()=>t("/agents"),className:"text-[var(--text-secondary)] hover:text-[var(--text-primary)]",children:"← Back to Agents"})}),i.jsxs("div",{className:"flex items-center gap-3",children:[i.jsx("h2",{className:"text-xl font-bold",children:"Test Run"}),s&&i.jsxs(i.Fragment,{children:[i.jsx("span",{className:"text-[var(--text-secondary)]",children:"•"}),i.jsx("span",{className:"text-lg",children:s.name})]}),i.jsx(J,{variant:a[n.status]||"default",children:n.status})]}),i.jsxs("p",{className:"text-sm text-[var(--text-secondary)] mt-1 font-mono",children:["ID: ",n.id.slice(0,8),"..."]})]}),i.jsxs("div",{className:"grid grid-cols-4 gap-4 mb-6",children:[i.jsx(Oa,{label:"Duration",value:`${n.duration_seconds.toFixed(2)}s`}),i.jsx(Oa,{label:"Total Tokens",value:n.tokens_total.toLocaleString()}),n.score!==null&&i.jsx(Oa,{label:"Score",value:`${(n.score*100).toFixed(1)}%`,status:n.passed?"success":"error"}),i.jsx(Oa,{label:"Status",value:n.status.charAt(0).toUpperCase()+n.status.slice(1),status:n.status==="completed"?"success":n.status==="failed"?"error":void 0})]}),i.jsx(Km,{tokensInput:n.tokens_input,tokensOutput:n.tokens_output,tokensTotal:n.tokens_total}),i.jsxs(se,{className:"mb-6",children:[i.jsx("h3",{className:"font-medium mb-3",children:"Prompt"}),i.jsx("pre",{className:"text-sm bg-[var(--bg-primary)] p-3 overflow-x-auto whitespace-pre-wrap border border-[var(--border)] font-mono",children:n.prompt})]}),n.error&&i.jsxs(se,{className:"mb-6 border-red-500/30 bg-red-500/5",children:[i.jsx("h3",{className:"font-medium mb-3 text-red-400",children:"Error"}),i.jsx("pre",{className:"text-sm text-red-300 overflow-x-auto whitespace-pre-wrap",children:n.error})]}),n.reasoning&&i.jsxs(se,{className:"mb-6",children:[i.jsx("h3",{className:"font-medium mb-3",children:"Evaluation"}),i.jsx("p",{className:"text-sm text-[var(--text-secondary)]",children:n.reasoning})]}),i.jsxs(se,{className:"mb-6",children:[i.jsx("h3",{className:"font-medium mb-3",children:"Agent Output"}),i.jsx("pre",{className:"text-sm bg-[var(--bg-primary)] p-3 overflow-x-auto whitespace-pre-wrap border border-[var(--border)]",children:n.output||"(no output)"})]}),n.files_created&&n.files_created.length>0&&i.jsxs(se,{className:"mb-6",children:[i.jsx("h3",{className:"font-medium mb-3",children:"Files Created"}),i.jsx("div",{className:"space-y-1",children:n.files_created.map(l=>i.jsx("div",{className:"text-sm font-mono text-[var(--text-secondary)]",children:l},l))})]}),n.trace&&Object.keys(n.trace).length>0&&i.jsx(Bm,{trace:n.trace}),i.jsxs(se,{className:"mb-6",children:[i.jsx("h3",{className:"font-medium mb-3",children:"Timestamps"}),i.jsxs("div",{className:"grid grid-cols-3 gap-4 text-sm",children:[i.jsxs("div",{children:[i.jsx("span",{className:"text-[var(--text-secondary)]",children:"Created:"}),i.jsx("div",{className:"font-mono",children:new Date(n.created_at).toLocaleString()})]}),n.started_at&&i.jsxs("div",{children:[i.jsx("span",{className:"text-[var(--text-secondary)]",children:"Started:"}),i.jsx("div",{className:"font-mono",children:new Date(n.started_at).toLocaleString()})]}),n.completed_at&&i.jsxs("div",{children:[i.jsx("span",{className:"text-[var(--text-secondary)]",children:"Completed:"}),i.jsx("div",{className:"font-mono",children:new Date(n.completed_at).toLocaleString()})]})]})]})]})}function Oa({label:e,value:t,status:n}){const r={success:"text-green-400",error:"text-red-400"};return i.jsxs(se,{children:[i.jsx("div",{className:"text-sm text-[var(--text-secondary)]",children:e}),i.jsx("div",{className:`text-xl font-bold ${n?r[n]:""}`,children:t})]})}function r1(){const{authConfig:e,isLoading:t,error:n,login:r,loginWithGitHub:s,clearError:a}=Ku(),[l,o]=k.useState(""),[u,c]=k.useState("");k.useEffect(()=>{n&&a()},[l,u]);const h=async m=>{m.preventDefault(),!(!l||!u)&&await r(l,u)},d=()=>{s()};return i.jsx("div",{className:"min-h-screen bg-[var(--bg-primary)] flex items-center justify-center p-4",children:i.jsxs("div",{className:"w-full max-w-md",children:[i.jsxs("div",{className:"text-center mb-8",children:[i.jsx("h1",{className:"text-2xl font-bold text-[var(--text-primary)] mb-2",children:"Flow"}),i.jsx("p",{className:"text-[var(--text-secondary)]",children:"Sign in to access the optimization dashboard"})]}),i.jsxs("div",{className:"bg-[var(--bg-secondary)] border border-[var(--border)] p-6 space-y-6",children:[n&&i.jsxs("div",{className:"flex items-start gap-3 p-3 bg-[var(--error)]/10 border border-[var(--error)]/20 text-[var(--error)]",children:[i.jsx(_m,{size:18,className:"mt-0.5 flex-shrink-0"}),i.jsx("p",{className:"text-sm",children:n})]}),(e==null?void 0:e.mode)==="basic"&&i.jsxs("form",{onSubmit:h,className:"space-y-4",children:[i.jsxs("div",{className:"space-y-1",children:[i.jsx("label",{className:"block text-sm text-[var(--text-secondary)]",children:"Username"}),i.jsxs("div",{className:"relative",children:[i.jsx(Lm,{size:16,className:"absolute left-3 top-1/2 -translate-y-1/2 text-[var(--text-tertiary)]"}),i.jsx("input",{type:"text",value:l,onChange:m=>o(m.target.value),className:"w-full bg-[var(--bg-primary)] border border-[var(--border)] pl-10 pr-3 py-2 text-sm focus:outline-none focus:border-[var(--accent)]",placeholder:"Enter username",autoComplete:"username",autoFocus:!0})]})]}),i.jsxs("div",{className:"space-y-1",children:[i.jsx("label",{className:"block text-sm text-[var(--text-secondary)]",children:"Password"}),i.jsxs("div",{className:"relative",children:[i.jsx(Pm,{size:16,className:"absolute left-3 top-1/2 -translate-y-1/2 text-[var(--text-tertiary)]"}),i.jsx("input",{type:"password",value:u,onChange:m=>c(m.target.value),className:"w-full bg-[var(--bg-primary)] border border-[var(--border)] pl-10 pr-3 py-2 text-sm focus:outline-none focus:border-[var(--accent)]",placeholder:"Enter password",autoComplete:"current-password"})]})]}),i.jsx(V,{type:"submit",variant:"primary",className:"w-full justify-center",loading:t,disabled:!l||!u,children:"Sign In"})]}),(e==null?void 0:e.mode)==="github"&&i.jsxs("div",{className:"space-y-4",children:[i.jsx("p",{className:"text-sm text-[var(--text-secondary)] text-center",children:"Sign in with your GitHub account to continue"}),i.jsx(V,{onClick:d,variant:"secondary",className:"w-full justify-center",icon:Sg,children:"Continue with GitHub"})]})]})]})})}function s1({children:e}){const{authConfig:t,isLoadingConfig:n,isAuthenticated:r,loadAuthConfig:s,handleOAuthCallback:a}=Ku();return k.useEffect(()=>{s()},[s]),k.useEffect(()=>{n||a()},[n,a]),n?i.jsx("div",{className:"min-h-screen bg-[var(--bg-primary)] flex items-center justify-center",children:i.jsxs("div",{className:"text-center",children:[i.jsx(ca,{className:"w-8 h-8 animate-spin text-[var(--accent)] mx-auto mb-4"}),i.jsx("p",{className:"text-[var(--text-secondary)]",children:"Loading..."})]})}):t!=null&&t.enabled&&!r?i.jsx(r1,{}):i.jsx(i.Fragment,{children:e})}function a1(){return i.jsx(rg,{children:i.jsx(s1,{children:i.jsx(Jy,{children:i.jsxs(kt,{path:"/",element:i.jsx(x0,{}),children:[i.jsx(kt,{index:!0,element:i.jsx(Pd,{})}),i.jsx(kt,{path:"agents",element:i.jsx(Pd,{})}),i.jsx(kt,{path:"agents/:agentId",element:i.jsx(D0,{})}),i.jsx(kt,{path:"tasks",element:i.jsx(U0,{})}),i.jsx(kt,{path:"jobs",element:i.jsx(H0,{})}),i.jsx(kt,{path:"jobs/:jobId",element:i.jsx(e1,{})}),i.jsx(kt,{path:"runs/:runId",element:i.jsx(t1,{})}),i.jsx(kt,{path:"tests/:testId",element:i.jsx(n1,{})})]})})})})}const Ld=localStorage.getItem("flow-theme");if(Ld)try{const{state:e}=JSON.parse(Ld);e!=null&&e.theme&&document.documentElement.setAttribute("data-theme",e.theme)}catch{}const i1=new Vx({defaultOptions:{queries:{staleTime:5e3,refetchOnWindowFocus:!1}}});kl.createRoot(document.getElementById("root")).render(i.jsx(Qo.StrictMode,{children:i.jsx(Kx,{client:i1,children:i.jsx(a1,{})})})); diff --git a/src/flow/ui/ui/assets/index-k_vg2E38.css b/src/flow/ui/ui/assets/index-k_vg2E38.css new file mode 100644 index 0000000000000000000000000000000000000000..f43c0a9fb3e1e830755094edcfa40cd358c38f28 --- /dev/null +++ b/src/flow/ui/ui/assets/index-k_vg2E38.css @@ -0,0 +1 @@ +*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:JetBrains Mono,ui-monospace,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.pointer-events-none{pointer-events:none}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{top:0;right:0;bottom:0;left:0}.bottom-0{bottom:0}.left-0{left:0}.left-3{left:.75rem}.top-0{top:0}.top-1\/2{top:50%}.z-10{z-index:10}.z-50{z-index:50}.col-span-2{grid-column:span 2 / span 2}.mx-0\.5{margin-left:.125rem;margin-right:.125rem}.mx-4{margin-left:1rem;margin-right:1rem}.mx-auto{margin-left:auto;margin-right:auto}.-mb-px{margin-bottom:-1px}.-mt-2{margin-top:-.5rem}.mb-1{margin-bottom:.25rem}.mb-1\.5{margin-bottom:.375rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.mb-8{margin-bottom:2rem}.ml-1{margin-left:.25rem}.ml-4{margin-left:1rem}.ml-6{margin-left:1.5rem}.mr-1{margin-right:.25rem}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-8{margin-top:2rem}.mt-auto{margin-top:auto}.line-clamp-2{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.h-1\.5{height:.375rem}.h-12{height:3rem}.h-2{height:.5rem}.h-3{height:.75rem}.h-32{height:8rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-8{height:2rem}.h-full{height:100%}.max-h-32{max-height:8rem}.max-h-40{max-height:10rem}.max-h-48{max-height:12rem}.max-h-80{max-height:20rem}.max-h-96{max-height:24rem}.max-h-\[80vh\]{max-height:80vh}.min-h-0{min-height:0px}.min-h-\[100px\]{min-height:100px}.min-h-\[200px\]{min-height:200px}.min-h-screen{min-height:100vh}.w-11{width:2.75rem}.w-12{width:3rem}.w-2{width:.5rem}.w-20{width:5rem}.w-24{width:6rem}.w-3{width:.75rem}.w-32{width:8rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-8{width:2rem}.w-full{width:100%}.min-w-0{min-width:0px}.min-w-\[90px\]{min-width:90px}.max-w-2xl{max-width:42rem}.max-w-4xl{max-width:56rem}.max-w-7xl{max-width:80rem}.max-w-\[200px\]{max-width:200px}.max-w-full{max-width:100%}.max-w-lg{max-width:32rem}.max-w-md{max-width:28rem}.max-w-sm{max-width:24rem}.flex-1{flex:1 1 0%}.flex-shrink-0{flex-shrink:0}.-translate-y-1\/2{--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-1{--tw-translate-x: .25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-6{--tw-translate-x: 1.5rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-180{--tw-rotate: 180deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-90{--tw-rotate: 90deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.resize-none{resize:none}.resize-y{resize:vertical}.resize{resize:both}.list-disc{list-style-type:disc}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-6{gap:1.5rem}.gap-8{gap:2rem}.gap-x-4{-moz-column-gap:1rem;column-gap:1rem}.gap-y-1{row-gap:.25rem}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.space-y-5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.25rem * var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem * var(--tw-space-y-reverse))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.break-all{word-break:break-all}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.border{border-width:1px}.border-b{border-bottom-width:1px}.border-b-2{border-bottom-width:2px}.border-l-2{border-left-width:2px}.border-t{border-top-width:1px}.border-dashed{border-style:dashed}.border-\[var\(--accent\)\]{border-color:var(--accent)}.border-\[var\(--border\)\]{border-color:var(--border)}.border-blue-500\/30{border-color:#3b82f64d}.border-green-500\/20{border-color:#22c55e33}.border-green-500\/30{border-color:#22c55e4d}.border-green-500\/50{border-color:#22c55e80}.border-red-500\/20{border-color:#ef444433}.border-red-500\/30{border-color:#ef44444d}.border-red-500\/50{border-color:#ef444480}.border-transparent{border-color:transparent}.bg-\[var\(--accent\)\]{background-color:var(--accent)}.bg-\[var\(--bg-primary\)\]{background-color:var(--bg-primary)}.bg-\[var\(--bg-secondary\)\]{background-color:var(--bg-secondary)}.bg-\[var\(--bg-tertiary\)\]{background-color:var(--bg-tertiary)}.bg-\[var\(--border\)\]{background-color:var(--border)}.bg-\[var\(--error\)\]{background-color:var(--error)}.bg-black\/50{background-color:#00000080}.bg-black\/80{background-color:#000c}.bg-blue-100{--tw-bg-opacity: 1;background-color:rgb(219 234 254 / var(--tw-bg-opacity, 1))}.bg-blue-400{--tw-bg-opacity: 1;background-color:rgb(96 165 250 / var(--tw-bg-opacity, 1))}.bg-blue-500{--tw-bg-opacity: 1;background-color:rgb(59 130 246 / var(--tw-bg-opacity, 1))}.bg-blue-500\/10{background-color:#3b82f61a}.bg-blue-600{--tw-bg-opacity: 1;background-color:rgb(37 99 235 / var(--tw-bg-opacity, 1))}.bg-emerald-500{--tw-bg-opacity: 1;background-color:rgb(16 185 129 / var(--tw-bg-opacity, 1))}.bg-green-100{--tw-bg-opacity: 1;background-color:rgb(220 252 231 / var(--tw-bg-opacity, 1))}.bg-green-400{--tw-bg-opacity: 1;background-color:rgb(74 222 128 / var(--tw-bg-opacity, 1))}.bg-green-500{--tw-bg-opacity: 1;background-color:rgb(34 197 94 / var(--tw-bg-opacity, 1))}.bg-green-500\/10{background-color:#22c55e1a}.bg-green-500\/20{background-color:#22c55e33}.bg-green-600{--tw-bg-opacity: 1;background-color:rgb(22 163 74 / var(--tw-bg-opacity, 1))}.bg-orange-100{--tw-bg-opacity: 1;background-color:rgb(255 237 213 / var(--tw-bg-opacity, 1))}.bg-purple-100{--tw-bg-opacity: 1;background-color:rgb(243 232 255 / var(--tw-bg-opacity, 1))}.bg-red-100{--tw-bg-opacity: 1;background-color:rgb(254 226 226 / var(--tw-bg-opacity, 1))}.bg-red-500{--tw-bg-opacity: 1;background-color:rgb(239 68 68 / var(--tw-bg-opacity, 1))}.bg-red-500\/10{background-color:#ef44441a}.bg-red-500\/5{background-color:#ef44440d}.bg-red-600{--tw-bg-opacity: 1;background-color:rgb(220 38 38 / var(--tw-bg-opacity, 1))}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.bg-yellow-500{--tw-bg-opacity: 1;background-color:rgb(234 179 8 / var(--tw-bg-opacity, 1))}.p-1{padding:.25rem}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-6{padding:1.5rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-12{padding-top:3rem;padding-bottom:3rem}.py-16{padding-top:4rem;padding-bottom:4rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-8{padding-top:2rem;padding-bottom:2rem}.pb-2{padding-bottom:.5rem}.pb-3{padding-bottom:.75rem}.pl-10{padding-left:2.5rem}.pr-3{padding-right:.75rem}.pr-4{padding-right:1rem}.pt-1{padding-top:.25rem}.pt-2{padding-top:.5rem}.pt-3{padding-top:.75rem}.pt-4{padding-top:1rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.font-mono{font-family:JetBrains Mono,ui-monospace,monospace}.text-2xl{font-size:1.5rem;line-height:2rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.capitalize{text-transform:capitalize}.italic{font-style:italic}.tracking-wide{letter-spacing:.025em}.tracking-wider{letter-spacing:.05em}.text-\[var\(--accent\)\]{color:var(--accent)}.text-\[var\(--error\)\]{color:var(--error)}.text-\[var\(--text-primary\)\]{color:var(--text-primary)}.text-\[var\(--text-secondary\)\]{color:var(--text-secondary)}.text-\[var\(--text-tertiary\)\]{color:var(--text-tertiary)}.text-black{--tw-text-opacity: 1;color:rgb(0 0 0 / var(--tw-text-opacity, 1))}.text-blue-400{--tw-text-opacity: 1;color:rgb(96 165 250 / var(--tw-text-opacity, 1))}.text-blue-800{--tw-text-opacity: 1;color:rgb(30 64 175 / var(--tw-text-opacity, 1))}.text-emerald-400{--tw-text-opacity: 1;color:rgb(52 211 153 / var(--tw-text-opacity, 1))}.text-green-400{--tw-text-opacity: 1;color:rgb(74 222 128 / var(--tw-text-opacity, 1))}.text-green-500{--tw-text-opacity: 1;color:rgb(34 197 94 / var(--tw-text-opacity, 1))}.text-green-800{--tw-text-opacity: 1;color:rgb(22 101 52 / var(--tw-text-opacity, 1))}.text-orange-800{--tw-text-opacity: 1;color:rgb(154 52 18 / var(--tw-text-opacity, 1))}.text-purple-400{--tw-text-opacity: 1;color:rgb(192 132 252 / var(--tw-text-opacity, 1))}.text-purple-800{--tw-text-opacity: 1;color:rgb(107 33 168 / var(--tw-text-opacity, 1))}.text-red-300{--tw-text-opacity: 1;color:rgb(252 165 165 / var(--tw-text-opacity, 1))}.text-red-400{--tw-text-opacity: 1;color:rgb(248 113 113 / var(--tw-text-opacity, 1))}.text-red-500{--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity, 1))}.text-red-800{--tw-text-opacity: 1;color:rgb(153 27 27 / var(--tw-text-opacity, 1))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.text-yellow-500{--tw-text-opacity: 1;color:rgb(234 179 8 / var(--tw-text-opacity, 1))}.accent-\[var\(--accent\)\]{accent-color:var(--accent)}.opacity-50{opacity:.5}.shadow-lg{--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-xl{--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-300{transition-duration:.3s}:root{--bg-primary: #0a0a0a;--bg-secondary: #141414;--bg-tertiary: #1a1a1a;--text-primary: #f5f5f5;--text-secondary: #a3a3a3;--accent: #22c55e;--accent-dim: #166534;--border: #262626;--error: #ef4444}[data-theme=light]{--bg-primary: #ffffff;--bg-secondary: #f7f8f9;--bg-tertiary: #eef0f2;--text-primary: #1a1a1a;--text-secondary: #4a4a4a;--accent: #16a34a;--accent-dim: #dcfce7;--border: #d1d5db;--error: #dc2626}*{box-sizing:border-box}body{margin:0;background-color:var(--bg-primary);color:var(--text-primary);font-family:JetBrains Mono,ui-monospace,monospace;font-size:14px;line-height:1.6}::-webkit-scrollbar{width:8px;height:8px}::-webkit-scrollbar-track{background:var(--bg-secondary)}::-webkit-scrollbar-thumb{background:var(--border);border-radius:4px}::-webkit-scrollbar-thumb:hover{background:#404040}[data-theme=light] ::-webkit-scrollbar-thumb:hover{background:silver}.last\:border-0:last-child{border-width:0px}.hover\:border-\[var\(--accent\)\]:hover{border-color:var(--accent)}.hover\:border-\[var\(--accent-dim\)\]:hover{border-color:var(--accent-dim)}.hover\:bg-\[\#16a34a\]:hover{--tw-bg-opacity: 1;background-color:rgb(22 163 74 / var(--tw-bg-opacity, 1))}.hover\:bg-\[var\(--bg-primary\)\]:hover{background-color:var(--bg-primary)}.hover\:bg-\[var\(--bg-tertiary\)\]:hover{background-color:var(--bg-tertiary)}.hover\:bg-\[var\(--border\)\]:hover{background-color:var(--border)}.hover\:bg-red-600:hover{--tw-bg-opacity: 1;background-color:rgb(220 38 38 / var(--tw-bg-opacity, 1))}.hover\:text-\[var\(--accent\)\]:hover{color:var(--accent)}.hover\:text-\[var\(--error\)\]:hover{color:var(--error)}.hover\:text-\[var\(--text-primary\)\]:hover{color:var(--text-primary)}.hover\:text-red-600:hover{--tw-text-opacity: 1;color:rgb(220 38 38 / var(--tw-text-opacity, 1))}.hover\:opacity-80:hover{opacity:.8}.focus\:border-\[var\(--accent\)\]:focus{border-color:var(--accent)}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-2:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-\[var\(--accent\)\]:focus{--tw-ring-color: var(--accent)}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}@media (min-width: 768px){.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (min-width: 1024px){.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}@media (min-width: 1280px){.xl\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}@media (prefers-color-scheme: dark){.dark\:bg-blue-900{--tw-bg-opacity: 1;background-color:rgb(30 58 138 / var(--tw-bg-opacity, 1))}.dark\:bg-green-900{--tw-bg-opacity: 1;background-color:rgb(20 83 45 / var(--tw-bg-opacity, 1))}.dark\:bg-orange-900{--tw-bg-opacity: 1;background-color:rgb(124 45 18 / var(--tw-bg-opacity, 1))}.dark\:bg-purple-900{--tw-bg-opacity: 1;background-color:rgb(88 28 135 / var(--tw-bg-opacity, 1))}.dark\:bg-red-900{--tw-bg-opacity: 1;background-color:rgb(127 29 29 / var(--tw-bg-opacity, 1))}.dark\:text-blue-200{--tw-text-opacity: 1;color:rgb(191 219 254 / var(--tw-text-opacity, 1))}.dark\:text-green-200{--tw-text-opacity: 1;color:rgb(187 247 208 / var(--tw-text-opacity, 1))}.dark\:text-orange-200{--tw-text-opacity: 1;color:rgb(254 215 170 / var(--tw-text-opacity, 1))}.dark\:text-purple-200{--tw-text-opacity: 1;color:rgb(233 213 255 / var(--tw-text-opacity, 1))}.dark\:text-red-200{--tw-text-opacity: 1;color:rgb(254 202 202 / var(--tw-text-opacity, 1))}} diff --git a/src/flow/ui/ui/index.html b/src/flow/ui/ui/index.html index 3efabfe594ea33c57cd221cd088d6726f71d529e..34b14d54d44ea5241acea6a1881244553fff6c10 100644 --- a/src/flow/ui/ui/index.html +++ b/src/flow/ui/ui/index.html @@ -8,8 +8,8 @@ - - + +
diff --git a/uv.lock b/uv.lock index 0a8611fbe1731d5aeb8a160f0ccf7370222c1f84..3eac0d2953ebfb4e80f650d8f16173295f943415 100644 --- a/uv.lock +++ b/uv.lock @@ -1,6 +1,18 @@ version = 1 revision = 3 requires-python = ">=3.10" +resolution-markers = [ + "python_full_version >= '3.14' and sys_platform == 'win32'", + "python_full_version >= '3.14' and sys_platform == 'emscripten'", + "python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", + "python_full_version == '3.13.*' and sys_platform == 'win32'", + "python_full_version == '3.13.*' and sys_platform == 'emscripten'", + "python_full_version == '3.13.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", + "python_full_version >= '3.11' and python_full_version < '3.13' and sys_platform == 'win32'", + "python_full_version >= '3.11' and python_full_version < '3.13' and sys_platform == 'emscripten'", + "python_full_version >= '3.11' and python_full_version < '3.13' and sys_platform != 'emscripten' and sys_platform != 'win32'", + "python_full_version < '3.11'", +] [[package]] name = "agent-framework-core" @@ -23,6 +35,148 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/36/68/afe66c72951a279e0fe048fd5af1e775528cde40dbdab8ec03b42c545df4/agent_framework_core-1.0.0b260130-py3-none-any.whl", hash = "sha256:75b4dd0ca2ae52574d406cf5c9ed7adf63e187379f72fce891743254d83dfd56", size = 348724, upload-time = "2026-01-30T18:56:47.15Z" }, ] +[[package]] +name = "aiohappyeyeballs" +version = "2.6.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/26/30/f84a107a9c4331c14b2b586036f40965c128aa4fee4dda5d3d51cb14ad54/aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", size = 22760, upload-time = "2025-03-12T01:42:48.764Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8", size = 15265, upload-time = "2025-03-12T01:42:47.083Z" }, +] + +[[package]] +name = "aiohttp" +version = "3.13.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohappyeyeballs" }, + { name = "aiosignal" }, + { name = "async-timeout", marker = "python_full_version < '3.11'" }, + { name = "attrs" }, + { name = "frozenlist" }, + { name = "multidict" }, + { name = "propcache" }, + { name = "yarl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/50/42/32cf8e7704ceb4481406eb87161349abb46a57fee3f008ba9cb610968646/aiohttp-3.13.3.tar.gz", hash = "sha256:a949eee43d3782f2daae4f4a2819b2cb9b0c5d3b7f7a927067cc84dafdbb9f88", size = 7844556, upload-time = "2026-01-03T17:33:05.204Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/36/d6/5aec9313ee6ea9c7cde8b891b69f4ff4001416867104580670a31daeba5b/aiohttp-3.13.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d5a372fd5afd301b3a89582817fdcdb6c34124787c70dbcc616f259013e7eef7", size = 738950, upload-time = "2026-01-03T17:29:13.002Z" }, + { url = "https://files.pythonhosted.org/packages/68/03/8fa90a7e6d11ff20a18837a8e2b5dd23db01aabc475aa9271c8ad33299f5/aiohttp-3.13.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:147e422fd1223005c22b4fe080f5d93ced44460f5f9c105406b753612b587821", size = 496099, upload-time = "2026-01-03T17:29:15.268Z" }, + { url = "https://files.pythonhosted.org/packages/d2/23/b81f744d402510a8366b74eb420fc0cc1170d0c43daca12d10814df85f10/aiohttp-3.13.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:859bd3f2156e81dd01432f5849fc73e2243d4a487c4fd26609b1299534ee1845", size = 491072, upload-time = "2026-01-03T17:29:16.922Z" }, + { url = "https://files.pythonhosted.org/packages/d5/e1/56d1d1c0dd334cd203dd97706ce004c1aa24b34a813b0b8daf3383039706/aiohttp-3.13.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dca68018bf48c251ba17c72ed479f4dafe9dbd5a73707ad8d28a38d11f3d42af", size = 1671588, upload-time = "2026-01-03T17:29:18.539Z" }, + { url = "https://files.pythonhosted.org/packages/5f/34/8d7f962604f4bc2b4e39eb1220dac7d4e4cba91fb9ba0474b4ecd67db165/aiohttp-3.13.3-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:fee0c6bc7db1de362252affec009707a17478a00ec69f797d23ca256e36d5940", size = 1640334, upload-time = "2026-01-03T17:29:21.028Z" }, + { url = "https://files.pythonhosted.org/packages/94/1d/fcccf2c668d87337ddeef9881537baee13c58d8f01f12ba8a24215f2b804/aiohttp-3.13.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c048058117fd649334d81b4b526e94bde3ccaddb20463a815ced6ecbb7d11160", size = 1722656, upload-time = "2026-01-03T17:29:22.531Z" }, + { url = "https://files.pythonhosted.org/packages/aa/98/c6f3b081c4c606bc1e5f2ec102e87d6411c73a9ef3616fea6f2d5c98c062/aiohttp-3.13.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:215a685b6fbbfcf71dfe96e3eba7a6f58f10da1dfdf4889c7dd856abe430dca7", size = 1817625, upload-time = "2026-01-03T17:29:24.276Z" }, + { url = "https://files.pythonhosted.org/packages/2c/c0/cfcc3d2e11b477f86e1af2863f3858c8850d751ce8dc39c4058a072c9e54/aiohttp-3.13.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2c184bb1fe2cbd2cefba613e9db29a5ab559323f994b6737e370d3da0ac455", size = 1672604, upload-time = "2026-01-03T17:29:26.099Z" }, + { url = "https://files.pythonhosted.org/packages/1e/77/6b4ffcbcac4c6a5d041343a756f34a6dd26174ae07f977a64fe028dda5b0/aiohttp-3.13.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:75ca857eba4e20ce9f546cd59c7007b33906a4cd48f2ff6ccf1ccfc3b646f279", size = 1554370, upload-time = "2026-01-03T17:29:28.121Z" }, + { url = "https://files.pythonhosted.org/packages/f2/f0/e3ddfa93f17d689dbe014ba048f18e0c9f9b456033b70e94349a2e9048be/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:81e97251d9298386c2b7dbeb490d3d1badbdc69107fb8c9299dd04eb39bddc0e", size = 1642023, upload-time = "2026-01-03T17:29:30.002Z" }, + { url = "https://files.pythonhosted.org/packages/eb/45/c14019c9ec60a8e243d06d601b33dcc4fd92379424bde3021725859d7f99/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c0e2d366af265797506f0283487223146af57815b388623f0357ef7eac9b209d", size = 1649680, upload-time = "2026-01-03T17:29:31.782Z" }, + { url = "https://files.pythonhosted.org/packages/9c/fd/09c9451dae5aa5c5ed756df95ff9ef549d45d4be663bafd1e4954fd836f0/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4e239d501f73d6db1522599e14b9b321a7e3b1de66ce33d53a765d975e9f4808", size = 1692407, upload-time = "2026-01-03T17:29:33.392Z" }, + { url = "https://files.pythonhosted.org/packages/a6/81/938bc2ec33c10efd6637ccb3d22f9f3160d08e8f3aa2587a2c2d5ab578eb/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:0db318f7a6f065d84cb1e02662c526294450b314a02bd9e2a8e67f0d8564ce40", size = 1543047, upload-time = "2026-01-03T17:29:34.855Z" }, + { url = "https://files.pythonhosted.org/packages/f7/23/80488ee21c8d567c83045e412e1d9b7077d27171591a4eb7822586e8c06a/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:bfc1cc2fe31a6026a8a88e4ecfb98d7f6b1fec150cfd708adbfd1d2f42257c29", size = 1715264, upload-time = "2026-01-03T17:29:36.389Z" }, + { url = "https://files.pythonhosted.org/packages/e2/83/259a8da6683182768200b368120ab3deff5370bed93880fb9a3a86299f34/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af71fff7bac6bb7508956696dce8f6eec2bbb045eceb40343944b1ae62b5ef11", size = 1657275, upload-time = "2026-01-03T17:29:38.162Z" }, + { url = "https://files.pythonhosted.org/packages/3f/4f/2c41f800a0b560785c10fb316216ac058c105f9be50bdc6a285de88db625/aiohttp-3.13.3-cp310-cp310-win32.whl", hash = "sha256:37da61e244d1749798c151421602884db5270faf479cf0ef03af0ff68954c9dd", size = 434053, upload-time = "2026-01-03T17:29:40.074Z" }, + { url = "https://files.pythonhosted.org/packages/80/df/29cd63c7ecfdb65ccc12f7d808cac4fa2a19544660c06c61a4a48462de0c/aiohttp-3.13.3-cp310-cp310-win_amd64.whl", hash = "sha256:7e63f210bc1b57ef699035f2b4b6d9ce096b5914414a49b0997c839b2bd2223c", size = 456687, upload-time = "2026-01-03T17:29:41.819Z" }, + { url = "https://files.pythonhosted.org/packages/f1/4c/a164164834f03924d9a29dc3acd9e7ee58f95857e0b467f6d04298594ebb/aiohttp-3.13.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5b6073099fb654e0a068ae678b10feff95c5cae95bbfcbfa7af669d361a8aa6b", size = 746051, upload-time = "2026-01-03T17:29:43.287Z" }, + { url = "https://files.pythonhosted.org/packages/82/71/d5c31390d18d4f58115037c432b7e0348c60f6f53b727cad33172144a112/aiohttp-3.13.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cb93e166e6c28716c8c6aeb5f99dfb6d5ccf482d29fe9bf9a794110e6d0ab64", size = 499234, upload-time = "2026-01-03T17:29:44.822Z" }, + { url = "https://files.pythonhosted.org/packages/0e/c9/741f8ac91e14b1d2e7100690425a5b2b919a87a5075406582991fb7de920/aiohttp-3.13.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:28e027cf2f6b641693a09f631759b4d9ce9165099d2b5d92af9bd4e197690eea", size = 494979, upload-time = "2026-01-03T17:29:46.405Z" }, + { url = "https://files.pythonhosted.org/packages/75/b5/31d4d2e802dfd59f74ed47eba48869c1c21552c586d5e81a9d0d5c2ad640/aiohttp-3.13.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3b61b7169ababd7802f9568ed96142616a9118dd2be0d1866e920e77ec8fa92a", size = 1748297, upload-time = "2026-01-03T17:29:48.083Z" }, + { url = "https://files.pythonhosted.org/packages/1a/3e/eefad0ad42959f226bb79664826883f2687d602a9ae2941a18e0484a74d3/aiohttp-3.13.3-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:80dd4c21b0f6237676449c6baaa1039abae86b91636b6c91a7f8e61c87f89540", size = 1707172, upload-time = "2026-01-03T17:29:49.648Z" }, + { url = "https://files.pythonhosted.org/packages/c5/3a/54a64299fac2891c346cdcf2aa6803f994a2e4beeaf2e5a09dcc54acc842/aiohttp-3.13.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:65d2ccb7eabee90ce0503c17716fc77226be026dcc3e65cce859a30db715025b", size = 1805405, upload-time = "2026-01-03T17:29:51.244Z" }, + { url = "https://files.pythonhosted.org/packages/6c/70/ddc1b7169cf64075e864f64595a14b147a895a868394a48f6a8031979038/aiohttp-3.13.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5b179331a481cb5529fca8b432d8d3c7001cb217513c94cd72d668d1248688a3", size = 1899449, upload-time = "2026-01-03T17:29:53.938Z" }, + { url = "https://files.pythonhosted.org/packages/a1/7e/6815aab7d3a56610891c76ef79095677b8b5be6646aaf00f69b221765021/aiohttp-3.13.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d4c940f02f49483b18b079d1c27ab948721852b281f8b015c058100e9421dd1", size = 1748444, upload-time = "2026-01-03T17:29:55.484Z" }, + { url = "https://files.pythonhosted.org/packages/6b/f2/073b145c4100da5511f457dc0f7558e99b2987cf72600d42b559db856fbc/aiohttp-3.13.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f9444f105664c4ce47a2a7171a2418bce5b7bae45fb610f4e2c36045d85911d3", size = 1606038, upload-time = "2026-01-03T17:29:57.179Z" }, + { url = "https://files.pythonhosted.org/packages/0a/c1/778d011920cae03ae01424ec202c513dc69243cf2db303965615b81deeea/aiohttp-3.13.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:694976222c711d1d00ba131904beb60534f93966562f64440d0c9d41b8cdb440", size = 1724156, upload-time = "2026-01-03T17:29:58.914Z" }, + { url = "https://files.pythonhosted.org/packages/0e/cb/3419eabf4ec1e9ec6f242c32b689248365a1cf621891f6f0386632525494/aiohttp-3.13.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:f33ed1a2bf1997a36661874b017f5c4b760f41266341af36febaf271d179f6d7", size = 1722340, upload-time = "2026-01-03T17:30:01.962Z" }, + { url = "https://files.pythonhosted.org/packages/7a/e5/76cf77bdbc435bf233c1f114edad39ed4177ccbfab7c329482b179cff4f4/aiohttp-3.13.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e636b3c5f61da31a92bf0d91da83e58fdfa96f178ba682f11d24f31944cdd28c", size = 1783041, upload-time = "2026-01-03T17:30:03.609Z" }, + { url = "https://files.pythonhosted.org/packages/9d/d4/dd1ca234c794fd29c057ce8c0566b8ef7fd6a51069de5f06fa84b9a1971c/aiohttp-3.13.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:5d2d94f1f5fcbe40838ac51a6ab5704a6f9ea42e72ceda48de5e6b898521da51", size = 1596024, upload-time = "2026-01-03T17:30:05.132Z" }, + { url = "https://files.pythonhosted.org/packages/55/58/4345b5f26661a6180afa686c473620c30a66afdf120ed3dd545bbc809e85/aiohttp-3.13.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2be0e9ccf23e8a94f6f0650ce06042cefc6ac703d0d7ab6c7a917289f2539ad4", size = 1804590, upload-time = "2026-01-03T17:30:07.135Z" }, + { url = "https://files.pythonhosted.org/packages/7b/06/05950619af6c2df7e0a431d889ba2813c9f0129cec76f663e547a5ad56f2/aiohttp-3.13.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9af5e68ee47d6534d36791bbe9b646d2a7c7deb6fc24d7943628edfbb3581f29", size = 1740355, upload-time = "2026-01-03T17:30:09.083Z" }, + { url = "https://files.pythonhosted.org/packages/3e/80/958f16de79ba0422d7c1e284b2abd0c84bc03394fbe631d0a39ffa10e1eb/aiohttp-3.13.3-cp311-cp311-win32.whl", hash = "sha256:a2212ad43c0833a873d0fb3c63fa1bacedd4cf6af2fee62bf4b739ceec3ab239", size = 433701, upload-time = "2026-01-03T17:30:10.869Z" }, + { url = "https://files.pythonhosted.org/packages/dc/f2/27cdf04c9851712d6c1b99df6821a6623c3c9e55956d4b1e318c337b5a48/aiohttp-3.13.3-cp311-cp311-win_amd64.whl", hash = "sha256:642f752c3eb117b105acbd87e2c143de710987e09860d674e068c4c2c441034f", size = 457678, upload-time = "2026-01-03T17:30:12.719Z" }, + { url = "https://files.pythonhosted.org/packages/a0/be/4fc11f202955a69e0db803a12a062b8379c970c7c84f4882b6da17337cc1/aiohttp-3.13.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:b903a4dfee7d347e2d87697d0713be59e0b87925be030c9178c5faa58ea58d5c", size = 739732, upload-time = "2026-01-03T17:30:14.23Z" }, + { url = "https://files.pythonhosted.org/packages/97/2c/621d5b851f94fa0bb7430d6089b3aa970a9d9b75196bc93bb624b0db237a/aiohttp-3.13.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a45530014d7a1e09f4a55f4f43097ba0fd155089372e105e4bff4ca76cb1b168", size = 494293, upload-time = "2026-01-03T17:30:15.96Z" }, + { url = "https://files.pythonhosted.org/packages/5d/43/4be01406b78e1be8320bb8316dc9c42dbab553d281c40364e0f862d5661c/aiohttp-3.13.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:27234ef6d85c914f9efeb77ff616dbf4ad2380be0cda40b4db086ffc7ddd1b7d", size = 493533, upload-time = "2026-01-03T17:30:17.431Z" }, + { url = "https://files.pythonhosted.org/packages/8d/a8/5a35dc56a06a2c90d4742cbf35294396907027f80eea696637945a106f25/aiohttp-3.13.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d32764c6c9aafb7fb55366a224756387cd50bfa720f32b88e0e6fa45b27dcf29", size = 1737839, upload-time = "2026-01-03T17:30:19.422Z" }, + { url = "https://files.pythonhosted.org/packages/bf/62/4b9eeb331da56530bf2e198a297e5303e1c1ebdceeb00fe9b568a65c5a0c/aiohttp-3.13.3-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b1a6102b4d3ebc07dad44fbf07b45bb600300f15b552ddf1851b5390202ea2e3", size = 1703932, upload-time = "2026-01-03T17:30:21.756Z" }, + { url = "https://files.pythonhosted.org/packages/7c/f6/af16887b5d419e6a367095994c0b1332d154f647e7dc2bd50e61876e8e3d/aiohttp-3.13.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c014c7ea7fb775dd015b2d3137378b7be0249a448a1612268b5a90c2d81de04d", size = 1771906, upload-time = "2026-01-03T17:30:23.932Z" }, + { url = "https://files.pythonhosted.org/packages/ce/83/397c634b1bcc24292fa1e0c7822800f9f6569e32934bdeef09dae7992dfb/aiohttp-3.13.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2b8d8ddba8f95ba17582226f80e2de99c7a7948e66490ef8d947e272a93e9463", size = 1871020, upload-time = "2026-01-03T17:30:26Z" }, + { url = "https://files.pythonhosted.org/packages/86/f6/a62cbbf13f0ac80a70f71b1672feba90fdb21fd7abd8dbf25c0105fb6fa3/aiohttp-3.13.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9ae8dd55c8e6c4257eae3a20fd2c8f41edaea5992ed67156642493b8daf3cecc", size = 1755181, upload-time = "2026-01-03T17:30:27.554Z" }, + { url = "https://files.pythonhosted.org/packages/0a/87/20a35ad487efdd3fba93d5843efdfaa62d2f1479eaafa7453398a44faf13/aiohttp-3.13.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:01ad2529d4b5035578f5081606a465f3b814c542882804e2e8cda61adf5c71bf", size = 1561794, upload-time = "2026-01-03T17:30:29.254Z" }, + { url = "https://files.pythonhosted.org/packages/de/95/8fd69a66682012f6716e1bc09ef8a1a2a91922c5725cb904689f112309c4/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bb4f7475e359992b580559e008c598091c45b5088f28614e855e42d39c2f1033", size = 1697900, upload-time = "2026-01-03T17:30:31.033Z" }, + { url = "https://files.pythonhosted.org/packages/e5/66/7b94b3b5ba70e955ff597672dad1691333080e37f50280178967aff68657/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:c19b90316ad3b24c69cd78d5c9b4f3aa4497643685901185b65166293d36a00f", size = 1728239, upload-time = "2026-01-03T17:30:32.703Z" }, + { url = "https://files.pythonhosted.org/packages/47/71/6f72f77f9f7d74719692ab65a2a0252584bf8d5f301e2ecb4c0da734530a/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:96d604498a7c782cb15a51c406acaea70d8c027ee6b90c569baa6e7b93073679", size = 1740527, upload-time = "2026-01-03T17:30:34.695Z" }, + { url = "https://files.pythonhosted.org/packages/fa/b4/75ec16cbbd5c01bdaf4a05b19e103e78d7ce1ef7c80867eb0ace42ff4488/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:084911a532763e9d3dd95adf78a78f4096cd5f58cdc18e6fdbc1b58417a45423", size = 1554489, upload-time = "2026-01-03T17:30:36.864Z" }, + { url = "https://files.pythonhosted.org/packages/52/8f/bc518c0eea29f8406dcf7ed1f96c9b48e3bc3995a96159b3fc11f9e08321/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:7a4a94eb787e606d0a09404b9c38c113d3b099d508021faa615d70a0131907ce", size = 1767852, upload-time = "2026-01-03T17:30:39.433Z" }, + { url = "https://files.pythonhosted.org/packages/9d/f2/a07a75173124f31f11ea6f863dc44e6f09afe2bca45dd4e64979490deab1/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:87797e645d9d8e222e04160ee32aa06bc5c163e8499f24db719e7852ec23093a", size = 1722379, upload-time = "2026-01-03T17:30:41.081Z" }, + { url = "https://files.pythonhosted.org/packages/3c/4a/1a3fee7c21350cac78e5c5cef711bac1b94feca07399f3d406972e2d8fcd/aiohttp-3.13.3-cp312-cp312-win32.whl", hash = "sha256:b04be762396457bef43f3597c991e192ee7da460a4953d7e647ee4b1c28e7046", size = 428253, upload-time = "2026-01-03T17:30:42.644Z" }, + { url = "https://files.pythonhosted.org/packages/d9/b7/76175c7cb4eb73d91ad63c34e29fc4f77c9386bba4a65b53ba8e05ee3c39/aiohttp-3.13.3-cp312-cp312-win_amd64.whl", hash = "sha256:e3531d63d3bdfa7e3ac5e9b27b2dd7ec9df3206a98e0b3445fa906f233264c57", size = 455407, upload-time = "2026-01-03T17:30:44.195Z" }, + { url = "https://files.pythonhosted.org/packages/97/8a/12ca489246ca1faaf5432844adbfce7ff2cc4997733e0af120869345643a/aiohttp-3.13.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:5dff64413671b0d3e7d5918ea490bdccb97a4ad29b3f311ed423200b2203e01c", size = 734190, upload-time = "2026-01-03T17:30:45.832Z" }, + { url = "https://files.pythonhosted.org/packages/32/08/de43984c74ed1fca5c014808963cc83cb00d7bb06af228f132d33862ca76/aiohttp-3.13.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:87b9aab6d6ed88235aa2970294f496ff1a1f9adcd724d800e9b952395a80ffd9", size = 491783, upload-time = "2026-01-03T17:30:47.466Z" }, + { url = "https://files.pythonhosted.org/packages/17/f8/8dd2cf6112a5a76f81f81a5130c57ca829d101ad583ce57f889179accdda/aiohttp-3.13.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:425c126c0dc43861e22cb1c14ba4c8e45d09516d0a3ae0a3f7494b79f5f233a3", size = 490704, upload-time = "2026-01-03T17:30:49.373Z" }, + { url = "https://files.pythonhosted.org/packages/6d/40/a46b03ca03936f832bc7eaa47cfbb1ad012ba1be4790122ee4f4f8cba074/aiohttp-3.13.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7f9120f7093c2a32d9647abcaf21e6ad275b4fbec5b55969f978b1a97c7c86bf", size = 1720652, upload-time = "2026-01-03T17:30:50.974Z" }, + { url = "https://files.pythonhosted.org/packages/f7/7e/917fe18e3607af92657e4285498f500dca797ff8c918bd7d90b05abf6c2a/aiohttp-3.13.3-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:697753042d57f4bf7122cab985bf15d0cef23c770864580f5af4f52023a56bd6", size = 1692014, upload-time = "2026-01-03T17:30:52.729Z" }, + { url = "https://files.pythonhosted.org/packages/71/b6/cefa4cbc00d315d68973b671cf105b21a609c12b82d52e5d0c9ae61d2a09/aiohttp-3.13.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6de499a1a44e7de70735d0b39f67c8f25eb3d91eb3103be99ca0fa882cdd987d", size = 1759777, upload-time = "2026-01-03T17:30:54.537Z" }, + { url = "https://files.pythonhosted.org/packages/fb/e3/e06ee07b45e59e6d81498b591fc589629be1553abb2a82ce33efe2a7b068/aiohttp-3.13.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:37239e9f9a7ea9ac5bf6b92b0260b01f8a22281996da609206a84df860bc1261", size = 1861276, upload-time = "2026-01-03T17:30:56.512Z" }, + { url = "https://files.pythonhosted.org/packages/7c/24/75d274228acf35ceeb2850b8ce04de9dd7355ff7a0b49d607ee60c29c518/aiohttp-3.13.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f76c1e3fe7d7c8afad7ed193f89a292e1999608170dcc9751a7462a87dfd5bc0", size = 1743131, upload-time = "2026-01-03T17:30:58.256Z" }, + { url = "https://files.pythonhosted.org/packages/04/98/3d21dde21889b17ca2eea54fdcff21b27b93f45b7bb94ca029c31ab59dc3/aiohttp-3.13.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fc290605db2a917f6e81b0e1e0796469871f5af381ce15c604a3c5c7e51cb730", size = 1556863, upload-time = "2026-01-03T17:31:00.445Z" }, + { url = "https://files.pythonhosted.org/packages/9e/84/da0c3ab1192eaf64782b03971ab4055b475d0db07b17eff925e8c93b3aa5/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4021b51936308aeea0367b8f006dc999ca02bc118a0cc78c303f50a2ff6afb91", size = 1682793, upload-time = "2026-01-03T17:31:03.024Z" }, + { url = "https://files.pythonhosted.org/packages/ff/0f/5802ada182f575afa02cbd0ec5180d7e13a402afb7c2c03a9aa5e5d49060/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:49a03727c1bba9a97d3e93c9f93ca03a57300f484b6e935463099841261195d3", size = 1716676, upload-time = "2026-01-03T17:31:04.842Z" }, + { url = "https://files.pythonhosted.org/packages/3f/8c/714d53bd8b5a4560667f7bbbb06b20c2382f9c7847d198370ec6526af39c/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3d9908a48eb7416dc1f4524e69f1d32e5d90e3981e4e37eb0aa1cd18f9cfa2a4", size = 1733217, upload-time = "2026-01-03T17:31:06.868Z" }, + { url = "https://files.pythonhosted.org/packages/7d/79/e2176f46d2e963facea939f5be2d26368ce543622be6f00a12844d3c991f/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:2712039939ec963c237286113c68dbad80a82a4281543f3abf766d9d73228998", size = 1552303, upload-time = "2026-01-03T17:31:08.958Z" }, + { url = "https://files.pythonhosted.org/packages/ab/6a/28ed4dea1759916090587d1fe57087b03e6c784a642b85ef48217b0277ae/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:7bfdc049127717581866fa4708791220970ce291c23e28ccf3922c700740fdc0", size = 1763673, upload-time = "2026-01-03T17:31:10.676Z" }, + { url = "https://files.pythonhosted.org/packages/e8/35/4a3daeb8b9fab49240d21c04d50732313295e4bd813a465d840236dd0ce1/aiohttp-3.13.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8057c98e0c8472d8846b9c79f56766bcc57e3e8ac7bfd510482332366c56c591", size = 1721120, upload-time = "2026-01-03T17:31:12.575Z" }, + { url = "https://files.pythonhosted.org/packages/bc/9f/d643bb3c5fb99547323e635e251c609fbbc660d983144cfebec529e09264/aiohttp-3.13.3-cp313-cp313-win32.whl", hash = "sha256:1449ceddcdbcf2e0446957863af03ebaaa03f94c090f945411b61269e2cb5daf", size = 427383, upload-time = "2026-01-03T17:31:14.382Z" }, + { url = "https://files.pythonhosted.org/packages/4e/f1/ab0395f8a79933577cdd996dd2f9aa6014af9535f65dddcf88204682fe62/aiohttp-3.13.3-cp313-cp313-win_amd64.whl", hash = "sha256:693781c45a4033d31d4187d2436f5ac701e7bbfe5df40d917736108c1cc7436e", size = 453899, upload-time = "2026-01-03T17:31:15.958Z" }, + { url = "https://files.pythonhosted.org/packages/99/36/5b6514a9f5d66f4e2597e40dea2e3db271e023eb7a5d22defe96ba560996/aiohttp-3.13.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:ea37047c6b367fd4bd632bff8077449b8fa034b69e812a18e0132a00fae6e808", size = 737238, upload-time = "2026-01-03T17:31:17.909Z" }, + { url = "https://files.pythonhosted.org/packages/f7/49/459327f0d5bcd8c6c9ca69e60fdeebc3622861e696490d8674a6d0cb90a6/aiohttp-3.13.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:6fc0e2337d1a4c3e6acafda6a78a39d4c14caea625124817420abceed36e2415", size = 492292, upload-time = "2026-01-03T17:31:19.919Z" }, + { url = "https://files.pythonhosted.org/packages/e8/0b/b97660c5fd05d3495b4eb27f2d0ef18dc1dc4eff7511a9bf371397ff0264/aiohttp-3.13.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c685f2d80bb67ca8c3837823ad76196b3694b0159d232206d1e461d3d434666f", size = 493021, upload-time = "2026-01-03T17:31:21.636Z" }, + { url = "https://files.pythonhosted.org/packages/54/d4/438efabdf74e30aeceb890c3290bbaa449780583b1270b00661126b8aae4/aiohttp-3.13.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48e377758516d262bde50c2584fc6c578af272559c409eecbdd2bae1601184d6", size = 1717263, upload-time = "2026-01-03T17:31:23.296Z" }, + { url = "https://files.pythonhosted.org/packages/71/f2/7bddc7fd612367d1459c5bcf598a9e8f7092d6580d98de0e057eb42697ad/aiohttp-3.13.3-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:34749271508078b261c4abb1767d42b8d0c0cc9449c73a4df494777dc55f0687", size = 1669107, upload-time = "2026-01-03T17:31:25.334Z" }, + { url = "https://files.pythonhosted.org/packages/00/5a/1aeaecca40e22560f97610a329e0e5efef5e0b5afdf9f857f0d93839ab2e/aiohttp-3.13.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:82611aeec80eb144416956ec85b6ca45a64d76429c1ed46ae1b5f86c6e0c9a26", size = 1760196, upload-time = "2026-01-03T17:31:27.394Z" }, + { url = "https://files.pythonhosted.org/packages/f8/f8/0ff6992bea7bd560fc510ea1c815f87eedd745fe035589c71ce05612a19a/aiohttp-3.13.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2fff83cfc93f18f215896e3a190e8e5cb413ce01553901aca925176e7568963a", size = 1843591, upload-time = "2026-01-03T17:31:29.238Z" }, + { url = "https://files.pythonhosted.org/packages/e3/d1/e30e537a15f53485b61f5be525f2157da719819e8377298502aebac45536/aiohttp-3.13.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bbe7d4cecacb439e2e2a8a1a7b935c25b812af7a5fd26503a66dadf428e79ec1", size = 1720277, upload-time = "2026-01-03T17:31:31.053Z" }, + { url = "https://files.pythonhosted.org/packages/84/45/23f4c451d8192f553d38d838831ebbc156907ea6e05557f39563101b7717/aiohttp-3.13.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b928f30fe49574253644b1ca44b1b8adbd903aa0da4b9054a6c20fc7f4092a25", size = 1548575, upload-time = "2026-01-03T17:31:32.87Z" }, + { url = "https://files.pythonhosted.org/packages/6a/ed/0a42b127a43712eda7807e7892c083eadfaf8429ca8fb619662a530a3aab/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7b5e8fe4de30df199155baaf64f2fcd604f4c678ed20910db8e2c66dc4b11603", size = 1679455, upload-time = "2026-01-03T17:31:34.76Z" }, + { url = "https://files.pythonhosted.org/packages/2e/b5/c05f0c2b4b4fe2c9d55e73b6d3ed4fd6c9dc2684b1d81cbdf77e7fad9adb/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:8542f41a62bcc58fc7f11cf7c90e0ec324ce44950003feb70640fc2a9092c32a", size = 1687417, upload-time = "2026-01-03T17:31:36.699Z" }, + { url = "https://files.pythonhosted.org/packages/c9/6b/915bc5dad66aef602b9e459b5a973529304d4e89ca86999d9d75d80cbd0b/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:5e1d8c8b8f1d91cd08d8f4a3c2b067bfca6ec043d3ff36de0f3a715feeedf926", size = 1729968, upload-time = "2026-01-03T17:31:38.622Z" }, + { url = "https://files.pythonhosted.org/packages/11/3b/e84581290a9520024a08640b63d07673057aec5ca548177a82026187ba73/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:90455115e5da1c3c51ab619ac57f877da8fd6d73c05aacd125c5ae9819582aba", size = 1545690, upload-time = "2026-01-03T17:31:40.57Z" }, + { url = "https://files.pythonhosted.org/packages/f5/04/0c3655a566c43fd647c81b895dfe361b9f9ad6d58c19309d45cff52d6c3b/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:042e9e0bcb5fba81886c8b4fbb9a09d6b8a00245fd8d88e4d989c1f96c74164c", size = 1746390, upload-time = "2026-01-03T17:31:42.857Z" }, + { url = "https://files.pythonhosted.org/packages/1f/53/71165b26978f719c3419381514c9690bd5980e764a09440a10bb816ea4ab/aiohttp-3.13.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2eb752b102b12a76ca02dff751a801f028b4ffbbc478840b473597fc91a9ed43", size = 1702188, upload-time = "2026-01-03T17:31:44.984Z" }, + { url = "https://files.pythonhosted.org/packages/29/a7/cbe6c9e8e136314fa1980da388a59d2f35f35395948a08b6747baebb6aa6/aiohttp-3.13.3-cp314-cp314-win32.whl", hash = "sha256:b556c85915d8efaed322bf1bdae9486aa0f3f764195a0fb6ee962e5c71ef5ce1", size = 433126, upload-time = "2026-01-03T17:31:47.463Z" }, + { url = "https://files.pythonhosted.org/packages/de/56/982704adea7d3b16614fc5936014e9af85c0e34b58f9046655817f04306e/aiohttp-3.13.3-cp314-cp314-win_amd64.whl", hash = "sha256:9bf9f7a65e7aa20dd764151fb3d616c81088f91f8df39c3893a536e279b4b984", size = 459128, upload-time = "2026-01-03T17:31:49.2Z" }, + { url = "https://files.pythonhosted.org/packages/6c/2a/3c79b638a9c3d4658d345339d22070241ea341ed4e07b5ac60fb0f418003/aiohttp-3.13.3-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:05861afbbec40650d8a07ea324367cb93e9e8cc7762e04dd4405df99fa65159c", size = 769512, upload-time = "2026-01-03T17:31:51.134Z" }, + { url = "https://files.pythonhosted.org/packages/29/b9/3e5014d46c0ab0db8707e0ac2711ed28c4da0218c358a4e7c17bae0d8722/aiohttp-3.13.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2fc82186fadc4a8316768d61f3722c230e2c1dcab4200d52d2ebdf2482e47592", size = 506444, upload-time = "2026-01-03T17:31:52.85Z" }, + { url = "https://files.pythonhosted.org/packages/90/03/c1d4ef9a054e151cd7839cdc497f2638f00b93cbe8043983986630d7a80c/aiohttp-3.13.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0add0900ff220d1d5c5ebbf99ed88b0c1bbf87aa7e4262300ed1376a6b13414f", size = 510798, upload-time = "2026-01-03T17:31:54.91Z" }, + { url = "https://files.pythonhosted.org/packages/ea/76/8c1e5abbfe8e127c893fe7ead569148a4d5a799f7cf958d8c09f3eedf097/aiohttp-3.13.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:568f416a4072fbfae453dcf9a99194bbb8bdeab718e08ee13dfa2ba0e4bebf29", size = 1868835, upload-time = "2026-01-03T17:31:56.733Z" }, + { url = "https://files.pythonhosted.org/packages/8e/ac/984c5a6f74c363b01ff97adc96a3976d9c98940b8969a1881575b279ac5d/aiohttp-3.13.3-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:add1da70de90a2569c5e15249ff76a631ccacfe198375eead4aadf3b8dc849dc", size = 1720486, upload-time = "2026-01-03T17:31:58.65Z" }, + { url = "https://files.pythonhosted.org/packages/b2/9a/b7039c5f099c4eb632138728828b33428585031a1e658d693d41d07d89d1/aiohttp-3.13.3-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:10b47b7ba335d2e9b1239fa571131a87e2d8ec96b333e68b2a305e7a98b0bae2", size = 1847951, upload-time = "2026-01-03T17:32:00.989Z" }, + { url = "https://files.pythonhosted.org/packages/3c/02/3bec2b9a1ba3c19ff89a43a19324202b8eb187ca1e928d8bdac9bbdddebd/aiohttp-3.13.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3dd4dce1c718e38081c8f35f323209d4c1df7d4db4bab1b5c88a6b4d12b74587", size = 1941001, upload-time = "2026-01-03T17:32:03.122Z" }, + { url = "https://files.pythonhosted.org/packages/37/df/d879401cedeef27ac4717f6426c8c36c3091c6e9f08a9178cc87549c537f/aiohttp-3.13.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:34bac00a67a812570d4a460447e1e9e06fae622946955f939051e7cc895cfab8", size = 1797246, upload-time = "2026-01-03T17:32:05.255Z" }, + { url = "https://files.pythonhosted.org/packages/8d/15/be122de1f67e6953add23335c8ece6d314ab67c8bebb3f181063010795a7/aiohttp-3.13.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a19884d2ee70b06d9204b2727a7b9f983d0c684c650254679e716b0b77920632", size = 1627131, upload-time = "2026-01-03T17:32:07.607Z" }, + { url = "https://files.pythonhosted.org/packages/12/12/70eedcac9134cfa3219ab7af31ea56bc877395b1ac30d65b1bc4b27d0438/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5f8ca7f2bb6ba8348a3614c7918cc4bb73268c5ac2a207576b7afea19d3d9f64", size = 1795196, upload-time = "2026-01-03T17:32:09.59Z" }, + { url = "https://files.pythonhosted.org/packages/32/11/b30e1b1cd1f3054af86ebe60df96989c6a414dd87e27ad16950eee420bea/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:b0d95340658b9d2f11d9697f59b3814a9d3bb4b7a7c20b131df4bcef464037c0", size = 1782841, upload-time = "2026-01-03T17:32:11.445Z" }, + { url = "https://files.pythonhosted.org/packages/88/0d/d98a9367b38912384a17e287850f5695c528cff0f14f791ce8ee2e4f7796/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:a1e53262fd202e4b40b70c3aff944a8155059beedc8a89bba9dc1f9ef06a1b56", size = 1795193, upload-time = "2026-01-03T17:32:13.705Z" }, + { url = "https://files.pythonhosted.org/packages/43/a5/a2dfd1f5ff5581632c7f6a30e1744deda03808974f94f6534241ef60c751/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:d60ac9663f44168038586cab2157e122e46bdef09e9368b37f2d82d354c23f72", size = 1621979, upload-time = "2026-01-03T17:32:15.965Z" }, + { url = "https://files.pythonhosted.org/packages/fa/f0/12973c382ae7c1cccbc4417e129c5bf54c374dfb85af70893646e1f0e749/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:90751b8eed69435bac9ff4e3d2f6b3af1f57e37ecb0fbeee59c0174c9e2d41df", size = 1822193, upload-time = "2026-01-03T17:32:18.219Z" }, + { url = "https://files.pythonhosted.org/packages/3c/5f/24155e30ba7f8c96918af1350eb0663e2430aad9e001c0489d89cd708ab1/aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:fc353029f176fd2b3ec6cfc71be166aba1936fe5d73dd1992ce289ca6647a9aa", size = 1769801, upload-time = "2026-01-03T17:32:20.25Z" }, + { url = "https://files.pythonhosted.org/packages/eb/f8/7314031ff5c10e6ece114da79b338ec17eeff3a079e53151f7e9f43c4723/aiohttp-3.13.3-cp314-cp314t-win32.whl", hash = "sha256:2e41b18a58da1e474a057b3d35248d8320029f61d70a37629535b16a0c8f3767", size = 466523, upload-time = "2026-01-03T17:32:22.215Z" }, + { url = "https://files.pythonhosted.org/packages/b4/63/278a98c715ae467624eafe375542d8ba9b4383a016df8fdefe0ae28382a7/aiohttp-3.13.3-cp314-cp314t-win_amd64.whl", hash = "sha256:44531a36aa2264a1860089ffd4dce7baf875ee5a6079d5fb42e261c704ef7344", size = 499694, upload-time = "2026-01-03T17:32:24.546Z" }, +] + +[[package]] +name = "aiosignal" +version = "1.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "frozenlist" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/61/62/06741b579156360248d1ec624842ad0edf697050bbaf7c3e46394e106ad1/aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7", size = 25007, upload-time = "2025-07-03T22:54:43.528Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490, upload-time = "2025-07-03T22:54:42.156Z" }, +] + [[package]] name = "aiosqlite" version = "0.22.1" @@ -64,6 +218,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl", hash = "sha256:d405828884fc140aa80a3c667b8beed277f1dfedec42ba031bd6ac3db606ab6c", size = 113592, upload-time = "2026-01-06T11:45:19.497Z" }, ] +[[package]] +name = "async-timeout" +version = "5.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a5/ae/136395dfbfe00dfc94da3f3e136d0b13f394cba8f4841120e34226265780/async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3", size = 9274, upload-time = "2024-11-06T16:41:39.6Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c", size = 6233, upload-time = "2024-11-06T16:41:37.9Z" }, +] + [[package]] name = "attrs" version = "25.4.0" @@ -124,6 +287,84 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/1a/39/47f9197bdd44df24d67ac8893641e16f386c984a0619ef2ee4c51fbbc019/beautifulsoup4-4.14.3-py3-none-any.whl", hash = "sha256:0918bfe44902e6ad8d57732ba310582e98da931428d231a5ecb9e7c703a735bb", size = 107721, upload-time = "2025-11-30T15:08:24.087Z" }, ] +[[package]] +name = "brotli" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f7/16/c92ca344d646e71a43b8bb353f0a6490d7f6e06210f8554c8f874e454285/brotli-1.2.0.tar.gz", hash = "sha256:e310f77e41941c13340a95976fe66a8a95b01e783d430eeaf7a2f87e0a57dd0a", size = 7388632, upload-time = "2025-11-05T18:39:42.86Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/64/10/a090475284fc4a71aed40a96f32e44a7fe5bda39687353dd977720b211b6/brotli-1.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3b90b767916ac44e93a8e28ce6adf8d551e43affb512f2377c732d486ac6514e", size = 863089, upload-time = "2025-11-05T18:38:01.181Z" }, + { url = "https://files.pythonhosted.org/packages/03/41/17416630e46c07ac21e378c3464815dd2e120b441e641bc516ac32cc51d2/brotli-1.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6be67c19e0b0c56365c6a76e393b932fb0e78b3b56b711d180dd7013cb1fd984", size = 445442, upload-time = "2025-11-05T18:38:02.434Z" }, + { url = "https://files.pythonhosted.org/packages/24/31/90cc06584deb5d4fcafc0985e37741fc6b9717926a78674bbb3ce018957e/brotli-1.2.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0bbd5b5ccd157ae7913750476d48099aaf507a79841c0d04a9db4415b14842de", size = 1532658, upload-time = "2025-11-05T18:38:03.588Z" }, + { url = "https://files.pythonhosted.org/packages/62/17/33bf0c83bcbc96756dfd712201d87342732fad70bb3472c27e833a44a4f9/brotli-1.2.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3f3c908bcc404c90c77d5a073e55271a0a498f4e0756e48127c35d91cf155947", size = 1631241, upload-time = "2025-11-05T18:38:04.582Z" }, + { url = "https://files.pythonhosted.org/packages/48/10/f47854a1917b62efe29bc98ac18e5d4f71df03f629184575b862ef2e743b/brotli-1.2.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1b557b29782a643420e08d75aea889462a4a8796e9a6cf5621ab05a3f7da8ef2", size = 1424307, upload-time = "2025-11-05T18:38:05.587Z" }, + { url = "https://files.pythonhosted.org/packages/e4/b7/f88eb461719259c17483484ea8456925ee057897f8e64487d76e24e5e38d/brotli-1.2.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:81da1b229b1889f25adadc929aeb9dbc4e922bd18561b65b08dd9343cfccca84", size = 1488208, upload-time = "2025-11-05T18:38:06.613Z" }, + { url = "https://files.pythonhosted.org/packages/26/59/41bbcb983a0c48b0b8004203e74706c6b6e99a04f3c7ca6f4f41f364db50/brotli-1.2.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:ff09cd8c5eec3b9d02d2408db41be150d8891c5566addce57513bf546e3d6c6d", size = 1597574, upload-time = "2025-11-05T18:38:07.838Z" }, + { url = "https://files.pythonhosted.org/packages/8e/e6/8c89c3bdabbe802febb4c5c6ca224a395e97913b5df0dff11b54f23c1788/brotli-1.2.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:a1778532b978d2536e79c05dac2d8cd857f6c55cd0c95ace5b03740824e0e2f1", size = 1492109, upload-time = "2025-11-05T18:38:08.816Z" }, + { url = "https://files.pythonhosted.org/packages/ed/9a/4b19d4310b2dbd545c0c33f176b0528fa68c3cd0754e34b2f2bcf56548ae/brotli-1.2.0-cp310-cp310-win32.whl", hash = "sha256:b232029d100d393ae3c603c8ffd7e3fe6f798c5e28ddca5feabb8e8fdb732997", size = 334461, upload-time = "2025-11-05T18:38:10.729Z" }, + { url = "https://files.pythonhosted.org/packages/ac/39/70981d9f47705e3c2b95c0847dfa3e7a37aa3b7c6030aedc4873081ed005/brotli-1.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:ef87b8ab2704da227e83a246356a2b179ef826f550f794b2c52cddb4efbd0196", size = 369035, upload-time = "2025-11-05T18:38:11.827Z" }, + { url = "https://files.pythonhosted.org/packages/7a/ef/f285668811a9e1ddb47a18cb0b437d5fc2760d537a2fe8a57875ad6f8448/brotli-1.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:15b33fe93cedc4caaff8a0bd1eb7e3dab1c61bb22a0bf5bdfdfd97cd7da79744", size = 863110, upload-time = "2025-11-05T18:38:12.978Z" }, + { url = "https://files.pythonhosted.org/packages/50/62/a3b77593587010c789a9d6eaa527c79e0848b7b860402cc64bc0bc28a86c/brotli-1.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:898be2be399c221d2671d29eed26b6b2713a02c2119168ed914e7d00ceadb56f", size = 445438, upload-time = "2025-11-05T18:38:14.208Z" }, + { url = "https://files.pythonhosted.org/packages/cd/e1/7fadd47f40ce5549dc44493877db40292277db373da5053aff181656e16e/brotli-1.2.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:350c8348f0e76fff0a0fd6c26755d2653863279d086d3aa2c290a6a7251135dd", size = 1534420, upload-time = "2025-11-05T18:38:15.111Z" }, + { url = "https://files.pythonhosted.org/packages/12/8b/1ed2f64054a5a008a4ccd2f271dbba7a5fb1a3067a99f5ceadedd4c1d5a7/brotli-1.2.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2e1ad3fda65ae0d93fec742a128d72e145c9c7a99ee2fcd667785d99eb25a7fe", size = 1632619, upload-time = "2025-11-05T18:38:16.094Z" }, + { url = "https://files.pythonhosted.org/packages/89/5a/7071a621eb2d052d64efd5da2ef55ecdac7c3b0c6e4f9d519e9c66d987ef/brotli-1.2.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:40d918bce2b427a0c4ba189df7a006ac0c7277c180aee4617d99e9ccaaf59e6a", size = 1426014, upload-time = "2025-11-05T18:38:17.177Z" }, + { url = "https://files.pythonhosted.org/packages/26/6d/0971a8ea435af5156acaaccec1a505f981c9c80227633851f2810abd252a/brotli-1.2.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2a7f1d03727130fc875448b65b127a9ec5d06d19d0148e7554384229706f9d1b", size = 1489661, upload-time = "2025-11-05T18:38:18.41Z" }, + { url = "https://files.pythonhosted.org/packages/f3/75/c1baca8b4ec6c96a03ef8230fab2a785e35297632f402ebb1e78a1e39116/brotli-1.2.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:9c79f57faa25d97900bfb119480806d783fba83cd09ee0b33c17623935b05fa3", size = 1599150, upload-time = "2025-11-05T18:38:19.792Z" }, + { url = "https://files.pythonhosted.org/packages/0d/1a/23fcfee1c324fd48a63d7ebf4bac3a4115bdb1b00e600f80f727d850b1ae/brotli-1.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:844a8ceb8483fefafc412f85c14f2aae2fb69567bf2a0de53cdb88b73e7c43ae", size = 1493505, upload-time = "2025-11-05T18:38:20.913Z" }, + { url = "https://files.pythonhosted.org/packages/36/e5/12904bbd36afeef53d45a84881a4810ae8810ad7e328a971ebbfd760a0b3/brotli-1.2.0-cp311-cp311-win32.whl", hash = "sha256:aa47441fa3026543513139cb8926a92a8e305ee9c71a6209ef7a97d91640ea03", size = 334451, upload-time = "2025-11-05T18:38:21.94Z" }, + { url = "https://files.pythonhosted.org/packages/02/8b/ecb5761b989629a4758c394b9301607a5880de61ee2ee5fe104b87149ebc/brotli-1.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:022426c9e99fd65d9475dce5c195526f04bb8be8907607e27e747893f6ee3e24", size = 369035, upload-time = "2025-11-05T18:38:22.941Z" }, + { url = "https://files.pythonhosted.org/packages/11/ee/b0a11ab2315c69bb9b45a2aaed022499c9c24a205c3a49c3513b541a7967/brotli-1.2.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:35d382625778834a7f3061b15423919aa03e4f5da34ac8e02c074e4b75ab4f84", size = 861543, upload-time = "2025-11-05T18:38:24.183Z" }, + { url = "https://files.pythonhosted.org/packages/e1/2f/29c1459513cd35828e25531ebfcbf3e92a5e49f560b1777a9af7203eb46e/brotli-1.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7a61c06b334bd99bc5ae84f1eeb36bfe01400264b3c352f968c6e30a10f9d08b", size = 444288, upload-time = "2025-11-05T18:38:25.139Z" }, + { url = "https://files.pythonhosted.org/packages/3d/6f/feba03130d5fceadfa3a1bb102cb14650798c848b1df2a808356f939bb16/brotli-1.2.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:acec55bb7c90f1dfc476126f9711a8e81c9af7fb617409a9ee2953115343f08d", size = 1528071, upload-time = "2025-11-05T18:38:26.081Z" }, + { url = "https://files.pythonhosted.org/packages/2b/38/f3abb554eee089bd15471057ba85f47e53a44a462cfce265d9bf7088eb09/brotli-1.2.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:260d3692396e1895c5034f204f0db022c056f9e2ac841593a4cf9426e2a3faca", size = 1626913, upload-time = "2025-11-05T18:38:27.284Z" }, + { url = "https://files.pythonhosted.org/packages/03/a7/03aa61fbc3c5cbf99b44d158665f9b0dd3d8059be16c460208d9e385c837/brotli-1.2.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:072e7624b1fc4d601036ab3f4f27942ef772887e876beff0301d261210bca97f", size = 1419762, upload-time = "2025-11-05T18:38:28.295Z" }, + { url = "https://files.pythonhosted.org/packages/21/1b/0374a89ee27d152a5069c356c96b93afd1b94eae83f1e004b57eb6ce2f10/brotli-1.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:adedc4a67e15327dfdd04884873c6d5a01d3e3b6f61406f99b1ed4865a2f6d28", size = 1484494, upload-time = "2025-11-05T18:38:29.29Z" }, + { url = "https://files.pythonhosted.org/packages/cf/57/69d4fe84a67aef4f524dcd075c6eee868d7850e85bf01d778a857d8dbe0a/brotli-1.2.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7a47ce5c2288702e09dc22a44d0ee6152f2c7eda97b3c8482d826a1f3cfc7da7", size = 1593302, upload-time = "2025-11-05T18:38:30.639Z" }, + { url = "https://files.pythonhosted.org/packages/d5/3b/39e13ce78a8e9a621c5df3aeb5fd181fcc8caba8c48a194cd629771f6828/brotli-1.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:af43b8711a8264bb4e7d6d9a6d004c3a2019c04c01127a868709ec29962b6036", size = 1487913, upload-time = "2025-11-05T18:38:31.618Z" }, + { url = "https://files.pythonhosted.org/packages/62/28/4d00cb9bd76a6357a66fcd54b4b6d70288385584063f4b07884c1e7286ac/brotli-1.2.0-cp312-cp312-win32.whl", hash = "sha256:e99befa0b48f3cd293dafeacdd0d191804d105d279e0b387a32054c1180f3161", size = 334362, upload-time = "2025-11-05T18:38:32.939Z" }, + { url = "https://files.pythonhosted.org/packages/1c/4e/bc1dcac9498859d5e353c9b153627a3752868a9d5f05ce8dedd81a2354ab/brotli-1.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:b35c13ce241abdd44cb8ca70683f20c0c079728a36a996297adb5334adfc1c44", size = 369115, upload-time = "2025-11-05T18:38:33.765Z" }, + { url = "https://files.pythonhosted.org/packages/6c/d4/4ad5432ac98c73096159d9ce7ffeb82d151c2ac84adcc6168e476bb54674/brotli-1.2.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9e5825ba2c9998375530504578fd4d5d1059d09621a02065d1b6bfc41a8e05ab", size = 861523, upload-time = "2025-11-05T18:38:34.67Z" }, + { url = "https://files.pythonhosted.org/packages/91/9f/9cc5bd03ee68a85dc4bc89114f7067c056a3c14b3d95f171918c088bf88d/brotli-1.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0cf8c3b8ba93d496b2fae778039e2f5ecc7cff99df84df337ca31d8f2252896c", size = 444289, upload-time = "2025-11-05T18:38:35.6Z" }, + { url = "https://files.pythonhosted.org/packages/2e/b6/fe84227c56a865d16a6614e2c4722864b380cb14b13f3e6bef441e73a85a/brotli-1.2.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c8565e3cdc1808b1a34714b553b262c5de5fbda202285782173ec137fd13709f", size = 1528076, upload-time = "2025-11-05T18:38:36.639Z" }, + { url = "https://files.pythonhosted.org/packages/55/de/de4ae0aaca06c790371cf6e7ee93a024f6b4bb0568727da8c3de112e726c/brotli-1.2.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:26e8d3ecb0ee458a9804f47f21b74845cc823fd1bb19f02272be70774f56e2a6", size = 1626880, upload-time = "2025-11-05T18:38:37.623Z" }, + { url = "https://files.pythonhosted.org/packages/5f/16/a1b22cbea436642e071adcaf8d4b350a2ad02f5e0ad0da879a1be16188a0/brotli-1.2.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:67a91c5187e1eec76a61625c77a6c8c785650f5b576ca732bd33ef58b0dff49c", size = 1419737, upload-time = "2025-11-05T18:38:38.729Z" }, + { url = "https://files.pythonhosted.org/packages/46/63/c968a97cbb3bdbf7f974ef5a6ab467a2879b82afbc5ffb65b8acbb744f95/brotli-1.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4ecdb3b6dc36e6d6e14d3a1bdc6c1057c8cbf80db04031d566eb6080ce283a48", size = 1484440, upload-time = "2025-11-05T18:38:39.916Z" }, + { url = "https://files.pythonhosted.org/packages/06/9d/102c67ea5c9fc171f423e8399e585dabea29b5bc79b05572891e70013cdd/brotli-1.2.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3e1b35d56856f3ed326b140d3c6d9db91740f22e14b06e840fe4bb1923439a18", size = 1593313, upload-time = "2025-11-05T18:38:41.24Z" }, + { url = "https://files.pythonhosted.org/packages/9e/4a/9526d14fa6b87bc827ba1755a8440e214ff90de03095cacd78a64abe2b7d/brotli-1.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:54a50a9dad16b32136b2241ddea9e4df159b41247b2ce6aac0b3276a66a8f1e5", size = 1487945, upload-time = "2025-11-05T18:38:42.277Z" }, + { url = "https://files.pythonhosted.org/packages/5b/e8/3fe1ffed70cbef83c5236166acaed7bb9c766509b157854c80e2f766b38c/brotli-1.2.0-cp313-cp313-win32.whl", hash = "sha256:1b1d6a4efedd53671c793be6dd760fcf2107da3a52331ad9ea429edf0902f27a", size = 334368, upload-time = "2025-11-05T18:38:43.345Z" }, + { url = "https://files.pythonhosted.org/packages/ff/91/e739587be970a113b37b821eae8097aac5a48e5f0eca438c22e4c7dd8648/brotli-1.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:b63daa43d82f0cdabf98dee215b375b4058cce72871fd07934f179885aad16e8", size = 369116, upload-time = "2025-11-05T18:38:44.609Z" }, + { url = "https://files.pythonhosted.org/packages/17/e1/298c2ddf786bb7347a1cd71d63a347a79e5712a7c0cba9e3c3458ebd976f/brotli-1.2.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:6c12dad5cd04530323e723787ff762bac749a7b256a5bece32b2243dd5c27b21", size = 863080, upload-time = "2025-11-05T18:38:45.503Z" }, + { url = "https://files.pythonhosted.org/packages/84/0c/aac98e286ba66868b2b3b50338ffbd85a35c7122e9531a73a37a29763d38/brotli-1.2.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:3219bd9e69868e57183316ee19c84e03e8f8b5a1d1f2667e1aa8c2f91cb061ac", size = 445453, upload-time = "2025-11-05T18:38:46.433Z" }, + { url = "https://files.pythonhosted.org/packages/ec/f1/0ca1f3f99ae300372635ab3fe2f7a79fa335fee3d874fa7f9e68575e0e62/brotli-1.2.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:963a08f3bebd8b75ac57661045402da15991468a621f014be54e50f53a58d19e", size = 1528168, upload-time = "2025-11-05T18:38:47.371Z" }, + { url = "https://files.pythonhosted.org/packages/d6/a6/2ebfc8f766d46df8d3e65b880a2e220732395e6d7dc312c1e1244b0f074a/brotli-1.2.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9322b9f8656782414b37e6af884146869d46ab85158201d82bab9abbcb971dc7", size = 1627098, upload-time = "2025-11-05T18:38:48.385Z" }, + { url = "https://files.pythonhosted.org/packages/f3/2f/0976d5b097ff8a22163b10617f76b2557f15f0f39d6a0fe1f02b1a53e92b/brotli-1.2.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cf9cba6f5b78a2071ec6fb1e7bd39acf35071d90a81231d67e92d637776a6a63", size = 1419861, upload-time = "2025-11-05T18:38:49.372Z" }, + { url = "https://files.pythonhosted.org/packages/9c/97/d76df7176a2ce7616ff94c1fb72d307c9a30d2189fe877f3dd99af00ea5a/brotli-1.2.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7547369c4392b47d30a3467fe8c3330b4f2e0f7730e45e3103d7d636678a808b", size = 1484594, upload-time = "2025-11-05T18:38:50.655Z" }, + { url = "https://files.pythonhosted.org/packages/d3/93/14cf0b1216f43df5609f5b272050b0abd219e0b54ea80b47cef9867b45e7/brotli-1.2.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:fc1530af5c3c275b8524f2e24841cbe2599d74462455e9bae5109e9ff42e9361", size = 1593455, upload-time = "2025-11-05T18:38:51.624Z" }, + { url = "https://files.pythonhosted.org/packages/b3/73/3183c9e41ca755713bdf2cc1d0810df742c09484e2e1ddd693bee53877c1/brotli-1.2.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d2d085ded05278d1c7f65560aae97b3160aeb2ea2c0b3e26204856beccb60888", size = 1488164, upload-time = "2025-11-05T18:38:53.079Z" }, + { url = "https://files.pythonhosted.org/packages/64/6a/0c78d8f3a582859236482fd9fa86a65a60328a00983006bcf6d83b7b2253/brotli-1.2.0-cp314-cp314-win32.whl", hash = "sha256:832c115a020e463c2f67664560449a7bea26b0c1fdd690352addad6d0a08714d", size = 339280, upload-time = "2025-11-05T18:38:54.02Z" }, + { url = "https://files.pythonhosted.org/packages/f5/10/56978295c14794b2c12007b07f3e41ba26acda9257457d7085b0bb3bb90c/brotli-1.2.0-cp314-cp314-win_amd64.whl", hash = "sha256:e7c0af964e0b4e3412a0ebf341ea26ec767fa0b4cf81abb5e897c9338b5ad6a3", size = 375639, upload-time = "2025-11-05T18:38:55.67Z" }, +] + +[[package]] +name = "brotlicffi" +version = "1.2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/84/85/57c314a6b35336efbbdc13e5fc9ae13f6b60a0647cfa7c1221178ac6d8ae/brotlicffi-1.2.0.0.tar.gz", hash = "sha256:34345d8d1f9d534fcac2249e57a4c3c8801a33c9942ff9f8574f67a175e17adb", size = 476682, upload-time = "2025-11-21T18:17:57.334Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e4/df/a72b284d8c7bef0ed5756b41c2eb7d0219a1dd6ac6762f1c7bdbc31ef3af/brotlicffi-1.2.0.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:9458d08a7ccde8e3c0afedbf2c70a8263227a68dea5ab13590593f4c0a4fd5f4", size = 432340, upload-time = "2025-11-21T18:17:42.277Z" }, + { url = "https://files.pythonhosted.org/packages/74/2b/cc55a2d1d6fb4f5d458fba44a3d3f91fb4320aa14145799fd3a996af0686/brotlicffi-1.2.0.0-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:84e3d0020cf1bd8b8131f4a07819edee9f283721566fe044a20ec792ca8fd8b7", size = 1534002, upload-time = "2025-11-21T18:17:43.746Z" }, + { url = "https://files.pythonhosted.org/packages/e4/9c/d51486bf366fc7d6735f0e46b5b96ca58dc005b250263525a1eea3cd5d21/brotlicffi-1.2.0.0-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:33cfb408d0cff64cd50bef268c0fed397c46fbb53944aa37264148614a62e990", size = 1536547, upload-time = "2025-11-21T18:17:45.729Z" }, + { url = "https://files.pythonhosted.org/packages/1b/37/293a9a0a7caf17e6e657668bebb92dfe730305999fe8c0e2703b8888789c/brotlicffi-1.2.0.0-cp38-abi3-win32.whl", hash = "sha256:23e5c912fdc6fd37143203820230374d24babd078fc054e18070a647118158f6", size = 343085, upload-time = "2025-11-21T18:17:48.887Z" }, + { url = "https://files.pythonhosted.org/packages/07/6b/6e92009df3b8b7272f85a0992b306b61c34b7ea1c4776643746e61c380ac/brotlicffi-1.2.0.0-cp38-abi3-win_amd64.whl", hash = "sha256:f139a7cdfe4ae7859513067b736eb44d19fae1186f9e99370092f6915216451b", size = 378586, upload-time = "2025-11-21T18:17:50.531Z" }, + { url = "https://files.pythonhosted.org/packages/a4/ec/52488a0563f1663e2ccc75834b470650f4b8bcdea3132aef3bf67219c661/brotlicffi-1.2.0.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:fa102a60e50ddbd08de86a63431a722ea216d9bc903b000bf544149cc9b823dc", size = 402002, upload-time = "2025-11-21T18:17:51.76Z" }, + { url = "https://files.pythonhosted.org/packages/e4/63/d4aea4835fd97da1401d798d9b8ba77227974de565faea402f520b37b10f/brotlicffi-1.2.0.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7d3c4332fc808a94e8c1035950a10d04b681b03ab585ce897ae2a360d479037c", size = 406447, upload-time = "2025-11-21T18:17:53.614Z" }, + { url = "https://files.pythonhosted.org/packages/62/4e/5554ecb2615ff035ef8678d4e419549a0f7a28b3f096b272174d656749fb/brotlicffi-1.2.0.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fb4eb5830026b79a93bf503ad32b2c5257315e9ffc49e76b2715cffd07c8e3db", size = 402521, upload-time = "2025-11-21T18:17:54.875Z" }, + { url = "https://files.pythonhosted.org/packages/b5/d3/b07f8f125ac52bbee5dc00ef0d526f820f67321bf4184f915f17f50a4657/brotlicffi-1.2.0.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:3832c66e00d6d82087f20a972b2fc03e21cd99ef22705225a6f8f418a9158ecc", size = 374730, upload-time = "2025-11-21T18:17:56.334Z" }, +] + [[package]] name = "certifi" version = "2026.1.4" @@ -325,6 +566,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274, upload-time = "2025-11-15T20:45:41.139Z" }, ] +[[package]] +name = "cobble" +version = "0.1.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/54/7a/a507c709be2c96e1bb6102eb7b7f4026c5e5e223ef7d745a17d239e9d844/cobble-0.1.4.tar.gz", hash = "sha256:de38be1539992c8a06e569630717c485a5f91be2192c461ea2b220607dfa78aa", size = 3805, upload-time = "2024-06-01T18:11:09.528Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d5/e1/3714a2f371985215c219c2a70953d38e3eed81ef165aed061d21de0e998b/cobble-0.1.4-py3-none-any.whl", hash = "sha256:36c91b1655e599fd428e2b95fdd5f0da1ca2e9f1abb0bc871dec21a0e78a2b44", size = 3984, upload-time = "2024-06-01T18:11:07.911Z" }, +] + [[package]] name = "colorama" version = "0.4.6" @@ -498,6 +748,67 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/79/f4/9ceb90cfd6a3847069b0b0b353fd3075dc69b49defc70182d8af0c4ca390/cryptography-46.0.4-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:be8c01a7d5a55f9a47d1888162b76c8f49d62b234d88f0ff91a9fbebe32ffbc3", size = 3406043, upload-time = "2026-01-28T00:24:32.236Z" }, ] +[[package]] +name = "datasets" +version = "4.5.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "dill" }, + { name = "filelock" }, + { name = "fsspec", extra = ["http"] }, + { name = "httpx" }, + { name = "huggingface-hub" }, + { name = "multiprocess" }, + { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "numpy", version = "2.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "packaging" }, + { name = "pandas", version = "2.3.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "pandas", version = "3.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "pyarrow" }, + { name = "pyyaml" }, + { name = "requests" }, + { name = "tqdm" }, + { name = "xxhash" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/55/bf/bb927bde63d649296c83e883171ae77074717c1b80fe2868b328bd0dbcbb/datasets-4.5.0.tar.gz", hash = "sha256:00c698ce1c2452e646cc5fad47fef39d3fe78dd650a8a6eb205bb45eb63cd500", size = 588384, upload-time = "2026-01-14T18:27:54.297Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fc/d5/0d563ea3c205eee226dc8053cf7682a8ac588db8acecd0eda2b587987a0b/datasets-4.5.0-py3-none-any.whl", hash = "sha256:b5d7e08096ffa407dd69e58b1c0271c9b2506140839b8d99af07375ad31b6726", size = 515196, upload-time = "2026-01-14T18:27:52.419Z" }, +] + +[[package]] +name = "ddgs" +version = "9.10.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "fake-useragent" }, + { name = "httpx", extra = ["brotli", "http2", "socks"] }, + { name = "lxml" }, + { name = "primp" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/07/76/8dc0323d1577037abad7a679f8af150ebb73a94995d3012de71a8898e6e6/ddgs-9.10.0.tar.gz", hash = "sha256:d9381ff75bdf1ad6691d3d1dc2be12be190d1d32ecd24f1002c492143c52c34f", size = 31491, upload-time = "2025-12-17T23:30:15.021Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b5/0e/d4b7d6a8df5074cf67bc14adead39955b0bf847c947ff6cad0bb527887f4/ddgs-9.10.0-py3-none-any.whl", hash = "sha256:81233d79309836eb03e7df2a0d2697adc83c47c342713132c0ba618f1f2c6eee", size = 40311, upload-time = "2025-12-17T23:30:13.606Z" }, +] + +[[package]] +name = "defusedxml" +version = "0.7.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0f/d5/c66da9b79e5bdb124974bfe172b4daf3c984ebd9c2a06e2b8a4dc7331c72/defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69", size = 75520, upload-time = "2021-03-08T10:59:26.269Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61", size = 25604, upload-time = "2021-03-08T10:59:24.45Z" }, +] + +[[package]] +name = "dill" +version = "0.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/12/80/630b4b88364e9a8c8c5797f4602d0f76ef820909ee32f0bacb9f90654042/dill-0.4.0.tar.gz", hash = "sha256:0633f1d2df477324f53a895b02c901fb961bdbf65a17122586ea7019292cbcf0", size = 186976, upload-time = "2025-04-16T00:41:48.867Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/50/3d/9373ad9c56321fdab5b41197068e1d8c25883b3fea29dd361f9b55116869/dill-0.4.0-py3-none-any.whl", hash = "sha256:44f54bf6412c2c8464c14e8243eb163690a9800dbe2c367330883b19c7561049", size = 119668, upload-time = "2025-04-16T00:41:47.671Z" }, +] + [[package]] name = "distlib" version = "0.4.0" @@ -516,18 +827,36 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277, upload-time = "2023-12-24T09:54:30.421Z" }, ] +[[package]] +name = "et-xmlfile" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d3/38/af70d7ab1ae9d4da450eeec1fa3918940a5fafb9055e934af8d6eb0c2313/et_xmlfile-2.0.0.tar.gz", hash = "sha256:dab3f4764309081ce75662649be815c4c9081e88f0837825f90fd28317d4da54", size = 17234, upload-time = "2024-10-25T17:25:40.039Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/8b/5fe2cc11fee489817272089c4203e679c63b570a5aaeb18d852ae3cbba6a/et_xmlfile-2.0.0-py3-none-any.whl", hash = "sha256:7a91720bc756843502c3b7504c77b8fe44217c85c537d85037f0f536151b2caa", size = 18059, upload-time = "2024-10-25T17:25:39.051Z" }, +] + [[package]] name = "exceptiongroup" version = "1.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" }, ] +[[package]] +name = "fake-useragent" +version = "2.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/41/43/948d10bf42735709edb5ae51e23297d034086f17fc7279fef385a7acb473/fake_useragent-2.2.0.tar.gz", hash = "sha256:4e6ab6571e40cc086d788523cf9e018f618d07f9050f822ff409a4dfe17c16b2", size = 158898, upload-time = "2025-04-14T15:32:19.238Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/51/37/b3ea9cd5558ff4cb51957caca2193981c6b0ff30bd0d2630ac62505d99d0/fake_useragent-2.2.0-py3-none-any.whl", hash = "sha256:67f35ca4d847b0d298187443aaf020413746e56acd985a611908c73dba2daa24", size = 161695, upload-time = "2025-04-14T15:32:17.732Z" }, +] + [[package]] name = "fastapi" version = "0.128.0" @@ -543,6 +872,69 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5c/05/5cbb59154b093548acd0f4c7c474a118eda06da25aa75c616b72d8fcd92a/fastapi-0.128.0-py3-none-any.whl", hash = "sha256:aebd93f9716ee3b4f4fcfe13ffb7cf308d99c9f3ab5622d8877441072561582d", size = 103094, upload-time = "2025-12-27T15:21:12.154Z" }, ] +[[package]] +name = "fastuuid" +version = "0.14.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/7d/d9daedf0f2ebcacd20d599928f8913e9d2aea1d56d2d355a93bfa2b611d7/fastuuid-0.14.0.tar.gz", hash = "sha256:178947fc2f995b38497a74172adee64fdeb8b7ec18f2a5934d037641ba265d26", size = 18232, upload-time = "2025-10-19T22:19:22.402Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ad/b2/731a6696e37cd20eed353f69a09f37a984a43c9713764ee3f7ad5f57f7f9/fastuuid-0.14.0-cp310-cp310-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:6e6243d40f6c793c3e2ee14c13769e341b90be5ef0c23c82fa6515a96145181a", size = 516760, upload-time = "2025-10-19T22:25:21.509Z" }, + { url = "https://files.pythonhosted.org/packages/c5/79/c73c47be2a3b8734d16e628982653517f80bbe0570e27185d91af6096507/fastuuid-0.14.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:13ec4f2c3b04271f62be2e1ce7e95ad2dd1cf97e94503a3760db739afbd48f00", size = 264748, upload-time = "2025-10-19T22:41:52.873Z" }, + { url = "https://files.pythonhosted.org/packages/24/c5/84c1eea05977c8ba5173555b0133e3558dc628bcf868d6bf1689ff14aedc/fastuuid-0.14.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b2fdd48b5e4236df145a149d7125badb28e0a383372add3fbaac9a6b7a394470", size = 254537, upload-time = "2025-10-19T22:33:55.603Z" }, + { url = "https://files.pythonhosted.org/packages/0e/23/4e362367b7fa17dbed646922f216b9921efb486e7abe02147e4b917359f8/fastuuid-0.14.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f74631b8322d2780ebcf2d2d75d58045c3e9378625ec51865fe0b5620800c39d", size = 278994, upload-time = "2025-10-19T22:26:17.631Z" }, + { url = "https://files.pythonhosted.org/packages/b2/72/3985be633b5a428e9eaec4287ed4b873b7c4c53a9639a8b416637223c4cd/fastuuid-0.14.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83cffc144dc93eb604b87b179837f2ce2af44871a7b323f2bfed40e8acb40ba8", size = 280003, upload-time = "2025-10-19T22:23:45.415Z" }, + { url = "https://files.pythonhosted.org/packages/b3/6d/6ef192a6df34e2266d5c9deb39cd3eea986df650cbcfeaf171aa52a059c3/fastuuid-0.14.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a771f135ab4523eb786e95493803942a5d1fc1610915f131b363f55af53b219", size = 303583, upload-time = "2025-10-19T22:26:00.756Z" }, + { url = "https://files.pythonhosted.org/packages/9d/11/8a2ea753c68d4fece29d5d7c6f3f903948cc6e82d1823bc9f7f7c0355db3/fastuuid-0.14.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4edc56b877d960b4eda2c4232f953a61490c3134da94f3c28af129fb9c62a4f6", size = 460955, upload-time = "2025-10-19T22:36:25.196Z" }, + { url = "https://files.pythonhosted.org/packages/23/42/7a32c93b6ce12642d9a152ee4753a078f372c9ebb893bc489d838dd4afd5/fastuuid-0.14.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bcc96ee819c282e7c09b2eed2b9bd13084e3b749fdb2faf58c318d498df2efbe", size = 480763, upload-time = "2025-10-19T22:24:28.451Z" }, + { url = "https://files.pythonhosted.org/packages/b9/e9/a5f6f686b46e3ed4ed3b93770111c233baac87dd6586a411b4988018ef1d/fastuuid-0.14.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7a3c0bca61eacc1843ea97b288d6789fbad7400d16db24e36a66c28c268cfe3d", size = 452613, upload-time = "2025-10-19T22:25:06.827Z" }, + { url = "https://files.pythonhosted.org/packages/b4/c9/18abc73c9c5b7fc0e476c1733b678783b2e8a35b0be9babd423571d44e98/fastuuid-0.14.0-cp310-cp310-win32.whl", hash = "sha256:7f2f3efade4937fae4e77efae1af571902263de7b78a0aee1a1653795a093b2a", size = 155045, upload-time = "2025-10-19T22:28:32.732Z" }, + { url = "https://files.pythonhosted.org/packages/5e/8a/d9e33f4eb4d4f6d9f2c5c7d7e96b5cdbb535c93f3b1ad6acce97ee9d4bf8/fastuuid-0.14.0-cp310-cp310-win_amd64.whl", hash = "sha256:ae64ba730d179f439b0736208b4c279b8bc9c089b102aec23f86512ea458c8a4", size = 156122, upload-time = "2025-10-19T22:23:15.59Z" }, + { url = "https://files.pythonhosted.org/packages/98/f3/12481bda4e5b6d3e698fbf525df4443cc7dce746f246b86b6fcb2fba1844/fastuuid-0.14.0-cp311-cp311-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:73946cb950c8caf65127d4e9a325e2b6be0442a224fd51ba3b6ac44e1912ce34", size = 516386, upload-time = "2025-10-19T22:42:40.176Z" }, + { url = "https://files.pythonhosted.org/packages/59/19/2fc58a1446e4d72b655648eb0879b04e88ed6fa70d474efcf550f640f6ec/fastuuid-0.14.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:12ac85024637586a5b69645e7ed986f7535106ed3013640a393a03e461740cb7", size = 264569, upload-time = "2025-10-19T22:25:50.977Z" }, + { url = "https://files.pythonhosted.org/packages/78/29/3c74756e5b02c40cfcc8b1d8b5bac4edbd532b55917a6bcc9113550e99d1/fastuuid-0.14.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:05a8dde1f395e0c9b4be515b7a521403d1e8349443e7641761af07c7ad1624b1", size = 254366, upload-time = "2025-10-19T22:29:49.166Z" }, + { url = "https://files.pythonhosted.org/packages/52/96/d761da3fccfa84f0f353ce6e3eb8b7f76b3aa21fd25e1b00a19f9c80a063/fastuuid-0.14.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09378a05020e3e4883dfdab438926f31fea15fd17604908f3d39cbeb22a0b4dc", size = 278978, upload-time = "2025-10-19T22:35:41.306Z" }, + { url = "https://files.pythonhosted.org/packages/fc/c2/f84c90167cc7765cb82b3ff7808057608b21c14a38531845d933a4637307/fastuuid-0.14.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbb0c4b15d66b435d2538f3827f05e44e2baafcc003dd7d8472dc67807ab8fd8", size = 279692, upload-time = "2025-10-19T22:25:36.997Z" }, + { url = "https://files.pythonhosted.org/packages/af/7b/4bacd03897b88c12348e7bd77943bac32ccf80ff98100598fcff74f75f2e/fastuuid-0.14.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cd5a7f648d4365b41dbf0e38fe8da4884e57bed4e77c83598e076ac0c93995e7", size = 303384, upload-time = "2025-10-19T22:29:46.578Z" }, + { url = "https://files.pythonhosted.org/packages/c0/a2/584f2c29641df8bd810d00c1f21d408c12e9ad0c0dafdb8b7b29e5ddf787/fastuuid-0.14.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c0a94245afae4d7af8c43b3159d5e3934c53f47140be0be624b96acd672ceb73", size = 460921, upload-time = "2025-10-19T22:36:42.006Z" }, + { url = "https://files.pythonhosted.org/packages/24/68/c6b77443bb7764c760e211002c8638c0c7cce11cb584927e723215ba1398/fastuuid-0.14.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:2b29e23c97e77c3a9514d70ce343571e469098ac7f5a269320a0f0b3e193ab36", size = 480575, upload-time = "2025-10-19T22:28:18.975Z" }, + { url = "https://files.pythonhosted.org/packages/5a/87/93f553111b33f9bb83145be12868c3c475bf8ea87c107063d01377cc0e8e/fastuuid-0.14.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1e690d48f923c253f28151b3a6b4e335f2b06bf669c68a02665bc150b7839e94", size = 452317, upload-time = "2025-10-19T22:25:32.75Z" }, + { url = "https://files.pythonhosted.org/packages/9e/8c/a04d486ca55b5abb7eaa65b39df8d891b7b1635b22db2163734dc273579a/fastuuid-0.14.0-cp311-cp311-win32.whl", hash = "sha256:a6f46790d59ab38c6aa0e35c681c0484b50dc0acf9e2679c005d61e019313c24", size = 154804, upload-time = "2025-10-19T22:24:15.615Z" }, + { url = "https://files.pythonhosted.org/packages/9c/b2/2d40bf00820de94b9280366a122cbaa60090c8cf59e89ac3938cf5d75895/fastuuid-0.14.0-cp311-cp311-win_amd64.whl", hash = "sha256:e150eab56c95dc9e3fefc234a0eedb342fac433dacc273cd4d150a5b0871e1fa", size = 156099, upload-time = "2025-10-19T22:24:31.646Z" }, + { url = "https://files.pythonhosted.org/packages/02/a2/e78fcc5df65467f0d207661b7ef86c5b7ac62eea337c0c0fcedbeee6fb13/fastuuid-0.14.0-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:77e94728324b63660ebf8adb27055e92d2e4611645bf12ed9d88d30486471d0a", size = 510164, upload-time = "2025-10-19T22:31:45.635Z" }, + { url = "https://files.pythonhosted.org/packages/2b/b3/c846f933f22f581f558ee63f81f29fa924acd971ce903dab1a9b6701816e/fastuuid-0.14.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:caa1f14d2102cb8d353096bc6ef6c13b2c81f347e6ab9d6fbd48b9dea41c153d", size = 261837, upload-time = "2025-10-19T22:38:38.53Z" }, + { url = "https://files.pythonhosted.org/packages/54/ea/682551030f8c4fa9a769d9825570ad28c0c71e30cf34020b85c1f7ee7382/fastuuid-0.14.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d23ef06f9e67163be38cece704170486715b177f6baae338110983f99a72c070", size = 251370, upload-time = "2025-10-19T22:40:26.07Z" }, + { url = "https://files.pythonhosted.org/packages/14/dd/5927f0a523d8e6a76b70968e6004966ee7df30322f5fc9b6cdfb0276646a/fastuuid-0.14.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0c9ec605ace243b6dbe3bd27ebdd5d33b00d8d1d3f580b39fdd15cd96fd71796", size = 277766, upload-time = "2025-10-19T22:37:23.779Z" }, + { url = "https://files.pythonhosted.org/packages/16/6e/c0fb547eef61293153348f12e0f75a06abb322664b34a1573a7760501336/fastuuid-0.14.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:808527f2407f58a76c916d6aa15d58692a4a019fdf8d4c32ac7ff303b7d7af09", size = 278105, upload-time = "2025-10-19T22:26:56.821Z" }, + { url = "https://files.pythonhosted.org/packages/2d/b1/b9c75e03b768f61cf2e84ee193dc18601aeaf89a4684b20f2f0e9f52b62c/fastuuid-0.14.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2fb3c0d7fef6674bbeacdd6dbd386924a7b60b26de849266d1ff6602937675c8", size = 301564, upload-time = "2025-10-19T22:30:31.604Z" }, + { url = "https://files.pythonhosted.org/packages/fc/fa/f7395fdac07c7a54f18f801744573707321ca0cee082e638e36452355a9d/fastuuid-0.14.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab3f5d36e4393e628a4df337c2c039069344db5f4b9d2a3c9cea48284f1dd741", size = 459659, upload-time = "2025-10-19T22:31:32.341Z" }, + { url = "https://files.pythonhosted.org/packages/66/49/c9fd06a4a0b1f0f048aacb6599e7d96e5d6bc6fa680ed0d46bf111929d1b/fastuuid-0.14.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:b9a0ca4f03b7e0b01425281ffd44e99d360e15c895f1907ca105854ed85e2057", size = 478430, upload-time = "2025-10-19T22:26:22.962Z" }, + { url = "https://files.pythonhosted.org/packages/be/9c/909e8c95b494e8e140e8be6165d5fc3f61fdc46198c1554df7b3e1764471/fastuuid-0.14.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3acdf655684cc09e60fb7e4cf524e8f42ea760031945aa8086c7eae2eeeabeb8", size = 450894, upload-time = "2025-10-19T22:27:01.647Z" }, + { url = "https://files.pythonhosted.org/packages/90/eb/d29d17521976e673c55ef7f210d4cdd72091a9ec6755d0fd4710d9b3c871/fastuuid-0.14.0-cp312-cp312-win32.whl", hash = "sha256:9579618be6280700ae36ac42c3efd157049fe4dd40ca49b021280481c78c3176", size = 154374, upload-time = "2025-10-19T22:29:19.879Z" }, + { url = "https://files.pythonhosted.org/packages/cc/fc/f5c799a6ea6d877faec0472d0b27c079b47c86b1cdc577720a5386483b36/fastuuid-0.14.0-cp312-cp312-win_amd64.whl", hash = "sha256:d9e4332dc4ba054434a9594cbfaf7823b57993d7d8e7267831c3e059857cf397", size = 156550, upload-time = "2025-10-19T22:27:49.658Z" }, + { url = "https://files.pythonhosted.org/packages/a5/83/ae12dd39b9a39b55d7f90abb8971f1a5f3c321fd72d5aa83f90dc67fe9ed/fastuuid-0.14.0-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:77a09cb7427e7af74c594e409f7731a0cf887221de2f698e1ca0ebf0f3139021", size = 510720, upload-time = "2025-10-19T22:42:34.633Z" }, + { url = "https://files.pythonhosted.org/packages/53/b0/a4b03ff5d00f563cc7546b933c28cb3f2a07344b2aec5834e874f7d44143/fastuuid-0.14.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:9bd57289daf7b153bfa3e8013446aa144ce5e8c825e9e366d455155ede5ea2dc", size = 262024, upload-time = "2025-10-19T22:30:25.482Z" }, + { url = "https://files.pythonhosted.org/packages/9c/6d/64aee0a0f6a58eeabadd582e55d0d7d70258ffdd01d093b30c53d668303b/fastuuid-0.14.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ac60fc860cdf3c3f327374db87ab8e064c86566ca8c49d2e30df15eda1b0c2d5", size = 251679, upload-time = "2025-10-19T22:36:14.096Z" }, + { url = "https://files.pythonhosted.org/packages/60/f5/a7e9cda8369e4f7919d36552db9b2ae21db7915083bc6336f1b0082c8b2e/fastuuid-0.14.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ab32f74bd56565b186f036e33129da77db8be09178cd2f5206a5d4035fb2a23f", size = 277862, upload-time = "2025-10-19T22:36:23.302Z" }, + { url = "https://files.pythonhosted.org/packages/f0/d3/8ce11827c783affffd5bd4d6378b28eb6cc6d2ddf41474006b8d62e7448e/fastuuid-0.14.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33e678459cf4addaedd9936bbb038e35b3f6b2061330fd8f2f6a1d80414c0f87", size = 278278, upload-time = "2025-10-19T22:29:43.809Z" }, + { url = "https://files.pythonhosted.org/packages/a2/51/680fb6352d0bbade04036da46264a8001f74b7484e2fd1f4da9e3db1c666/fastuuid-0.14.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1e3cc56742f76cd25ecb98e4b82a25f978ccffba02e4bdce8aba857b6d85d87b", size = 301788, upload-time = "2025-10-19T22:36:06.825Z" }, + { url = "https://files.pythonhosted.org/packages/fa/7c/2014b5785bd8ebdab04ec857635ebd84d5ee4950186a577db9eff0fb8ff6/fastuuid-0.14.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:cb9a030f609194b679e1660f7e32733b7a0f332d519c5d5a6a0a580991290022", size = 459819, upload-time = "2025-10-19T22:35:31.623Z" }, + { url = "https://files.pythonhosted.org/packages/01/d2/524d4ceeba9160e7a9bc2ea3e8f4ccf1ad78f3bde34090ca0c51f09a5e91/fastuuid-0.14.0-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:09098762aad4f8da3a888eb9ae01c84430c907a297b97166b8abc07b640f2995", size = 478546, upload-time = "2025-10-19T22:26:03.023Z" }, + { url = "https://files.pythonhosted.org/packages/bc/17/354d04951ce114bf4afc78e27a18cfbd6ee319ab1829c2d5fb5e94063ac6/fastuuid-0.14.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:1383fff584fa249b16329a059c68ad45d030d5a4b70fb7c73a08d98fd53bcdab", size = 450921, upload-time = "2025-10-19T22:31:02.151Z" }, + { url = "https://files.pythonhosted.org/packages/fb/be/d7be8670151d16d88f15bb121c5b66cdb5ea6a0c2a362d0dcf30276ade53/fastuuid-0.14.0-cp313-cp313-win32.whl", hash = "sha256:a0809f8cc5731c066c909047f9a314d5f536c871a7a22e815cc4967c110ac9ad", size = 154559, upload-time = "2025-10-19T22:36:36.011Z" }, + { url = "https://files.pythonhosted.org/packages/22/1d/5573ef3624ceb7abf4a46073d3554e37191c868abc3aecd5289a72f9810a/fastuuid-0.14.0-cp313-cp313-win_amd64.whl", hash = "sha256:0df14e92e7ad3276327631c9e7cec09e32572ce82089c55cb1bb8df71cf394ed", size = 156539, upload-time = "2025-10-19T22:33:35.898Z" }, + { url = "https://files.pythonhosted.org/packages/16/c9/8c7660d1fe3862e3f8acabd9be7fc9ad71eb270f1c65cce9a2b7a31329ab/fastuuid-0.14.0-cp314-cp314-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:b852a870a61cfc26c884af205d502881a2e59cc07076b60ab4a951cc0c94d1ad", size = 510600, upload-time = "2025-10-19T22:43:44.17Z" }, + { url = "https://files.pythonhosted.org/packages/4c/f4/a989c82f9a90d0ad995aa957b3e572ebef163c5299823b4027986f133dfb/fastuuid-0.14.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:c7502d6f54cd08024c3ea9b3514e2d6f190feb2f46e6dbcd3747882264bb5f7b", size = 262069, upload-time = "2025-10-19T22:43:38.38Z" }, + { url = "https://files.pythonhosted.org/packages/da/6c/a1a24f73574ac995482b1326cf7ab41301af0fabaa3e37eeb6b3df00e6e2/fastuuid-0.14.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1ca61b592120cf314cfd66e662a5b54a578c5a15b26305e1b8b618a6f22df714", size = 251543, upload-time = "2025-10-19T22:32:22.537Z" }, + { url = "https://files.pythonhosted.org/packages/1a/20/2a9b59185ba7a6c7b37808431477c2d739fcbdabbf63e00243e37bd6bf49/fastuuid-0.14.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa75b6657ec129d0abded3bec745e6f7ab642e6dba3a5272a68247e85f5f316f", size = 277798, upload-time = "2025-10-19T22:33:53.821Z" }, + { url = "https://files.pythonhosted.org/packages/ef/33/4105ca574f6ded0af6a797d39add041bcfb468a1255fbbe82fcb6f592da2/fastuuid-0.14.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8a0dfea3972200f72d4c7df02c8ac70bad1bb4c58d7e0ec1e6f341679073a7f", size = 278283, upload-time = "2025-10-19T22:29:02.812Z" }, + { url = "https://files.pythonhosted.org/packages/fe/8c/fca59f8e21c4deb013f574eae05723737ddb1d2937ce87cb2a5d20992dc3/fastuuid-0.14.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1bf539a7a95f35b419f9ad105d5a8a35036df35fdafae48fb2fd2e5f318f0d75", size = 301627, upload-time = "2025-10-19T22:35:54.985Z" }, + { url = "https://files.pythonhosted.org/packages/cb/e2/f78c271b909c034d429218f2798ca4e89eeda7983f4257d7865976ddbb6c/fastuuid-0.14.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:9a133bf9cc78fdbd1179cb58a59ad0100aa32d8675508150f3658814aeefeaa4", size = 459778, upload-time = "2025-10-19T22:28:00.999Z" }, + { url = "https://files.pythonhosted.org/packages/1e/f0/5ff209d865897667a2ff3e7a572267a9ced8f7313919f6d6043aed8b1caa/fastuuid-0.14.0-cp314-cp314-musllinux_1_1_i686.whl", hash = "sha256:f54d5b36c56a2d5e1a31e73b950b28a0d83eb0c37b91d10408875a5a29494bad", size = 478605, upload-time = "2025-10-19T22:36:21.764Z" }, + { url = "https://files.pythonhosted.org/packages/e0/c8/2ce1c78f983a2c4987ea865d9516dbdfb141a120fd3abb977ae6f02ba7ca/fastuuid-0.14.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:ec27778c6ca3393ef662e2762dba8af13f4ec1aaa32d08d77f71f2a70ae9feb8", size = 450837, upload-time = "2025-10-19T22:34:37.178Z" }, + { url = "https://files.pythonhosted.org/packages/df/60/dad662ec9a33b4a5fe44f60699258da64172c39bd041da2994422cdc40fe/fastuuid-0.14.0-cp314-cp314-win32.whl", hash = "sha256:e23fc6a83f112de4be0cc1990e5b127c27663ae43f866353166f87df58e73d06", size = 154532, upload-time = "2025-10-19T22:35:18.217Z" }, + { url = "https://files.pythonhosted.org/packages/1f/f6/da4db31001e854025ffd26bc9ba0740a9cbba2c3259695f7c5834908b336/fastuuid-0.14.0-cp314-cp314-win_amd64.whl", hash = "sha256:df61342889d0f5e7a32f7284e55ef95103f2110fee433c2ae7c2c0956d76ac8a", size = 156457, upload-time = "2025-10-19T22:33:44.579Z" }, +] + [[package]] name = "filelock" version = "3.20.3" @@ -561,7 +953,9 @@ dependencies = [ { name = "aiosqlite" }, { name = "azure-identity" }, { name = "fastapi" }, + { name = "greenlet" }, { name = "httpx" }, + { name = "loguru" }, { name = "opentelemetry-api" }, { name = "opentelemetry-sdk" }, { name = "opentelemetry-semantic-conventions" }, @@ -579,11 +973,29 @@ dependencies = [ [package.optional-dependencies] all = [ { name = "beautifulsoup4" }, + { name = "cffi" }, + { name = "cryptography" }, + { name = "datasets" }, { name = "gepa" }, { name = "html2text" }, { name = "langchain-core" }, { name = "langchain-openai" }, { name = "langgraph" }, + { name = "litellm" }, + { name = "mammoth" }, + { name = "markdownify" }, + { name = "openpyxl" }, + { name = "pandas", version = "2.3.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "pandas", version = "3.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "pdfminer-six" }, + { name = "pillow" }, + { name = "puremagic" }, + { name = "pypdf" }, + { name = "python-pptx" }, + { name = "serpapi" }, + { name = "smolagents", extra = ["toolkit"] }, + { name = "wikipedia-api" }, + { name = "youtube-transcript-api" }, ] dev = [ { name = "mypy" }, @@ -595,6 +1007,9 @@ dev = [ { name = "pytest-cov" }, { name = "ruff" }, ] +hf-datasets = [ + { name = "datasets" }, +] langgraph = [ { name = "langchain-core" }, { name = "langchain-openai" }, @@ -602,11 +1017,30 @@ langgraph = [ ] optimizer = [ { name = "gepa" }, + { name = "litellm" }, ] research = [ { name = "beautifulsoup4" }, { name = "html2text" }, ] +smolagents = [ + { name = "cffi" }, + { name = "cryptography" }, + { name = "mammoth" }, + { name = "markdownify" }, + { name = "openpyxl" }, + { name = "pandas", version = "2.3.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "pandas", version = "3.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "pdfminer-six" }, + { name = "pillow" }, + { name = "puremagic" }, + { name = "pypdf" }, + { name = "python-pptx" }, + { name = "serpapi" }, + { name = "smolagents", extra = ["toolkit"] }, + { name = "wikipedia-api" }, + { name = "youtube-transcript-api" }, +] [package.metadata] requires-dist = [ @@ -614,36 +1048,190 @@ requires-dist = [ { name = "aiosqlite", specifier = ">=0.19.0" }, { name = "azure-identity", specifier = ">=1.15.0" }, { name = "beautifulsoup4", marker = "extra == 'research'", specifier = ">=4.12.0" }, + { name = "cffi", marker = "extra == 'smolagents'", specifier = ">=1.16.0" }, + { name = "cryptography", marker = "extra == 'smolagents'", specifier = ">=42.0.0" }, + { name = "datasets", marker = "extra == 'hf-datasets'", specifier = ">=2.0.0" }, { name = "fastapi", specifier = ">=0.109.0" }, - { name = "flow-agent", extras = ["research", "langgraph", "optimizer"], marker = "extra == 'all'" }, - { name = "gepa", marker = "extra == 'optimizer'", specifier = ">=0.0.20" }, + { name = "flow-agent", extras = ["research", "langgraph", "optimizer", "smolagents", "hf-datasets"], marker = "extra == 'all'" }, + { name = "gepa", marker = "extra == 'optimizer'", specifier = ">=0.0.27" }, + { name = "greenlet", specifier = ">=3.0.0" }, { name = "html2text", marker = "extra == 'research'", specifier = ">=2024.2.26" }, { name = "httpx", specifier = ">=0.25.0" }, { name = "langchain-core", marker = "extra == 'langgraph'", specifier = ">=0.3.0" }, { name = "langchain-openai", marker = "extra == 'langgraph'", specifier = ">=0.2.0" }, { name = "langgraph", marker = "extra == 'langgraph'", specifier = ">=0.2.0" }, + { name = "litellm", marker = "extra == 'optimizer'", specifier = ">=1.0.0" }, + { name = "loguru", specifier = ">=0.7.3" }, + { name = "mammoth", marker = "extra == 'smolagents'", specifier = ">=1.8.0" }, + { name = "markdownify", marker = "extra == 'smolagents'", specifier = ">=0.13.1" }, { name = "mypy", marker = "extra == 'dev'", specifier = ">=1.8.0" }, + { name = "openpyxl", marker = "extra == 'smolagents'", specifier = ">=3.1.0" }, { name = "opentelemetry-api", specifier = ">=1.20.0" }, { name = "opentelemetry-sdk", specifier = ">=1.20.0" }, { name = "opentelemetry-semantic-conventions", specifier = ">=0.41b0" }, + { name = "pandas", marker = "extra == 'smolagents'", specifier = ">=2.2.3" }, + { name = "pdfminer-six", marker = "extra == 'smolagents'", specifier = ">=20240706" }, + { name = "pillow", marker = "extra == 'smolagents'", specifier = ">=11.0.0" }, { name = "poethepoet", marker = "extra == 'dev'", specifier = ">=0.24.0" }, { name = "pre-commit", marker = "extra == 'dev'", specifier = ">=3.6.0" }, + { name = "puremagic", marker = "extra == 'smolagents'", specifier = ">=1.28" }, { name = "pydantic", specifier = ">=2.0.0" }, { name = "pydantic-settings", specifier = ">=2.0.0" }, + { name = "pypdf", marker = "extra == 'smolagents'", specifier = ">=5.1.0" }, { name = "pyright", marker = "extra == 'dev'", specifier = ">=1.1.350" }, { name = "pytest", marker = "extra == 'dev'", specifier = ">=8.0.0" }, { name = "pytest-asyncio", marker = "extra == 'dev'", specifier = ">=0.23.0" }, { name = "pytest-cov", marker = "extra == 'dev'", specifier = ">=4.1.0" }, { name = "python-dotenv", specifier = ">=1.0.0" }, + { name = "python-pptx", marker = "extra == 'smolagents'", specifier = ">=1.0.2" }, { name = "pyyaml", specifier = ">=6.0.0" }, { name = "rich", specifier = ">=13.0.0" }, { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.2.0" }, + { name = "serpapi", marker = "extra == 'smolagents'", specifier = ">=0.1.5" }, + { name = "smolagents", extras = ["toolkit"], marker = "extra == 'smolagents'", specifier = ">=1.24.0" }, { name = "sqlmodel", specifier = ">=0.0.14" }, { name = "tiktoken", specifier = ">=0.12.0" }, { name = "typer", specifier = ">=0.9.0" }, { name = "uvicorn", specifier = ">=0.27.0" }, + { name = "wikipedia-api", marker = "extra == 'smolagents'", specifier = ">=0.9.0" }, + { name = "youtube-transcript-api", marker = "extra == 'smolagents'", specifier = ">=0.6.2" }, +] +provides-extras = ["research", "langgraph", "smolagents", "optimizer", "hf-datasets", "all", "dev"] + +[[package]] +name = "frozenlist" +version = "1.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2d/f5/c831fac6cc817d26fd54c7eaccd04ef7e0288806943f7cc5bbf69f3ac1f0/frozenlist-1.8.0.tar.gz", hash = "sha256:3ede829ed8d842f6cd48fc7081d7a41001a56f1f38603f9d49bf3020d59a31ad", size = 45875, upload-time = "2025-10-06T05:38:17.865Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/83/4a/557715d5047da48d54e659203b9335be7bfaafda2c3f627b7c47e0b3aaf3/frozenlist-1.8.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b37f6d31b3dcea7deb5e9696e529a6aa4a898adc33db82da12e4c60a7c4d2011", size = 86230, upload-time = "2025-10-06T05:35:23.699Z" }, + { url = "https://files.pythonhosted.org/packages/a2/fb/c85f9fed3ea8fe8740e5b46a59cc141c23b842eca617da8876cfce5f760e/frozenlist-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ef2b7b394f208233e471abc541cc6991f907ffd47dc72584acee3147899d6565", size = 49621, upload-time = "2025-10-06T05:35:25.341Z" }, + { url = "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a88f062f072d1589b7b46e951698950e7da00442fc1cacbe17e19e025dc327ad", size = 49889, upload-time = "2025-10-06T05:35:26.797Z" }, + { url = "https://files.pythonhosted.org/packages/5d/ed/c7895fd2fde7f3ee70d248175f9b6cdf792fb741ab92dc59cd9ef3bd241b/frozenlist-1.8.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f57fb59d9f385710aa7060e89410aeb5058b99e62f4d16b08b91986b9a2140c2", size = 219464, upload-time = "2025-10-06T05:35:28.254Z" }, + { url = "https://files.pythonhosted.org/packages/6b/83/4d587dccbfca74cb8b810472392ad62bfa100bf8108c7223eb4c4fa2f7b3/frozenlist-1.8.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:799345ab092bee59f01a915620b5d014698547afd011e691a208637312db9186", size = 221649, upload-time = "2025-10-06T05:35:29.454Z" }, + { url = "https://files.pythonhosted.org/packages/6a/c6/fd3b9cd046ec5fff9dab66831083bc2077006a874a2d3d9247dea93ddf7e/frozenlist-1.8.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c23c3ff005322a6e16f71bf8692fcf4d5a304aaafe1e262c98c6d4adc7be863e", size = 219188, upload-time = "2025-10-06T05:35:30.951Z" }, + { url = "https://files.pythonhosted.org/packages/ce/80/6693f55eb2e085fc8afb28cf611448fb5b90e98e068fa1d1b8d8e66e5c7d/frozenlist-1.8.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8a76ea0f0b9dfa06f254ee06053d93a600865b3274358ca48a352ce4f0798450", size = 231748, upload-time = "2025-10-06T05:35:32.101Z" }, + { url = "https://files.pythonhosted.org/packages/97/d6/e9459f7c5183854abd989ba384fe0cc1a0fb795a83c033f0571ec5933ca4/frozenlist-1.8.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c7366fe1418a6133d5aa824ee53d406550110984de7637d65a178010f759c6ef", size = 236351, upload-time = "2025-10-06T05:35:33.834Z" }, + { url = "https://files.pythonhosted.org/packages/97/92/24e97474b65c0262e9ecd076e826bfd1d3074adcc165a256e42e7b8a7249/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:13d23a45c4cebade99340c4165bd90eeb4a56c6d8a9d8aa49568cac19a6d0dc4", size = 218767, upload-time = "2025-10-06T05:35:35.205Z" }, + { url = "https://files.pythonhosted.org/packages/ee/bf/dc394a097508f15abff383c5108cb8ad880d1f64a725ed3b90d5c2fbf0bb/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:e4a3408834f65da56c83528fb52ce7911484f0d1eaf7b761fc66001db1646eff", size = 235887, upload-time = "2025-10-06T05:35:36.354Z" }, + { url = "https://files.pythonhosted.org/packages/40/90/25b201b9c015dbc999a5baf475a257010471a1fa8c200c843fd4abbee725/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:42145cd2748ca39f32801dad54aeea10039da6f86e303659db90db1c4b614c8c", size = 228785, upload-time = "2025-10-06T05:35:37.949Z" }, + { url = "https://files.pythonhosted.org/packages/84/f4/b5bc148df03082f05d2dd30c089e269acdbe251ac9a9cf4e727b2dbb8a3d/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e2de870d16a7a53901e41b64ffdf26f2fbb8917b3e6ebf398098d72c5b20bd7f", size = 230312, upload-time = "2025-10-06T05:35:39.178Z" }, + { url = "https://files.pythonhosted.org/packages/db/4b/87e95b5d15097c302430e647136b7d7ab2398a702390cf4c8601975709e7/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:20e63c9493d33ee48536600d1a5c95eefc870cd71e7ab037763d1fbb89cc51e7", size = 217650, upload-time = "2025-10-06T05:35:40.377Z" }, + { url = "https://files.pythonhosted.org/packages/e5/70/78a0315d1fea97120591a83e0acd644da638c872f142fd72a6cebee825f3/frozenlist-1.8.0-cp310-cp310-win32.whl", hash = "sha256:adbeebaebae3526afc3c96fad434367cafbfd1b25d72369a9e5858453b1bb71a", size = 39659, upload-time = "2025-10-06T05:35:41.863Z" }, + { url = "https://files.pythonhosted.org/packages/66/aa/3f04523fb189a00e147e60c5b2205126118f216b0aa908035c45336e27e4/frozenlist-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:667c3777ca571e5dbeb76f331562ff98b957431df140b54c85fd4d52eea8d8f6", size = 43837, upload-time = "2025-10-06T05:35:43.205Z" }, + { url = "https://files.pythonhosted.org/packages/39/75/1135feecdd7c336938bd55b4dc3b0dfc46d85b9be12ef2628574b28de776/frozenlist-1.8.0-cp310-cp310-win_arm64.whl", hash = "sha256:80f85f0a7cc86e7a54c46d99c9e1318ff01f4687c172ede30fd52d19d1da1c8e", size = 39989, upload-time = "2025-10-06T05:35:44.596Z" }, + { url = "https://files.pythonhosted.org/packages/bc/03/077f869d540370db12165c0aa51640a873fb661d8b315d1d4d67b284d7ac/frozenlist-1.8.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:09474e9831bc2b2199fad6da3c14c7b0fbdd377cce9d3d77131be28906cb7d84", size = 86912, upload-time = "2025-10-06T05:35:45.98Z" }, + { url = "https://files.pythonhosted.org/packages/df/b5/7610b6bd13e4ae77b96ba85abea1c8cb249683217ef09ac9e0ae93f25a91/frozenlist-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:17c883ab0ab67200b5f964d2b9ed6b00971917d5d8a92df149dc2c9779208ee9", size = 50046, upload-time = "2025-10-06T05:35:47.009Z" }, + { url = "https://files.pythonhosted.org/packages/6e/ef/0e8f1fe32f8a53dd26bdd1f9347efe0778b0fddf62789ea683f4cc7d787d/frozenlist-1.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fa47e444b8ba08fffd1c18e8cdb9a75db1b6a27f17507522834ad13ed5922b93", size = 50119, upload-time = "2025-10-06T05:35:48.38Z" }, + { url = "https://files.pythonhosted.org/packages/11/b1/71a477adc7c36e5fb628245dfbdea2166feae310757dea848d02bd0689fd/frozenlist-1.8.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2552f44204b744fba866e573be4c1f9048d6a324dfe14475103fd51613eb1d1f", size = 231067, upload-time = "2025-10-06T05:35:49.97Z" }, + { url = "https://files.pythonhosted.org/packages/45/7e/afe40eca3a2dc19b9904c0f5d7edfe82b5304cb831391edec0ac04af94c2/frozenlist-1.8.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:957e7c38f250991e48a9a73e6423db1bb9dd14e722a10f6b8bb8e16a0f55f695", size = 233160, upload-time = "2025-10-06T05:35:51.729Z" }, + { url = "https://files.pythonhosted.org/packages/a6/aa/7416eac95603ce428679d273255ffc7c998d4132cfae200103f164b108aa/frozenlist-1.8.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8585e3bb2cdea02fc88ffa245069c36555557ad3609e83be0ec71f54fd4abb52", size = 228544, upload-time = "2025-10-06T05:35:53.246Z" }, + { url = "https://files.pythonhosted.org/packages/8b/3d/2a2d1f683d55ac7e3875e4263d28410063e738384d3adc294f5ff3d7105e/frozenlist-1.8.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:edee74874ce20a373d62dc28b0b18b93f645633c2943fd90ee9d898550770581", size = 243797, upload-time = "2025-10-06T05:35:54.497Z" }, + { url = "https://files.pythonhosted.org/packages/78/1e/2d5565b589e580c296d3bb54da08d206e797d941a83a6fdea42af23be79c/frozenlist-1.8.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c9a63152fe95756b85f31186bddf42e4c02c6321207fd6601a1c89ebac4fe567", size = 247923, upload-time = "2025-10-06T05:35:55.861Z" }, + { url = "https://files.pythonhosted.org/packages/aa/c3/65872fcf1d326a7f101ad4d86285c403c87be7d832b7470b77f6d2ed5ddc/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b6db2185db9be0a04fecf2f241c70b63b1a242e2805be291855078f2b404dd6b", size = 230886, upload-time = "2025-10-06T05:35:57.399Z" }, + { url = "https://files.pythonhosted.org/packages/a0/76/ac9ced601d62f6956f03cc794f9e04c81719509f85255abf96e2510f4265/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:f4be2e3d8bc8aabd566f8d5b8ba7ecc09249d74ba3c9ed52e54dc23a293f0b92", size = 245731, upload-time = "2025-10-06T05:35:58.563Z" }, + { url = "https://files.pythonhosted.org/packages/b9/49/ecccb5f2598daf0b4a1415497eba4c33c1e8ce07495eb07d2860c731b8d5/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c8d1634419f39ea6f5c427ea2f90ca85126b54b50837f31497f3bf38266e853d", size = 241544, upload-time = "2025-10-06T05:35:59.719Z" }, + { url = "https://files.pythonhosted.org/packages/53/4b/ddf24113323c0bbcc54cb38c8b8916f1da7165e07b8e24a717b4a12cbf10/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:1a7fa382a4a223773ed64242dbe1c9c326ec09457e6b8428efb4118c685c3dfd", size = 241806, upload-time = "2025-10-06T05:36:00.959Z" }, + { url = "https://files.pythonhosted.org/packages/a7/fb/9b9a084d73c67175484ba2789a59f8eebebd0827d186a8102005ce41e1ba/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:11847b53d722050808926e785df837353bd4d75f1d494377e59b23594d834967", size = 229382, upload-time = "2025-10-06T05:36:02.22Z" }, + { url = "https://files.pythonhosted.org/packages/95/a3/c8fb25aac55bf5e12dae5c5aa6a98f85d436c1dc658f21c3ac73f9fa95e5/frozenlist-1.8.0-cp311-cp311-win32.whl", hash = "sha256:27c6e8077956cf73eadd514be8fb04d77fc946a7fe9f7fe167648b0b9085cc25", size = 39647, upload-time = "2025-10-06T05:36:03.409Z" }, + { url = "https://files.pythonhosted.org/packages/0a/f5/603d0d6a02cfd4c8f2a095a54672b3cf967ad688a60fb9faf04fc4887f65/frozenlist-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:ac913f8403b36a2c8610bbfd25b8013488533e71e62b4b4adce9c86c8cea905b", size = 44064, upload-time = "2025-10-06T05:36:04.368Z" }, + { url = "https://files.pythonhosted.org/packages/5d/16/c2c9ab44e181f043a86f9a8f84d5124b62dbcb3a02c0977ec72b9ac1d3e0/frozenlist-1.8.0-cp311-cp311-win_arm64.whl", hash = "sha256:d4d3214a0f8394edfa3e303136d0575eece0745ff2b47bd2cb2e66dd92d4351a", size = 39937, upload-time = "2025-10-06T05:36:05.669Z" }, + { url = "https://files.pythonhosted.org/packages/69/29/948b9aa87e75820a38650af445d2ef2b6b8a6fab1a23b6bb9e4ef0be2d59/frozenlist-1.8.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:78f7b9e5d6f2fdb88cdde9440dc147259b62b9d3b019924def9f6478be254ac1", size = 87782, upload-time = "2025-10-06T05:36:06.649Z" }, + { url = "https://files.pythonhosted.org/packages/64/80/4f6e318ee2a7c0750ed724fa33a4bdf1eacdc5a39a7a24e818a773cd91af/frozenlist-1.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:229bf37d2e4acdaf808fd3f06e854a4a7a3661e871b10dc1f8f1896a3b05f18b", size = 50594, upload-time = "2025-10-06T05:36:07.69Z" }, + { url = "https://files.pythonhosted.org/packages/2b/94/5c8a2b50a496b11dd519f4a24cb5496cf125681dd99e94c604ccdea9419a/frozenlist-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f833670942247a14eafbb675458b4e61c82e002a148f49e68257b79296e865c4", size = 50448, upload-time = "2025-10-06T05:36:08.78Z" }, + { url = "https://files.pythonhosted.org/packages/6a/bd/d91c5e39f490a49df14320f4e8c80161cfcce09f1e2cde1edd16a551abb3/frozenlist-1.8.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:494a5952b1c597ba44e0e78113a7266e656b9794eec897b19ead706bd7074383", size = 242411, upload-time = "2025-10-06T05:36:09.801Z" }, + { url = "https://files.pythonhosted.org/packages/8f/83/f61505a05109ef3293dfb1ff594d13d64a2324ac3482be2cedc2be818256/frozenlist-1.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96f423a119f4777a4a056b66ce11527366a8bb92f54e541ade21f2374433f6d4", size = 243014, upload-time = "2025-10-06T05:36:11.394Z" }, + { url = "https://files.pythonhosted.org/packages/d8/cb/cb6c7b0f7d4023ddda30cf56b8b17494eb3a79e3fda666bf735f63118b35/frozenlist-1.8.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3462dd9475af2025c31cc61be6652dfa25cbfb56cbbf52f4ccfe029f38decaf8", size = 234909, upload-time = "2025-10-06T05:36:12.598Z" }, + { url = "https://files.pythonhosted.org/packages/31/c5/cd7a1f3b8b34af009fb17d4123c5a778b44ae2804e3ad6b86204255f9ec5/frozenlist-1.8.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4c800524c9cd9bac5166cd6f55285957fcfc907db323e193f2afcd4d9abd69b", size = 250049, upload-time = "2025-10-06T05:36:14.065Z" }, + { url = "https://files.pythonhosted.org/packages/c0/01/2f95d3b416c584a1e7f0e1d6d31998c4a795f7544069ee2e0962a4b60740/frozenlist-1.8.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d6a5df73acd3399d893dafc71663ad22534b5aa4f94e8a2fabfe856c3c1b6a52", size = 256485, upload-time = "2025-10-06T05:36:15.39Z" }, + { url = "https://files.pythonhosted.org/packages/ce/03/024bf7720b3abaebcff6d0793d73c154237b85bdf67b7ed55e5e9596dc9a/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:405e8fe955c2280ce66428b3ca55e12b3c4e9c336fb2103a4937e891c69a4a29", size = 237619, upload-time = "2025-10-06T05:36:16.558Z" }, + { url = "https://files.pythonhosted.org/packages/69/fa/f8abdfe7d76b731f5d8bd217827cf6764d4f1d9763407e42717b4bed50a0/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:908bd3f6439f2fef9e85031b59fd4f1297af54415fb60e4254a95f75b3cab3f3", size = 250320, upload-time = "2025-10-06T05:36:17.821Z" }, + { url = "https://files.pythonhosted.org/packages/f5/3c/b051329f718b463b22613e269ad72138cc256c540f78a6de89452803a47d/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:294e487f9ec720bd8ffcebc99d575f7eff3568a08a253d1ee1a0378754b74143", size = 246820, upload-time = "2025-10-06T05:36:19.046Z" }, + { url = "https://files.pythonhosted.org/packages/0f/ae/58282e8f98e444b3f4dd42448ff36fa38bef29e40d40f330b22e7108f565/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:74c51543498289c0c43656701be6b077f4b265868fa7f8a8859c197006efb608", size = 250518, upload-time = "2025-10-06T05:36:20.763Z" }, + { url = "https://files.pythonhosted.org/packages/8f/96/007e5944694d66123183845a106547a15944fbbb7154788cbf7272789536/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:776f352e8329135506a1d6bf16ac3f87bc25b28e765949282dcc627af36123aa", size = 239096, upload-time = "2025-10-06T05:36:22.129Z" }, + { url = "https://files.pythonhosted.org/packages/66/bb/852b9d6db2fa40be96f29c0d1205c306288f0684df8fd26ca1951d461a56/frozenlist-1.8.0-cp312-cp312-win32.whl", hash = "sha256:433403ae80709741ce34038da08511d4a77062aa924baf411ef73d1146e74faf", size = 39985, upload-time = "2025-10-06T05:36:23.661Z" }, + { url = "https://files.pythonhosted.org/packages/b8/af/38e51a553dd66eb064cdf193841f16f077585d4d28394c2fa6235cb41765/frozenlist-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:34187385b08f866104f0c0617404c8eb08165ab1272e884abc89c112e9c00746", size = 44591, upload-time = "2025-10-06T05:36:24.958Z" }, + { url = "https://files.pythonhosted.org/packages/a7/06/1dc65480ab147339fecc70797e9c2f69d9cea9cf38934ce08df070fdb9cb/frozenlist-1.8.0-cp312-cp312-win_arm64.whl", hash = "sha256:fe3c58d2f5db5fbd18c2987cba06d51b0529f52bc3a6cdc33d3f4eab725104bd", size = 40102, upload-time = "2025-10-06T05:36:26.333Z" }, + { url = "https://files.pythonhosted.org/packages/2d/40/0832c31a37d60f60ed79e9dfb5a92e1e2af4f40a16a29abcc7992af9edff/frozenlist-1.8.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8d92f1a84bb12d9e56f818b3a746f3efba93c1b63c8387a73dde655e1e42282a", size = 85717, upload-time = "2025-10-06T05:36:27.341Z" }, + { url = "https://files.pythonhosted.org/packages/30/ba/b0b3de23f40bc55a7057bd38434e25c34fa48e17f20ee273bbde5e0650f3/frozenlist-1.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:96153e77a591c8adc2ee805756c61f59fef4cf4073a9275ee86fe8cba41241f7", size = 49651, upload-time = "2025-10-06T05:36:28.855Z" }, + { url = "https://files.pythonhosted.org/packages/0c/ab/6e5080ee374f875296c4243c381bbdef97a9ac39c6e3ce1d5f7d42cb78d6/frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f21f00a91358803399890ab167098c131ec2ddd5f8f5fd5fe9c9f2c6fcd91e40", size = 49417, upload-time = "2025-10-06T05:36:29.877Z" }, + { url = "https://files.pythonhosted.org/packages/d5/4e/e4691508f9477ce67da2015d8c00acd751e6287739123113a9fca6f1604e/frozenlist-1.8.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fb30f9626572a76dfe4293c7194a09fb1fe93ba94c7d4f720dfae3b646b45027", size = 234391, upload-time = "2025-10-06T05:36:31.301Z" }, + { url = "https://files.pythonhosted.org/packages/40/76/c202df58e3acdf12969a7895fd6f3bc016c642e6726aa63bd3025e0fc71c/frozenlist-1.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eaa352d7047a31d87dafcacbabe89df0aa506abb5b1b85a2fb91bc3faa02d822", size = 233048, upload-time = "2025-10-06T05:36:32.531Z" }, + { url = "https://files.pythonhosted.org/packages/f9/c0/8746afb90f17b73ca5979c7a3958116e105ff796e718575175319b5bb4ce/frozenlist-1.8.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:03ae967b4e297f58f8c774c7eabcce57fe3c2434817d4385c50661845a058121", size = 226549, upload-time = "2025-10-06T05:36:33.706Z" }, + { url = "https://files.pythonhosted.org/packages/7e/eb/4c7eefc718ff72f9b6c4893291abaae5fbc0c82226a32dcd8ef4f7a5dbef/frozenlist-1.8.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f6292f1de555ffcc675941d65fffffb0a5bcd992905015f85d0592201793e0e5", size = 239833, upload-time = "2025-10-06T05:36:34.947Z" }, + { url = "https://files.pythonhosted.org/packages/c2/4e/e5c02187cf704224f8b21bee886f3d713ca379535f16893233b9d672ea71/frozenlist-1.8.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29548f9b5b5e3460ce7378144c3010363d8035cea44bc0bf02d57f5a685e084e", size = 245363, upload-time = "2025-10-06T05:36:36.534Z" }, + { url = "https://files.pythonhosted.org/packages/1f/96/cb85ec608464472e82ad37a17f844889c36100eed57bea094518bf270692/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ec3cc8c5d4084591b4237c0a272cc4f50a5b03396a47d9caaf76f5d7b38a4f11", size = 229314, upload-time = "2025-10-06T05:36:38.582Z" }, + { url = "https://files.pythonhosted.org/packages/5d/6f/4ae69c550e4cee66b57887daeebe006fe985917c01d0fff9caab9883f6d0/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:517279f58009d0b1f2e7c1b130b377a349405da3f7621ed6bfae50b10adf20c1", size = 243365, upload-time = "2025-10-06T05:36:40.152Z" }, + { url = "https://files.pythonhosted.org/packages/7a/58/afd56de246cf11780a40a2c28dc7cbabbf06337cc8ddb1c780a2d97e88d8/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:db1e72ede2d0d7ccb213f218df6a078a9c09a7de257c2fe8fcef16d5925230b1", size = 237763, upload-time = "2025-10-06T05:36:41.355Z" }, + { url = "https://files.pythonhosted.org/packages/cb/36/cdfaf6ed42e2644740d4a10452d8e97fa1c062e2a8006e4b09f1b5fd7d63/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b4dec9482a65c54a5044486847b8a66bf10c9cb4926d42927ec4e8fd5db7fed8", size = 240110, upload-time = "2025-10-06T05:36:42.716Z" }, + { url = "https://files.pythonhosted.org/packages/03/a8/9ea226fbefad669f11b52e864c55f0bd57d3c8d7eb07e9f2e9a0b39502e1/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:21900c48ae04d13d416f0e1e0c4d81f7931f73a9dfa0b7a8746fb2fe7dd970ed", size = 233717, upload-time = "2025-10-06T05:36:44.251Z" }, + { url = "https://files.pythonhosted.org/packages/1e/0b/1b5531611e83ba7d13ccc9988967ea1b51186af64c42b7a7af465dcc9568/frozenlist-1.8.0-cp313-cp313-win32.whl", hash = "sha256:8b7b94a067d1c504ee0b16def57ad5738701e4ba10cec90529f13fa03c833496", size = 39628, upload-time = "2025-10-06T05:36:45.423Z" }, + { url = "https://files.pythonhosted.org/packages/d8/cf/174c91dbc9cc49bc7b7aab74d8b734e974d1faa8f191c74af9b7e80848e6/frozenlist-1.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:878be833caa6a3821caf85eb39c5ba92d28e85df26d57afb06b35b2efd937231", size = 43882, upload-time = "2025-10-06T05:36:46.796Z" }, + { url = "https://files.pythonhosted.org/packages/c1/17/502cd212cbfa96eb1388614fe39a3fc9ab87dbbe042b66f97acb57474834/frozenlist-1.8.0-cp313-cp313-win_arm64.whl", hash = "sha256:44389d135b3ff43ba8cc89ff7f51f5a0bb6b63d829c8300f79a2fe4fe61bcc62", size = 39676, upload-time = "2025-10-06T05:36:47.8Z" }, + { url = "https://files.pythonhosted.org/packages/d2/5c/3bbfaa920dfab09e76946a5d2833a7cbdf7b9b4a91c714666ac4855b88b4/frozenlist-1.8.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:e25ac20a2ef37e91c1b39938b591457666a0fa835c7783c3a8f33ea42870db94", size = 89235, upload-time = "2025-10-06T05:36:48.78Z" }, + { url = "https://files.pythonhosted.org/packages/d2/d6/f03961ef72166cec1687e84e8925838442b615bd0b8854b54923ce5b7b8a/frozenlist-1.8.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:07cdca25a91a4386d2e76ad992916a85038a9b97561bf7a3fd12d5d9ce31870c", size = 50742, upload-time = "2025-10-06T05:36:49.837Z" }, + { url = "https://files.pythonhosted.org/packages/1e/bb/a6d12b7ba4c3337667d0e421f7181c82dda448ce4e7ad7ecd249a16fa806/frozenlist-1.8.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4e0c11f2cc6717e0a741f84a527c52616140741cd812a50422f83dc31749fb52", size = 51725, upload-time = "2025-10-06T05:36:50.851Z" }, + { url = "https://files.pythonhosted.org/packages/bc/71/d1fed0ffe2c2ccd70b43714c6cab0f4188f09f8a67a7914a6b46ee30f274/frozenlist-1.8.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b3210649ee28062ea6099cfda39e147fa1bc039583c8ee4481cb7811e2448c51", size = 284533, upload-time = "2025-10-06T05:36:51.898Z" }, + { url = "https://files.pythonhosted.org/packages/c9/1f/fb1685a7b009d89f9bf78a42d94461bc06581f6e718c39344754a5d9bada/frozenlist-1.8.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:581ef5194c48035a7de2aefc72ac6539823bb71508189e5de01d60c9dcd5fa65", size = 292506, upload-time = "2025-10-06T05:36:53.101Z" }, + { url = "https://files.pythonhosted.org/packages/e6/3b/b991fe1612703f7e0d05c0cf734c1b77aaf7c7d321df4572e8d36e7048c8/frozenlist-1.8.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3ef2d026f16a2b1866e1d86fc4e1291e1ed8a387b2c333809419a2f8b3a77b82", size = 274161, upload-time = "2025-10-06T05:36:54.309Z" }, + { url = "https://files.pythonhosted.org/packages/ca/ec/c5c618767bcdf66e88945ec0157d7f6c4a1322f1473392319b7a2501ded7/frozenlist-1.8.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5500ef82073f599ac84d888e3a8c1f77ac831183244bfd7f11eaa0289fb30714", size = 294676, upload-time = "2025-10-06T05:36:55.566Z" }, + { url = "https://files.pythonhosted.org/packages/7c/ce/3934758637d8f8a88d11f0585d6495ef54b2044ed6ec84492a91fa3b27aa/frozenlist-1.8.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:50066c3997d0091c411a66e710f4e11752251e6d2d73d70d8d5d4c76442a199d", size = 300638, upload-time = "2025-10-06T05:36:56.758Z" }, + { url = "https://files.pythonhosted.org/packages/fc/4f/a7e4d0d467298f42de4b41cbc7ddaf19d3cfeabaf9ff97c20c6c7ee409f9/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:5c1c8e78426e59b3f8005e9b19f6ff46e5845895adbde20ece9218319eca6506", size = 283067, upload-time = "2025-10-06T05:36:57.965Z" }, + { url = "https://files.pythonhosted.org/packages/dc/48/c7b163063d55a83772b268e6d1affb960771b0e203b632cfe09522d67ea5/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:eefdba20de0d938cec6a89bd4d70f346a03108a19b9df4248d3cf0d88f1b0f51", size = 292101, upload-time = "2025-10-06T05:36:59.237Z" }, + { url = "https://files.pythonhosted.org/packages/9f/d0/2366d3c4ecdc2fd391e0afa6e11500bfba0ea772764d631bbf82f0136c9d/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:cf253e0e1c3ceb4aaff6df637ce033ff6535fb8c70a764a8f46aafd3d6ab798e", size = 289901, upload-time = "2025-10-06T05:37:00.811Z" }, + { url = "https://files.pythonhosted.org/packages/b8/94/daff920e82c1b70e3618a2ac39fbc01ae3e2ff6124e80739ce5d71c9b920/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:032efa2674356903cd0261c4317a561a6850f3ac864a63fc1583147fb05a79b0", size = 289395, upload-time = "2025-10-06T05:37:02.115Z" }, + { url = "https://files.pythonhosted.org/packages/e3/20/bba307ab4235a09fdcd3cc5508dbabd17c4634a1af4b96e0f69bfe551ebd/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6da155091429aeba16851ecb10a9104a108bcd32f6c1642867eadaee401c1c41", size = 283659, upload-time = "2025-10-06T05:37:03.711Z" }, + { url = "https://files.pythonhosted.org/packages/fd/00/04ca1c3a7a124b6de4f8a9a17cc2fcad138b4608e7a3fc5877804b8715d7/frozenlist-1.8.0-cp313-cp313t-win32.whl", hash = "sha256:0f96534f8bfebc1a394209427d0f8a63d343c9779cda6fc25e8e121b5fd8555b", size = 43492, upload-time = "2025-10-06T05:37:04.915Z" }, + { url = "https://files.pythonhosted.org/packages/59/5e/c69f733a86a94ab10f68e496dc6b7e8bc078ebb415281d5698313e3af3a1/frozenlist-1.8.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5d63a068f978fc69421fb0e6eb91a9603187527c86b7cd3f534a5b77a592b888", size = 48034, upload-time = "2025-10-06T05:37:06.343Z" }, + { url = "https://files.pythonhosted.org/packages/16/6c/be9d79775d8abe79b05fa6d23da99ad6e7763a1d080fbae7290b286093fd/frozenlist-1.8.0-cp313-cp313t-win_arm64.whl", hash = "sha256:bf0a7e10b077bf5fb9380ad3ae8ce20ef919a6ad93b4552896419ac7e1d8e042", size = 41749, upload-time = "2025-10-06T05:37:07.431Z" }, + { url = "https://files.pythonhosted.org/packages/f1/c8/85da824b7e7b9b6e7f7705b2ecaf9591ba6f79c1177f324c2735e41d36a2/frozenlist-1.8.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:cee686f1f4cadeb2136007ddedd0aaf928ab95216e7691c63e50a8ec066336d0", size = 86127, upload-time = "2025-10-06T05:37:08.438Z" }, + { url = "https://files.pythonhosted.org/packages/8e/e8/a1185e236ec66c20afd72399522f142c3724c785789255202d27ae992818/frozenlist-1.8.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:119fb2a1bd47307e899c2fac7f28e85b9a543864df47aa7ec9d3c1b4545f096f", size = 49698, upload-time = "2025-10-06T05:37:09.48Z" }, + { url = "https://files.pythonhosted.org/packages/a1/93/72b1736d68f03fda5fdf0f2180fb6caaae3894f1b854d006ac61ecc727ee/frozenlist-1.8.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4970ece02dbc8c3a92fcc5228e36a3e933a01a999f7094ff7c23fbd2beeaa67c", size = 49749, upload-time = "2025-10-06T05:37:10.569Z" }, + { url = "https://files.pythonhosted.org/packages/a7/b2/fabede9fafd976b991e9f1b9c8c873ed86f202889b864756f240ce6dd855/frozenlist-1.8.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:cba69cb73723c3f329622e34bdbf5ce1f80c21c290ff04256cff1cd3c2036ed2", size = 231298, upload-time = "2025-10-06T05:37:11.993Z" }, + { url = "https://files.pythonhosted.org/packages/3a/3b/d9b1e0b0eed36e70477ffb8360c49c85c8ca8ef9700a4e6711f39a6e8b45/frozenlist-1.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:778a11b15673f6f1df23d9586f83c4846c471a8af693a22e066508b77d201ec8", size = 232015, upload-time = "2025-10-06T05:37:13.194Z" }, + { url = "https://files.pythonhosted.org/packages/dc/94/be719d2766c1138148564a3960fc2c06eb688da592bdc25adcf856101be7/frozenlist-1.8.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0325024fe97f94c41c08872db482cf8ac4800d80e79222c6b0b7b162d5b13686", size = 225038, upload-time = "2025-10-06T05:37:14.577Z" }, + { url = "https://files.pythonhosted.org/packages/e4/09/6712b6c5465f083f52f50cf74167b92d4ea2f50e46a9eea0523d658454ae/frozenlist-1.8.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:97260ff46b207a82a7567b581ab4190bd4dfa09f4db8a8b49d1a958f6aa4940e", size = 240130, upload-time = "2025-10-06T05:37:15.781Z" }, + { url = "https://files.pythonhosted.org/packages/f8/d4/cd065cdcf21550b54f3ce6a22e143ac9e4836ca42a0de1022da8498eac89/frozenlist-1.8.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:54b2077180eb7f83dd52c40b2750d0a9f175e06a42e3213ce047219de902717a", size = 242845, upload-time = "2025-10-06T05:37:17.037Z" }, + { url = "https://files.pythonhosted.org/packages/62/c3/f57a5c8c70cd1ead3d5d5f776f89d33110b1addae0ab010ad774d9a44fb9/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2f05983daecab868a31e1da44462873306d3cbfd76d1f0b5b69c473d21dbb128", size = 229131, upload-time = "2025-10-06T05:37:18.221Z" }, + { url = "https://files.pythonhosted.org/packages/6c/52/232476fe9cb64f0742f3fde2b7d26c1dac18b6d62071c74d4ded55e0ef94/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:33f48f51a446114bc5d251fb2954ab0164d5be02ad3382abcbfe07e2531d650f", size = 240542, upload-time = "2025-10-06T05:37:19.771Z" }, + { url = "https://files.pythonhosted.org/packages/5f/85/07bf3f5d0fb5414aee5f47d33c6f5c77bfe49aac680bfece33d4fdf6a246/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:154e55ec0655291b5dd1b8731c637ecdb50975a2ae70c606d100750a540082f7", size = 237308, upload-time = "2025-10-06T05:37:20.969Z" }, + { url = "https://files.pythonhosted.org/packages/11/99/ae3a33d5befd41ac0ca2cc7fd3aa707c9c324de2e89db0e0f45db9a64c26/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:4314debad13beb564b708b4a496020e5306c7333fa9a3ab90374169a20ffab30", size = 238210, upload-time = "2025-10-06T05:37:22.252Z" }, + { url = "https://files.pythonhosted.org/packages/b2/60/b1d2da22f4970e7a155f0adde9b1435712ece01b3cd45ba63702aea33938/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:073f8bf8becba60aa931eb3bc420b217bb7d5b8f4750e6f8b3be7f3da85d38b7", size = 231972, upload-time = "2025-10-06T05:37:23.5Z" }, + { url = "https://files.pythonhosted.org/packages/3f/ab/945b2f32de889993b9c9133216c068b7fcf257d8595a0ac420ac8677cab0/frozenlist-1.8.0-cp314-cp314-win32.whl", hash = "sha256:bac9c42ba2ac65ddc115d930c78d24ab8d4f465fd3fc473cdedfccadb9429806", size = 40536, upload-time = "2025-10-06T05:37:25.581Z" }, + { url = "https://files.pythonhosted.org/packages/59/ad/9caa9b9c836d9ad6f067157a531ac48b7d36499f5036d4141ce78c230b1b/frozenlist-1.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:3e0761f4d1a44f1d1a47996511752cf3dcec5bbdd9cc2b4fe595caf97754b7a0", size = 44330, upload-time = "2025-10-06T05:37:26.928Z" }, + { url = "https://files.pythonhosted.org/packages/82/13/e6950121764f2676f43534c555249f57030150260aee9dcf7d64efda11dd/frozenlist-1.8.0-cp314-cp314-win_arm64.whl", hash = "sha256:d1eaff1d00c7751b7c6662e9c5ba6eb2c17a2306ba5e2a37f24ddf3cc953402b", size = 40627, upload-time = "2025-10-06T05:37:28.075Z" }, + { url = "https://files.pythonhosted.org/packages/c0/c7/43200656ecc4e02d3f8bc248df68256cd9572b3f0017f0a0c4e93440ae23/frozenlist-1.8.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:d3bb933317c52d7ea5004a1c442eef86f426886fba134ef8cf4226ea6ee1821d", size = 89238, upload-time = "2025-10-06T05:37:29.373Z" }, + { url = "https://files.pythonhosted.org/packages/d1/29/55c5f0689b9c0fb765055629f472c0de484dcaf0acee2f7707266ae3583c/frozenlist-1.8.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:8009897cdef112072f93a0efdce29cd819e717fd2f649ee3016efd3cd885a7ed", size = 50738, upload-time = "2025-10-06T05:37:30.792Z" }, + { url = "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2c5dcbbc55383e5883246d11fd179782a9d07a986c40f49abe89ddf865913930", size = 51739, upload-time = "2025-10-06T05:37:32.127Z" }, + { url = "https://files.pythonhosted.org/packages/62/1c/3d8622e60d0b767a5510d1d3cf21065b9db874696a51ea6d7a43180a259c/frozenlist-1.8.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:39ecbc32f1390387d2aa4f5a995e465e9e2f79ba3adcac92d68e3e0afae6657c", size = 284186, upload-time = "2025-10-06T05:37:33.21Z" }, + { url = "https://files.pythonhosted.org/packages/2d/14/aa36d5f85a89679a85a1d44cd7a6657e0b1c75f61e7cad987b203d2daca8/frozenlist-1.8.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92db2bf818d5cc8d9c1f1fc56b897662e24ea5adb36ad1f1d82875bd64e03c24", size = 292196, upload-time = "2025-10-06T05:37:36.107Z" }, + { url = "https://files.pythonhosted.org/packages/05/23/6bde59eb55abd407d34f77d39a5126fb7b4f109a3f611d3929f14b700c66/frozenlist-1.8.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2dc43a022e555de94c3b68a4ef0b11c4f747d12c024a520c7101709a2144fb37", size = 273830, upload-time = "2025-10-06T05:37:37.663Z" }, + { url = "https://files.pythonhosted.org/packages/d2/3f/22cff331bfad7a8afa616289000ba793347fcd7bc275f3b28ecea2a27909/frozenlist-1.8.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cb89a7f2de3602cfed448095bab3f178399646ab7c61454315089787df07733a", size = 294289, upload-time = "2025-10-06T05:37:39.261Z" }, + { url = "https://files.pythonhosted.org/packages/a4/89/5b057c799de4838b6c69aa82b79705f2027615e01be996d2486a69ca99c4/frozenlist-1.8.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:33139dc858c580ea50e7e60a1b0ea003efa1fd42e6ec7fdbad78fff65fad2fd2", size = 300318, upload-time = "2025-10-06T05:37:43.213Z" }, + { url = "https://files.pythonhosted.org/packages/30/de/2c22ab3eb2a8af6d69dc799e48455813bab3690c760de58e1bf43b36da3e/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:168c0969a329b416119507ba30b9ea13688fafffac1b7822802537569a1cb0ef", size = 282814, upload-time = "2025-10-06T05:37:45.337Z" }, + { url = "https://files.pythonhosted.org/packages/59/f7/970141a6a8dbd7f556d94977858cfb36fa9b66e0892c6dd780d2219d8cd8/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:28bd570e8e189d7f7b001966435f9dac6718324b5be2990ac496cf1ea9ddb7fe", size = 291762, upload-time = "2025-10-06T05:37:46.657Z" }, + { url = "https://files.pythonhosted.org/packages/c1/15/ca1adae83a719f82df9116d66f5bb28bb95557b3951903d39135620ef157/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b2a095d45c5d46e5e79ba1e5b9cb787f541a8dee0433836cea4b96a2c439dcd8", size = 289470, upload-time = "2025-10-06T05:37:47.946Z" }, + { url = "https://files.pythonhosted.org/packages/ac/83/dca6dc53bf657d371fbc88ddeb21b79891e747189c5de990b9dfff2ccba1/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:eab8145831a0d56ec9c4139b6c3e594c7a83c2c8be25d5bcf2d86136a532287a", size = 289042, upload-time = "2025-10-06T05:37:49.499Z" }, + { url = "https://files.pythonhosted.org/packages/96/52/abddd34ca99be142f354398700536c5bd315880ed0a213812bc491cff5e4/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:974b28cf63cc99dfb2188d8d222bc6843656188164848c4f679e63dae4b0708e", size = 283148, upload-time = "2025-10-06T05:37:50.745Z" }, + { url = "https://files.pythonhosted.org/packages/af/d3/76bd4ed4317e7119c2b7f57c3f6934aba26d277acc6309f873341640e21f/frozenlist-1.8.0-cp314-cp314t-win32.whl", hash = "sha256:342c97bf697ac5480c0a7ec73cd700ecfa5a8a40ac923bd035484616efecc2df", size = 44676, upload-time = "2025-10-06T05:37:52.222Z" }, + { url = "https://files.pythonhosted.org/packages/89/76/c615883b7b521ead2944bb3480398cbb07e12b7b4e4d073d3752eb721558/frozenlist-1.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:06be8f67f39c8b1dc671f5d83aaefd3358ae5cdcf8314552c57e7ed3e6475bdd", size = 49451, upload-time = "2025-10-06T05:37:53.425Z" }, + { url = "https://files.pythonhosted.org/packages/e0/a3/5982da14e113d07b325230f95060e2169f5311b1017ea8af2a29b374c289/frozenlist-1.8.0-cp314-cp314t-win_arm64.whl", hash = "sha256:102e6314ca4da683dca92e3b1355490fed5f313b768500084fbe6371fddfdb79", size = 42507, upload-time = "2025-10-06T05:37:54.513Z" }, + { url = "https://files.pythonhosted.org/packages/9a/9a/e35b4a917281c0b8419d4207f4334c8e8c5dbf4f3f5f9ada73958d937dcc/frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d", size = 13409, upload-time = "2025-10-06T05:38:16.721Z" }, +] + +[[package]] +name = "fsspec" +version = "2025.10.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/24/7f/2747c0d332b9acfa75dc84447a066fdf812b5a6b8d30472b74d309bfe8cb/fsspec-2025.10.0.tar.gz", hash = "sha256:b6789427626f068f9a83ca4e8a3cc050850b6c0f71f99ddb4f542b8266a26a59", size = 309285, upload-time = "2025-10-30T14:58:44.036Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/eb/02/a6b21098b1d5d6249b7c5ab69dde30108a71e4e819d4a9778f1de1d5b70d/fsspec-2025.10.0-py3-none-any.whl", hash = "sha256:7c7712353ae7d875407f97715f0e1ffcc21e33d5b24556cb1e090ae9409ec61d", size = 200966, upload-time = "2025-10-30T14:58:42.53Z" }, +] + +[package.optional-dependencies] +http = [ + { name = "aiohttp" }, ] -provides-extras = ["research", "langgraph", "optimizer", "all", "dev"] [[package]] name = "gepa" @@ -717,6 +1305,57 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, ] +[[package]] +name = "h2" +version = "4.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "hpack" }, + { name = "hyperframe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1d/17/afa56379f94ad0fe8defd37d6eb3f89a25404ffc71d4d848893d270325fc/h2-4.3.0.tar.gz", hash = "sha256:6c59efe4323fa18b47a632221a1888bd7fde6249819beda254aeca909f221bf1", size = 2152026, upload-time = "2025-08-23T18:12:19.778Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/69/b2/119f6e6dcbd96f9069ce9a2665e0146588dc9f88f29549711853645e736a/h2-4.3.0-py3-none-any.whl", hash = "sha256:c438f029a25f7945c69e0ccf0fb951dc3f73a5f6412981daee861431b70e2bdd", size = 61779, upload-time = "2025-08-23T18:12:17.779Z" }, +] + +[[package]] +name = "hf-xet" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5e/6e/0f11bacf08a67f7fb5ee09740f2ca54163863b07b70d579356e9222ce5d8/hf_xet-1.2.0.tar.gz", hash = "sha256:a8c27070ca547293b6890c4bf389f713f80e8c478631432962bb7f4bc0bd7d7f", size = 506020, upload-time = "2025-10-24T19:04:32.129Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/a5/85ef910a0aa034a2abcfadc360ab5ac6f6bc4e9112349bd40ca97551cff0/hf_xet-1.2.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:ceeefcd1b7aed4956ae8499e2199607765fbd1c60510752003b6cc0b8413b649", size = 2861870, upload-time = "2025-10-24T19:04:11.422Z" }, + { url = "https://files.pythonhosted.org/packages/ea/40/e2e0a7eb9a51fe8828ba2d47fe22a7e74914ea8a0db68a18c3aa7449c767/hf_xet-1.2.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b70218dd548e9840224df5638fdc94bd033552963cfa97f9170829381179c813", size = 2717584, upload-time = "2025-10-24T19:04:09.586Z" }, + { url = "https://files.pythonhosted.org/packages/a5/7d/daf7f8bc4594fdd59a8a596f9e3886133fdc68e675292218a5e4c1b7e834/hf_xet-1.2.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d40b18769bb9a8bc82a9ede575ce1a44c75eb80e7375a01d76259089529b5dc", size = 3315004, upload-time = "2025-10-24T19:04:00.314Z" }, + { url = "https://files.pythonhosted.org/packages/b1/ba/45ea2f605fbf6d81c8b21e4d970b168b18a53515923010c312c06cd83164/hf_xet-1.2.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:cd3a6027d59cfb60177c12d6424e31f4b5ff13d8e3a1247b3a584bf8977e6df5", size = 3222636, upload-time = "2025-10-24T19:03:58.111Z" }, + { url = "https://files.pythonhosted.org/packages/4a/1d/04513e3cab8f29ab8c109d309ddd21a2705afab9d52f2ba1151e0c14f086/hf_xet-1.2.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6de1fc44f58f6dd937956c8d304d8c2dea264c80680bcfa61ca4a15e7b76780f", size = 3408448, upload-time = "2025-10-24T19:04:20.951Z" }, + { url = "https://files.pythonhosted.org/packages/f0/7c/60a2756d7feec7387db3a1176c632357632fbe7849fce576c5559d4520c7/hf_xet-1.2.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f182f264ed2acd566c514e45da9f2119110e48a87a327ca271027904c70c5832", size = 3503401, upload-time = "2025-10-24T19:04:22.549Z" }, + { url = "https://files.pythonhosted.org/packages/4e/64/48fffbd67fb418ab07451e4ce641a70de1c40c10a13e25325e24858ebe5a/hf_xet-1.2.0-cp313-cp313t-win_amd64.whl", hash = "sha256:293a7a3787e5c95d7be1857358a9130694a9c6021de3f27fa233f37267174382", size = 2900866, upload-time = "2025-10-24T19:04:33.461Z" }, + { url = "https://files.pythonhosted.org/packages/e2/51/f7e2caae42f80af886db414d4e9885fac959330509089f97cccb339c6b87/hf_xet-1.2.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:10bfab528b968c70e062607f663e21e34e2bba349e8038db546646875495179e", size = 2861861, upload-time = "2025-10-24T19:04:19.01Z" }, + { url = "https://files.pythonhosted.org/packages/6e/1d/a641a88b69994f9371bd347f1dd35e5d1e2e2460a2e350c8d5165fc62005/hf_xet-1.2.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2a212e842647b02eb6a911187dc878e79c4aa0aa397e88dd3b26761676e8c1f8", size = 2717699, upload-time = "2025-10-24T19:04:17.306Z" }, + { url = "https://files.pythonhosted.org/packages/df/e0/e5e9bba7d15f0318955f7ec3f4af13f92e773fbb368c0b8008a5acbcb12f/hf_xet-1.2.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:30e06daccb3a7d4c065f34fc26c14c74f4653069bb2b194e7f18f17cbe9939c0", size = 3314885, upload-time = "2025-10-24T19:04:07.642Z" }, + { url = "https://files.pythonhosted.org/packages/21/90/b7fe5ff6f2b7b8cbdf1bd56145f863c90a5807d9758a549bf3d916aa4dec/hf_xet-1.2.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:29c8fc913a529ec0a91867ce3d119ac1aac966e098cf49501800c870328cc090", size = 3221550, upload-time = "2025-10-24T19:04:05.55Z" }, + { url = "https://files.pythonhosted.org/packages/6f/cb/73f276f0a7ce46cc6a6ec7d6c7d61cbfe5f2e107123d9bbd0193c355f106/hf_xet-1.2.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e159cbfcfbb29f920db2c09ed8b660eb894640d284f102ada929b6e3dc410a", size = 3408010, upload-time = "2025-10-24T19:04:28.598Z" }, + { url = "https://files.pythonhosted.org/packages/b8/1e/d642a12caa78171f4be64f7cd9c40e3ca5279d055d0873188a58c0f5fbb9/hf_xet-1.2.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9c91d5ae931510107f148874e9e2de8a16052b6f1b3ca3c1b12f15ccb491390f", size = 3503264, upload-time = "2025-10-24T19:04:30.397Z" }, + { url = "https://files.pythonhosted.org/packages/17/b5/33764714923fa1ff922770f7ed18c2daae034d21ae6e10dbf4347c854154/hf_xet-1.2.0-cp314-cp314t-win_amd64.whl", hash = "sha256:210d577732b519ac6ede149d2f2f34049d44e8622bf14eb3d63bbcd2d4b332dc", size = 2901071, upload-time = "2025-10-24T19:04:37.463Z" }, + { url = "https://files.pythonhosted.org/packages/96/2d/22338486473df5923a9ab7107d375dbef9173c338ebef5098ef593d2b560/hf_xet-1.2.0-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:46740d4ac024a7ca9b22bebf77460ff43332868b661186a8e46c227fdae01848", size = 2866099, upload-time = "2025-10-24T19:04:15.366Z" }, + { url = "https://files.pythonhosted.org/packages/7f/8c/c5becfa53234299bc2210ba314eaaae36c2875e0045809b82e40a9544f0c/hf_xet-1.2.0-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:27df617a076420d8845bea087f59303da8be17ed7ec0cd7ee3b9b9f579dff0e4", size = 2722178, upload-time = "2025-10-24T19:04:13.695Z" }, + { url = "https://files.pythonhosted.org/packages/9a/92/cf3ab0b652b082e66876d08da57fcc6fa2f0e6c70dfbbafbd470bb73eb47/hf_xet-1.2.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3651fd5bfe0281951b988c0facbe726aa5e347b103a675f49a3fa8144c7968fd", size = 3320214, upload-time = "2025-10-24T19:04:03.596Z" }, + { url = "https://files.pythonhosted.org/packages/46/92/3f7ec4a1b6a65bf45b059b6d4a5d38988f63e193056de2f420137e3c3244/hf_xet-1.2.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d06fa97c8562fb3ee7a378dd9b51e343bc5bc8190254202c9771029152f5e08c", size = 3229054, upload-time = "2025-10-24T19:04:01.949Z" }, + { url = "https://files.pythonhosted.org/packages/0b/dd/7ac658d54b9fb7999a0ccb07ad863b413cbaf5cf172f48ebcd9497ec7263/hf_xet-1.2.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:4c1428c9ae73ec0939410ec73023c4f842927f39db09b063b9482dac5a3bb737", size = 3413812, upload-time = "2025-10-24T19:04:24.585Z" }, + { url = "https://files.pythonhosted.org/packages/92/68/89ac4e5b12a9ff6286a12174c8538a5930e2ed662091dd2572bbe0a18c8a/hf_xet-1.2.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a55558084c16b09b5ed32ab9ed38421e2d87cf3f1f89815764d1177081b99865", size = 3508920, upload-time = "2025-10-24T19:04:26.927Z" }, + { url = "https://files.pythonhosted.org/packages/cb/44/870d44b30e1dcfb6a65932e3e1506c103a8a5aea9103c337e7a53180322c/hf_xet-1.2.0-cp37-abi3-win_amd64.whl", hash = "sha256:e6584a52253f72c9f52f9e549d5895ca7a471608495c4ecaa6cc73dba2b24d69", size = 2905735, upload-time = "2025-10-24T19:04:35.928Z" }, +] + +[[package]] +name = "hpack" +version = "4.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2c/48/71de9ed269fdae9c8057e5a4c0aa7402e8bb16f2c6e90b3aa53327b113f8/hpack-4.1.0.tar.gz", hash = "sha256:ec5eca154f7056aa06f196a557655c5b009b382873ac8d1e66e79e87535f1dca", size = 51276, upload-time = "2025-01-22T21:44:58.347Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/07/c6/80c95b1b2b94682a72cbdbfb85b81ae2daffa4291fbfa1b1464502ede10d/hpack-4.1.0-py3-none-any.whl", hash = "sha256:157ac792668d995c657d93111f46b4535ed114f0c9c8d672271bbec7eae1b496", size = 34357, upload-time = "2025-01-22T21:44:56.92Z" }, +] + [[package]] name = "html2text" version = "2025.4.15" @@ -754,6 +1393,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, ] +[package.optional-dependencies] +brotli = [ + { name = "brotli", marker = "platform_python_implementation == 'CPython'" }, + { name = "brotlicffi", marker = "platform_python_implementation != 'CPython'" }, +] +http2 = [ + { name = "h2" }, +] +socks = [ + { name = "socksio" }, +] + [[package]] name = "httpx-sse" version = "0.4.3" @@ -763,6 +1414,34 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl", hash = "sha256:0ac1c9fe3c0afad2e0ebb25a934a59f4c7823b60792691f779fad2c5568830fc", size = 8960, upload-time = "2025-10-10T21:48:21.158Z" }, ] +[[package]] +name = "huggingface-hub" +version = "0.36.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "filelock" }, + { name = "fsspec" }, + { name = "hf-xet", marker = "platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64'" }, + { name = "packaging" }, + { name = "pyyaml" }, + { name = "requests" }, + { name = "tqdm" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/45/54/096903f02ca14eb2670a4d11729da44a026c0bababec8c15f160441124c5/huggingface_hub-0.36.1.tar.gz", hash = "sha256:5a3b8bf87e182ad6f1692c196bb9ec9ade7755311d5d5e792dc45045f77283ad", size = 649681, upload-time = "2026-02-02T10:46:58.287Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/cb/8f5141b3c21d1ecdf87852506eb583fec497c7e9803a168fe4aec64252bb/huggingface_hub-0.36.1-py3-none-any.whl", hash = "sha256:c6fa8a8f7b8559bc624ebb7e218fb72171b30f6049ebe08f8bfc2a44b38ece50", size = 566283, upload-time = "2026-02-02T10:46:56.459Z" }, +] + +[[package]] +name = "hyperframe" +version = "6.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/02/e7/94f8232d4a74cc99514c13a9f995811485a6903d48e5d952771ef6322e30/hyperframe-6.1.0.tar.gz", hash = "sha256:f630908a00854a7adeabd6382b43923a4c4cd4b821fcb527e6ab9e15382a3b08", size = 26566, upload-time = "2025-01-22T21:41:49.302Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/48/30/47d0bf6072f7252e6521f3447ccfa40b421b6824517f82854703d0f5a98b/hyperframe-6.1.0-py3-none-any.whl", hash = "sha256:b03380493a519fce58ea5af42e4a42317bf9bd425596f7a0835ffce80f1a42e5", size = 13007, upload-time = "2025-01-22T21:41:47.295Z" }, +] + [[package]] name = "identify" version = "2.6.16" @@ -802,6 +1481,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, ] +[[package]] +name = "jinja2" +version = "3.1.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, +] + [[package]] name = "jiter" version = "0.13.0" @@ -1129,6 +1820,178 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fc/85/69f92b2a7b3c0f88ffe107c86b952b397004b5b8ea5a81da3d9c04c04422/librt-0.7.8-cp314-cp314t-win_arm64.whl", hash = "sha256:8766ece9de08527deabcd7cb1b4f1a967a385d26e33e536d6d8913db6ef74f06", size = 40550, upload-time = "2026-01-14T12:56:01.542Z" }, ] +[[package]] +name = "litellm" +version = "1.81.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohttp" }, + { name = "click" }, + { name = "fastuuid" }, + { name = "httpx" }, + { name = "importlib-metadata" }, + { name = "jinja2" }, + { name = "jsonschema" }, + { name = "openai" }, + { name = "pydantic" }, + { name = "python-dotenv" }, + { name = "tiktoken" }, + { name = "tokenizers" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/77/69/cfa8a1d68cd10223a9d9741c411e131aece85c60c29c1102d762738b3e5c/litellm-1.81.7.tar.gz", hash = "sha256:442ff38708383ebee21357b3d936e58938172bae892f03bc5be4019ed4ff4a17", size = 14039864, upload-time = "2026-02-03T19:43:10.633Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/60/95/8cecc7e6377171e4ac96f23d65236af8706d99c1b7b71a94c72206672810/litellm-1.81.7-py3-none-any.whl", hash = "sha256:58466c88c3289c6a3830d88768cf8f307581d9e6c87861de874d1128bb2de90d", size = 12254178, upload-time = "2026-02-03T19:43:08.035Z" }, +] + +[[package]] +name = "loguru" +version = "0.7.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "win32-setctime", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3a/05/a1dae3dffd1116099471c643b8924f5aa6524411dc6c63fdae648c4f1aca/loguru-0.7.3.tar.gz", hash = "sha256:19480589e77d47b8d85b2c827ad95d49bf31b0dcde16593892eb51dd18706eb6", size = 63559, upload-time = "2024-12-06T11:20:56.608Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/29/0348de65b8cc732daa3e33e67806420b2ae89bdce2b04af740289c5c6c8c/loguru-0.7.3-py3-none-any.whl", hash = "sha256:31a33c10c8e1e10422bfd431aeb5d351c7cf7fa671e3c4df004162264b28220c", size = 61595, upload-time = "2024-12-06T11:20:54.538Z" }, +] + +[[package]] +name = "lxml" +version = "6.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/aa/88/262177de60548e5a2bfc46ad28232c9e9cbde697bd94132aeb80364675cb/lxml-6.0.2.tar.gz", hash = "sha256:cd79f3367bd74b317dda655dc8fcfa304d9eb6e4fb06b7168c5cf27f96e0cd62", size = 4073426, upload-time = "2025-09-22T04:04:59.287Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/db/8a/f8192a08237ef2fb1b19733f709db88a4c43bc8ab8357f01cb41a27e7f6a/lxml-6.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e77dd455b9a16bbd2a5036a63ddbd479c19572af81b624e79ef422f929eef388", size = 8590589, upload-time = "2025-09-22T04:00:10.51Z" }, + { url = "https://files.pythonhosted.org/packages/12/64/27bcd07ae17ff5e5536e8d88f4c7d581b48963817a13de11f3ac3329bfa2/lxml-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5d444858b9f07cefff6455b983aea9a67f7462ba1f6cbe4a21e8bf6791bf2153", size = 4629671, upload-time = "2025-09-22T04:00:15.411Z" }, + { url = "https://files.pythonhosted.org/packages/02/5a/a7d53b3291c324e0b6e48f3c797be63836cc52156ddf8f33cd72aac78866/lxml-6.0.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f952dacaa552f3bb8834908dddd500ba7d508e6ea6eb8c52eb2d28f48ca06a31", size = 4999961, upload-time = "2025-09-22T04:00:17.619Z" }, + { url = "https://files.pythonhosted.org/packages/f5/55/d465e9b89df1761674d8672bb3e4ae2c47033b01ec243964b6e334c6743f/lxml-6.0.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:71695772df6acea9f3c0e59e44ba8ac50c4f125217e84aab21074a1a55e7e5c9", size = 5157087, upload-time = "2025-09-22T04:00:19.868Z" }, + { url = "https://files.pythonhosted.org/packages/62/38/3073cd7e3e8dfc3ba3c3a139e33bee3a82de2bfb0925714351ad3d255c13/lxml-6.0.2-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:17f68764f35fd78d7c4cc4ef209a184c38b65440378013d24b8aecd327c3e0c8", size = 5067620, upload-time = "2025-09-22T04:00:21.877Z" }, + { url = "https://files.pythonhosted.org/packages/4a/d3/1e001588c5e2205637b08985597827d3827dbaaece16348c8822bfe61c29/lxml-6.0.2-cp310-cp310-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:058027e261afed589eddcfe530fcc6f3402d7fd7e89bfd0532df82ebc1563dba", size = 5406664, upload-time = "2025-09-22T04:00:23.714Z" }, + { url = "https://files.pythonhosted.org/packages/20/cf/cab09478699b003857ed6ebfe95e9fb9fa3d3c25f1353b905c9b73cfb624/lxml-6.0.2-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8ffaeec5dfea5881d4c9d8913a32d10cfe3923495386106e4a24d45300ef79c", size = 5289397, upload-time = "2025-09-22T04:00:25.544Z" }, + { url = "https://files.pythonhosted.org/packages/a3/84/02a2d0c38ac9a8b9f9e5e1bbd3f24b3f426044ad618b552e9549ee91bd63/lxml-6.0.2-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:f2e3b1a6bb38de0bc713edd4d612969dd250ca8b724be8d460001a387507021c", size = 4772178, upload-time = "2025-09-22T04:00:27.602Z" }, + { url = "https://files.pythonhosted.org/packages/56/87/e1ceadcc031ec4aa605fe95476892d0b0ba3b7f8c7dcdf88fdeff59a9c86/lxml-6.0.2-cp310-cp310-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d6690ec5ec1cce0385cb20896b16be35247ac8c2046e493d03232f1c2414d321", size = 5358148, upload-time = "2025-09-22T04:00:29.323Z" }, + { url = "https://files.pythonhosted.org/packages/fe/13/5bb6cf42bb228353fd4ac5f162c6a84fd68a4d6f67c1031c8cf97e131fc6/lxml-6.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f2a50c3c1d11cad0ebebbac357a97b26aa79d2bcaf46f256551152aa85d3a4d1", size = 5112035, upload-time = "2025-09-22T04:00:31.061Z" }, + { url = "https://files.pythonhosted.org/packages/e4/e2/ea0498552102e59834e297c5c6dff8d8ded3db72ed5e8aad77871476f073/lxml-6.0.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:3efe1b21c7801ffa29a1112fab3b0f643628c30472d507f39544fd48e9549e34", size = 4799111, upload-time = "2025-09-22T04:00:33.11Z" }, + { url = "https://files.pythonhosted.org/packages/6a/9e/8de42b52a73abb8af86c66c969b3b4c2a96567b6ac74637c037d2e3baa60/lxml-6.0.2-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:59c45e125140b2c4b33920d21d83681940ca29f0b83f8629ea1a2196dc8cfe6a", size = 5351662, upload-time = "2025-09-22T04:00:35.237Z" }, + { url = "https://files.pythonhosted.org/packages/28/a2/de776a573dfb15114509a37351937c367530865edb10a90189d0b4b9b70a/lxml-6.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:452b899faa64f1805943ec1c0c9ebeaece01a1af83e130b69cdefeda180bb42c", size = 5314973, upload-time = "2025-09-22T04:00:37.086Z" }, + { url = "https://files.pythonhosted.org/packages/50/a0/3ae1b1f8964c271b5eec91db2043cf8c6c0bce101ebb2a633b51b044db6c/lxml-6.0.2-cp310-cp310-win32.whl", hash = "sha256:1e786a464c191ca43b133906c6903a7e4d56bef376b75d97ccbb8ec5cf1f0a4b", size = 3611953, upload-time = "2025-09-22T04:00:39.224Z" }, + { url = "https://files.pythonhosted.org/packages/d1/70/bd42491f0634aad41bdfc1e46f5cff98825fb6185688dc82baa35d509f1a/lxml-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:dacf3c64ef3f7440e3167aa4b49aa9e0fb99e0aa4f9ff03795640bf94531bcb0", size = 4032695, upload-time = "2025-09-22T04:00:41.402Z" }, + { url = "https://files.pythonhosted.org/packages/d2/d0/05c6a72299f54c2c561a6c6cbb2f512e047fca20ea97a05e57931f194ac4/lxml-6.0.2-cp310-cp310-win_arm64.whl", hash = "sha256:45f93e6f75123f88d7f0cfd90f2d05f441b808562bf0bc01070a00f53f5028b5", size = 3680051, upload-time = "2025-09-22T04:00:43.525Z" }, + { url = "https://files.pythonhosted.org/packages/77/d5/becbe1e2569b474a23f0c672ead8a29ac50b2dc1d5b9de184831bda8d14c/lxml-6.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:13e35cbc684aadf05d8711a5d1b5857c92e5e580efa9a0d2be197199c8def607", size = 8634365, upload-time = "2025-09-22T04:00:45.672Z" }, + { url = "https://files.pythonhosted.org/packages/28/66/1ced58f12e804644426b85d0bb8a4478ca77bc1761455da310505f1a3526/lxml-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3b1675e096e17c6fe9c0e8c81434f5736c0739ff9ac6123c87c2d452f48fc938", size = 4650793, upload-time = "2025-09-22T04:00:47.783Z" }, + { url = "https://files.pythonhosted.org/packages/11/84/549098ffea39dfd167e3f174b4ce983d0eed61f9d8d25b7bf2a57c3247fc/lxml-6.0.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8ac6e5811ae2870953390452e3476694196f98d447573234592d30488147404d", size = 4944362, upload-time = "2025-09-22T04:00:49.845Z" }, + { url = "https://files.pythonhosted.org/packages/ac/bd/f207f16abf9749d2037453d56b643a7471d8fde855a231a12d1e095c4f01/lxml-6.0.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5aa0fc67ae19d7a64c3fe725dc9a1bb11f80e01f78289d05c6f62545affec438", size = 5083152, upload-time = "2025-09-22T04:00:51.709Z" }, + { url = "https://files.pythonhosted.org/packages/15/ae/bd813e87d8941d52ad5b65071b1affb48da01c4ed3c9c99e40abb266fbff/lxml-6.0.2-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:de496365750cc472b4e7902a485d3f152ecf57bd3ba03ddd5578ed8ceb4c5964", size = 5023539, upload-time = "2025-09-22T04:00:53.593Z" }, + { url = "https://files.pythonhosted.org/packages/02/cd/9bfef16bd1d874fbe0cb51afb00329540f30a3283beb9f0780adbb7eec03/lxml-6.0.2-cp311-cp311-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:200069a593c5e40b8f6fc0d84d86d970ba43138c3e68619ffa234bc9bb806a4d", size = 5344853, upload-time = "2025-09-22T04:00:55.524Z" }, + { url = "https://files.pythonhosted.org/packages/b8/89/ea8f91594bc5dbb879734d35a6f2b0ad50605d7fb419de2b63d4211765cc/lxml-6.0.2-cp311-cp311-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7d2de809c2ee3b888b59f995625385f74629707c9355e0ff856445cdcae682b7", size = 5225133, upload-time = "2025-09-22T04:00:57.269Z" }, + { url = "https://files.pythonhosted.org/packages/b9/37/9c735274f5dbec726b2db99b98a43950395ba3d4a1043083dba2ad814170/lxml-6.0.2-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:b2c3da8d93cf5db60e8858c17684c47d01fee6405e554fb55018dd85fc23b178", size = 4677944, upload-time = "2025-09-22T04:00:59.052Z" }, + { url = "https://files.pythonhosted.org/packages/20/28/7dfe1ba3475d8bfca3878365075abe002e05d40dfaaeb7ec01b4c587d533/lxml-6.0.2-cp311-cp311-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:442de7530296ef5e188373a1ea5789a46ce90c4847e597856570439621d9c553", size = 5284535, upload-time = "2025-09-22T04:01:01.335Z" }, + { url = "https://files.pythonhosted.org/packages/e7/cf/5f14bc0de763498fc29510e3532bf2b4b3a1c1d5d0dff2e900c16ba021ef/lxml-6.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2593c77efde7bfea7f6389f1ab249b15ed4aa5bc5cb5131faa3b843c429fbedb", size = 5067343, upload-time = "2025-09-22T04:01:03.13Z" }, + { url = "https://files.pythonhosted.org/packages/1c/b0/bb8275ab5472f32b28cfbbcc6db7c9d092482d3439ca279d8d6fa02f7025/lxml-6.0.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:3e3cb08855967a20f553ff32d147e14329b3ae70ced6edc2f282b94afbc74b2a", size = 4725419, upload-time = "2025-09-22T04:01:05.013Z" }, + { url = "https://files.pythonhosted.org/packages/25/4c/7c222753bc72edca3b99dbadba1b064209bc8ed4ad448af990e60dcce462/lxml-6.0.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:2ed6c667fcbb8c19c6791bbf40b7268ef8ddf5a96940ba9404b9f9a304832f6c", size = 5275008, upload-time = "2025-09-22T04:01:07.327Z" }, + { url = "https://files.pythonhosted.org/packages/6c/8c/478a0dc6b6ed661451379447cdbec77c05741a75736d97e5b2b729687828/lxml-6.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b8f18914faec94132e5b91e69d76a5c1d7b0c73e2489ea8929c4aaa10b76bbf7", size = 5248906, upload-time = "2025-09-22T04:01:09.452Z" }, + { url = "https://files.pythonhosted.org/packages/2d/d9/5be3a6ab2784cdf9accb0703b65e1b64fcdd9311c9f007630c7db0cfcce1/lxml-6.0.2-cp311-cp311-win32.whl", hash = "sha256:6605c604e6daa9e0d7f0a2137bdc47a2e93b59c60a65466353e37f8272f47c46", size = 3610357, upload-time = "2025-09-22T04:01:11.102Z" }, + { url = "https://files.pythonhosted.org/packages/e2/7d/ca6fb13349b473d5732fb0ee3eec8f6c80fc0688e76b7d79c1008481bf1f/lxml-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e5867f2651016a3afd8dd2c8238baa66f1e2802f44bc17e236f547ace6647078", size = 4036583, upload-time = "2025-09-22T04:01:12.766Z" }, + { url = "https://files.pythonhosted.org/packages/ab/a2/51363b5ecd3eab46563645f3a2c3836a2fc67d01a1b87c5017040f39f567/lxml-6.0.2-cp311-cp311-win_arm64.whl", hash = "sha256:4197fb2534ee05fd3e7afaab5d8bfd6c2e186f65ea7f9cd6a82809c887bd1285", size = 3680591, upload-time = "2025-09-22T04:01:14.874Z" }, + { url = "https://files.pythonhosted.org/packages/f3/c8/8ff2bc6b920c84355146cd1ab7d181bc543b89241cfb1ebee824a7c81457/lxml-6.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a59f5448ba2ceccd06995c95ea59a7674a10de0810f2ce90c9006f3cbc044456", size = 8661887, upload-time = "2025-09-22T04:01:17.265Z" }, + { url = "https://files.pythonhosted.org/packages/37/6f/9aae1008083bb501ef63284220ce81638332f9ccbfa53765b2b7502203cf/lxml-6.0.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e8113639f3296706fbac34a30813929e29247718e88173ad849f57ca59754924", size = 4667818, upload-time = "2025-09-22T04:01:19.688Z" }, + { url = "https://files.pythonhosted.org/packages/f1/ca/31fb37f99f37f1536c133476674c10b577e409c0a624384147653e38baf2/lxml-6.0.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:a8bef9b9825fa8bc816a6e641bb67219489229ebc648be422af695f6e7a4fa7f", size = 4950807, upload-time = "2025-09-22T04:01:21.487Z" }, + { url = "https://files.pythonhosted.org/packages/da/87/f6cb9442e4bada8aab5ae7e1046264f62fdbeaa6e3f6211b93f4c0dd97f1/lxml-6.0.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:65ea18d710fd14e0186c2f973dc60bb52039a275f82d3c44a0e42b43440ea534", size = 5109179, upload-time = "2025-09-22T04:01:23.32Z" }, + { url = "https://files.pythonhosted.org/packages/c8/20/a7760713e65888db79bbae4f6146a6ae5c04e4a204a3c48896c408cd6ed2/lxml-6.0.2-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c371aa98126a0d4c739ca93ceffa0fd7a5d732e3ac66a46e74339acd4d334564", size = 5023044, upload-time = "2025-09-22T04:01:25.118Z" }, + { url = "https://files.pythonhosted.org/packages/a2/b0/7e64e0460fcb36471899f75831509098f3fd7cd02a3833ac517433cb4f8f/lxml-6.0.2-cp312-cp312-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:700efd30c0fa1a3581d80a748157397559396090a51d306ea59a70020223d16f", size = 5359685, upload-time = "2025-09-22T04:01:27.398Z" }, + { url = "https://files.pythonhosted.org/packages/b9/e1/e5df362e9ca4e2f48ed6411bd4b3a0ae737cc842e96877f5bf9428055ab4/lxml-6.0.2-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c33e66d44fe60e72397b487ee92e01da0d09ba2d66df8eae42d77b6d06e5eba0", size = 5654127, upload-time = "2025-09-22T04:01:29.629Z" }, + { url = "https://files.pythonhosted.org/packages/c6/d1/232b3309a02d60f11e71857778bfcd4acbdb86c07db8260caf7d008b08f8/lxml-6.0.2-cp312-cp312-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:90a345bbeaf9d0587a3aaffb7006aa39ccb6ff0e96a57286c0cb2fd1520ea192", size = 5253958, upload-time = "2025-09-22T04:01:31.535Z" }, + { url = "https://files.pythonhosted.org/packages/35/35/d955a070994725c4f7d80583a96cab9c107c57a125b20bb5f708fe941011/lxml-6.0.2-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:064fdadaf7a21af3ed1dcaa106b854077fbeada827c18f72aec9346847cd65d0", size = 4711541, upload-time = "2025-09-22T04:01:33.801Z" }, + { url = "https://files.pythonhosted.org/packages/1e/be/667d17363b38a78c4bd63cfd4b4632029fd68d2c2dc81f25ce9eb5224dd5/lxml-6.0.2-cp312-cp312-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fbc74f42c3525ac4ffa4b89cbdd00057b6196bcefe8bce794abd42d33a018092", size = 5267426, upload-time = "2025-09-22T04:01:35.639Z" }, + { url = "https://files.pythonhosted.org/packages/ea/47/62c70aa4a1c26569bc958c9ca86af2bb4e1f614e8c04fb2989833874f7ae/lxml-6.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6ddff43f702905a4e32bc24f3f2e2edfe0f8fde3277d481bffb709a4cced7a1f", size = 5064917, upload-time = "2025-09-22T04:01:37.448Z" }, + { url = "https://files.pythonhosted.org/packages/bd/55/6ceddaca353ebd0f1908ef712c597f8570cc9c58130dbb89903198e441fd/lxml-6.0.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:6da5185951d72e6f5352166e3da7b0dc27aa70bd1090b0eb3f7f7212b53f1bb8", size = 4788795, upload-time = "2025-09-22T04:01:39.165Z" }, + { url = "https://files.pythonhosted.org/packages/cf/e8/fd63e15da5e3fd4c2146f8bbb3c14e94ab850589beab88e547b2dbce22e1/lxml-6.0.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:57a86e1ebb4020a38d295c04fc79603c7899e0df71588043eb218722dabc087f", size = 5676759, upload-time = "2025-09-22T04:01:41.506Z" }, + { url = "https://files.pythonhosted.org/packages/76/47/b3ec58dc5c374697f5ba37412cd2728f427d056315d124dd4b61da381877/lxml-6.0.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:2047d8234fe735ab77802ce5f2297e410ff40f5238aec569ad7c8e163d7b19a6", size = 5255666, upload-time = "2025-09-22T04:01:43.363Z" }, + { url = "https://files.pythonhosted.org/packages/19/93/03ba725df4c3d72afd9596eef4a37a837ce8e4806010569bedfcd2cb68fd/lxml-6.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6f91fd2b2ea15a6800c8e24418c0775a1694eefc011392da73bc6cef2623b322", size = 5277989, upload-time = "2025-09-22T04:01:45.215Z" }, + { url = "https://files.pythonhosted.org/packages/c6/80/c06de80bfce881d0ad738576f243911fccf992687ae09fd80b734712b39c/lxml-6.0.2-cp312-cp312-win32.whl", hash = "sha256:3ae2ce7d6fedfb3414a2b6c5e20b249c4c607f72cb8d2bb7cc9c6ec7c6f4e849", size = 3611456, upload-time = "2025-09-22T04:01:48.243Z" }, + { url = "https://files.pythonhosted.org/packages/f7/d7/0cdfb6c3e30893463fb3d1e52bc5f5f99684a03c29a0b6b605cfae879cd5/lxml-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:72c87e5ee4e58a8354fb9c7c84cbf95a1c8236c127a5d1b7683f04bed8361e1f", size = 4011793, upload-time = "2025-09-22T04:01:50.042Z" }, + { url = "https://files.pythonhosted.org/packages/ea/7b/93c73c67db235931527301ed3785f849c78991e2e34f3fd9a6663ffda4c5/lxml-6.0.2-cp312-cp312-win_arm64.whl", hash = "sha256:61cb10eeb95570153e0c0e554f58df92ecf5109f75eacad4a95baa709e26c3d6", size = 3672836, upload-time = "2025-09-22T04:01:52.145Z" }, + { url = "https://files.pythonhosted.org/packages/53/fd/4e8f0540608977aea078bf6d79f128e0e2c2bba8af1acf775c30baa70460/lxml-6.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9b33d21594afab46f37ae58dfadd06636f154923c4e8a4d754b0127554eb2e77", size = 8648494, upload-time = "2025-09-22T04:01:54.242Z" }, + { url = "https://files.pythonhosted.org/packages/5d/f4/2a94a3d3dfd6c6b433501b8d470a1960a20ecce93245cf2db1706adf6c19/lxml-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6c8963287d7a4c5c9a432ff487c52e9c5618667179c18a204bdedb27310f022f", size = 4661146, upload-time = "2025-09-22T04:01:56.282Z" }, + { url = "https://files.pythonhosted.org/packages/25/2e/4efa677fa6b322013035d38016f6ae859d06cac67437ca7dc708a6af7028/lxml-6.0.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1941354d92699fb5ffe6ed7b32f9649e43c2feb4b97205f75866f7d21aa91452", size = 4946932, upload-time = "2025-09-22T04:01:58.989Z" }, + { url = "https://files.pythonhosted.org/packages/ce/0f/526e78a6d38d109fdbaa5049c62e1d32fdd70c75fb61c4eadf3045d3d124/lxml-6.0.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bb2f6ca0ae2d983ded09357b84af659c954722bbf04dea98030064996d156048", size = 5100060, upload-time = "2025-09-22T04:02:00.812Z" }, + { url = "https://files.pythonhosted.org/packages/81/76/99de58d81fa702cc0ea7edae4f4640416c2062813a00ff24bd70ac1d9c9b/lxml-6.0.2-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eb2a12d704f180a902d7fa778c6d71f36ceb7b0d317f34cdc76a5d05aa1dd1df", size = 5019000, upload-time = "2025-09-22T04:02:02.671Z" }, + { url = "https://files.pythonhosted.org/packages/b5/35/9e57d25482bc9a9882cb0037fdb9cc18f4b79d85df94fa9d2a89562f1d25/lxml-6.0.2-cp313-cp313-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:6ec0e3f745021bfed19c456647f0298d60a24c9ff86d9d051f52b509663feeb1", size = 5348496, upload-time = "2025-09-22T04:02:04.904Z" }, + { url = "https://files.pythonhosted.org/packages/a6/8e/cb99bd0b83ccc3e8f0f528e9aa1f7a9965dfec08c617070c5db8d63a87ce/lxml-6.0.2-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:846ae9a12d54e368933b9759052d6206a9e8b250291109c48e350c1f1f49d916", size = 5643779, upload-time = "2025-09-22T04:02:06.689Z" }, + { url = "https://files.pythonhosted.org/packages/d0/34/9e591954939276bb679b73773836c6684c22e56d05980e31d52a9a8deb18/lxml-6.0.2-cp313-cp313-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ef9266d2aa545d7374938fb5c484531ef5a2ec7f2d573e62f8ce722c735685fd", size = 5244072, upload-time = "2025-09-22T04:02:08.587Z" }, + { url = "https://files.pythonhosted.org/packages/8d/27/b29ff065f9aaca443ee377aff699714fcbffb371b4fce5ac4ca759e436d5/lxml-6.0.2-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:4077b7c79f31755df33b795dc12119cb557a0106bfdab0d2c2d97bd3cf3dffa6", size = 4718675, upload-time = "2025-09-22T04:02:10.783Z" }, + { url = "https://files.pythonhosted.org/packages/2b/9f/f756f9c2cd27caa1a6ef8c32ae47aadea697f5c2c6d07b0dae133c244fbe/lxml-6.0.2-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a7c5d5e5f1081955358533be077166ee97ed2571d6a66bdba6ec2f609a715d1a", size = 5255171, upload-time = "2025-09-22T04:02:12.631Z" }, + { url = "https://files.pythonhosted.org/packages/61/46/bb85ea42d2cb1bd8395484fd72f38e3389611aa496ac7772da9205bbda0e/lxml-6.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:8f8d0cbd0674ee89863a523e6994ac25fd5be9c8486acfc3e5ccea679bad2679", size = 5057175, upload-time = "2025-09-22T04:02:14.718Z" }, + { url = "https://files.pythonhosted.org/packages/95/0c/443fc476dcc8e41577f0af70458c50fe299a97bb6b7505bb1ae09aa7f9ac/lxml-6.0.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:2cbcbf6d6e924c28f04a43f3b6f6e272312a090f269eff68a2982e13e5d57659", size = 4785688, upload-time = "2025-09-22T04:02:16.957Z" }, + { url = "https://files.pythonhosted.org/packages/48/78/6ef0b359d45bb9697bc5a626e1992fa5d27aa3f8004b137b2314793b50a0/lxml-6.0.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:dfb874cfa53340009af6bdd7e54ebc0d21012a60a4e65d927c2e477112e63484", size = 5660655, upload-time = "2025-09-22T04:02:18.815Z" }, + { url = "https://files.pythonhosted.org/packages/ff/ea/e1d33808f386bc1339d08c0dcada6e4712d4ed8e93fcad5f057070b7988a/lxml-6.0.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:fb8dae0b6b8b7f9e96c26fdd8121522ce5de9bb5538010870bd538683d30e9a2", size = 5247695, upload-time = "2025-09-22T04:02:20.593Z" }, + { url = "https://files.pythonhosted.org/packages/4f/47/eba75dfd8183673725255247a603b4ad606f4ae657b60c6c145b381697da/lxml-6.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:358d9adae670b63e95bc59747c72f4dc97c9ec58881d4627fe0120da0f90d314", size = 5269841, upload-time = "2025-09-22T04:02:22.489Z" }, + { url = "https://files.pythonhosted.org/packages/76/04/5c5e2b8577bc936e219becb2e98cdb1aca14a4921a12995b9d0c523502ae/lxml-6.0.2-cp313-cp313-win32.whl", hash = "sha256:e8cd2415f372e7e5a789d743d133ae474290a90b9023197fd78f32e2dc6873e2", size = 3610700, upload-time = "2025-09-22T04:02:24.465Z" }, + { url = "https://files.pythonhosted.org/packages/fe/0a/4643ccc6bb8b143e9f9640aa54e38255f9d3b45feb2cbe7ae2ca47e8782e/lxml-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:b30d46379644fbfc3ab81f8f82ae4de55179414651f110a1514f0b1f8f6cb2d7", size = 4010347, upload-time = "2025-09-22T04:02:26.286Z" }, + { url = "https://files.pythonhosted.org/packages/31/ef/dcf1d29c3f530577f61e5fe2f1bd72929acf779953668a8a47a479ae6f26/lxml-6.0.2-cp313-cp313-win_arm64.whl", hash = "sha256:13dcecc9946dca97b11b7c40d29fba63b55ab4170d3c0cf8c0c164343b9bfdcf", size = 3671248, upload-time = "2025-09-22T04:02:27.918Z" }, + { url = "https://files.pythonhosted.org/packages/03/15/d4a377b385ab693ce97b472fe0c77c2b16ec79590e688b3ccc71fba19884/lxml-6.0.2-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:b0c732aa23de8f8aec23f4b580d1e52905ef468afb4abeafd3fec77042abb6fe", size = 8659801, upload-time = "2025-09-22T04:02:30.113Z" }, + { url = "https://files.pythonhosted.org/packages/c8/e8/c128e37589463668794d503afaeb003987373c5f94d667124ffd8078bbd9/lxml-6.0.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:4468e3b83e10e0317a89a33d28f7aeba1caa4d1a6fd457d115dd4ffe90c5931d", size = 4659403, upload-time = "2025-09-22T04:02:32.119Z" }, + { url = "https://files.pythonhosted.org/packages/00/ce/74903904339decdf7da7847bb5741fc98a5451b42fc419a86c0c13d26fe2/lxml-6.0.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:abd44571493973bad4598a3be7e1d807ed45aa2adaf7ab92ab7c62609569b17d", size = 4966974, upload-time = "2025-09-22T04:02:34.155Z" }, + { url = "https://files.pythonhosted.org/packages/1f/d3/131dec79ce61c5567fecf82515bd9bc36395df42501b50f7f7f3bd065df0/lxml-6.0.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:370cd78d5855cfbffd57c422851f7d3864e6ae72d0da615fca4dad8c45d375a5", size = 5102953, upload-time = "2025-09-22T04:02:36.054Z" }, + { url = "https://files.pythonhosted.org/packages/3a/ea/a43ba9bb750d4ffdd885f2cd333572f5bb900cd2408b67fdda07e85978a0/lxml-6.0.2-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:901e3b4219fa04ef766885fb40fa516a71662a4c61b80c94d25336b4934b71c0", size = 5055054, upload-time = "2025-09-22T04:02:38.154Z" }, + { url = "https://files.pythonhosted.org/packages/60/23/6885b451636ae286c34628f70a7ed1fcc759f8d9ad382d132e1c8d3d9bfd/lxml-6.0.2-cp314-cp314-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:a4bf42d2e4cf52c28cc1812d62426b9503cdb0c87a6de81442626aa7d69707ba", size = 5352421, upload-time = "2025-09-22T04:02:40.413Z" }, + { url = "https://files.pythonhosted.org/packages/48/5b/fc2ddfc94ddbe3eebb8e9af6e3fd65e2feba4967f6a4e9683875c394c2d8/lxml-6.0.2-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b2c7fdaa4d7c3d886a42534adec7cfac73860b89b4e5298752f60aa5984641a0", size = 5673684, upload-time = "2025-09-22T04:02:42.288Z" }, + { url = "https://files.pythonhosted.org/packages/29/9c/47293c58cc91769130fbf85531280e8cc7868f7fbb6d92f4670071b9cb3e/lxml-6.0.2-cp314-cp314-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:98a5e1660dc7de2200b00d53fa00bcd3c35a3608c305d45a7bbcaf29fa16e83d", size = 5252463, upload-time = "2025-09-22T04:02:44.165Z" }, + { url = "https://files.pythonhosted.org/packages/9b/da/ba6eceb830c762b48e711ded880d7e3e89fc6c7323e587c36540b6b23c6b/lxml-6.0.2-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:dc051506c30b609238d79eda75ee9cab3e520570ec8219844a72a46020901e37", size = 4698437, upload-time = "2025-09-22T04:02:46.524Z" }, + { url = "https://files.pythonhosted.org/packages/a5/24/7be3f82cb7990b89118d944b619e53c656c97dc89c28cfb143fdb7cd6f4d/lxml-6.0.2-cp314-cp314-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8799481bbdd212470d17513a54d568f44416db01250f49449647b5ab5b5dccb9", size = 5269890, upload-time = "2025-09-22T04:02:48.812Z" }, + { url = "https://files.pythonhosted.org/packages/1b/bd/dcfb9ea1e16c665efd7538fc5d5c34071276ce9220e234217682e7d2c4a5/lxml-6.0.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9261bb77c2dab42f3ecd9103951aeca2c40277701eb7e912c545c1b16e0e4917", size = 5097185, upload-time = "2025-09-22T04:02:50.746Z" }, + { url = "https://files.pythonhosted.org/packages/21/04/a60b0ff9314736316f28316b694bccbbabe100f8483ad83852d77fc7468e/lxml-6.0.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:65ac4a01aba353cfa6d5725b95d7aed6356ddc0a3cd734de00124d285b04b64f", size = 4745895, upload-time = "2025-09-22T04:02:52.968Z" }, + { url = "https://files.pythonhosted.org/packages/d6/bd/7d54bd1846e5a310d9c715921c5faa71cf5c0853372adf78aee70c8d7aa2/lxml-6.0.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:b22a07cbb82fea98f8a2fd814f3d1811ff9ed76d0fc6abc84eb21527596e7cc8", size = 5695246, upload-time = "2025-09-22T04:02:54.798Z" }, + { url = "https://files.pythonhosted.org/packages/fd/32/5643d6ab947bc371da21323acb2a6e603cedbe71cb4c99c8254289ab6f4e/lxml-6.0.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:d759cdd7f3e055d6bc8d9bec3ad905227b2e4c785dc16c372eb5b5e83123f48a", size = 5260797, upload-time = "2025-09-22T04:02:57.058Z" }, + { url = "https://files.pythonhosted.org/packages/33/da/34c1ec4cff1eea7d0b4cd44af8411806ed943141804ac9c5d565302afb78/lxml-6.0.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:945da35a48d193d27c188037a05fec5492937f66fb1958c24fc761fb9d40d43c", size = 5277404, upload-time = "2025-09-22T04:02:58.966Z" }, + { url = "https://files.pythonhosted.org/packages/82/57/4eca3e31e54dc89e2c3507e1cd411074a17565fa5ffc437c4ae0a00d439e/lxml-6.0.2-cp314-cp314-win32.whl", hash = "sha256:be3aaa60da67e6153eb15715cc2e19091af5dc75faef8b8a585aea372507384b", size = 3670072, upload-time = "2025-09-22T04:03:38.05Z" }, + { url = "https://files.pythonhosted.org/packages/e3/e0/c96cf13eccd20c9421ba910304dae0f619724dcf1702864fd59dd386404d/lxml-6.0.2-cp314-cp314-win_amd64.whl", hash = "sha256:fa25afbadead523f7001caf0c2382afd272c315a033a7b06336da2637d92d6ed", size = 4080617, upload-time = "2025-09-22T04:03:39.835Z" }, + { url = "https://files.pythonhosted.org/packages/d5/5d/b3f03e22b3d38d6f188ef044900a9b29b2fe0aebb94625ce9fe244011d34/lxml-6.0.2-cp314-cp314-win_arm64.whl", hash = "sha256:063eccf89df5b24e361b123e257e437f9e9878f425ee9aae3144c77faf6da6d8", size = 3754930, upload-time = "2025-09-22T04:03:41.565Z" }, + { url = "https://files.pythonhosted.org/packages/5e/5c/42c2c4c03554580708fc738d13414801f340c04c3eff90d8d2d227145275/lxml-6.0.2-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:6162a86d86893d63084faaf4ff937b3daea233e3682fb4474db07395794fa80d", size = 8910380, upload-time = "2025-09-22T04:03:01.645Z" }, + { url = "https://files.pythonhosted.org/packages/bf/4f/12df843e3e10d18d468a7557058f8d3733e8b6e12401f30b1ef29360740f/lxml-6.0.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:414aaa94e974e23a3e92e7ca5b97d10c0cf37b6481f50911032c69eeb3991bba", size = 4775632, upload-time = "2025-09-22T04:03:03.814Z" }, + { url = "https://files.pythonhosted.org/packages/e4/0c/9dc31e6c2d0d418483cbcb469d1f5a582a1cd00a1f4081953d44051f3c50/lxml-6.0.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:48461bd21625458dd01e14e2c38dd0aea69addc3c4f960c30d9f59d7f93be601", size = 4975171, upload-time = "2025-09-22T04:03:05.651Z" }, + { url = "https://files.pythonhosted.org/packages/e7/2b/9b870c6ca24c841bdd887504808f0417aa9d8d564114689266f19ddf29c8/lxml-6.0.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:25fcc59afc57d527cfc78a58f40ab4c9b8fd096a9a3f964d2781ffb6eb33f4ed", size = 5110109, upload-time = "2025-09-22T04:03:07.452Z" }, + { url = "https://files.pythonhosted.org/packages/bf/0c/4f5f2a4dd319a178912751564471355d9019e220c20d7db3fb8307ed8582/lxml-6.0.2-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5179c60288204e6ddde3f774a93350177e08876eaf3ab78aa3a3649d43eb7d37", size = 5041061, upload-time = "2025-09-22T04:03:09.297Z" }, + { url = "https://files.pythonhosted.org/packages/12/64/554eed290365267671fe001a20d72d14f468ae4e6acef1e179b039436967/lxml-6.0.2-cp314-cp314t-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:967aab75434de148ec80597b75062d8123cadf2943fb4281f385141e18b21338", size = 5306233, upload-time = "2025-09-22T04:03:11.651Z" }, + { url = "https://files.pythonhosted.org/packages/7a/31/1d748aa275e71802ad9722df32a7a35034246b42c0ecdd8235412c3396ef/lxml-6.0.2-cp314-cp314t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d100fcc8930d697c6561156c6810ab4a508fb264c8b6779e6e61e2ed5e7558f9", size = 5604739, upload-time = "2025-09-22T04:03:13.592Z" }, + { url = "https://files.pythonhosted.org/packages/8f/41/2c11916bcac09ed561adccacceaedd2bf0e0b25b297ea92aab99fd03d0fa/lxml-6.0.2-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2ca59e7e13e5981175b8b3e4ab84d7da57993eeff53c07764dcebda0d0e64ecd", size = 5225119, upload-time = "2025-09-22T04:03:15.408Z" }, + { url = "https://files.pythonhosted.org/packages/99/05/4e5c2873d8f17aa018e6afde417c80cc5d0c33be4854cce3ef5670c49367/lxml-6.0.2-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:957448ac63a42e2e49531b9d6c0fa449a1970dbc32467aaad46f11545be9af1d", size = 4633665, upload-time = "2025-09-22T04:03:17.262Z" }, + { url = "https://files.pythonhosted.org/packages/0f/c9/dcc2da1bebd6275cdc723b515f93edf548b82f36a5458cca3578bc899332/lxml-6.0.2-cp314-cp314t-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b7fc49c37f1786284b12af63152fe1d0990722497e2d5817acfe7a877522f9a9", size = 5234997, upload-time = "2025-09-22T04:03:19.14Z" }, + { url = "https://files.pythonhosted.org/packages/9c/e2/5172e4e7468afca64a37b81dba152fc5d90e30f9c83c7c3213d6a02a5ce4/lxml-6.0.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e19e0643cc936a22e837f79d01a550678da8377d7d801a14487c10c34ee49c7e", size = 5090957, upload-time = "2025-09-22T04:03:21.436Z" }, + { url = "https://files.pythonhosted.org/packages/a5/b3/15461fd3e5cd4ddcb7938b87fc20b14ab113b92312fc97afe65cd7c85de1/lxml-6.0.2-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:1db01e5cf14345628e0cbe71067204db658e2fb8e51e7f33631f5f4735fefd8d", size = 4764372, upload-time = "2025-09-22T04:03:23.27Z" }, + { url = "https://files.pythonhosted.org/packages/05/33/f310b987c8bf9e61c4dd8e8035c416bd3230098f5e3cfa69fc4232de7059/lxml-6.0.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:875c6b5ab39ad5291588aed6925fac99d0097af0dd62f33c7b43736043d4a2ec", size = 5634653, upload-time = "2025-09-22T04:03:25.767Z" }, + { url = "https://files.pythonhosted.org/packages/70/ff/51c80e75e0bc9382158133bdcf4e339b5886c6ee2418b5199b3f1a61ed6d/lxml-6.0.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:cdcbed9ad19da81c480dfd6dd161886db6096083c9938ead313d94b30aadf272", size = 5233795, upload-time = "2025-09-22T04:03:27.62Z" }, + { url = "https://files.pythonhosted.org/packages/56/4d/4856e897df0d588789dd844dbed9d91782c4ef0b327f96ce53c807e13128/lxml-6.0.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:80dadc234ebc532e09be1975ff538d154a7fa61ea5031c03d25178855544728f", size = 5257023, upload-time = "2025-09-22T04:03:30.056Z" }, + { url = "https://files.pythonhosted.org/packages/0f/85/86766dfebfa87bea0ab78e9ff7a4b4b45225df4b4d3b8cc3c03c5cd68464/lxml-6.0.2-cp314-cp314t-win32.whl", hash = "sha256:da08e7bb297b04e893d91087df19638dc7a6bb858a954b0cc2b9f5053c922312", size = 3911420, upload-time = "2025-09-22T04:03:32.198Z" }, + { url = "https://files.pythonhosted.org/packages/fe/1a/b248b355834c8e32614650b8008c69ffeb0ceb149c793961dd8c0b991bb3/lxml-6.0.2-cp314-cp314t-win_amd64.whl", hash = "sha256:252a22982dca42f6155125ac76d3432e548a7625d56f5a273ee78a5057216eca", size = 4406837, upload-time = "2025-09-22T04:03:34.027Z" }, + { url = "https://files.pythonhosted.org/packages/92/aa/df863bcc39c5e0946263454aba394de8a9084dbaff8ad143846b0d844739/lxml-6.0.2-cp314-cp314t-win_arm64.whl", hash = "sha256:bb4c1847b303835d89d785a18801a883436cdfd5dc3d62947f9c49e24f0f5a2c", size = 3822205, upload-time = "2025-09-22T04:03:36.249Z" }, + { url = "https://files.pythonhosted.org/packages/e7/9c/780c9a8fce3f04690b374f72f41306866b0400b9d0fdf3e17aaa37887eed/lxml-6.0.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:e748d4cf8fef2526bb2a589a417eba0c8674e29ffcb570ce2ceca44f1e567bf6", size = 3939264, upload-time = "2025-09-22T04:04:32.892Z" }, + { url = "https://files.pythonhosted.org/packages/f5/5a/1ab260c00adf645d8bf7dec7f920f744b032f69130c681302821d5debea6/lxml-6.0.2-pp310-pypy310_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4ddb1049fa0579d0cbd00503ad8c58b9ab34d1254c77bc6a5576d96ec7853dba", size = 4216435, upload-time = "2025-09-22T04:04:34.907Z" }, + { url = "https://files.pythonhosted.org/packages/f2/37/565f3b3d7ffede22874b6d86be1a1763d00f4ea9fc5b9b6ccb11e4ec8612/lxml-6.0.2-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cb233f9c95f83707dae461b12b720c1af9c28c2d19208e1be03387222151daf5", size = 4325913, upload-time = "2025-09-22T04:04:37.205Z" }, + { url = "https://files.pythonhosted.org/packages/22/ec/f3a1b169b2fb9d03467e2e3c0c752ea30e993be440a068b125fc7dd248b0/lxml-6.0.2-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bc456d04db0515ce3320d714a1eac7a97774ff0849e7718b492d957da4631dd4", size = 4269357, upload-time = "2025-09-22T04:04:39.322Z" }, + { url = "https://files.pythonhosted.org/packages/77/a2/585a28fe3e67daa1cf2f06f34490d556d121c25d500b10082a7db96e3bcd/lxml-6.0.2-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2613e67de13d619fd283d58bda40bff0ee07739f624ffee8b13b631abf33083d", size = 4412295, upload-time = "2025-09-22T04:04:41.647Z" }, + { url = "https://files.pythonhosted.org/packages/7b/d9/a57dd8bcebd7c69386c20263830d4fa72d27e6b72a229ef7a48e88952d9a/lxml-6.0.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:24a8e756c982c001ca8d59e87c80c4d9dcd4d9b44a4cbeb8d9be4482c514d41d", size = 3516913, upload-time = "2025-09-22T04:04:43.602Z" }, + { url = "https://files.pythonhosted.org/packages/0b/11/29d08bc103a62c0eba8016e7ed5aeebbf1e4312e83b0b1648dd203b0e87d/lxml-6.0.2-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:1c06035eafa8404b5cf475bb37a9f6088b0aca288d4ccc9d69389750d5543700", size = 3949829, upload-time = "2025-09-22T04:04:45.608Z" }, + { url = "https://files.pythonhosted.org/packages/12/b3/52ab9a3b31e5ab8238da241baa19eec44d2ab426532441ee607165aebb52/lxml-6.0.2-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c7d13103045de1bdd6fe5d61802565f1a3537d70cd3abf596aa0af62761921ee", size = 4226277, upload-time = "2025-09-22T04:04:47.754Z" }, + { url = "https://files.pythonhosted.org/packages/a0/33/1eaf780c1baad88224611df13b1c2a9dfa460b526cacfe769103ff50d845/lxml-6.0.2-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0a3c150a95fbe5ac91de323aa756219ef9cf7fde5a3f00e2281e30f33fa5fa4f", size = 4330433, upload-time = "2025-09-22T04:04:49.907Z" }, + { url = "https://files.pythonhosted.org/packages/7a/c1/27428a2ff348e994ab4f8777d3a0ad510b6b92d37718e5887d2da99952a2/lxml-6.0.2-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:60fa43be34f78bebb27812ed90f1925ec99560b0fa1decdb7d12b84d857d31e9", size = 4272119, upload-time = "2025-09-22T04:04:51.801Z" }, + { url = "https://files.pythonhosted.org/packages/f0/d0/3020fa12bcec4ab62f97aab026d57c2f0cfd480a558758d9ca233bb6a79d/lxml-6.0.2-pp311-pypy311_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:21c73b476d3cfe836be731225ec3421fa2f048d84f6df6a8e70433dff1376d5a", size = 4417314, upload-time = "2025-09-22T04:04:55.024Z" }, + { url = "https://files.pythonhosted.org/packages/6c/77/d7f491cbc05303ac6801651aabeb262d43f319288c1ea96c66b1d2692ff3/lxml-6.0.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:27220da5be049e936c3aca06f174e8827ca6445a4353a1995584311487fc4e3e", size = 3518768, upload-time = "2025-09-22T04:04:57.097Z" }, +] + +[[package]] +name = "mammoth" +version = "1.11.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cobble" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ed/3c/a58418d2af00f2da60d4a51e18cd0311307b72d48d2fffec36a97b4a5e44/mammoth-1.11.0.tar.gz", hash = "sha256:a0f59e442f34d5b6447f4b0999306cbf3e67aaabfa8cb516f878fb1456744637", size = 53142, upload-time = "2025-09-19T10:35:20.373Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ca/54/2e39566a131b13f6d8d193f974cb6a34e81bb7cc2fa6f7e03de067b36588/mammoth-1.11.0-py2.py3-none-any.whl", hash = "sha256:c077ab0d450bd7c0c6ecd529a23bf7e0fa8190c929e28998308ff4eada3f063b", size = 54752, upload-time = "2025-09-19T10:35:18.699Z" }, +] + [[package]] name = "markdown-it-py" version = "4.0.0" @@ -1141,6 +2004,104 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" }, ] +[[package]] +name = "markdownify" +version = "1.2.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "beautifulsoup4" }, + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3f/bc/c8c8eea5335341306b0fa7e1cb33c5e1c8d24ef70ddd684da65f41c49c92/markdownify-1.2.2.tar.gz", hash = "sha256:b274f1b5943180b031b699b199cbaeb1e2ac938b75851849a31fd0c3d6603d09", size = 18816, upload-time = "2025-11-16T19:21:18.565Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/43/ce/f1e3e9d959db134cedf06825fae8d5b294bd368aacdd0831a3975b7c4d55/markdownify-1.2.2-py3-none-any.whl", hash = "sha256:3f02d3cc52714084d6e589f70397b6fc9f2f3a8531481bf35e8cc39f975e186a", size = 15724, upload-time = "2025-11-16T19:21:17.622Z" }, +] + +[[package]] +name = "markupsafe" +version = "3.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e8/4b/3541d44f3937ba468b75da9eebcae497dcf67adb65caa16760b0a6807ebb/markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559", size = 11631, upload-time = "2025-09-27T18:36:05.558Z" }, + { url = "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419", size = 12057, upload-time = "2025-09-27T18:36:07.165Z" }, + { url = "https://files.pythonhosted.org/packages/40/01/e560d658dc0bb8ab762670ece35281dec7b6c1b33f5fbc09ebb57a185519/markupsafe-3.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695", size = 22050, upload-time = "2025-09-27T18:36:08.005Z" }, + { url = "https://files.pythonhosted.org/packages/af/cd/ce6e848bbf2c32314c9b237839119c5a564a59725b53157c856e90937b7a/markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591", size = 20681, upload-time = "2025-09-27T18:36:08.881Z" }, + { url = "https://files.pythonhosted.org/packages/c9/2a/b5c12c809f1c3045c4d580b035a743d12fcde53cf685dbc44660826308da/markupsafe-3.0.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c", size = 20705, upload-time = "2025-09-27T18:36:10.131Z" }, + { url = "https://files.pythonhosted.org/packages/cf/e3/9427a68c82728d0a88c50f890d0fc072a1484de2f3ac1ad0bfc1a7214fd5/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f", size = 21524, upload-time = "2025-09-27T18:36:11.324Z" }, + { url = "https://files.pythonhosted.org/packages/bc/36/23578f29e9e582a4d0278e009b38081dbe363c5e7165113fad546918a232/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6", size = 20282, upload-time = "2025-09-27T18:36:12.573Z" }, + { url = "https://files.pythonhosted.org/packages/56/21/dca11354e756ebd03e036bd8ad58d6d7168c80ce1fe5e75218e4945cbab7/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1", size = 20745, upload-time = "2025-09-27T18:36:13.504Z" }, + { url = "https://files.pythonhosted.org/packages/87/99/faba9369a7ad6e4d10b6a5fbf71fa2a188fe4a593b15f0963b73859a1bbd/markupsafe-3.0.3-cp310-cp310-win32.whl", hash = "sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa", size = 14571, upload-time = "2025-09-27T18:36:14.779Z" }, + { url = "https://files.pythonhosted.org/packages/d6/25/55dc3ab959917602c96985cb1253efaa4ff42f71194bddeb61eb7278b8be/markupsafe-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8", size = 15056, upload-time = "2025-09-27T18:36:16.125Z" }, + { url = "https://files.pythonhosted.org/packages/d0/9e/0a02226640c255d1da0b8d12e24ac2aa6734da68bff14c05dd53b94a0fc3/markupsafe-3.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1", size = 13932, upload-time = "2025-09-27T18:36:17.311Z" }, + { url = "https://files.pythonhosted.org/packages/08/db/fefacb2136439fc8dd20e797950e749aa1f4997ed584c62cfb8ef7c2be0e/markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad", size = 11631, upload-time = "2025-09-27T18:36:18.185Z" }, + { url = "https://files.pythonhosted.org/packages/e1/2e/5898933336b61975ce9dc04decbc0a7f2fee78c30353c5efba7f2d6ff27a/markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a", size = 12058, upload-time = "2025-09-27T18:36:19.444Z" }, + { url = "https://files.pythonhosted.org/packages/1d/09/adf2df3699d87d1d8184038df46a9c80d78c0148492323f4693df54e17bb/markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50", size = 24287, upload-time = "2025-09-27T18:36:20.768Z" }, + { url = "https://files.pythonhosted.org/packages/30/ac/0273f6fcb5f42e314c6d8cd99effae6a5354604d461b8d392b5ec9530a54/markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf", size = 22940, upload-time = "2025-09-27T18:36:22.249Z" }, + { url = "https://files.pythonhosted.org/packages/19/ae/31c1be199ef767124c042c6c3e904da327a2f7f0cd63a0337e1eca2967a8/markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f", size = 21887, upload-time = "2025-09-27T18:36:23.535Z" }, + { url = "https://files.pythonhosted.org/packages/b2/76/7edcab99d5349a4532a459e1fe64f0b0467a3365056ae550d3bcf3f79e1e/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a", size = 23692, upload-time = "2025-09-27T18:36:24.823Z" }, + { url = "https://files.pythonhosted.org/packages/a4/28/6e74cdd26d7514849143d69f0bf2399f929c37dc2b31e6829fd2045b2765/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115", size = 21471, upload-time = "2025-09-27T18:36:25.95Z" }, + { url = "https://files.pythonhosted.org/packages/62/7e/a145f36a5c2945673e590850a6f8014318d5577ed7e5920a4b3448e0865d/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a", size = 22923, upload-time = "2025-09-27T18:36:27.109Z" }, + { url = "https://files.pythonhosted.org/packages/0f/62/d9c46a7f5c9adbeeeda52f5b8d802e1094e9717705a645efc71b0913a0a8/markupsafe-3.0.3-cp311-cp311-win32.whl", hash = "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19", size = 14572, upload-time = "2025-09-27T18:36:28.045Z" }, + { url = "https://files.pythonhosted.org/packages/83/8a/4414c03d3f891739326e1783338e48fb49781cc915b2e0ee052aa490d586/markupsafe-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01", size = 15077, upload-time = "2025-09-27T18:36:29.025Z" }, + { url = "https://files.pythonhosted.org/packages/35/73/893072b42e6862f319b5207adc9ae06070f095b358655f077f69a35601f0/markupsafe-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c", size = 13876, upload-time = "2025-09-27T18:36:29.954Z" }, + { url = "https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", size = 11615, upload-time = "2025-09-27T18:36:30.854Z" }, + { url = "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", size = 12020, upload-time = "2025-09-27T18:36:31.971Z" }, + { url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", size = 24332, upload-time = "2025-09-27T18:36:32.813Z" }, + { url = "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", size = 22947, upload-time = "2025-09-27T18:36:33.86Z" }, + { url = "https://files.pythonhosted.org/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", size = 21962, upload-time = "2025-09-27T18:36:35.099Z" }, + { url = "https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", size = 23760, upload-time = "2025-09-27T18:36:36.001Z" }, + { url = "https://files.pythonhosted.org/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", size = 21529, upload-time = "2025-09-27T18:36:36.906Z" }, + { url = "https://files.pythonhosted.org/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", size = 23015, upload-time = "2025-09-27T18:36:37.868Z" }, + { url = "https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", size = 14540, upload-time = "2025-09-27T18:36:38.761Z" }, + { url = "https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", size = 15105, upload-time = "2025-09-27T18:36:39.701Z" }, + { url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size = 13906, upload-time = "2025-09-27T18:36:40.689Z" }, + { url = "https://files.pythonhosted.org/packages/38/2f/907b9c7bbba283e68f20259574b13d005c121a0fa4c175f9bed27c4597ff/markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795", size = 11622, upload-time = "2025-09-27T18:36:41.777Z" }, + { url = "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219", size = 12029, upload-time = "2025-09-27T18:36:43.257Z" }, + { url = "https://files.pythonhosted.org/packages/00/07/575a68c754943058c78f30db02ee03a64b3c638586fba6a6dd56830b30a3/markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6", size = 24374, upload-time = "2025-09-27T18:36:44.508Z" }, + { url = "https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676", size = 22980, upload-time = "2025-09-27T18:36:45.385Z" }, + { url = "https://files.pythonhosted.org/packages/7f/71/544260864f893f18b6827315b988c146b559391e6e7e8f7252839b1b846a/markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9", size = 21990, upload-time = "2025-09-27T18:36:46.916Z" }, + { url = "https://files.pythonhosted.org/packages/c2/28/b50fc2f74d1ad761af2f5dcce7492648b983d00a65b8c0e0cb457c82ebbe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1", size = 23784, upload-time = "2025-09-27T18:36:47.884Z" }, + { url = "https://files.pythonhosted.org/packages/ed/76/104b2aa106a208da8b17a2fb72e033a5a9d7073c68f7e508b94916ed47a9/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc", size = 21588, upload-time = "2025-09-27T18:36:48.82Z" }, + { url = "https://files.pythonhosted.org/packages/b5/99/16a5eb2d140087ebd97180d95249b00a03aa87e29cc224056274f2e45fd6/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12", size = 23041, upload-time = "2025-09-27T18:36:49.797Z" }, + { url = "https://files.pythonhosted.org/packages/19/bc/e7140ed90c5d61d77cea142eed9f9c303f4c4806f60a1044c13e3f1471d0/markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed", size = 14543, upload-time = "2025-09-27T18:36:51.584Z" }, + { url = "https://files.pythonhosted.org/packages/05/73/c4abe620b841b6b791f2edc248f556900667a5a1cf023a6646967ae98335/markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5", size = 15113, upload-time = "2025-09-27T18:36:52.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/3a/fa34a0f7cfef23cf9500d68cb7c32dd64ffd58a12b09225fb03dd37d5b80/markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485", size = 13911, upload-time = "2025-09-27T18:36:53.513Z" }, + { url = "https://files.pythonhosted.org/packages/e4/d7/e05cd7efe43a88a17a37b3ae96e79a19e846f3f456fe79c57ca61356ef01/markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73", size = 11658, upload-time = "2025-09-27T18:36:54.819Z" }, + { url = "https://files.pythonhosted.org/packages/99/9e/e412117548182ce2148bdeacdda3bb494260c0b0184360fe0d56389b523b/markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37", size = 12066, upload-time = "2025-09-27T18:36:55.714Z" }, + { url = "https://files.pythonhosted.org/packages/bc/e6/fa0ffcda717ef64a5108eaa7b4f5ed28d56122c9a6d70ab8b72f9f715c80/markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19", size = 25639, upload-time = "2025-09-27T18:36:56.908Z" }, + { url = "https://files.pythonhosted.org/packages/96/ec/2102e881fe9d25fc16cb4b25d5f5cde50970967ffa5dddafdb771237062d/markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025", size = 23569, upload-time = "2025-09-27T18:36:57.913Z" }, + { url = "https://files.pythonhosted.org/packages/4b/30/6f2fce1f1f205fc9323255b216ca8a235b15860c34b6798f810f05828e32/markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6", size = 23284, upload-time = "2025-09-27T18:36:58.833Z" }, + { url = "https://files.pythonhosted.org/packages/58/47/4a0ccea4ab9f5dcb6f79c0236d954acb382202721e704223a8aafa38b5c8/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f", size = 24801, upload-time = "2025-09-27T18:36:59.739Z" }, + { url = "https://files.pythonhosted.org/packages/6a/70/3780e9b72180b6fecb83a4814d84c3bf4b4ae4bf0b19c27196104149734c/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb", size = 22769, upload-time = "2025-09-27T18:37:00.719Z" }, + { url = "https://files.pythonhosted.org/packages/98/c5/c03c7f4125180fc215220c035beac6b9cb684bc7a067c84fc69414d315f5/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009", size = 23642, upload-time = "2025-09-27T18:37:01.673Z" }, + { url = "https://files.pythonhosted.org/packages/80/d6/2d1b89f6ca4bff1036499b1e29a1d02d282259f3681540e16563f27ebc23/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354", size = 14612, upload-time = "2025-09-27T18:37:02.639Z" }, + { url = "https://files.pythonhosted.org/packages/2b/98/e48a4bfba0a0ffcf9925fe2d69240bfaa19c6f7507b8cd09c70684a53c1e/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218", size = 15200, upload-time = "2025-09-27T18:37:03.582Z" }, + { url = "https://files.pythonhosted.org/packages/0e/72/e3cc540f351f316e9ed0f092757459afbc595824ca724cbc5a5d4263713f/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287", size = 13973, upload-time = "2025-09-27T18:37:04.929Z" }, + { url = "https://files.pythonhosted.org/packages/33/8a/8e42d4838cd89b7dde187011e97fe6c3af66d8c044997d2183fbd6d31352/markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe", size = 11619, upload-time = "2025-09-27T18:37:06.342Z" }, + { url = "https://files.pythonhosted.org/packages/b5/64/7660f8a4a8e53c924d0fa05dc3a55c9cee10bbd82b11c5afb27d44b096ce/markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026", size = 12029, upload-time = "2025-09-27T18:37:07.213Z" }, + { url = "https://files.pythonhosted.org/packages/da/ef/e648bfd021127bef5fa12e1720ffed0c6cbb8310c8d9bea7266337ff06de/markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737", size = 24408, upload-time = "2025-09-27T18:37:09.572Z" }, + { url = "https://files.pythonhosted.org/packages/41/3c/a36c2450754618e62008bf7435ccb0f88053e07592e6028a34776213d877/markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97", size = 23005, upload-time = "2025-09-27T18:37:10.58Z" }, + { url = "https://files.pythonhosted.org/packages/bc/20/b7fdf89a8456b099837cd1dc21974632a02a999ec9bf7ca3e490aacd98e7/markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d", size = 22048, upload-time = "2025-09-27T18:37:11.547Z" }, + { url = "https://files.pythonhosted.org/packages/9a/a7/591f592afdc734f47db08a75793a55d7fbcc6902a723ae4cfbab61010cc5/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda", size = 23821, upload-time = "2025-09-27T18:37:12.48Z" }, + { url = "https://files.pythonhosted.org/packages/7d/33/45b24e4f44195b26521bc6f1a82197118f74df348556594bd2262bda1038/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf", size = 21606, upload-time = "2025-09-27T18:37:13.485Z" }, + { url = "https://files.pythonhosted.org/packages/ff/0e/53dfaca23a69fbfbbf17a4b64072090e70717344c52eaaaa9c5ddff1e5f0/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe", size = 23043, upload-time = "2025-09-27T18:37:14.408Z" }, + { url = "https://files.pythonhosted.org/packages/46/11/f333a06fc16236d5238bfe74daccbca41459dcd8d1fa952e8fbd5dccfb70/markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9", size = 14747, upload-time = "2025-09-27T18:37:15.36Z" }, + { url = "https://files.pythonhosted.org/packages/28/52/182836104b33b444e400b14f797212f720cbc9ed6ba34c800639d154e821/markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581", size = 15341, upload-time = "2025-09-27T18:37:16.496Z" }, + { url = "https://files.pythonhosted.org/packages/6f/18/acf23e91bd94fd7b3031558b1f013adfa21a8e407a3fdb32745538730382/markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4", size = 14073, upload-time = "2025-09-27T18:37:17.476Z" }, + { url = "https://files.pythonhosted.org/packages/3c/f0/57689aa4076e1b43b15fdfa646b04653969d50cf30c32a102762be2485da/markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab", size = 11661, upload-time = "2025-09-27T18:37:18.453Z" }, + { url = "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175", size = 12069, upload-time = "2025-09-27T18:37:19.332Z" }, + { url = "https://files.pythonhosted.org/packages/f0/00/be561dce4e6ca66b15276e184ce4b8aec61fe83662cce2f7d72bd3249d28/markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634", size = 25670, upload-time = "2025-09-27T18:37:20.245Z" }, + { url = "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50", size = 23598, upload-time = "2025-09-27T18:37:21.177Z" }, + { url = "https://files.pythonhosted.org/packages/22/44/a0681611106e0b2921b3033fc19bc53323e0b50bc70cffdd19f7d679bb66/markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e", size = 23261, upload-time = "2025-09-27T18:37:22.167Z" }, + { url = "https://files.pythonhosted.org/packages/5f/57/1b0b3f100259dc9fffe780cfb60d4be71375510e435efec3d116b6436d43/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5", size = 24835, upload-time = "2025-09-27T18:37:23.296Z" }, + { url = "https://files.pythonhosted.org/packages/26/6a/4bf6d0c97c4920f1597cc14dd720705eca0bf7c787aebc6bb4d1bead5388/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523", size = 22733, upload-time = "2025-09-27T18:37:24.237Z" }, + { url = "https://files.pythonhosted.org/packages/14/c7/ca723101509b518797fedc2fdf79ba57f886b4aca8a7d31857ba3ee8281f/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc", size = 23672, upload-time = "2025-09-27T18:37:25.271Z" }, + { url = "https://files.pythonhosted.org/packages/fb/df/5bd7a48c256faecd1d36edc13133e51397e41b73bb77e1a69deab746ebac/markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d", size = 14819, upload-time = "2025-09-27T18:37:26.285Z" }, + { url = "https://files.pythonhosted.org/packages/1a/8a/0402ba61a2f16038b48b39bccca271134be00c5c9f0f623208399333c448/markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9", size = 15426, upload-time = "2025-09-27T18:37:27.316Z" }, + { url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146, upload-time = "2025-09-27T18:37:28.327Z" }, +] + [[package]] name = "mcp" version = "1.26.0" @@ -1206,6 +2167,167 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5e/75/bd9b7bb966668920f06b200e84454c8f3566b102183bc55c5473d96cb2b9/msal_extensions-1.3.1-py3-none-any.whl", hash = "sha256:96d3de4d034504e969ac5e85bae8106c8373b5c6568e4c8fa7af2eca9dbe6bca", size = 20583, upload-time = "2025-03-14T23:51:03.016Z" }, ] +[[package]] +name = "multidict" +version = "6.7.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1a/c2/c2d94cbe6ac1753f3fc980da97b3d930efe1da3af3c9f5125354436c073d/multidict-6.7.1.tar.gz", hash = "sha256:ec6652a1bee61c53a3e5776b6049172c53b6aaba34f18c9ad04f82712bac623d", size = 102010, upload-time = "2026-01-26T02:46:45.979Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/84/0b/19348d4c98980c4851d2f943f8ebafdece2ae7ef737adcfa5994ce8e5f10/multidict-6.7.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c93c3db7ea657dd4637d57e74ab73de31bccefe144d3d4ce370052035bc85fb5", size = 77176, upload-time = "2026-01-26T02:42:59.784Z" }, + { url = "https://files.pythonhosted.org/packages/ef/04/9de3f8077852e3d438215c81e9b691244532d2e05b4270e89ce67b7d103c/multidict-6.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:974e72a2474600827abaeda71af0c53d9ebbc3c2eb7da37b37d7829ae31232d8", size = 44996, upload-time = "2026-01-26T02:43:01.674Z" }, + { url = "https://files.pythonhosted.org/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cdea2e7b2456cfb6694fb113066fd0ec7ea4d67e3a35e1f4cbeea0b448bf5872", size = 44631, upload-time = "2026-01-26T02:43:03.169Z" }, + { url = "https://files.pythonhosted.org/packages/b7/7f/0e3b1390ae772f27501199996b94b52ceeb64fe6f9120a32c6c3f6b781be/multidict-6.7.1-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:17207077e29342fdc2c9a82e4b306f1127bf1ea91f8b71e02d4798a70bb99991", size = 242561, upload-time = "2026-01-26T02:43:04.733Z" }, + { url = "https://files.pythonhosted.org/packages/dd/f4/8719f4f167586af317b69dd3e90f913416c91ca610cac79a45c53f590312/multidict-6.7.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d4f49cb5661344764e4c7c7973e92a47a59b8fc19b6523649ec9dc4960e58a03", size = 242223, upload-time = "2026-01-26T02:43:06.695Z" }, + { url = "https://files.pythonhosted.org/packages/47/ab/7c36164cce64a6ad19c6d9a85377b7178ecf3b89f8fd589c73381a5eedfd/multidict-6.7.1-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a9fc4caa29e2e6ae408d1c450ac8bf19892c5fca83ee634ecd88a53332c59981", size = 222322, upload-time = "2026-01-26T02:43:08.472Z" }, + { url = "https://files.pythonhosted.org/packages/f5/79/a25add6fb38035b5337bc5734f296d9afc99163403bbcf56d4170f97eb62/multidict-6.7.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c5f0c21549ab432b57dcc82130f388d84ad8179824cc3f223d5e7cfbfd4143f6", size = 254005, upload-time = "2026-01-26T02:43:10.127Z" }, + { url = "https://files.pythonhosted.org/packages/4a/7b/64a87cf98e12f756fc8bd444b001232ffff2be37288f018ad0d3f0aae931/multidict-6.7.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7dfb78d966b2c906ae1d28ccf6e6712a3cd04407ee5088cd276fe8cb42186190", size = 251173, upload-time = "2026-01-26T02:43:11.731Z" }, + { url = "https://files.pythonhosted.org/packages/4b/ac/b605473de2bb404e742f2cc3583d12aedb2352a70e49ae8fce455b50c5aa/multidict-6.7.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9b0d9b91d1aa44db9c1f1ecd0d9d2ae610b2f4f856448664e01a3b35899f3f92", size = 243273, upload-time = "2026-01-26T02:43:13.063Z" }, + { url = "https://files.pythonhosted.org/packages/03/65/11492d6a0e259783720f3bc1d9ea55579a76f1407e31ed44045c99542004/multidict-6.7.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:dd96c01a9dcd4889dcfcf9eb5544ca0c77603f239e3ffab0524ec17aea9a93ee", size = 238956, upload-time = "2026-01-26T02:43:14.843Z" }, + { url = "https://files.pythonhosted.org/packages/5f/a7/7ee591302af64e7c196fb63fe856c788993c1372df765102bd0448e7e165/multidict-6.7.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:067343c68cd6612d375710f895337b3a98a033c94f14b9a99eff902f205424e2", size = 233477, upload-time = "2026-01-26T02:43:16.025Z" }, + { url = "https://files.pythonhosted.org/packages/9c/99/c109962d58756c35fd9992fed7f2355303846ea2ff054bb5f5e9d6b888de/multidict-6.7.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:5884a04f4ff56c6120f6ccf703bdeb8b5079d808ba604d4d53aec0d55dc33568", size = 243615, upload-time = "2026-01-26T02:43:17.84Z" }, + { url = "https://files.pythonhosted.org/packages/d5/5f/1973e7c771c86e93dcfe1c9cc55a5481b610f6614acfc28c0d326fe6bfad/multidict-6.7.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8affcf1c98b82bc901702eb73b6947a1bfa170823c153fe8a47b5f5f02e48e40", size = 249930, upload-time = "2026-01-26T02:43:19.06Z" }, + { url = "https://files.pythonhosted.org/packages/5d/a5/f170fc2268c3243853580203378cd522446b2df632061e0a5409817854c7/multidict-6.7.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:0d17522c37d03e85c8098ec8431636309b2682cf12e58f4dbc76121fb50e4962", size = 243807, upload-time = "2026-01-26T02:43:20.286Z" }, + { url = "https://files.pythonhosted.org/packages/de/01/73856fab6d125e5bc652c3986b90e8699a95e84b48d72f39ade6c0e74a8c/multidict-6.7.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:24c0cf81544ca5e17cfcb6e482e7a82cd475925242b308b890c9452a074d4505", size = 239103, upload-time = "2026-01-26T02:43:21.508Z" }, + { url = "https://files.pythonhosted.org/packages/e7/46/f1220bd9944d8aa40d8ccff100eeeee19b505b857b6f603d6078cb5315b0/multidict-6.7.1-cp310-cp310-win32.whl", hash = "sha256:d82dd730a95e6643802f4454b8fdecdf08667881a9c5670db85bc5a56693f122", size = 41416, upload-time = "2026-01-26T02:43:22.703Z" }, + { url = "https://files.pythonhosted.org/packages/68/00/9b38e272a770303692fc406c36e1a4c740f401522d5787691eb38a8925a8/multidict-6.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:cf37cbe5ced48d417ba045aca1b21bafca67489452debcde94778a576666a1df", size = 46022, upload-time = "2026-01-26T02:43:23.77Z" }, + { url = "https://files.pythonhosted.org/packages/64/65/d8d42490c02ee07b6bbe00f7190d70bb4738b3cce7629aaf9f213ef730dd/multidict-6.7.1-cp310-cp310-win_arm64.whl", hash = "sha256:59bc83d3f66b41dac1e7460aac1d196edc70c9ba3094965c467715a70ecb46db", size = 43238, upload-time = "2026-01-26T02:43:24.882Z" }, + { url = "https://files.pythonhosted.org/packages/ce/f1/a90635c4f88fb913fbf4ce660b83b7445b7a02615bda034b2f8eb38fd597/multidict-6.7.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7ff981b266af91d7b4b3793ca3382e53229088d193a85dfad6f5f4c27fc73e5d", size = 76626, upload-time = "2026-01-26T02:43:26.485Z" }, + { url = "https://files.pythonhosted.org/packages/a6/9b/267e64eaf6fc637a15b35f5de31a566634a2740f97d8d094a69d34f524a4/multidict-6.7.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:844c5bca0b5444adb44a623fb0a1310c2f4cd41f402126bb269cd44c9b3f3e1e", size = 44706, upload-time = "2026-01-26T02:43:27.607Z" }, + { url = "https://files.pythonhosted.org/packages/dd/a4/d45caf2b97b035c57267791ecfaafbd59c68212004b3842830954bb4b02e/multidict-6.7.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f2a0a924d4c2e9afcd7ec64f9de35fcd96915149b2216e1cb2c10a56df483855", size = 44356, upload-time = "2026-01-26T02:43:28.661Z" }, + { url = "https://files.pythonhosted.org/packages/fd/d2/0a36c8473f0cbaeadd5db6c8b72d15bbceeec275807772bfcd059bef487d/multidict-6.7.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:8be1802715a8e892c784c0197c2ace276ea52702a0ede98b6310c8f255a5afb3", size = 244355, upload-time = "2026-01-26T02:43:31.165Z" }, + { url = "https://files.pythonhosted.org/packages/5d/16/8c65be997fd7dd311b7d39c7b6e71a0cb449bad093761481eccbbe4b42a2/multidict-6.7.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2e2d2ed645ea29f31c4c7ea1552fcfd7cb7ba656e1eafd4134a6620c9f5fdd9e", size = 246433, upload-time = "2026-01-26T02:43:32.581Z" }, + { url = "https://files.pythonhosted.org/packages/01/fb/4dbd7e848d2799c6a026ec88ad39cf2b8416aa167fcc903baa55ecaa045c/multidict-6.7.1-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:95922cee9a778659e91db6497596435777bd25ed116701a4c034f8e46544955a", size = 225376, upload-time = "2026-01-26T02:43:34.417Z" }, + { url = "https://files.pythonhosted.org/packages/b6/8a/4a3a6341eac3830f6053062f8fbc9a9e54407c80755b3f05bc427295c2d0/multidict-6.7.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6b83cabdc375ffaaa15edd97eb7c0c672ad788e2687004990074d7d6c9b140c8", size = 257365, upload-time = "2026-01-26T02:43:35.741Z" }, + { url = "https://files.pythonhosted.org/packages/f7/a2/dd575a69c1aa206e12d27d0770cdf9b92434b48a9ef0cd0d1afdecaa93c4/multidict-6.7.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:38fb49540705369bab8484db0689d86c0a33a0a9f2c1b197f506b71b4b6c19b0", size = 254747, upload-time = "2026-01-26T02:43:36.976Z" }, + { url = "https://files.pythonhosted.org/packages/5a/56/21b27c560c13822ed93133f08aa6372c53a8e067f11fbed37b4adcdac922/multidict-6.7.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:439cbebd499f92e9aa6793016a8acaa161dfa749ae86d20960189f5398a19144", size = 246293, upload-time = "2026-01-26T02:43:38.258Z" }, + { url = "https://files.pythonhosted.org/packages/5a/a4/23466059dc3854763423d0ad6c0f3683a379d97673b1b89ec33826e46728/multidict-6.7.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6d3bc717b6fe763b8be3f2bee2701d3c8eb1b2a8ae9f60910f1b2860c82b6c49", size = 242962, upload-time = "2026-01-26T02:43:40.034Z" }, + { url = "https://files.pythonhosted.org/packages/1f/67/51dd754a3524d685958001e8fa20a0f5f90a6a856e0a9dcabff69be3dbb7/multidict-6.7.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:619e5a1ac57986dbfec9f0b301d865dddf763696435e2962f6d9cf2fdff2bb71", size = 237360, upload-time = "2026-01-26T02:43:41.752Z" }, + { url = "https://files.pythonhosted.org/packages/64/3f/036dfc8c174934d4b55d86ff4f978e558b0e585cef70cfc1ad01adc6bf18/multidict-6.7.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0b38ebffd9be37c1170d33bc0f36f4f262e0a09bc1aac1c34c7aa51a7293f0b3", size = 245940, upload-time = "2026-01-26T02:43:43.042Z" }, + { url = "https://files.pythonhosted.org/packages/3d/20/6214d3c105928ebc353a1c644a6ef1408bc5794fcb4f170bb524a3c16311/multidict-6.7.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:10ae39c9cfe6adedcdb764f5e8411d4a92b055e35573a2eaa88d3323289ef93c", size = 253502, upload-time = "2026-01-26T02:43:44.371Z" }, + { url = "https://files.pythonhosted.org/packages/b1/e2/c653bc4ae1be70a0f836b82172d643fcf1dade042ba2676ab08ec08bff0f/multidict-6.7.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:25167cc263257660290fba06b9318d2026e3c910be240a146e1f66dd114af2b0", size = 247065, upload-time = "2026-01-26T02:43:45.745Z" }, + { url = "https://files.pythonhosted.org/packages/c8/11/a854b4154cd3bd8b1fd375e8a8ca9d73be37610c361543d56f764109509b/multidict-6.7.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:128441d052254f42989ef98b7b6a6ecb1e6f708aa962c7984235316db59f50fa", size = 241870, upload-time = "2026-01-26T02:43:47.054Z" }, + { url = "https://files.pythonhosted.org/packages/13/bf/9676c0392309b5fdae322333d22a829715b570edb9baa8016a517b55b558/multidict-6.7.1-cp311-cp311-win32.whl", hash = "sha256:d62b7f64ffde3b99d06b707a280db04fb3855b55f5a06df387236051d0668f4a", size = 41302, upload-time = "2026-01-26T02:43:48.753Z" }, + { url = "https://files.pythonhosted.org/packages/c9/68/f16a3a8ba6f7b6dc92a1f19669c0810bd2c43fc5a02da13b1cbf8e253845/multidict-6.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:bdbf9f3b332abd0cdb306e7c2113818ab1e922dc84b8f8fd06ec89ed2a19ab8b", size = 45981, upload-time = "2026-01-26T02:43:49.921Z" }, + { url = "https://files.pythonhosted.org/packages/ac/ad/9dd5305253fa00cd3c7555dbef69d5bf4133debc53b87ab8d6a44d411665/multidict-6.7.1-cp311-cp311-win_arm64.whl", hash = "sha256:b8c990b037d2fff2f4e33d3f21b9b531c5745b33a49a7d6dbe7a177266af44f6", size = 43159, upload-time = "2026-01-26T02:43:51.635Z" }, + { url = "https://files.pythonhosted.org/packages/8d/9c/f20e0e2cf80e4b2e4b1c365bf5fe104ee633c751a724246262db8f1a0b13/multidict-6.7.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a90f75c956e32891a4eda3639ce6dd86e87105271f43d43442a3aedf3cddf172", size = 76893, upload-time = "2026-01-26T02:43:52.754Z" }, + { url = "https://files.pythonhosted.org/packages/fe/cf/18ef143a81610136d3da8193da9d80bfe1cb548a1e2d1c775f26b23d024a/multidict-6.7.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3fccb473e87eaa1382689053e4a4618e7ba7b9b9b8d6adf2027ee474597128cd", size = 45456, upload-time = "2026-01-26T02:43:53.893Z" }, + { url = "https://files.pythonhosted.org/packages/a9/65/1caac9d4cd32e8433908683446eebc953e82d22b03d10d41a5f0fefe991b/multidict-6.7.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b0fa96985700739c4c7853a43c0b3e169360d6855780021bfc6d0f1ce7c123e7", size = 43872, upload-time = "2026-01-26T02:43:55.041Z" }, + { url = "https://files.pythonhosted.org/packages/cf/3b/d6bd75dc4f3ff7c73766e04e705b00ed6dbbaccf670d9e05a12b006f5a21/multidict-6.7.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:cb2a55f408c3043e42b40cc8eecd575afa27b7e0b956dfb190de0f8499a57a53", size = 251018, upload-time = "2026-01-26T02:43:56.198Z" }, + { url = "https://files.pythonhosted.org/packages/fd/80/c959c5933adedb9ac15152e4067c702a808ea183a8b64cf8f31af8ad3155/multidict-6.7.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eb0ce7b2a32d09892b3dd6cc44877a0d02a33241fafca5f25c8b6b62374f8b75", size = 258883, upload-time = "2026-01-26T02:43:57.499Z" }, + { url = "https://files.pythonhosted.org/packages/86/85/7ed40adafea3d4f1c8b916e3b5cc3a8e07dfcdcb9cd72800f4ed3ca1b387/multidict-6.7.1-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c3a32d23520ee37bf327d1e1a656fec76a2edd5c038bf43eddfa0572ec49c60b", size = 242413, upload-time = "2026-01-26T02:43:58.755Z" }, + { url = "https://files.pythonhosted.org/packages/d2/57/b8565ff533e48595503c785f8361ff9a4fde4d67de25c207cd0ba3befd03/multidict-6.7.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9c90fed18bffc0189ba814749fdcc102b536e83a9f738a9003e569acd540a733", size = 268404, upload-time = "2026-01-26T02:44:00.216Z" }, + { url = "https://files.pythonhosted.org/packages/e0/50/9810c5c29350f7258180dfdcb2e52783a0632862eb334c4896ac717cebcb/multidict-6.7.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:da62917e6076f512daccfbbde27f46fed1c98fee202f0559adec8ee0de67f71a", size = 269456, upload-time = "2026-01-26T02:44:02.202Z" }, + { url = "https://files.pythonhosted.org/packages/f3/8d/5e5be3ced1d12966fefb5c4ea3b2a5b480afcea36406559442c6e31d4a48/multidict-6.7.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bfde23ef6ed9db7eaee6c37dcec08524cb43903c60b285b172b6c094711b3961", size = 256322, upload-time = "2026-01-26T02:44:03.56Z" }, + { url = "https://files.pythonhosted.org/packages/31/6e/d8a26d81ac166a5592782d208dd90dfdc0a7a218adaa52b45a672b46c122/multidict-6.7.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3758692429e4e32f1ba0df23219cd0b4fc0a52f476726fff9337d1a57676a582", size = 253955, upload-time = "2026-01-26T02:44:04.845Z" }, + { url = "https://files.pythonhosted.org/packages/59/4c/7c672c8aad41534ba619bcd4ade7a0dc87ed6b8b5c06149b85d3dd03f0cd/multidict-6.7.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:398c1478926eca669f2fd6a5856b6de9c0acf23a2cb59a14c0ba5844fa38077e", size = 251254, upload-time = "2026-01-26T02:44:06.133Z" }, + { url = "https://files.pythonhosted.org/packages/7b/bd/84c24de512cbafbdbc39439f74e967f19570ce7924e3007174a29c348916/multidict-6.7.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c102791b1c4f3ab36ce4101154549105a53dc828f016356b3e3bcae2e3a039d3", size = 252059, upload-time = "2026-01-26T02:44:07.518Z" }, + { url = "https://files.pythonhosted.org/packages/fa/ba/f5449385510825b73d01c2d4087bf6d2fccc20a2d42ac34df93191d3dd03/multidict-6.7.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a088b62bd733e2ad12c50dad01b7d0166c30287c166e137433d3b410add807a6", size = 263588, upload-time = "2026-01-26T02:44:09.382Z" }, + { url = "https://files.pythonhosted.org/packages/d7/11/afc7c677f68f75c84a69fe37184f0f82fce13ce4b92f49f3db280b7e92b3/multidict-6.7.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3d51ff4785d58d3f6c91bdbffcb5e1f7ddfda557727043aa20d20ec4f65e324a", size = 259642, upload-time = "2026-01-26T02:44:10.73Z" }, + { url = "https://files.pythonhosted.org/packages/2b/17/ebb9644da78c4ab36403739e0e6e0e30ebb135b9caf3440825001a0bddcb/multidict-6.7.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fc5907494fccf3e7d3f94f95c91d6336b092b5fc83811720fae5e2765890dfba", size = 251377, upload-time = "2026-01-26T02:44:12.042Z" }, + { url = "https://files.pythonhosted.org/packages/ca/a4/840f5b97339e27846c46307f2530a2805d9d537d8b8bd416af031cad7fa0/multidict-6.7.1-cp312-cp312-win32.whl", hash = "sha256:28ca5ce2fd9716631133d0e9a9b9a745ad7f60bac2bccafb56aa380fc0b6c511", size = 41887, upload-time = "2026-01-26T02:44:14.245Z" }, + { url = "https://files.pythonhosted.org/packages/80/31/0b2517913687895f5904325c2069d6a3b78f66cc641a86a2baf75a05dcbb/multidict-6.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcee94dfbd638784645b066074b338bc9cc155d4b4bffa4adce1615c5a426c19", size = 46053, upload-time = "2026-01-26T02:44:15.371Z" }, + { url = "https://files.pythonhosted.org/packages/0c/5b/aba28e4ee4006ae4c7df8d327d31025d760ffa992ea23812a601d226e682/multidict-6.7.1-cp312-cp312-win_arm64.whl", hash = "sha256:ba0a9fb644d0c1a2194cf7ffb043bd852cea63a57f66fbd33959f7dae18517bf", size = 43307, upload-time = "2026-01-26T02:44:16.852Z" }, + { url = "https://files.pythonhosted.org/packages/f2/22/929c141d6c0dba87d3e1d38fbdf1ba8baba86b7776469f2bc2d3227a1e67/multidict-6.7.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:2b41f5fed0ed563624f1c17630cb9941cf2309d4df00e494b551b5f3e3d67a23", size = 76174, upload-time = "2026-01-26T02:44:18.509Z" }, + { url = "https://files.pythonhosted.org/packages/c7/75/bc704ae15fee974f8fccd871305e254754167dce5f9e42d88a2def741a1d/multidict-6.7.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:84e61e3af5463c19b67ced91f6c634effb89ef8bfc5ca0267f954451ed4bb6a2", size = 45116, upload-time = "2026-01-26T02:44:19.745Z" }, + { url = "https://files.pythonhosted.org/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:935434b9853c7c112eee7ac891bc4cb86455aa631269ae35442cb316790c1445", size = 43524, upload-time = "2026-01-26T02:44:21.571Z" }, + { url = "https://files.pythonhosted.org/packages/e9/3c/414842ef8d5a1628d68edee29ba0e5bcf235dbfb3ccd3ea303a7fe8c72ff/multidict-6.7.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:432feb25a1cb67fe82a9680b4d65fb542e4635cb3166cd9c01560651ad60f177", size = 249368, upload-time = "2026-01-26T02:44:22.803Z" }, + { url = "https://files.pythonhosted.org/packages/f6/32/befed7f74c458b4a525e60519fe8d87eef72bb1e99924fa2b0f9d97a221e/multidict-6.7.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e82d14e3c948952a1a85503817e038cba5905a3352de76b9a465075d072fba23", size = 256952, upload-time = "2026-01-26T02:44:24.306Z" }, + { url = "https://files.pythonhosted.org/packages/03/d6/c878a44ba877f366630c860fdf74bfb203c33778f12b6ac274936853c451/multidict-6.7.1-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4cfb48c6ea66c83bcaaf7e4dfa7ec1b6bbcf751b7db85a328902796dfde4c060", size = 240317, upload-time = "2026-01-26T02:44:25.772Z" }, + { url = "https://files.pythonhosted.org/packages/68/49/57421b4d7ad2e9e60e25922b08ceb37e077b90444bde6ead629095327a6f/multidict-6.7.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1d540e51b7e8e170174555edecddbd5538105443754539193e3e1061864d444d", size = 267132, upload-time = "2026-01-26T02:44:27.648Z" }, + { url = "https://files.pythonhosted.org/packages/b7/fe/ec0edd52ddbcea2a2e89e174f0206444a61440b40f39704e64dc807a70bd/multidict-6.7.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:273d23f4b40f3dce4d6c8a821c741a86dec62cded82e1175ba3d99be128147ed", size = 268140, upload-time = "2026-01-26T02:44:29.588Z" }, + { url = "https://files.pythonhosted.org/packages/b0/73/6e1b01cbeb458807aa0831742232dbdd1fa92bfa33f52a3f176b4ff3dc11/multidict-6.7.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d624335fd4fa1c08a53f8b4be7676ebde19cd092b3895c421045ca87895b429", size = 254277, upload-time = "2026-01-26T02:44:30.902Z" }, + { url = "https://files.pythonhosted.org/packages/6a/b2/5fb8c124d7561a4974c342bc8c778b471ebbeb3cc17df696f034a7e9afe7/multidict-6.7.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:12fad252f8b267cc75b66e8fc51b3079604e8d43a75428ffe193cd9e2195dfd6", size = 252291, upload-time = "2026-01-26T02:44:32.31Z" }, + { url = "https://files.pythonhosted.org/packages/5a/96/51d4e4e06bcce92577fcd488e22600bd38e4fd59c20cb49434d054903bd2/multidict-6.7.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:03ede2a6ffbe8ef936b92cb4529f27f42be7f56afcdab5ab739cd5f27fb1cbf9", size = 250156, upload-time = "2026-01-26T02:44:33.734Z" }, + { url = "https://files.pythonhosted.org/packages/db/6b/420e173eec5fba721a50e2a9f89eda89d9c98fded1124f8d5c675f7a0c0f/multidict-6.7.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:90efbcf47dbe33dcf643a1e400d67d59abeac5db07dc3f27d6bdeae497a2198c", size = 249742, upload-time = "2026-01-26T02:44:35.222Z" }, + { url = "https://files.pythonhosted.org/packages/44/a3/ec5b5bd98f306bc2aa297b8c6f11a46714a56b1e6ef5ebda50a4f5d7c5fb/multidict-6.7.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:5c4b9bfc148f5a91be9244d6264c53035c8a0dcd2f51f1c3c6e30e30ebaa1c84", size = 262221, upload-time = "2026-01-26T02:44:36.604Z" }, + { url = "https://files.pythonhosted.org/packages/cd/f7/e8c0d0da0cd1e28d10e624604e1a36bcc3353aaebdfdc3a43c72bc683a12/multidict-6.7.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:401c5a650f3add2472d1d288c26deebc540f99e2fb83e9525007a74cd2116f1d", size = 258664, upload-time = "2026-01-26T02:44:38.008Z" }, + { url = "https://files.pythonhosted.org/packages/52/da/151a44e8016dd33feed44f730bd856a66257c1ee7aed4f44b649fb7edeb3/multidict-6.7.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:97891f3b1b3ffbded884e2916cacf3c6fc87b66bb0dde46f7357404750559f33", size = 249490, upload-time = "2026-01-26T02:44:39.386Z" }, + { url = "https://files.pythonhosted.org/packages/87/af/a3b86bf9630b732897f6fc3f4c4714b90aa4361983ccbdcd6c0339b21b0c/multidict-6.7.1-cp313-cp313-win32.whl", hash = "sha256:e1c5988359516095535c4301af38d8a8838534158f649c05dd1050222321bcb3", size = 41695, upload-time = "2026-01-26T02:44:41.318Z" }, + { url = "https://files.pythonhosted.org/packages/b2/35/e994121b0e90e46134673422dd564623f93304614f5d11886b1b3e06f503/multidict-6.7.1-cp313-cp313-win_amd64.whl", hash = "sha256:960c83bf01a95b12b08fd54324a4eb1d5b52c88932b5cba5d6e712bb3ed12eb5", size = 45884, upload-time = "2026-01-26T02:44:42.488Z" }, + { url = "https://files.pythonhosted.org/packages/ca/61/42d3e5dbf661242a69c97ea363f2d7b46c567da8eadef8890022be6e2ab0/multidict-6.7.1-cp313-cp313-win_arm64.whl", hash = "sha256:563fe25c678aaba333d5399408f5ec3c383ca5b663e7f774dd179a520b8144df", size = 43122, upload-time = "2026-01-26T02:44:43.664Z" }, + { url = "https://files.pythonhosted.org/packages/6d/b3/e6b21c6c4f314bb956016b0b3ef2162590a529b84cb831c257519e7fde44/multidict-6.7.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:c76c4bec1538375dad9d452d246ca5368ad6e1c9039dadcf007ae59c70619ea1", size = 83175, upload-time = "2026-01-26T02:44:44.894Z" }, + { url = "https://files.pythonhosted.org/packages/fb/76/23ecd2abfe0957b234f6c960f4ade497f55f2c16aeb684d4ecdbf1c95791/multidict-6.7.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:57b46b24b5d5ebcc978da4ec23a819a9402b4228b8a90d9c656422b4bdd8a963", size = 48460, upload-time = "2026-01-26T02:44:46.106Z" }, + { url = "https://files.pythonhosted.org/packages/c4/57/a0ed92b23f3a042c36bc4227b72b97eca803f5f1801c1ab77c8a212d455e/multidict-6.7.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e954b24433c768ce78ab7929e84ccf3422e46deb45a4dc9f93438f8217fa2d34", size = 46930, upload-time = "2026-01-26T02:44:47.278Z" }, + { url = "https://files.pythonhosted.org/packages/b5/66/02ec7ace29162e447f6382c495dc95826bf931d3818799bbef11e8f7df1a/multidict-6.7.1-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3bd231490fa7217cc832528e1cd8752a96f0125ddd2b5749390f7c3ec8721b65", size = 242582, upload-time = "2026-01-26T02:44:48.604Z" }, + { url = "https://files.pythonhosted.org/packages/58/18/64f5a795e7677670e872673aca234162514696274597b3708b2c0d276cce/multidict-6.7.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:253282d70d67885a15c8a7716f3a73edf2d635793ceda8173b9ecc21f2fb8292", size = 250031, upload-time = "2026-01-26T02:44:50.544Z" }, + { url = "https://files.pythonhosted.org/packages/c8/ed/e192291dbbe51a8290c5686f482084d31bcd9d09af24f63358c3d42fd284/multidict-6.7.1-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0b4c48648d7649c9335cf1927a8b87fa692de3dcb15faa676c6a6f1f1aabda43", size = 228596, upload-time = "2026-01-26T02:44:51.951Z" }, + { url = "https://files.pythonhosted.org/packages/1e/7e/3562a15a60cf747397e7f2180b0a11dc0c38d9175a650e75fa1b4d325e15/multidict-6.7.1-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:98bc624954ec4d2c7cb074b8eefc2b5d0ce7d482e410df446414355d158fe4ca", size = 257492, upload-time = "2026-01-26T02:44:53.902Z" }, + { url = "https://files.pythonhosted.org/packages/24/02/7d0f9eae92b5249bb50ac1595b295f10e263dd0078ebb55115c31e0eaccd/multidict-6.7.1-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1b99af4d9eec0b49927b4402bcbb58dea89d3e0db8806a4086117019939ad3dd", size = 255899, upload-time = "2026-01-26T02:44:55.316Z" }, + { url = "https://files.pythonhosted.org/packages/00/e3/9b60ed9e23e64c73a5cde95269ef1330678e9c6e34dd4eb6b431b85b5a10/multidict-6.7.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6aac4f16b472d5b7dc6f66a0d49dd57b0e0902090be16594dc9ebfd3d17c47e7", size = 247970, upload-time = "2026-01-26T02:44:56.783Z" }, + { url = "https://files.pythonhosted.org/packages/3e/06/538e58a63ed5cfb0bd4517e346b91da32fde409d839720f664e9a4ae4f9d/multidict-6.7.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:21f830fe223215dffd51f538e78c172ed7c7f60c9b96a2bf05c4848ad49921c3", size = 245060, upload-time = "2026-01-26T02:44:58.195Z" }, + { url = "https://files.pythonhosted.org/packages/b2/2f/d743a3045a97c895d401e9bd29aaa09b94f5cbdf1bd561609e5a6c431c70/multidict-6.7.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f5dd81c45b05518b9aa4da4aa74e1c93d715efa234fd3e8a179df611cc85e5f4", size = 235888, upload-time = "2026-01-26T02:44:59.57Z" }, + { url = "https://files.pythonhosted.org/packages/38/83/5a325cac191ab28b63c52f14f1131f3b0a55ba3b9aa65a6d0bf2a9b921a0/multidict-6.7.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:eb304767bca2bb92fb9c5bd33cedc95baee5bb5f6c88e63706533a1c06ad08c8", size = 243554, upload-time = "2026-01-26T02:45:01.054Z" }, + { url = "https://files.pythonhosted.org/packages/20/1f/9d2327086bd15da2725ef6aae624208e2ef828ed99892b17f60c344e57ed/multidict-6.7.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:c9035dde0f916702850ef66460bc4239d89d08df4d02023a5926e7446724212c", size = 252341, upload-time = "2026-01-26T02:45:02.484Z" }, + { url = "https://files.pythonhosted.org/packages/e8/2c/2a1aa0280cf579d0f6eed8ee5211c4f1730bd7e06c636ba2ee6aafda302e/multidict-6.7.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:af959b9beeb66c822380f222f0e0a1889331597e81f1ded7f374f3ecb0fd6c52", size = 246391, upload-time = "2026-01-26T02:45:03.862Z" }, + { url = "https://files.pythonhosted.org/packages/e5/03/7ca022ffc36c5a3f6e03b179a5ceb829be9da5783e6fe395f347c0794680/multidict-6.7.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:41f2952231456154ee479651491e94118229844dd7226541788be783be2b5108", size = 243422, upload-time = "2026-01-26T02:45:05.296Z" }, + { url = "https://files.pythonhosted.org/packages/dc/1d/b31650eab6c5778aceed46ba735bd97f7c7d2f54b319fa916c0f96e7805b/multidict-6.7.1-cp313-cp313t-win32.whl", hash = "sha256:df9f19c28adcb40b6aae30bbaa1478c389efd50c28d541d76760199fc1037c32", size = 47770, upload-time = "2026-01-26T02:45:06.754Z" }, + { url = "https://files.pythonhosted.org/packages/ac/5b/2d2d1d522e51285bd61b1e20df8f47ae1a9d80839db0b24ea783b3832832/multidict-6.7.1-cp313-cp313t-win_amd64.whl", hash = "sha256:d54ecf9f301853f2c5e802da559604b3e95bb7a3b01a9c295c6ee591b9882de8", size = 53109, upload-time = "2026-01-26T02:45:08.044Z" }, + { url = "https://files.pythonhosted.org/packages/3d/a3/cc409ba012c83ca024a308516703cf339bdc4b696195644a7215a5164a24/multidict-6.7.1-cp313-cp313t-win_arm64.whl", hash = "sha256:5a37ca18e360377cfda1d62f5f382ff41f2b8c4ccb329ed974cc2e1643440118", size = 45573, upload-time = "2026-01-26T02:45:09.349Z" }, + { url = "https://files.pythonhosted.org/packages/91/cc/db74228a8be41884a567e88a62fd589a913708fcf180d029898c17a9a371/multidict-6.7.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8f333ec9c5eb1b7105e3b84b53141e66ca05a19a605368c55450b6ba208cb9ee", size = 75190, upload-time = "2026-01-26T02:45:10.651Z" }, + { url = "https://files.pythonhosted.org/packages/d5/22/492f2246bb5b534abd44804292e81eeaf835388901f0c574bac4eeec73c5/multidict-6.7.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:a407f13c188f804c759fc6a9f88286a565c242a76b27626594c133b82883b5c2", size = 44486, upload-time = "2026-01-26T02:45:11.938Z" }, + { url = "https://files.pythonhosted.org/packages/f1/4f/733c48f270565d78b4544f2baddc2fb2a245e5a8640254b12c36ac7ac68e/multidict-6.7.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0e161ddf326db5577c3a4cc2d8648f81456e8a20d40415541587a71620d7a7d1", size = 43219, upload-time = "2026-01-26T02:45:14.346Z" }, + { url = "https://files.pythonhosted.org/packages/24/bb/2c0c2287963f4259c85e8bcbba9182ced8d7fca65c780c38e99e61629d11/multidict-6.7.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1e3a8bb24342a8201d178c3b4984c26ba81a577c80d4d525727427460a50c22d", size = 245132, upload-time = "2026-01-26T02:45:15.712Z" }, + { url = "https://files.pythonhosted.org/packages/a7/f9/44d4b3064c65079d2467888794dea218d1601898ac50222ab8a9a8094460/multidict-6.7.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97231140a50f5d447d3164f994b86a0bed7cd016e2682f8650d6a9158e14fd31", size = 252420, upload-time = "2026-01-26T02:45:17.293Z" }, + { url = "https://files.pythonhosted.org/packages/8b/13/78f7275e73fa17b24c9a51b0bd9d73ba64bb32d0ed51b02a746eb876abe7/multidict-6.7.1-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6b10359683bd8806a200fd2909e7c8ca3a7b24ec1d8132e483d58e791d881048", size = 233510, upload-time = "2026-01-26T02:45:19.356Z" }, + { url = "https://files.pythonhosted.org/packages/4b/25/8167187f62ae3cbd52da7893f58cb036b47ea3fb67138787c76800158982/multidict-6.7.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:283ddac99f7ac25a4acadbf004cb5ae34480bbeb063520f70ce397b281859362", size = 264094, upload-time = "2026-01-26T02:45:20.834Z" }, + { url = "https://files.pythonhosted.org/packages/a1/e7/69a3a83b7b030cf283fb06ce074a05a02322359783424d7edf0f15fe5022/multidict-6.7.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:538cec1e18c067d0e6103aa9a74f9e832904c957adc260e61cd9d8cf0c3b3d37", size = 260786, upload-time = "2026-01-26T02:45:22.818Z" }, + { url = "https://files.pythonhosted.org/packages/fe/3b/8ec5074bcfc450fe84273713b4b0a0dd47c0249358f5d82eb8104ffe2520/multidict-6.7.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7eee46ccb30ff48a1e35bb818cc90846c6be2b68240e42a78599166722cea709", size = 248483, upload-time = "2026-01-26T02:45:24.368Z" }, + { url = "https://files.pythonhosted.org/packages/48/5a/d5a99e3acbca0e29c5d9cba8f92ceb15dce78bab963b308ae692981e3a5d/multidict-6.7.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fa263a02f4f2dd2d11a7b1bb4362aa7cb1049f84a9235d31adf63f30143469a0", size = 248403, upload-time = "2026-01-26T02:45:25.982Z" }, + { url = "https://files.pythonhosted.org/packages/35/48/e58cd31f6c7d5102f2a4bf89f96b9cf7e00b6c6f3d04ecc44417c00a5a3c/multidict-6.7.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:2e1425e2f99ec5bd36c15a01b690a1a2456209c5deed58f95469ffb46039ccbb", size = 240315, upload-time = "2026-01-26T02:45:27.487Z" }, + { url = "https://files.pythonhosted.org/packages/94/33/1cd210229559cb90b6786c30676bb0c58249ff42f942765f88793b41fdce/multidict-6.7.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:497394b3239fc6f0e13a78a3e1b61296e72bf1c5f94b4c4eb80b265c37a131cd", size = 245528, upload-time = "2026-01-26T02:45:28.991Z" }, + { url = "https://files.pythonhosted.org/packages/64/f2/6e1107d226278c876c783056b7db43d800bb64c6131cec9c8dfb6903698e/multidict-6.7.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:233b398c29d3f1b9676b4b6f75c518a06fcb2ea0b925119fb2c1bc35c05e1601", size = 258784, upload-time = "2026-01-26T02:45:30.503Z" }, + { url = "https://files.pythonhosted.org/packages/4d/c1/11f664f14d525e4a1b5327a82d4de61a1db604ab34c6603bb3c2cc63ad34/multidict-6.7.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:93b1818e4a6e0930454f0f2af7dfce69307ca03cdcfb3739bf4d91241967b6c1", size = 251980, upload-time = "2026-01-26T02:45:32.603Z" }, + { url = "https://files.pythonhosted.org/packages/e1/9f/75a9ac888121d0c5bbd4ecf4eead45668b1766f6baabfb3b7f66a410e231/multidict-6.7.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f33dc2a3abe9249ea5d8360f969ec7f4142e7ac45ee7014d8f8d5acddf178b7b", size = 243602, upload-time = "2026-01-26T02:45:34.043Z" }, + { url = "https://files.pythonhosted.org/packages/9a/e7/50bf7b004cc8525d80dbbbedfdc7aed3e4c323810890be4413e589074032/multidict-6.7.1-cp314-cp314-win32.whl", hash = "sha256:3ab8b9d8b75aef9df299595d5388b14530839f6422333357af1339443cff777d", size = 40930, upload-time = "2026-01-26T02:45:36.278Z" }, + { url = "https://files.pythonhosted.org/packages/e0/bf/52f25716bbe93745595800f36fb17b73711f14da59ed0bb2eba141bc9f0f/multidict-6.7.1-cp314-cp314-win_amd64.whl", hash = "sha256:5e01429a929600e7dab7b166062d9bb54a5eed752384c7384c968c2afab8f50f", size = 45074, upload-time = "2026-01-26T02:45:37.546Z" }, + { url = "https://files.pythonhosted.org/packages/97/ab/22803b03285fa3a525f48217963da3a65ae40f6a1b6f6cf2768879e208f9/multidict-6.7.1-cp314-cp314-win_arm64.whl", hash = "sha256:4885cb0e817aef5d00a2e8451d4665c1808378dc27c2705f1bf4ef8505c0d2e5", size = 42471, upload-time = "2026-01-26T02:45:38.889Z" }, + { url = "https://files.pythonhosted.org/packages/e0/6d/f9293baa6146ba9507e360ea0292b6422b016907c393e2f63fc40ab7b7b5/multidict-6.7.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:0458c978acd8e6ea53c81eefaddbbee9c6c5e591f41b3f5e8e194780fe026581", size = 82401, upload-time = "2026-01-26T02:45:40.254Z" }, + { url = "https://files.pythonhosted.org/packages/7a/68/53b5494738d83558d87c3c71a486504d8373421c3e0dbb6d0db48ad42ee0/multidict-6.7.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:c0abd12629b0af3cf590982c0b413b1e7395cd4ec026f30986818ab95bfaa94a", size = 48143, upload-time = "2026-01-26T02:45:41.635Z" }, + { url = "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:14525a5f61d7d0c94b368a42cff4c9a4e7ba2d52e2672a7b23d84dc86fb02b0c", size = 46507, upload-time = "2026-01-26T02:45:42.99Z" }, + { url = "https://files.pythonhosted.org/packages/e4/fc/6800d0e5b3875568b4083ecf5f310dcf91d86d52573160834fb4bfcf5e4f/multidict-6.7.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:17307b22c217b4cf05033dabefe68255a534d637c6c9b0cc8382718f87be4262", size = 239358, upload-time = "2026-01-26T02:45:44.376Z" }, + { url = "https://files.pythonhosted.org/packages/41/75/4ad0973179361cdf3a113905e6e088173198349131be2b390f9fa4da5fc6/multidict-6.7.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a7e590ff876a3eaf1c02a4dfe0724b6e69a9e9de6d8f556816f29c496046e59", size = 246884, upload-time = "2026-01-26T02:45:47.167Z" }, + { url = "https://files.pythonhosted.org/packages/c3/9c/095bb28b5da139bd41fb9a5d5caff412584f377914bd8787c2aa98717130/multidict-6.7.1-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:5fa6a95dfee63893d80a34758cd0e0c118a30b8dcb46372bf75106c591b77889", size = 225878, upload-time = "2026-01-26T02:45:48.698Z" }, + { url = "https://files.pythonhosted.org/packages/07/d0/c0a72000243756e8f5a277b6b514fa005f2c73d481b7d9e47cd4568aa2e4/multidict-6.7.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a0543217a6a017692aa6ae5cc39adb75e587af0f3a82288b1492eb73dd6cc2a4", size = 253542, upload-time = "2026-01-26T02:45:50.164Z" }, + { url = "https://files.pythonhosted.org/packages/c0/6b/f69da15289e384ecf2a68837ec8b5ad8c33e973aa18b266f50fe55f24b8c/multidict-6.7.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f99fe611c312b3c1c0ace793f92464d8cd263cc3b26b5721950d977b006b6c4d", size = 252403, upload-time = "2026-01-26T02:45:51.779Z" }, + { url = "https://files.pythonhosted.org/packages/a2/76/b9669547afa5a1a25cd93eaca91c0da1c095b06b6d2d8ec25b713588d3a1/multidict-6.7.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9004d8386d133b7e6135679424c91b0b854d2d164af6ea3f289f8f2761064609", size = 244889, upload-time = "2026-01-26T02:45:53.27Z" }, + { url = "https://files.pythonhosted.org/packages/7e/a9/a50d2669e506dad33cfc45b5d574a205587b7b8a5f426f2fbb2e90882588/multidict-6.7.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e628ef0e6859ffd8273c69412a2465c4be4a9517d07261b33334b5ec6f3c7489", size = 241982, upload-time = "2026-01-26T02:45:54.919Z" }, + { url = "https://files.pythonhosted.org/packages/c5/bb/1609558ad8b456b4827d3c5a5b775c93b87878fd3117ed3db3423dfbce1b/multidict-6.7.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:841189848ba629c3552035a6a7f5bf3b02eb304e9fea7492ca220a8eda6b0e5c", size = 232415, upload-time = "2026-01-26T02:45:56.981Z" }, + { url = "https://files.pythonhosted.org/packages/d8/59/6f61039d2aa9261871e03ab9dc058a550d240f25859b05b67fd70f80d4b3/multidict-6.7.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:ce1bbd7d780bb5a0da032e095c951f7014d6b0a205f8318308140f1a6aba159e", size = 240337, upload-time = "2026-01-26T02:45:58.698Z" }, + { url = "https://files.pythonhosted.org/packages/a1/29/fdc6a43c203890dc2ae9249971ecd0c41deaedfe00d25cb6564b2edd99eb/multidict-6.7.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b26684587228afed0d50cf804cc71062cc9c1cdf55051c4c6345d372947b268c", size = 248788, upload-time = "2026-01-26T02:46:00.862Z" }, + { url = "https://files.pythonhosted.org/packages/a9/14/a153a06101323e4cf086ecee3faadba52ff71633d471f9685c42e3736163/multidict-6.7.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:9f9af11306994335398293f9958071019e3ab95e9a707dc1383a35613f6abcb9", size = 242842, upload-time = "2026-01-26T02:46:02.824Z" }, + { url = "https://files.pythonhosted.org/packages/41/5f/604ae839e64a4a6efc80db94465348d3b328ee955e37acb24badbcd24d83/multidict-6.7.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b4938326284c4f1224178a560987b6cf8b4d38458b113d9b8c1db1a836e640a2", size = 240237, upload-time = "2026-01-26T02:46:05.898Z" }, + { url = "https://files.pythonhosted.org/packages/5f/60/c3a5187bf66f6fb546ff4ab8fb5a077cbdd832d7b1908d4365c7f74a1917/multidict-6.7.1-cp314-cp314t-win32.whl", hash = "sha256:98655c737850c064a65e006a3df7c997cd3b220be4ec8fe26215760b9697d4d7", size = 48008, upload-time = "2026-01-26T02:46:07.468Z" }, + { url = "https://files.pythonhosted.org/packages/0c/f7/addf1087b860ac60e6f382240f64fb99f8bfb532bb06f7c542b83c29ca61/multidict-6.7.1-cp314-cp314t-win_amd64.whl", hash = "sha256:497bde6223c212ba11d462853cfa4f0ae6ef97465033e7dc9940cdb3ab5b48e5", size = 53542, upload-time = "2026-01-26T02:46:08.809Z" }, + { url = "https://files.pythonhosted.org/packages/4c/81/4629d0aa32302ef7b2ec65c75a728cc5ff4fa410c50096174c1632e70b3e/multidict-6.7.1-cp314-cp314t-win_arm64.whl", hash = "sha256:2bbd113e0d4af5db41d5ebfe9ccaff89de2120578164f86a5d17d5a576d1e5b2", size = 44719, upload-time = "2026-01-26T02:46:11.146Z" }, + { url = "https://files.pythonhosted.org/packages/81/08/7036c080d7117f28a4af526d794aab6a84463126db031b007717c1a6676e/multidict-6.7.1-py3-none-any.whl", hash = "sha256:55d97cc6dae627efa6a6e548885712d4864b81110ac76fa4e534c03819fa4a56", size = 12319, upload-time = "2026-01-26T02:46:44.004Z" }, +] + +[[package]] +name = "multiprocess" +version = "0.70.18" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "dill" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/72/fd/2ae3826f5be24c6ed87266bc4e59c46ea5b059a103f3d7e7eb76a52aeecb/multiprocess-0.70.18.tar.gz", hash = "sha256:f9597128e6b3e67b23956da07cf3d2e5cba79e2f4e0fba8d7903636663ec6d0d", size = 1798503, upload-time = "2025-04-17T03:11:27.742Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c8/f8/7f9a8f08bf98cea1dfaa181e05cc8bbcb59cecf044b5a9ac3cce39f9c449/multiprocess-0.70.18-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:25d4012dcaaf66b9e8e955f58482b42910c2ee526d532844d8bcf661bbc604df", size = 135083, upload-time = "2025-04-17T03:11:04.223Z" }, + { url = "https://files.pythonhosted.org/packages/e5/03/b7b10dbfc17b2b3ce07d4d30b3ba8367d0ed32d6d46cd166e298f161dd46/multiprocess-0.70.18-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:06b19433de0d02afe5869aec8931dd5c01d99074664f806c73896b0d9e527213", size = 135128, upload-time = "2025-04-17T03:11:06.045Z" }, + { url = "https://files.pythonhosted.org/packages/c1/a3/5f8d3b9690ea5580bee5868ab7d7e2cfca74b7e826b28192b40aa3881cdc/multiprocess-0.70.18-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:6fa1366f994373aaf2d4738b0f56e707caeaa05486e97a7f71ee0853823180c2", size = 135132, upload-time = "2025-04-17T03:11:07.533Z" }, + { url = "https://files.pythonhosted.org/packages/55/4d/9af0d1279c84618bcd35bf5fd7e371657358c7b0a523e54a9cffb87461f8/multiprocess-0.70.18-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:8b8940ae30139e04b076da6c5b83e9398585ebdf0f2ad3250673fef5b2ff06d6", size = 144695, upload-time = "2025-04-17T03:11:09.161Z" }, + { url = "https://files.pythonhosted.org/packages/17/bf/87323e79dd0562474fad3373c21c66bc6c3c9963b68eb2a209deb4c8575e/multiprocess-0.70.18-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:0929ba95831adb938edbd5fb801ac45e705ecad9d100b3e653946b7716cb6bd3", size = 144742, upload-time = "2025-04-17T03:11:10.072Z" }, + { url = "https://files.pythonhosted.org/packages/dd/74/cb8c831e58dc6d5cf450b17c7db87f14294a1df52eb391da948b5e0a0b94/multiprocess-0.70.18-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:4d77f8e4bfe6c6e2e661925bbf9aed4d5ade9a1c6502d5dfc10129b9d1141797", size = 144745, upload-time = "2025-04-17T03:11:11.453Z" }, + { url = "https://files.pythonhosted.org/packages/ba/d8/0cba6cf51a1a31f20471fbc823a716170c73012ddc4fb85d706630ed6e8f/multiprocess-0.70.18-py310-none-any.whl", hash = "sha256:60c194974c31784019c1f459d984e8f33ee48f10fcf42c309ba97b30d9bd53ea", size = 134948, upload-time = "2025-04-17T03:11:20.223Z" }, + { url = "https://files.pythonhosted.org/packages/4b/88/9039f2fed1012ef584751d4ceff9ab4a51e5ae264898f0b7cbf44340a859/multiprocess-0.70.18-py311-none-any.whl", hash = "sha256:5aa6eef98e691281b3ad923be2832bf1c55dd2c859acd73e5ec53a66aae06a1d", size = 144462, upload-time = "2025-04-17T03:11:21.657Z" }, + { url = "https://files.pythonhosted.org/packages/bf/b6/5f922792be93b82ec6b5f270bbb1ef031fd0622847070bbcf9da816502cc/multiprocess-0.70.18-py312-none-any.whl", hash = "sha256:9b78f8e5024b573730bfb654783a13800c2c0f2dfc0c25e70b40d184d64adaa2", size = 150287, upload-time = "2025-04-17T03:11:22.69Z" }, + { url = "https://files.pythonhosted.org/packages/ee/25/7d7e78e750bc1aecfaf0efbf826c69a791d2eeaf29cf20cba93ff4cced78/multiprocess-0.70.18-py313-none-any.whl", hash = "sha256:871743755f43ef57d7910a38433cfe41319e72be1bbd90b79c7a5ac523eb9334", size = 151917, upload-time = "2025-04-17T03:11:24.044Z" }, + { url = "https://files.pythonhosted.org/packages/3b/c3/ca84c19bd14cdfc21c388fdcebf08b86a7a470ebc9f5c3c084fc2dbc50f7/multiprocess-0.70.18-py38-none-any.whl", hash = "sha256:dbf705e52a154fe5e90fb17b38f02556169557c2dd8bb084f2e06c2784d8279b", size = 132636, upload-time = "2025-04-17T03:11:24.936Z" }, + { url = "https://files.pythonhosted.org/packages/6c/28/dd72947e59a6a8c856448a5e74da6201cb5502ddff644fbc790e4bd40b9a/multiprocess-0.70.18-py39-none-any.whl", hash = "sha256:e78ca805a72b1b810c690b6b4cc32579eba34f403094bbbae962b7b5bf9dfcb8", size = 133478, upload-time = "2025-04-17T03:11:26.253Z" }, +] + [[package]] name = "mypy" version = "1.19.1" @@ -1270,6 +2392,161 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", size = 23438, upload-time = "2025-12-20T14:08:52.782Z" }, ] +[[package]] +name = "numpy" +version = "2.2.6" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.11'", +] +sdist = { url = "https://files.pythonhosted.org/packages/76/21/7d2a95e4bba9dc13d043ee156a356c0a8f0c6309dff6b21b4d71a073b8a8/numpy-2.2.6.tar.gz", hash = "sha256:e29554e2bef54a90aa5cc07da6ce955accb83f21ab5de01a62c8478897b264fd", size = 20276440, upload-time = "2025-05-17T22:38:04.611Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9a/3e/ed6db5be21ce87955c0cbd3009f2803f59fa08df21b5df06862e2d8e2bdd/numpy-2.2.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b412caa66f72040e6d268491a59f2c43bf03eb6c96dd8f0307829feb7fa2b6fb", size = 21165245, upload-time = "2025-05-17T21:27:58.555Z" }, + { url = "https://files.pythonhosted.org/packages/22/c2/4b9221495b2a132cc9d2eb862e21d42a009f5a60e45fc44b00118c174bff/numpy-2.2.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e41fd67c52b86603a91c1a505ebaef50b3314de0213461c7a6e99c9a3beff90", size = 14360048, upload-time = "2025-05-17T21:28:21.406Z" }, + { url = "https://files.pythonhosted.org/packages/fd/77/dc2fcfc66943c6410e2bf598062f5959372735ffda175b39906d54f02349/numpy-2.2.6-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:37e990a01ae6ec7fe7fa1c26c55ecb672dd98b19c3d0e1d1f326fa13cb38d163", size = 5340542, upload-time = "2025-05-17T21:28:30.931Z" }, + { url = "https://files.pythonhosted.org/packages/7a/4f/1cb5fdc353a5f5cc7feb692db9b8ec2c3d6405453f982435efc52561df58/numpy-2.2.6-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:5a6429d4be8ca66d889b7cf70f536a397dc45ba6faeb5f8c5427935d9592e9cf", size = 6878301, upload-time = "2025-05-17T21:28:41.613Z" }, + { url = "https://files.pythonhosted.org/packages/eb/17/96a3acd228cec142fcb8723bd3cc39c2a474f7dcf0a5d16731980bcafa95/numpy-2.2.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:efd28d4e9cd7d7a8d39074a4d44c63eda73401580c5c76acda2ce969e0a38e83", size = 14297320, upload-time = "2025-05-17T21:29:02.78Z" }, + { url = "https://files.pythonhosted.org/packages/b4/63/3de6a34ad7ad6646ac7d2f55ebc6ad439dbbf9c4370017c50cf403fb19b5/numpy-2.2.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc7b73d02efb0e18c000e9ad8b83480dfcd5dfd11065997ed4c6747470ae8915", size = 16801050, upload-time = "2025-05-17T21:29:27.675Z" }, + { url = "https://files.pythonhosted.org/packages/07/b6/89d837eddef52b3d0cec5c6ba0456c1bf1b9ef6a6672fc2b7873c3ec4e2e/numpy-2.2.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:74d4531beb257d2c3f4b261bfb0fc09e0f9ebb8842d82a7b4209415896adc680", size = 15807034, upload-time = "2025-05-17T21:29:51.102Z" }, + { url = "https://files.pythonhosted.org/packages/01/c8/dc6ae86e3c61cfec1f178e5c9f7858584049b6093f843bca541f94120920/numpy-2.2.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8fc377d995680230e83241d8a96def29f204b5782f371c532579b4f20607a289", size = 18614185, upload-time = "2025-05-17T21:30:18.703Z" }, + { url = "https://files.pythonhosted.org/packages/5b/c5/0064b1b7e7c89137b471ccec1fd2282fceaae0ab3a9550f2568782d80357/numpy-2.2.6-cp310-cp310-win32.whl", hash = "sha256:b093dd74e50a8cba3e873868d9e93a85b78e0daf2e98c6797566ad8044e8363d", size = 6527149, upload-time = "2025-05-17T21:30:29.788Z" }, + { url = "https://files.pythonhosted.org/packages/a3/dd/4b822569d6b96c39d1215dbae0582fd99954dcbcf0c1a13c61783feaca3f/numpy-2.2.6-cp310-cp310-win_amd64.whl", hash = "sha256:f0fd6321b839904e15c46e0d257fdd101dd7f530fe03fd6359c1ea63738703f3", size = 12904620, upload-time = "2025-05-17T21:30:48.994Z" }, + { url = "https://files.pythonhosted.org/packages/da/a8/4f83e2aa666a9fbf56d6118faaaf5f1974d456b1823fda0a176eff722839/numpy-2.2.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f9f1adb22318e121c5c69a09142811a201ef17ab257a1e66ca3025065b7f53ae", size = 21176963, upload-time = "2025-05-17T21:31:19.36Z" }, + { url = "https://files.pythonhosted.org/packages/b3/2b/64e1affc7972decb74c9e29e5649fac940514910960ba25cd9af4488b66c/numpy-2.2.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c820a93b0255bc360f53eca31a0e676fd1101f673dda8da93454a12e23fc5f7a", size = 14406743, upload-time = "2025-05-17T21:31:41.087Z" }, + { url = "https://files.pythonhosted.org/packages/4a/9f/0121e375000b5e50ffdd8b25bf78d8e1a5aa4cca3f185d41265198c7b834/numpy-2.2.6-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:3d70692235e759f260c3d837193090014aebdf026dfd167834bcba43e30c2a42", size = 5352616, upload-time = "2025-05-17T21:31:50.072Z" }, + { url = "https://files.pythonhosted.org/packages/31/0d/b48c405c91693635fbe2dcd7bc84a33a602add5f63286e024d3b6741411c/numpy-2.2.6-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:481b49095335f8eed42e39e8041327c05b0f6f4780488f61286ed3c01368d491", size = 6889579, upload-time = "2025-05-17T21:32:01.712Z" }, + { url = "https://files.pythonhosted.org/packages/52/b8/7f0554d49b565d0171eab6e99001846882000883998e7b7d9f0d98b1f934/numpy-2.2.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b64d8d4d17135e00c8e346e0a738deb17e754230d7e0810ac5012750bbd85a5a", size = 14312005, upload-time = "2025-05-17T21:32:23.332Z" }, + { url = "https://files.pythonhosted.org/packages/b3/dd/2238b898e51bd6d389b7389ffb20d7f4c10066d80351187ec8e303a5a475/numpy-2.2.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba10f8411898fc418a521833e014a77d3ca01c15b0c6cdcce6a0d2897e6dbbdf", size = 16821570, upload-time = "2025-05-17T21:32:47.991Z" }, + { url = "https://files.pythonhosted.org/packages/83/6c/44d0325722cf644f191042bf47eedad61c1e6df2432ed65cbe28509d404e/numpy-2.2.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:bd48227a919f1bafbdda0583705e547892342c26fb127219d60a5c36882609d1", size = 15818548, upload-time = "2025-05-17T21:33:11.728Z" }, + { url = "https://files.pythonhosted.org/packages/ae/9d/81e8216030ce66be25279098789b665d49ff19eef08bfa8cb96d4957f422/numpy-2.2.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9551a499bf125c1d4f9e250377c1ee2eddd02e01eac6644c080162c0c51778ab", size = 18620521, upload-time = "2025-05-17T21:33:39.139Z" }, + { url = "https://files.pythonhosted.org/packages/6a/fd/e19617b9530b031db51b0926eed5345ce8ddc669bb3bc0044b23e275ebe8/numpy-2.2.6-cp311-cp311-win32.whl", hash = "sha256:0678000bb9ac1475cd454c6b8c799206af8107e310843532b04d49649c717a47", size = 6525866, upload-time = "2025-05-17T21:33:50.273Z" }, + { url = "https://files.pythonhosted.org/packages/31/0a/f354fb7176b81747d870f7991dc763e157a934c717b67b58456bc63da3df/numpy-2.2.6-cp311-cp311-win_amd64.whl", hash = "sha256:e8213002e427c69c45a52bbd94163084025f533a55a59d6f9c5b820774ef3303", size = 12907455, upload-time = "2025-05-17T21:34:09.135Z" }, + { url = "https://files.pythonhosted.org/packages/82/5d/c00588b6cf18e1da539b45d3598d3557084990dcc4331960c15ee776ee41/numpy-2.2.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:41c5a21f4a04fa86436124d388f6ed60a9343a6f767fced1a8a71c3fbca038ff", size = 20875348, upload-time = "2025-05-17T21:34:39.648Z" }, + { url = "https://files.pythonhosted.org/packages/66/ee/560deadcdde6c2f90200450d5938f63a34b37e27ebff162810f716f6a230/numpy-2.2.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:de749064336d37e340f640b05f24e9e3dd678c57318c7289d222a8a2f543e90c", size = 14119362, upload-time = "2025-05-17T21:35:01.241Z" }, + { url = "https://files.pythonhosted.org/packages/3c/65/4baa99f1c53b30adf0acd9a5519078871ddde8d2339dc5a7fde80d9d87da/numpy-2.2.6-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:894b3a42502226a1cac872f840030665f33326fc3dac8e57c607905773cdcde3", size = 5084103, upload-time = "2025-05-17T21:35:10.622Z" }, + { url = "https://files.pythonhosted.org/packages/cc/89/e5a34c071a0570cc40c9a54eb472d113eea6d002e9ae12bb3a8407fb912e/numpy-2.2.6-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:71594f7c51a18e728451bb50cc60a3ce4e6538822731b2933209a1f3614e9282", size = 6625382, upload-time = "2025-05-17T21:35:21.414Z" }, + { url = "https://files.pythonhosted.org/packages/f8/35/8c80729f1ff76b3921d5c9487c7ac3de9b2a103b1cd05e905b3090513510/numpy-2.2.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2618db89be1b4e05f7a1a847a9c1c0abd63e63a1607d892dd54668dd92faf87", size = 14018462, upload-time = "2025-05-17T21:35:42.174Z" }, + { url = "https://files.pythonhosted.org/packages/8c/3d/1e1db36cfd41f895d266b103df00ca5b3cbe965184df824dec5c08c6b803/numpy-2.2.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd83c01228a688733f1ded5201c678f0c53ecc1006ffbc404db9f7a899ac6249", size = 16527618, upload-time = "2025-05-17T21:36:06.711Z" }, + { url = "https://files.pythonhosted.org/packages/61/c6/03ed30992602c85aa3cd95b9070a514f8b3c33e31124694438d88809ae36/numpy-2.2.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:37c0ca431f82cd5fa716eca9506aefcabc247fb27ba69c5062a6d3ade8cf8f49", size = 15505511, upload-time = "2025-05-17T21:36:29.965Z" }, + { url = "https://files.pythonhosted.org/packages/b7/25/5761d832a81df431e260719ec45de696414266613c9ee268394dd5ad8236/numpy-2.2.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fe27749d33bb772c80dcd84ae7e8df2adc920ae8297400dabec45f0dedb3f6de", size = 18313783, upload-time = "2025-05-17T21:36:56.883Z" }, + { url = "https://files.pythonhosted.org/packages/57/0a/72d5a3527c5ebffcd47bde9162c39fae1f90138c961e5296491ce778e682/numpy-2.2.6-cp312-cp312-win32.whl", hash = "sha256:4eeaae00d789f66c7a25ac5f34b71a7035bb474e679f410e5e1a94deb24cf2d4", size = 6246506, upload-time = "2025-05-17T21:37:07.368Z" }, + { url = "https://files.pythonhosted.org/packages/36/fa/8c9210162ca1b88529ab76b41ba02d433fd54fecaf6feb70ef9f124683f1/numpy-2.2.6-cp312-cp312-win_amd64.whl", hash = "sha256:c1f9540be57940698ed329904db803cf7a402f3fc200bfe599334c9bd84a40b2", size = 12614190, upload-time = "2025-05-17T21:37:26.213Z" }, + { url = "https://files.pythonhosted.org/packages/f9/5c/6657823f4f594f72b5471f1db1ab12e26e890bb2e41897522d134d2a3e81/numpy-2.2.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0811bb762109d9708cca4d0b13c4f67146e3c3b7cf8d34018c722adb2d957c84", size = 20867828, upload-time = "2025-05-17T21:37:56.699Z" }, + { url = "https://files.pythonhosted.org/packages/dc/9e/14520dc3dadf3c803473bd07e9b2bd1b69bc583cb2497b47000fed2fa92f/numpy-2.2.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:287cc3162b6f01463ccd86be154f284d0893d2b3ed7292439ea97eafa8170e0b", size = 14143006, upload-time = "2025-05-17T21:38:18.291Z" }, + { url = "https://files.pythonhosted.org/packages/4f/06/7e96c57d90bebdce9918412087fc22ca9851cceaf5567a45c1f404480e9e/numpy-2.2.6-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:f1372f041402e37e5e633e586f62aa53de2eac8d98cbfb822806ce4bbefcb74d", size = 5076765, upload-time = "2025-05-17T21:38:27.319Z" }, + { url = "https://files.pythonhosted.org/packages/73/ed/63d920c23b4289fdac96ddbdd6132e9427790977d5457cd132f18e76eae0/numpy-2.2.6-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:55a4d33fa519660d69614a9fad433be87e5252f4b03850642f88993f7b2ca566", size = 6617736, upload-time = "2025-05-17T21:38:38.141Z" }, + { url = "https://files.pythonhosted.org/packages/85/c5/e19c8f99d83fd377ec8c7e0cf627a8049746da54afc24ef0a0cb73d5dfb5/numpy-2.2.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f92729c95468a2f4f15e9bb94c432a9229d0d50de67304399627a943201baa2f", size = 14010719, upload-time = "2025-05-17T21:38:58.433Z" }, + { url = "https://files.pythonhosted.org/packages/19/49/4df9123aafa7b539317bf6d342cb6d227e49f7a35b99c287a6109b13dd93/numpy-2.2.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bc23a79bfabc5d056d106f9befb8d50c31ced2fbc70eedb8155aec74a45798f", size = 16526072, upload-time = "2025-05-17T21:39:22.638Z" }, + { url = "https://files.pythonhosted.org/packages/b2/6c/04b5f47f4f32f7c2b0e7260442a8cbcf8168b0e1a41ff1495da42f42a14f/numpy-2.2.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e3143e4451880bed956e706a3220b4e5cf6172ef05fcc397f6f36a550b1dd868", size = 15503213, upload-time = "2025-05-17T21:39:45.865Z" }, + { url = "https://files.pythonhosted.org/packages/17/0a/5cd92e352c1307640d5b6fec1b2ffb06cd0dabe7d7b8227f97933d378422/numpy-2.2.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b4f13750ce79751586ae2eb824ba7e1e8dba64784086c98cdbbcc6a42112ce0d", size = 18316632, upload-time = "2025-05-17T21:40:13.331Z" }, + { url = "https://files.pythonhosted.org/packages/f0/3b/5cba2b1d88760ef86596ad0f3d484b1cbff7c115ae2429678465057c5155/numpy-2.2.6-cp313-cp313-win32.whl", hash = "sha256:5beb72339d9d4fa36522fc63802f469b13cdbe4fdab4a288f0c441b74272ebfd", size = 6244532, upload-time = "2025-05-17T21:43:46.099Z" }, + { url = "https://files.pythonhosted.org/packages/cb/3b/d58c12eafcb298d4e6d0d40216866ab15f59e55d148a5658bb3132311fcf/numpy-2.2.6-cp313-cp313-win_amd64.whl", hash = "sha256:b0544343a702fa80c95ad5d3d608ea3599dd54d4632df855e4c8d24eb6ecfa1c", size = 12610885, upload-time = "2025-05-17T21:44:05.145Z" }, + { url = "https://files.pythonhosted.org/packages/6b/9e/4bf918b818e516322db999ac25d00c75788ddfd2d2ade4fa66f1f38097e1/numpy-2.2.6-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0bca768cd85ae743b2affdc762d617eddf3bcf8724435498a1e80132d04879e6", size = 20963467, upload-time = "2025-05-17T21:40:44Z" }, + { url = "https://files.pythonhosted.org/packages/61/66/d2de6b291507517ff2e438e13ff7b1e2cdbdb7cb40b3ed475377aece69f9/numpy-2.2.6-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:fc0c5673685c508a142ca65209b4e79ed6740a4ed6b2267dbba90f34b0b3cfda", size = 14225144, upload-time = "2025-05-17T21:41:05.695Z" }, + { url = "https://files.pythonhosted.org/packages/e4/25/480387655407ead912e28ba3a820bc69af9adf13bcbe40b299d454ec011f/numpy-2.2.6-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:5bd4fc3ac8926b3819797a7c0e2631eb889b4118a9898c84f585a54d475b7e40", size = 5200217, upload-time = "2025-05-17T21:41:15.903Z" }, + { url = "https://files.pythonhosted.org/packages/aa/4a/6e313b5108f53dcbf3aca0c0f3e9c92f4c10ce57a0a721851f9785872895/numpy-2.2.6-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:fee4236c876c4e8369388054d02d0e9bb84821feb1a64dd59e137e6511a551f8", size = 6712014, upload-time = "2025-05-17T21:41:27.321Z" }, + { url = "https://files.pythonhosted.org/packages/b7/30/172c2d5c4be71fdf476e9de553443cf8e25feddbe185e0bd88b096915bcc/numpy-2.2.6-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1dda9c7e08dc141e0247a5b8f49cf05984955246a327d4c48bda16821947b2f", size = 14077935, upload-time = "2025-05-17T21:41:49.738Z" }, + { url = "https://files.pythonhosted.org/packages/12/fb/9e743f8d4e4d3c710902cf87af3512082ae3d43b945d5d16563f26ec251d/numpy-2.2.6-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f447e6acb680fd307f40d3da4852208af94afdfab89cf850986c3ca00562f4fa", size = 16600122, upload-time = "2025-05-17T21:42:14.046Z" }, + { url = "https://files.pythonhosted.org/packages/12/75/ee20da0e58d3a66f204f38916757e01e33a9737d0b22373b3eb5a27358f9/numpy-2.2.6-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:389d771b1623ec92636b0786bc4ae56abafad4a4c513d36a55dce14bd9ce8571", size = 15586143, upload-time = "2025-05-17T21:42:37.464Z" }, + { url = "https://files.pythonhosted.org/packages/76/95/bef5b37f29fc5e739947e9ce5179ad402875633308504a52d188302319c8/numpy-2.2.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8e9ace4a37db23421249ed236fdcdd457d671e25146786dfc96835cd951aa7c1", size = 18385260, upload-time = "2025-05-17T21:43:05.189Z" }, + { url = "https://files.pythonhosted.org/packages/09/04/f2f83279d287407cf36a7a8053a5abe7be3622a4363337338f2585e4afda/numpy-2.2.6-cp313-cp313t-win32.whl", hash = "sha256:038613e9fb8c72b0a41f025a7e4c3f0b7a1b5d768ece4796b674c8f3fe13efff", size = 6377225, upload-time = "2025-05-17T21:43:16.254Z" }, + { url = "https://files.pythonhosted.org/packages/67/0e/35082d13c09c02c011cf21570543d202ad929d961c02a147493cb0c2bdf5/numpy-2.2.6-cp313-cp313t-win_amd64.whl", hash = "sha256:6031dd6dfecc0cf9f668681a37648373bddd6421fff6c66ec1624eed0180ee06", size = 12771374, upload-time = "2025-05-17T21:43:35.479Z" }, + { url = "https://files.pythonhosted.org/packages/9e/3b/d94a75f4dbf1ef5d321523ecac21ef23a3cd2ac8b78ae2aac40873590229/numpy-2.2.6-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0b605b275d7bd0c640cad4e5d30fa701a8d59302e127e5f79138ad62762c3e3d", size = 21040391, upload-time = "2025-05-17T21:44:35.948Z" }, + { url = "https://files.pythonhosted.org/packages/17/f4/09b2fa1b58f0fb4f7c7963a1649c64c4d315752240377ed74d9cd878f7b5/numpy-2.2.6-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:7befc596a7dc9da8a337f79802ee8adb30a552a94f792b9c9d18c840055907db", size = 6786754, upload-time = "2025-05-17T21:44:47.446Z" }, + { url = "https://files.pythonhosted.org/packages/af/30/feba75f143bdc868a1cc3f44ccfa6c4b9ec522b36458e738cd00f67b573f/numpy-2.2.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce47521a4754c8f4593837384bd3424880629f718d87c5d44f8ed763edd63543", size = 16643476, upload-time = "2025-05-17T21:45:11.871Z" }, + { url = "https://files.pythonhosted.org/packages/37/48/ac2a9584402fb6c0cd5b5d1a91dcf176b15760130dd386bbafdbfe3640bf/numpy-2.2.6-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d042d24c90c41b54fd506da306759e06e568864df8ec17ccc17e9e884634fd00", size = 12812666, upload-time = "2025-05-17T21:45:31.426Z" }, +] + +[[package]] +name = "numpy" +version = "2.4.2" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.14' and sys_platform == 'win32'", + "python_full_version >= '3.14' and sys_platform == 'emscripten'", + "python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", + "python_full_version == '3.13.*' and sys_platform == 'win32'", + "python_full_version == '3.13.*' and sys_platform == 'emscripten'", + "python_full_version == '3.13.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", + "python_full_version >= '3.11' and python_full_version < '3.13' and sys_platform == 'win32'", + "python_full_version >= '3.11' and python_full_version < '3.13' and sys_platform == 'emscripten'", + "python_full_version >= '3.11' and python_full_version < '3.13' and sys_platform != 'emscripten' and sys_platform != 'win32'", +] +sdist = { url = "https://files.pythonhosted.org/packages/57/fd/0005efbd0af48e55eb3c7208af93f2862d4b1a56cd78e84309a2d959208d/numpy-2.4.2.tar.gz", hash = "sha256:659a6107e31a83c4e33f763942275fd278b21d095094044eb35569e86a21ddae", size = 20723651, upload-time = "2026-01-31T23:13:10.135Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d3/44/71852273146957899753e69986246d6a176061ea183407e95418c2aa4d9a/numpy-2.4.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e7e88598032542bd49af7c4747541422884219056c268823ef6e5e89851c8825", size = 16955478, upload-time = "2026-01-31T23:10:25.623Z" }, + { url = "https://files.pythonhosted.org/packages/74/41/5d17d4058bd0cd96bcbd4d9ff0fb2e21f52702aab9a72e4a594efa18692f/numpy-2.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7edc794af8b36ca37ef5fcb5e0d128c7e0595c7b96a2318d1badb6fcd8ee86b1", size = 14965467, upload-time = "2026-01-31T23:10:28.186Z" }, + { url = "https://files.pythonhosted.org/packages/49/48/fb1ce8136c19452ed15f033f8aee91d5defe515094e330ce368a0647846f/numpy-2.4.2-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:6e9f61981ace1360e42737e2bae58b27bf28a1b27e781721047d84bd754d32e7", size = 5475172, upload-time = "2026-01-31T23:10:30.848Z" }, + { url = "https://files.pythonhosted.org/packages/40/a9/3feb49f17bbd1300dd2570432961f5c8a4ffeff1db6f02c7273bd020a4c9/numpy-2.4.2-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:cb7bbb88aa74908950d979eeaa24dbdf1a865e3c7e45ff0121d8f70387b55f73", size = 6805145, upload-time = "2026-01-31T23:10:32.352Z" }, + { url = "https://files.pythonhosted.org/packages/3f/39/fdf35cbd6d6e2fcad42fcf85ac04a85a0d0fbfbf34b30721c98d602fd70a/numpy-2.4.2-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4f069069931240b3fc703f1e23df63443dbd6390614c8c44a87d96cd0ec81eb1", size = 15966084, upload-time = "2026-01-31T23:10:34.502Z" }, + { url = "https://files.pythonhosted.org/packages/1b/46/6fa4ea94f1ddf969b2ee941290cca6f1bfac92b53c76ae5f44afe17ceb69/numpy-2.4.2-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c02ef4401a506fb60b411467ad501e1429a3487abca4664871d9ae0b46c8ba32", size = 16899477, upload-time = "2026-01-31T23:10:37.075Z" }, + { url = "https://files.pythonhosted.org/packages/09/a1/2a424e162b1a14a5bd860a464ab4e07513916a64ab1683fae262f735ccd2/numpy-2.4.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2653de5c24910e49c2b106499803124dde62a5a1fe0eedeaecf4309a5f639390", size = 17323429, upload-time = "2026-01-31T23:10:39.704Z" }, + { url = "https://files.pythonhosted.org/packages/ce/a2/73014149ff250628df72c58204822ac01d768697913881aacf839ff78680/numpy-2.4.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1ae241bbfc6ae276f94a170b14785e561cb5e7f626b6688cf076af4110887413", size = 18635109, upload-time = "2026-01-31T23:10:41.924Z" }, + { url = "https://files.pythonhosted.org/packages/6c/0c/73e8be2f1accd56df74abc1c5e18527822067dced5ec0861b5bb882c2ce0/numpy-2.4.2-cp311-cp311-win32.whl", hash = "sha256:df1b10187212b198dd45fa943d8985a3c8cf854aed4923796e0e019e113a1bda", size = 6237915, upload-time = "2026-01-31T23:10:45.26Z" }, + { url = "https://files.pythonhosted.org/packages/76/ae/e0265e0163cf127c24c3969d29f1c4c64551a1e375d95a13d32eab25d364/numpy-2.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:b9c618d56a29c9cb1c4da979e9899be7578d2e0b3c24d52079c166324c9e8695", size = 12607972, upload-time = "2026-01-31T23:10:47.021Z" }, + { url = "https://files.pythonhosted.org/packages/29/a5/c43029af9b8014d6ea157f192652c50042e8911f4300f8f6ed3336bf437f/numpy-2.4.2-cp311-cp311-win_arm64.whl", hash = "sha256:47c5a6ed21d9452b10227e5e8a0e1c22979811cad7dcc19d8e3e2fb8fa03f1a3", size = 10485763, upload-time = "2026-01-31T23:10:50.087Z" }, + { url = "https://files.pythonhosted.org/packages/51/6e/6f394c9c77668153e14d4da83bcc247beb5952f6ead7699a1a2992613bea/numpy-2.4.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:21982668592194c609de53ba4933a7471880ccbaadcc52352694a59ecc860b3a", size = 16667963, upload-time = "2026-01-31T23:10:52.147Z" }, + { url = "https://files.pythonhosted.org/packages/1f/f8/55483431f2b2fd015ae6ed4fe62288823ce908437ed49db5a03d15151678/numpy-2.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40397bda92382fcec844066efb11f13e1c9a3e2a8e8f318fb72ed8b6db9f60f1", size = 14693571, upload-time = "2026-01-31T23:10:54.789Z" }, + { url = "https://files.pythonhosted.org/packages/2f/20/18026832b1845cdc82248208dd929ca14c9d8f2bac391f67440707fff27c/numpy-2.4.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:b3a24467af63c67829bfaa61eecf18d5432d4f11992688537be59ecd6ad32f5e", size = 5203469, upload-time = "2026-01-31T23:10:57.343Z" }, + { url = "https://files.pythonhosted.org/packages/7d/33/2eb97c8a77daaba34eaa3fa7241a14ac5f51c46a6bd5911361b644c4a1e2/numpy-2.4.2-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:805cc8de9fd6e7a22da5aed858e0ab16be5a4db6c873dde1d7451c541553aa27", size = 6550820, upload-time = "2026-01-31T23:10:59.429Z" }, + { url = "https://files.pythonhosted.org/packages/b1/91/b97fdfd12dc75b02c44e26c6638241cc004d4079a0321a69c62f51470c4c/numpy-2.4.2-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d82351358ffbcdcd7b686b90742a9b86632d6c1c051016484fa0b326a0a1548", size = 15663067, upload-time = "2026-01-31T23:11:01.291Z" }, + { url = "https://files.pythonhosted.org/packages/f5/c6/a18e59f3f0b8071cc85cbc8d80cd02d68aa9710170b2553a117203d46936/numpy-2.4.2-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e35d3e0144137d9fdae62912e869136164534d64a169f86438bc9561b6ad49f", size = 16619782, upload-time = "2026-01-31T23:11:03.669Z" }, + { url = "https://files.pythonhosted.org/packages/b7/83/9751502164601a79e18847309f5ceec0b1446d7b6aa12305759b72cf98b2/numpy-2.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:adb6ed2ad29b9e15321d167d152ee909ec73395901b70936f029c3bc6d7f4460", size = 17013128, upload-time = "2026-01-31T23:11:05.913Z" }, + { url = "https://files.pythonhosted.org/packages/61/c4/c4066322256ec740acc1c8923a10047818691d2f8aec254798f3dd90f5f2/numpy-2.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8906e71fd8afcb76580404e2a950caef2685df3d2a57fe82a86ac8d33cc007ba", size = 18345324, upload-time = "2026-01-31T23:11:08.248Z" }, + { url = "https://files.pythonhosted.org/packages/ab/af/6157aa6da728fa4525a755bfad486ae7e3f76d4c1864138003eb84328497/numpy-2.4.2-cp312-cp312-win32.whl", hash = "sha256:ec055f6dae239a6299cace477b479cca2fc125c5675482daf1dd886933a1076f", size = 5960282, upload-time = "2026-01-31T23:11:10.497Z" }, + { url = "https://files.pythonhosted.org/packages/92/0f/7ceaaeaacb40567071e94dbf2c9480c0ae453d5bb4f52bea3892c39dc83c/numpy-2.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:209fae046e62d0ce6435fcfe3b1a10537e858249b3d9b05829e2a05218296a85", size = 12314210, upload-time = "2026-01-31T23:11:12.176Z" }, + { url = "https://files.pythonhosted.org/packages/2f/a3/56c5c604fae6dd40fa2ed3040d005fca97e91bd320d232ac9931d77ba13c/numpy-2.4.2-cp312-cp312-win_arm64.whl", hash = "sha256:fbde1b0c6e81d56f5dccd95dd4a711d9b95df1ae4009a60887e56b27e8d903fa", size = 10220171, upload-time = "2026-01-31T23:11:14.684Z" }, + { url = "https://files.pythonhosted.org/packages/a1/22/815b9fe25d1d7ae7d492152adbc7226d3eff731dffc38fe970589fcaaa38/numpy-2.4.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:25f2059807faea4b077a2b6837391b5d830864b3543627f381821c646f31a63c", size = 16663696, upload-time = "2026-01-31T23:11:17.516Z" }, + { url = "https://files.pythonhosted.org/packages/09/f0/817d03a03f93ba9c6c8993de509277d84e69f9453601915e4a69554102a1/numpy-2.4.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bd3a7a9f5847d2fb8c2c6d1c862fa109c31a9abeca1a3c2bd5a64572955b2979", size = 14688322, upload-time = "2026-01-31T23:11:19.883Z" }, + { url = "https://files.pythonhosted.org/packages/da/b4/f805ab79293c728b9a99438775ce51885fd4f31b76178767cfc718701a39/numpy-2.4.2-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:8e4549f8a3c6d13d55041925e912bfd834285ef1dd64d6bc7d542583355e2e98", size = 5198157, upload-time = "2026-01-31T23:11:22.375Z" }, + { url = "https://files.pythonhosted.org/packages/74/09/826e4289844eccdcd64aac27d13b0fd3f32039915dd5b9ba01baae1f436c/numpy-2.4.2-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:aea4f66ff44dfddf8c2cffd66ba6538c5ec67d389285292fe428cb2c738c8aef", size = 6546330, upload-time = "2026-01-31T23:11:23.958Z" }, + { url = "https://files.pythonhosted.org/packages/19/fb/cbfdbfa3057a10aea5422c558ac57538e6acc87ec1669e666d32ac198da7/numpy-2.4.2-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c3cd545784805de05aafe1dde61752ea49a359ccba9760c1e5d1c88a93bbf2b7", size = 15660968, upload-time = "2026-01-31T23:11:25.713Z" }, + { url = "https://files.pythonhosted.org/packages/04/dc/46066ce18d01645541f0186877377b9371b8fa8017fa8262002b4ef22612/numpy-2.4.2-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d0d9b7c93578baafcbc5f0b83eaf17b79d345c6f36917ba0c67f45226911d499", size = 16607311, upload-time = "2026-01-31T23:11:28.117Z" }, + { url = "https://files.pythonhosted.org/packages/14/d9/4b5adfc39a43fa6bf918c6d544bc60c05236cc2f6339847fc5b35e6cb5b0/numpy-2.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f74f0f7779cc7ae07d1810aab8ac6b1464c3eafb9e283a40da7309d5e6e48fbb", size = 17012850, upload-time = "2026-01-31T23:11:30.888Z" }, + { url = "https://files.pythonhosted.org/packages/b7/20/adb6e6adde6d0130046e6fdfb7675cc62bc2f6b7b02239a09eb58435753d/numpy-2.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c7ac672d699bf36275c035e16b65539931347d68b70667d28984c9fb34e07fa7", size = 18334210, upload-time = "2026-01-31T23:11:33.214Z" }, + { url = "https://files.pythonhosted.org/packages/78/0e/0a73b3dff26803a8c02baa76398015ea2a5434d9b8265a7898a6028c1591/numpy-2.4.2-cp313-cp313-win32.whl", hash = "sha256:8e9afaeb0beff068b4d9cd20d322ba0ee1cecfb0b08db145e4ab4dd44a6b5110", size = 5958199, upload-time = "2026-01-31T23:11:35.385Z" }, + { url = "https://files.pythonhosted.org/packages/43/bc/6352f343522fcb2c04dbaf94cb30cca6fd32c1a750c06ad6231b4293708c/numpy-2.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:7df2de1e4fba69a51c06c28f5a3de36731eb9639feb8e1cf7e4a7b0daf4cf622", size = 12310848, upload-time = "2026-01-31T23:11:38.001Z" }, + { url = "https://files.pythonhosted.org/packages/6e/8d/6da186483e308da5da1cc6918ce913dcfe14ffde98e710bfeff2a6158d4e/numpy-2.4.2-cp313-cp313-win_arm64.whl", hash = "sha256:0fece1d1f0a89c16b03442eae5c56dc0be0c7883b5d388e0c03f53019a4bfd71", size = 10221082, upload-time = "2026-01-31T23:11:40.392Z" }, + { url = "https://files.pythonhosted.org/packages/25/a1/9510aa43555b44781968935c7548a8926274f815de42ad3997e9e83680dd/numpy-2.4.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5633c0da313330fd20c484c78cdd3f9b175b55e1a766c4a174230c6b70ad8262", size = 14815866, upload-time = "2026-01-31T23:11:42.495Z" }, + { url = "https://files.pythonhosted.org/packages/36/30/6bbb5e76631a5ae46e7923dd16ca9d3f1c93cfa8d4ed79a129814a9d8db3/numpy-2.4.2-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:d9f64d786b3b1dd742c946c42d15b07497ed14af1a1f3ce840cce27daa0ce913", size = 5325631, upload-time = "2026-01-31T23:11:44.7Z" }, + { url = "https://files.pythonhosted.org/packages/46/00/3a490938800c1923b567b3a15cd17896e68052e2145d8662aaf3e1ffc58f/numpy-2.4.2-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:b21041e8cb6a1eb5312dd1d2f80a94d91efffb7a06b70597d44f1bd2dfc315ab", size = 6646254, upload-time = "2026-01-31T23:11:46.341Z" }, + { url = "https://files.pythonhosted.org/packages/d3/e9/fac0890149898a9b609caa5af7455a948b544746e4b8fe7c212c8edd71f8/numpy-2.4.2-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:00ab83c56211a1d7c07c25e3217ea6695e50a3e2f255053686b081dc0b091a82", size = 15720138, upload-time = "2026-01-31T23:11:48.082Z" }, + { url = "https://files.pythonhosted.org/packages/ea/5c/08887c54e68e1e28df53709f1893ce92932cc6f01f7c3d4dc952f61ffd4e/numpy-2.4.2-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2fb882da679409066b4603579619341c6d6898fc83a8995199d5249f986e8e8f", size = 16655398, upload-time = "2026-01-31T23:11:50.293Z" }, + { url = "https://files.pythonhosted.org/packages/4d/89/253db0fa0e66e9129c745e4ef25631dc37d5f1314dad2b53e907b8538e6d/numpy-2.4.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:66cb9422236317f9d44b67b4d18f44efe6e9c7f8794ac0462978513359461554", size = 17079064, upload-time = "2026-01-31T23:11:52.927Z" }, + { url = "https://files.pythonhosted.org/packages/2a/d5/cbade46ce97c59c6c3da525e8d95b7abe8a42974a1dc5c1d489c10433e88/numpy-2.4.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:0f01dcf33e73d80bd8dc0f20a71303abbafa26a19e23f6b68d1aa9990af90257", size = 18379680, upload-time = "2026-01-31T23:11:55.22Z" }, + { url = "https://files.pythonhosted.org/packages/40/62/48f99ae172a4b63d981babe683685030e8a3df4f246c893ea5c6ef99f018/numpy-2.4.2-cp313-cp313t-win32.whl", hash = "sha256:52b913ec40ff7ae845687b0b34d8d93b60cb66dcee06996dd5c99f2fc9328657", size = 6082433, upload-time = "2026-01-31T23:11:58.096Z" }, + { url = "https://files.pythonhosted.org/packages/07/38/e054a61cfe48ad9f1ed0d188e78b7e26859d0b60ef21cd9de4897cdb5326/numpy-2.4.2-cp313-cp313t-win_amd64.whl", hash = "sha256:5eea80d908b2c1f91486eb95b3fb6fab187e569ec9752ab7d9333d2e66bf2d6b", size = 12451181, upload-time = "2026-01-31T23:11:59.782Z" }, + { url = "https://files.pythonhosted.org/packages/6e/a4/a05c3a6418575e185dd84d0b9680b6bb2e2dc3e4202f036b7b4e22d6e9dc/numpy-2.4.2-cp313-cp313t-win_arm64.whl", hash = "sha256:fd49860271d52127d61197bb50b64f58454e9f578cb4b2c001a6de8b1f50b0b1", size = 10290756, upload-time = "2026-01-31T23:12:02.438Z" }, + { url = "https://files.pythonhosted.org/packages/18/88/b7df6050bf18fdcfb7046286c6535cabbdd2064a3440fca3f069d319c16e/numpy-2.4.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:444be170853f1f9d528428eceb55f12918e4fda5d8805480f36a002f1415e09b", size = 16663092, upload-time = "2026-01-31T23:12:04.521Z" }, + { url = "https://files.pythonhosted.org/packages/25/7a/1fee4329abc705a469a4afe6e69b1ef7e915117747886327104a8493a955/numpy-2.4.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:d1240d50adff70c2a88217698ca844723068533f3f5c5fa6ee2e3220e3bdb000", size = 14698770, upload-time = "2026-01-31T23:12:06.96Z" }, + { url = "https://files.pythonhosted.org/packages/fb/0b/f9e49ba6c923678ad5bc38181c08ac5e53b7a5754dbca8e581aa1a56b1ff/numpy-2.4.2-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:7cdde6de52fb6664b00b056341265441192d1291c130e99183ec0d4b110ff8b1", size = 5208562, upload-time = "2026-01-31T23:12:09.632Z" }, + { url = "https://files.pythonhosted.org/packages/7d/12/d7de8f6f53f9bb76997e5e4c069eda2051e3fe134e9181671c4391677bb2/numpy-2.4.2-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:cda077c2e5b780200b6b3e09d0b42205a3d1c68f30c6dceb90401c13bff8fe74", size = 6543710, upload-time = "2026-01-31T23:12:11.969Z" }, + { url = "https://files.pythonhosted.org/packages/09/63/c66418c2e0268a31a4cf8a8b512685748200f8e8e8ec6c507ce14e773529/numpy-2.4.2-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d30291931c915b2ab5717c2974bb95ee891a1cf22ebc16a8006bd59cd210d40a", size = 15677205, upload-time = "2026-01-31T23:12:14.33Z" }, + { url = "https://files.pythonhosted.org/packages/5d/6c/7f237821c9642fb2a04d2f1e88b4295677144ca93285fd76eff3bcba858d/numpy-2.4.2-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bba37bc29d4d85761deed3954a1bc62be7cf462b9510b51d367b769a8c8df325", size = 16611738, upload-time = "2026-01-31T23:12:16.525Z" }, + { url = "https://files.pythonhosted.org/packages/c2/a7/39c4cdda9f019b609b5c473899d87abff092fc908cfe4d1ecb2fcff453b0/numpy-2.4.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b2f0073ed0868db1dcd86e052d37279eef185b9c8db5bf61f30f46adac63c909", size = 17028888, upload-time = "2026-01-31T23:12:19.306Z" }, + { url = "https://files.pythonhosted.org/packages/da/b3/e84bb64bdfea967cc10950d71090ec2d84b49bc691df0025dddb7c26e8e3/numpy-2.4.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7f54844851cdb630ceb623dcec4db3240d1ac13d4990532446761baede94996a", size = 18339556, upload-time = "2026-01-31T23:12:21.816Z" }, + { url = "https://files.pythonhosted.org/packages/88/f5/954a291bc1192a27081706862ac62bb5920fbecfbaa302f64682aa90beed/numpy-2.4.2-cp314-cp314-win32.whl", hash = "sha256:12e26134a0331d8dbd9351620f037ec470b7c75929cb8a1537f6bfe411152a1a", size = 6006899, upload-time = "2026-01-31T23:12:24.14Z" }, + { url = "https://files.pythonhosted.org/packages/05/cb/eff72a91b2efdd1bc98b3b8759f6a1654aa87612fc86e3d87d6fe4f948c4/numpy-2.4.2-cp314-cp314-win_amd64.whl", hash = "sha256:068cdb2d0d644cdb45670810894f6a0600797a69c05f1ac478e8d31670b8ee75", size = 12443072, upload-time = "2026-01-31T23:12:26.33Z" }, + { url = "https://files.pythonhosted.org/packages/37/75/62726948db36a56428fce4ba80a115716dc4fad6a3a4352487f8bb950966/numpy-2.4.2-cp314-cp314-win_arm64.whl", hash = "sha256:6ed0be1ee58eef41231a5c943d7d1375f093142702d5723ca2eb07db9b934b05", size = 10494886, upload-time = "2026-01-31T23:12:28.488Z" }, + { url = "https://files.pythonhosted.org/packages/36/2f/ee93744f1e0661dc267e4b21940870cabfae187c092e1433b77b09b50ac4/numpy-2.4.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:98f16a80e917003a12c0580f97b5f875853ebc33e2eaa4bccfc8201ac6869308", size = 14818567, upload-time = "2026-01-31T23:12:30.709Z" }, + { url = "https://files.pythonhosted.org/packages/a7/24/6535212add7d76ff938d8bdc654f53f88d35cddedf807a599e180dcb8e66/numpy-2.4.2-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:20abd069b9cda45874498b245c8015b18ace6de8546bf50dfa8cea1696ed06ef", size = 5328372, upload-time = "2026-01-31T23:12:32.962Z" }, + { url = "https://files.pythonhosted.org/packages/5e/9d/c48f0a035725f925634bf6b8994253b43f2047f6778a54147d7e213bc5a7/numpy-2.4.2-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:e98c97502435b53741540a5717a6749ac2ada901056c7db951d33e11c885cc7d", size = 6649306, upload-time = "2026-01-31T23:12:34.797Z" }, + { url = "https://files.pythonhosted.org/packages/81/05/7c73a9574cd4a53a25907bad38b59ac83919c0ddc8234ec157f344d57d9a/numpy-2.4.2-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:da6cad4e82cb893db4b69105c604d805e0c3ce11501a55b5e9f9083b47d2ffe8", size = 15722394, upload-time = "2026-01-31T23:12:36.565Z" }, + { url = "https://files.pythonhosted.org/packages/35/fa/4de10089f21fc7d18442c4a767ab156b25c2a6eaf187c0db6d9ecdaeb43f/numpy-2.4.2-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e4424677ce4b47fe73c8b5556d876571f7c6945d264201180db2dc34f676ab5", size = 16653343, upload-time = "2026-01-31T23:12:39.188Z" }, + { url = "https://files.pythonhosted.org/packages/b8/f9/d33e4ffc857f3763a57aa85650f2e82486832d7492280ac21ba9efda80da/numpy-2.4.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:2b8f157c8a6f20eb657e240f8985cc135598b2b46985c5bccbde7616dc9c6b1e", size = 17078045, upload-time = "2026-01-31T23:12:42.041Z" }, + { url = "https://files.pythonhosted.org/packages/c8/b8/54bdb43b6225badbea6389fa038c4ef868c44f5890f95dd530a218706da3/numpy-2.4.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5daf6f3914a733336dab21a05cdec343144600e964d2fcdabaac0c0269874b2a", size = 18380024, upload-time = "2026-01-31T23:12:44.331Z" }, + { url = "https://files.pythonhosted.org/packages/a5/55/6e1a61ded7af8df04016d81b5b02daa59f2ea9252ee0397cb9f631efe9e5/numpy-2.4.2-cp314-cp314t-win32.whl", hash = "sha256:8c50dd1fc8826f5b26a5ee4d77ca55d88a895f4e4819c7ecc2a9f5905047a443", size = 6153937, upload-time = "2026-01-31T23:12:47.229Z" }, + { url = "https://files.pythonhosted.org/packages/45/aa/fa6118d1ed6d776b0983f3ceac9b1a5558e80df9365b1c3aa6d42bf9eee4/numpy-2.4.2-cp314-cp314t-win_amd64.whl", hash = "sha256:fcf92bee92742edd401ba41135185866f7026c502617f422eb432cfeca4fe236", size = 12631844, upload-time = "2026-01-31T23:12:48.997Z" }, + { url = "https://files.pythonhosted.org/packages/32/0a/2ec5deea6dcd158f254a7b372fb09cfba5719419c8d66343bab35237b3fb/numpy-2.4.2-cp314-cp314t-win_arm64.whl", hash = "sha256:1f92f53998a17265194018d1cc321b2e96e900ca52d54c7c77837b71b9465181", size = 10565379, upload-time = "2026-01-31T23:12:51.345Z" }, + { url = "https://files.pythonhosted.org/packages/f4/f8/50e14d36d915ef64d8f8bc4a087fc8264d82c785eda6711f80ab7e620335/numpy-2.4.2-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:89f7268c009bc492f506abd6f5265defa7cb3f7487dc21d357c3d290add45082", size = 16833179, upload-time = "2026-01-31T23:12:53.5Z" }, + { url = "https://files.pythonhosted.org/packages/17/17/809b5cad63812058a8189e91a1e2d55a5a18fd04611dbad244e8aeae465c/numpy-2.4.2-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:e6dee3bb76aa4009d5a912180bf5b2de012532998d094acee25d9cb8dee3e44a", size = 14889755, upload-time = "2026-01-31T23:12:55.933Z" }, + { url = "https://files.pythonhosted.org/packages/3e/ea/181b9bcf7627fc8371720316c24db888dcb9829b1c0270abf3d288b2e29b/numpy-2.4.2-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:cd2bd2bbed13e213d6b55dc1d035a4f91748a7d3edc9480c13898b0353708920", size = 5399500, upload-time = "2026-01-31T23:12:58.671Z" }, + { url = "https://files.pythonhosted.org/packages/33/9f/413adf3fc955541ff5536b78fcf0754680b3c6d95103230252a2c9408d23/numpy-2.4.2-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:cf28c0c1d4c4bf00f509fa7eb02c58d7caf221b50b467bcb0d9bbf1584d5c821", size = 6714252, upload-time = "2026-01-31T23:13:00.518Z" }, + { url = "https://files.pythonhosted.org/packages/91/da/643aad274e29ccbdf42ecd94dafe524b81c87bcb56b83872d54827f10543/numpy-2.4.2-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e04ae107ac591763a47398bb45b568fc38f02dbc4aa44c063f67a131f99346cb", size = 15797142, upload-time = "2026-01-31T23:13:02.219Z" }, + { url = "https://files.pythonhosted.org/packages/66/27/965b8525e9cb5dc16481b30a1b3c21e50c7ebf6e9dbd48d0c4d0d5089c7e/numpy-2.4.2-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:602f65afdef699cda27ec0b9224ae5dc43e328f4c24c689deaf77133dbee74d0", size = 16727979, upload-time = "2026-01-31T23:13:04.62Z" }, + { url = "https://files.pythonhosted.org/packages/de/e5/b7d20451657664b07986c2f6e3be564433f5dcaf3482d68eaecd79afaf03/numpy-2.4.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:be71bf1edb48ebbbf7f6337b5bfd2f895d1902f6335a5830b20141fc126ffba0", size = 12502577, upload-time = "2026-01-31T23:13:07.08Z" }, +] + [[package]] name = "openai" version = "2.16.0" @@ -1289,6 +2566,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/16/83/0315bf2cfd75a2ce8a7e54188e9456c60cec6c0cf66728ed07bd9859ff26/openai-2.16.0-py3-none-any.whl", hash = "sha256:5f46643a8f42899a84e80c38838135d7038e7718333ce61396994f887b09a59b", size = 1068612, upload-time = "2026-01-27T23:28:00.356Z" }, ] +[[package]] +name = "openpyxl" +version = "3.1.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "et-xmlfile" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3d/f9/88d94a75de065ea32619465d2f77b29a0469500e99012523b91cc4141cd1/openpyxl-3.1.5.tar.gz", hash = "sha256:cf0e3cf56142039133628b5acffe8ef0c12bc902d2aadd3e0fe5878dc08d1050", size = 186464, upload-time = "2024-06-28T14:03:44.161Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c0/da/977ded879c29cbd04de313843e76868e6e13408a94ed6b987245dc7c8506/openpyxl-3.1.5-py2.py3-none-any.whl", hash = "sha256:5282c12b107bffeef825f4617dc029afaf41d0ea60823bbb665ef3079dc79de2", size = 250910, upload-time = "2024-06-28T14:03:41.161Z" }, +] + [[package]] name = "opentelemetry-api" version = "1.39.1" @@ -1484,6 +2773,141 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529", size = 74366, upload-time = "2026-01-21T20:50:37.788Z" }, ] +[[package]] +name = "pandas" +version = "2.3.3" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.11'", +] +dependencies = [ + { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "python-dateutil", marker = "python_full_version < '3.11'" }, + { name = "pytz", marker = "python_full_version < '3.11'" }, + { name = "tzdata", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/33/01/d40b85317f86cf08d853a4f495195c73815fdf205eef3993821720274518/pandas-2.3.3.tar.gz", hash = "sha256:e05e1af93b977f7eafa636d043f9f94c7ee3ac81af99c13508215942e64c993b", size = 4495223, upload-time = "2025-09-29T23:34:51.853Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3d/f7/f425a00df4fcc22b292c6895c6831c0c8ae1d9fac1e024d16f98a9ce8749/pandas-2.3.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:376c6446ae31770764215a6c937f72d917f214b43560603cd60da6408f183b6c", size = 11555763, upload-time = "2025-09-29T23:16:53.287Z" }, + { url = "https://files.pythonhosted.org/packages/13/4f/66d99628ff8ce7857aca52fed8f0066ce209f96be2fede6cef9f84e8d04f/pandas-2.3.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e19d192383eab2f4ceb30b412b22ea30690c9e618f78870357ae1d682912015a", size = 10801217, upload-time = "2025-09-29T23:17:04.522Z" }, + { url = "https://files.pythonhosted.org/packages/1d/03/3fc4a529a7710f890a239cc496fc6d50ad4a0995657dccc1d64695adb9f4/pandas-2.3.3-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5caf26f64126b6c7aec964f74266f435afef1c1b13da3b0636c7518a1fa3e2b1", size = 12148791, upload-time = "2025-09-29T23:17:18.444Z" }, + { url = "https://files.pythonhosted.org/packages/40/a8/4dac1f8f8235e5d25b9955d02ff6f29396191d4e665d71122c3722ca83c5/pandas-2.3.3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dd7478f1463441ae4ca7308a70e90b33470fa593429f9d4c578dd00d1fa78838", size = 12769373, upload-time = "2025-09-29T23:17:35.846Z" }, + { url = "https://files.pythonhosted.org/packages/df/91/82cc5169b6b25440a7fc0ef3a694582418d875c8e3ebf796a6d6470aa578/pandas-2.3.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4793891684806ae50d1288c9bae9330293ab4e083ccd1c5e383c34549c6e4250", size = 13200444, upload-time = "2025-09-29T23:17:49.341Z" }, + { url = "https://files.pythonhosted.org/packages/10/ae/89b3283800ab58f7af2952704078555fa60c807fff764395bb57ea0b0dbd/pandas-2.3.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:28083c648d9a99a5dd035ec125d42439c6c1c525098c58af0fc38dd1a7a1b3d4", size = 13858459, upload-time = "2025-09-29T23:18:03.722Z" }, + { url = "https://files.pythonhosted.org/packages/85/72/530900610650f54a35a19476eca5104f38555afccda1aa11a92ee14cb21d/pandas-2.3.3-cp310-cp310-win_amd64.whl", hash = "sha256:503cf027cf9940d2ceaa1a93cfb5f8c8c7e6e90720a2850378f0b3f3b1e06826", size = 11346086, upload-time = "2025-09-29T23:18:18.505Z" }, + { url = "https://files.pythonhosted.org/packages/c1/fa/7ac648108144a095b4fb6aa3de1954689f7af60a14cf25583f4960ecb878/pandas-2.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:602b8615ebcc4a0c1751e71840428ddebeb142ec02c786e8ad6b1ce3c8dec523", size = 11578790, upload-time = "2025-09-29T23:18:30.065Z" }, + { url = "https://files.pythonhosted.org/packages/9b/35/74442388c6cf008882d4d4bdfc4109be87e9b8b7ccd097ad1e7f006e2e95/pandas-2.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8fe25fc7b623b0ef6b5009149627e34d2a4657e880948ec3c840e9402e5c1b45", size = 10833831, upload-time = "2025-09-29T23:38:56.071Z" }, + { url = "https://files.pythonhosted.org/packages/fe/e4/de154cbfeee13383ad58d23017da99390b91d73f8c11856f2095e813201b/pandas-2.3.3-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b468d3dad6ff947df92dcb32ede5b7bd41a9b3cceef0a30ed925f6d01fb8fa66", size = 12199267, upload-time = "2025-09-29T23:18:41.627Z" }, + { url = "https://files.pythonhosted.org/packages/bf/c9/63f8d545568d9ab91476b1818b4741f521646cbdd151c6efebf40d6de6f7/pandas-2.3.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b98560e98cb334799c0b07ca7967ac361a47326e9b4e5a7dfb5ab2b1c9d35a1b", size = 12789281, upload-time = "2025-09-29T23:18:56.834Z" }, + { url = "https://files.pythonhosted.org/packages/f2/00/a5ac8c7a0e67fd1a6059e40aa08fa1c52cc00709077d2300e210c3ce0322/pandas-2.3.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37b5848ba49824e5c30bedb9c830ab9b7751fd049bc7914533e01c65f79791", size = 13240453, upload-time = "2025-09-29T23:19:09.247Z" }, + { url = "https://files.pythonhosted.org/packages/27/4d/5c23a5bc7bd209231618dd9e606ce076272c9bc4f12023a70e03a86b4067/pandas-2.3.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:db4301b2d1f926ae677a751eb2bd0e8c5f5319c9cb3f88b0becbbb0b07b34151", size = 13890361, upload-time = "2025-09-29T23:19:25.342Z" }, + { url = "https://files.pythonhosted.org/packages/8e/59/712db1d7040520de7a4965df15b774348980e6df45c129b8c64d0dbe74ef/pandas-2.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:f086f6fe114e19d92014a1966f43a3e62285109afe874f067f5abbdcbb10e59c", size = 11348702, upload-time = "2025-09-29T23:19:38.296Z" }, + { url = "https://files.pythonhosted.org/packages/9c/fb/231d89e8637c808b997d172b18e9d4a4bc7bf31296196c260526055d1ea0/pandas-2.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d21f6d74eb1725c2efaa71a2bfc661a0689579b58e9c0ca58a739ff0b002b53", size = 11597846, upload-time = "2025-09-29T23:19:48.856Z" }, + { url = "https://files.pythonhosted.org/packages/5c/bd/bf8064d9cfa214294356c2d6702b716d3cf3bb24be59287a6a21e24cae6b/pandas-2.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3fd2f887589c7aa868e02632612ba39acb0b8948faf5cc58f0850e165bd46f35", size = 10729618, upload-time = "2025-09-29T23:39:08.659Z" }, + { url = "https://files.pythonhosted.org/packages/57/56/cf2dbe1a3f5271370669475ead12ce77c61726ffd19a35546e31aa8edf4e/pandas-2.3.3-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ecaf1e12bdc03c86ad4a7ea848d66c685cb6851d807a26aa245ca3d2017a1908", size = 11737212, upload-time = "2025-09-29T23:19:59.765Z" }, + { url = "https://files.pythonhosted.org/packages/e5/63/cd7d615331b328e287d8233ba9fdf191a9c2d11b6af0c7a59cfcec23de68/pandas-2.3.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b3d11d2fda7eb164ef27ffc14b4fcab16a80e1ce67e9f57e19ec0afaf715ba89", size = 12362693, upload-time = "2025-09-29T23:20:14.098Z" }, + { url = "https://files.pythonhosted.org/packages/a6/de/8b1895b107277d52f2b42d3a6806e69cfef0d5cf1d0ba343470b9d8e0a04/pandas-2.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a68e15f780eddf2b07d242e17a04aa187a7ee12b40b930bfdd78070556550e98", size = 12771002, upload-time = "2025-09-29T23:20:26.76Z" }, + { url = "https://files.pythonhosted.org/packages/87/21/84072af3187a677c5893b170ba2c8fbe450a6ff911234916da889b698220/pandas-2.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:371a4ab48e950033bcf52b6527eccb564f52dc826c02afd9a1bc0ab731bba084", size = 13450971, upload-time = "2025-09-29T23:20:41.344Z" }, + { url = "https://files.pythonhosted.org/packages/86/41/585a168330ff063014880a80d744219dbf1dd7a1c706e75ab3425a987384/pandas-2.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:a16dcec078a01eeef8ee61bf64074b4e524a2a3f4b3be9326420cabe59c4778b", size = 10992722, upload-time = "2025-09-29T23:20:54.139Z" }, + { url = "https://files.pythonhosted.org/packages/cd/4b/18b035ee18f97c1040d94debd8f2e737000ad70ccc8f5513f4eefad75f4b/pandas-2.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:56851a737e3470de7fa88e6131f41281ed440d29a9268dcbf0002da5ac366713", size = 11544671, upload-time = "2025-09-29T23:21:05.024Z" }, + { url = "https://files.pythonhosted.org/packages/31/94/72fac03573102779920099bcac1c3b05975c2cb5f01eac609faf34bed1ca/pandas-2.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bdcd9d1167f4885211e401b3036c0c8d9e274eee67ea8d0758a256d60704cfe8", size = 10680807, upload-time = "2025-09-29T23:21:15.979Z" }, + { url = "https://files.pythonhosted.org/packages/16/87/9472cf4a487d848476865321de18cc8c920b8cab98453ab79dbbc98db63a/pandas-2.3.3-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e32e7cc9af0f1cc15548288a51a3b681cc2a219faa838e995f7dc53dbab1062d", size = 11709872, upload-time = "2025-09-29T23:21:27.165Z" }, + { url = "https://files.pythonhosted.org/packages/15/07/284f757f63f8a8d69ed4472bfd85122bd086e637bf4ed09de572d575a693/pandas-2.3.3-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:318d77e0e42a628c04dc56bcef4b40de67918f7041c2b061af1da41dcff670ac", size = 12306371, upload-time = "2025-09-29T23:21:40.532Z" }, + { url = "https://files.pythonhosted.org/packages/33/81/a3afc88fca4aa925804a27d2676d22dcd2031c2ebe08aabd0ae55b9ff282/pandas-2.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4e0a175408804d566144e170d0476b15d78458795bb18f1304fb94160cabf40c", size = 12765333, upload-time = "2025-09-29T23:21:55.77Z" }, + { url = "https://files.pythonhosted.org/packages/8d/0f/b4d4ae743a83742f1153464cf1a8ecfafc3ac59722a0b5c8602310cb7158/pandas-2.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:93c2d9ab0fc11822b5eece72ec9587e172f63cff87c00b062f6e37448ced4493", size = 13418120, upload-time = "2025-09-29T23:22:10.109Z" }, + { url = "https://files.pythonhosted.org/packages/4f/c7/e54682c96a895d0c808453269e0b5928a07a127a15704fedb643e9b0a4c8/pandas-2.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:f8bfc0e12dc78f777f323f55c58649591b2cd0c43534e8355c51d3fede5f4dee", size = 10993991, upload-time = "2025-09-29T23:25:04.889Z" }, + { url = "https://files.pythonhosted.org/packages/f9/ca/3f8d4f49740799189e1395812f3bf23b5e8fc7c190827d55a610da72ce55/pandas-2.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:75ea25f9529fdec2d2e93a42c523962261e567d250b0013b16210e1d40d7c2e5", size = 12048227, upload-time = "2025-09-29T23:22:24.343Z" }, + { url = "https://files.pythonhosted.org/packages/0e/5a/f43efec3e8c0cc92c4663ccad372dbdff72b60bdb56b2749f04aa1d07d7e/pandas-2.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:74ecdf1d301e812db96a465a525952f4dde225fdb6d8e5a521d47e1f42041e21", size = 11411056, upload-time = "2025-09-29T23:22:37.762Z" }, + { url = "https://files.pythonhosted.org/packages/46/b1/85331edfc591208c9d1a63a06baa67b21d332e63b7a591a5ba42a10bb507/pandas-2.3.3-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6435cb949cb34ec11cc9860246ccb2fdc9ecd742c12d3304989017d53f039a78", size = 11645189, upload-time = "2025-09-29T23:22:51.688Z" }, + { url = "https://files.pythonhosted.org/packages/44/23/78d645adc35d94d1ac4f2a3c4112ab6f5b8999f4898b8cdf01252f8df4a9/pandas-2.3.3-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:900f47d8f20860de523a1ac881c4c36d65efcb2eb850e6948140fa781736e110", size = 12121912, upload-time = "2025-09-29T23:23:05.042Z" }, + { url = "https://files.pythonhosted.org/packages/53/da/d10013df5e6aaef6b425aa0c32e1fc1f3e431e4bcabd420517dceadce354/pandas-2.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a45c765238e2ed7d7c608fc5bc4a6f88b642f2f01e70c0c23d2224dd21829d86", size = 12712160, upload-time = "2025-09-29T23:23:28.57Z" }, + { url = "https://files.pythonhosted.org/packages/bd/17/e756653095a083d8a37cbd816cb87148debcfcd920129b25f99dd8d04271/pandas-2.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c4fc4c21971a1a9f4bdb4c73978c7f7256caa3e62b323f70d6cb80db583350bc", size = 13199233, upload-time = "2025-09-29T23:24:24.876Z" }, + { url = "https://files.pythonhosted.org/packages/04/fd/74903979833db8390b73b3a8a7d30d146d710bd32703724dd9083950386f/pandas-2.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:ee15f284898e7b246df8087fc82b87b01686f98ee67d85a17b7ab44143a3a9a0", size = 11540635, upload-time = "2025-09-29T23:25:52.486Z" }, + { url = "https://files.pythonhosted.org/packages/21/00/266d6b357ad5e6d3ad55093a7e8efc7dd245f5a842b584db9f30b0f0a287/pandas-2.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1611aedd912e1ff81ff41c745822980c49ce4a7907537be8692c8dbc31924593", size = 10759079, upload-time = "2025-09-29T23:26:33.204Z" }, + { url = "https://files.pythonhosted.org/packages/ca/05/d01ef80a7a3a12b2f8bbf16daba1e17c98a2f039cbc8e2f77a2c5a63d382/pandas-2.3.3-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d2cefc361461662ac48810cb14365a365ce864afe85ef1f447ff5a1e99ea81c", size = 11814049, upload-time = "2025-09-29T23:27:15.384Z" }, + { url = "https://files.pythonhosted.org/packages/15/b2/0e62f78c0c5ba7e3d2c5945a82456f4fac76c480940f805e0b97fcbc2f65/pandas-2.3.3-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ee67acbbf05014ea6c763beb097e03cd629961c8a632075eeb34247120abcb4b", size = 12332638, upload-time = "2025-09-29T23:27:51.625Z" }, + { url = "https://files.pythonhosted.org/packages/c5/33/dd70400631b62b9b29c3c93d2feee1d0964dc2bae2e5ad7a6c73a7f25325/pandas-2.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c46467899aaa4da076d5abc11084634e2d197e9460643dd455ac3db5856b24d6", size = 12886834, upload-time = "2025-09-29T23:28:21.289Z" }, + { url = "https://files.pythonhosted.org/packages/d3/18/b5d48f55821228d0d2692b34fd5034bb185e854bdb592e9c640f6290e012/pandas-2.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6253c72c6a1d990a410bc7de641d34053364ef8bcd3126f7e7450125887dffe3", size = 13409925, upload-time = "2025-09-29T23:28:58.261Z" }, + { url = "https://files.pythonhosted.org/packages/a6/3d/124ac75fcd0ecc09b8fdccb0246ef65e35b012030defb0e0eba2cbbbe948/pandas-2.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:1b07204a219b3b7350abaae088f451860223a52cfb8a6c53358e7948735158e5", size = 11109071, upload-time = "2025-09-29T23:32:27.484Z" }, + { url = "https://files.pythonhosted.org/packages/89/9c/0e21c895c38a157e0faa1fb64587a9226d6dd46452cac4532d80c3c4a244/pandas-2.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2462b1a365b6109d275250baaae7b760fd25c726aaca0054649286bcfbb3e8ec", size = 12048504, upload-time = "2025-09-29T23:29:31.47Z" }, + { url = "https://files.pythonhosted.org/packages/d7/82/b69a1c95df796858777b68fbe6a81d37443a33319761d7c652ce77797475/pandas-2.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0242fe9a49aa8b4d78a4fa03acb397a58833ef6199e9aa40a95f027bb3a1b6e7", size = 11410702, upload-time = "2025-09-29T23:29:54.591Z" }, + { url = "https://files.pythonhosted.org/packages/f9/88/702bde3ba0a94b8c73a0181e05144b10f13f29ebfc2150c3a79062a8195d/pandas-2.3.3-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a21d830e78df0a515db2b3d2f5570610f5e6bd2e27749770e8bb7b524b89b450", size = 11634535, upload-time = "2025-09-29T23:30:21.003Z" }, + { url = "https://files.pythonhosted.org/packages/a4/1e/1bac1a839d12e6a82ec6cb40cda2edde64a2013a66963293696bbf31fbbb/pandas-2.3.3-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2e3ebdb170b5ef78f19bfb71b0dc5dc58775032361fa188e814959b74d726dd5", size = 12121582, upload-time = "2025-09-29T23:30:43.391Z" }, + { url = "https://files.pythonhosted.org/packages/44/91/483de934193e12a3b1d6ae7c8645d083ff88dec75f46e827562f1e4b4da6/pandas-2.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d051c0e065b94b7a3cea50eb1ec32e912cd96dba41647eb24104b6c6c14c5788", size = 12699963, upload-time = "2025-09-29T23:31:10.009Z" }, + { url = "https://files.pythonhosted.org/packages/70/44/5191d2e4026f86a2a109053e194d3ba7a31a2d10a9c2348368c63ed4e85a/pandas-2.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3869faf4bd07b3b66a9f462417d0ca3a9df29a9f6abd5d0d0dbab15dac7abe87", size = 13202175, upload-time = "2025-09-29T23:31:59.173Z" }, +] + +[[package]] +name = "pandas" +version = "3.0.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.14' and sys_platform == 'win32'", + "python_full_version >= '3.14' and sys_platform == 'emscripten'", + "python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", + "python_full_version == '3.13.*' and sys_platform == 'win32'", + "python_full_version == '3.13.*' and sys_platform == 'emscripten'", + "python_full_version == '3.13.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", + "python_full_version >= '3.11' and python_full_version < '3.13' and sys_platform == 'win32'", + "python_full_version >= '3.11' and python_full_version < '3.13' and sys_platform == 'emscripten'", + "python_full_version >= '3.11' and python_full_version < '3.13' and sys_platform != 'emscripten' and sys_platform != 'win32'", +] +dependencies = [ + { name = "numpy", version = "2.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "python-dateutil", marker = "python_full_version >= '3.11'" }, + { name = "tzdata", marker = "(python_full_version >= '3.11' and sys_platform == 'emscripten') or (python_full_version >= '3.11' and sys_platform == 'win32')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/de/da/b1dc0481ab8d55d0f46e343cfe67d4551a0e14fcee52bd38ca1bd73258d8/pandas-3.0.0.tar.gz", hash = "sha256:0facf7e87d38f721f0af46fe70d97373a37701b1c09f7ed7aeeb292ade5c050f", size = 4633005, upload-time = "2026-01-21T15:52:04.726Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/46/1e/b184654a856e75e975a6ee95d6577b51c271cd92cb2b020c9378f53e0032/pandas-3.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d64ce01eb9cdca96a15266aa679ae50212ec52757c79204dbc7701a222401850", size = 10313247, upload-time = "2026-01-21T15:50:15.775Z" }, + { url = "https://files.pythonhosted.org/packages/dd/5e/e04a547ad0f0183bf151fd7c7a477468e3b85ff2ad231c566389e6cc9587/pandas-3.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:613e13426069793aa1ec53bdcc3b86e8d32071daea138bbcf4fa959c9cdaa2e2", size = 9913131, upload-time = "2026-01-21T15:50:18.611Z" }, + { url = "https://files.pythonhosted.org/packages/a2/93/bb77bfa9fc2aba9f7204db807d5d3fb69832ed2854c60ba91b4c65ba9219/pandas-3.0.0-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0192fee1f1a8e743b464a6607858ee4b071deb0b118eb143d71c2a1d170996d5", size = 10741925, upload-time = "2026-01-21T15:50:21.058Z" }, + { url = "https://files.pythonhosted.org/packages/62/fb/89319812eb1d714bfc04b7f177895caeba8ab4a37ef6712db75ed786e2e0/pandas-3.0.0-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f0b853319dec8d5e0c8b875374c078ef17f2269986a78168d9bd57e49bf650ae", size = 11245979, upload-time = "2026-01-21T15:50:23.413Z" }, + { url = "https://files.pythonhosted.org/packages/a9/63/684120486f541fc88da3862ed31165b3b3e12b6a1c7b93be4597bc84e26c/pandas-3.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:707a9a877a876c326ae2cb640fbdc4ef63b0a7b9e2ef55c6df9942dcee8e2af9", size = 11756337, upload-time = "2026-01-21T15:50:25.932Z" }, + { url = "https://files.pythonhosted.org/packages/39/92/7eb0ad232312b59aec61550c3c81ad0743898d10af5df7f80bc5e5065416/pandas-3.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:afd0aa3d0b5cda6e0b8ffc10dbcca3b09ef3cbcd3fe2b27364f85fdc04e1989d", size = 12325517, upload-time = "2026-01-21T15:50:27.952Z" }, + { url = "https://files.pythonhosted.org/packages/51/27/bf9436dd0a4fc3130acec0828951c7ef96a0631969613a9a35744baf27f6/pandas-3.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:113b4cca2614ff7e5b9fee9b6f066618fe73c5a83e99d721ffc41217b2bf57dd", size = 9881576, upload-time = "2026-01-21T15:50:30.149Z" }, + { url = "https://files.pythonhosted.org/packages/e7/2b/c618b871fce0159fd107516336e82891b404e3f340821853c2fc28c7830f/pandas-3.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c14837eba8e99a8da1527c0280bba29b0eb842f64aa94982c5e21227966e164b", size = 9140807, upload-time = "2026-01-21T15:50:32.308Z" }, + { url = "https://files.pythonhosted.org/packages/0b/38/db33686f4b5fa64d7af40d96361f6a4615b8c6c8f1b3d334eee46ae6160e/pandas-3.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:9803b31f5039b3c3b10cc858c5e40054adb4b29b4d81cb2fd789f4121c8efbcd", size = 10334013, upload-time = "2026-01-21T15:50:34.771Z" }, + { url = "https://files.pythonhosted.org/packages/a5/7b/9254310594e9774906bacdd4e732415e1f86ab7dbb4b377ef9ede58cd8ec/pandas-3.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:14c2a4099cd38a1d18ff108168ea417909b2dea3bd1ebff2ccf28ddb6a74d740", size = 9874154, upload-time = "2026-01-21T15:50:36.67Z" }, + { url = "https://files.pythonhosted.org/packages/63/d4/726c5a67a13bc66643e66d2e9ff115cead482a44fc56991d0c4014f15aaf/pandas-3.0.0-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d257699b9a9960e6125686098d5714ac59d05222bef7a5e6af7a7fd87c650801", size = 10384433, upload-time = "2026-01-21T15:50:39.132Z" }, + { url = "https://files.pythonhosted.org/packages/bf/2e/9211f09bedb04f9832122942de8b051804b31a39cfbad199a819bb88d9f3/pandas-3.0.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:69780c98f286076dcafca38d8b8eee1676adf220199c0a39f0ecbf976b68151a", size = 10864519, upload-time = "2026-01-21T15:50:41.043Z" }, + { url = "https://files.pythonhosted.org/packages/00/8d/50858522cdc46ac88b9afdc3015e298959a70a08cd21e008a44e9520180c/pandas-3.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4a66384f017240f3858a4c8a7cf21b0591c3ac885cddb7758a589f0f71e87ebb", size = 11394124, upload-time = "2026-01-21T15:50:43.377Z" }, + { url = "https://files.pythonhosted.org/packages/86/3f/83b2577db02503cd93d8e95b0f794ad9d4be0ba7cb6c8bcdcac964a34a42/pandas-3.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:be8c515c9bc33989d97b89db66ea0cececb0f6e3c2a87fcc8b69443a6923e95f", size = 11920444, upload-time = "2026-01-21T15:50:45.932Z" }, + { url = "https://files.pythonhosted.org/packages/64/2d/4f8a2f192ed12c90a0aab47f5557ece0e56b0370c49de9454a09de7381b2/pandas-3.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:a453aad8c4f4e9f166436994a33884442ea62aa8b27d007311e87521b97246e1", size = 9730970, upload-time = "2026-01-21T15:50:47.962Z" }, + { url = "https://files.pythonhosted.org/packages/d4/64/ff571be435cf1e643ca98d0945d76732c0b4e9c37191a89c8550b105eed1/pandas-3.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:da768007b5a33057f6d9053563d6b74dd6d029c337d93c6d0d22a763a5c2ecc0", size = 9041950, upload-time = "2026-01-21T15:50:50.422Z" }, + { url = "https://files.pythonhosted.org/packages/6f/fa/7f0ac4ca8877c57537aaff2a842f8760e630d8e824b730eb2e859ffe96ca/pandas-3.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b78d646249b9a2bc191040988c7bb524c92fa8534fb0898a0741d7e6f2ffafa6", size = 10307129, upload-time = "2026-01-21T15:50:52.877Z" }, + { url = "https://files.pythonhosted.org/packages/6f/11/28a221815dcea4c0c9414dfc845e34a84a6a7dabc6da3194498ed5ba4361/pandas-3.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bc9cba7b355cb4162442a88ce495e01cb605f17ac1e27d6596ac963504e0305f", size = 9850201, upload-time = "2026-01-21T15:50:54.807Z" }, + { url = "https://files.pythonhosted.org/packages/ba/da/53bbc8c5363b7e5bd10f9ae59ab250fc7a382ea6ba08e4d06d8694370354/pandas-3.0.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3c9a1a149aed3b6c9bf246033ff91e1b02d529546c5d6fb6b74a28fea0cf4c70", size = 10354031, upload-time = "2026-01-21T15:50:57.463Z" }, + { url = "https://files.pythonhosted.org/packages/f7/a3/51e02ebc2a14974170d51e2410dfdab58870ea9bcd37cda15bd553d24dc4/pandas-3.0.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:95683af6175d884ee89471842acfca29172a85031fccdabc35e50c0984470a0e", size = 10861165, upload-time = "2026-01-21T15:50:59.32Z" }, + { url = "https://files.pythonhosted.org/packages/a5/fe/05a51e3cac11d161472b8297bd41723ea98013384dd6d76d115ce3482f9b/pandas-3.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1fbbb5a7288719e36b76b4f18d46ede46e7f916b6c8d9915b756b0a6c3f792b3", size = 11359359, upload-time = "2026-01-21T15:51:02.014Z" }, + { url = "https://files.pythonhosted.org/packages/ee/56/ba620583225f9b85a4d3e69c01df3e3870659cc525f67929b60e9f21dcd1/pandas-3.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8e8b9808590fa364416b49b2a35c1f4cf2785a6c156935879e57f826df22038e", size = 11912907, upload-time = "2026-01-21T15:51:05.175Z" }, + { url = "https://files.pythonhosted.org/packages/c9/8c/c6638d9f67e45e07656b3826405c5cc5f57f6fd07c8b2572ade328c86e22/pandas-3.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:98212a38a709feb90ae658cb6227ea3657c22ba8157d4b8f913cd4c950de5e7e", size = 9732138, upload-time = "2026-01-21T15:51:07.569Z" }, + { url = "https://files.pythonhosted.org/packages/7b/bf/bd1335c3bf1770b6d8fed2799993b11c4971af93bb1b729b9ebbc02ca2ec/pandas-3.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:177d9df10b3f43b70307a149d7ec49a1229a653f907aa60a48f1877d0e6be3be", size = 9033568, upload-time = "2026-01-21T15:51:09.484Z" }, + { url = "https://files.pythonhosted.org/packages/8e/c6/f5e2171914d5e29b9171d495344097d54e3ffe41d2d85d8115baba4dc483/pandas-3.0.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:2713810ad3806767b89ad3b7b69ba153e1c6ff6d9c20f9c2140379b2a98b6c98", size = 10741936, upload-time = "2026-01-21T15:51:11.693Z" }, + { url = "https://files.pythonhosted.org/packages/51/88/9a0164f99510a1acb9f548691f022c756c2314aad0d8330a24616c14c462/pandas-3.0.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:15d59f885ee5011daf8335dff47dcb8a912a27b4ad7826dc6cbe809fd145d327", size = 10393884, upload-time = "2026-01-21T15:51:14.197Z" }, + { url = "https://files.pythonhosted.org/packages/e0/53/b34d78084d88d8ae2b848591229da8826d1e65aacf00b3abe34023467648/pandas-3.0.0-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:24e6547fb64d2c92665dd2adbfa4e85fa4fd70a9c070e7cfb03b629a0bbab5eb", size = 10310740, upload-time = "2026-01-21T15:51:16.093Z" }, + { url = "https://files.pythonhosted.org/packages/5b/d3/bee792e7c3d6930b74468d990604325701412e55d7aaf47460a22311d1a5/pandas-3.0.0-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:48ee04b90e2505c693d3f8e8f524dab8cb8aaf7ddcab52c92afa535e717c4812", size = 10700014, upload-time = "2026-01-21T15:51:18.818Z" }, + { url = "https://files.pythonhosted.org/packages/55/db/2570bc40fb13aaed1cbc3fbd725c3a60ee162477982123c3adc8971e7ac1/pandas-3.0.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:66f72fb172959af42a459e27a8d8d2c7e311ff4c1f7db6deb3b643dbc382ae08", size = 11323737, upload-time = "2026-01-21T15:51:20.784Z" }, + { url = "https://files.pythonhosted.org/packages/bc/2e/297ac7f21c8181b62a4cccebad0a70caf679adf3ae5e83cb676194c8acc3/pandas-3.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4a4a400ca18230976724a5066f20878af785f36c6756e498e94c2a5e5d57779c", size = 11771558, upload-time = "2026-01-21T15:51:22.977Z" }, + { url = "https://files.pythonhosted.org/packages/0a/46/e1c6876d71c14332be70239acce9ad435975a80541086e5ffba2f249bcf6/pandas-3.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:940eebffe55528074341a5a36515f3e4c5e25e958ebbc764c9502cfc35ba3faa", size = 10473771, upload-time = "2026-01-21T15:51:25.285Z" }, + { url = "https://files.pythonhosted.org/packages/c0/db/0270ad9d13c344b7a36fa77f5f8344a46501abf413803e885d22864d10bf/pandas-3.0.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:597c08fb9fef0edf1e4fa2f9828dd27f3d78f9b8c9b4a748d435ffc55732310b", size = 10312075, upload-time = "2026-01-21T15:51:28.5Z" }, + { url = "https://files.pythonhosted.org/packages/09/9f/c176f5e9717f7c91becfe0f55a52ae445d3f7326b4a2cf355978c51b7913/pandas-3.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:447b2d68ac5edcbf94655fe909113a6dba6ef09ad7f9f60c80477825b6c489fe", size = 9900213, upload-time = "2026-01-21T15:51:30.955Z" }, + { url = "https://files.pythonhosted.org/packages/d9/e7/63ad4cc10b257b143e0a5ebb04304ad806b4e1a61c5da25f55896d2ca0f4/pandas-3.0.0-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:debb95c77ff3ed3ba0d9aa20c3a2f19165cc7956362f9873fce1ba0a53819d70", size = 10428768, upload-time = "2026-01-21T15:51:33.018Z" }, + { url = "https://files.pythonhosted.org/packages/9e/0e/4e4c2d8210f20149fd2248ef3fff26623604922bd564d915f935a06dd63d/pandas-3.0.0-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fedabf175e7cd82b69b74c30adbaa616de301291a5231138d7242596fc296a8d", size = 10882954, upload-time = "2026-01-21T15:51:35.287Z" }, + { url = "https://files.pythonhosted.org/packages/c6/60/c9de8ac906ba1f4d2250f8a951abe5135b404227a55858a75ad26f84db47/pandas-3.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:412d1a89aab46889f3033a386912efcdfa0f1131c5705ff5b668dda88305e986", size = 11430293, upload-time = "2026-01-21T15:51:37.57Z" }, + { url = "https://files.pythonhosted.org/packages/a1/69/806e6637c70920e5787a6d6896fd707f8134c2c55cd761e7249a97b7dc5a/pandas-3.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e979d22316f9350c516479dd3a92252be2937a9531ed3a26ec324198a99cdd49", size = 11952452, upload-time = "2026-01-21T15:51:39.618Z" }, + { url = "https://files.pythonhosted.org/packages/cb/de/918621e46af55164c400ab0ef389c9d969ab85a43d59ad1207d4ddbe30a5/pandas-3.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:083b11415b9970b6e7888800c43c82e81a06cd6b06755d84804444f0007d6bb7", size = 9851081, upload-time = "2026-01-21T15:51:41.758Z" }, + { url = "https://files.pythonhosted.org/packages/91/a1/3562a18dd0bd8c73344bfa26ff90c53c72f827df119d6d6b1dacc84d13e3/pandas-3.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:5db1e62cb99e739fa78a28047e861b256d17f88463c76b8dafc7c1338086dca8", size = 9174610, upload-time = "2026-01-21T15:51:44.312Z" }, + { url = "https://files.pythonhosted.org/packages/ce/26/430d91257eaf366f1737d7a1c158677caaf6267f338ec74e3a1ec444111c/pandas-3.0.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:697b8f7d346c68274b1b93a170a70974cdc7d7354429894d5927c1effdcccd73", size = 10761999, upload-time = "2026-01-21T15:51:46.899Z" }, + { url = "https://files.pythonhosted.org/packages/ec/1a/954eb47736c2b7f7fe6a9d56b0cb6987773c00faa3c6451a43db4beb3254/pandas-3.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:8cb3120f0d9467ed95e77f67a75e030b67545bcfa08964e349252d674171def2", size = 10410279, upload-time = "2026-01-21T15:51:48.89Z" }, + { url = "https://files.pythonhosted.org/packages/20/fc/b96f3a5a28b250cd1b366eb0108df2501c0f38314a00847242abab71bb3a/pandas-3.0.0-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:33fd3e6baa72899746b820c31e4b9688c8e1b7864d7aec2de7ab5035c285277a", size = 10330198, upload-time = "2026-01-21T15:51:51.015Z" }, + { url = "https://files.pythonhosted.org/packages/90/b3/d0e2952f103b4fbef1ef22d0c2e314e74fc9064b51cee30890b5e3286ee6/pandas-3.0.0-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8942e333dc67ceda1095227ad0febb05a3b36535e520154085db632c40ad084", size = 10728513, upload-time = "2026-01-21T15:51:53.387Z" }, + { url = "https://files.pythonhosted.org/packages/76/81/832894f286df828993dc5fd61c63b231b0fb73377e99f6c6c369174cf97e/pandas-3.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:783ac35c4d0fe0effdb0d67161859078618b1b6587a1af15928137525217a721", size = 11345550, upload-time = "2026-01-21T15:51:55.329Z" }, + { url = "https://files.pythonhosted.org/packages/34/a0/ed160a00fb4f37d806406bc0a79a8b62fe67f29d00950f8d16203ff3409b/pandas-3.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:125eb901e233f155b268bbef9abd9afb5819db74f0e677e89a61b246228c71ac", size = 11799386, upload-time = "2026-01-21T15:51:57.457Z" }, + { url = "https://files.pythonhosted.org/packages/36/c8/2ac00d7255252c5e3cf61b35ca92ca25704b0188f7454ca4aec08a33cece/pandas-3.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:b86d113b6c109df3ce0ad5abbc259fe86a1bd4adfd4a31a89da42f84f65509bb", size = 10873041, upload-time = "2026-01-21T15:52:00.034Z" }, + { url = "https://files.pythonhosted.org/packages/e6/3f/a80ac00acbc6b35166b42850e98a4f466e2c0d9c64054161ba9620f95680/pandas-3.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:1c39eab3ad38f2d7a249095f0a3d8f8c22cc0f847e98ccf5bbe732b272e2d9fa", size = 9441003, upload-time = "2026-01-21T15:52:02.281Z" }, +] + [[package]] name = "pastel" version = "0.2.1" @@ -1502,6 +2926,117 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ef/3c/2c197d226f9ea224a9ab8d197933f9da0ae0aac5b6e0f884e2b8d9c8e9f7/pathspec-1.0.4-py3-none-any.whl", hash = "sha256:fb6ae2fd4e7c921a165808a552060e722767cfa526f99ca5156ed2ce45a5c723", size = 55206, upload-time = "2026-01-27T03:59:45.137Z" }, ] +[[package]] +name = "pdfminer-six" +version = "20260107" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "charset-normalizer" }, + { name = "cryptography" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/34/a4/5cec1112009f0439a5ca6afa8ace321f0ab2f48da3255b7a1c8953014670/pdfminer_six-20260107.tar.gz", hash = "sha256:96bfd431e3577a55a0efd25676968ca4ce8fd5b53f14565f85716ff363889602", size = 8512094, upload-time = "2026-01-07T13:29:12.937Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/8b/28c4eaec9d6b036a52cb44720408f26b1a143ca9bce76cc19e8f5de00ab4/pdfminer_six-20260107-py3-none-any.whl", hash = "sha256:366585ba97e80dffa8f00cebe303d2f381884d8637af4ce422f1df3ef38111a9", size = 6592252, upload-time = "2026-01-07T13:29:10.742Z" }, +] + +[[package]] +name = "pillow" +version = "12.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d0/02/d52c733a2452ef1ffcc123b68e6606d07276b0e358db70eabad7e40042b7/pillow-12.1.0.tar.gz", hash = "sha256:5c5ae0a06e9ea030ab786b0251b32c7e4ce10e58d983c0d5c56029455180b5b9", size = 46977283, upload-time = "2026-01-02T09:13:29.892Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fe/41/f73d92b6b883a579e79600d391f2e21cb0df767b2714ecbd2952315dfeef/pillow-12.1.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:fb125d860738a09d363a88daa0f59c4533529a90e564785e20fe875b200b6dbd", size = 5304089, upload-time = "2026-01-02T09:10:24.953Z" }, + { url = "https://files.pythonhosted.org/packages/94/55/7aca2891560188656e4a91ed9adba305e914a4496800da6b5c0a15f09edf/pillow-12.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cad302dc10fac357d3467a74a9561c90609768a6f73a1923b0fd851b6486f8b0", size = 4657815, upload-time = "2026-01-02T09:10:27.063Z" }, + { url = "https://files.pythonhosted.org/packages/e9/d2/b28221abaa7b4c40b7dba948f0f6a708bd7342c4d47ce342f0ea39643974/pillow-12.1.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:a40905599d8079e09f25027423aed94f2823adaf2868940de991e53a449e14a8", size = 6222593, upload-time = "2026-01-02T09:10:29.115Z" }, + { url = "https://files.pythonhosted.org/packages/71/b8/7a61fb234df6a9b0b479f69e66901209d89ff72a435b49933f9122f94cac/pillow-12.1.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:92a7fe4225365c5e3a8e598982269c6d6698d3e783b3b1ae979e7819f9cd55c1", size = 8027579, upload-time = "2026-01-02T09:10:31.182Z" }, + { url = "https://files.pythonhosted.org/packages/ea/51/55c751a57cc524a15a0e3db20e5cde517582359508d62305a627e77fd295/pillow-12.1.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f10c98f49227ed8383d28174ee95155a675c4ed7f85e2e573b04414f7e371bda", size = 6335760, upload-time = "2026-01-02T09:10:33.02Z" }, + { url = "https://files.pythonhosted.org/packages/dc/7c/60e3e6f5e5891a1a06b4c910f742ac862377a6fe842f7184df4a274ce7bf/pillow-12.1.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8637e29d13f478bc4f153d8daa9ffb16455f0a6cb287da1b432fdad2bfbd66c7", size = 7027127, upload-time = "2026-01-02T09:10:35.009Z" }, + { url = "https://files.pythonhosted.org/packages/06/37/49d47266ba50b00c27ba63a7c898f1bb41a29627ced8c09e25f19ebec0ff/pillow-12.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:21e686a21078b0f9cb8c8a961d99e6a4ddb88e0fc5ea6e130172ddddc2e5221a", size = 6449896, upload-time = "2026-01-02T09:10:36.793Z" }, + { url = "https://files.pythonhosted.org/packages/f9/e5/67fd87d2913902462cd9b79c6211c25bfe95fcf5783d06e1367d6d9a741f/pillow-12.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2415373395a831f53933c23ce051021e79c8cd7979822d8cc478547a3f4da8ef", size = 7151345, upload-time = "2026-01-02T09:10:39.064Z" }, + { url = "https://files.pythonhosted.org/packages/bd/15/f8c7abf82af68b29f50d77c227e7a1f87ce02fdc66ded9bf603bc3b41180/pillow-12.1.0-cp310-cp310-win32.whl", hash = "sha256:e75d3dba8fc1ddfec0cd752108f93b83b4f8d6ab40e524a95d35f016b9683b09", size = 6325568, upload-time = "2026-01-02T09:10:41.035Z" }, + { url = "https://files.pythonhosted.org/packages/d4/24/7d1c0e160b6b5ac2605ef7d8be537e28753c0db5363d035948073f5513d7/pillow-12.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:64efdf00c09e31efd754448a383ea241f55a994fd079866b92d2bbff598aad91", size = 7032367, upload-time = "2026-01-02T09:10:43.09Z" }, + { url = "https://files.pythonhosted.org/packages/f4/03/41c038f0d7a06099254c60f618d0ec7be11e79620fc23b8e85e5b31d9a44/pillow-12.1.0-cp310-cp310-win_arm64.whl", hash = "sha256:f188028b5af6b8fb2e9a76ac0f841a575bd1bd396e46ef0840d9b88a48fdbcea", size = 2452345, upload-time = "2026-01-02T09:10:44.795Z" }, + { url = "https://files.pythonhosted.org/packages/43/c4/bf8328039de6cc22182c3ef007a2abfbbdab153661c0a9aa78af8d706391/pillow-12.1.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:a83e0850cb8f5ac975291ebfc4170ba481f41a28065277f7f735c202cd8e0af3", size = 5304057, upload-time = "2026-01-02T09:10:46.627Z" }, + { url = "https://files.pythonhosted.org/packages/43/06/7264c0597e676104cc22ca73ee48f752767cd4b1fe084662620b17e10120/pillow-12.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b6e53e82ec2db0717eabb276aa56cf4e500c9a7cec2c2e189b55c24f65a3e8c0", size = 4657811, upload-time = "2026-01-02T09:10:49.548Z" }, + { url = "https://files.pythonhosted.org/packages/72/64/f9189e44474610daf83da31145fa56710b627b5c4c0b9c235e34058f6b31/pillow-12.1.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:40a8e3b9e8773876d6e30daed22f016509e3987bab61b3b7fe309d7019a87451", size = 6232243, upload-time = "2026-01-02T09:10:51.62Z" }, + { url = "https://files.pythonhosted.org/packages/ef/30/0df458009be6a4caca4ca2c52975e6275c387d4e5c95544e34138b41dc86/pillow-12.1.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:800429ac32c9b72909c671aaf17ecd13110f823ddb7db4dfef412a5587c2c24e", size = 8037872, upload-time = "2026-01-02T09:10:53.446Z" }, + { url = "https://files.pythonhosted.org/packages/e4/86/95845d4eda4f4f9557e25381d70876aa213560243ac1a6d619c46caaedd9/pillow-12.1.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0b022eaaf709541b391ee069f0022ee5b36c709df71986e3f7be312e46f42c84", size = 6345398, upload-time = "2026-01-02T09:10:55.426Z" }, + { url = "https://files.pythonhosted.org/packages/5c/1f/8e66ab9be3aaf1435bc03edd1ebdf58ffcd17f7349c1d970cafe87af27d9/pillow-12.1.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1f345e7bc9d7f368887c712aa5054558bad44d2a301ddf9248599f4161abc7c0", size = 7034667, upload-time = "2026-01-02T09:10:57.11Z" }, + { url = "https://files.pythonhosted.org/packages/f9/f6/683b83cb9b1db1fb52b87951b1c0b99bdcfceaa75febf11406c19f82cb5e/pillow-12.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d70347c8a5b7ccd803ec0c85c8709f036e6348f1e6a5bf048ecd9c64d3550b8b", size = 6458743, upload-time = "2026-01-02T09:10:59.331Z" }, + { url = "https://files.pythonhosted.org/packages/9a/7d/de833d63622538c1d58ce5395e7c6cb7e7dce80decdd8bde4a484e095d9f/pillow-12.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1fcc52d86ce7a34fd17cb04e87cfdb164648a3662a6f20565910a99653d66c18", size = 7159342, upload-time = "2026-01-02T09:11:01.82Z" }, + { url = "https://files.pythonhosted.org/packages/8c/40/50d86571c9e5868c42b81fe7da0c76ca26373f3b95a8dd675425f4a92ec1/pillow-12.1.0-cp311-cp311-win32.whl", hash = "sha256:3ffaa2f0659e2f740473bcf03c702c39a8d4b2b7ffc629052028764324842c64", size = 6328655, upload-time = "2026-01-02T09:11:04.556Z" }, + { url = "https://files.pythonhosted.org/packages/6c/af/b1d7e301c4cd26cd45d4af884d9ee9b6fab893b0ad2450d4746d74a6968c/pillow-12.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:806f3987ffe10e867bab0ddad45df1148a2b98221798457fa097ad85d6e8bc75", size = 7031469, upload-time = "2026-01-02T09:11:06.538Z" }, + { url = "https://files.pythonhosted.org/packages/48/36/d5716586d887fb2a810a4a61518a327a1e21c8b7134c89283af272efe84b/pillow-12.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:9f5fefaca968e700ad1a4a9de98bf0869a94e397fe3524c4c9450c1445252304", size = 2452515, upload-time = "2026-01-02T09:11:08.226Z" }, + { url = "https://files.pythonhosted.org/packages/20/31/dc53fe21a2f2996e1b7d92bf671cdb157079385183ef7c1ae08b485db510/pillow-12.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a332ac4ccb84b6dde65dbace8431f3af08874bf9770719d32a635c4ef411b18b", size = 5262642, upload-time = "2026-01-02T09:11:10.138Z" }, + { url = "https://files.pythonhosted.org/packages/ab/c1/10e45ac9cc79419cedf5121b42dcca5a50ad2b601fa080f58c22fb27626e/pillow-12.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:907bfa8a9cb790748a9aa4513e37c88c59660da3bcfffbd24a7d9e6abf224551", size = 4657464, upload-time = "2026-01-02T09:11:12.319Z" }, + { url = "https://files.pythonhosted.org/packages/ad/26/7b82c0ab7ef40ebede7a97c72d473bda5950f609f8e0c77b04af574a0ddb/pillow-12.1.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:efdc140e7b63b8f739d09a99033aa430accce485ff78e6d311973a67b6bf3208", size = 6234878, upload-time = "2026-01-02T09:11:14.096Z" }, + { url = "https://files.pythonhosted.org/packages/76/25/27abc9792615b5e886ca9411ba6637b675f1b77af3104710ac7353fe5605/pillow-12.1.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bef9768cab184e7ae6e559c032e95ba8d07b3023c289f79a2bd36e8bf85605a5", size = 8044868, upload-time = "2026-01-02T09:11:15.903Z" }, + { url = "https://files.pythonhosted.org/packages/0a/ea/f200a4c36d836100e7bc738fc48cd963d3ba6372ebc8298a889e0cfc3359/pillow-12.1.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:742aea052cf5ab5034a53c3846165bc3ce88d7c38e954120db0ab867ca242661", size = 6349468, upload-time = "2026-01-02T09:11:17.631Z" }, + { url = "https://files.pythonhosted.org/packages/11/8f/48d0b77ab2200374c66d344459b8958c86693be99526450e7aee714e03e4/pillow-12.1.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a6dfc2af5b082b635af6e08e0d1f9f1c4e04d17d4e2ca0ef96131e85eda6eb17", size = 7041518, upload-time = "2026-01-02T09:11:19.389Z" }, + { url = "https://files.pythonhosted.org/packages/1d/23/c281182eb986b5d31f0a76d2a2c8cd41722d6fb8ed07521e802f9bba52de/pillow-12.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:609e89d9f90b581c8d16358c9087df76024cf058fa693dd3e1e1620823f39670", size = 6462829, upload-time = "2026-01-02T09:11:21.28Z" }, + { url = "https://files.pythonhosted.org/packages/25/ef/7018273e0faac099d7b00982abdcc39142ae6f3bd9ceb06de09779c4a9d6/pillow-12.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:43b4899cfd091a9693a1278c4982f3e50f7fb7cff5153b05174b4afc9593b616", size = 7166756, upload-time = "2026-01-02T09:11:23.559Z" }, + { url = "https://files.pythonhosted.org/packages/8f/c8/993d4b7ab2e341fe02ceef9576afcf5830cdec640be2ac5bee1820d693d4/pillow-12.1.0-cp312-cp312-win32.whl", hash = "sha256:aa0c9cc0b82b14766a99fbe6084409972266e82f459821cd26997a488a7261a7", size = 6328770, upload-time = "2026-01-02T09:11:25.661Z" }, + { url = "https://files.pythonhosted.org/packages/a7/87/90b358775a3f02765d87655237229ba64a997b87efa8ccaca7dd3e36e7a7/pillow-12.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:d70534cea9e7966169ad29a903b99fc507e932069a881d0965a1a84bb57f6c6d", size = 7033406, upload-time = "2026-01-02T09:11:27.474Z" }, + { url = "https://files.pythonhosted.org/packages/5d/cf/881b457eccacac9e5b2ddd97d5071fb6d668307c57cbf4e3b5278e06e536/pillow-12.1.0-cp312-cp312-win_arm64.whl", hash = "sha256:65b80c1ee7e14a87d6a068dd3b0aea268ffcabfe0498d38661b00c5b4b22e74c", size = 2452612, upload-time = "2026-01-02T09:11:29.309Z" }, + { url = "https://files.pythonhosted.org/packages/dd/c7/2530a4aa28248623e9d7f27316b42e27c32ec410f695929696f2e0e4a778/pillow-12.1.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:7b5dd7cbae20285cdb597b10eb5a2c13aa9de6cde9bb64a3c1317427b1db1ae1", size = 4062543, upload-time = "2026-01-02T09:11:31.566Z" }, + { url = "https://files.pythonhosted.org/packages/8f/1f/40b8eae823dc1519b87d53c30ed9ef085506b05281d313031755c1705f73/pillow-12.1.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:29a4cef9cb672363926f0470afc516dbf7305a14d8c54f7abbb5c199cd8f8179", size = 4138373, upload-time = "2026-01-02T09:11:33.367Z" }, + { url = "https://files.pythonhosted.org/packages/d4/77/6fa60634cf06e52139fd0e89e5bbf055e8166c691c42fb162818b7fda31d/pillow-12.1.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:681088909d7e8fa9e31b9799aaa59ba5234c58e5e4f1951b4c4d1082a2e980e0", size = 3601241, upload-time = "2026-01-02T09:11:35.011Z" }, + { url = "https://files.pythonhosted.org/packages/4f/bf/28ab865de622e14b747f0cd7877510848252d950e43002e224fb1c9ababf/pillow-12.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:983976c2ab753166dc66d36af6e8ec15bb511e4a25856e2227e5f7e00a160587", size = 5262410, upload-time = "2026-01-02T09:11:36.682Z" }, + { url = "https://files.pythonhosted.org/packages/1c/34/583420a1b55e715937a85bd48c5c0991598247a1fd2eb5423188e765ea02/pillow-12.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:db44d5c160a90df2d24a24760bbd37607d53da0b34fb546c4c232af7192298ac", size = 4657312, upload-time = "2026-01-02T09:11:38.535Z" }, + { url = "https://files.pythonhosted.org/packages/1d/fd/f5a0896839762885b3376ff04878f86ab2b097c2f9a9cdccf4eda8ba8dc0/pillow-12.1.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6b7a9d1db5dad90e2991645874f708e87d9a3c370c243c2d7684d28f7e133e6b", size = 6232605, upload-time = "2026-01-02T09:11:40.602Z" }, + { url = "https://files.pythonhosted.org/packages/98/aa/938a09d127ac1e70e6ed467bd03834350b33ef646b31edb7452d5de43792/pillow-12.1.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6258f3260986990ba2fa8a874f8b6e808cf5abb51a94015ca3dc3c68aa4f30ea", size = 8041617, upload-time = "2026-01-02T09:11:42.721Z" }, + { url = "https://files.pythonhosted.org/packages/17/e8/538b24cb426ac0186e03f80f78bc8dc7246c667f58b540bdd57c71c9f79d/pillow-12.1.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e115c15e3bc727b1ca3e641a909f77f8ca72a64fff150f666fcc85e57701c26c", size = 6346509, upload-time = "2026-01-02T09:11:44.955Z" }, + { url = "https://files.pythonhosted.org/packages/01/9a/632e58ec89a32738cabfd9ec418f0e9898a2b4719afc581f07c04a05e3c9/pillow-12.1.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6741e6f3074a35e47c77b23a4e4f2d90db3ed905cb1c5e6e0d49bff2045632bc", size = 7038117, upload-time = "2026-01-02T09:11:46.736Z" }, + { url = "https://files.pythonhosted.org/packages/c7/a2/d40308cf86eada842ca1f3ffa45d0ca0df7e4ab33c83f81e73f5eaed136d/pillow-12.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:935b9d1aed48fcfb3f838caac506f38e29621b44ccc4f8a64d575cb1b2a88644", size = 6460151, upload-time = "2026-01-02T09:11:48.625Z" }, + { url = "https://files.pythonhosted.org/packages/f1/88/f5b058ad6453a085c5266660a1417bdad590199da1b32fb4efcff9d33b05/pillow-12.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5fee4c04aad8932da9f8f710af2c1a15a83582cfb884152a9caa79d4efcdbf9c", size = 7164534, upload-time = "2026-01-02T09:11:50.445Z" }, + { url = "https://files.pythonhosted.org/packages/19/ce/c17334caea1db789163b5d855a5735e47995b0b5dc8745e9a3605d5f24c0/pillow-12.1.0-cp313-cp313-win32.whl", hash = "sha256:a786bf667724d84aa29b5db1c61b7bfdde380202aaca12c3461afd6b71743171", size = 6332551, upload-time = "2026-01-02T09:11:52.234Z" }, + { url = "https://files.pythonhosted.org/packages/e5/07/74a9d941fa45c90a0d9465098fe1ec85de3e2afbdc15cc4766622d516056/pillow-12.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:461f9dfdafa394c59cd6d818bdfdbab4028b83b02caadaff0ffd433faf4c9a7a", size = 7040087, upload-time = "2026-01-02T09:11:54.822Z" }, + { url = "https://files.pythonhosted.org/packages/88/09/c99950c075a0e9053d8e880595926302575bc742b1b47fe1bbcc8d388d50/pillow-12.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:9212d6b86917a2300669511ed094a9406888362e085f2431a7da985a6b124f45", size = 2452470, upload-time = "2026-01-02T09:11:56.522Z" }, + { url = "https://files.pythonhosted.org/packages/b5/ba/970b7d85ba01f348dee4d65412476321d40ee04dcb51cd3735b9dc94eb58/pillow-12.1.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:00162e9ca6d22b7c3ee8e61faa3c3253cd19b6a37f126cad04f2f88b306f557d", size = 5264816, upload-time = "2026-01-02T09:11:58.227Z" }, + { url = "https://files.pythonhosted.org/packages/10/60/650f2fb55fdba7a510d836202aa52f0baac633e50ab1cf18415d332188fb/pillow-12.1.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:7d6daa89a00b58c37cb1747ec9fb7ac3bc5ffd5949f5888657dfddde6d1312e0", size = 4660472, upload-time = "2026-01-02T09:12:00.798Z" }, + { url = "https://files.pythonhosted.org/packages/2b/c0/5273a99478956a099d533c4f46cbaa19fd69d606624f4334b85e50987a08/pillow-12.1.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e2479c7f02f9d505682dc47df8c0ea1fc5e264c4d1629a5d63fe3e2334b89554", size = 6268974, upload-time = "2026-01-02T09:12:02.572Z" }, + { url = "https://files.pythonhosted.org/packages/b4/26/0bf714bc2e73d5267887d47931d53c4ceeceea6978148ed2ab2a4e6463c4/pillow-12.1.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f188d580bd870cda1e15183790d1cc2fa78f666e76077d103edf048eed9c356e", size = 8073070, upload-time = "2026-01-02T09:12:04.75Z" }, + { url = "https://files.pythonhosted.org/packages/43/cf/1ea826200de111a9d65724c54f927f3111dc5ae297f294b370a670c17786/pillow-12.1.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0fde7ec5538ab5095cc02df38ee99b0443ff0e1c847a045554cf5f9af1f4aa82", size = 6380176, upload-time = "2026-01-02T09:12:06.626Z" }, + { url = "https://files.pythonhosted.org/packages/03/e0/7938dd2b2013373fd85d96e0f38d62b7a5a262af21ac274250c7ca7847c9/pillow-12.1.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0ed07dca4a8464bada6139ab38f5382f83e5f111698caf3191cb8dbf27d908b4", size = 7067061, upload-time = "2026-01-02T09:12:08.624Z" }, + { url = "https://files.pythonhosted.org/packages/86/ad/a2aa97d37272a929a98437a8c0ac37b3cf012f4f8721e1bd5154699b2518/pillow-12.1.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:f45bd71d1fa5e5749587613037b172e0b3b23159d1c00ef2fc920da6f470e6f0", size = 6491824, upload-time = "2026-01-02T09:12:10.488Z" }, + { url = "https://files.pythonhosted.org/packages/a4/44/80e46611b288d51b115826f136fb3465653c28f491068a72d3da49b54cd4/pillow-12.1.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:277518bf4fe74aa91489e1b20577473b19ee70fb97c374aa50830b279f25841b", size = 7190911, upload-time = "2026-01-02T09:12:12.772Z" }, + { url = "https://files.pythonhosted.org/packages/86/77/eacc62356b4cf81abe99ff9dbc7402750044aed02cfd6a503f7c6fc11f3e/pillow-12.1.0-cp313-cp313t-win32.whl", hash = "sha256:7315f9137087c4e0ee73a761b163fc9aa3b19f5f606a7fc08d83fd3e4379af65", size = 6336445, upload-time = "2026-01-02T09:12:14.775Z" }, + { url = "https://files.pythonhosted.org/packages/e7/3c/57d81d0b74d218706dafccb87a87ea44262c43eef98eb3b164fd000e0491/pillow-12.1.0-cp313-cp313t-win_amd64.whl", hash = "sha256:0ddedfaa8b5f0b4ffbc2fa87b556dc59f6bb4ecb14a53b33f9189713ae8053c0", size = 7045354, upload-time = "2026-01-02T09:12:16.599Z" }, + { url = "https://files.pythonhosted.org/packages/ac/82/8b9b97bba2e3576a340f93b044a3a3a09841170ab4c1eb0d5c93469fd32f/pillow-12.1.0-cp313-cp313t-win_arm64.whl", hash = "sha256:80941e6d573197a0c28f394753de529bb436b1ca990ed6e765cf42426abc39f8", size = 2454547, upload-time = "2026-01-02T09:12:18.704Z" }, + { url = "https://files.pythonhosted.org/packages/8c/87/bdf971d8bbcf80a348cc3bacfcb239f5882100fe80534b0ce67a784181d8/pillow-12.1.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:5cb7bc1966d031aec37ddb9dcf15c2da5b2e9f7cc3ca7c54473a20a927e1eb91", size = 4062533, upload-time = "2026-01-02T09:12:20.791Z" }, + { url = "https://files.pythonhosted.org/packages/ff/4f/5eb37a681c68d605eb7034c004875c81f86ec9ef51f5be4a63eadd58859a/pillow-12.1.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:97e9993d5ed946aba26baf9c1e8cf18adbab584b99f452ee72f7ee8acb882796", size = 4138546, upload-time = "2026-01-02T09:12:23.664Z" }, + { url = "https://files.pythonhosted.org/packages/11/6d/19a95acb2edbace40dcd582d077b991646b7083c41b98da4ed7555b59733/pillow-12.1.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:414b9a78e14ffeb98128863314e62c3f24b8a86081066625700b7985b3f529bd", size = 3601163, upload-time = "2026-01-02T09:12:26.338Z" }, + { url = "https://files.pythonhosted.org/packages/fc/36/2b8138e51cb42e4cc39c3297713455548be855a50558c3ac2beebdc251dd/pillow-12.1.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:e6bdb408f7c9dd2a5ff2b14a3b0bb6d4deb29fb9961e6eb3ae2031ae9a5cec13", size = 5266086, upload-time = "2026-01-02T09:12:28.782Z" }, + { url = "https://files.pythonhosted.org/packages/53/4b/649056e4d22e1caa90816bf99cef0884aed607ed38075bd75f091a607a38/pillow-12.1.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:3413c2ae377550f5487991d444428f1a8ae92784aac79caa8b1e3b89b175f77e", size = 4657344, upload-time = "2026-01-02T09:12:31.117Z" }, + { url = "https://files.pythonhosted.org/packages/6c/6b/c5742cea0f1ade0cd61485dc3d81f05261fc2276f537fbdc00802de56779/pillow-12.1.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e5dcbe95016e88437ecf33544ba5db21ef1b8dd6e1b434a2cb2a3d605299e643", size = 6232114, upload-time = "2026-01-02T09:12:32.936Z" }, + { url = "https://files.pythonhosted.org/packages/bf/8f/9f521268ce22d63991601aafd3d48d5ff7280a246a1ef62d626d67b44064/pillow-12.1.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d0a7735df32ccbcc98b98a1ac785cc4b19b580be1bdf0aeb5c03223220ea09d5", size = 8042708, upload-time = "2026-01-02T09:12:34.78Z" }, + { url = "https://files.pythonhosted.org/packages/1a/eb/257f38542893f021502a1bbe0c2e883c90b5cff26cc33b1584a841a06d30/pillow-12.1.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0c27407a2d1b96774cbc4a7594129cc027339fd800cd081e44497722ea1179de", size = 6347762, upload-time = "2026-01-02T09:12:36.748Z" }, + { url = "https://files.pythonhosted.org/packages/c4/5a/8ba375025701c09b309e8d5163c5a4ce0102fa86bbf8800eb0d7ac87bc51/pillow-12.1.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:15c794d74303828eaa957ff8070846d0efe8c630901a1c753fdc63850e19ecd9", size = 7039265, upload-time = "2026-01-02T09:12:39.082Z" }, + { url = "https://files.pythonhosted.org/packages/cf/dc/cf5e4cdb3db533f539e88a7bbf9f190c64ab8a08a9bc7a4ccf55067872e4/pillow-12.1.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c990547452ee2800d8506c4150280757f88532f3de2a58e3022e9b179107862a", size = 6462341, upload-time = "2026-01-02T09:12:40.946Z" }, + { url = "https://files.pythonhosted.org/packages/d0/47/0291a25ac9550677e22eda48510cfc4fa4b2ef0396448b7fbdc0a6946309/pillow-12.1.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b63e13dd27da389ed9475b3d28510f0f954bca0041e8e551b2a4eb1eab56a39a", size = 7165395, upload-time = "2026-01-02T09:12:42.706Z" }, + { url = "https://files.pythonhosted.org/packages/4f/4c/e005a59393ec4d9416be06e6b45820403bb946a778e39ecec62f5b2b991e/pillow-12.1.0-cp314-cp314-win32.whl", hash = "sha256:1a949604f73eb07a8adab38c4fe50791f9919344398bdc8ac6b307f755fc7030", size = 6431413, upload-time = "2026-01-02T09:12:44.944Z" }, + { url = "https://files.pythonhosted.org/packages/1c/af/f23697f587ac5f9095d67e31b81c95c0249cd461a9798a061ed6709b09b5/pillow-12.1.0-cp314-cp314-win_amd64.whl", hash = "sha256:4f9f6a650743f0ddee5593ac9e954ba1bdbc5e150bc066586d4f26127853ab94", size = 7176779, upload-time = "2026-01-02T09:12:46.727Z" }, + { url = "https://files.pythonhosted.org/packages/b3/36/6a51abf8599232f3e9afbd16d52829376a68909fe14efe29084445db4b73/pillow-12.1.0-cp314-cp314-win_arm64.whl", hash = "sha256:808b99604f7873c800c4840f55ff389936ef1948e4e87645eaf3fccbc8477ac4", size = 2543105, upload-time = "2026-01-02T09:12:49.243Z" }, + { url = "https://files.pythonhosted.org/packages/82/54/2e1dd20c8749ff225080d6ba465a0cab4387f5db0d1c5fb1439e2d99923f/pillow-12.1.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:bc11908616c8a283cf7d664f77411a5ed2a02009b0097ff8abbba5e79128ccf2", size = 5268571, upload-time = "2026-01-02T09:12:51.11Z" }, + { url = "https://files.pythonhosted.org/packages/57/61/571163a5ef86ec0cf30d265ac2a70ae6fc9e28413d1dc94fa37fae6bda89/pillow-12.1.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:896866d2d436563fa2a43a9d72f417874f16b5545955c54a64941e87c1376c61", size = 4660426, upload-time = "2026-01-02T09:12:52.865Z" }, + { url = "https://files.pythonhosted.org/packages/5e/e1/53ee5163f794aef1bf84243f755ee6897a92c708505350dd1923f4afec48/pillow-12.1.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8e178e3e99d3c0ea8fc64b88447f7cac8ccf058af422a6cedc690d0eadd98c51", size = 6269908, upload-time = "2026-01-02T09:12:54.884Z" }, + { url = "https://files.pythonhosted.org/packages/bc/0b/b4b4106ff0ee1afa1dc599fde6ab230417f800279745124f6c50bcffed8e/pillow-12.1.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:079af2fb0c599c2ec144ba2c02766d1b55498e373b3ac64687e43849fbbef5bc", size = 8074733, upload-time = "2026-01-02T09:12:56.802Z" }, + { url = "https://files.pythonhosted.org/packages/19/9f/80b411cbac4a732439e629a26ad3ef11907a8c7fc5377b7602f04f6fe4e7/pillow-12.1.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bdec5e43377761c5dbca620efb69a77f6855c5a379e32ac5b158f54c84212b14", size = 6381431, upload-time = "2026-01-02T09:12:58.823Z" }, + { url = "https://files.pythonhosted.org/packages/8f/b7/d65c45db463b66ecb6abc17c6ba6917a911202a07662247e1355ce1789e7/pillow-12.1.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:565c986f4b45c020f5421a4cea13ef294dde9509a8577f29b2fc5edc7587fff8", size = 7068529, upload-time = "2026-01-02T09:13:00.885Z" }, + { url = "https://files.pythonhosted.org/packages/50/96/dfd4cd726b4a45ae6e3c669fc9e49deb2241312605d33aba50499e9d9bd1/pillow-12.1.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:43aca0a55ce1eefc0aefa6253661cb54571857b1a7b2964bd8a1e3ef4b729924", size = 6492981, upload-time = "2026-01-02T09:13:03.314Z" }, + { url = "https://files.pythonhosted.org/packages/4d/1c/b5dc52cf713ae46033359c5ca920444f18a6359ce1020dd3e9c553ea5bc6/pillow-12.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0deedf2ea233722476b3a81e8cdfbad786f7adbed5d848469fa59fe52396e4ef", size = 7191878, upload-time = "2026-01-02T09:13:05.276Z" }, + { url = "https://files.pythonhosted.org/packages/53/26/c4188248bd5edaf543864fe4834aebe9c9cb4968b6f573ce014cc42d0720/pillow-12.1.0-cp314-cp314t-win32.whl", hash = "sha256:b17fbdbe01c196e7e159aacb889e091f28e61020a8abeac07b68079b6e626988", size = 6438703, upload-time = "2026-01-02T09:13:07.491Z" }, + { url = "https://files.pythonhosted.org/packages/b8/0e/69ed296de8ea05cb03ee139cee600f424ca166e632567b2d66727f08c7ed/pillow-12.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:27b9baecb428899db6c0de572d6d305cfaf38ca1596b5c0542a5182e3e74e8c6", size = 7182927, upload-time = "2026-01-02T09:13:09.841Z" }, + { url = "https://files.pythonhosted.org/packages/fc/f5/68334c015eed9b5cff77814258717dec591ded209ab5b6fb70e2ae873d1d/pillow-12.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:f61333d817698bdcdd0f9d7793e365ac3d2a21c1f1eb02b32ad6aefb8d8ea831", size = 2545104, upload-time = "2026-01-02T09:13:12.068Z" }, + { url = "https://files.pythonhosted.org/packages/8b/bc/224b1d98cffd7164b14707c91aac83c07b047fbd8f58eba4066a3e53746a/pillow-12.1.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ca94b6aac0d7af2a10ba08c0f888b3d5114439b6b3ef39968378723622fed377", size = 5228605, upload-time = "2026-01-02T09:13:14.084Z" }, + { url = "https://files.pythonhosted.org/packages/0c/ca/49ca7769c4550107de049ed85208240ba0f330b3f2e316f24534795702ce/pillow-12.1.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:351889afef0f485b84078ea40fe33727a0492b9af3904661b0abbafee0355b72", size = 4622245, upload-time = "2026-01-02T09:13:15.964Z" }, + { url = "https://files.pythonhosted.org/packages/73/48/fac807ce82e5955bcc2718642b94b1bd22a82a6d452aea31cbb678cddf12/pillow-12.1.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bb0984b30e973f7e2884362b7d23d0a348c7143ee559f38ef3eaab640144204c", size = 5247593, upload-time = "2026-01-02T09:13:17.913Z" }, + { url = "https://files.pythonhosted.org/packages/d2/95/3e0742fe358c4664aed4fd05d5f5373dcdad0b27af52aa0972568541e3f4/pillow-12.1.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:84cabc7095dd535ca934d57e9ce2a72ffd216e435a84acb06b2277b1de2689bd", size = 6989008, upload-time = "2026-01-02T09:13:20.083Z" }, + { url = "https://files.pythonhosted.org/packages/5a/74/fe2ac378e4e202e56d50540d92e1ef4ff34ed687f3c60f6a121bcf99437e/pillow-12.1.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:53d8b764726d3af1a138dd353116f774e3862ec7e3794e0c8781e30db0f35dfc", size = 5313824, upload-time = "2026-01-02T09:13:22.405Z" }, + { url = "https://files.pythonhosted.org/packages/f3/77/2a60dee1adee4e2655ac328dd05c02a955c1cd683b9f1b82ec3feb44727c/pillow-12.1.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5da841d81b1a05ef940a8567da92decaa15bc4d7dedb540a8c219ad83d91808a", size = 5963278, upload-time = "2026-01-02T09:13:24.706Z" }, + { url = "https://files.pythonhosted.org/packages/2d/71/64e9b1c7f04ae0027f788a248e6297d7fcc29571371fe7d45495a78172c0/pillow-12.1.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:75af0b4c229ac519b155028fa1be632d812a519abba9b46b20e50c6caa184f19", size = 7029809, upload-time = "2026-01-02T09:13:26.541Z" }, +] + [[package]] name = "platformdirs" version = "4.5.1" @@ -1550,6 +3085,202 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5d/19/fd3ef348460c80af7bb4669ea7926651d1f95c23ff2df18b9d24bab4f3fa/pre_commit-4.5.1-py2.py3-none-any.whl", hash = "sha256:3b3afd891e97337708c1674210f8eba659b52a38ea5f822ff142d10786221f77", size = 226437, upload-time = "2025-12-16T21:14:32.409Z" }, ] +[[package]] +name = "primp" +version = "0.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/56/0b/a87556189da4de1fc6360ca1aa05e8335509633f836cdd06dd17f0743300/primp-0.15.0.tar.gz", hash = "sha256:1af8ea4b15f57571ff7fc5e282a82c5eb69bc695e19b8ddeeda324397965b30a", size = 113022, upload-time = "2025-04-17T11:41:05.315Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f5/5a/146ac964b99ea7657ad67eb66f770be6577dfe9200cb28f9a95baffd6c3f/primp-0.15.0-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:1b281f4ca41a0c6612d4c6e68b96e28acfe786d226a427cd944baa8d7acd644f", size = 3178914, upload-time = "2025-04-17T11:40:59.558Z" }, + { url = "https://files.pythonhosted.org/packages/bc/8a/cc2321e32db3ce64d6e32950d5bcbea01861db97bfb20b5394affc45b387/primp-0.15.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:489cbab55cd793ceb8f90bb7423c6ea64ebb53208ffcf7a044138e3c66d77299", size = 2955079, upload-time = "2025-04-17T11:40:57.398Z" }, + { url = "https://files.pythonhosted.org/packages/c3/7b/cbd5d999a07ff2a21465975d4eb477ae6f69765e8fe8c9087dab250180d8/primp-0.15.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c18b45c23f94016215f62d2334552224236217aaeb716871ce0e4dcfa08eb161", size = 3281018, upload-time = "2025-04-17T11:40:55.308Z" }, + { url = "https://files.pythonhosted.org/packages/1b/6e/a6221c612e61303aec2bcac3f0a02e8b67aee8c0db7bdc174aeb8010f975/primp-0.15.0-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:e985a9cba2e3f96a323722e5440aa9eccaac3178e74b884778e926b5249df080", size = 3255229, upload-time = "2025-04-17T11:40:47.811Z" }, + { url = "https://files.pythonhosted.org/packages/3b/54/bfeef5aca613dc660a69d0760a26c6b8747d8fdb5a7f20cb2cee53c9862f/primp-0.15.0-cp38-abi3-manylinux_2_34_armv7l.whl", hash = "sha256:6b84a6ffa083e34668ff0037221d399c24d939b5629cd38223af860de9e17a83", size = 3014522, upload-time = "2025-04-17T11:40:50.191Z" }, + { url = "https://files.pythonhosted.org/packages/ac/96/84078e09f16a1dad208f2fe0f8a81be2cf36e024675b0f9eec0c2f6e2182/primp-0.15.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:592f6079646bdf5abbbfc3b0a28dac8de943f8907a250ce09398cda5eaebd260", size = 3418567, upload-time = "2025-04-17T11:41:01.595Z" }, + { url = "https://files.pythonhosted.org/packages/6c/80/8a7a9587d3eb85be3d0b64319f2f690c90eb7953e3f73a9ddd9e46c8dc42/primp-0.15.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5a728e5a05f37db6189eb413d22c78bd143fa59dd6a8a26dacd43332b3971fe8", size = 3606279, upload-time = "2025-04-17T11:41:03.61Z" }, + { url = "https://files.pythonhosted.org/packages/0c/dd/f0183ed0145e58cf9d286c1b2c14f63ccee987a4ff79ac85acc31b5d86bd/primp-0.15.0-cp38-abi3-win_amd64.whl", hash = "sha256:aeb6bd20b06dfc92cfe4436939c18de88a58c640752cf7f30d9e4ae893cdec32", size = 3149967, upload-time = "2025-04-17T11:41:07.067Z" }, +] + +[[package]] +name = "propcache" +version = "0.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9e/da/e9fc233cf63743258bff22b3dfa7ea5baef7b5bc324af47a0ad89b8ffc6f/propcache-0.4.1.tar.gz", hash = "sha256:f48107a8c637e80362555f37ecf49abe20370e557cc4ab374f04ec4423c97c3d", size = 46442, upload-time = "2025-10-08T19:49:02.291Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3c/0e/934b541323035566a9af292dba85a195f7b78179114f2c6ebb24551118a9/propcache-0.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c2d1fa3201efaf55d730400d945b5b3ab6e672e100ba0f9a409d950ab25d7db", size = 79534, upload-time = "2025-10-08T19:46:02.083Z" }, + { url = "https://files.pythonhosted.org/packages/a1/6b/db0d03d96726d995dc7171286c6ba9d8d14251f37433890f88368951a44e/propcache-0.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1eb2994229cc8ce7fe9b3db88f5465f5fd8651672840b2e426b88cdb1a30aac8", size = 45526, upload-time = "2025-10-08T19:46:03.884Z" }, + { url = "https://files.pythonhosted.org/packages/e4/c3/82728404aea669e1600f304f2609cde9e665c18df5a11cdd57ed73c1dceb/propcache-0.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:66c1f011f45a3b33d7bcb22daed4b29c0c9e2224758b6be00686731e1b46f925", size = 47263, upload-time = "2025-10-08T19:46:05.405Z" }, + { url = "https://files.pythonhosted.org/packages/df/1b/39313ddad2bf9187a1432654c38249bab4562ef535ef07f5eb6eb04d0b1b/propcache-0.4.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9a52009f2adffe195d0b605c25ec929d26b36ef986ba85244891dee3b294df21", size = 201012, upload-time = "2025-10-08T19:46:07.165Z" }, + { url = "https://files.pythonhosted.org/packages/5b/01/f1d0b57d136f294a142acf97f4ed58c8e5b974c21e543000968357115011/propcache-0.4.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5d4e2366a9c7b837555cf02fb9be2e3167d333aff716332ef1b7c3a142ec40c5", size = 209491, upload-time = "2025-10-08T19:46:08.909Z" }, + { url = "https://files.pythonhosted.org/packages/a1/c8/038d909c61c5bb039070b3fb02ad5cccdb1dde0d714792e251cdb17c9c05/propcache-0.4.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9d2b6caef873b4f09e26ea7e33d65f42b944837563a47a94719cc3544319a0db", size = 215319, upload-time = "2025-10-08T19:46:10.7Z" }, + { url = "https://files.pythonhosted.org/packages/08/57/8c87e93142b2c1fa2408e45695205a7ba05fb5db458c0bf5c06ba0e09ea6/propcache-0.4.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2b16ec437a8c8a965ecf95739448dd938b5c7f56e67ea009f4300d8df05f32b7", size = 196856, upload-time = "2025-10-08T19:46:12.003Z" }, + { url = "https://files.pythonhosted.org/packages/42/df/5615fec76aa561987a534759b3686008a288e73107faa49a8ae5795a9f7a/propcache-0.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:296f4c8ed03ca7476813fe666c9ea97869a8d7aec972618671b33a38a5182ef4", size = 193241, upload-time = "2025-10-08T19:46:13.495Z" }, + { url = "https://files.pythonhosted.org/packages/d5/21/62949eb3a7a54afe8327011c90aca7e03547787a88fb8bd9726806482fea/propcache-0.4.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:1f0978529a418ebd1f49dad413a2b68af33f85d5c5ca5c6ca2a3bed375a7ac60", size = 190552, upload-time = "2025-10-08T19:46:14.938Z" }, + { url = "https://files.pythonhosted.org/packages/30/ee/ab4d727dd70806e5b4de96a798ae7ac6e4d42516f030ee60522474b6b332/propcache-0.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fd138803047fb4c062b1c1dd95462f5209456bfab55c734458f15d11da288f8f", size = 200113, upload-time = "2025-10-08T19:46:16.695Z" }, + { url = "https://files.pythonhosted.org/packages/8a/0b/38b46208e6711b016aa8966a3ac793eee0d05c7159d8342aa27fc0bc365e/propcache-0.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8c9b3cbe4584636d72ff556d9036e0c9317fa27b3ac1f0f558e7e84d1c9c5900", size = 200778, upload-time = "2025-10-08T19:46:18.023Z" }, + { url = "https://files.pythonhosted.org/packages/cf/81/5abec54355ed344476bee711e9f04815d4b00a311ab0535599204eecc257/propcache-0.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f93243fdc5657247533273ac4f86ae106cc6445a0efacb9a1bfe982fcfefd90c", size = 193047, upload-time = "2025-10-08T19:46:19.449Z" }, + { url = "https://files.pythonhosted.org/packages/ec/b6/1f237c04e32063cb034acd5f6ef34ef3a394f75502e72703545631ab1ef6/propcache-0.4.1-cp310-cp310-win32.whl", hash = "sha256:a0ee98db9c5f80785b266eb805016e36058ac72c51a064040f2bc43b61101cdb", size = 38093, upload-time = "2025-10-08T19:46:20.643Z" }, + { url = "https://files.pythonhosted.org/packages/a6/67/354aac4e0603a15f76439caf0427781bcd6797f370377f75a642133bc954/propcache-0.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:1cdb7988c4e5ac7f6d175a28a9aa0c94cb6f2ebe52756a3c0cda98d2809a9e37", size = 41638, upload-time = "2025-10-08T19:46:21.935Z" }, + { url = "https://files.pythonhosted.org/packages/e0/e1/74e55b9fd1a4c209ff1a9a824bf6c8b3d1fc5a1ac3eabe23462637466785/propcache-0.4.1-cp310-cp310-win_arm64.whl", hash = "sha256:d82ad62b19645419fe79dd63b3f9253e15b30e955c0170e5cebc350c1844e581", size = 38229, upload-time = "2025-10-08T19:46:23.368Z" }, + { url = "https://files.pythonhosted.org/packages/8c/d4/4e2c9aaf7ac2242b9358f98dccd8f90f2605402f5afeff6c578682c2c491/propcache-0.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:60a8fda9644b7dfd5dece8c61d8a85e271cb958075bfc4e01083c148b61a7caf", size = 80208, upload-time = "2025-10-08T19:46:24.597Z" }, + { url = "https://files.pythonhosted.org/packages/c2/21/d7b68e911f9c8e18e4ae43bdbc1e1e9bbd971f8866eb81608947b6f585ff/propcache-0.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c30b53e7e6bda1d547cabb47c825f3843a0a1a42b0496087bb58d8fedf9f41b5", size = 45777, upload-time = "2025-10-08T19:46:25.733Z" }, + { url = "https://files.pythonhosted.org/packages/d3/1d/11605e99ac8ea9435651ee71ab4cb4bf03f0949586246476a25aadfec54a/propcache-0.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6918ecbd897443087a3b7cd978d56546a812517dcaaca51b49526720571fa93e", size = 47647, upload-time = "2025-10-08T19:46:27.304Z" }, + { url = "https://files.pythonhosted.org/packages/58/1a/3c62c127a8466c9c843bccb503d40a273e5cc69838805f322e2826509e0d/propcache-0.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3d902a36df4e5989763425a8ab9e98cd8ad5c52c823b34ee7ef307fd50582566", size = 214929, upload-time = "2025-10-08T19:46:28.62Z" }, + { url = "https://files.pythonhosted.org/packages/56/b9/8fa98f850960b367c4b8fe0592e7fc341daa7a9462e925228f10a60cf74f/propcache-0.4.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a9695397f85973bb40427dedddf70d8dc4a44b22f1650dd4af9eedf443d45165", size = 221778, upload-time = "2025-10-08T19:46:30.358Z" }, + { url = "https://files.pythonhosted.org/packages/46/a6/0ab4f660eb59649d14b3d3d65c439421cf2f87fe5dd68591cbe3c1e78a89/propcache-0.4.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2bb07ffd7eaad486576430c89f9b215f9e4be68c4866a96e97db9e97fead85dc", size = 228144, upload-time = "2025-10-08T19:46:32.607Z" }, + { url = "https://files.pythonhosted.org/packages/52/6a/57f43e054fb3d3a56ac9fc532bc684fc6169a26c75c353e65425b3e56eef/propcache-0.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fd6f30fdcf9ae2a70abd34da54f18da086160e4d7d9251f81f3da0ff84fc5a48", size = 210030, upload-time = "2025-10-08T19:46:33.969Z" }, + { url = "https://files.pythonhosted.org/packages/40/e2/27e6feebb5f6b8408fa29f5efbb765cd54c153ac77314d27e457a3e993b7/propcache-0.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fc38cba02d1acba4e2869eef1a57a43dfbd3d49a59bf90dda7444ec2be6a5570", size = 208252, upload-time = "2025-10-08T19:46:35.309Z" }, + { url = "https://files.pythonhosted.org/packages/9e/f8/91c27b22ccda1dbc7967f921c42825564fa5336a01ecd72eb78a9f4f53c2/propcache-0.4.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:67fad6162281e80e882fb3ec355398cf72864a54069d060321f6cd0ade95fe85", size = 202064, upload-time = "2025-10-08T19:46:36.993Z" }, + { url = "https://files.pythonhosted.org/packages/f2/26/7f00bd6bd1adba5aafe5f4a66390f243acab58eab24ff1a08bebb2ef9d40/propcache-0.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f10207adf04d08bec185bae14d9606a1444715bc99180f9331c9c02093e1959e", size = 212429, upload-time = "2025-10-08T19:46:38.398Z" }, + { url = "https://files.pythonhosted.org/packages/84/89/fd108ba7815c1117ddca79c228f3f8a15fc82a73bca8b142eb5de13b2785/propcache-0.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e9b0d8d0845bbc4cfcdcbcdbf5086886bc8157aa963c31c777ceff7846c77757", size = 216727, upload-time = "2025-10-08T19:46:39.732Z" }, + { url = "https://files.pythonhosted.org/packages/79/37/3ec3f7e3173e73f1d600495d8b545b53802cbf35506e5732dd8578db3724/propcache-0.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:981333cb2f4c1896a12f4ab92a9cc8f09ea664e9b7dbdc4eff74627af3a11c0f", size = 205097, upload-time = "2025-10-08T19:46:41.025Z" }, + { url = "https://files.pythonhosted.org/packages/61/b0/b2631c19793f869d35f47d5a3a56fb19e9160d3c119f15ac7344fc3ccae7/propcache-0.4.1-cp311-cp311-win32.whl", hash = "sha256:f1d2f90aeec838a52f1c1a32fe9a619fefd5e411721a9117fbf82aea638fe8a1", size = 38084, upload-time = "2025-10-08T19:46:42.693Z" }, + { url = "https://files.pythonhosted.org/packages/f4/78/6cce448e2098e9f3bfc91bb877f06aa24b6ccace872e39c53b2f707c4648/propcache-0.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:364426a62660f3f699949ac8c621aad6977be7126c5807ce48c0aeb8e7333ea6", size = 41637, upload-time = "2025-10-08T19:46:43.778Z" }, + { url = "https://files.pythonhosted.org/packages/9c/e9/754f180cccd7f51a39913782c74717c581b9cc8177ad0e949f4d51812383/propcache-0.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:e53f3a38d3510c11953f3e6a33f205c6d1b001129f972805ca9b42fc308bc239", size = 38064, upload-time = "2025-10-08T19:46:44.872Z" }, + { url = "https://files.pythonhosted.org/packages/a2/0f/f17b1b2b221d5ca28b4b876e8bb046ac40466513960646bda8e1853cdfa2/propcache-0.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e153e9cd40cc8945138822807139367f256f89c6810c2634a4f6902b52d3b4e2", size = 80061, upload-time = "2025-10-08T19:46:46.075Z" }, + { url = "https://files.pythonhosted.org/packages/76/47/8ccf75935f51448ba9a16a71b783eb7ef6b9ee60f5d14c7f8a8a79fbeed7/propcache-0.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cd547953428f7abb73c5ad82cbb32109566204260d98e41e5dfdc682eb7f8403", size = 46037, upload-time = "2025-10-08T19:46:47.23Z" }, + { url = "https://files.pythonhosted.org/packages/0a/b6/5c9a0e42df4d00bfb4a3cbbe5cf9f54260300c88a0e9af1f47ca5ce17ac0/propcache-0.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f048da1b4f243fc44f205dfd320933a951b8d89e0afd4c7cacc762a8b9165207", size = 47324, upload-time = "2025-10-08T19:46:48.384Z" }, + { url = "https://files.pythonhosted.org/packages/9e/d3/6c7ee328b39a81ee877c962469f1e795f9db87f925251efeb0545e0020d0/propcache-0.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ec17c65562a827bba85e3872ead335f95405ea1674860d96483a02f5c698fa72", size = 225505, upload-time = "2025-10-08T19:46:50.055Z" }, + { url = "https://files.pythonhosted.org/packages/01/5d/1c53f4563490b1d06a684742cc6076ef944bc6457df6051b7d1a877c057b/propcache-0.4.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:405aac25c6394ef275dee4c709be43745d36674b223ba4eb7144bf4d691b7367", size = 230242, upload-time = "2025-10-08T19:46:51.815Z" }, + { url = "https://files.pythonhosted.org/packages/20/e1/ce4620633b0e2422207c3cb774a0ee61cac13abc6217763a7b9e2e3f4a12/propcache-0.4.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0013cb6f8dde4b2a2f66903b8ba740bdfe378c943c4377a200551ceb27f379e4", size = 238474, upload-time = "2025-10-08T19:46:53.208Z" }, + { url = "https://files.pythonhosted.org/packages/46/4b/3aae6835b8e5f44ea6a68348ad90f78134047b503765087be2f9912140ea/propcache-0.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:15932ab57837c3368b024473a525e25d316d8353016e7cc0e5ba9eb343fbb1cf", size = 221575, upload-time = "2025-10-08T19:46:54.511Z" }, + { url = "https://files.pythonhosted.org/packages/6e/a5/8a5e8678bcc9d3a1a15b9a29165640d64762d424a16af543f00629c87338/propcache-0.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:031dce78b9dc099f4c29785d9cf5577a3faf9ebf74ecbd3c856a7b92768c3df3", size = 216736, upload-time = "2025-10-08T19:46:56.212Z" }, + { url = "https://files.pythonhosted.org/packages/f1/63/b7b215eddeac83ca1c6b934f89d09a625aa9ee4ba158338854c87210cc36/propcache-0.4.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ab08df6c9a035bee56e31af99be621526bd237bea9f32def431c656b29e41778", size = 213019, upload-time = "2025-10-08T19:46:57.595Z" }, + { url = "https://files.pythonhosted.org/packages/57/74/f580099a58c8af587cac7ba19ee7cb418506342fbbe2d4a4401661cca886/propcache-0.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4d7af63f9f93fe593afbf104c21b3b15868efb2c21d07d8732c0c4287e66b6a6", size = 220376, upload-time = "2025-10-08T19:46:59.067Z" }, + { url = "https://files.pythonhosted.org/packages/c4/ee/542f1313aff7eaf19c2bb758c5d0560d2683dac001a1c96d0774af799843/propcache-0.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:cfc27c945f422e8b5071b6e93169679e4eb5bf73bbcbf1ba3ae3a83d2f78ebd9", size = 226988, upload-time = "2025-10-08T19:47:00.544Z" }, + { url = "https://files.pythonhosted.org/packages/8f/18/9c6b015dd9c6930f6ce2229e1f02fb35298b847f2087ea2b436a5bfa7287/propcache-0.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:35c3277624a080cc6ec6f847cbbbb5b49affa3598c4535a0a4682a697aaa5c75", size = 215615, upload-time = "2025-10-08T19:47:01.968Z" }, + { url = "https://files.pythonhosted.org/packages/80/9e/e7b85720b98c45a45e1fca6a177024934dc9bc5f4d5dd04207f216fc33ed/propcache-0.4.1-cp312-cp312-win32.whl", hash = "sha256:671538c2262dadb5ba6395e26c1731e1d52534bfe9ae56d0b5573ce539266aa8", size = 38066, upload-time = "2025-10-08T19:47:03.503Z" }, + { url = "https://files.pythonhosted.org/packages/54/09/d19cff2a5aaac632ec8fc03737b223597b1e347416934c1b3a7df079784c/propcache-0.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:cb2d222e72399fcf5890d1d5cc1060857b9b236adff2792ff48ca2dfd46c81db", size = 41655, upload-time = "2025-10-08T19:47:04.973Z" }, + { url = "https://files.pythonhosted.org/packages/68/ab/6b5c191bb5de08036a8c697b265d4ca76148efb10fa162f14af14fb5f076/propcache-0.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:204483131fb222bdaaeeea9f9e6c6ed0cac32731f75dfc1d4a567fc1926477c1", size = 37789, upload-time = "2025-10-08T19:47:06.077Z" }, + { url = "https://files.pythonhosted.org/packages/bf/df/6d9c1b6ac12b003837dde8a10231a7344512186e87b36e855bef32241942/propcache-0.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:43eedf29202c08550aac1d14e0ee619b0430aaef78f85864c1a892294fbc28cf", size = 77750, upload-time = "2025-10-08T19:47:07.648Z" }, + { url = "https://files.pythonhosted.org/packages/8b/e8/677a0025e8a2acf07d3418a2e7ba529c9c33caf09d3c1f25513023c1db56/propcache-0.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d62cdfcfd89ccb8de04e0eda998535c406bf5e060ffd56be6c586cbcc05b3311", size = 44780, upload-time = "2025-10-08T19:47:08.851Z" }, + { url = "https://files.pythonhosted.org/packages/89/a4/92380f7ca60f99ebae761936bc48a72a639e8a47b29050615eef757cb2a7/propcache-0.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cae65ad55793da34db5f54e4029b89d3b9b9490d8abe1b4c7ab5d4b8ec7ebf74", size = 46308, upload-time = "2025-10-08T19:47:09.982Z" }, + { url = "https://files.pythonhosted.org/packages/2d/48/c5ac64dee5262044348d1d78a5f85dd1a57464a60d30daee946699963eb3/propcache-0.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:333ddb9031d2704a301ee3e506dc46b1fe5f294ec198ed6435ad5b6a085facfe", size = 208182, upload-time = "2025-10-08T19:47:11.319Z" }, + { url = "https://files.pythonhosted.org/packages/c6/0c/cd762dd011a9287389a6a3eb43aa30207bde253610cca06824aeabfe9653/propcache-0.4.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:fd0858c20f078a32cf55f7e81473d96dcf3b93fd2ccdb3d40fdf54b8573df3af", size = 211215, upload-time = "2025-10-08T19:47:13.146Z" }, + { url = "https://files.pythonhosted.org/packages/30/3e/49861e90233ba36890ae0ca4c660e95df565b2cd15d4a68556ab5865974e/propcache-0.4.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:678ae89ebc632c5c204c794f8dab2837c5f159aeb59e6ed0539500400577298c", size = 218112, upload-time = "2025-10-08T19:47:14.913Z" }, + { url = "https://files.pythonhosted.org/packages/f1/8b/544bc867e24e1bd48f3118cecd3b05c694e160a168478fa28770f22fd094/propcache-0.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d472aeb4fbf9865e0c6d622d7f4d54a4e101a89715d8904282bb5f9a2f476c3f", size = 204442, upload-time = "2025-10-08T19:47:16.277Z" }, + { url = "https://files.pythonhosted.org/packages/50/a6/4282772fd016a76d3e5c0df58380a5ea64900afd836cec2c2f662d1b9bb3/propcache-0.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4d3df5fa7e36b3225954fba85589da77a0fe6a53e3976de39caf04a0db4c36f1", size = 199398, upload-time = "2025-10-08T19:47:17.962Z" }, + { url = "https://files.pythonhosted.org/packages/3e/ec/d8a7cd406ee1ddb705db2139f8a10a8a427100347bd698e7014351c7af09/propcache-0.4.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:ee17f18d2498f2673e432faaa71698032b0127ebf23ae5974eeaf806c279df24", size = 196920, upload-time = "2025-10-08T19:47:19.355Z" }, + { url = "https://files.pythonhosted.org/packages/f6/6c/f38ab64af3764f431e359f8baf9e0a21013e24329e8b85d2da32e8ed07ca/propcache-0.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:580e97762b950f993ae618e167e7be9256b8353c2dcd8b99ec100eb50f5286aa", size = 203748, upload-time = "2025-10-08T19:47:21.338Z" }, + { url = "https://files.pythonhosted.org/packages/d6/e3/fa846bd70f6534d647886621388f0a265254d30e3ce47e5c8e6e27dbf153/propcache-0.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:501d20b891688eb8e7aa903021f0b72d5a55db40ffaab27edefd1027caaafa61", size = 205877, upload-time = "2025-10-08T19:47:23.059Z" }, + { url = "https://files.pythonhosted.org/packages/e2/39/8163fc6f3133fea7b5f2827e8eba2029a0277ab2c5beee6c1db7b10fc23d/propcache-0.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a0bd56e5b100aef69bd8562b74b46254e7c8812918d3baa700c8a8009b0af66", size = 199437, upload-time = "2025-10-08T19:47:24.445Z" }, + { url = "https://files.pythonhosted.org/packages/93/89/caa9089970ca49c7c01662bd0eeedfe85494e863e8043565aeb6472ce8fe/propcache-0.4.1-cp313-cp313-win32.whl", hash = "sha256:bcc9aaa5d80322bc2fb24bb7accb4a30f81e90ab8d6ba187aec0744bc302ad81", size = 37586, upload-time = "2025-10-08T19:47:25.736Z" }, + { url = "https://files.pythonhosted.org/packages/f5/ab/f76ec3c3627c883215b5c8080debb4394ef5a7a29be811f786415fc1e6fd/propcache-0.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:381914df18634f5494334d201e98245c0596067504b9372d8cf93f4bb23e025e", size = 40790, upload-time = "2025-10-08T19:47:26.847Z" }, + { url = "https://files.pythonhosted.org/packages/59/1b/e71ae98235f8e2ba5004d8cb19765a74877abf189bc53fc0c80d799e56c3/propcache-0.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:8873eb4460fd55333ea49b7d189749ecf6e55bf85080f11b1c4530ed3034cba1", size = 37158, upload-time = "2025-10-08T19:47:27.961Z" }, + { url = "https://files.pythonhosted.org/packages/83/ce/a31bbdfc24ee0dcbba458c8175ed26089cf109a55bbe7b7640ed2470cfe9/propcache-0.4.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:92d1935ee1f8d7442da9c0c4fa7ac20d07e94064184811b685f5c4fada64553b", size = 81451, upload-time = "2025-10-08T19:47:29.445Z" }, + { url = "https://files.pythonhosted.org/packages/25/9c/442a45a470a68456e710d96cacd3573ef26a1d0a60067e6a7d5e655621ed/propcache-0.4.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:473c61b39e1460d386479b9b2f337da492042447c9b685f28be4f74d3529e566", size = 46374, upload-time = "2025-10-08T19:47:30.579Z" }, + { url = "https://files.pythonhosted.org/packages/f4/bf/b1d5e21dbc3b2e889ea4327044fb16312a736d97640fb8b6aa3f9c7b3b65/propcache-0.4.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c0ef0aaafc66fbd87842a3fe3902fd889825646bc21149eafe47be6072725835", size = 48396, upload-time = "2025-10-08T19:47:31.79Z" }, + { url = "https://files.pythonhosted.org/packages/f4/04/5b4c54a103d480e978d3c8a76073502b18db0c4bc17ab91b3cb5092ad949/propcache-0.4.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f95393b4d66bfae908c3ca8d169d5f79cd65636ae15b5e7a4f6e67af675adb0e", size = 275950, upload-time = "2025-10-08T19:47:33.481Z" }, + { url = "https://files.pythonhosted.org/packages/b4/c1/86f846827fb969c4b78b0af79bba1d1ea2156492e1b83dea8b8a6ae27395/propcache-0.4.1-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c07fda85708bc48578467e85099645167a955ba093be0a2dcba962195676e859", size = 273856, upload-time = "2025-10-08T19:47:34.906Z" }, + { url = "https://files.pythonhosted.org/packages/36/1d/fc272a63c8d3bbad6878c336c7a7dea15e8f2d23a544bda43205dfa83ada/propcache-0.4.1-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:af223b406d6d000830c6f65f1e6431783fc3f713ba3e6cc8c024d5ee96170a4b", size = 280420, upload-time = "2025-10-08T19:47:36.338Z" }, + { url = "https://files.pythonhosted.org/packages/07/0c/01f2219d39f7e53d52e5173bcb09c976609ba30209912a0680adfb8c593a/propcache-0.4.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a78372c932c90ee474559c5ddfffd718238e8673c340dc21fe45c5b8b54559a0", size = 263254, upload-time = "2025-10-08T19:47:37.692Z" }, + { url = "https://files.pythonhosted.org/packages/2d/18/cd28081658ce597898f0c4d174d4d0f3c5b6d4dc27ffafeef835c95eb359/propcache-0.4.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:564d9f0d4d9509e1a870c920a89b2fec951b44bf5ba7d537a9e7c1ccec2c18af", size = 261205, upload-time = "2025-10-08T19:47:39.659Z" }, + { url = "https://files.pythonhosted.org/packages/7a/71/1f9e22eb8b8316701c2a19fa1f388c8a3185082607da8e406a803c9b954e/propcache-0.4.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:17612831fda0138059cc5546f4d12a2aacfb9e47068c06af35c400ba58ba7393", size = 247873, upload-time = "2025-10-08T19:47:41.084Z" }, + { url = "https://files.pythonhosted.org/packages/4a/65/3d4b61f36af2b4eddba9def857959f1016a51066b4f1ce348e0cf7881f58/propcache-0.4.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:41a89040cb10bd345b3c1a873b2bf36413d48da1def52f268a055f7398514874", size = 262739, upload-time = "2025-10-08T19:47:42.51Z" }, + { url = "https://files.pythonhosted.org/packages/2a/42/26746ab087faa77c1c68079b228810436ccd9a5ce9ac85e2b7307195fd06/propcache-0.4.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e35b88984e7fa64aacecea39236cee32dd9bd8c55f57ba8a75cf2399553f9bd7", size = 263514, upload-time = "2025-10-08T19:47:43.927Z" }, + { url = "https://files.pythonhosted.org/packages/94/13/630690fe201f5502d2403dd3cfd451ed8858fe3c738ee88d095ad2ff407b/propcache-0.4.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6f8b465489f927b0df505cbe26ffbeed4d6d8a2bbc61ce90eb074ff129ef0ab1", size = 257781, upload-time = "2025-10-08T19:47:45.448Z" }, + { url = "https://files.pythonhosted.org/packages/92/f7/1d4ec5841505f423469efbfc381d64b7b467438cd5a4bbcbb063f3b73d27/propcache-0.4.1-cp313-cp313t-win32.whl", hash = "sha256:2ad890caa1d928c7c2965b48f3a3815c853180831d0e5503d35cf00c472f4717", size = 41396, upload-time = "2025-10-08T19:47:47.202Z" }, + { url = "https://files.pythonhosted.org/packages/48/f0/615c30622316496d2cbbc29f5985f7777d3ada70f23370608c1d3e081c1f/propcache-0.4.1-cp313-cp313t-win_amd64.whl", hash = "sha256:f7ee0e597f495cf415bcbd3da3caa3bd7e816b74d0d52b8145954c5e6fd3ff37", size = 44897, upload-time = "2025-10-08T19:47:48.336Z" }, + { url = "https://files.pythonhosted.org/packages/fd/ca/6002e46eccbe0e33dcd4069ef32f7f1c9e243736e07adca37ae8c4830ec3/propcache-0.4.1-cp313-cp313t-win_arm64.whl", hash = "sha256:929d7cbe1f01bb7baffb33dc14eb5691c95831450a26354cd210a8155170c93a", size = 39789, upload-time = "2025-10-08T19:47:49.876Z" }, + { url = "https://files.pythonhosted.org/packages/8e/5c/bca52d654a896f831b8256683457ceddd490ec18d9ec50e97dfd8fc726a8/propcache-0.4.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3f7124c9d820ba5548d431afb4632301acf965db49e666aa21c305cbe8c6de12", size = 78152, upload-time = "2025-10-08T19:47:51.051Z" }, + { url = "https://files.pythonhosted.org/packages/65/9b/03b04e7d82a5f54fb16113d839f5ea1ede58a61e90edf515f6577c66fa8f/propcache-0.4.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:c0d4b719b7da33599dfe3b22d3db1ef789210a0597bc650b7cee9c77c2be8c5c", size = 44869, upload-time = "2025-10-08T19:47:52.594Z" }, + { url = "https://files.pythonhosted.org/packages/b2/fa/89a8ef0468d5833a23fff277b143d0573897cf75bd56670a6d28126c7d68/propcache-0.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9f302f4783709a78240ebc311b793f123328716a60911d667e0c036bc5dcbded", size = 46596, upload-time = "2025-10-08T19:47:54.073Z" }, + { url = "https://files.pythonhosted.org/packages/86/bd/47816020d337f4a746edc42fe8d53669965138f39ee117414c7d7a340cfe/propcache-0.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c80ee5802e3fb9ea37938e7eecc307fb984837091d5fd262bb37238b1ae97641", size = 206981, upload-time = "2025-10-08T19:47:55.715Z" }, + { url = "https://files.pythonhosted.org/packages/df/f6/c5fa1357cc9748510ee55f37173eb31bfde6d94e98ccd9e6f033f2fc06e1/propcache-0.4.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ed5a841e8bb29a55fb8159ed526b26adc5bdd7e8bd7bf793ce647cb08656cdf4", size = 211490, upload-time = "2025-10-08T19:47:57.499Z" }, + { url = "https://files.pythonhosted.org/packages/80/1e/e5889652a7c4a3846683401a48f0f2e5083ce0ec1a8a5221d8058fbd1adf/propcache-0.4.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:55c72fd6ea2da4c318e74ffdf93c4fe4e926051133657459131a95c846d16d44", size = 215371, upload-time = "2025-10-08T19:47:59.317Z" }, + { url = "https://files.pythonhosted.org/packages/b2/f2/889ad4b2408f72fe1a4f6a19491177b30ea7bf1a0fd5f17050ca08cfc882/propcache-0.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8326e144341460402713f91df60ade3c999d601e7eb5ff8f6f7862d54de0610d", size = 201424, upload-time = "2025-10-08T19:48:00.67Z" }, + { url = "https://files.pythonhosted.org/packages/27/73/033d63069b57b0812c8bd19f311faebeceb6ba31b8f32b73432d12a0b826/propcache-0.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:060b16ae65bc098da7f6d25bf359f1f31f688384858204fe5d652979e0015e5b", size = 197566, upload-time = "2025-10-08T19:48:02.604Z" }, + { url = "https://files.pythonhosted.org/packages/dc/89/ce24f3dc182630b4e07aa6d15f0ff4b14ed4b9955fae95a0b54c58d66c05/propcache-0.4.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:89eb3fa9524f7bec9de6e83cf3faed9d79bffa560672c118a96a171a6f55831e", size = 193130, upload-time = "2025-10-08T19:48:04.499Z" }, + { url = "https://files.pythonhosted.org/packages/a9/24/ef0d5fd1a811fb5c609278d0209c9f10c35f20581fcc16f818da959fc5b4/propcache-0.4.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:dee69d7015dc235f526fe80a9c90d65eb0039103fe565776250881731f06349f", size = 202625, upload-time = "2025-10-08T19:48:06.213Z" }, + { url = "https://files.pythonhosted.org/packages/f5/02/98ec20ff5546f68d673df2f7a69e8c0d076b5abd05ca882dc7ee3a83653d/propcache-0.4.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:5558992a00dfd54ccbc64a32726a3357ec93825a418a401f5cc67df0ac5d9e49", size = 204209, upload-time = "2025-10-08T19:48:08.432Z" }, + { url = "https://files.pythonhosted.org/packages/a0/87/492694f76759b15f0467a2a93ab68d32859672b646aa8a04ce4864e7932d/propcache-0.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c9b822a577f560fbd9554812526831712c1436d2c046cedee4c3796d3543b144", size = 197797, upload-time = "2025-10-08T19:48:09.968Z" }, + { url = "https://files.pythonhosted.org/packages/ee/36/66367de3575db1d2d3f3d177432bd14ee577a39d3f5d1b3d5df8afe3b6e2/propcache-0.4.1-cp314-cp314-win32.whl", hash = "sha256:ab4c29b49d560fe48b696cdcb127dd36e0bc2472548f3bf56cc5cb3da2b2984f", size = 38140, upload-time = "2025-10-08T19:48:11.232Z" }, + { url = "https://files.pythonhosted.org/packages/0c/2a/a758b47de253636e1b8aef181c0b4f4f204bf0dd964914fb2af90a95b49b/propcache-0.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:5a103c3eb905fcea0ab98be99c3a9a5ab2de60228aa5aceedc614c0281cf6153", size = 41257, upload-time = "2025-10-08T19:48:12.707Z" }, + { url = "https://files.pythonhosted.org/packages/34/5e/63bd5896c3fec12edcbd6f12508d4890d23c265df28c74b175e1ef9f4f3b/propcache-0.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:74c1fb26515153e482e00177a1ad654721bf9207da8a494a0c05e797ad27b992", size = 38097, upload-time = "2025-10-08T19:48:13.923Z" }, + { url = "https://files.pythonhosted.org/packages/99/85/9ff785d787ccf9bbb3f3106f79884a130951436f58392000231b4c737c80/propcache-0.4.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:824e908bce90fb2743bd6b59db36eb4f45cd350a39637c9f73b1c1ea66f5b75f", size = 81455, upload-time = "2025-10-08T19:48:15.16Z" }, + { url = "https://files.pythonhosted.org/packages/90/85/2431c10c8e7ddb1445c1f7c4b54d886e8ad20e3c6307e7218f05922cad67/propcache-0.4.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:c2b5e7db5328427c57c8e8831abda175421b709672f6cfc3d630c3b7e2146393", size = 46372, upload-time = "2025-10-08T19:48:16.424Z" }, + { url = "https://files.pythonhosted.org/packages/01/20/b0972d902472da9bcb683fa595099911f4d2e86e5683bcc45de60dd05dc3/propcache-0.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6f6ff873ed40292cd4969ef5310179afd5db59fdf055897e282485043fc80ad0", size = 48411, upload-time = "2025-10-08T19:48:17.577Z" }, + { url = "https://files.pythonhosted.org/packages/e2/e3/7dc89f4f21e8f99bad3d5ddb3a3389afcf9da4ac69e3deb2dcdc96e74169/propcache-0.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:49a2dc67c154db2c1463013594c458881a069fcf98940e61a0569016a583020a", size = 275712, upload-time = "2025-10-08T19:48:18.901Z" }, + { url = "https://files.pythonhosted.org/packages/20/67/89800c8352489b21a8047c773067644e3897f02ecbbd610f4d46b7f08612/propcache-0.4.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:005f08e6a0529984491e37d8dbc3dd86f84bd78a8ceb5fa9a021f4c48d4984be", size = 273557, upload-time = "2025-10-08T19:48:20.762Z" }, + { url = "https://files.pythonhosted.org/packages/e2/a1/b52b055c766a54ce6d9c16d9aca0cad8059acd9637cdf8aa0222f4a026ef/propcache-0.4.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5c3310452e0d31390da9035c348633b43d7e7feb2e37be252be6da45abd1abcc", size = 280015, upload-time = "2025-10-08T19:48:22.592Z" }, + { url = "https://files.pythonhosted.org/packages/48/c8/33cee30bd890672c63743049f3c9e4be087e6780906bfc3ec58528be59c1/propcache-0.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c3c70630930447f9ef1caac7728c8ad1c56bc5015338b20fed0d08ea2480b3a", size = 262880, upload-time = "2025-10-08T19:48:23.947Z" }, + { url = "https://files.pythonhosted.org/packages/0c/b1/8f08a143b204b418285c88b83d00edbd61afbc2c6415ffafc8905da7038b/propcache-0.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8e57061305815dfc910a3634dcf584f08168a8836e6999983569f51a8544cd89", size = 260938, upload-time = "2025-10-08T19:48:25.656Z" }, + { url = "https://files.pythonhosted.org/packages/cf/12/96e4664c82ca2f31e1c8dff86afb867348979eb78d3cb8546a680287a1e9/propcache-0.4.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:521a463429ef54143092c11a77e04056dd00636f72e8c45b70aaa3140d639726", size = 247641, upload-time = "2025-10-08T19:48:27.207Z" }, + { url = "https://files.pythonhosted.org/packages/18/ed/e7a9cfca28133386ba52278136d42209d3125db08d0a6395f0cba0c0285c/propcache-0.4.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:120c964da3fdc75e3731aa392527136d4ad35868cc556fd09bb6d09172d9a367", size = 262510, upload-time = "2025-10-08T19:48:28.65Z" }, + { url = "https://files.pythonhosted.org/packages/f5/76/16d8bf65e8845dd62b4e2b57444ab81f07f40caa5652b8969b87ddcf2ef6/propcache-0.4.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:d8f353eb14ee3441ee844ade4277d560cdd68288838673273b978e3d6d2c8f36", size = 263161, upload-time = "2025-10-08T19:48:30.133Z" }, + { url = "https://files.pythonhosted.org/packages/e7/70/c99e9edb5d91d5ad8a49fa3c1e8285ba64f1476782fed10ab251ff413ba1/propcache-0.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ab2943be7c652f09638800905ee1bab2c544e537edb57d527997a24c13dc1455", size = 257393, upload-time = "2025-10-08T19:48:31.567Z" }, + { url = "https://files.pythonhosted.org/packages/08/02/87b25304249a35c0915d236575bc3574a323f60b47939a2262b77632a3ee/propcache-0.4.1-cp314-cp314t-win32.whl", hash = "sha256:05674a162469f31358c30bcaa8883cb7829fa3110bf9c0991fe27d7896c42d85", size = 42546, upload-time = "2025-10-08T19:48:32.872Z" }, + { url = "https://files.pythonhosted.org/packages/cb/ef/3c6ecf8b317aa982f309835e8f96987466123c6e596646d4e6a1dfcd080f/propcache-0.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:990f6b3e2a27d683cb7602ed6c86f15ee6b43b1194736f9baaeb93d0016633b1", size = 46259, upload-time = "2025-10-08T19:48:34.226Z" }, + { url = "https://files.pythonhosted.org/packages/c4/2d/346e946d4951f37eca1e4f55be0f0174c52cd70720f84029b02f296f4a38/propcache-0.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:ecef2343af4cc68e05131e45024ba34f6095821988a9d0a02aa7c73fcc448aa9", size = 40428, upload-time = "2025-10-08T19:48:35.441Z" }, + { url = "https://files.pythonhosted.org/packages/5b/5a/bc7b4a4ef808fa59a816c17b20c4bef6884daebbdf627ff2a161da67da19/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237", size = 13305, upload-time = "2025-10-08T19:49:00.792Z" }, +] + +[[package]] +name = "puremagic" +version = "1.30" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/dd/7f/9998706bc516bdd664ccf929a1da6c6e5ee06e48f723ce45aae7cf3ff36e/puremagic-1.30.tar.gz", hash = "sha256:f9ff7ac157d54e9cf3bff1addfd97233548e75e685282d84ae11e7ffee1614c9", size = 314785, upload-time = "2025-07-04T18:48:36.061Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/91/ed/1e347d85d05b37a8b9a039ca832e5747e1e5248d0bd66042783ef48b4a37/puremagic-1.30-py3-none-any.whl", hash = "sha256:5eeeb2dd86f335b9cfe8e205346612197af3500c6872dffebf26929f56e9d3c1", size = 43304, upload-time = "2025-07-04T18:48:34.801Z" }, +] + +[[package]] +name = "pyarrow" +version = "23.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/01/33/ffd9c3eb087fa41dd79c3cf20c4c0ae3cdb877c4f8e1107a446006344924/pyarrow-23.0.0.tar.gz", hash = "sha256:180e3150e7edfcd182d3d9afba72f7cf19839a497cc76555a8dce998a8f67615", size = 1167185, upload-time = "2026-01-18T16:19:42.218Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ae/2f/23e042a5aa99bcb15e794e14030e8d065e00827e846e53a66faec73c7cd6/pyarrow-23.0.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:cbdc2bf5947aa4d462adcf8453cf04aee2f7932653cb67a27acd96e5e8528a67", size = 34281861, upload-time = "2026-01-18T16:13:34.332Z" }, + { url = "https://files.pythonhosted.org/packages/8b/65/1651933f504b335ec9cd8f99463718421eb08d883ed84f0abd2835a16cad/pyarrow-23.0.0-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:4d38c836930ce15cd31dce20114b21ba082da231c884bdc0a7b53e1477fe7f07", size = 35825067, upload-time = "2026-01-18T16:13:42.549Z" }, + { url = "https://files.pythonhosted.org/packages/84/ec/d6fceaec050c893f4e35c0556b77d4cc9973fcc24b0a358a5781b1234582/pyarrow-23.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:4222ff8f76919ecf6c716175a0e5fddb5599faeed4c56d9ea41a2c42be4998b2", size = 44458539, upload-time = "2026-01-18T16:13:52.975Z" }, + { url = "https://files.pythonhosted.org/packages/fd/d9/369f134d652b21db62fe3ec1c5c2357e695f79eb67394b8a93f3a2b2cffa/pyarrow-23.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:87f06159cbe38125852657716889296c83c37b4d09a5e58f3d10245fd1f69795", size = 47535889, upload-time = "2026-01-18T16:14:03.693Z" }, + { url = "https://files.pythonhosted.org/packages/a3/95/f37b6a252fdbf247a67a78fb3f61a529fe0600e304c4d07741763d3522b1/pyarrow-23.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:1675c374570d8b91ea6d4edd4608fa55951acd44e0c31bd146e091b4005de24f", size = 48157777, upload-time = "2026-01-18T16:14:12.483Z" }, + { url = "https://files.pythonhosted.org/packages/ab/ab/fb94923108c9c6415dab677cf1f066d3307798eafc03f9a65ab4abc61056/pyarrow-23.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:247374428fde4f668f138b04031a7e7077ba5fa0b5b1722fdf89a017bf0b7ee0", size = 50580441, upload-time = "2026-01-18T16:14:20.187Z" }, + { url = "https://files.pythonhosted.org/packages/ae/78/897ba6337b517fc8e914891e1bd918da1c4eb8e936a553e95862e67b80f6/pyarrow-23.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:de53b1bd3b88a2ee93c9af412c903e57e738c083be4f6392288294513cd8b2c1", size = 27530028, upload-time = "2026-01-18T16:14:27.353Z" }, + { url = "https://files.pythonhosted.org/packages/aa/c0/57fe251102ca834fee0ef69a84ad33cc0ff9d5dfc50f50b466846356ecd7/pyarrow-23.0.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:5574d541923efcbfdf1294a2746ae3b8c2498a2dc6cd477882f6f4e7b1ac08d3", size = 34276762, upload-time = "2026-01-18T16:14:34.128Z" }, + { url = "https://files.pythonhosted.org/packages/f8/4e/24130286548a5bc250cbed0b6bbf289a2775378a6e0e6f086ae8c68fc098/pyarrow-23.0.0-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:2ef0075c2488932e9d3c2eb3482f9459c4be629aa673b725d5e3cf18f777f8e4", size = 35821420, upload-time = "2026-01-18T16:14:40.699Z" }, + { url = "https://files.pythonhosted.org/packages/ee/55/a869e8529d487aa2e842d6c8865eb1e2c9ec33ce2786eb91104d2c3e3f10/pyarrow-23.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:65666fc269669af1ef1c14478c52222a2aa5c907f28b68fb50a203c777e4f60c", size = 44457412, upload-time = "2026-01-18T16:14:49.051Z" }, + { url = "https://files.pythonhosted.org/packages/36/81/1de4f0edfa9a483bbdf0082a05790bd6a20ed2169ea12a65039753be3a01/pyarrow-23.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:4d85cb6177198f3812db4788e394b757223f60d9a9f5ad6634b3e32be1525803", size = 47534285, upload-time = "2026-01-18T16:14:56.748Z" }, + { url = "https://files.pythonhosted.org/packages/f2/04/464a052d673b5ece074518f27377861662449f3c1fdb39ce740d646fd098/pyarrow-23.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1a9ff6fa4141c24a03a1a434c63c8fa97ce70f8f36bccabc18ebba905ddf0f17", size = 48157913, upload-time = "2026-01-18T16:15:05.114Z" }, + { url = "https://files.pythonhosted.org/packages/f4/1b/32a4de9856ee6688c670ca2def588382e573cce45241a965af04c2f61687/pyarrow-23.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:84839d060a54ae734eb60a756aeacb62885244aaa282f3c968f5972ecc7b1ecc", size = 50582529, upload-time = "2026-01-18T16:15:12.846Z" }, + { url = "https://files.pythonhosted.org/packages/db/c7/d6581f03e9b9e44ea60b52d1750ee1a7678c484c06f939f45365a45f7eef/pyarrow-23.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:a149a647dbfe928ce8830a713612aa0b16e22c64feac9d1761529778e4d4eaa5", size = 27542646, upload-time = "2026-01-18T16:15:18.89Z" }, + { url = "https://files.pythonhosted.org/packages/3d/bd/c861d020831ee57609b73ea721a617985ece817684dc82415b0bc3e03ac3/pyarrow-23.0.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:5961a9f646c232697c24f54d3419e69b4261ba8a8b66b0ac54a1851faffcbab8", size = 34189116, upload-time = "2026-01-18T16:15:28.054Z" }, + { url = "https://files.pythonhosted.org/packages/8c/23/7725ad6cdcbaf6346221391e7b3eecd113684c805b0a95f32014e6fa0736/pyarrow-23.0.0-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:632b3e7c3d232f41d64e1a4a043fb82d44f8a349f339a1188c6a0dd9d2d47d8a", size = 35803831, upload-time = "2026-01-18T16:15:33.798Z" }, + { url = "https://files.pythonhosted.org/packages/57/06/684a421543455cdc2944d6a0c2cc3425b028a4c6b90e34b35580c4899743/pyarrow-23.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:76242c846db1411f1d6c2cc3823be6b86b40567ee24493344f8226ba34a81333", size = 44436452, upload-time = "2026-01-18T16:15:41.598Z" }, + { url = "https://files.pythonhosted.org/packages/c6/6f/8f9eb40c2328d66e8b097777ddcf38494115ff9f1b5bc9754ba46991191e/pyarrow-23.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:b73519f8b52ae28127000986bf228fda781e81d3095cd2d3ece76eb5cf760e1b", size = 47557396, upload-time = "2026-01-18T16:15:51.252Z" }, + { url = "https://files.pythonhosted.org/packages/10/6e/f08075f1472e5159553501fde2cc7bc6700944bdabe49a03f8a035ee6ccd/pyarrow-23.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:068701f6823449b1b6469120f399a1239766b117d211c5d2519d4ed5861f75de", size = 48147129, upload-time = "2026-01-18T16:16:00.299Z" }, + { url = "https://files.pythonhosted.org/packages/7d/82/d5a680cd507deed62d141cc7f07f7944a6766fc51019f7f118e4d8ad0fb8/pyarrow-23.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1801ba947015d10e23bca9dd6ef5d0e9064a81569a89b6e9a63b59224fd060df", size = 50596642, upload-time = "2026-01-18T16:16:08.502Z" }, + { url = "https://files.pythonhosted.org/packages/a9/26/4f29c61b3dce9fa7780303b86895ec6a0917c9af927101daaaf118fbe462/pyarrow-23.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:52265266201ec25b6839bf6bd4ea918ca6d50f31d13e1cf200b4261cd11dc25c", size = 27660628, upload-time = "2026-01-18T16:16:15.28Z" }, + { url = "https://files.pythonhosted.org/packages/66/34/564db447d083ec7ff93e0a883a597d2f214e552823bfc178a2d0b1f2c257/pyarrow-23.0.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:ad96a597547af7827342ffb3c503c8316e5043bb09b47a84885ce39394c96e00", size = 34184630, upload-time = "2026-01-18T16:16:22.141Z" }, + { url = "https://files.pythonhosted.org/packages/aa/3a/3999daebcb5e6119690c92a621c4d78eef2ffba7a0a1b56386d2875fcd77/pyarrow-23.0.0-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:b9edf990df77c2901e79608f08c13fbde60202334a4fcadb15c1f57bf7afee43", size = 35796820, upload-time = "2026-01-18T16:16:29.441Z" }, + { url = "https://files.pythonhosted.org/packages/ec/ee/39195233056c6a8d0976d7d1ac1cd4fe21fb0ec534eca76bc23ef3f60e11/pyarrow-23.0.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:36d1b5bc6ddcaff0083ceec7e2561ed61a51f49cce8be079ee8ed406acb6fdef", size = 44438735, upload-time = "2026-01-18T16:16:38.79Z" }, + { url = "https://files.pythonhosted.org/packages/2c/41/6a7328ee493527e7afc0c88d105ecca69a3580e29f2faaeac29308369fd7/pyarrow-23.0.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:4292b889cd224f403304ddda8b63a36e60f92911f89927ec8d98021845ea21be", size = 47557263, upload-time = "2026-01-18T16:16:46.248Z" }, + { url = "https://files.pythonhosted.org/packages/c6/ee/34e95b21ee84db494eae60083ddb4383477b31fb1fd19fd866d794881696/pyarrow-23.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:dfd9e133e60eaa847fd80530a1b89a052f09f695d0b9c34c235ea6b2e0924cf7", size = 48153529, upload-time = "2026-01-18T16:16:53.412Z" }, + { url = "https://files.pythonhosted.org/packages/52/88/8a8d83cea30f4563efa1b7bf51d241331ee5cd1b185a7e063f5634eca415/pyarrow-23.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:832141cc09fac6aab1cd3719951d23301396968de87080c57c9a7634e0ecd068", size = 50598851, upload-time = "2026-01-18T16:17:01.133Z" }, + { url = "https://files.pythonhosted.org/packages/c6/4c/2929c4be88723ba025e7b3453047dc67e491c9422965c141d24bab6b5962/pyarrow-23.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:7a7d067c9a88faca655c71bcc30ee2782038d59c802d57950826a07f60d83c4c", size = 27577747, upload-time = "2026-01-18T16:18:02.413Z" }, + { url = "https://files.pythonhosted.org/packages/64/52/564a61b0b82d72bd68ec3aef1adda1e3eba776f89134b9ebcb5af4b13cb6/pyarrow-23.0.0-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:ce9486e0535a843cf85d990e2ec5820a47918235183a5c7b8b97ed7e92c2d47d", size = 34446038, upload-time = "2026-01-18T16:17:07.861Z" }, + { url = "https://files.pythonhosted.org/packages/cc/c9/232d4f9855fd1de0067c8a7808a363230d223c83aeee75e0fe6eab851ba9/pyarrow-23.0.0-cp313-cp313t-macosx_12_0_x86_64.whl", hash = "sha256:075c29aeaa685fd1182992a9ed2499c66f084ee54eea47da3eb76e125e06064c", size = 35921142, upload-time = "2026-01-18T16:17:15.401Z" }, + { url = "https://files.pythonhosted.org/packages/96/f2/60af606a3748367b906bb82d41f0032e059f075444445d47e32a7ff1df62/pyarrow-23.0.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:799965a5379589510d888be3094c2296efd186a17ca1cef5b77703d4d5121f53", size = 44490374, upload-time = "2026-01-18T16:17:23.93Z" }, + { url = "https://files.pythonhosted.org/packages/ff/2d/7731543050a678ea3a413955a2d5d80d2a642f270aa57a3cb7d5a86e3f46/pyarrow-23.0.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:ef7cac8fe6fccd8b9e7617bfac785b0371a7fe26af59463074e4882747145d40", size = 47527896, upload-time = "2026-01-18T16:17:33.393Z" }, + { url = "https://files.pythonhosted.org/packages/5a/90/f3342553b7ac9879413aed46500f1637296f3c8222107523a43a1c08b42a/pyarrow-23.0.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:15a414f710dc927132dd67c361f78c194447479555af57317066ee5116b90e9e", size = 48210401, upload-time = "2026-01-18T16:17:42.012Z" }, + { url = "https://files.pythonhosted.org/packages/f3/da/9862ade205ecc46c172b6ce5038a74b5151c7401e36255f15975a45878b2/pyarrow-23.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:3e0d2e6915eca7d786be6a77bf227fbc06d825a75b5b5fe9bcbef121dec32685", size = 50579677, upload-time = "2026-01-18T16:17:50.241Z" }, + { url = "https://files.pythonhosted.org/packages/c2/4c/f11f371f5d4740a5dafc2e11c76bcf42d03dfdb2d68696da97de420b6963/pyarrow-23.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:4b317ea6e800b5704e5e5929acb6e2dc13e9276b708ea97a39eb8b345aa2658b", size = 27631889, upload-time = "2026-01-18T16:17:56.55Z" }, + { url = "https://files.pythonhosted.org/packages/97/bb/15aec78bcf43a0c004067bd33eb5352836a29a49db8581fc56f2b6ca88b7/pyarrow-23.0.0-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:20b187ed9550d233a872074159f765f52f9d92973191cd4b93f293a19efbe377", size = 34213265, upload-time = "2026-01-18T16:18:07.904Z" }, + { url = "https://files.pythonhosted.org/packages/f6/6c/deb2c594bbba41c37c5d9aa82f510376998352aa69dfcb886cb4b18ad80f/pyarrow-23.0.0-cp314-cp314-macosx_12_0_x86_64.whl", hash = "sha256:18ec84e839b493c3886b9b5e06861962ab4adfaeb79b81c76afbd8d84c7d5fda", size = 35819211, upload-time = "2026-01-18T16:18:13.94Z" }, + { url = "https://files.pythonhosted.org/packages/e0/e5/ee82af693cb7b5b2b74f6524cdfede0e6ace779d7720ebca24d68b57c36b/pyarrow-23.0.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:e438dd3f33894e34fd02b26bd12a32d30d006f5852315f611aa4add6c7fab4bc", size = 44502313, upload-time = "2026-01-18T16:18:20.367Z" }, + { url = "https://files.pythonhosted.org/packages/9c/86/95c61ad82236495f3c31987e85135926ba3ec7f3819296b70a68d8066b49/pyarrow-23.0.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:a244279f240c81f135631be91146d7fa0e9e840e1dfed2aba8483eba25cd98e6", size = 47585886, upload-time = "2026-01-18T16:18:27.544Z" }, + { url = "https://files.pythonhosted.org/packages/bb/6e/a72d901f305201802f016d015de1e05def7706fff68a1dedefef5dc7eff7/pyarrow-23.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c4692e83e42438dba512a570c6eaa42be2f8b6c0f492aea27dec54bdc495103a", size = 48207055, upload-time = "2026-01-18T16:18:35.425Z" }, + { url = "https://files.pythonhosted.org/packages/f9/e5/5de029c537630ca18828db45c30e2a78da03675a70ac6c3528203c416fe3/pyarrow-23.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ae7f30f898dfe44ea69654a35c93e8da4cef6606dc4c72394068fd95f8e9f54a", size = 50619812, upload-time = "2026-01-18T16:18:43.553Z" }, + { url = "https://files.pythonhosted.org/packages/59/8d/2af846cd2412e67a087f5bda4a8e23dfd4ebd570f777db2e8686615dafc1/pyarrow-23.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:5b86bb649e4112fb0614294b7d0a175c7513738876b89655605ebb87c804f861", size = 28263851, upload-time = "2026-01-18T16:19:38.567Z" }, + { url = "https://files.pythonhosted.org/packages/7b/7f/caab863e587041156f6786c52e64151b7386742c8c27140f637176e9230e/pyarrow-23.0.0-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:ebc017d765d71d80a3f8584ca0566b53e40464586585ac64176115baa0ada7d3", size = 34463240, upload-time = "2026-01-18T16:18:49.755Z" }, + { url = "https://files.pythonhosted.org/packages/c9/fa/3a5b8c86c958e83622b40865e11af0857c48ec763c11d472c87cd518283d/pyarrow-23.0.0-cp314-cp314t-macosx_12_0_x86_64.whl", hash = "sha256:0800cc58a6d17d159df823f87ad66cefebf105b982493d4bad03ee7fab84b993", size = 35935712, upload-time = "2026-01-18T16:18:55.626Z" }, + { url = "https://files.pythonhosted.org/packages/c5/08/17a62078fc1a53decb34a9aa79cf9009efc74d63d2422e5ade9fed2f99e3/pyarrow-23.0.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:3a7c68c722da9bb5b0f8c10e3eae71d9825a4b429b40b32709df5d1fa55beb3d", size = 44503523, upload-time = "2026-01-18T16:19:03.958Z" }, + { url = "https://files.pythonhosted.org/packages/cc/70/84d45c74341e798aae0323d33b7c39194e23b1abc439ceaf60a68a7a969a/pyarrow-23.0.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:bd5556c24622df90551063ea41f559b714aa63ca953db884cfb958559087a14e", size = 47542490, upload-time = "2026-01-18T16:19:11.208Z" }, + { url = "https://files.pythonhosted.org/packages/61/d9/d1274b0e6f19e235de17441e53224f4716574b2ca837022d55702f24d71d/pyarrow-23.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:54810f6e6afc4ffee7c2e0051b61722fbea9a4961b46192dcfae8ea12fa09059", size = 48233605, upload-time = "2026-01-18T16:19:19.544Z" }, + { url = "https://files.pythonhosted.org/packages/39/07/e4e2d568cb57543d84482f61e510732820cddb0f47c4bb7df629abfed852/pyarrow-23.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:14de7d48052cf4b0ed174533eafa3cfe0711b8076ad70bede32cf59f744f0d7c", size = 50603979, upload-time = "2026-01-18T16:19:26.717Z" }, + { url = "https://files.pythonhosted.org/packages/72/9c/47693463894b610f8439b2e970b82ef81e9599c757bf2049365e40ff963c/pyarrow-23.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:427deac1f535830a744a4f04a6ac183a64fcac4341b3f618e693c41b7b98d2b0", size = 28338905, upload-time = "2026-01-18T16:19:32.93Z" }, +] + [[package]] name = "pycparser" version = "3.0" @@ -1729,6 +3460,18 @@ crypto = [ { name = "cryptography" }, ] +[[package]] +name = "pypdf" +version = "6.6.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b8/bb/a44bab1ac3c54dbcf653d7b8bcdee93dddb2d3bf025a3912cacb8149a2f2/pypdf-6.6.2.tar.gz", hash = "sha256:0a3ea3b3303982333404e22d8f75d7b3144f9cf4b2970b96856391a516f9f016", size = 5281850, upload-time = "2026-01-26T11:57:55.964Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7d/be/549aaf1dfa4ab4aed29b09703d2fb02c4366fc1f05e880948c296c5764b9/pypdf-6.6.2-py3-none-any.whl", hash = "sha256:44c0c9811cfb3b83b28f1c3d054531d5b8b81abaedee0d8cb403650d023832ba", size = 329132, upload-time = "2026-01-26T11:57:54.099Z" }, +] + [[package]] name = "pyright" version = "1.1.408" @@ -1788,6 +3531,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ee/49/1377b49de7d0c1ce41292161ea0f721913fa8722c19fb9c1e3aa0367eecb/pytest_cov-7.0.0-py3-none-any.whl", hash = "sha256:3b8e9558b16cc1479da72058bdecf8073661c7f57f7d3c5f22a1c23507f2d861", size = 22424, upload-time = "2025-09-09T10:57:00.695Z" }, ] +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, +] + [[package]] name = "python-dotenv" version = "1.2.1" @@ -1806,6 +3561,30 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/1b/d0/397f9626e711ff749a95d96b7af99b9c566a9bb5129b8e4c10fc4d100304/python_multipart-0.0.22-py3-none-any.whl", hash = "sha256:2b2cd894c83d21bf49d702499531c7bafd057d730c201782048f7945d82de155", size = 24579, upload-time = "2026-01-25T10:15:54.811Z" }, ] +[[package]] +name = "python-pptx" +version = "1.0.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "lxml" }, + { name = "pillow" }, + { name = "typing-extensions" }, + { name = "xlsxwriter" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/52/a9/0c0db8d37b2b8a645666f7fd8accea4c6224e013c42b1d5c17c93590cd06/python_pptx-1.0.2.tar.gz", hash = "sha256:479a8af0eaf0f0d76b6f00b0887732874ad2e3188230315290cd1f9dd9cc7095", size = 10109297, upload-time = "2024-08-07T17:33:37.772Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d9/4f/00be2196329ebbff56ce564aa94efb0fbc828d00de250b1980de1a34ab49/python_pptx-1.0.2-py3-none-any.whl", hash = "sha256:160838e0b8565a8b1f67947675886e9fea18aa5e795db7ae531606d68e785cba", size = 472788, upload-time = "2024-08-07T17:33:28.192Z" }, +] + +[[package]] +name = "pytz" +version = "2025.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", size = 320884, upload-time = "2025-03-25T02:25:00.538Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225, upload-time = "2025-03-25T02:24:58.468Z" }, +] + [[package]] name = "pywin32" version = "311" @@ -2215,6 +3994,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9e/6a/40fee331a52339926a92e17ae748827270b288a35ef4a15c9c8f2ec54715/ruff-0.14.14-py3-none-win_arm64.whl", hash = "sha256:56e6981a98b13a32236a72a8da421d7839221fa308b223b9283312312e5ac76c", size = 10920448, upload-time = "2026-01-22T22:30:15.417Z" }, ] +[[package]] +name = "serpapi" +version = "0.1.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f0/fa/3fd8809287f3977a3e752bb88610e918d49cb1038b14f4bc51e13e594197/serpapi-0.1.5.tar.gz", hash = "sha256:b9707ed54750fdd2f62dc3a17c6a3fb7fa421dc37902fd65b2263c0ac765a1a5", size = 14191, upload-time = "2023-11-01T14:00:43.602Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/df/6a/21deade04100d64844e494353a5d65e7971fbdfddf78eb1f248423593ad0/serpapi-0.1.5-py2.py3-none-any.whl", hash = "sha256:6467b6adec1231059f754ccaa952b229efeaa8b9cae6e71f879703ec9e5bb3d1", size = 10966, upload-time = "2023-11-01T14:00:38.885Z" }, +] + [[package]] name = "shellingham" version = "1.5.4" @@ -2224,6 +4015,38 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" }, ] +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] + +[[package]] +name = "smolagents" +version = "1.24.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "huggingface-hub" }, + { name = "jinja2" }, + { name = "pillow" }, + { name = "python-dotenv" }, + { name = "requests" }, + { name = "rich" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0a/1c/8d8e7f39f3586dc85a7f96681b08b7c1cfbd734b258a025f368632f2d666/smolagents-1.24.0.tar.gz", hash = "sha256:4d5028ffbd72aca85fb2e8daac52d03fb7d4290a9bf99dbc311dd65980f6b5de", size = 225246, upload-time = "2026-01-16T05:37:04.156Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/7a/461ead649c088d30f7847ef1c70f245a9c188381ed09a264633831050497/smolagents-1.24.0-py3-none-any.whl", hash = "sha256:54853759d07a92a939f1ff59238b757fb1a153204c90b69324c8e9709025aa86", size = 155727, upload-time = "2026-01-16T05:37:02.903Z" }, +] + +[package.optional-dependencies] +toolkit = [ + { name = "ddgs" }, + { name = "markdownify" }, +] + [[package]] name = "sniffio" version = "1.3.1" @@ -2233,6 +4056,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, ] +[[package]] +name = "socksio" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f8/5c/48a7d9495be3d1c651198fd99dbb6ce190e2274d0f28b9051307bdec6b85/socksio-1.0.0.tar.gz", hash = "sha256:f88beb3da5b5c38b9890469de67d0cb0f9d494b78b106ca1845f96c10b91c4ac", size = 19055, upload-time = "2020-04-17T15:50:34.664Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/37/c3/6eeb6034408dac0fa653d126c9204ade96b819c936e136c5e8a6897eee9c/socksio-1.0.0-py3-none-any.whl", hash = "sha256:95dc1f15f9b34e8d7b16f06d74b8ccf48f609af32ab33c608d08761c5dcbb1f3", size = 12763, upload-time = "2020-04-17T15:50:31.878Z" }, +] + [[package]] name = "soupsieve" version = "2.8.3" @@ -2407,6 +4239,36 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/af/df/c7891ef9d2712ad774777271d39fdef63941ffba0a9d59b7ad1fd2765e57/tiktoken-0.12.0-cp314-cp314t-win_amd64.whl", hash = "sha256:f61c0aea5565ac82e2ec50a05e02a6c44734e91b51c10510b084ea1b8e633a71", size = 920667, upload-time = "2025-10-06T20:22:34.444Z" }, ] +[[package]] +name = "tokenizers" +version = "0.22.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "huggingface-hub" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/73/6f/f80cfef4a312e1fb34baf7d85c72d4411afde10978d4657f8cdd811d3ccc/tokenizers-0.22.2.tar.gz", hash = "sha256:473b83b915e547aa366d1eee11806deaf419e17be16310ac0a14077f1e28f917", size = 372115, upload-time = "2026-01-05T10:45:15.988Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/92/97/5dbfabf04c7e348e655e907ed27913e03db0923abb5dfdd120d7b25630e1/tokenizers-0.22.2-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:544dd704ae7238755d790de45ba8da072e9af3eea688f698b137915ae959281c", size = 3100275, upload-time = "2026-01-05T10:41:02.158Z" }, + { url = "https://files.pythonhosted.org/packages/2e/47/174dca0502ef88b28f1c9e06b73ce33500eedfac7a7692108aec220464e7/tokenizers-0.22.2-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:1e418a55456beedca4621dbab65a318981467a2b188e982a23e117f115ce5001", size = 2981472, upload-time = "2026-01-05T10:41:00.276Z" }, + { url = "https://files.pythonhosted.org/packages/d6/84/7990e799f1309a8b87af6b948f31edaa12a3ed22d11b352eaf4f4b2e5753/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2249487018adec45d6e3554c71d46eb39fa8ea67156c640f7513eb26f318cec7", size = 3290736, upload-time = "2026-01-05T10:40:32.165Z" }, + { url = "https://files.pythonhosted.org/packages/78/59/09d0d9ba94dcd5f4f1368d4858d24546b4bdc0231c2354aa31d6199f0399/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25b85325d0815e86e0bac263506dd114578953b7b53d7de09a6485e4a160a7dd", size = 3168835, upload-time = "2026-01-05T10:40:38.847Z" }, + { url = "https://files.pythonhosted.org/packages/47/50/b3ebb4243e7160bda8d34b731e54dd8ab8b133e50775872e7a434e524c28/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bfb88f22a209ff7b40a576d5324bf8286b519d7358663db21d6246fb17eea2d5", size = 3521673, upload-time = "2026-01-05T10:40:56.614Z" }, + { url = "https://files.pythonhosted.org/packages/e0/fa/89f4cb9e08df770b57adb96f8cbb7e22695a4cb6c2bd5f0c4f0ebcf33b66/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1c774b1276f71e1ef716e5486f21e76333464f47bece56bbd554485982a9e03e", size = 3724818, upload-time = "2026-01-05T10:40:44.507Z" }, + { url = "https://files.pythonhosted.org/packages/64/04/ca2363f0bfbe3b3d36e95bf67e56a4c88c8e3362b658e616d1ac185d47f2/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:df6c4265b289083bf710dff49bc51ef252f9d5be33a45ee2bed151114a56207b", size = 3379195, upload-time = "2026-01-05T10:40:51.139Z" }, + { url = "https://files.pythonhosted.org/packages/2e/76/932be4b50ef6ccedf9d3c6639b056a967a86258c6d9200643f01269211ca/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:369cc9fc8cc10cb24143873a0d95438bb8ee257bb80c71989e3ee290e8d72c67", size = 3274982, upload-time = "2026-01-05T10:40:58.331Z" }, + { url = "https://files.pythonhosted.org/packages/1d/28/5f9f5a4cc211b69e89420980e483831bcc29dade307955cc9dc858a40f01/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:29c30b83d8dcd061078b05ae0cb94d3c710555fbb44861139f9f83dcca3dc3e4", size = 9478245, upload-time = "2026-01-05T10:41:04.053Z" }, + { url = "https://files.pythonhosted.org/packages/6c/fb/66e2da4704d6aadebf8cb39f1d6d1957df667ab24cff2326b77cda0dcb85/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:37ae80a28c1d3265bb1f22464c856bd23c02a05bb211e56d0c5301a435be6c1a", size = 9560069, upload-time = "2026-01-05T10:45:10.673Z" }, + { url = "https://files.pythonhosted.org/packages/16/04/fed398b05caa87ce9b1a1bb5166645e38196081b225059a6edaff6440fac/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:791135ee325f2336f498590eb2f11dc5c295232f288e75c99a36c5dbce63088a", size = 9899263, upload-time = "2026-01-05T10:45:12.559Z" }, + { url = "https://files.pythonhosted.org/packages/05/a1/d62dfe7376beaaf1394917e0f8e93ee5f67fea8fcf4107501db35996586b/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38337540fbbddff8e999d59970f3c6f35a82de10053206a7562f1ea02d046fa5", size = 10033429, upload-time = "2026-01-05T10:45:14.333Z" }, + { url = "https://files.pythonhosted.org/packages/fd/18/a545c4ea42af3df6effd7d13d250ba77a0a86fb20393143bbb9a92e434d4/tokenizers-0.22.2-cp39-abi3-win32.whl", hash = "sha256:a6bf3f88c554a2b653af81f3204491c818ae2ac6fbc09e76ef4773351292bc92", size = 2502363, upload-time = "2026-01-05T10:45:20.593Z" }, + { url = "https://files.pythonhosted.org/packages/65/71/0670843133a43d43070abeb1949abfdef12a86d490bea9cd9e18e37c5ff7/tokenizers-0.22.2-cp39-abi3-win_amd64.whl", hash = "sha256:c9ea31edff2968b44a88f97d784c2f16dc0729b8b143ed004699ebca91f05c48", size = 2747786, upload-time = "2026-01-05T10:45:18.411Z" }, + { url = "https://files.pythonhosted.org/packages/72/f4/0de46cfa12cdcbcd464cc59fde36912af405696f687e53a091fb432f694c/tokenizers-0.22.2-cp39-abi3-win_arm64.whl", hash = "sha256:9ce725d22864a1e965217204946f830c37876eee3b2ba6fc6255e8e903d5fcbc", size = 2612133, upload-time = "2026-01-05T10:45:17.232Z" }, + { url = "https://files.pythonhosted.org/packages/84/04/655b79dbcc9b3ac5f1479f18e931a344af67e5b7d3b251d2dcdcd7558592/tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:753d47ebd4542742ef9261d9da92cd545b2cacbb48349a1225466745bb866ec4", size = 3282301, upload-time = "2026-01-05T10:40:34.858Z" }, + { url = "https://files.pythonhosted.org/packages/46/cd/e4851401f3d8f6f45d8480262ab6a5c8cb9c4302a790a35aa14eeed6d2fd/tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e10bf9113d209be7cd046d40fbabbaf3278ff6d18eb4da4c500443185dc1896c", size = 3161308, upload-time = "2026-01-05T10:40:40.737Z" }, + { url = "https://files.pythonhosted.org/packages/6f/6e/55553992a89982cd12d4a66dddb5e02126c58677ea3931efcbe601d419db/tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:64d94e84f6660764e64e7e0b22baa72f6cd942279fdbb21d46abd70d179f0195", size = 3718964, upload-time = "2026-01-05T10:40:46.56Z" }, + { url = "https://files.pythonhosted.org/packages/59/8c/b1c87148aa15e099243ec9f0cf9d0e970cc2234c3257d558c25a2c5304e6/tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f01a9c019878532f98927d2bacb79bbb404b43d3437455522a00a30718cdedb5", size = 3373542, upload-time = "2026-01-05T10:40:52.803Z" }, +] + [[package]] name = "tomli" version = "2.4.0" @@ -2509,6 +4371,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" }, ] +[[package]] +name = "tzdata" +version = "2025.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5e/a7/c202b344c5ca7daf398f3b8a477eeb205cf3b6f32e7ec3a6bac0629ca975/tzdata-2025.3.tar.gz", hash = "sha256:de39c2ca5dc7b0344f2eba86f49d614019d29f060fc4ebc8a417896a620b56a7", size = 196772, upload-time = "2025-12-13T17:45:35.667Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl", hash = "sha256:06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1", size = 348521, upload-time = "2025-12-13T17:45:33.889Z" }, +] + [[package]] name = "urllib3" version = "2.6.3" @@ -2644,6 +4515,33 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/6f/28/258ebab549c2bf3e64d2b0217b973467394a9cea8c42f70418ca2c5d0d2e/websockets-16.0-py3-none-any.whl", hash = "sha256:1637db62fad1dc833276dded54215f2c7fa46912301a24bd94d45d46a011ceec", size = 171598, upload-time = "2026-01-10T09:23:45.395Z" }, ] +[[package]] +name = "wikipedia-api" +version = "0.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/49/7b/8b775cf22f266086cefa762b58df0a35a4c4532de3f2f6a0b7432fd31fd1/wikipedia_api-0.9.0.tar.gz", hash = "sha256:6aabd1f9fe34f594f4d36f5af67e468b0a50d713aa9a1d102b4d996bc76dd58e", size = 20041, upload-time = "2026-01-24T21:47:08.75Z" } + +[[package]] +name = "win32-setctime" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b3/8f/705086c9d734d3b663af0e9bb3d4de6578d08f46b1b101c2442fd9aecaa2/win32_setctime-1.2.0.tar.gz", hash = "sha256:ae1fdf948f5640aae05c511ade119313fb6a30d7eabe25fef9764dca5873c4c0", size = 4867, upload-time = "2024-12-07T15:28:28.314Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e1/07/c6fe3ad3e685340704d314d765b7912993bcb8dc198f0e7a89382d37974b/win32_setctime-1.2.0-py3-none-any.whl", hash = "sha256:95d644c4e708aba81dc3704a116d8cbc974d70b3bdb8be1d150e36be6e9d1390", size = 4083, upload-time = "2024-12-07T15:28:26.465Z" }, +] + +[[package]] +name = "xlsxwriter" +version = "3.2.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/46/2c/c06ef49dc36e7954e55b802a8b231770d286a9758b3d936bd1e04ce5ba88/xlsxwriter-3.2.9.tar.gz", hash = "sha256:254b1c37a368c444eac6e2f867405cc9e461b0ed97a3233b2ac1e574efb4140c", size = 215940, upload-time = "2025-09-16T00:16:21.63Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3a/0c/3662f4a66880196a590b202f0db82d919dd2f89e99a27fadef91c4a33d41/xlsxwriter-3.2.9-py3-none-any.whl", hash = "sha256:9a5db42bc5dff014806c58a20b9eae7322a134abb6fce3c92c181bfb275ec5b3", size = 175315, upload-time = "2025-09-16T00:16:20.108Z" }, +] + [[package]] name = "xxhash" version = "3.6.0" @@ -2762,6 +4660,145 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/7b/d9/8d95e906764a386a3d3b596f3c68bb63687dfca806373509f51ce8eea81f/xxhash-3.6.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:15e0dac10eb9309508bfc41f7f9deaa7755c69e35af835db9cb10751adebc35d", size = 31565, upload-time = "2025-10-02T14:37:06.966Z" }, ] +[[package]] +name = "yarl" +version = "1.22.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "multidict" }, + { name = "propcache" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/57/63/0c6ebca57330cd313f6102b16dd57ffaf3ec4c83403dcb45dbd15c6f3ea1/yarl-1.22.0.tar.gz", hash = "sha256:bebf8557577d4401ba8bd9ff33906f1376c877aa78d1fe216ad01b4d6745af71", size = 187169, upload-time = "2025-10-06T14:12:55.963Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/43/a2204825342f37c337f5edb6637040fa14e365b2fcc2346960201d457579/yarl-1.22.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c7bd6683587567e5a49ee6e336e0612bec8329be1b7d4c8af5687dcdeb67ee1e", size = 140517, upload-time = "2025-10-06T14:08:42.494Z" }, + { url = "https://files.pythonhosted.org/packages/44/6f/674f3e6f02266428c56f704cd2501c22f78e8b2eeb23f153117cc86fb28a/yarl-1.22.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5cdac20da754f3a723cceea5b3448e1a2074866406adeb4ef35b469d089adb8f", size = 93495, upload-time = "2025-10-06T14:08:46.2Z" }, + { url = "https://files.pythonhosted.org/packages/b8/12/5b274d8a0f30c07b91b2f02cba69152600b47830fcfb465c108880fcee9c/yarl-1.22.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:07a524d84df0c10f41e3ee918846e1974aba4ec017f990dc735aad487a0bdfdf", size = 94400, upload-time = "2025-10-06T14:08:47.855Z" }, + { url = "https://files.pythonhosted.org/packages/e2/7f/df1b6949b1fa1aa9ff6de6e2631876ad4b73c4437822026e85d8acb56bb1/yarl-1.22.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e1b329cb8146d7b736677a2440e422eadd775d1806a81db2d4cded80a48efc1a", size = 347545, upload-time = "2025-10-06T14:08:49.683Z" }, + { url = "https://files.pythonhosted.org/packages/84/09/f92ed93bd6cd77872ab6c3462df45ca45cd058d8f1d0c9b4f54c1704429f/yarl-1.22.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:75976c6945d85dbb9ee6308cd7ff7b1fb9409380c82d6119bd778d8fcfe2931c", size = 319598, upload-time = "2025-10-06T14:08:51.215Z" }, + { url = "https://files.pythonhosted.org/packages/c3/97/ac3f3feae7d522cf7ccec3d340bb0b2b61c56cb9767923df62a135092c6b/yarl-1.22.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:80ddf7a5f8c86cb3eb4bc9028b07bbbf1f08a96c5c0bc1244be5e8fefcb94147", size = 363893, upload-time = "2025-10-06T14:08:53.144Z" }, + { url = "https://files.pythonhosted.org/packages/06/49/f3219097403b9c84a4d079b1d7bda62dd9b86d0d6e4428c02d46ab2c77fc/yarl-1.22.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d332fc2e3c94dad927f2112395772a4e4fedbcf8f80efc21ed7cdfae4d574fdb", size = 371240, upload-time = "2025-10-06T14:08:55.036Z" }, + { url = "https://files.pythonhosted.org/packages/35/9f/06b765d45c0e44e8ecf0fe15c9eacbbde342bb5b7561c46944f107bfb6c3/yarl-1.22.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0cf71bf877efeac18b38d3930594c0948c82b64547c1cf420ba48722fe5509f6", size = 346965, upload-time = "2025-10-06T14:08:56.722Z" }, + { url = "https://files.pythonhosted.org/packages/c5/69/599e7cea8d0fcb1694323b0db0dda317fa3162f7b90166faddecf532166f/yarl-1.22.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:663e1cadaddae26be034a6ab6072449a8426ddb03d500f43daf952b74553bba0", size = 342026, upload-time = "2025-10-06T14:08:58.563Z" }, + { url = "https://files.pythonhosted.org/packages/95/6f/9dfd12c8bc90fea9eab39832ee32ea48f8e53d1256252a77b710c065c89f/yarl-1.22.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:6dcbb0829c671f305be48a7227918cfcd11276c2d637a8033a99a02b67bf9eda", size = 335637, upload-time = "2025-10-06T14:09:00.506Z" }, + { url = "https://files.pythonhosted.org/packages/57/2e/34c5b4eb9b07e16e873db5b182c71e5f06f9b5af388cdaa97736d79dd9a6/yarl-1.22.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f0d97c18dfd9a9af4490631905a3f131a8e4c9e80a39353919e2cfed8f00aedc", size = 359082, upload-time = "2025-10-06T14:09:01.936Z" }, + { url = "https://files.pythonhosted.org/packages/31/71/fa7e10fb772d273aa1f096ecb8ab8594117822f683bab7d2c5a89914c92a/yarl-1.22.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:437840083abe022c978470b942ff832c3940b2ad3734d424b7eaffcd07f76737", size = 357811, upload-time = "2025-10-06T14:09:03.445Z" }, + { url = "https://files.pythonhosted.org/packages/26/da/11374c04e8e1184a6a03cf9c8f5688d3e5cec83ed6f31ad3481b3207f709/yarl-1.22.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:a899cbd98dce6f5d8de1aad31cb712ec0a530abc0a86bd6edaa47c1090138467", size = 351223, upload-time = "2025-10-06T14:09:05.401Z" }, + { url = "https://files.pythonhosted.org/packages/82/8f/e2d01f161b0c034a30410e375e191a5d27608c1f8693bab1a08b089ca096/yarl-1.22.0-cp310-cp310-win32.whl", hash = "sha256:595697f68bd1f0c1c159fcb97b661fc9c3f5db46498043555d04805430e79bea", size = 82118, upload-time = "2025-10-06T14:09:11.148Z" }, + { url = "https://files.pythonhosted.org/packages/62/46/94c76196642dbeae634c7a61ba3da88cd77bed875bf6e4a8bed037505aa6/yarl-1.22.0-cp310-cp310-win_amd64.whl", hash = "sha256:cb95a9b1adaa48e41815a55ae740cfda005758104049a640a398120bf02515ca", size = 86852, upload-time = "2025-10-06T14:09:12.958Z" }, + { url = "https://files.pythonhosted.org/packages/af/af/7df4f179d3b1a6dcb9a4bd2ffbc67642746fcafdb62580e66876ce83fff4/yarl-1.22.0-cp310-cp310-win_arm64.whl", hash = "sha256:b85b982afde6df99ecc996990d4ad7ccbdbb70e2a4ba4de0aecde5922ba98a0b", size = 82012, upload-time = "2025-10-06T14:09:14.664Z" }, + { url = "https://files.pythonhosted.org/packages/4d/27/5ab13fc84c76a0250afd3d26d5936349a35be56ce5785447d6c423b26d92/yarl-1.22.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1ab72135b1f2db3fed3997d7e7dc1b80573c67138023852b6efb336a5eae6511", size = 141607, upload-time = "2025-10-06T14:09:16.298Z" }, + { url = "https://files.pythonhosted.org/packages/6a/a1/d065d51d02dc02ce81501d476b9ed2229d9a990818332242a882d5d60340/yarl-1.22.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:669930400e375570189492dc8d8341301578e8493aec04aebc20d4717f899dd6", size = 94027, upload-time = "2025-10-06T14:09:17.786Z" }, + { url = "https://files.pythonhosted.org/packages/c1/da/8da9f6a53f67b5106ffe902c6fa0164e10398d4e150d85838b82f424072a/yarl-1.22.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:792a2af6d58177ef7c19cbf0097aba92ca1b9cb3ffdd9c7470e156c8f9b5e028", size = 94963, upload-time = "2025-10-06T14:09:19.662Z" }, + { url = "https://files.pythonhosted.org/packages/68/fe/2c1f674960c376e29cb0bec1249b117d11738db92a6ccc4a530b972648db/yarl-1.22.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3ea66b1c11c9150f1372f69afb6b8116f2dd7286f38e14ea71a44eee9ec51b9d", size = 368406, upload-time = "2025-10-06T14:09:21.402Z" }, + { url = "https://files.pythonhosted.org/packages/95/26/812a540e1c3c6418fec60e9bbd38e871eaba9545e94fa5eff8f4a8e28e1e/yarl-1.22.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3e2daa88dc91870215961e96a039ec73e4937da13cf77ce17f9cad0c18df3503", size = 336581, upload-time = "2025-10-06T14:09:22.98Z" }, + { url = "https://files.pythonhosted.org/packages/0b/f5/5777b19e26fdf98563985e481f8be3d8a39f8734147a6ebf459d0dab5a6b/yarl-1.22.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ba440ae430c00eee41509353628600212112cd5018d5def7e9b05ea7ac34eb65", size = 388924, upload-time = "2025-10-06T14:09:24.655Z" }, + { url = "https://files.pythonhosted.org/packages/86/08/24bd2477bd59c0bbd994fe1d93b126e0472e4e3df5a96a277b0a55309e89/yarl-1.22.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e6438cc8f23a9c1478633d216b16104a586b9761db62bfacb6425bac0a36679e", size = 392890, upload-time = "2025-10-06T14:09:26.617Z" }, + { url = "https://files.pythonhosted.org/packages/46/00/71b90ed48e895667ecfb1eaab27c1523ee2fa217433ed77a73b13205ca4b/yarl-1.22.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c52a6e78aef5cf47a98ef8e934755abf53953379b7d53e68b15ff4420e6683d", size = 365819, upload-time = "2025-10-06T14:09:28.544Z" }, + { url = "https://files.pythonhosted.org/packages/30/2d/f715501cae832651d3282387c6a9236cd26bd00d0ff1e404b3dc52447884/yarl-1.22.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3b06bcadaac49c70f4c88af4ffcfbe3dc155aab3163e75777818092478bcbbe7", size = 363601, upload-time = "2025-10-06T14:09:30.568Z" }, + { url = "https://files.pythonhosted.org/packages/f8/f9/a678c992d78e394e7126ee0b0e4e71bd2775e4334d00a9278c06a6cce96a/yarl-1.22.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:6944b2dc72c4d7f7052683487e3677456050ff77fcf5e6204e98caf785ad1967", size = 358072, upload-time = "2025-10-06T14:09:32.528Z" }, + { url = "https://files.pythonhosted.org/packages/2c/d1/b49454411a60edb6fefdcad4f8e6dbba7d8019e3a508a1c5836cba6d0781/yarl-1.22.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:d5372ca1df0f91a86b047d1277c2aaf1edb32d78bbcefffc81b40ffd18f027ed", size = 385311, upload-time = "2025-10-06T14:09:34.634Z" }, + { url = "https://files.pythonhosted.org/packages/87/e5/40d7a94debb8448c7771a916d1861d6609dddf7958dc381117e7ba36d9e8/yarl-1.22.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:51af598701f5299012b8416486b40fceef8c26fc87dc6d7d1f6fc30609ea0aa6", size = 381094, upload-time = "2025-10-06T14:09:36.268Z" }, + { url = "https://files.pythonhosted.org/packages/35/d8/611cc282502381ad855448643e1ad0538957fc82ae83dfe7762c14069e14/yarl-1.22.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b266bd01fedeffeeac01a79ae181719ff848a5a13ce10075adbefc8f1daee70e", size = 370944, upload-time = "2025-10-06T14:09:37.872Z" }, + { url = "https://files.pythonhosted.org/packages/2d/df/fadd00fb1c90e1a5a8bd731fa3d3de2e165e5a3666a095b04e31b04d9cb6/yarl-1.22.0-cp311-cp311-win32.whl", hash = "sha256:a9b1ba5610a4e20f655258d5a1fdc7ebe3d837bb0e45b581398b99eb98b1f5ca", size = 81804, upload-time = "2025-10-06T14:09:39.359Z" }, + { url = "https://files.pythonhosted.org/packages/b5/f7/149bb6f45f267cb5c074ac40c01c6b3ea6d8a620d34b337f6321928a1b4d/yarl-1.22.0-cp311-cp311-win_amd64.whl", hash = "sha256:078278b9b0b11568937d9509b589ee83ef98ed6d561dfe2020e24a9fd08eaa2b", size = 86858, upload-time = "2025-10-06T14:09:41.068Z" }, + { url = "https://files.pythonhosted.org/packages/2b/13/88b78b93ad3f2f0b78e13bfaaa24d11cbc746e93fe76d8c06bf139615646/yarl-1.22.0-cp311-cp311-win_arm64.whl", hash = "sha256:b6a6f620cfe13ccec221fa312139135166e47ae169f8253f72a0abc0dae94376", size = 81637, upload-time = "2025-10-06T14:09:42.712Z" }, + { url = "https://files.pythonhosted.org/packages/75/ff/46736024fee3429b80a165a732e38e5d5a238721e634ab41b040d49f8738/yarl-1.22.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e340382d1afa5d32b892b3ff062436d592ec3d692aeea3bef3a5cfe11bbf8c6f", size = 142000, upload-time = "2025-10-06T14:09:44.631Z" }, + { url = "https://files.pythonhosted.org/packages/5a/9a/b312ed670df903145598914770eb12de1bac44599549b3360acc96878df8/yarl-1.22.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f1e09112a2c31ffe8d80be1b0988fa6a18c5d5cad92a9ffbb1c04c91bfe52ad2", size = 94338, upload-time = "2025-10-06T14:09:46.372Z" }, + { url = "https://files.pythonhosted.org/packages/ba/f5/0601483296f09c3c65e303d60c070a5c19fcdbc72daa061e96170785bc7d/yarl-1.22.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:939fe60db294c786f6b7c2d2e121576628468f65453d86b0fe36cb52f987bd74", size = 94909, upload-time = "2025-10-06T14:09:48.648Z" }, + { url = "https://files.pythonhosted.org/packages/60/41/9a1fe0b73dbcefce72e46cf149b0e0a67612d60bfc90fb59c2b2efdfbd86/yarl-1.22.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e1651bf8e0398574646744c1885a41198eba53dc8a9312b954073f845c90a8df", size = 372940, upload-time = "2025-10-06T14:09:50.089Z" }, + { url = "https://files.pythonhosted.org/packages/17/7a/795cb6dfee561961c30b800f0ed616b923a2ec6258b5def2a00bf8231334/yarl-1.22.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b8a0588521a26bf92a57a1705b77b8b59044cdceccac7151bd8d229e66b8dedb", size = 345825, upload-time = "2025-10-06T14:09:52.142Z" }, + { url = "https://files.pythonhosted.org/packages/d7/93/a58f4d596d2be2ae7bab1a5846c4d270b894958845753b2c606d666744d3/yarl-1.22.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:42188e6a615c1a75bcaa6e150c3fe8f3e8680471a6b10150c5f7e83f47cc34d2", size = 386705, upload-time = "2025-10-06T14:09:54.128Z" }, + { url = "https://files.pythonhosted.org/packages/61/92/682279d0e099d0e14d7fd2e176bd04f48de1484f56546a3e1313cd6c8e7c/yarl-1.22.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f6d2cb59377d99718913ad9a151030d6f83ef420a2b8f521d94609ecc106ee82", size = 396518, upload-time = "2025-10-06T14:09:55.762Z" }, + { url = "https://files.pythonhosted.org/packages/db/0f/0d52c98b8a885aeda831224b78f3be7ec2e1aa4a62091f9f9188c3c65b56/yarl-1.22.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50678a3b71c751d58d7908edc96d332af328839eea883bb554a43f539101277a", size = 377267, upload-time = "2025-10-06T14:09:57.958Z" }, + { url = "https://files.pythonhosted.org/packages/22/42/d2685e35908cbeaa6532c1fc73e89e7f2efb5d8a7df3959ea8e37177c5a3/yarl-1.22.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e8fbaa7cec507aa24ea27a01456e8dd4b6fab829059b69844bd348f2d467124", size = 365797, upload-time = "2025-10-06T14:09:59.527Z" }, + { url = "https://files.pythonhosted.org/packages/a2/83/cf8c7bcc6355631762f7d8bdab920ad09b82efa6b722999dfb05afa6cfac/yarl-1.22.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:433885ab5431bc3d3d4f2f9bd15bfa1614c522b0f1405d62c4f926ccd69d04fa", size = 365535, upload-time = "2025-10-06T14:10:01.139Z" }, + { url = "https://files.pythonhosted.org/packages/25/e1/5302ff9b28f0c59cac913b91fe3f16c59a033887e57ce9ca5d41a3a94737/yarl-1.22.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:b790b39c7e9a4192dc2e201a282109ed2985a1ddbd5ac08dc56d0e121400a8f7", size = 382324, upload-time = "2025-10-06T14:10:02.756Z" }, + { url = "https://files.pythonhosted.org/packages/bf/cd/4617eb60f032f19ae3a688dc990d8f0d89ee0ea378b61cac81ede3e52fae/yarl-1.22.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:31f0b53913220599446872d757257be5898019c85e7971599065bc55065dc99d", size = 383803, upload-time = "2025-10-06T14:10:04.552Z" }, + { url = "https://files.pythonhosted.org/packages/59/65/afc6e62bb506a319ea67b694551dab4a7e6fb7bf604e9bd9f3e11d575fec/yarl-1.22.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a49370e8f711daec68d09b821a34e1167792ee2d24d405cbc2387be4f158b520", size = 374220, upload-time = "2025-10-06T14:10:06.489Z" }, + { url = "https://files.pythonhosted.org/packages/e7/3d/68bf18d50dc674b942daec86a9ba922d3113d8399b0e52b9897530442da2/yarl-1.22.0-cp312-cp312-win32.whl", hash = "sha256:70dfd4f241c04bd9239d53b17f11e6ab672b9f1420364af63e8531198e3f5fe8", size = 81589, upload-time = "2025-10-06T14:10:09.254Z" }, + { url = "https://files.pythonhosted.org/packages/c8/9a/6ad1a9b37c2f72874f93e691b2e7ecb6137fb2b899983125db4204e47575/yarl-1.22.0-cp312-cp312-win_amd64.whl", hash = "sha256:8884d8b332a5e9b88e23f60bb166890009429391864c685e17bd73a9eda9105c", size = 87213, upload-time = "2025-10-06T14:10:11.369Z" }, + { url = "https://files.pythonhosted.org/packages/44/c5/c21b562d1680a77634d748e30c653c3ca918beb35555cff24986fff54598/yarl-1.22.0-cp312-cp312-win_arm64.whl", hash = "sha256:ea70f61a47f3cc93bdf8b2f368ed359ef02a01ca6393916bc8ff877427181e74", size = 81330, upload-time = "2025-10-06T14:10:13.112Z" }, + { url = "https://files.pythonhosted.org/packages/ea/f3/d67de7260456ee105dc1d162d43a019ecad6b91e2f51809d6cddaa56690e/yarl-1.22.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8dee9c25c74997f6a750cd317b8ca63545169c098faee42c84aa5e506c819b53", size = 139980, upload-time = "2025-10-06T14:10:14.601Z" }, + { url = "https://files.pythonhosted.org/packages/01/88/04d98af0b47e0ef42597b9b28863b9060bb515524da0a65d5f4db160b2d5/yarl-1.22.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:01e73b85a5434f89fc4fe27dcda2aff08ddf35e4d47bbbea3bdcd25321af538a", size = 93424, upload-time = "2025-10-06T14:10:16.115Z" }, + { url = "https://files.pythonhosted.org/packages/18/91/3274b215fd8442a03975ce6bee5fe6aa57a8326b29b9d3d56234a1dca244/yarl-1.22.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:22965c2af250d20c873cdbee8ff958fb809940aeb2e74ba5f20aaf6b7ac8c70c", size = 93821, upload-time = "2025-10-06T14:10:17.993Z" }, + { url = "https://files.pythonhosted.org/packages/61/3a/caf4e25036db0f2da4ca22a353dfeb3c9d3c95d2761ebe9b14df8fc16eb0/yarl-1.22.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b4f15793aa49793ec8d1c708ab7f9eded1aa72edc5174cae703651555ed1b601", size = 373243, upload-time = "2025-10-06T14:10:19.44Z" }, + { url = "https://files.pythonhosted.org/packages/6e/9e/51a77ac7516e8e7803b06e01f74e78649c24ee1021eca3d6a739cb6ea49c/yarl-1.22.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e5542339dcf2747135c5c85f68680353d5cb9ffd741c0f2e8d832d054d41f35a", size = 342361, upload-time = "2025-10-06T14:10:21.124Z" }, + { url = "https://files.pythonhosted.org/packages/d4/f8/33b92454789dde8407f156c00303e9a891f1f51a0330b0fad7c909f87692/yarl-1.22.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5c401e05ad47a75869c3ab3e35137f8468b846770587e70d71e11de797d113df", size = 387036, upload-time = "2025-10-06T14:10:22.902Z" }, + { url = "https://files.pythonhosted.org/packages/d9/9a/c5db84ea024f76838220280f732970aa4ee154015d7f5c1bfb60a267af6f/yarl-1.22.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:243dda95d901c733f5b59214d28b0120893d91777cb8aa043e6ef059d3cddfe2", size = 397671, upload-time = "2025-10-06T14:10:24.523Z" }, + { url = "https://files.pythonhosted.org/packages/11/c9/cd8538dc2e7727095e0c1d867bad1e40c98f37763e6d995c1939f5fdc7b1/yarl-1.22.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bec03d0d388060058f5d291a813f21c011041938a441c593374da6077fe21b1b", size = 377059, upload-time = "2025-10-06T14:10:26.406Z" }, + { url = "https://files.pythonhosted.org/packages/a1/b9/ab437b261702ced75122ed78a876a6dec0a1b0f5e17a4ac7a9a2482d8abe/yarl-1.22.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b0748275abb8c1e1e09301ee3cf90c8a99678a4e92e4373705f2a2570d581273", size = 365356, upload-time = "2025-10-06T14:10:28.461Z" }, + { url = "https://files.pythonhosted.org/packages/b2/9d/8e1ae6d1d008a9567877b08f0ce4077a29974c04c062dabdb923ed98e6fe/yarl-1.22.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:47fdb18187e2a4e18fda2c25c05d8251a9e4a521edaed757fef033e7d8498d9a", size = 361331, upload-time = "2025-10-06T14:10:30.541Z" }, + { url = "https://files.pythonhosted.org/packages/ca/5a/09b7be3905962f145b73beb468cdd53db8aa171cf18c80400a54c5b82846/yarl-1.22.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c7044802eec4524fde550afc28edda0dd5784c4c45f0be151a2d3ba017daca7d", size = 382590, upload-time = "2025-10-06T14:10:33.352Z" }, + { url = "https://files.pythonhosted.org/packages/aa/7f/59ec509abf90eda5048b0bc3e2d7b5099dffdb3e6b127019895ab9d5ef44/yarl-1.22.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:139718f35149ff544caba20fce6e8a2f71f1e39b92c700d8438a0b1d2a631a02", size = 385316, upload-time = "2025-10-06T14:10:35.034Z" }, + { url = "https://files.pythonhosted.org/packages/e5/84/891158426bc8036bfdfd862fabd0e0fa25df4176ec793e447f4b85cf1be4/yarl-1.22.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e1b51bebd221006d3d2f95fbe124b22b247136647ae5dcc8c7acafba66e5ee67", size = 374431, upload-time = "2025-10-06T14:10:37.76Z" }, + { url = "https://files.pythonhosted.org/packages/bb/49/03da1580665baa8bef5e8ed34c6df2c2aca0a2f28bf397ed238cc1bbc6f2/yarl-1.22.0-cp313-cp313-win32.whl", hash = "sha256:d3e32536234a95f513bd374e93d717cf6b2231a791758de6c509e3653f234c95", size = 81555, upload-time = "2025-10-06T14:10:39.649Z" }, + { url = "https://files.pythonhosted.org/packages/9a/ee/450914ae11b419eadd067c6183ae08381cfdfcb9798b90b2b713bbebddda/yarl-1.22.0-cp313-cp313-win_amd64.whl", hash = "sha256:47743b82b76d89a1d20b83e60d5c20314cbd5ba2befc9cda8f28300c4a08ed4d", size = 86965, upload-time = "2025-10-06T14:10:41.313Z" }, + { url = "https://files.pythonhosted.org/packages/98/4d/264a01eae03b6cf629ad69bae94e3b0e5344741e929073678e84bf7a3e3b/yarl-1.22.0-cp313-cp313-win_arm64.whl", hash = "sha256:5d0fcda9608875f7d052eff120c7a5da474a6796fe4d83e152e0e4d42f6d1a9b", size = 81205, upload-time = "2025-10-06T14:10:43.167Z" }, + { url = "https://files.pythonhosted.org/packages/88/fc/6908f062a2f77b5f9f6d69cecb1747260831ff206adcbc5b510aff88df91/yarl-1.22.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:719ae08b6972befcba4310e49edb1161a88cdd331e3a694b84466bd938a6ab10", size = 146209, upload-time = "2025-10-06T14:10:44.643Z" }, + { url = "https://files.pythonhosted.org/packages/65/47/76594ae8eab26210b4867be6f49129861ad33da1f1ebdf7051e98492bf62/yarl-1.22.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:47d8a5c446df1c4db9d21b49619ffdba90e77c89ec6e283f453856c74b50b9e3", size = 95966, upload-time = "2025-10-06T14:10:46.554Z" }, + { url = "https://files.pythonhosted.org/packages/ab/ce/05e9828a49271ba6b5b038b15b3934e996980dd78abdfeb52a04cfb9467e/yarl-1.22.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:cfebc0ac8333520d2d0423cbbe43ae43c8838862ddb898f5ca68565e395516e9", size = 97312, upload-time = "2025-10-06T14:10:48.007Z" }, + { url = "https://files.pythonhosted.org/packages/d1/c5/7dffad5e4f2265b29c9d7ec869c369e4223166e4f9206fc2243ee9eea727/yarl-1.22.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4398557cbf484207df000309235979c79c4356518fd5c99158c7d38203c4da4f", size = 361967, upload-time = "2025-10-06T14:10:49.997Z" }, + { url = "https://files.pythonhosted.org/packages/50/b2/375b933c93a54bff7fc041e1a6ad2c0f6f733ffb0c6e642ce56ee3b39970/yarl-1.22.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2ca6fd72a8cd803be290d42f2dec5cdcd5299eeb93c2d929bf060ad9efaf5de0", size = 323949, upload-time = "2025-10-06T14:10:52.004Z" }, + { url = "https://files.pythonhosted.org/packages/66/50/bfc2a29a1d78644c5a7220ce2f304f38248dc94124a326794e677634b6cf/yarl-1.22.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ca1f59c4e1ab6e72f0a23c13fca5430f889634166be85dbf1013683e49e3278e", size = 361818, upload-time = "2025-10-06T14:10:54.078Z" }, + { url = "https://files.pythonhosted.org/packages/46/96/f3941a46af7d5d0f0498f86d71275696800ddcdd20426298e572b19b91ff/yarl-1.22.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6c5010a52015e7c70f86eb967db0f37f3c8bd503a695a49f8d45700144667708", size = 372626, upload-time = "2025-10-06T14:10:55.767Z" }, + { url = "https://files.pythonhosted.org/packages/c1/42/8b27c83bb875cd89448e42cd627e0fb971fa1675c9ec546393d18826cb50/yarl-1.22.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d7672ecf7557476642c88497c2f8d8542f8e36596e928e9bcba0e42e1e7d71f", size = 341129, upload-time = "2025-10-06T14:10:57.985Z" }, + { url = "https://files.pythonhosted.org/packages/49/36/99ca3122201b382a3cf7cc937b95235b0ac944f7e9f2d5331d50821ed352/yarl-1.22.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:3b7c88eeef021579d600e50363e0b6ee4f7f6f728cd3486b9d0f3ee7b946398d", size = 346776, upload-time = "2025-10-06T14:10:59.633Z" }, + { url = "https://files.pythonhosted.org/packages/85/b4/47328bf996acd01a4c16ef9dcd2f59c969f495073616586f78cd5f2efb99/yarl-1.22.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f4afb5c34f2c6fecdcc182dfcfc6af6cccf1aa923eed4d6a12e9d96904e1a0d8", size = 334879, upload-time = "2025-10-06T14:11:01.454Z" }, + { url = "https://files.pythonhosted.org/packages/c2/ad/b77d7b3f14a4283bffb8e92c6026496f6de49751c2f97d4352242bba3990/yarl-1.22.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:59c189e3e99a59cf8d83cbb31d4db02d66cda5a1a4374e8a012b51255341abf5", size = 350996, upload-time = "2025-10-06T14:11:03.452Z" }, + { url = "https://files.pythonhosted.org/packages/81/c8/06e1d69295792ba54d556f06686cbd6a7ce39c22307100e3fb4a2c0b0a1d/yarl-1.22.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:5a3bf7f62a289fa90f1990422dc8dff5a458469ea71d1624585ec3a4c8d6960f", size = 356047, upload-time = "2025-10-06T14:11:05.115Z" }, + { url = "https://files.pythonhosted.org/packages/4b/b8/4c0e9e9f597074b208d18cef227d83aac36184bfbc6eab204ea55783dbc5/yarl-1.22.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:de6b9a04c606978fdfe72666fa216ffcf2d1a9f6a381058d4378f8d7b1e5de62", size = 342947, upload-time = "2025-10-06T14:11:08.137Z" }, + { url = "https://files.pythonhosted.org/packages/e0/e5/11f140a58bf4c6ad7aca69a892bff0ee638c31bea4206748fc0df4ebcb3a/yarl-1.22.0-cp313-cp313t-win32.whl", hash = "sha256:1834bb90991cc2999f10f97f5f01317f99b143284766d197e43cd5b45eb18d03", size = 86943, upload-time = "2025-10-06T14:11:10.284Z" }, + { url = "https://files.pythonhosted.org/packages/31/74/8b74bae38ed7fe6793d0c15a0c8207bbb819cf287788459e5ed230996cdd/yarl-1.22.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ff86011bd159a9d2dfc89c34cfd8aff12875980e3bd6a39ff097887520e60249", size = 93715, upload-time = "2025-10-06T14:11:11.739Z" }, + { url = "https://files.pythonhosted.org/packages/69/66/991858aa4b5892d57aef7ee1ba6b4d01ec3b7eb3060795d34090a3ca3278/yarl-1.22.0-cp313-cp313t-win_arm64.whl", hash = "sha256:7861058d0582b847bc4e3a4a4c46828a410bca738673f35a29ba3ca5db0b473b", size = 83857, upload-time = "2025-10-06T14:11:13.586Z" }, + { url = "https://files.pythonhosted.org/packages/46/b3/e20ef504049f1a1c54a814b4b9bed96d1ac0e0610c3b4da178f87209db05/yarl-1.22.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:34b36c2c57124530884d89d50ed2c1478697ad7473efd59cfd479945c95650e4", size = 140520, upload-time = "2025-10-06T14:11:15.465Z" }, + { url = "https://files.pythonhosted.org/packages/e4/04/3532d990fdbab02e5ede063676b5c4260e7f3abea2151099c2aa745acc4c/yarl-1.22.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:0dd9a702591ca2e543631c2a017e4a547e38a5c0f29eece37d9097e04a7ac683", size = 93504, upload-time = "2025-10-06T14:11:17.106Z" }, + { url = "https://files.pythonhosted.org/packages/11/63/ff458113c5c2dac9a9719ac68ee7c947cb621432bcf28c9972b1c0e83938/yarl-1.22.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:594fcab1032e2d2cc3321bb2e51271e7cd2b516c7d9aee780ece81b07ff8244b", size = 94282, upload-time = "2025-10-06T14:11:19.064Z" }, + { url = "https://files.pythonhosted.org/packages/a7/bc/315a56aca762d44a6aaaf7ad253f04d996cb6b27bad34410f82d76ea8038/yarl-1.22.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f3d7a87a78d46a2e3d5b72587ac14b4c16952dd0887dbb051451eceac774411e", size = 372080, upload-time = "2025-10-06T14:11:20.996Z" }, + { url = "https://files.pythonhosted.org/packages/3f/3f/08e9b826ec2e099ea6e7c69a61272f4f6da62cb5b1b63590bb80ca2e4a40/yarl-1.22.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:852863707010316c973162e703bddabec35e8757e67fcb8ad58829de1ebc8590", size = 338696, upload-time = "2025-10-06T14:11:22.847Z" }, + { url = "https://files.pythonhosted.org/packages/e3/9f/90360108e3b32bd76789088e99538febfea24a102380ae73827f62073543/yarl-1.22.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:131a085a53bfe839a477c0845acf21efc77457ba2bcf5899618136d64f3303a2", size = 387121, upload-time = "2025-10-06T14:11:24.889Z" }, + { url = "https://files.pythonhosted.org/packages/98/92/ab8d4657bd5b46a38094cfaea498f18bb70ce6b63508fd7e909bd1f93066/yarl-1.22.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:078a8aefd263f4d4f923a9677b942b445a2be970ca24548a8102689a3a8ab8da", size = 394080, upload-time = "2025-10-06T14:11:27.307Z" }, + { url = "https://files.pythonhosted.org/packages/f5/e7/d8c5a7752fef68205296201f8ec2bf718f5c805a7a7e9880576c67600658/yarl-1.22.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bca03b91c323036913993ff5c738d0842fc9c60c4648e5c8d98331526df89784", size = 372661, upload-time = "2025-10-06T14:11:29.387Z" }, + { url = "https://files.pythonhosted.org/packages/b6/2e/f4d26183c8db0bb82d491b072f3127fb8c381a6206a3a56332714b79b751/yarl-1.22.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:68986a61557d37bb90d3051a45b91fa3d5c516d177dfc6dd6f2f436a07ff2b6b", size = 364645, upload-time = "2025-10-06T14:11:31.423Z" }, + { url = "https://files.pythonhosted.org/packages/80/7c/428e5812e6b87cd00ee8e898328a62c95825bf37c7fa87f0b6bb2ad31304/yarl-1.22.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:4792b262d585ff0dff6bcb787f8492e40698443ec982a3568c2096433660c694", size = 355361, upload-time = "2025-10-06T14:11:33.055Z" }, + { url = "https://files.pythonhosted.org/packages/ec/2a/249405fd26776f8b13c067378ef4d7dd49c9098d1b6457cdd152a99e96a9/yarl-1.22.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:ebd4549b108d732dba1d4ace67614b9545b21ece30937a63a65dd34efa19732d", size = 381451, upload-time = "2025-10-06T14:11:35.136Z" }, + { url = "https://files.pythonhosted.org/packages/67/a8/fb6b1adbe98cf1e2dd9fad71003d3a63a1bc22459c6e15f5714eb9323b93/yarl-1.22.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:f87ac53513d22240c7d59203f25cc3beac1e574c6cd681bbfd321987b69f95fd", size = 383814, upload-time = "2025-10-06T14:11:37.094Z" }, + { url = "https://files.pythonhosted.org/packages/d9/f9/3aa2c0e480fb73e872ae2814c43bc1e734740bb0d54e8cb2a95925f98131/yarl-1.22.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:22b029f2881599e2f1b06f8f1db2ee63bd309e2293ba2d566e008ba12778b8da", size = 370799, upload-time = "2025-10-06T14:11:38.83Z" }, + { url = "https://files.pythonhosted.org/packages/50/3c/af9dba3b8b5eeb302f36f16f92791f3ea62e3f47763406abf6d5a4a3333b/yarl-1.22.0-cp314-cp314-win32.whl", hash = "sha256:6a635ea45ba4ea8238463b4f7d0e721bad669f80878b7bfd1f89266e2ae63da2", size = 82990, upload-time = "2025-10-06T14:11:40.624Z" }, + { url = "https://files.pythonhosted.org/packages/ac/30/ac3a0c5bdc1d6efd1b41fa24d4897a4329b3b1e98de9449679dd327af4f0/yarl-1.22.0-cp314-cp314-win_amd64.whl", hash = "sha256:0d6e6885777af0f110b0e5d7e5dda8b704efed3894da26220b7f3d887b839a79", size = 88292, upload-time = "2025-10-06T14:11:42.578Z" }, + { url = "https://files.pythonhosted.org/packages/df/0a/227ab4ff5b998a1b7410abc7b46c9b7a26b0ca9e86c34ba4b8d8bc7c63d5/yarl-1.22.0-cp314-cp314-win_arm64.whl", hash = "sha256:8218f4e98d3c10d683584cb40f0424f4b9fd6e95610232dd75e13743b070ee33", size = 82888, upload-time = "2025-10-06T14:11:44.863Z" }, + { url = "https://files.pythonhosted.org/packages/06/5e/a15eb13db90abd87dfbefb9760c0f3f257ac42a5cac7e75dbc23bed97a9f/yarl-1.22.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:45c2842ff0e0d1b35a6bf1cd6c690939dacb617a70827f715232b2e0494d55d1", size = 146223, upload-time = "2025-10-06T14:11:46.796Z" }, + { url = "https://files.pythonhosted.org/packages/18/82/9665c61910d4d84f41a5bf6837597c89e665fa88aa4941080704645932a9/yarl-1.22.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:d947071e6ebcf2e2bee8fce76e10faca8f7a14808ca36a910263acaacef08eca", size = 95981, upload-time = "2025-10-06T14:11:48.845Z" }, + { url = "https://files.pythonhosted.org/packages/5d/9a/2f65743589809af4d0a6d3aa749343c4b5f4c380cc24a8e94a3c6625a808/yarl-1.22.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:334b8721303e61b00019474cc103bdac3d7b1f65e91f0bfedeec2d56dfe74b53", size = 97303, upload-time = "2025-10-06T14:11:50.897Z" }, + { url = "https://files.pythonhosted.org/packages/b0/ab/5b13d3e157505c43c3b43b5a776cbf7b24a02bc4cccc40314771197e3508/yarl-1.22.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e7ce67c34138a058fd092f67d07a72b8e31ff0c9236e751957465a24b28910c", size = 361820, upload-time = "2025-10-06T14:11:52.549Z" }, + { url = "https://files.pythonhosted.org/packages/fb/76/242a5ef4677615cf95330cfc1b4610e78184400699bdda0acb897ef5e49a/yarl-1.22.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d77e1b2c6d04711478cb1c4ab90db07f1609ccf06a287d5607fcd90dc9863acf", size = 323203, upload-time = "2025-10-06T14:11:54.225Z" }, + { url = "https://files.pythonhosted.org/packages/8c/96/475509110d3f0153b43d06164cf4195c64d16999e0c7e2d8a099adcd6907/yarl-1.22.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4647674b6150d2cae088fc07de2738a84b8bcedebef29802cf0b0a82ab6face", size = 363173, upload-time = "2025-10-06T14:11:56.069Z" }, + { url = "https://files.pythonhosted.org/packages/c9/66/59db471aecfbd559a1fd48aedd954435558cd98c7d0da8b03cc6c140a32c/yarl-1.22.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:efb07073be061c8f79d03d04139a80ba33cbd390ca8f0297aae9cce6411e4c6b", size = 373562, upload-time = "2025-10-06T14:11:58.783Z" }, + { url = "https://files.pythonhosted.org/packages/03/1f/c5d94abc91557384719da10ff166b916107c1b45e4d0423a88457071dd88/yarl-1.22.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e51ac5435758ba97ad69617e13233da53908beccc6cfcd6c34bbed8dcbede486", size = 339828, upload-time = "2025-10-06T14:12:00.686Z" }, + { url = "https://files.pythonhosted.org/packages/5f/97/aa6a143d3afba17b6465733681c70cf175af89f76ec8d9286e08437a7454/yarl-1.22.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:33e32a0dd0c8205efa8e83d04fc9f19313772b78522d1bdc7d9aed706bfd6138", size = 347551, upload-time = "2025-10-06T14:12:02.628Z" }, + { url = "https://files.pythonhosted.org/packages/43/3c/45a2b6d80195959239a7b2a8810506d4eea5487dce61c2a3393e7fc3c52e/yarl-1.22.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:bf4a21e58b9cde0e401e683ebd00f6ed30a06d14e93f7c8fd059f8b6e8f87b6a", size = 334512, upload-time = "2025-10-06T14:12:04.871Z" }, + { url = "https://files.pythonhosted.org/packages/86/a0/c2ab48d74599c7c84cb104ebd799c5813de252bea0f360ffc29d270c2caa/yarl-1.22.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:e4b582bab49ac33c8deb97e058cd67c2c50dac0dd134874106d9c774fd272529", size = 352400, upload-time = "2025-10-06T14:12:06.624Z" }, + { url = "https://files.pythonhosted.org/packages/32/75/f8919b2eafc929567d3d8411f72bdb1a2109c01caaab4ebfa5f8ffadc15b/yarl-1.22.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:0b5bcc1a9c4839e7e30b7b30dd47fe5e7e44fb7054ec29b5bb8d526aa1041093", size = 357140, upload-time = "2025-10-06T14:12:08.362Z" }, + { url = "https://files.pythonhosted.org/packages/cf/72/6a85bba382f22cf78add705d8c3731748397d986e197e53ecc7835e76de7/yarl-1.22.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c0232bce2170103ec23c454e54a57008a9a72b5d1c3105dc2496750da8cfa47c", size = 341473, upload-time = "2025-10-06T14:12:10.994Z" }, + { url = "https://files.pythonhosted.org/packages/35/18/55e6011f7c044dc80b98893060773cefcfdbf60dfefb8cb2f58b9bacbd83/yarl-1.22.0-cp314-cp314t-win32.whl", hash = "sha256:8009b3173bcd637be650922ac455946197d858b3630b6d8787aa9e5c4564533e", size = 89056, upload-time = "2025-10-06T14:12:13.317Z" }, + { url = "https://files.pythonhosted.org/packages/f9/86/0f0dccb6e59a9e7f122c5afd43568b1d31b8ab7dda5f1b01fb5c7025c9a9/yarl-1.22.0-cp314-cp314t-win_amd64.whl", hash = "sha256:9fb17ea16e972c63d25d4a97f016d235c78dd2344820eb35bc034bc32012ee27", size = 96292, upload-time = "2025-10-06T14:12:15.398Z" }, + { url = "https://files.pythonhosted.org/packages/48/b7/503c98092fb3b344a179579f55814b613c1fbb1c23b3ec14a7b008a66a6e/yarl-1.22.0-cp314-cp314t-win_arm64.whl", hash = "sha256:9f6d73c1436b934e3f01df1e1b21ff765cd1d28c77dfb9ace207f746d4610ee1", size = 85171, upload-time = "2025-10-06T14:12:16.935Z" }, + { url = "https://files.pythonhosted.org/packages/73/ae/b48f95715333080afb75a4504487cbe142cae1268afc482d06692d605ae6/yarl-1.22.0-py3-none-any.whl", hash = "sha256:1380560bdba02b6b6c90de54133c81c9f2a453dee9912fe58c1dcced1edb7cff", size = 46814, upload-time = "2025-10-06T14:12:53.872Z" }, +] + +[[package]] +name = "youtube-transcript-api" +version = "1.2.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "defusedxml" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/60/43/4104185a2eaa839daa693b30e15c37e7e58795e8e09ec414f22b3db54bec/youtube_transcript_api-1.2.4.tar.gz", hash = "sha256:b72d0e96a335df599d67cee51d49e143cff4f45b84bcafc202ff51291603ddcd", size = 469839, upload-time = "2026-01-29T09:09:17.088Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/be/95/129ea37efd6cd6ed00f62baae6543345c677810b8a3bf0026756e1d3cf3c/youtube_transcript_api-1.2.4-py3-none-any.whl", hash = "sha256:03878759356da5caf5edac77431780b91448fb3d8c21d4496015bdc8a7bc43ff", size = 485227, upload-time = "2026-01-29T09:09:15.427Z" }, +] + [[package]] name = "zipp" version = "3.23.0"